]> granicus.if.org Git - clang/commitdiff
For code completion in C++ member access expressions and tag names,
authorDouglas Gregor <dgregor@apple.com>
Fri, 18 Sep 2009 17:42:29 +0000 (17:42 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 18 Sep 2009 17:42:29 +0000 (17:42 +0000)
look into the current scope for anything that could start a
nested-names-specifier. These results are ranked worse than any of the
results actually found in the lexical scope.

Perform a little more pruning of the result set, eliminating
constructors, __va_list_tag, and any duplication of declarations in
the result set. For the latter, implemented
NamespaceDecl::getCanonicalDecl.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82231 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/Sema/CodeCompleteConsumer.h
lib/Sema/CodeCompleteConsumer.cpp
test/CodeCompletion/tag.cpp [new file with mode: 0644]

index 21b459a0ea61e8df69f1eb98254ec7d08563cbf6..231e36ab5f3276e630532c88db467cc9bec70698 100644 (file)
@@ -201,6 +201,8 @@ public:
   }
   void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
 
+  virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
+
   virtual SourceRange getSourceRange() const {
     return SourceRange(getLocation(), RBracLoc);
   }
index 425a937a93d85ddb2fea16be0fec63d84d8f41e9..ce5707ed3af07dd217ece0039c9680cd2c91b95e 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/Type.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include <list>
 #include <map>
 #include <vector>
@@ -25,6 +26,7 @@ class raw_ostream;
 
 namespace clang {
   
+class Decl;
 class DeclContext;
 class NamedDecl;
 class Scope;
@@ -89,6 +91,11 @@ public:
     /// \brief The actual results we have found.
     std::vector<Result> Results;
 
+    /// \brief A record of all of the declarations we have found and placed
+    /// into the result set, used to ensure that no declaration ever gets into
+    /// the result set twice.
+    llvm::SmallPtrSet<Decl*, 16> AllDeclsFound;
+    
     /// \brief A mapping from declaration names to the declarations that have
     /// this name within a particular scope and their index within the list of
     /// results.
index fb82a6c3313eb739f9c71813e994f16f2f516471..7dee12a3dcb7d13b86822aa8afee77e08b41f54a 100644 (file)
@@ -53,8 +53,10 @@ CodeCompleteConsumer::CodeCompleteMemberReferenceExpr(Scope *S,
         // The "template" keyword can follow "->" or "." in the grammar.
         Results.MaybeAddResult(Result("template", NextRank++));
 
-      // FIXME: For C++, we also need to look into the current scope, since
-      // we could have the start of a nested-name-specifier.
+      // We could have the start of a nested-name-specifier. Add those
+      // results as well.
+      Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
+      CollectLookupResults(S, NextRank, Results);
     }
 
     // Hand off the results found for code completion.
@@ -83,10 +85,14 @@ void CodeCompleteConsumer::CodeCompleteTag(Scope *S, ElaboratedType::TagKind TK)
   }
   
   ResultSet Results(*this, Filter);
-  CollectLookupResults(S, 0, Results);
+  unsigned NextRank = CollectLookupResults(S, 0, Results);
   
-  // FIXME: In C++, we could have the start of a nested-name-specifier.
-  // Add those results (with a poorer rank, naturally).
+  if (getSema().getLangOptions().CPlusPlus) {
+    // We could have the start of a nested-name-specifier. Add those
+    // results as well.
+    Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
+    CollectLookupResults(S, NextRank, Results);
+  }
   
   ProcessCodeCompleteResults(Results.data(), Results.size());
 }
@@ -121,10 +127,6 @@ void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) {
   // FIXME: Using declarations
   // FIXME: Separate overload sets
   
-  // Filter out any unwanted results.
-  if (Filter && !(Completer.*Filter)(R.Declaration))
-    return;
-  
   Decl *CanonDecl = R.Declaration->getCanonicalDecl();
   unsigned IDNS = CanonDecl->getIdentifierNamespace();
 
@@ -134,6 +136,23 @@ void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) {
       (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
     return;
 
+  if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
+    // __va_list_tag is a freak of nature. Find it and skip it.
+    if (Id->isStr("__va_list_tag"))
+      return;
+
+    // FIXME: Should we filter out other names in the implementation's
+    // namespace, e.g., those containing a __ or that start with _[A-Z]?
+  }
+
+  // C++ constructors are never found by name lookup.
+  if (isa<CXXConstructorDecl>(CanonDecl))
+    return;
+  
+  // Filter out any unwanted results.
+  if (Filter && !(Completer.*Filter)(R.Declaration))
+    return;
+  
   ShadowMap &SMap = ShadowMaps.back();
   ShadowMap::iterator I, IEnd;
   for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName());
@@ -187,6 +206,10 @@ void CodeCompleteConsumer::ResultSet::MaybeAddResult(Result R) {
     }
   }
   
+  // Make sure that any given declaration only shows up in the result set once.
+  if (!AllDeclsFound.insert(CanonDecl))
+    return;
+  
   // Insert this result into the set of results and into the current shadow
   // map.
   SMap.insert(std::make_pair(R.Declaration->getDeclName(),
diff --git a/test/CodeCompletion/tag.cpp b/test/CodeCompletion/tag.cpp
new file mode 100644 (file)
index 0000000..addad9d
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// RUN: true
+
+class X { };
+struct Y { };
+
+namespace N {
+  template<typename> class Z;
+}
+
+namespace N {
+  class Y;
+  
+  void test() {
+    // CHECK-CC1: Y : 2
+    // CHECK-CC1: Z : 2
+    // CHECK-CC1: X : 3
+    // CHECK-CC1: Y : 3
+    // CHECK-CC1: N : 6
+    class