]> granicus.if.org Git - clang/commitdiff
Improve code completion in failure cases in two ways:
authorDouglas Gregor <dgregor@apple.com>
Tue, 25 May 2010 05:58:43 +0000 (05:58 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 25 May 2010 05:58:43 +0000 (05:58 +0000)
  1) Suppress diagnostics as soon as we form the code-completion
  token, so we don't get any error/warning spew from the early
  end-of-file.
  2) If we consume a code-completion token when we weren't expecting
  one, go into a code-completion recovery path that produces the best
  results it can based on the context that the parser is in.

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

13 files changed:
include/clang/Parse/Action.h
include/clang/Parse/Parser.h
lib/Lex/Lexer.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseObjc.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/Parser.cpp
lib/Sema/CodeCompleteConsumer.cpp
lib/Sema/SemaCodeComplete.cpp
test/Index/complete-recovery.m [new file with mode: 0644]

index f9aef9b0e9a439c68255934bc09eb87274735fe1..c9bbceef5401651cccb919ffac833c62bdca169c 100644 (file)
@@ -2649,9 +2649,13 @@ public:
     /// \brief Code completion occurs at the beginning of the
     /// initialization statement (or expression) in a for loop.
     CCC_ForInit,
-    /// \brief Code completion ocurs within the condition of an if,
+    /// \brief Code completion occurs within the condition of an if,
     /// while, switch, or for statement.
-    CCC_Condition
+    CCC_Condition,
+    /// \brief Code completion occurs within the body of a function on a 
+    /// recovery path, where we do not have a specific handle on our position
+    /// in the grammar.
+    CCC_RecoveryInFunction
   };
     
   /// \brief Code completion for an ordinary name that occurs within the given
index 646f84021ddcdeba799cc0a9dcf3adc0e23f8367..2e722f7a3863e8a7107699fb76f262103ff0d4c9 100644 (file)
@@ -234,6 +234,11 @@ private:
     assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() &&
            !isTokenBrace() &&
            "Should consume special tokens with Consume*Token");
+    if (Tok.is(tok::code_completion)) {
+      CodeCompletionRecovery();
+      return ConsumeCodeCompletionToken();
+    }
+    
     PrevTokLocation = Tok.getLocation();
     PP.Lex(Tok);
     return PrevTokLocation;
@@ -308,6 +313,22 @@ private:
     return PrevTokLocation;
   }
 
+  /// \brief Consume the current code-completion token.
+  ///
+  /// This routine should be called to consume the code-completion token once
+  /// a code-completion action has already been invoked.
+  SourceLocation ConsumeCodeCompletionToken() {
+    assert(Tok.is(tok::code_completion));
+    PrevTokLocation = Tok.getLocation();
+    PP.Lex(Tok);
+    return PrevTokLocation;    
+  }
+  
+  ///\ brief When we are consuming a code-completion token within having 
+  /// matched specific position in the grammar, provide code-completion results
+  /// based on context.
+  void CodeCompletionRecovery();
+
   /// GetLookAheadToken - This peeks ahead N tokens and returns that token
   /// without consuming any tokens.  LookAhead(0) returns 'Tok', LookAhead(1)
   /// returns the token after Tok, etc.
index 0925dd73fe931b95b1852c88cb08a3958f7d3d08..cd153e147b5d44dc13a763d5e57f4d631de2a384 100644 (file)
@@ -1359,6 +1359,9 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
     
     // Only do the eof -> code_completion translation once.
     PP->SetCodeCompletionPoint(0, 0, 0);
+    
+    // Silence any diagnostics that occur once we hit the code-completion point.
+    PP->getDiagnostics().setSuppressAllDiagnostics(true);
     return true;
   }
   
index e7650eae84625aeefb9d9452db8f234a1d146517..3e7d4a13c5df54cf000c5a2fd53b19926203550b 100644 (file)
@@ -839,7 +839,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       CCC = Action::CCC_ObjCImplementation;
     
     Actions.CodeCompleteOrdinaryName(CurScope, CCC);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
   
   DS.SetRangeStart(Tok.getLocation());
