//------------------------------------------------------------------------------ // CLING - the C++ LLVM-based InterpreterG :) // author: Vassil Vassilev // // This file is dual-licensed: you can choose to license it under the University // of Illinois Open Source License or the GNU Lesser General Public License. See // LICENSE.TXT for details. //------------------------------------------------------------------------------ #include "cling/Interpreter/LookupHelper.h" #include "cling/Utils/Output.h" #include "DeclUnloader.h" #include "cling/Interpreter/Interpreter.h" #include "cling/Utils/AST.h" #include "cling/Utils/ParserStateRAII.h" #include "clang/AST/ASTContext.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" using namespace clang; namespace cling { ///\brief Class to help with the custom allocation of clang::Expr /// struct ExprAlloc { char fBuffer[sizeof(clang::OpaqueValueExpr)]; }; class StartParsingRAII { LookupHelper& m_LH; llvm::SaveAndRestore SaveIsRecursivelyRunning; // Save and restore the state of the Parser and lexer. // Note: ROOT::Internal::ParsingStateRAII also save and restore the state of // Sema, including pending instantiation for example. It is not clear // whether we need to do so here too or whether we need to also see the // "on-going" semantic information ... For now, we leave Sema untouched. clang::Preprocessor::CleanupAndRestoreCacheRAII fCleanupRAII; clang::Parser::ParserCurTokRestoreRAII fSavedCurToken; ParserStateRAII ResetParserState; clang::Sema::SFINAETrap fSFINAETrap; void prepareForParsing(llvm::StringRef code, llvm::StringRef bufferName, LookupHelper::DiagSetting diagOnOff); public: StartParsingRAII(LookupHelper& LH, llvm::StringRef code, llvm::StringRef bufferName, LookupHelper::DiagSetting diagOnOff) : m_LH(LH), SaveIsRecursivelyRunning(LH.IsRecursivelyRunning), fCleanupRAII(LH.m_Parser->getPreprocessor()), fSavedCurToken(*LH.m_Parser), ResetParserState(*LH.m_Parser, !LH.IsRecursivelyRunning /*skipToEOF*/), fSFINAETrap(m_LH.m_Parser->getActions()) { LH.IsRecursivelyRunning = true; prepareForParsing(code, bufferName, diagOnOff); } ~StartParsingRAII() { pop(); } void pop() const {} }; void StartParsingRAII::prepareForParsing(llvm::StringRef code, llvm::StringRef bufferName, LookupHelper::DiagSetting diagOnOff) { ++m_LH.m_TotalParseRequests; Parser& P = *m_LH.m_Parser; Sema& S = P.getActions(); Preprocessor& PP = P.getPreprocessor(); // // Tell the diagnostic engine to ignore all diagnostics. // P.getActions().getDiagnostics().setSuppressAllDiagnostics( diagOnOff == LookupHelper::NoDiagnostics); // // Tell Sema we are not in the process of doing an instantiation. // fSFINAETrap will reset any SFINAE error count of a SFINAE context from "above". // fSFINAETrap will reset this value to the previous one; the line below is overwriting // the value set by fSFINAETrap. P.getActions().InNonInstantiationSFINAEContext = true; // // Tell the parser to not attempt spelling correction. // const_cast(PP.getLangOpts()).SpellChecking = 0; assert(!code.empty() && "prepareForParsing should only be called when need"); // Create a fake file to parse the type name. FileID FID; llvm::hash_code hashedCode = llvm::hash_value(code); auto cacheItr = m_LH.m_ParseBufferCache.find(hashedCode); SourceLocation NewLoc; SourceManager& SM = S.getSourceManager(); bool CacheIsValid = false; if (cacheItr != m_LH.m_ParseBufferCache.end()) { SourceLocation FileStartLoc = SourceLocation::getFromRawEncoding(cacheItr->second); FID = SM.getFileID(FileStartLoc); bool Invalid = true; llvm::StringRef FIDContents = SM.getBufferData(FID, &Invalid); // A FileID is a (cached via ContentCache) SourceManager view of a // FileManager::FileEntry (which is a wrapper on the file system file). // In a subtle cases, code unloading can remove the cached region. // However we are safe because it will empty the ContentCache and force // the FileEntry to be re-read. It will keep the FileID intact and valid // by design. When we reprocess the same (but modified) file it will get // a new FileID. Then the Invalid flag will be false but the underlying // buffer content will be empty. It will not compare equal to the lookup // string and we will avoid using (a potentially broken) cache. assert(!Invalid); // Compare the contents of the cached buffer and the string we should // process. If there are hash collisions this assert should trigger // making it easier to debug. CacheIsValid = FIDContents.equals(llvm::StringRef(code.str() + "\n")); assert(CacheIsValid && "Hash collision!"); if (CacheIsValid) { // We have already included this file once. Reuse the include loc. NewLoc = SM.getIncludeLoc(FID); // The Preprocessor will try to set the NumCreatedFIDs but we are // reparsing and this value was already set. Force reset it to avoid // triggering an assertion in the setNumCreatedFIDsForFileID routine. SM.setNumCreatedFIDsForFileID(FID, 0, /*force*/ true); ++m_LH.m_CacheHits; } } if (!CacheIsValid) { std::unique_ptr SB = llvm::MemoryBuffer::getMemBufferCopy(code.str() + "\n", bufferName.str()); NewLoc = m_LH.m_Interpreter->getNextAvailableLoc(); FID = SM.createFileID(std::move(SB), SrcMgr::C_User, /*LoadedID*/0, /*LoadedOffset*/0, NewLoc); SourceLocation FileStartLoc = SM.getLocForStartOfFile(FID); m_LH.m_ParseBufferCache[hashedCode] = FileStartLoc.getRawEncoding(); } // // Switch to the new file the way #include does. // // Note: To switch back to the main file we must consume an eof token. // PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc); PP.Lex(const_cast(P.getCurToken())); } // pin *tor here so that we can have clang::Parser defined and be able to call // the dtor on the OwningPtr LookupHelper::LookupHelper(clang::Parser* P, Interpreter* interp) : m_Parser(P), m_Interpreter(interp) { } LookupHelper::~LookupHelper() {} static DeclContext* getCompleteContext(const Decl* scopeDecl, ASTContext& Context, Sema &S); static const TagDecl* RequireCompleteDeclContext(Sema& S, Preprocessor& PP, const TagDecl *tobeCompleted, LookupHelper::DiagSetting diagOnOff) { // getContextAndSpec create the CXXScopeSpec and requires the scope // to be complete, so this is exactly what we need. bool OldSuppressAllDiagnostics(PP.getDiagnostics() .getSuppressAllDiagnostics()); PP.getDiagnostics().setSuppressAllDiagnostics( diagOnOff == LookupHelper::NoDiagnostics); ASTContext& Context = S.getASTContext(); DeclContext* complete = getCompleteContext(tobeCompleted,Context,S); PP.getDiagnostics().setSuppressAllDiagnostics(OldSuppressAllDiagnostics); if (!complete) return 0; if (const TagDecl *result = dyn_cast(complete)) return result->getDefinition(); return 0; } ///\brief Look for a tag decl based on its name /// ///\param declName name of the class, enum, uniorn or namespace being /// looked for ///\param resultDecl pointer that will be updated with the answer ///\param P Parse to use for the search ///\param diagOnOff whether the error diagnostics are printed or not. ///\return returns true if the answer is authoritative or false if a more /// detailed search is needed (usually this is for class template /// instances). /// static bool quickFindDecl(llvm::StringRef declName, const Decl *& resultDecl, Parser &P, LookupHelper::DiagSetting diagOnOff) { Sema &S = P.getActions(); Preprocessor &PP = P.getPreprocessor(); resultDecl = nullptr; const clang::DeclContext *sofar = nullptr; const clang::Decl *next = nullptr; for (size_t c = 0, last = 0; c < declName.size(); ++c) { const char current = declName[c]; if (current == '<' || current == '>' || current == ' ' || current == '&' || current == '*' || current == '[' || current == ']') { // For now we do not know how to deal with // template instances. return false; } if (current == ':') { if (c + 2 >= declName.size() || declName[c + 1] != ':') { // Looks like an invalid name, we won't find anything. return true; } next = utils::Lookup::Named(&S, declName.substr(last, c - last), sofar); if (next == (void *) -1) { // Ambiguous result, we need to go through the long path return false; } else if (next && next != (void *) -1) { // Need to handle typedef here too. const TypedefNameDecl *typedefDecl = dyn_cast(next); if (typedefDecl) { // We are stripping the typedef, this is technically incorrect, // as the result (if resultType has been specified) will not be // an accurate representation of the input string. // As we strip the typedef we ought to rebuild the nested name // specifier. // Since we do not use this path for template handling, this // is not relevant for ROOT itself .... ASTContext &Context = S.getASTContext(); QualType T = Context.getTypedefType(typedefDecl); const TagType *TagTy = T->getAs(); if (TagTy) next = TagTy->getDecl(); } // To use Lookup::Named we need to fit the assertion: // ((!isa(LookupCtx) || LookupCtx->isDependentContext() // || cast(LookupCtx)->isCompleteDefinition() // || cast(LookupCtx)->isBeingDefined()) && // "Declaration context must already be complete!"), // function LookupQualifiedName, file SemaLookup.cpp, line 1614. const clang::TagDecl *tdecl = dyn_cast(next); if (tdecl && !(next = tdecl->getDefinition())) { //fprintf(stderr,"Incomplete (inner) type for %s (part %s).\n", // declName.str().c_str(), // declName.substr(last,c-last).str().c_str()); // Incomplete type we will not be able to go on. // We always require completeness of the scope, if the caller // want piece-meal instantiation, the calling code will need to // split the call to findScope. // if (instantiateTemplate) { if (dyn_cast(tdecl)) { // Go back to the normal schedule since we need a valid point // of instantiation: // Assertion failed: (Loc.isValid() && // "point of instantiation must be valid!"), // function setPointOfInstantiation, file DeclTemplate.h, // line 1520. // Which can happen here because the simple name maybe a // typedef to a template (for example std::string). return false; } next = RequireCompleteDeclContext(S, PP, tdecl, diagOnOff); // } else { // return false; // } } sofar = dyn_cast_or_null(next); } else { sofar = 0; } if (!sofar) { // We are looking into something that is not a decl context, // so we won't find anything. return true; } last = c + 2; ++c; // Consume the second ':' } else if (c + 1 == declName.size()) { // End of the line. next = utils::Lookup::Named(&S, declName.substr(last, c + 1 - last), sofar); // If there is an ambiguity, we need to go the long route. if (next == (void *) -1) return false; if (next) { resultDecl = next; } return true; } } // for each characters // Should be unreacheable. return false; } static QualType findBuiltinType(llvm::StringRef typeName, ASTContext &Context) { bool issigned = false; bool isunsigned = false; if (typeName.starts_with("signed ")) { issigned = true; typeName = StringRef(typeName.data()+7, typeName.size()-7); } if (!issigned && typeName.starts_with("unsigned ")) { isunsigned = true; typeName = StringRef(typeName.data()+9, typeName.size()-9); } if (typeName.equals("char")) { if (isunsigned) return Context.UnsignedCharTy; return Context.SignedCharTy; } if (typeName.equals("short")) { if (isunsigned) return Context.UnsignedShortTy; return Context.ShortTy; } if (typeName.equals("int")) { if (isunsigned) return Context.UnsignedIntTy; return Context.IntTy; } if (typeName.equals("long")) { if (isunsigned) return Context.UnsignedLongTy; return Context.LongTy; } if (typeName.equals("long long")) { if (isunsigned) return Context.UnsignedLongLongTy; return Context.LongLongTy; } if (!issigned && !isunsigned) { if (typeName.equals("bool")) return Context.BoolTy; if (typeName.equals("float")) return Context.FloatTy; if (typeName.equals("double")) return Context.DoubleTy; if (typeName.equals("long double")) return Context.LongDoubleTy; if (typeName.equals("wchar_t")) return Context.WCharTy; if (typeName.equals("char16_t")) return Context.Char16Ty; if (typeName.equals("char32_t")) return Context.Char32Ty; } /* Missing CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99. CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions. */ return QualType(); } ///\brief Look for a tag decl based on its name /// ///\param typeName name of the class, enum, uniorn or namespace being /// looked for ///\param resultType reference to QualType that will be updated with the answer ///\param P Parse to use for the search ///\param diagOnOff whether the error diagnostics are printed or not. ///\return returns true if the answer is authoritative or false if a more /// detailed search is needed (usually this is for class template /// instances). /// static bool quickFindType(llvm::StringRef typeName, QualType &resultType, Parser &P, LookupHelper::DiagSetting diagOnOff) { resultType = QualType(); llvm::StringRef quickTypeName = typeName.trim(); bool innerConst = false; bool outerConst = false; if (quickTypeName.starts_with("const ")) { // Use this syntax to avoid the redudant tests in substr. quickTypeName = StringRef(quickTypeName.data()+6, quickTypeName.size()-6); innerConst = true; } enum PointerType { kPointerType, kLRefType, kRRefType, }; if (quickTypeName.ends_with("const")) { if (quickTypeName.size() < 6) return true; auto c = quickTypeName[quickTypeName.size()-6]; if (c==' ' || c=='&' || c=='*') { outerConst = true; if (c == ' ') quickTypeName = StringRef(quickTypeName.data(), quickTypeName.size() - 6); else quickTypeName = StringRef(quickTypeName.data(), quickTypeName.size() - 5); } } std::vector ptrref; for(auto c = quickTypeName.end()-1; c != quickTypeName.begin(); --c) { if (*c == '*') ptrref.push_back(kPointerType); else if (*c == '&') { if (*(c-1)== '&') { --c; ptrref.push_back(kRRefType); } else ptrref.push_back(kLRefType); } else break; } if (!ptrref.empty()) quickTypeName = StringRef(quickTypeName.data(),quickTypeName.size()-ptrref.size()); Sema &S = P.getActions(); ASTContext &Context = S.getASTContext(); QualType quickFind = findBuiltinType(quickTypeName, Context); const Decl *quickDecl = nullptr; if (quickFind.isNull() && quickFindDecl(quickTypeName, quickDecl, P, diagOnOff)) { // The result of quickFindDecl was definitive, we don't need // to check any further. //const TypeDecl *typedecl = dyn_cast(quickDecl); if (quickDecl) { const TypeDecl *typedecl = dyn_cast(quickDecl); if (typedecl) { quickFind = Context.getTypeDeclType(typedecl); } else { return true; } } else { return true; } } if (!quickFind.isNull()) { if (innerConst && !quickFind->isReferenceType()) quickFind.addConst(); for(auto t : ptrref) { switch (t) { case kPointerType : quickFind = Context.getPointerType(quickFind); break; case kLRefType : quickFind = Context.getLValueReferenceType(quickFind); break; case kRRefType : quickFind = Context.getRValueReferenceType(quickFind); break; } } if (outerConst && !quickFind->isReferenceType()) quickFind.addConst(); resultType = quickFind; return true; } return false; } QualType LookupHelper::findType(llvm::StringRef typeName, DiagSetting diagOnOff) const { // // Our return value. // QualType TheQT; if (typeName.empty()) return TheQT; // Could trigger deserialization of decls. Interpreter::PushTransactionRAII RAII(m_Interpreter); // Deal with the most common case. // Going through this custom finder is both much faster // (6 times faster, 10.6s to 57.5s for 1 000 000 calls) and consumes // infinite less memory (0B vs 181 B per call for 'Float_t*'). QualType quickFind; if (quickFindType(typeName,quickFind, *m_Parser, diagOnOff)) { // The result of quickFindDecl was definitive, we don't need // to check any further. return quickFind; } // Use P for shortness Parser& P = *m_Parser; StartParsingRAII ParseStarted(const_cast(*this), typeName, llvm::StringRef("lookup.type.by.name.file"), diagOnOff); // // Try parsing the type name. // clang::ParsedAttributes Attrs(P.getAttrFactory()); // FIXME: All arguments to ParseTypeName are the default arguments. Remove. TypeResult Res(P.ParseTypeName(0, DeclaratorContext::TypeName, clang::AS_none, 0, &Attrs)); if (Res.isUsable()) { // Accept it only if the whole name was parsed. if (P.NextToken().getKind() == clang::tok::eof) { TypeSourceInfo* TSI = 0; TheQT = clang::Sema::GetTypeFromParser(Res.get(), &TSI); } } // if (!quickFind.isNull() && !TheQT.isNull() && TheQT != quickFind) { // fprintf(stderr,"Different result\n"); // fprintf(stderr,"quickFindType:"); quickFind.dump(); // fprintf(stderr,"TheQT :"); TheQT.dump(); // // } return TheQT; } const Decl* LookupHelper::findScope(llvm::StringRef className, DiagSetting diagOnOff, const Type** resultType /* = nullptr */, bool instantiateTemplate/*=true*/) const { // // Some utilities. // // Use P for shortness Parser &P = *m_Parser; Sema &S = P.getActions(); Preprocessor &PP = P.getPreprocessor(); ASTContext &Context = S.getASTContext(); // The user wants to see the template instantiation, existing or not. // Here we might not have an active transaction to handle // the caused instantiation decl. // Also quickFindDecl could trigger deserialization of decls. Interpreter::PushTransactionRAII pushedT(m_Interpreter); // See if we can find it without a buffer and any clang parsing, // We need to go scope by scope. { const Decl *quickResult = nullptr; if (quickFindDecl(className, quickResult, *m_Parser, diagOnOff)) { // The result of quickFindDecl was definitive, we don't need // to check any further. if (!quickResult) { return nullptr; } else { const TagDecl *tagdecl = dyn_cast(quickResult); const TypedefNameDecl *typedefDecl = dyn_cast(quickResult); if (typedefDecl) { QualType T = Context.getTypedefType(typedefDecl); const TagType *TagTy = T->getAs(); if (TagTy) tagdecl = TagTy->getDecl(); // NOTE: Should we instantiate here? ... maybe ... if (tagdecl && resultType) *resultType = T.getTypePtr(); } else if (tagdecl && resultType) { *resultType = tagdecl->getTypeForDecl(); } // fprintf(stderr,"Short cut taken for %s.\n",className.str().c_str()); if (tagdecl) { const TagDecl *defdecl = tagdecl->getDefinition(); if (!defdecl || !defdecl->isCompleteDefinition()) { // fprintf(stderr,"Incomplete type for %s.\n",className.str().c_str()); if (instantiateTemplate) { if (dyn_cast(tagdecl)) { // Go back to the normal schedule since we need a valid point // of instantiation: // Assertion failed: (Loc.isValid() && // "point of instantiation must be valid!"), // function setPointOfInstantiation, file DeclTemplate.h, // line 1520. // Which can happen here because the simple name maybe a // typedef to a template (for example std::string). // break; // the next code executed must be the TransactionRAII below } else return RequireCompleteDeclContext(S, PP, tagdecl, diagOnOff); } else { return nullptr; } } else { return defdecl; // now pointing to the definition. } } else if (isa(quickResult)) { return quickResult->getCanonicalDecl(); } else if (auto alias = dyn_cast(quickResult)) { return alias->getNamespace()->getCanonicalDecl(); } else { //fprintf(stderr,"Not a scope decl for %s.\n",className.str().c_str()); // The name exist and does not point to a 'scope' decl. return nullptr; } } } } StartParsingRAII ParseStarted(const_cast(*this), className.str() + "::", llvm::StringRef("lookup.class.by.name.file"), diagOnOff); // // Our return values. // const Type* TheType = 0; const Type** setResultType = &TheType; if (resultType) setResultType = resultType; *setResultType = 0; // // Prevent failing on an assert in TryAnnotateCXXScopeToken. // if (!P.getCurToken().is(clang::tok::identifier) && !P.getCurToken().is(clang::tok::coloncolon) && !(P.getCurToken().is(clang::tok::annot_template_id) && P.NextToken().is(clang::tok::coloncolon)) && !P.getCurToken().is(clang::tok::kw_decltype)) { // error path return 0; } // // Try parsing the name as a nested-name-specifier. // if (P.TryAnnotateCXXScopeToken(false)) { // error path return 0; } Decl* TheDecl = 0; if (P.getCurToken().getKind() == tok::annot_cxxscope) { CXXScopeSpec SS; S.RestoreNestedNameSpecifierAnnotation(P.getCurToken().getAnnotationValue(), P.getCurToken().getAnnotationRange(), SS); if (SS.isValid()) { NestedNameSpecifier* NNS = SS.getScopeRep(); NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); // Only accept the parse if we consumed all of the name. if (P.NextToken().getKind() == clang::tok::eof) { // // Be careful, not all nested name specifiers refer to classes // and namespaces, and those are the only things we want. // switch (Kind) { case NestedNameSpecifier::Identifier: { // Dependent type. // We do not accept these. } break; case NestedNameSpecifier::Namespace: { // Namespace. NamespaceDecl* NSD = NNS->getAsNamespace(); NSD = NSD->getCanonicalDecl(); TheDecl = NSD; } break; case NestedNameSpecifier::NamespaceAlias: { // Namespace alias. // Note: In the future, should we return the alias instead? NamespaceAliasDecl* NSAD = NNS->getAsNamespaceAlias(); NamespaceDecl* NSD = NSAD->getNamespace(); NSD = NSD->getCanonicalDecl(); TheDecl = NSD; } break; case NestedNameSpecifier::TypeSpec: // Type name. // Intentional fall-though case NestedNameSpecifier::TypeSpecWithTemplate: { // Type name qualified with "template". // Note: Do we need to check for a dependent type here? NestedNameSpecifier *prefix = NNS->getPrefix(); if (prefix) { QualType temp = Context.getElaboratedType(ETK_None,prefix, QualType(NNS->getAsType(),0)); *setResultType = temp.getTypePtr(); } else { *setResultType = NNS->getAsType(); } const TagType* TagTy = (*setResultType)->getAs(); if (TagTy) { // It is a class, struct, or union. TagDecl* TD = TagTy->getDecl(); if (TD) { TheDecl = TD->getDefinition(); // NOTE: if (TheDecl) ... check for theDecl->isInvalidDecl() if (TD && TD->isInvalidDecl()) { printf("Warning: FindScope got an invalid tag decl\n"); } if (TheDecl && TheDecl->isInvalidDecl()) { printf("ERROR: FindScope about to return an invalid decl\n"); } if (!TheDecl && instantiateTemplate) { // Make sure it is not just forward declared, and // instantiate any templates. DeclContext *ctxt = TD; if (!S.RequireCompleteDeclContext(SS, ctxt)) { // Success, type is complete, instantiations have // been done. TheDecl = TD->getDefinition(); if (TheDecl->isInvalidDecl()) { // if the decl is invalid try to clean up UnloadDecl(&S, TheDecl); *setResultType = nullptr; return 0; } } else { // NOTE: We cannot instantiate the scope: not a valid decl. // Need to unload it if this decl is a definition. // But do not unload pre-existing fwd decls. Note that this might have failed // because several other Decls failed to instantiate, leaving several Decls // in invalid state. We should be unloading all of them, i.e. inload the // current (possibly nested) transaction. auto *T = const_cast(m_Interpreter->getCurrentTransaction()); // Must not unload the Transaction, which might delete // it: the RAII above still points to it! Instead, just // mark it as "erroneous" which causes the RAII to // unload it in due time. T->setIssuedDiags(Transaction::kErrors); *setResultType = nullptr; return 0; } } } } } break; case clang::NestedNameSpecifier::Global: { // Name was just "::" and nothing more. TheDecl = Context.getTranslationUnitDecl(); } break; case NestedNameSpecifier::Super: // Microsoft's __super:: return 0; } return TheDecl; } } } // // Cleanup after failed parse as a nested-name-specifier. // P.SkipUntil(clang::tok::eof); // Doesn't reset the diagnostic mappings S.getDiagnostics().Reset(/*soft=*/true); // // Setup to reparse as a type. // std::unique_ptr SB(llvm::MemoryBuffer::getMemBufferCopy(className.str() + "\n", "lookup.type.file")); SourceLocation NewLoc = m_Interpreter->getNextAvailableLoc(); FileID FID = S.getSourceManager().createFileID(std::move(SB), SrcMgr::C_User, /*LoadedID*/0, /*LoadedOffset*/0, NewLoc); PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc); PP.Lex(const_cast(P.getCurToken())); // // Now try to parse the name as a type. // if (P.TryAnnotateTypeOrScopeToken()) { // error path return 0; } if (P.getCurToken().getKind() == tok::annot_typename) { TypeResult T = P.getTypeAnnotation(const_cast(P.getCurToken())); // Only accept the parse if we consumed all of the name. if (P.NextToken().getKind() == clang::tok::eof) if (!T.get().get().isNull()) { TypeSourceInfo *TSI = 0; clang::QualType QT = clang::Sema::GetTypeFromParser(T.get(), &TSI); if (const TagType* TT = QT->getAs()) { TheDecl = TT->getDecl()->getDefinition(); *setResultType = QT.getTypePtr(); } } } return TheDecl; } const ClassTemplateDecl* LookupHelper::findClassTemplate(llvm::StringRef Name, DiagSetting diagOnOff) const { // // Find a class template decl given its name. // if (Name.empty()) return 0; // Humm ... this seems to do the trick ... or does it? or is there a better way? // Use P for shortness Parser& P = *m_Parser; Sema& S = P.getActions(); ASTContext& Context = S.getASTContext(); StartParsingRAII ParseStarted(const_cast(*this), Name.str(), llvm::StringRef("lookup.class.by.name.file"), diagOnOff); // // Prevent failing on an assert in TryAnnotateCXXScopeToken. // if (!P.getCurToken().is(clang::tok::identifier) && !P.getCurToken().is(clang::tok::coloncolon) && !(P.getCurToken().is(clang::tok::annot_template_id) && P.NextToken().is(clang::tok::coloncolon)) && !P.getCurToken().is(clang::tok::kw_decltype)) { // error path return 0; } // // Now try to parse the name as a type. // if (P.TryAnnotateTypeOrScopeToken()) { // error path return 0; } DeclContext *where = 0; if (P.getCurToken().getKind() == tok::annot_cxxscope) { CXXScopeSpec SS; S.RestoreNestedNameSpecifierAnnotation(P.getCurToken().getAnnotationValue(), P.getCurToken().getAnnotationRange(), SS); if (SS.isValid()) { P.ConsumeAnyToken(); if (!P.getCurToken().is(clang::tok::identifier)) { return 0; } NestedNameSpecifier *nested = SS.getScopeRep(); if (!nested) return 0; switch (nested->getKind()) { case NestedNameSpecifier::Global: where = Context.getTranslationUnitDecl(); break; case NestedNameSpecifier::Namespace: where = nested->getAsNamespace(); break; case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Identifier: return 0; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { const Type *ntype = nested->getAsType(); where = ntype->getAsCXXRecordDecl(); if (!where) return 0; break; } case NestedNameSpecifier::Super: // Microsoft's __super:: return 0; }; } } else if (P.getCurToken().is(clang::tok::annot_typename)) { // A deduced template? // P.getTypeAnnotation() takes a non-const Token& until clang r306291. //auto ParsedTy = P.getTypeAnnotation(P.getCurToken()); auto ParsedTy = ParsedType::getFromOpaquePtr(P.getCurToken().getAnnotationValue()); if (ParsedTy) { QualType QT = ParsedTy.get(); const Type* TyPtr = QT.getTypePtr(); if (const auto *LocInfoTy = dyn_cast(TyPtr)) TyPtr = LocInfoTy->getType().getTypePtr(); TyPtr = TyPtr->getUnqualifiedDesugaredType(); if (const auto *DTST = dyn_cast(TyPtr)) { if (auto TD = DTST->getTemplateName().getAsTemplateDecl()) { if (auto CTD = dyn_cast(TD)) return CTD; } } } } else if (P.getCurToken().is(clang::tok::identifier)) { // We have a single indentifier, let's look for it in the // the global scope. where = Context.getTranslationUnitDecl(); } if (where) { // Great we now have a scope and something to search for,let's go ahead. Interpreter::PushTransactionRAII pushedT(m_Interpreter); DeclContext::lookup_result R = where->lookup(P.getCurToken().getIdentifierInfo()); for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) { ClassTemplateDecl *theDecl = dyn_cast(*I); if (theDecl) return theDecl; } } return 0; } const ValueDecl* LookupHelper::findDataMember(const clang::Decl* scopeDecl, llvm::StringRef dataName, DiagSetting diagOnOff) const { // Lookup a data member based on its Decl(Context), name. Parser& P = *m_Parser; Sema& S = P.getActions(); Preprocessor& PP = S.getPreprocessor(); IdentifierInfo *dataII = &PP.getIdentifierTable().get(dataName); DeclarationName decl_name( dataII ); const clang::DeclContext *dc = llvm::cast(scopeDecl); Interpreter::PushTransactionRAII pushedT(m_Interpreter); DeclContext::lookup_result lookup = const_cast(dc)->lookup(decl_name); for (DeclContext::lookup_iterator I = lookup.begin(), E = lookup.end(); I != E; ++I) { const ValueDecl *result = dyn_cast(*I); if (result && !isa(result)) return result; } return 0; } static DeclContext* getContextAndSpec(CXXScopeSpec &SS, const Decl* scopeDecl, ASTContext& Context, Sema &S) { // // Some validity checks on the passed decl. // DeclContext* foundDC = dyn_cast(const_cast(scopeDecl)); if (foundDC->isDependentContext()) { // Passed decl is a template, we cannot use it. return 0; } if (scopeDecl->isInvalidDecl()) { // if the decl is invalid try to clean up UnloadDecl(&S, const_cast(scopeDecl)); return 0; } // // Convert the passed decl into a nested name specifier, // a scope spec, and a decl context. // NestedNameSpecifier* classNNS = 0; if (const NamespaceDecl* NSD = dyn_cast(scopeDecl)) { classNNS = NestedNameSpecifier::Create(Context, 0, const_cast(NSD)); SS.MakeTrivial(Context, classNNS, scopeDecl->getSourceRange()); return foundDC; } else if (const RecordDecl* RD = dyn_cast(scopeDecl)) { const Type* T = Context.getRecordType(RD).getTypePtr(); classNNS = NestedNameSpecifier::Create(Context, 0, false, T); // We pass a 'random' but valid source range. SS.MakeTrivial(Context, classNNS, scopeDecl->getSourceRange()); if (S.RequireCompleteDeclContext(SS, foundDC)) { // Forward decl or instantiation failure, we cannot use it. return 0; } return foundDC; } else if (llvm::isa(scopeDecl)) { // We pass a 'random' but valid source range. SS.MakeGlobal(Context,scopeDecl->getLocation()); return foundDC; } // Not a namespace or class, we cannot use it. return 0; } static DeclContext* getCompleteContext(const Decl* scopeDecl, ASTContext& Context, Sema &S) { // // Some validity checks on the passed decl. // DeclContext* foundDC = dyn_cast(const_cast(scopeDecl)); if (foundDC->isDependentContext()) { // Passed decl is a template, we cannot use it. return 0; } if (scopeDecl->isInvalidDecl()) { // if the decl is invalid try to clean up UnloadDecl(&S, const_cast(scopeDecl)); return 0; } // // Convert the passed decl into a nested name specifier, // a scope spec, and a decl context. // if (isa(scopeDecl)) { return foundDC; } else if (const RecordDecl* RD = dyn_cast(scopeDecl)) { if (RD->getDefinition()) { // We are already complete, we are done. return foundDC; } else { //const Type* T = Context.getRecordType(RD).getTypePtr(); const Type* T = Context.getTypeDeclType(RD).getTypePtr(); NestedNameSpecifier* classNNS = NestedNameSpecifier::Create(Context, 0, false, T); // We pass a 'random' but valid source range. CXXScopeSpec SS; SS.MakeTrivial(Context, classNNS, scopeDecl->getSourceRange()); if (S.RequireCompleteDeclContext(SS, foundDC)) { // Forward decl or instantiation failure, we cannot use it. return 0; } } } else if (llvm::isa(scopeDecl)) { return dyn_cast(const_cast(scopeDecl)); } else { // Not a namespace or class, we cannot use it. return 0; } return foundDC; } static bool FuncArgTypesMatch(const ASTContext& C, const llvm::SmallVectorImpl &GivenArgs, const FunctionProtoType* FPT) { // FIXME: What if FTP->arg_size() != GivenArgTypes.size()? FunctionProtoType::param_type_iterator ATI = FPT->param_type_begin(); FunctionProtoType::param_type_iterator E = FPT->param_type_end(); llvm::SmallVectorImpl::const_iterator GAI = GivenArgs.begin(); for (; ATI && (ATI != E); ++ATI, ++GAI) { if ((*GAI)->isLValue()) { // If the user specified a reference we may have transform it into // an LValue non reference (See getExprProto) to have it in a form // useful for the lookup. So we are a bit sloppy per se here (maybe) const ReferenceType *RefType = (*ATI)->getAs(); if (RefType) { if (!C.hasSameType(RefType->getPointeeType(),(*GAI)->getType())) return false; } else if (!C.hasSameType(*ATI,(*GAI)->getType())) { return false; } } else if (!C.hasSameType(*ATI, (*GAI)->getType() )) { return false; } } return true; } static bool IsOverload(const ASTContext& C, const TemplateArgumentListInfo* FuncTemplateArgs, const llvm::SmallVectorImpl &GivenArgs, const FunctionDecl* FD) { //FunctionTemplateDecl* FTD = FD->getDescribedFunctionTemplate(); QualType FQT = C.getCanonicalType(FD->getType()); if (llvm::isa(FQT.getTypePtr())) { // A K&R-style function (no prototype), is considered to match the args. return false; } const FunctionProtoType* FPT = llvm::cast(FQT); if ((GivenArgs.size() != FPT->getNumParams()) || //(GivenArgsAreEllipsis != FPT->isVariadic()) || !FuncArgTypesMatch(C, GivenArgs, FPT)) { return true; } return false; } static const FunctionDecl* overloadFunctionSelector(DeclContext* foundDC, bool objectIsConst, const llvm::SmallVectorImpl &GivenArgs, LookupResult &Result, DeclarationNameInfo &FuncNameInfo, const TemplateArgumentListInfo* FuncTemplateArgs, ASTContext& Context, Parser &P, Sema &S, LookupHelper::DiagSetting diagOnOff) { // // Our return value. // FunctionDecl* TheDecl = 0; // // If we are looking up a member function, construct // the implicit object argument. // // Note: For now this is always a non-CV qualified lvalue. // QualType ClassType; Expr::Classification ObjExprClassification; if (CXXRecordDecl* CRD = dyn_cast(foundDC)) { if (objectIsConst) ClassType = Context.getTypeDeclType(CRD).getCanonicalType().withConst(); else ClassType = Context.getTypeDeclType(CRD).getCanonicalType(); OpaqueValueExpr ObjExpr(SourceLocation(), ClassType, VK_LValue); ObjExprClassification = ObjExpr.Classify(Context); } // // Tell the diagnostic engine to ignore all diagnostics. // bool OldSuppressAllDiagnostics = S.getDiagnostics().getSuppressAllDiagnostics(); S.getDiagnostics().setSuppressAllDiagnostics( diagOnOff == LookupHelper::NoDiagnostics); struct ResetDiagSuppression { bool _Old; Sema& _S; ResetDiagSuppression(Sema &S, bool Old): _Old(Old), _S(S) {} ~ResetDiagSuppression() { _S.getDiagnostics().setSuppressAllDiagnostics(_Old); } } DiagSuppressionRAII(S, OldSuppressAllDiagnostics); // // Construct the overload candidate set. // OverloadCandidateSet Candidates(FuncNameInfo.getLoc(), OverloadCandidateSet::CSK_Normal); for (LookupResult::iterator I = Result.begin(), E = Result.end(); I != E; ++I) { NamedDecl* ND = *I; if (FunctionDecl* FD = dyn_cast(ND)) { if (isa(FD) && !cast(FD)->isStatic() && !isa(FD)) { // Class method, not static, not a constructor, so has // an implicit object argument. CXXMethodDecl* MD = cast(FD); if (FuncTemplateArgs && (FuncTemplateArgs->size() != 0)) { // Explicit template args were given, cannot use a plain func. continue; } S.AddMethodCandidate(MD, I.getPair(), MD->getParent(), /*ObjectType=*/ClassType, /*ObjectClassification=*/ObjExprClassification, llvm::ArrayRef(GivenArgs.data(), GivenArgs.size()), Candidates); } else { const FunctionProtoType* Proto = dyn_cast( FD->getType()->getAs()); if (!Proto) { // Function has no prototype, cannot do overloading. continue; } if (FuncTemplateArgs && (FuncTemplateArgs->size() != 0)) { // Explicit template args were given, cannot use a plain func. continue; } S.AddOverloadCandidate(FD, I.getPair(), llvm::ArrayRef(GivenArgs.data(), GivenArgs.size()), Candidates); } } else if (FunctionTemplateDecl* FTD = dyn_cast(ND)) { if (isa(FTD->getTemplatedDecl()) && !cast(FTD->getTemplatedDecl())->isStatic() && !isa(FTD->getTemplatedDecl())) { // Class method template, not static, not a constructor, so has // an implicit object argument. S.AddMethodTemplateCandidate( FTD, I.getPair(), cast(FTD->getDeclContext()), const_cast(FuncTemplateArgs), /*ObjectType=*/ClassType, /*ObjectClassification=*/ObjExprClassification, llvm::ArrayRef(GivenArgs.data(), GivenArgs.size()), Candidates); } else { S.AddTemplateOverloadCandidate( FTD, I.getPair(), const_cast(FuncTemplateArgs), llvm::ArrayRef(GivenArgs.data(), GivenArgs.size()), Candidates, /*SuppressUserConversions=*/false); } } else { // Is there any other cases? } } // // Find the best viable function from the set. // { OverloadCandidateSet::iterator Best; OverloadingResult OR = Candidates.BestViableFunction(S, Result.getNameLoc(), Best); if (OR == OR_Success) { TheDecl = Best->Function; // We prefer to get the canonical decl for consistency and ease // of comparison. TheDecl = TheDecl->getCanonicalDecl(); if (TheDecl->isTemplateInstantiation() && !TheDecl->isDefined()) { S.InstantiateFunctionDefinition(SourceLocation(), TheDecl, true /*recursive instantiation*/); } if (TheDecl->isInvalidDecl()) { // if the decl is invalid try to clean up UnloadDecl(&S, const_cast(TheDecl)); return 0; } } } return TheDecl; } static const FunctionDecl* matchFunctionSelector(DeclContext* foundDC, bool objectIsConst, const llvm::SmallVectorImpl &GivenArgs, LookupResult &Result, DeclarationNameInfo &FuncNameInfo, const TemplateArgumentListInfo* FuncTemplateArgs, ASTContext& Context, Parser &P, Sema &S, LookupHelper::DiagSetting diagOnOff) { // // Our return value. // const FunctionDecl* TheDecl = overloadFunctionSelector(foundDC, objectIsConst, GivenArgs, Result, FuncNameInfo, FuncTemplateArgs, Context,P,S, diagOnOff); if (TheDecl) { if ( IsOverload(Context, FuncTemplateArgs, GivenArgs, TheDecl) ) { return 0; } else { // Double check const-ness. if (const clang::CXXMethodDecl *md = llvm::dyn_cast(TheDecl)) { if (md->getMethodQualifiers().hasConst()) { if (!objectIsConst) { TheDecl = 0; } } else { // FIXME: The else should be attached to the if hasConst stmt if (objectIsConst) { TheDecl = 0; } } } } } return TheDecl; } static bool ParseWithShortcuts(DeclContext* foundDC, ASTContext& Context, llvm::StringRef funcName, Interpreter* Interp, UnqualifiedId &FuncId, LookupHelper::DiagSetting diagOnOff, ParserStateRAII &ResetParserState) { // Use a very simple parse step that dectect whether the name search (which // is already supposed to be an unqualified name) is a simple identifier, // a constructor name or a destructor name. In those 3 cases, we can easily // create the UnqualifiedId object that would have resulted from the 'real' // parse. By using this direct creation of the UnqualifiedId, we avoid the // 'permanent' cost associated with creating a memory buffer and the // associated FileID. // If the name is a template or an operator, we revert to the regular parse // (and its associated permanent cost). // In the operator case, the additional work is in the case of a conversion // operator where we would need to 'quickly' parse the type itself (if want // to avoid the permanent cost). // In the case with the template the problem gets a bit worse as we need to // handle potentially arbitrary spaces and ordering // ('const int' vs 'int const', etc.) Parser &P = const_cast(Interp->getParser()); Sema &S = Interp->getSema(); if (funcName.size() == 0) return false; Preprocessor& PP = S.getPreprocessor(); // See if we can avoid creating the buffer, for now we just look for // simple indentifier, constructor and destructor. if (funcName.size() > 8 && strncmp(funcName.data(),"operator",8) == 0 &&( funcName[8] == ' ' || funcName[8] == '*' || funcName[8] == '%' || funcName[8] == '&' || funcName[8] == '|' || funcName[8] == '/' || funcName[8] == '+' || funcName[8] == '-' || funcName[8] == '(' || funcName[8] == '[' || funcName[8] == '=' || funcName[8] == '!' || funcName[8] == '<' || funcName[8] == '>' || funcName[8] == '-' || funcName[8] == '^') ) { // We have called: // setOperatorFunctionId (SourceLocation OperatorLoc, // OverloadedOperatorKind Op, // SourceLocation SymbolLocations[3]) // or // setConversionFunctionId (SourceLocation OperatorLoc, // ParsedType Ty, SourceLocation EndLoc) } else if (funcName.find('<') != StringRef::npos) { // We might have a template name, // setTemplateId (TemplateIdAnnotation *TemplateId) // or // setConstructorTemplateId (TemplateIdAnnotation *TemplateId) } else if (funcName[0] == '~') { // Destructor. // Let's see if this is our contructor. TagDecl *decl = llvm::dyn_cast(foundDC); if (decl) { // We have a class or struct or something. if (funcName.substr(1).equals(decl->getName())) { ParsedType PT; QualType QT( decl->getTypeForDecl(), 0 ); PT.set(QT); FuncId.setDestructorName(SourceLocation(),PT,SourceLocation()); return true; } } // So it starts with ~ but is not followed by the name of // a class or at least not the one that is the declaration context, // let's try a real parsing, to see if we can do better. } else { // We either have a simple type or a constructor name TagDecl *decl = llvm::dyn_cast(foundDC); if (decl) { // We have a class or struct or something. if (funcName.equals(decl->getName())) { ParsedType PT; QualType QT( decl->getTypeForDecl(), 0 ); PT.set(QT); FuncId.setConstructorName(PT,SourceLocation(),SourceLocation()); } else { IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get(funcName); FuncId.setIdentifier (TypeInfoII, SourceLocation() ); } return true; } else { // We have a namespace like context, it can't be a constructor IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get(funcName); FuncId.setIdentifier (TypeInfoII, SourceLocation() ); return true; } } // // Setup to reparse as a type. // // // Create a fake file to parse the function name. // // FIXME:, TODO: Cleanup that complete mess. ResetParserState.SetSkipToEOF(true); { PP.getDiagnostics().setSuppressAllDiagnostics(diagOnOff == LookupHelper::NoDiagnostics); std::unique_ptr SB(llvm::MemoryBuffer::getMemBufferCopy(funcName.str() + "\n", "lookup.funcname.file")); SourceLocation NewLoc = Interp->getNextAvailableLoc(); FileID FID = S.getSourceManager().createFileID(std::move(SB), SrcMgr::C_User, /*LoadedID*/0, /*LoadedOffset*/0, NewLoc); PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc); PP.Lex(const_cast(P.getCurToken())); } // // Parse the function name. // SourceLocation TemplateKWLoc; CXXScopeSpec SS; { Decl *decl = llvm::dyn_cast(foundDC); getContextAndSpec(SS,decl,Context,S); } if (P.ParseUnqualifiedId(SS, ParsedType(), /*ObjectHadErrors=*/false, /*EnteringContext*/false, /*AllowDestructorName*/true, /*AllowConstructorName*/true, /*AllowDeductionGuide*/ false, &TemplateKWLoc, FuncId)) { // Failed parse, cleanup. return false; } return true; } template T findFunction(DeclContext* foundDC, llvm::StringRef funcName, const llvm::SmallVectorImpl &GivenArgs, bool objectIsConst, ASTContext& Context, Interpreter* Interp, T (*functionSelector)(DeclContext* foundDC, bool objectIsConst, const llvm::SmallVectorImpl &GivenArgs, LookupResult &Result, DeclarationNameInfo &FuncNameInfo, const TemplateArgumentListInfo* FuncTemplateArgs, ASTContext& Context, Parser &P, Sema &S, LookupHelper::DiagSetting diagOnOff), LookupHelper::DiagSetting diagOnOff ) { // Given the correctly types arguments, etc. find the function itself. // // Make the class we are looking up the function // in the current scope to please the constructor // name lookup. We do not need to do this otherwise, // and may be able to remove it in the future if // the way constructors are looked up changes. // Parser &P = const_cast(Interp->getParser()); Sema &S = Interp->getSema(); DeclContext* OldEntity = P.getCurScope()->getEntity(); DeclContext* TUCtx = Context.getTranslationUnitDecl(); P.getCurScope()->setEntity(TUCtx); P.EnterScope(Scope::DeclScope); P.getCurScope()->setEntity(foundDC); P.EnterScope(Scope::DeclScope); Sema::ContextRAII SemaContext(S, foundDC); S.EnterDeclaratorContext(P.getCurScope(), foundDC); UnqualifiedId FuncId; ParserStateRAII ResetParserState(P, false /*skipToEOF*/); if (!ParseWithShortcuts(foundDC, Context, funcName, Interp, FuncId, diagOnOff, ResetParserState)) { // Failed parse, cleanup. // Destroy the scope we created first, and // restore the original. S.ExitDeclaratorContext(P.getCurScope()); P.ExitScope(); P.ExitScope(); P.getCurScope()->setEntity(OldEntity); // Then exit. return 0; } // // Get any template args in the function name. // TemplateArgumentListInfo FuncTemplateArgsBuffer; DeclarationNameInfo FuncNameInfo; const TemplateArgumentListInfo* FuncTemplateArgs; S.DecomposeUnqualifiedId(FuncId, FuncTemplateArgsBuffer, FuncNameInfo, FuncTemplateArgs); // // Lookup the function name in the given class now. // DeclarationName FuncName = FuncNameInfo.getName(); SourceLocation FuncNameLoc = FuncNameInfo.getLoc(); LookupResult Result(S, FuncName, FuncNameLoc, Sema::LookupMemberName, Sema::NotForRedeclaration); Result.suppressDiagnostics(); bool LookupSuccess = true; if (FuncTemplateArgsBuffer.size()) { // It's a template. Calculate the NNS and do qualified template lookup. NestedNameSpecifier* scopeNNS = nullptr; SourceRange scopeSrcRange; if (isa(foundDC)) { scopeNNS = NestedNameSpecifier::GlobalSpecifier(Context); } else if (const auto *foundNS = dyn_cast(foundDC)) { scopeNNS = NestedNameSpecifier::Create(Context, /*NNSPrefix*/ nullptr, foundNS); scopeSrcRange = foundNS->getSourceRange(); } else if (const auto *foundRD = dyn_cast(foundDC)) { // a type const Type* foundTy = Context.getTypeDeclType(foundRD).getTypePtr(); scopeNNS = NestedNameSpecifier::Create(Context, /*NNSPrefix*/ nullptr, /*Template*/ false, foundTy); scopeSrcRange = foundRD->getSourceRange(); } CXXScopeSpec SS; if (scopeNNS) SS.MakeTrivial(Context, scopeNNS, scopeSrcRange); bool MemberOfUnknownSpecialization; S.LookupTemplateName(Result, P.getCurScope(), SS, QualType(), /*EnteringContext*/false, MemberOfUnknownSpecialization); // "Translation" of the TemplateDecl to the specialization is done // in findAnyFunctionSelector() given the ExplicitTemplateArgs. if (Result.empty()) LookupSuccess = false; } else { LookupSuccess = S.LookupQualifiedName(Result, foundDC); } if (!LookupSuccess) { // Lookup failed. // Destroy the scope we created first, and // restore the original. S.ExitDeclaratorContext(P.getCurScope()); P.ExitScope(); P.ExitScope(); P.getCurScope()->setEntity(OldEntity); // Then cleanup and exit. return 0; } // // Destroy the scope we created, and restore the original. // S.ExitDeclaratorContext(P.getCurScope()); P.ExitScope(); P.ExitScope(); P.getCurScope()->setEntity(OldEntity); // // Check for lookup failure. // if (Result.getResultKind() != LookupResult::Found && Result.getResultKind() != LookupResult::FoundOverloaded) { // Lookup failed. return 0; } return functionSelector(foundDC,objectIsConst,GivenArgs, Result, FuncNameInfo, FuncTemplateArgs, Context, P, S, diagOnOff); } template returnType execFindFunction(Parser &P, Interpreter* Interp, LookupHelper &LH, const clang::Decl* scopeDecl, llvm::StringRef funcName, const typename DigestArgsInput::ArgsInput &funcArgs, bool objectIsConst, returnType (*functionSelector)(DeclContext* foundDC, bool objectIsConst, const llvm::SmallVectorImpl &GivenArgs, LookupResult &Result, DeclarationNameInfo &FuncNameInfo, const TemplateArgumentListInfo* FuncTemplateArgs, ASTContext& Context, Parser &P, Sema &S, LookupHelper::DiagSetting diagOnOff), LookupHelper::DiagSetting diagOnOff ) { assert(scopeDecl && "Decl cannot be null"); // // Some utilities. // Sema& S = P.getActions(); ASTContext& Context = S.getASTContext(); // // Convert the passed decl into a nested name specifier, // a scope spec, and a decl context. // // Do this 'early' to save on the expansive parser setup, // in case of failure. // DeclContext* foundDC = getCompleteContext(scopeDecl,Context,S); if (!foundDC) return 0; DigestArgsInput inputEval; llvm::SmallVector GivenArgs; if (!inputEval(GivenArgs,funcArgs,diagOnOff,P,Interp,LH)) return 0; Interpreter::PushTransactionRAII pushedT(Interp); return findFunction(foundDC, funcName, GivenArgs, objectIsConst, Context, Interp, functionSelector, diagOnOff); } struct NoParse { typedef const char* ArgsInput; bool operator()(llvm::SmallVectorImpl & /* GivenArgs */, const ArgsInput &/* funcArgs */, LookupHelper::DiagSetting /* diagOnOff */, Parser & /* P */, const Interpreter* /* Interp */, const LookupHelper& /* LH */) { return true; } }; struct ExprFromTypes { typedef llvm::SmallVectorImpl ArgsInput; llvm::SmallVector ExprMemory; bool operator()(llvm::SmallVectorImpl &GivenArgs, const ArgsInput &GivenTypes, LookupHelper::DiagSetting /* diagOnOff */, Parser & /* P */, const Interpreter* /* Interp */, LookupHelper& /* LH */) { if (GivenTypes.empty()) return true; else return getExprProto(GivenArgs,GivenTypes); } bool getExprProto(llvm::SmallVectorImpl &GivenArgs, const llvm::SmallVectorImpl &GivenTypes) { // // Create the array of Expr from the array of Types. // assert(!ExprMemory.size() && "Size must be 0"); ExprMemory.resize(GivenTypes.size() + 1); for(size_t i = 0, e = GivenTypes.size(); i < e; ++i) { const clang::QualType QT = GivenTypes[i].getCanonicalType(); { ExprValueKind VK = VK_PRValue; if (QT->getAs()) { VK = VK_LValue; } clang::QualType NonRefQT(QT.getNonReferenceType()); Expr* val = new (&ExprMemory[i]) OpaqueValueExpr(SourceLocation(), NonRefQT, VK); GivenArgs.push_back(val); } } return true; } }; struct ParseProto { typedef llvm::StringRef ArgsInput; llvm::SmallVector ExprMemory; bool operator()(llvm::SmallVectorImpl &GivenArgs, const ArgsInput &funcProto, LookupHelper::DiagSetting diagOnOff, Parser& P, const Interpreter* Interp, LookupHelper& LH) { if (funcProto.empty()) return true; else return Parse(GivenArgs,funcProto,diagOnOff, P, Interp, LH); } bool Parse(llvm::SmallVectorImpl &GivenArgs, const ArgsInput &funcProto, LookupHelper::DiagSetting diagOnOff, Parser& P, const Interpreter* Interp, LookupHelper& LH) { // // Parse the prototype now. // StartParsingRAII ParseStarted(LH, funcProto, llvm::StringRef("func.prototype.file"), diagOnOff); // ParseTypeName might trigger deserialization. Interpreter::PushTransactionRAII TforDeser(Interp); unsigned int nargs = 0; while (P.getCurToken().isNot(tok::eof)) { TypeResult Res(P.ParseTypeName()); if (!Res.isUsable()) { // Bad parse, done. return false; } TypeSourceInfo *TSI = 0; clang::QualType QT = clang::Sema::GetTypeFromParser(Res.get(), &TSI); QT = QT.getCanonicalType(); { ExprValueKind VK = VK_PRValue; if (QT->getAs()) { VK = VK_LValue; } // FIXME: This is potentially dangerous because if the capacity exceeds // the reserved capacity of ExprMemory, it will reallocate and cause // memory corruption on the OpaqueValueExpr. See ROOT-7749. clang::QualType NonRefQT(QT.getNonReferenceType()); ExprMemory.resize(++nargs); new (&ExprMemory[nargs-1]) OpaqueValueExpr(TSI->getTypeLoc().getBeginLoc(), NonRefQT, VK); } // Type names should be comma separated. // FIXME: Here if we have type followed by name won't work. Eg int f, ... if (!P.getCurToken().is(clang::tok::comma)) { break; } // Eat the comma. P.ConsumeToken(); } for(unsigned int slot = 0; slot < nargs; ++slot) { Expr* val = (OpaqueValueExpr*)( &ExprMemory[slot] ); GivenArgs.push_back(val); } if (P.getCurToken().isNot(tok::eof)) { // We did not consume all of the prototype, bad parse. return false; } // // Cleanup after prototype parse. // P.SkipUntil(clang::tok::eof); // Doesn't reset the diagnostic mappings Sema& S = P.getActions(); S.getDiagnostics().Reset(/*soft=*/true); return true; } }; static const FunctionTemplateDecl* findFunctionTemplateSelector(DeclContext* , bool /* objectIsConst */, const llvm::SmallVectorImpl &, LookupResult &Result, DeclarationNameInfo &, const TemplateArgumentListInfo* ExplicitTemplateArgs, ASTContext&, Parser &, Sema &S, LookupHelper::DiagSetting diagOnOff) { // // Check for lookup failure. // if (Result.empty()) return 0; if (Result.isSingleResult()) return dyn_cast(Result.getFoundDecl()); else { for (LookupResult::iterator I = Result.begin(), E = Result.end(); I != E; ++I) { NamedDecl* ND = *I; FunctionTemplateDecl *MethodTmpl =dyn_cast(ND); if (MethodTmpl) { return MethodTmpl; } } return 0; } } const FunctionTemplateDecl* LookupHelper::findFunctionTemplate(const clang::Decl* scopeDecl, llvm::StringRef templateName, DiagSetting diagOnOff, bool objectIsConst) const { // Lookup a function template based on its Decl(Context), name. return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, templateName, "", objectIsConst, findFunctionTemplateSelector, diagOnOff); } static const FunctionDecl* findAnyFunctionSelector(DeclContext* , bool /* objectIsConst */, const llvm::SmallVectorImpl &, LookupResult &Result, DeclarationNameInfo &, const TemplateArgumentListInfo* ExplicitTemplateArgs, ASTContext&, Parser &, Sema &S, LookupHelper::DiagSetting diagOnOff) { // // Check for lookup failure. // if (Result.empty()) return 0; if (Result.isSingleResult()) return dyn_cast(Result.getFoundDecl()); else { NamedDecl *aResult = *(Result.begin()); FunctionDecl *res = dyn_cast(aResult); if (res) return res; FunctionTemplateDecl *MethodTmpl =dyn_cast(aResult); if (MethodTmpl) { if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size()==0) { // Not argument was specified, any instantiation will do. if (MethodTmpl->spec_begin() != MethodTmpl->spec_end()) { return *( MethodTmpl->spec_begin() ); } } // pick a specialization that result match the given arguments SourceLocation loc; sema::TemplateDeductionInfo Info(loc); FunctionDecl *fdecl = 0; Sema::TemplateDeductionResult TemplDedResult = S.DeduceTemplateArguments(MethodTmpl, const_cast(ExplicitTemplateArgs), fdecl, Info); if (TemplDedResult != Sema::TDK_Success) { // Deduction failure. return 0; } else { // Instantiate the function if needed. if (!fdecl->isDefined()) S.InstantiateFunctionDefinition(loc, fdecl, true /*recursive instantiation*/); if (fdecl->isInvalidDecl()) { // if the decl is invalid try to clean up UnloadDecl(&S, fdecl); return 0; } return fdecl; } } return 0; } } const FunctionDecl* LookupHelper::findAnyFunction(const clang::Decl*scopeDecl, llvm::StringRef funcName, DiagSetting diagOnOff, bool objectIsConst) const { return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, funcName, "", objectIsConst, findAnyFunctionSelector, diagOnOff); } const FunctionDecl* LookupHelper::findFunctionProto(const Decl* scopeDecl, llvm::StringRef funcName, const llvm::SmallVectorImpl& funcProto, DiagSetting diagOnOff, bool objectIsConst) const { assert(scopeDecl && "Decl cannot be null"); return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, funcName, funcProto, objectIsConst, overloadFunctionSelector, diagOnOff); } const FunctionDecl* LookupHelper::findFunctionProto(const Decl* scopeDecl, llvm::StringRef funcName, llvm::StringRef funcProto, DiagSetting diagOnOff, bool objectIsConst) const{ assert(scopeDecl && "Decl cannot be null"); return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, funcName, funcProto, objectIsConst, overloadFunctionSelector, diagOnOff); } const FunctionDecl* LookupHelper::matchFunctionProto(const Decl* scopeDecl, llvm::StringRef funcName, llvm::StringRef funcProto, DiagSetting diagOnOff, bool objectIsConst) const { assert(scopeDecl && "Decl cannot be null"); return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, funcName, funcProto, objectIsConst, matchFunctionSelector, diagOnOff); } const FunctionDecl* LookupHelper::matchFunctionProto(const Decl* scopeDecl, llvm::StringRef funcName, const llvm::SmallVectorImpl& funcProto, DiagSetting diagOnOff, bool objectIsConst) const { assert(scopeDecl && "Decl cannot be null"); return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, funcName, funcProto, objectIsConst, matchFunctionSelector, diagOnOff); } struct ParseArgs { typedef llvm::StringRef ArgsInput; bool operator()(llvm::SmallVectorImpl &GivenArgs, const ArgsInput &funcArgs, LookupHelper::DiagSetting diagOnOff, Parser &P, const Interpreter* Interp, LookupHelper& LH) { if (funcArgs.empty()) return true; else return Parse(GivenArgs,funcArgs,diagOnOff, P, Interp, LH); } bool Parse(llvm::SmallVectorImpl &GivenArgs, llvm::StringRef funcArgs, LookupHelper::DiagSetting diagOnOff, Parser &P, const Interpreter* Interp, LookupHelper& LH) { // // Parse the arguments now. // Interpreter::PushTransactionRAII TforDeser(Interp); StartParsingRAII ParseStarted(LH, funcArgs, llvm::StringRef("func.args.file"), diagOnOff); Sema& S = P.getActions(); ASTContext& Context = S.getASTContext(); PrintingPolicy Policy(Context.getPrintingPolicy()); Policy.SuppressTagKeyword = true; Policy.SuppressUnwrittenScope = true; Policy.SuppressInitializers = true; Policy.AnonymousTagLocations = false; std::string proto; { bool first_time = true; while (P.getCurToken().isNot(tok::eof)) { ExprResult Res = P.ParseAssignmentExpression(); if (Res.isUsable()) { Expr* expr = Res.get(); GivenArgs.push_back(expr); if (first_time) { first_time = false; } else { proto += ','; } stdstrstream tmp; expr->printPretty(tmp, /*PrinterHelper=*/0, Policy, /*Indentation=*/0); proto += tmp.str(); } if (!P.getCurToken().is(tok::comma)) { break; } P.ConsumeToken(); } } // For backward compatibility with CINT accept (for now?) a trailing close // parenthesis. if (P.getCurToken().isNot(tok::eof) && P.getCurToken().isNot(tok::r_paren) ) { // We did not consume all of the arg list, bad parse. return false; } // // Cleanup after the arg list parse. // P.SkipUntil(clang::tok::eof); // Doesn't reset the diagnostic mappings S.getDiagnostics().Reset(/*soft=*/true); return true; } }; const FunctionDecl* LookupHelper::findFunctionArgs(const Decl* scopeDecl, llvm::StringRef funcName, llvm::StringRef funcArgs, DiagSetting diagOnOff, bool objectIsConst) const { assert(scopeDecl && "Decl cannot be null"); return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, funcName, funcArgs, objectIsConst, overloadFunctionSelector, diagOnOff); } void LookupHelper::findArgList(llvm::StringRef argList, llvm::SmallVectorImpl& argExprs, DiagSetting diagOnOff) const { if (argList.empty()) return; // // Some utilities. // // Use P for shortness Parser& P = *m_Parser; StartParsingRAII ParseStarted(const_cast(*this), argList, llvm::StringRef("arg.list.file"), diagOnOff); // // Parse the arguments now. // { bool hasUnusableResult = false; while (P.getCurToken().isNot(tok::eof)) { ExprResult Res = P.ParseAssignmentExpression(); if (Res.isUsable()) { argExprs.push_back(Res.get()); } else { hasUnusableResult = true; break; } if (!P.getCurToken().is(tok::comma)) { break; } P.ConsumeToken(); } if (hasUnusableResult) // if one of the arguments is not usable return empty. argExprs.clear(); } } static bool hasFunctionSelector(DeclContext* , bool /* objectIsConst */, const llvm::SmallVectorImpl &, LookupResult &Result, DeclarationNameInfo &, const TemplateArgumentListInfo* , ASTContext&, Parser &, Sema &, LookupHelper::DiagSetting /*diagOnOff*/) { // // Check for lookup failure. // if (Result.empty()) return false; if (Result.isSingleResult()) return isa(Result.getFoundDecl()); // We have many - those must be functions. return true; } bool LookupHelper::hasFunction(const clang::Decl* scopeDecl, llvm::StringRef funcName, DiagSetting diagOnOff) const { return execFindFunction(*m_Parser, m_Interpreter, const_cast(*this), scopeDecl, funcName, "", false /* objectIsConst */, hasFunctionSelector, diagOnOff); } static const clang::Type* getType(LookupHelper* LH, llvm::StringRef Type) { QualType Qt = LH->findType(Type, LookupHelper::WithDiagnostics); assert(!Qt.isNull() && "Type should exist"); return Qt.getTypePtr(); } LookupHelper::StringType LookupHelper::getStringType(const clang::Type* Type) { assert(Type && "Type cannot be null"); const Transaction*& Cache = m_Interpreter->getStdStringTransaction(); if (!Cache || !m_StringTy[kStdString]) { // getStringType can be called multiple times with Cache being null, and // the local cache should be discarded when that occurs. if (!Cache) m_StringTy = {{}}; QualType Qt = findType("std::string", WithDiagnostics); m_StringTy[kStdString] = Qt.isNull() ? nullptr : Qt.getTypePtr(); if (!m_StringTy[kStdString]) return kNotAString; Cache = m_Interpreter->getLatestTransaction(); m_StringTy[kWCharString] = getType(this, "std::wstring"); const clang::LangOptions& LO = m_Interpreter->getCI()->getLangOpts(); if (LO.CPlusPlus11) { m_StringTy[kUTF16Str] = getType(this, "std::u16string"); m_StringTy[kUTF32Str] = getType(this, "std::u32string"); } } ASTContext& Ctx = m_Interpreter->getSema().getASTContext(); for (unsigned I = 0; I < kNumCachedStrings; ++I) { if (m_StringTy[I] && Ctx.hasSameType(Type, m_StringTy[I])) return StringType(I); } return kNotAString; } void LookupHelper::printStats() const { llvm::errs() << "Cached entries: " << m_ParseBufferCache.size() << "\n"; llvm::errs() << "Total parse requests: " << m_TotalParseRequests << "\n"; llvm::errs() << "Cache hits: " << m_CacheHits << "\n"; } } // end namespace cling