diff options
-rw-r--r-- | include/clang/AST/CanonicalType.h | 6 | ||||
-rw-r--r-- | include/clang/AST/TypeOrdering.h | 21 | ||||
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 18 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 46 | ||||
-rw-r--r-- | test/Index/complete-exprs.c | 3 |
5 files changed, 81 insertions, 13 deletions
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index a1023a2810..dad4dfc926 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -703,9 +703,9 @@ inline CanQual<Type> CanQual<T>::getNonReferenceType() const { template<typename T> CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) { CanQual<T> Result; - Result.Stored.setFromOpaqueValue(Ptr); - assert((!Result || Result.Stored.isCanonical()) - && "Type is not canonical!"); + Result.Stored = QualType::getFromOpaquePtr(Ptr); + assert((!Result || Result.Stored.getAsOpaquePtr() == (void*)-1 || + Result.Stored.isCanonical()) && "Type is not canonical!"); return Result; } diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h index 1a050d29c8..7cf0d5e999 100644 --- a/include/clang/AST/TypeOrdering.h +++ b/include/clang/AST/TypeOrdering.h @@ -17,6 +17,7 @@ #define LLVM_CLANG_TYPE_ORDERING_H #include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" #include <functional> namespace clang { @@ -51,6 +52,26 @@ namespace llvm { return LHS == RHS; } }; + + template<> struct DenseMapInfo<clang::CanQualType> { + static inline clang::CanQualType getEmptyKey() { + return clang::CanQualType(); + } + + static inline clang::CanQualType getTombstoneKey() { + using clang::CanQualType; + return CanQualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1)); + } + + static unsigned getHashValue(clang::CanQualType Val) { + return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^ + ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9)); + } + + static bool isEqual(clang::CanQualType LHS, clang::CanQualType RHS) { + return LHS == RHS; + } + }; } #endif diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index f8859425ff..77a641a2c5 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -235,12 +235,30 @@ public: /// \brief The simplified type class for a non-macro completion result. SimplifiedTypeClass TypeClass; + + /// \brief The type of a non-macro completion result, stored as a unique + /// integer used by the string map of cached completion types. + /// + /// This value will be zero if the type is not known, or a unique value + /// determined by the formatted type string. Se \c CachedCompletionTypes + /// for more information. + unsigned Type; }; + /// \brief Retrieve the mapping from formatted type names to unique type + /// identifiers. + llvm::StringMap<unsigned> &getCachedCompletionTypes() { + return CachedCompletionTypes; + } + private: /// \brief The set of cached code-completion results. std::vector<CachedCodeCompletionResult> CachedCompletionResults; + /// \brief A mapping from the formatted type name to a unique number for that + /// type, which is used for type equality comparisons. + llvm::StringMap<unsigned> CachedCompletionTypes; + /// \brief Cache any "global" code-completion results, so that we can avoid /// recomputing them with each completion. void CacheCodeCompletionResults(); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index b54162f8d7..86588c9375 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -182,6 +183,8 @@ void ASTUnit::CacheCodeCompletionResults() { TheSema->GatherGlobalCodeCompletions(Results); // Translate global code completions into cached completions. + llvm::DenseMap<CanQualType, unsigned> CompletionTypes; + for (unsigned I = 0, N = Results.size(); I != N; ++I) { switch (Results[I].Kind) { case Result::RK_Declaration: { @@ -192,13 +195,30 @@ void ASTUnit::CacheCodeCompletionResults() { CachedResult.Priority = Results[I].Priority; CachedResult.Kind = Results[I].CursorKind; + // Keep track of the type of this completion in an ASTContext-agnostic + // way. QualType UsageType = getDeclUsageType(*Ctx, Results[I].Declaration); - if (UsageType.isNull()) + if (UsageType.isNull()) { CachedResult.TypeClass = STC_Void; - else { - CachedResult.TypeClass - = getSimplifiedTypeClass(Ctx->getCanonicalType(UsageType)); + CachedResult.Type = 0; + } else { + CanQualType CanUsageType + = Ctx->getCanonicalType(UsageType.getUnqualifiedType()); + CachedResult.TypeClass = getSimplifiedTypeClass(CanUsageType); + + // Determine whether we have already seen this type. If so, we save + // ourselves the work of formatting the type string by using the + // temporary, CanQualType-based hash table to find the associated value. + unsigned &TypeValue = CompletionTypes[CanUsageType]; + if (TypeValue == 0) { + TypeValue = CompletionTypes.size(); + CachedCompletionTypes[QualType(CanUsageType).getAsString()] + = TypeValue; + } + + CachedResult.Type = TypeValue; } + CachedCompletionResults.push_back(CachedResult); break; } @@ -224,6 +244,7 @@ void ASTUnit::CacheCodeCompletionResults() { CachedResult.Priority = Results[I].Priority; CachedResult.Kind = Results[I].CursorKind; CachedResult.TypeClass = STC_Void; + CachedResult.Type = 0; CachedCompletionResults.push_back(CachedResult); break; } @@ -239,6 +260,7 @@ void ASTUnit::ClearCachedCompletionResults() { for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I) delete CachedCompletionResults[I].Completion; CachedCompletionResults.clear(); + CachedCompletionTypes.clear(); } namespace { @@ -1432,13 +1454,21 @@ namespace { if (C->Kind == CXCursor_MacroDefinition) { Priority = getMacroUsagePriority(C->Completion->getTypedText(), Context.getPreferredType()->isAnyPointerType()); - } else { + } else if (C->Type) { CanQualType Expected - = S.Context.getCanonicalType(Context.getPreferredType()); + = S.Context.getCanonicalType( + Context.getPreferredType().getUnqualifiedType()); SimplifiedTypeClass ExpectedSTC = getSimplifiedTypeClass(Expected); if (ExpectedSTC == C->TypeClass) { - // FIXME: How can we check for an exact match? - Priority /= CCF_SimilarTypeMatch; + // We know this type is similar; check for an exact match. + llvm::StringMap<unsigned> &CachedCompletionTypes + = AST.getCachedCompletionTypes(); + llvm::StringMap<unsigned>::iterator Pos + = CachedCompletionTypes.find(QualType(Expected).getAsString()); + if (Pos != CachedCompletionTypes.end() && Pos->second == C->Type) + Priority /= CCF_ExactTypeMatch; + else + Priority /= CCF_SimilarTypeMatch; } } } diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c index 3605420956..5eead7e1fd 100644 --- a/test/Index/complete-exprs.c +++ b/test/Index/complete-exprs.c @@ -20,10 +20,9 @@ const char *str = "Hello, \nWorld"; // CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (2) // CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30) // RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1a %s -// FIXME: Priorities aren't right // CHECK-CC1a: ParmDecl:{ResultType int}{TypedText j} (2) // CHECK-CC1a: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30) -// CHECK-CC1a: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (25) +// CHECK-CC1a: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (12) // CHECK-CC1a: macro definition:{TypedText __VERSION__} (70) // RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s |