aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/CanonicalType.h6
-rw-r--r--include/clang/AST/TypeOrdering.h21
-rw-r--r--include/clang/Frontend/ASTUnit.h18
-rw-r--r--lib/Frontend/ASTUnit.cpp46
-rw-r--r--test/Index/complete-exprs.c3
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