From: Daniel Dunbar Date: Fri, 13 Nov 2009 08:58:20 +0000 (+0000) Subject: Rework Sema code completion interface. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3a2838d14251427089c39caec90c8abbc27f7a14;p=clang Rework Sema code completion interface. - Provide Sema in callbacks, instead of requiring it in constructor. This eliminates the need for a factory function. Clients now just pass the object to consume the results in directly. - CodeCompleteConsumer is cheap to construct, so building it whenever we are doing code completion is reasonable. Doug, please review. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@87099 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index c436b398f9..5d27b1a90f 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -373,17 +373,18 @@ public: /// \name Code-completion callbacks //@{ /// \brief Process the finalized code-completion results. - virtual void ProcessCodeCompleteResults(Result *Results, + virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, unsigned NumResults) { } - - /// \brief Process the set of overload candidates. + + /// \param S the semantic-analyzer object for which code-completion is being + /// done. /// /// \param CurrentArg the index of the current argument. /// /// \param Candidates an array of overload candidates. /// /// \param NumCandidates the number of overload candidates - virtual void ProcessOverloadCandidates(unsigned CurrentArg, + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates) { } //@} @@ -392,25 +393,21 @@ public: /// \brief A simple code-completion consumer that prints the results it /// receives in a simple format. class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { - /// \brief The semantic-analysis object to which this code-completion - /// consumer is attached. - Sema &SemaRef; - /// \brief The raw output stream. llvm::raw_ostream &OS; public: /// \brief Create a new printing code-completion consumer that prints its /// results to the given raw output stream. - PrintingCodeCompleteConsumer(Sema &S, bool IncludeMacros, + PrintingCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros), SemaRef(S), OS(OS) { } + : CodeCompleteConsumer(IncludeMacros), OS(OS) { } /// \brief Prints the finalized code-completion results. - virtual void ProcessCodeCompleteResults(Result *Results, + virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, unsigned NumResults); - virtual void ProcessOverloadCandidates(unsigned CurrentArg, + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates); }; @@ -418,10 +415,6 @@ public: /// \brief A code-completion consumer that prints the results it receives /// in a format that is parsable by the CIndex library. class CIndexCodeCompleteConsumer : public CodeCompleteConsumer { - /// \brief The semantic-analysis object to which this code-completion - /// consumer is attached. - Sema &SemaRef; - /// \brief The raw output stream. llvm::raw_ostream &OS; @@ -429,14 +422,14 @@ public: /// \brief Create a new CIndex code-completion consumer that prints its /// results to the given raw output stream in a format readable to the CIndex /// library. - CIndexCodeCompleteConsumer(Sema &S, bool IncludeMacros, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros), SemaRef(S), OS(OS) { } + CIndexCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS) + : CodeCompleteConsumer(IncludeMacros), OS(OS) { } /// \brief Prints the finalized code-completion results. - virtual void ProcessCodeCompleteResults(Result *Results, + virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, unsigned NumResults); - virtual void ProcessOverloadCandidates(unsigned CurrentArg, + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates); }; diff --git a/include/clang/Sema/ParseAST.h b/include/clang/Sema/ParseAST.h index 8a245d03cd..f6cff2a023 100644 --- a/include/clang/Sema/ParseAST.h +++ b/include/clang/Sema/ParseAST.h @@ -20,7 +20,7 @@ namespace clang { class ASTContext; class CodeCompleteConsumer; class Sema; - + /// \brief Parse the entire file specified, notifying the ASTConsumer as /// the file is parsed. /// @@ -30,11 +30,13 @@ namespace clang { /// \param CompleteTranslationUnit When true, the parsed file is /// considered to be a complete translation unit, and any /// end-of-translation-unit wrapup will be performed. + /// + /// \param CompletionConsumer If given, an object to consume code completion + /// results. void ParseAST(Preprocessor &pp, ASTConsumer *C, ASTContext &Ctx, bool PrintStats = false, bool CompleteTranslationUnit = true, - CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data) = 0, - void *CreateCodeCompleterData = 0); + CodeCompleteConsumer *CompletionConsumer = 0); } // end namespace clang diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index f94989ee72..3529ece257 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -508,7 +508,8 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { CodeCompleteConsumer::~CodeCompleteConsumer() { } void -PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, +PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, + Result *Results, unsigned NumResults) { // Print the results. for (unsigned I = 0; I != NumResults; ++I) { @@ -552,7 +553,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, } void -PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, +PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, + unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { @@ -570,7 +572,8 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, } void -CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, +CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, + Result *Results, unsigned NumResults) { // Print the results. for (unsigned I = 0; I != NumResults; ++I) { @@ -632,7 +635,8 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, } void -CIndexCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, +CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, + unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index d3f26d875c..9afc8100c7 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -35,15 +35,14 @@ using namespace clang; void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, bool CompleteTranslationUnit, - CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data), - void *CreateCodeCompleterData) { + CodeCompleteConsumer *CompletionConsumer) { // Collect global stats on Decls/Stmts (until we have a module streamer). if (PrintStats) { Decl::CollectingStats(true); Stmt::CollectingStats(true); } - Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit); + Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); Parser P(PP, S); PP.EnterMainSourceFile(); @@ -63,12 +62,6 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, External->StartTranslationUnit(Consumer); } - CodeCompleteConsumer *CodeCompleter = 0; - if (CreateCodeCompleter) { - CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData); - S.setCodeCompleteConsumer(CodeCompleter); - } - Parser::DeclGroupPtrTy ADecl; while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. @@ -87,9 +80,6 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Consumer->HandleTranslationUnit(Ctx); - if (CreateCodeCompleter) - delete CodeCompleter; - if (PrintStats) { fprintf(stderr, "\nSTATISTICS:\n"); P.getActions().PrintStats(); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index f6f572feec..b2bbac8bc2 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -347,10 +347,11 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - bool CompleteTranslationUnit) + bool CompleteTranslationUnit, + CodeCompleteConsumer *CodeCompleter) : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - ExternalSource(0), CodeCompleter(0), CurContext(0), + ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4a6d01b4e2..2324a51650 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -373,7 +373,8 @@ public: bool isSelfExpr(Expr *RExpr); public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - bool CompleteTranslationUnit = true); + bool CompleteTranslationUnit = true, + CodeCompleteConsumer *CompletionConsumer = 0); ~Sema() { if (PackContext) FreePackedContext(); } @@ -3853,7 +3854,6 @@ public: /// \name Code completion //@{ - void setCodeCompleteConsumer(CodeCompleteConsumer *CCC); virtual void CodeCompleteOrdinaryName(Scope *S); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 072dfe9b73..84262a4c8f 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -23,13 +23,6 @@ using namespace clang; -/// \brief Set the code-completion consumer for semantic analysis. -void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) { - assert(((CodeCompleter != 0) != (CCC != 0)) && - "Already set or cleared a code-completion consumer?"); - CodeCompleter = CCC; -} - namespace { /// \brief A container of code-completion results. class ResultBuilder { @@ -1079,14 +1072,15 @@ static void AddMacroResults(Preprocessor &PP, unsigned Rank, Results.ExitScope(); } -static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, - CodeCompleteConsumer::Result *Results, - unsigned NumResults) { +static void HandleCodeCompleteResults(Sema *S, + CodeCompleteConsumer *CodeCompleter, + CodeCompleteConsumer::Result *Results, + unsigned NumResults) { // Sort the results by rank/kind/etc. std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); if (CodeCompleter) - CodeCompleter->ProcessCodeCompleteResults(Results, NumResults); + CodeCompleter->ProcessCodeCompleteResults(*S, Results, NumResults); } void Sema::CodeCompleteOrdinaryName(Scope *S) { @@ -1095,7 +1089,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S) { 0, CurContext, Results); if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, @@ -1120,46 +1114,46 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, ResultBuilder Results(*this, &ResultBuilder::IsMember); unsigned NextRank = 0; - - if (const RecordType *Record = BaseType->getAs()) { - NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, - Record->getDecl(), Results); - - if (getLangOptions().CPlusPlus) { - if (!Results.empty()) { - // The "template" keyword can follow "->" or "." in the grammar. - // However, we only want to suggest the template keyword if something - // is dependent. - bool IsDependent = BaseType->isDependentType(); - if (!IsDependent) { - for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) - if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) { - IsDependent = Ctx->isDependentContext(); - break; - } - } - - if (IsDependent) - Results.MaybeAddResult(Result("template", NextRank++)); + + // If this isn't a record type, we are done. + const RecordType *Record = BaseType->getAs(); + if (!Record) + return; + + NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, + Record->getDecl(), Results); + + if (getLangOptions().CPlusPlus) { + if (!Results.empty()) { + // The "template" keyword can follow "->" or "." in the grammar. + // However, we only want to suggest the template keyword if something + // is dependent. + bool IsDependent = BaseType->isDependentType(); + if (!IsDependent) { + for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent()) + if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) { + IsDependent = Ctx->isDependentContext(); + break; + } } - - // We could have the start of a nested-name-specifier. Add those - // results as well. - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, - CurContext, Results); + + if (IsDependent) + Results.MaybeAddResult(Result("template", NextRank++)); } - - // Add macros - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); - - // Hand off the results found for code completion. - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); - - // We're done! - return; + + // We could have the start of a nested-name-specifier. Add those + // results as well. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, + CurContext, Results); } + + // Add macros + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + + // Hand off the results found for code completion. + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { @@ -1201,7 +1195,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteCase(Scope *S) { @@ -1280,7 +1274,7 @@ void Sema::CodeCompleteCase(Scope *S) { if (CodeCompleter->includeMacros()) AddMacroResults(PP, 1, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } namespace { @@ -1352,7 +1346,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, if (Cand->Viable) Results.push_back(ResultCandidate(Cand->Function)); } - CodeCompleter->ProcessOverloadCandidates(NumArgs, Results.data(), + CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), Results.size()); } @@ -1376,7 +1370,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank + 1, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { @@ -1398,7 +1392,7 @@ void Sema::CodeCompleteUsing(Scope *S) { if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteUsingDirective(Scope *S) { @@ -1414,7 +1408,7 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { Results.ExitScope(); if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteNamespaceDecl(Scope *S) { @@ -1450,7 +1444,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { if (CodeCompleter->includeMacros()) AddMacroResults(PP, 1, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { @@ -1463,7 +1457,7 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { 0, CurContext, Results); if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteOperatorName(Scope *S) { @@ -1495,7 +1489,7 @@ void Sema::CodeCompleteOperatorName(Scope *S) { if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { @@ -1523,7 +1517,7 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { if (!(Attributes & ObjCDeclSpec::DQ_PR_getter)) Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0)); Results.ExitScope(); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName) { @@ -1574,7 +1568,7 @@ void Sema::CodeCompleteObjCFactoryMethod(Scope *S, IdentifierInfo *FName) { } Results.ExitScope(); // This also suppresses remaining diagnostics. - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteObjCInstanceMethod(Scope *S, ExprTy *Receiver) { @@ -1634,5 +1628,5 @@ void Sema::CodeCompleteObjCInstanceMethod(Scope *S, ExprTy *Receiver) { } Results.ExitScope(); // This also suppresses remaining diagnostics. - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index b186f20ed5..5092e1ab32 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -210,19 +210,6 @@ std::string GetBuiltinIncludePath(const char *Argv0) { return P.str(); } -/// \brief Buld a new code-completion consumer that prints the results of -/// code completion to standard output. -static CodeCompleteConsumer *BuildPrintingCodeCompleter(Sema &S, - void *UserData) { - const FrontendOptions &Opts = *(FrontendOptions*)UserData; - if (Opts.DebugCodeCompletionPrinter) - return new PrintingCodeCompleteConsumer(S, Opts.ShowMacrosInCodeCompletion, - llvm::outs()); - - return new CIndexCodeCompleteConsumer(S, Opts.ShowMacrosInCodeCompletion, - llvm::outs()); -} - //===----------------------------------------------------------------------===// // Basic Parser driver //===----------------------------------------------------------------------===// @@ -494,9 +481,7 @@ static void ProcessInputFile(CompilerInstance &CI, const std::string &InFile, if (InitializeSourceManager(PP, CI.getFrontendOpts(), InFile)) return; - CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *) = 0; - void *CreateCodeCompleterData = (void*) &FEOpts; - + llvm::OwningPtr CCConsumer; if (!FEOpts.CodeCompletionAt.FileName.empty()) { // Tell the source manager to chop off the given file at a specific // line and column. @@ -508,7 +493,14 @@ static void ProcessInputFile(CompilerInstance &CI, const std::string &InFile, FEOpts.CodeCompletionAt.Column); // Set up the creation routine for code-completion. - CreateCodeCompleter = BuildPrintingCodeCompleter; + if (FEOpts.DebugCodeCompletionPrinter) + CCConsumer.reset( + new PrintingCodeCompleteConsumer(FEOpts.ShowMacrosInCodeCompletion, + llvm::outs())); + else + CCConsumer.reset( + new CIndexCodeCompleteConsumer(FEOpts.ShowMacrosInCodeCompletion, + llvm::outs())); } else { PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) << FEOpts.CodeCompletionAt.FileName; @@ -518,7 +510,7 @@ static void ProcessInputFile(CompilerInstance &CI, const std::string &InFile, // Run the AST consumer action. ParseAST(PP, Consumer.get(), CI.getASTContext(), FEOpts.ShowStats, CompleteTranslationUnit, - CreateCodeCompleter, CreateCodeCompleterData); + CCConsumer.get()); } else { // Initialize builtin info. PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),