#define LLVM_CLANG_TYPE_ORDERING_H
#include "clang/AST/Type.h"
+#include "clang/AST/CanonicalType.h"
#include <functional>
namespace clang {
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
/// \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();
#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"
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: {
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;
}
CachedResult.Priority = Results[I].Priority;
CachedResult.Kind = Results[I].CursorKind;
CachedResult.TypeClass = STC_Void;
+ CachedResult.Type = 0;
CachedCompletionResults.push_back(CachedResult);
break;
}
for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I)
delete CachedCompletionResults[I].Completion;
CachedCompletionResults.clear();
+ CachedCompletionTypes.clear();
}
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;
}
}
}
// 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