]> granicus.if.org Git - clang/commitdiff
Code completion for ordinary names when we're starting a declaration, expression...
authorDouglas Gregor <dgregor@apple.com>
Mon, 21 Sep 2009 20:51:25 +0000 (20:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 21 Sep 2009 20:51:25 +0000 (20:51 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82481 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Action.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/Parser.cpp
lib/Sema/Sema.h
lib/Sema/SemaCodeComplete.cpp
test/CodeCompletion/ordinary-name.c [new file with mode: 0644]

index fb7f641f3107faf22d1634aab1c1292e6c1bce43..d86b8ee1c84d00b0eed822c52910ac62aedeb598 100644 (file)
@@ -2192,9 +2192,19 @@ public:
   /// found at a point in the grammar where the Action implementation is
   /// likely to be able to provide a list of possible completions, e.g.,
   /// after the "." or "->" of a member access expression.
-  ///
+  /// 
+  /// \todo Code completion for designated field initializers
+  /// \todo Code completion for call arguments after a function template-id
+  /// \todo Code completion within a call expression, object construction, etc.
+  /// \todo Code completion within a template argument list.
   //@{
   
+  /// \brief Code completion for an ordinary name that occurs within the given
+  /// scope.
+  ///
+  /// \param S the scope in which the name occurs.
+  virtual void CodeCompleteOrdinaryName(Scope *S) { }
+  
   /// \brief Code completion for a member access expression.
   ///
   /// This code completion action is invoked when the code-completion token
index 2eccbd04dad964cc69c2ba11fe94e09e08ff45e3..4ca5b48e8b671b25f5a05e9af2e4a2d2cc0609a2 100644 (file)
@@ -710,6 +710,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
                                         const ParsedTemplateInfo &TemplateInfo,
                                         AccessSpecifier AS,
                                         DeclSpecContext DSContext) {
+  if (Tok.is(tok::code_completion)) {
+    Actions.CodeCompleteOrdinaryName(CurScope);
+    ConsumeToken();
+  }
+  
   DS.SetRangeStart(Tok.getLocation());
   while (1) {
     bool isInvalid = false;
index db507c2d3adb5e528452d619e41b32c65da09ce0..156c84804fd0e5715027c776bfc56dfe02d527a4 100644 (file)
@@ -200,6 +200,11 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
 ///         expression ',' assignment-expression
 ///
 Parser::OwningExprResult Parser::ParseExpression() {
+  if (Tok.is(tok::code_completion)) {
+    Actions.CodeCompleteOrdinaryName(CurScope);
+    ConsumeToken();
+  }
+
   OwningExprResult LHS(ParseAssignmentExpression());
   if (LHS.isInvalid()) return move(LHS);
 
index 4fdcf2a077f3551c0b6c76aa11d2bbd5f03766fc..907ca802b4aeb74df5309829e9b9cfaacdd43bbd 100644 (file)
@@ -90,6 +90,11 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
       return ParseObjCAtStatement(AtLoc);
     }
 
+  case tok::code_completion:
+    Actions.CodeCompleteOrdinaryName(CurScope);
+    ConsumeToken();
+    return ParseStatementOrDeclaration(OnlyStatement);
+      
   case tok::identifier:
     if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
       // identifier ':' statement
@@ -918,6 +923,11 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
   OwningStmtResult FirstPart(Actions);
   OwningExprResult SecondPart(Actions), ThirdPart(Actions);
 
+  if (Tok.is(tok::code_completion)) {
+    Actions.CodeCompleteOrdinaryName(CurScope);
+    ConsumeToken();
+  }
+  
   // Parse the first part of the for specifier.
   if (Tok.is(tok::semi)) {  // for (;
     // no first part, eat the ';'.
index 177290b4381dc66439a938847d7a3cfc88eb740d..2f500a484da31c72e28c1fa269b3b56cce6e6388 100644 (file)
@@ -442,6 +442,10 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
     }
     SingleDecl = ParseObjCMethodDefinition();
     break;
+  case tok::code_completion:
+    Actions.CodeCompleteOrdinaryName(CurScope);
+    ConsumeToken();
+    return ParseExternalDeclaration();
   case tok::kw_using:
   case tok::kw_namespace:
   case tok::kw_typedef:
index aa35a60ee65e5d9298c7ab94bb44c1e9bff4dad7..7fa546258e43b30ea971b29a888056e013ccfba4 100644 (file)
@@ -3629,6 +3629,7 @@ public:
   /// \name Code completion
   //@{
   void setCodeCompleteConsumer(CodeCompleteConsumer *CCC);
+  virtual void CodeCompleteOrdinaryName(Scope *S);
   virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
                                                SourceLocation OpLoc,
                                                bool IsArrow);
index 79904c9c5329156b5a2407f681e04a55f0c81813..52e7d0e0050445e4038cdc716822729b0f78515e 100644 (file)
@@ -104,6 +104,7 @@ namespace {
     /// results of name lookup. All of the predicates have the same type, so that
     /// 
     //@{
+    bool IsOrdinaryName(NamedDecl *ND) const;
     bool IsNestedNameSpecifier(NamedDecl *ND) const;
     bool IsEnum(NamedDecl *ND) const;
     bool IsClassOrStruct(NamedDecl *ND) const;
@@ -316,6 +317,16 @@ void ResultBuilder::ExitScope() {
   ShadowMaps.pop_back();
 }
 
+/// \brief Determines whether this given declaration will be found by
+/// ordinary name lookup.
+bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
+  unsigned IDNS = Decl::IDNS_Ordinary;
+  if (SemaRef.getLangOptions().CPlusPlus)
+    IDNS |= Decl::IDNS_Tag;
+  
+  return ND->getIdentifierNamespace() & IDNS;
+}
+
 /// \brief Determines whether the given declaration is suitable as the 
 /// start of a C++ nested-name-specifier, e.g., a class or namespace.
 bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const {
@@ -874,6 +885,13 @@ static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter,
     CodeCompleter->ProcessCodeCompleteResults(Results, NumResults);
 }
 
+void Sema::CodeCompleteOrdinaryName(Scope *S) {
+  ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
+  CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, 
+                       Results);
+  HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
+}
+
 void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
                                            SourceLocation OpLoc,
                                            bool IsArrow) {
diff --git a/test/CodeCompletion/ordinary-name.c b/test/CodeCompletion/ordinary-name.c
new file mode 100644 (file)
index 0000000..a532409
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// RUN: true
+
+struct X { int x; };
+
+typedef struct X TYPEDEF;
+
+void foo() {
+  int y;
+  // CHECK-CC1: y : 0
+  // CHECK-NEXT-CC1: TYPEDEF : 2
+  // CHECK-NEXT-CC1: foo : 2