From: Douglas Gregor Date: Tue, 25 May 2010 05:58:43 +0000 (+0000) Subject: Improve code completion in failure cases in two ways: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dc8453422bec3bbf70c03920e01498d75783d122;p=clang Improve code completion in failure cases in two ways: 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 --- diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index f9aef9b0e9..c9bbceef54 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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 diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 646f84021d..2e722f7a38 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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. diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 0925dd73fe..cd153e147b 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -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; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e7650eae84..3e7d4a13c5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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 Attr; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b276db6bee..479c04c37d 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index ed27f3bccb..b036e568f8 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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()); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 0a909f626f..46f1d94cf2 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 9acb4fef80..9cfe73456a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -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 &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. diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index ea364ee2b6..98c005837e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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. diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 37475d23fe..8407db1916 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -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 diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 0ef9a15faa..52562f6b44 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -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(); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 036ae7e869..1685cd572e 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -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 index 0000000000..2ea9fd9f77 --- /dev/null +++ b/test/Index/complete-recovery.m @@ -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