@@ -1870,7 +1870,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
   if (Tok.is(tok::code_completion)) {
     // Code completion for an enum name.
     Actions.CodeCompleteTag(CurScope, DeclSpec::TST_enum);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
   
   llvm::OwningPtr<AttributeList> Attr;
index b276db6beed26ef1a67fb60d3bf20eff897889fc..479c04c37d7aaf738cfbd3d3408b48ab0ade1356 100644 (file)
@@ -50,7 +50,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
 
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteNamespaceDecl(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   SourceLocation IdentLoc;
@@ -136,7 +136,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
 
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteNamespaceAliasDecl(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   CXXScopeSpec SS;
@@ -231,7 +231,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
 
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteUsing(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   if (Tok.is(tok::kw_namespace))
@@ -268,7 +268,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
 
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteUsingDirective(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   CXXScopeSpec SS;
@@ -610,7 +610,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
   if (Tok.is(tok::code_completion)) {
     // Code completion for a struct, class, or union name.
     Actions.CodeCompleteTag(CurScope, TagType);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   AttributeList *AttrList = 0;
index ed27f3bccb0070d1f880dc35185b707ab945234d..b036e568f8bb3e53526bfee336250b1accf41b66 100644 (file)
@@ -222,7 +222,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
 Parser::OwningExprResult Parser::ParseAssignmentExpression() {
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   if (Tok.is(tok::kw_throw))
@@ -906,7 +906,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
     return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
   case tok::code_completion:
     Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
     return ParseCastExpression(isUnaryExpression, isAddressOfOperand, 
                                NotCastExpr, TypeOfCast);
   case tok::l_square:
@@ -975,7 +975,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
 
       if (Tok.is(tok::code_completion)) {
         Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0);
-        ConsumeToken();
+        ConsumeCodeCompletionToken();
       }
       
       if (Tok.isNot(tok::r_paren)) {
@@ -1029,7 +1029,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
         Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(),
                                                 OpLoc, OpKind == tok::arrow);
         
-        ConsumeToken();
+        ConsumeCodeCompletionToken();
       }
       
       if (MayBePseudoDestructor) {
@@ -1562,7 +1562,7 @@ bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs,
     if (Tok.is(tok::code_completion)) {
       if (Completer)
         (Actions.*Completer)(CurScope, Data, Exprs.data(), Exprs.size());
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     OwningExprResult Expr(ParseAssignmentExpression());
index 0a909f626ffec7b077a54c75d72a18032d8d9f29..46f1d94cf2c19505087f7d748bbaae09e59fe4a7 100644 (file)
@@ -110,7 +110,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
         // Code completion for a nested-name-specifier, where the code
         // code completion token follows the '::'.
         Actions.CodeCompleteQualifiedId(CurScope, SS, EnteringContext);
-        ConsumeToken();
+        ConsumeCodeCompletionToken();
       }
     }
 
@@ -729,7 +729,7 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
                                bool ConvertToBoolean) {
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   if (!isCXXConditionDeclaration()) {
@@ -1274,7 +1274,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
       Actions.CodeCompleteOperatorName(CurScope);
       
       // Consume the operator token.
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
       
       // Don't try to parse any further.
       return true;
index 9acb4fef80f2e3a4fd3f607c94cf970443e83595..9cfe73456a5f3b04bd68f646337edc03b6538502 100644 (file)
@@ -32,7 +32,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
 
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   switch (Tok.getObjCKeywordID()) {
@@ -131,7 +131,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
   // Code completion after '@interface'.
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCInterfaceDecl(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   if (Tok.isNot(tok::identifier)) {
@@ -149,7 +149,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
     IdentifierInfo *categoryId = 0;
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     // For ObjC2, the category name is optional (not an error).
@@ -204,7 +204,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
     // Code completion of superclass names.
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
 
     if (Tok.isNot(tok::identifier)) {
@@ -350,7 +350,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
       Actions.CodeCompleteOrdinaryName(CurScope, 
                                   ObjCImpDecl? Action::CCC_ObjCImplementation
                                              : Action::CCC_ObjCInterface);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     // If we don't have an @ directive, parse it as a function definition.
@@ -371,7 +371,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
     SourceLocation AtLoc = ConsumeToken(); // the "@"
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
       break;
     }
 
@@ -438,7 +438,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
   // EOF.  In the former case, eat the @end.  In the later case, emit an error.
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   } else if (Tok.isObjCAtKeyword(tok::objc_end))
     ConsumeToken(); // the "end" identifier
   else
@@ -477,7 +477,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
   while (1) {
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCPropertyFlags(CurScope, DS);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     const IdentifierInfo *II = Tok.getIdentifierInfo();
 
@@ -514,7 +514,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl,
         else
           Actions.CodeCompleteObjCPropertyGetter(CurScope, ClassDecl,
                                                  Methods, NumMethods);
-        ConsumeToken();
+        ConsumeCodeCompletionToken();
       }
 
       if (Tok.isNot(tok::identifier)) {
@@ -782,7 +782,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, 
                                        /*ReturnType=*/0, IDecl);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   // Parse the return type if present.
@@ -799,7 +799,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, 
                                        ReturnType, IDecl);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   // Now parse the selector.
@@ -945,7 +945,7 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(), 
                                                  ProtocolIdents.size());
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
 
     if (Tok.isNot(tok::identifier)) {
@@ -1026,7 +1026,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
       
       if (Tok.is(tok::code_completion)) {
         Actions.CodeCompleteObjCAtVisibility(CurScope);
-        ConsumeToken();
+        ConsumeCodeCompletionToken();
       }
       
       switch (Tok.getObjCKeywordID()) {
@@ -1046,7 +1046,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteOrdinaryName(CurScope, 
                                        Action::CCC_ObjCInstanceVariableList);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     struct ObjCIvarCallback : FieldCallback {
@@ -1117,7 +1117,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
 
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCProtocolDecl(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   if (Tok.isNot(tok::identifier)) {
@@ -1203,7 +1203,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
   // Code completion after '@implementation'.
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCImplementationDecl(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
 
   if (Tok.isNot(tok::identifier)) {
@@ -1222,7 +1222,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
 
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     if (Tok.is(tok::identifier)) {
@@ -1342,7 +1342,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
   while (true) {
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     if (Tok.isNot(tok::identifier)) {
@@ -1361,7 +1361,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
       if (Tok.is(tok::code_completion)) {
         Actions.CodeCompleteObjCPropertySynthesizeIvar(CurScope, propertyId,
                                                        ObjCImpDecl);
-        ConsumeToken();
+        ConsumeCodeCompletionToken();
       }
       
       if (Tok.isNot(tok::identifier)) {
@@ -1400,7 +1400,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
   while (true) {
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     if (Tok.isNot(tok::identifier)) {
@@ -1654,7 +1654,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
 Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCAtStatement(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
     return StmtError();
   }
   
@@ -1685,7 +1685,7 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
   switch (Tok.getKind()) {
   case tok::code_completion:
     Actions.CodeCompleteObjCAtExpression(CurScope);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
     return ExprError();
 
   case tok::string_literal:    // primary-expression: string-literal
@@ -1925,7 +1925,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
     else
       Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), 
                                               0, 0);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
   
   // Parse objc-selector
@@ -1979,7 +1979,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
           Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(),
                                                   KeyIdents.data(), 
                                                   KeyIdents.size());
-        ConsumeToken();
+        ConsumeCodeCompletionToken();
       }
             
       // Check for another keyword selector.
index ea364ee2b6b710619600bd0da9fa08c503f43644..98c005837e7c7eefdbbb5b36fb34e1730a06b02d 100644 (file)
@@ -283,7 +283,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
 
     if (Tok.is(tok::code_completion)) {
       Actions.CodeCompleteCase(CurScope);
-      ConsumeToken();
+      ConsumeCodeCompletionToken();
     }
     
     /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'.
@@ -1000,7 +1000,7 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
     Actions.CodeCompleteOrdinaryName(CurScope, 
                                      C99orCXXorObjC? Action::CCC_ForInit
                                                    : Action::CCC_Expression);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
   }
   
   // Parse the first part of the for specifier.
index 37475d23fe04c686cfdfe9140ed407e1dc2b6edd..8407db1916fc65b7acb684a97d2fd2d38abec54c 100644 (file)
@@ -134,7 +134,7 @@ SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
 /// returned.
 bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
                               const char *Msg, tok::TokenKind SkipToTok) {
-  if (Tok.is(ExpectedTok)) {
+  if (Tok.is(ExpectedTok) || Tok.is(tok::code_completion)) {
     ConsumeAnyToken();
     return false;
   }
@@ -189,7 +189,11 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
     case tok::eof:
       // Ran out of tokens.
       return false;
-
+        
+    case tok::code_completion:
+      ConsumeToken();
+      return false;
+        
     case tok::l_paren:
       // Recursively skip properly-nested parens.
       ConsumeParen();
@@ -447,7 +451,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr)
       Actions.CodeCompleteOrdinaryName(CurScope, 
                                    ObjCImpDecl? Action::CCC_ObjCImplementation
                                               : Action::CCC_Namespace);
-    ConsumeToken();
+    ConsumeCodeCompletionToken();
     return ParseExternalDeclaration(Attr);
   case tok::kw_using:
   case tok::kw_namespace:
@@ -1072,6 +1076,22 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
   return false;
 }
 
+void Parser::CodeCompletionRecovery() {
+  for (Scope *S = CurScope; S; S = S->getParent()) {
+    if (S->getFlags() & Scope::FnScope) {
+      Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_RecoveryInFunction);
+      return;
+    }
+    
+    if (S->getFlags() & Scope::ClassScope) {
+      Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Class);
+      return;
+    }
+  }
+  
+  Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Namespace);
+}
+
 // Anchor the Parser::FieldCallback vtable to this translation unit.
 // We use a spurious method instead of the destructor because
 // destroying FieldCallbacks can actually be slightly
index 0ef9a15faaf9db6a05cb136e5d17df15b6a5dfe2..52562f6b4471d8cfed7c4dc58c363b1a7eb0ecd9 100644 (file)
@@ -459,11 +459,6 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
     }
     }
   }
-  
-  // Once we've printed the code-completion results, suppress remaining
-  // diagnostics.
-  // FIXME: Move this somewhere else!
-  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
 }
 
 void 
@@ -478,11 +473,6 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
       delete CCS;
     }
   }
-
-  // Once we've printed the code-completion results, suppress remaining
-  // diagnostics.
-  // FIXME: Move this somewhere else!
-  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
 }
 
 void 
@@ -599,11 +589,6 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
     CCS->Serialize(OS);
     delete CCS;
   }
-  
-  // Once we've printed the code-completion results, suppress remaining
-  // diagnostics.
-  // FIXME: Move this somewhere else!
-  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
 }
 
 void 
@@ -619,9 +604,4 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
     CCS->Serialize(OS);
     delete CCS;
   }
-  
-  // Once we've printed the code-completion results, suppress remaining
-  // diagnostics.
-  // FIXME: Move this somewhere else!
-  SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics();
 }
