]> granicus.if.org Git - clang/commitdiff
When caching global completion results, keep track of the simplified
authorDouglas Gregor <dgregor@apple.com>
Mon, 16 Aug 2010 16:18:59 +0000 (16:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 16 Aug 2010 16:18:59 +0000 (16:18 +0000)
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

include/clang/Frontend/ASTUnit.h
include/clang/Sema/CodeCompleteConsumer.h
lib/Frontend/ASTUnit.cpp
lib/Sema/SemaCodeComplete.cpp
test/Index/complete-exprs.c
test/Index/complete-macros.c

index 76a86871de3d0173826e2a756a23c915ef871f49..f18e70e750272e739b79b1ff74792b271fe0e445 100644 (file)
@@ -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:
index 16dd69d40135735b0370bdcc283744b5de192c84..82ea46c290c64a358006ed6af578ee4c5e7f7b11 100644 (file)
@@ -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; }
 };
 
 
index 8ac5b681a6f6ac91ddbfff21ce191c813b9548e4..a573fb41ab649a678fb61c895c705a925db240cf 100644 (file)
@@ -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
index 599a10fd90a5f1c4878a3b1f3b2f2b5485e078d4..332f8c802930b76a49085f6d29f6359387b752c7 100644 (file)
@@ -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<BuiltinType>(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<NamedDecl>(ND->getUnderlyingDecl());
   
   if (TypeDecl *Type = dyn_cast<TypeDecl>(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());
 }
 
index 7dfe280d9e9da6f627a381d7156ab7ee4d49d393..3605420956e449f7d04a47753a5f8ef3486ec075 100644 (file)
@@ -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
index d0974db31fb335be7272ae990cabd9cb754362e3..26a63b151b7b8a9672893252f8ef2ddf7b2d19d2 100644 (file)
@@ -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)