diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 182 | ||||
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 164 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 20 |
4 files changed, 288 insertions, 84 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index e501260af7..e6bae6b727 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -50,7 +50,8 @@ const unsigned DefaultPreambleRebuildInterval = 5; ASTUnit::ASTUnit(bool _MainFileIsAST) : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked), - PreambleRebuildCounter(0), SavedMainFileBuffer(0) { + PreambleRebuildCounter(0), SavedMainFileBuffer(0), + ShouldCacheCodeCompletionResults(false) { } ASTUnit::~ASTUnit() { @@ -75,6 +76,8 @@ ASTUnit::~ASTUnit() { delete SavedMainFileBuffer; + ClearCachedCompletionResults(); + for (unsigned I = 0, N = Timers.size(); I != N; ++I) delete Timers[I]; } @@ -85,6 +88,70 @@ void ASTUnit::CleanTemporaryFiles() { TemporaryFiles.clear(); } +void ASTUnit::CacheCodeCompletionResults() { + if (!TheSema) + return; + + llvm::Timer *CachingTimer = 0; + if (TimerGroup.get()) { + CachingTimer = new llvm::Timer("Cache global code completions", + *TimerGroup); + CachingTimer->startTimer(); + Timers.push_back(CachingTimer); + } + + // Clear out the previous results. + ClearCachedCompletionResults(); + + // Gather the set of global code completions. + typedef CodeCompleteConsumer::Result Result; + llvm::SmallVector<Result, 8> Results; + TheSema->GatherGlobalCodeCompletions(Results); + + // Translate global code completions into cached completions. + for (unsigned I = 0, N = Results.size(); I != N; ++I) { + switch (Results[I].Kind) { + case Result::RK_Declaration: + // FIXME: Handle declarations! + break; + + case Result::RK_Keyword: + case Result::RK_Pattern: + // Ignore keywords and patterns; we don't care, since they are so + // easily regenerated. + break; + + case Result::RK_Macro: { + CachedCodeCompletionResult CachedResult; + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.ShowInContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); + CachedResult.Priority = Results[I].Priority; + CachedResult.Kind = Results[I].CursorKind; + CachedCompletionResults.push_back(CachedResult); + break; + } + } + Results[I].Destroy(); + } + + if (CachingTimer) + CachingTimer->stopTimer(); +} + +void ASTUnit::ClearCachedCompletionResults() { + for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I) + delete CachedCompletionResults[I].Completion; + CachedCompletionResults.clear(); +} + namespace { /// \brief Gathers information from PCHReader that will be used to initialize @@ -542,6 +609,12 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { Clang.takeDiagnosticClient(); Invocation.reset(Clang.takeInvocation()); + + // If we were asked to cache code-completion results and don't have any + // results yet, do so now. + if (ShouldCacheCodeCompletionResults && CachedCompletionResults.empty()) + CacheCodeCompletionResults(); + return false; error: @@ -579,7 +652,6 @@ static std::string GetPreamblePCHPath() { if (P.createTemporaryFileOnDisk()) return std::string(); - fprintf(stderr, "Preamble file: %s\n", P.str().c_str()); return P.str(); } @@ -1044,7 +1116,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CompleteTranslationUnit) { + bool CompleteTranslationUnit, + bool CacheCodeCompletionResults) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -1059,6 +1132,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->CaptureDiagnostics = CaptureDiagnostics; AST->OnlyLocalDecls = OnlyLocalDecls; AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->Invocation.reset(CI); CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; @@ -1097,7 +1171,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, unsigned NumRemappedFiles, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CompleteTranslationUnit) { + bool CompleteTranslationUnit, + bool CacheCodeCompletionResults) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -1159,7 +1234,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, CI->getFrontendOpts().DisableFree = true; return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls, CaptureDiagnostics, PrecompilePreamble, - CompleteTranslationUnit); + CompleteTranslationUnit, + CacheCodeCompletionResults); } bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { @@ -1196,6 +1272,91 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { return Result; } +//----------------------------------------------------------------------------// +// Code completion +//----------------------------------------------------------------------------// + +namespace { + /// \brief Code completion consumer that combines the cached code-completion + /// results from an ASTUnit with the code-completion results provided to it, + /// then passes the result on to + class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer { + unsigned NormalContexts; + ASTUnit &AST; + CodeCompleteConsumer &Next; + + public: + AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next, + bool IncludeMacros, bool IncludeCodePatterns) + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, + Next.isOutputBinary()), AST(AST), Next(Next) + { + // Compute the set of contexts in which we will look when we don't have + // any information about the specific context. + NormalContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) + | (1 << (CodeCompletionContext::CCC_MemberAccess - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); + + if (AST.getASTContext().getLangOptions().CPlusPlus) + NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)) + | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) + | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)); + } + + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + Result *Results, + unsigned NumResults) { + // Merge the results we were given with the results we cached. + bool AddedResult = false; + unsigned InContexts = + (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts + : (1 << (Context.getKind() - 1))); + typedef CodeCompleteConsumer::Result Result; + llvm::SmallVector<Result, 8> AllResults; + for (ASTUnit::cached_completion_iterator + C = AST.cached_completion_begin(), + CEnd = AST.cached_completion_end(); + C != CEnd; ++C) { + // If the context we are in matches any of the contexts we are + // interested in, we'll add this result. + if ((C->ShowInContexts & InContexts) == 0) + continue; + + // If we haven't added any results previously, do so now. + if (!AddedResult) { + AllResults.insert(AllResults.end(), Results, Results + NumResults); + AddedResult = true; + } + + AllResults.push_back(Result(C->Completion, C->Priority, C->Kind)); + } + + // If we did not add any cached completion results, just forward the + // results we were given to the next consumer. + if (!AddedResult) { + Next.ProcessCodeCompleteResults(S, Context, Results, NumResults); + return; + } + + Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), + AllResults.size()); + } + + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); + } + }; +} void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, @@ -1223,7 +1384,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts(); PreprocessorOptions &PreprocessorOpts = CCInvocation.getPreprocessorOpts(); - FrontendOpts.ShowMacrosInCodeCompletion = IncludeMacros; + FrontendOpts.ShowMacrosInCodeCompletion + = IncludeMacros && CachedCompletionResults.empty(); FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns; FrontendOpts.CodeCompletionAt.FileName = File; FrontendOpts.CodeCompletionAt.Line = Line; @@ -1281,8 +1443,12 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, RemappedFiles[I].second); - // Use the code completion consumer we were given. - Clang.setCodeCompletionConsumer(&Consumer); + // Use the code completion consumer we were given, but adding any cached + // code-completion results. + AugmentedCodeCompleteConsumer + AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion, + FrontendOpts.ShowCodePatternsInCodeCompletion); + Clang.setCodeCompletionConsumer(&AugmentedConsumer); // If we have a precompiled preamble, try to use it. We only allow // the use of the precompiled preamble if we're if the completion diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 6f4e1839e3..c1b666a792 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -496,95 +496,109 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, } } -namespace clang { - // FIXME: Used externally by CIndexCodeCompletion.cpp; this code - // will move there, eventually, when the CIndexCodeCompleteConsumer - // dies. - CXCursorKind - getCursorKindForCompletionResult(const CodeCompleteConsumer::Result &R) { - typedef CodeCompleteConsumer::Result Result; - switch (R.Kind) { - case Result::RK_Declaration: - switch (R.Declaration->getKind()) { - case Decl::Record: - case Decl::CXXRecord: - case Decl::ClassTemplateSpecialization: { - RecordDecl *Record = cast<RecordDecl>(R.Declaration); - if (Record->isStruct()) - return CXCursor_StructDecl; - else if (Record->isUnion()) - return CXCursor_UnionDecl; - else - return CXCursor_ClassDecl; - } - - case Decl::ObjCMethod: { - ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration); - if (Method->isInstanceMethod()) - return CXCursor_ObjCInstanceMethodDecl; - else - return CXCursor_ObjCClassMethodDecl; - } - - case Decl::Typedef: - return CXCursor_TypedefDecl; - - case Decl::Enum: - return CXCursor_EnumDecl; +void CodeCompleteConsumer::Result::computeCursorKind() { + switch (Kind) { + case RK_Declaration: + switch (Declaration->getKind()) { + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: { + RecordDecl *Record = cast<RecordDecl>(Declaration); + if (Record->isStruct()) + CursorKind = CXCursor_StructDecl; + else if (Record->isUnion()) + CursorKind = CXCursor_UnionDecl; + else + CursorKind = CXCursor_ClassDecl; + break; + } + + case Decl::ObjCMethod: { + ObjCMethodDecl *Method = cast<ObjCMethodDecl>(Declaration); + if (Method->isInstanceMethod()) + CursorKind = CXCursor_ObjCInstanceMethodDecl; + else + CursorKind = CXCursor_ObjCClassMethodDecl; + break; + } + + case Decl::Typedef: + CursorKind = CXCursor_TypedefDecl; + break; - case Decl::Field: - return CXCursor_FieldDecl; + case Decl::Enum: + CursorKind = CXCursor_EnumDecl; + break; - case Decl::EnumConstant: - return CXCursor_EnumConstantDecl; + case Decl::Field: + CursorKind = CXCursor_FieldDecl; + break; - case Decl::Function: - case Decl::CXXMethod: - case Decl::CXXConstructor: - case Decl::CXXDestructor: - case Decl::CXXConversion: - return CXCursor_FunctionDecl; + case Decl::EnumConstant: + CursorKind = CXCursor_EnumConstantDecl; + break; - case Decl::Var: - return CXCursor_VarDecl; + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + CursorKind = CXCursor_FunctionDecl; + break; - case Decl::ParmVar: - return CXCursor_ParmDecl; + case Decl::Var: + CursorKind = CXCursor_VarDecl; + break; - case Decl::ObjCInterface: - return CXCursor_ObjCInterfaceDecl; + case Decl::ParmVar: + CursorKind = CXCursor_ParmDecl; + break; - case Decl::ObjCCategory: - return CXCursor_ObjCCategoryDecl; + case Decl::ObjCInterface: + CursorKind = CXCursor_ObjCInterfaceDecl; + break; - case Decl::ObjCProtocol: - return CXCursor_ObjCProtocolDecl; + case Decl::ObjCCategory: + CursorKind = CXCursor_ObjCCategoryDecl; + break; - case Decl::ObjCProperty: - return CXCursor_ObjCPropertyDecl; + case Decl::ObjCProtocol: + CursorKind = CXCursor_ObjCProtocolDecl; + break; + + case Decl::ObjCProperty: + CursorKind = CXCursor_ObjCPropertyDecl; + break; - case Decl::ObjCIvar: - return CXCursor_ObjCIvarDecl; + case Decl::ObjCIvar: + CursorKind = CXCursor_ObjCIvarDecl; + break; - case Decl::ObjCImplementation: - return CXCursor_ObjCImplementationDecl; + case Decl::ObjCImplementation: + CursorKind = CXCursor_ObjCImplementationDecl; + break; - case Decl::ObjCCategoryImpl: - return CXCursor_ObjCCategoryImplDecl; + case Decl::ObjCCategoryImpl: + CursorKind = CXCursor_ObjCCategoryImplDecl; + break; - default: - break; - } + default: + CursorKind = CXCursor_NotImplemented; break; - - case Result::RK_Macro: - return CXCursor_MacroDefinition; - - case Result::RK_Keyword: - case Result::RK_Pattern: - return CXCursor_NotImplemented; } - return CXCursor_NotImplemented; + break; + + case Result::RK_Macro: + CursorKind = CXCursor_MacroDefinition; + break; + + case Result::RK_Keyword: + CursorKind = CXCursor_NotImplemented; + break; + + case Result::RK_Pattern: + // Do nothing: Patterns can come with cursor kinds! + break; } } @@ -595,7 +609,7 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, unsigned NumResults) { // Print the results. for (unsigned I = 0; I != NumResults; ++I) { - WriteUnsigned(OS, getCursorKindForCompletionResult(Results[I])); + WriteUnsigned(OS, Results[I].CursorKind); WriteUnsigned(OS, Results[I].Priority); CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); assert(CCS && "No code-completion string?"); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index f5c85ad99c..95f08bdf01 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -269,8 +269,10 @@ void Sema::ActOnEndOfTranslationUnit() { true)), UnusedFileScopedDecls.end()); - if (!CompleteTranslationUnit) + if (!CompleteTranslationUnit) { + TUScope = 0; return; + } // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic @@ -340,6 +342,8 @@ void Sema::ActOnEndOfTranslationUnit() { Diag((*I)->getLocation(), diag::warn_unused_variable) << cast<VarDecl>(*I)->getDeclName(); } + + TUScope = 0; } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index b8fb04425e..31185683a1 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4336,3 +4336,23 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); } + +void Sema::GatherGlobalCodeCompletions( + llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results) { + ResultBuilder Builder(*this); + +#if 0 + // FIXME: We need a name lookup that means "look for everything", + CodeCompletionDeclConsumer Consumer(Builder, + Context.getTranslationUnitDecl()); + LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupOrdinaryName, + Consumer); +#endif + + if (!CodeCompleter || CodeCompleter->includeMacros()) + AddMacroResults(PP, Builder); + + Results.clear(); + Results.insert(Results.end(), + Builder.data(), Builder.data() + Builder.size()); +} |