index 036ae7e8690b9e2531ff13b2c6e6d0684063fdb0..1685cd572e1a299f47a6a14afdc9e5d5934da13a 100644 (file)
@@ -843,6 +843,7 @@ static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC,
   case Action::CCC_Statement:
   case Action::CCC_ForInit:
   case Action::CCC_Condition:
+  case Action::CCC_RecoveryInFunction:
     break;
   }
 }
@@ -994,6 +995,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
     AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true);
     break;
       
+  case Action::CCC_RecoveryInFunction:
   case Action::CCC_Statement: {
     Results.AddResult(Result("typedef"));
 
@@ -1925,6 +1927,10 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
   case CCC_Condition:
     Results.setFilter(&ResultBuilder::IsOrdinaryName);
     break;
+      
+  case CCC_RecoveryInFunction:
+    // Unfiltered
+    break;
   }
 
   CodeCompletionDeclConsumer Consumer(Results, CurContext);
@@ -3079,8 +3085,6 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
   }
 
   Results.ExitScope();
-  
-  // This also suppresses remaining diagnostics.
   HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
 }
 
diff --git a/test/Index/complete-recovery.m b/test/Index/complete-recovery.m
new file mode 100644 (file)
index 0000000..2ea9fd9
--- /dev/null
@@ -0,0 +1,21 @@
+/* Run lines are at the end, since line/column matter in this test. */
+
+@interface A
+- (void)method:(int)x;
+@end
+
+@implementation A
+- (void)method:(int)x {
+  A *a = [A method:1];
+  blarg * blah = wibble
+}
+@end
+
+// RUN: c-index-test -code-completion-at=%s:9:20 %s 2>%t | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: not grep error %t
+// CHECK-CC1: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
+// CHECK-CC1: NotImplemented:{TypedText _Bool}
+// CHECK-CC1: VarDecl:{ResultType A *}{TypedText a}
+// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
+
+// RUN: c-index-test -code-completion-at=%s:10:24 %s 2>%t | FileCheck -check-prefix=CHECK-CC1 %s