#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang-c/Index.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
/// declarations parsed within the precompiled preamble.
std::vector<pch::DeclID> TopLevelDeclsInPreamble;
+ ///
+ /// \defgroup CodeCompleteCaching Code-completion caching
+ ///
+ /// \{
+ ///
+
+ /// \brief Whether we should be caching code-completion results.
+ bool ShouldCacheCodeCompletionResults;
+
+public:
+ /// \brief A cached code-completion result, which may be introduced in one of
+ /// many different contexts.
+ struct CachedCodeCompletionResult {
+ /// \brief The code-completion string corresponding to this completion
+ /// result.
+ CodeCompletionString *Completion;
+
+ /// \brief A bitmask that indicates which code-completion contexts should
+ /// contain this completion result.
+ ///
+ /// The bits in the bitmask correspond to the values of
+ /// CodeCompleteContext::Kind. To map from a completion context kind to a
+ /// bit, subtract one from the completion context kind and shift 1 by that
+ /// number of bits. Many completions can occur in several different
+ /// contexts.
+ unsigned ShowInContexts;
+
+ /// \brief The priority given to this code-completion result.
+ unsigned Priority;
+
+ /// \brief The libclang cursor kind corresponding to this code-completion
+ /// result.
+ CXCursorKind Kind;
+ };
+
+private:
+ /// \brief The set of cached code-completion results.
+ std::vector<CachedCodeCompletionResult> CachedCompletionResults;
+
+ /// \brief Cache any "global" code-completion results, so that we
+ void CacheCodeCompletionResults();
+
+ /// \brief Clear out and deallocate
+ void ClearCachedCompletionResults();
+
+ ///
+ /// \}
+ ///
+
/// \brief The timers we've created from the various parses, reparses, etc.
/// involved in this translation unit.
std::vector<llvm::Timer *> Timers;
return StoredDiagnostics;
}
+ typedef std::vector<CachedCodeCompletionResult>::iterator
+ cached_completion_iterator;
+
+ cached_completion_iterator cached_completion_begin() {
+ return CachedCompletionResults.begin();
+ }
+
+ cached_completion_iterator cached_completion_end() {
+ return CachedCompletionResults.end();
+ }
+
+ unsigned cached_completion_size() const {
+ return CachedCompletionResults.size();
+ }
+
/// \brief Whether this AST represents a complete translation unit.
///
/// If false, this AST is only a partial translation unit, e.g., one
bool OnlyLocalDecls = false,
bool CaptureDiagnostics = false,
bool PrecompilePreamble = false,
- bool CompleteTranslationUnit = true);
+ bool CompleteTranslationUnit = true,
+ bool CacheCodeCompletionResults = false);
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
/// arguments, which must specify exactly one source file.
unsigned NumRemappedFiles = 0,
bool CaptureDiagnostics = false,
bool PrecompilePreamble = false,
- bool CompleteTranslationUnit = true);
+ bool CompleteTranslationUnit = true,
+ bool CacheCodeCompletionResults = false);
/// \brief Reparse the source files using the same command-line options that
/// were originally used to produce this translation unit.
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "clang-c/Index.h"
#include <memory>
#include <string>
/// \brief The priority of this particular code-completion result.
unsigned Priority;
+ /// \brief The cursor kind that describes this result.
+ CXCursorKind CursorKind;
+
/// \brief Specifies which parameter (of a function, Objective-C method,
/// macro, etc.) we should start with when formatting the result.
unsigned StartParameter;
Hidden(false), QualifierIsInformative(QualifierIsInformative),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
DeclaringEntity(false), Qualifier(Qualifier) {
+ computeCursorKind();
}
/// \brief Build a result that refers to a keyword or symbol.
: Kind(RK_Keyword), Keyword(Keyword), Priority(Priority),
StartParameter(0), Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- DeclaringEntity(false), Qualifier(0) { }
+ DeclaringEntity(false), Qualifier(0) {
+ computeCursorKind();
+ }
/// \brief Build a result that refers to a macro.
Result(IdentifierInfo *Macro, unsigned Priority = CCP_Macro)
- : Kind(RK_Macro), Macro(Macro), Priority(Priority), StartParameter(0),
- Hidden(false), QualifierIsInformative(0),
- StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- DeclaringEntity(false), Qualifier(0) { }
+ : Kind(RK_Macro), Macro(Macro), Priority(Priority), StartParameter(0),
+ Hidden(false), QualifierIsInformative(0),
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ DeclaringEntity(false), Qualifier(0) {
+ computeCursorKind();
+ }
/// \brief Build a result that refers to a pattern.
- Result(CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern)
+ Result(CodeCompletionString *Pattern, unsigned Priority = CCP_CodePattern,
+ CXCursorKind CursorKind = CXCursor_NotImplemented)
: Kind(RK_Pattern), Pattern(Pattern), Priority(Priority),
- StartParameter(0), Hidden(false), QualifierIsInformative(0),
- StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- DeclaringEntity(false), Qualifier(0) { }
+ CursorKind(CursorKind), StartParameter(0), Hidden(false),
+ QualifierIsInformative(0), StartsNestedNameSpecifier(false),
+ AllParametersAreInformative(false), DeclaringEntity(false),
+ Qualifier(0)
+ {
+ }
/// \brief Retrieve the declaration stored in this result.
NamedDecl *getDeclaration() const {
/// brief Determine a base priority for the given declaration.
static unsigned getPriorityFromDecl(NamedDecl *ND);
+
+ private:
+ void computeCursorKind();
};
class OverloadCandidate {
Sema &S) const;
};
- CodeCompleteConsumer() : IncludeMacros(false), OutputIsBinary(false) { }
+ CodeCompleteConsumer() : IncludeMacros(false), IncludeCodePatterns(false),
+ OutputIsBinary(false) { }
CodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns,
bool OutputIsBinary)
#define LLVM_CLANG_AST_SEMA_H
#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Template.h"
namespace clang {
class ASTContext;
class ASTConsumer;
- class CodeCompleteConsumer;
class Preprocessor;
class Decl;
class DeclContext;
TypeTy *ReturnType,
IdentifierInfo **SelIdents,
unsigned NumSelIdents);
-
+ void GatherGlobalCodeCompletions(
+ llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results);
//@}
//===--------------------------------------------------------------------===//
ASTUnit::ASTUnit(bool _MainFileIsAST)
: CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked),
- PreambleRebuildCounter(0), SavedMainFileBuffer(0) {
+ PreambleRebuildCounter(0), SavedMainFileBuffer(0),
+ ShouldCacheCodeCompletionResults(false) {
}
ASTUnit::~ASTUnit() {
delete SavedMainFileBuffer;
+ ClearCachedCompletionResults();
+
for (unsigned I = 0, N = Timers.size(); I != N; ++I)
delete Timers[I];
}
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
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:
if (P.createTemporaryFileOnDisk())
return std::string();
- fprintf(stderr, "Preamble file: %s\n", P.str().c_str());
return P.str();
}
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.
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CompleteTranslationUnit = CompleteTranslationUnit;
+ AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation.reset(CI);
CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
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.
CI->getFrontendOpts().DisableFree = true;
return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
CaptureDiagnostics, PrecompilePreamble,
- CompleteTranslationUnit);
+ CompleteTranslationUnit,
+ CacheCodeCompletionResults);
}
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,
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;
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
}
}
-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;
}
}
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?");
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
Diag((*I)->getLocation(), diag::warn_unused_variable)
<< cast<VarDecl>(*I)->getDeclName();
}
+
+ TUScope = 0;
}
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());
+}
}
// RUN: c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: macro definition:{TypedText FOO}{LeftParen (}{Placeholder Arg1}{Comma , }{Placeholder Arg2}{RightParen )}
// RUN: c-index-test -code-completion-at=%s:13:13 %s | FileCheck -check-prefix=CHECK-CC2 %s
// RUN: c-index-test -code-completion-at=%s:14:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
if (getenv("CINDEXTEST_EDITING"))
options |= clang_defaultEditingTranslationUnitOptions();
+ if (getenv("CINDEXTEST_COMPLETION_CACHING"))
+ options |= CXTranslationUnit_CacheCompletionResults;
return options;
}
bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble;
bool CompleteTranslationUnit
= ((options & CXTranslationUnit_Incomplete) == 0);
-
+ bool CacheCodeCompetionResults
+ = options & CXTranslationUnit_CacheCompletionResults;
+
// Configure the diagnostics.
DiagnosticOptions DiagOpts;
llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
RemappedFiles.size(),
/*CaptureDiagnostics=*/true,
PrecompilePreamble,
- CompleteTranslationUnit));
+ CompleteTranslationUnit,
+ CacheCodeCompetionResults));
if (NumErrors != Diags->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
} // end extern "C"
-namespace clang {
- // FIXME: defined in CodeCompleteConsumer.cpp, but should be a
- // static function here.
- CXCursorKind
- getCursorKindForCompletionResult(const CodeCompleteConsumer::Result &R);
-}
-
-
namespace {
class CaptureCompletionResults : public CodeCompleteConsumer {
AllocatedCXCodeCompleteResults &AllocatedResults;
CXStoredCodeCompletionString *StoredCompletion
= new CXStoredCodeCompletionString(Results[I].Priority);
(void)Results[I].CreateCodeCompletionString(S, StoredCompletion);
- AllocatedResults.Results[I].CursorKind
- = getCursorKindForCompletionResult(Results[I]);
+ AllocatedResults.Results[I].CursorKind = Results[I].CursorKind;
AllocatedResults.Results[I].CompletionString = StoredCompletion;
}
}