From: Douglas Gregor Date: Mon, 16 Aug 2010 16:18:59 +0000 (+0000) Subject: When caching global completion results, keep track of the simplified X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1827e10051638770ad9ccf3e285caf95f995afd1;p=clang When caching global completion results, keep track of the simplified type class, so that we can adjust priorities appropriately when the preferred type for the context and the actual type of the completion are similar. This gets us one step closer to parity of the cached completion results with the non-cached completion results. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111139 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 76a86871de..f18e70e750 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -232,6 +232,9 @@ public: /// \brief The libclang cursor kind corresponding to this code-completion /// result. CXCursorKind Kind; + + /// \brief The simplified type class for a non-macro completion result. + SimplifiedTypeClass TypeClass; }; private: diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 16dd69d401..82ea46c290 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H #include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "clang-c/Index.h" @@ -72,7 +73,38 @@ enum { /// Objective-C object pointer types). CCF_SimilarTypeMatch = 2 }; + +/// \brief A simplified classification of types used when determining +/// "similar" types for code completion. +enum SimplifiedTypeClass { + STC_Arithmetic, + STC_Array, + STC_Block, + STC_Function, + STC_ObjectiveC, + STC_Other, + STC_Pointer, + STC_Record, + STC_Void +}; + +/// \brief Determine the simplified type class of the given canonical type. +SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T); +/// \brief Determine the type that this declaration will have if it is used +/// as a type or in an expression. +QualType getDeclUsageType(ASTContext &C, NamedDecl *ND); + +/// \brief Determine the priority to be given to a macro code completion result +/// with the given name. +/// +/// \param MacroName The name of the macro. +/// +/// \param PreferredTypeIsPointer Whether the preferred type for the context +/// of this macro is a pointer type. +unsigned getMacroUsagePriority(llvm::StringRef MacroName, + bool PreferredTypeIsPointer = false); + class FunctionDecl; class FunctionType; class FunctionTemplateDecl; @@ -138,29 +170,36 @@ public: private: enum Kind Kind; + /// \brief The type that would prefer to see at this point (e.g., the type + /// of an initializer or function parameter). + QualType PreferredType; + /// \brief The type of the base object in a member access expression. - QualType Type; + QualType BaseType; public: /// \brief Construct a new code-completion context of the given kind. - CodeCompletionContext(enum Kind Kind) : Kind(Kind) { - assert(Kind != CCC_MemberAccess && "Member access requires a type"); - } + CodeCompletionContext(enum Kind Kind) : Kind(Kind) { } /// \brief Construct a new code-completion context of the given kind. - CodeCompletionContext(enum Kind Kind, QualType T) : Kind(Kind), Type(T) { - assert(Kind == CCC_MemberAccess && "Only member access has a type"); + CodeCompletionContext(enum Kind Kind, QualType T) : Kind(Kind) { + if (Kind == CCC_MemberAccess) + BaseType = T; + else + PreferredType = T; } /// \brief Retrieve the kind of code-completion context. enum Kind getKind() const { return Kind; } + /// \brief Retrieve the type that this expression would prefer to have, e.g., + /// if the expression is a variable initializer or a function argument, the + /// type of the corresponding variable or function parameter. + QualType getPreferredType() const { return PreferredType; } + /// \brief Retrieve the type of the base object in a member-access /// expression. - QualType getType() const { - assert(Kind == CCC_MemberAccess && "Only member access has a type"); - return Type; - } + QualType getBaseType() const { return BaseType; } }; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 8ac5b681a6..a573fb41ab 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -191,6 +191,10 @@ void ASTUnit::CacheCodeCompletionResults() { Ctx->getLangOptions()); CachedResult.Priority = Results[I].Priority; CachedResult.Kind = Results[I].CursorKind; + CachedResult.TypeClass + = getSimplifiedTypeClass( + Ctx->getCanonicalType(getDeclUsageType(*Ctx, + Results[I].Declaration))); CachedCompletionResults.push_back(CachedResult); break; } @@ -215,6 +219,7 @@ void ASTUnit::CacheCodeCompletionResults() { | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); CachedResult.Priority = Results[I].Priority; CachedResult.Kind = Results[I].CursorKind; + CachedResult.TypeClass = STC_Void; CachedCompletionResults.push_back(CachedResult); break; } @@ -1417,7 +1422,24 @@ namespace { AddedResult = true; } - AllResults.push_back(Result(C->Completion, C->Priority, C->Kind)); + // Adjust priority based on similar type classes. + unsigned Priority = C->Priority; + if (!Context.getPreferredType().isNull()) { + if (C->Kind == CXCursor_MacroDefinition) { + Priority = getMacroUsagePriority(C->Completion->getTypedText(), + Context.getPreferredType()->isAnyPointerType()); + } else { + CanQualType Expected + = S.Context.getCanonicalType(Context.getPreferredType()); + SimplifiedTypeClass ExpectedSTC = getSimplifiedTypeClass(Expected); + if (ExpectedSTC == C->TypeClass) { + // FIXME: How can we check for an exact match? + Priority /= CCF_SimilarTypeMatch; + } + } + } + + AllResults.push_back(Result(C->Completion, Priority, C->Kind)); } // If we did not add any cached completion results, just forward the diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 599a10fd90..332f8c8029 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -476,21 +476,9 @@ bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, return false; } -enum SimplifiedTypeClass { - STC_Arithmetic, - STC_Array, - STC_Block, - STC_Function, - STC_ObjectiveC, - STC_Other, - STC_Pointer, - STC_Record, - STC_Void -}; - /// \brief A simplified classification of types used to determine whether two /// types are "similar enough" when adjusting priorities. -static SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T) { +SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) { switch (T->getTypeClass()) { case Type::Builtin: switch (cast(T)->getKind()) { @@ -561,7 +549,7 @@ static SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T) { /// \brief Get the type that a given expression will have if this declaration /// is used as an expression in its "typical" code-completion form. -static QualType getDeclUsageType(ASTContext &C, NamedDecl *ND) { +QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) { ND = cast(ND->getUnderlyingDecl()); if (TypeDecl *Type = dyn_cast(ND)) @@ -2202,6 +2190,20 @@ namespace { }; } +unsigned clang::getMacroUsagePriority(llvm::StringRef MacroName, + bool PreferredTypeIsPointer) { + unsigned Priority = CCP_Macro; + + // Treat the "nil" and "NULL" macros as null pointer constants. + if (MacroName.equals("nil") || MacroName.equals("NULL")) { + Priority = CCP_Constant; + if (PreferredTypeIsPointer) + Priority = Priority / CCF_SimilarTypeMatch; + } + + return Priority; +} + static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, bool TargetTypeIsPointer = false) { typedef CodeCompleteConsumer::Result Result; @@ -2210,16 +2212,9 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) { - unsigned Priority = CCP_Macro; - - // Treat the "nil" and "NULL" macros as null pointer constants. - if (M->first->isStr("nil") || M->first->isStr("NULL")) { - Priority = CCP_Constant; - if (TargetTypeIsPointer) - Priority = Priority / CCF_SimilarTypeMatch; - } - - Results.AddResult(Result(M->first, Priority)); + Results.AddResult(Result(M->first, + getMacroUsagePriority(M->first->getName(), + TargetTypeIsPointer))); } Results.ExitScope(); } @@ -2356,7 +2351,7 @@ void Sema::CodeCompleteExpression(Scope *S, QualType T, if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, PreferredTypeIsPointer); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Expression, + CodeCompletionContext(CodeCompletionContext::CCC_Expression, T), Results.data(),Results.size()); } diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c index 7dfe280d9e..3605420956 100644 --- a/test/Index/complete-exprs.c +++ b/test/Index/complete-exprs.c @@ -23,7 +23,7 @@ const char *str = "Hello, \nWorld"; // 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 )} (50) +// CHECK-CC1a: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (25) // 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 diff --git a/test/Index/complete-macros.c b/test/Index/complete-macros.c index d0974db31f..26a63b151b 100644 --- a/test/Index/complete-macros.c +++ b/test/Index/complete-macros.c @@ -20,6 +20,8 @@ void f2() { // 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 +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:14:8 %s | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: macro definition:{TypedText nil} (30) // RUN: c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: macro definition:{TypedText nil} (60)