diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f523bed976..80e4626536 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1262,6 +1262,12 @@ private: Decl *ParseFunctionStatementBody(Decl *Decl); Decl *ParseFunctionTryBlock(Decl *Decl); + /// \brief When in code-completion, skip parsing of the function/method body + /// unless the body contains the code-completion point. + /// + /// \returns true if the function body was skipped. + bool MaybeSkipFunctionBodyForCodeCompletion(); + bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index c48f6803b0..25829e8975 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1718,6 +1718,9 @@ Decl *Parser::ParseObjCMethodDefinition() { // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); + if (MaybeSkipFunctionBodyForCodeCompletion()) + return Actions.ActOnFinishFunctionBody(MDecl, 0); + StmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index d25cc110a8..28b140e731 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1466,18 +1466,8 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); - // When in code-completion, skip parsing for all function bodies unless - // the body contains the code-completion point. - if (PP.isCodeCompletionEnabled()) { - TentativeParsingAction PA(*this); - ConsumeBrace(); - if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, - /*StopAtCodeCompletion=*/true)) { - PA.Commit(); - return Actions.ActOnFinishFunctionBody(Decl, 0); - } - PA.Revert(); - } + if (MaybeSkipFunctionBodyForCodeCompletion()) + return Actions.ActOnFinishFunctionBody(Decl, 0); PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); @@ -1511,6 +1501,9 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); + if (MaybeSkipFunctionBodyForCodeCompletion()) + return Actions.ActOnFinishFunctionBody(Decl, 0); + SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); // If we failed to parse the try-catch, we just give the function an empty @@ -1522,6 +1515,26 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } +bool Parser::MaybeSkipFunctionBodyForCodeCompletion() { + assert(Tok.is(tok::l_brace)); + + if (!PP.isCodeCompletionEnabled()) + return false; + + // We're in code-completion mode. Skip parsing for all function bodies unless + // the body contains the code-completion point. + TentativeParsingAction PA(*this); + ConsumeBrace(); + if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, + /*StopAtCodeCompletion=*/true)) { + PA.Commit(); + return true; + } + + PA.Revert(); + return false; +} + /// ParseCXXTryBlock - Parse a C++ try-block. /// /// try-block: diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index dc851a3e83..1c03f7d7f7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5415,7 +5415,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - MD->setEndLoc(Body->getLocEnd()); + if (Body) + MD->setEndLoc(Body->getLocEnd()); if (!MD->isInvalidDecl()) { DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), diff --git a/test/Index/complete-synthesized.m b/test/Index/complete-synthesized.m index a97eeab8cb..2c26d36a34 100644 --- a/test/Index/complete-synthesized.m +++ b/test/Index/complete-synthesized.m @@ -51,6 +51,6 @@ // RUN: c-index-test -code-completion-at=%s:34:2 -Xclang -fobjc-nonfragile-abi2 %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: NotImplemented:{TypedText _Bool} (50) // CHECK-CC3: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35) -// CHECK-CC3: ObjCIvarDecl:{ResultType double}{TypedText prop4} +// CHECK-CC3: ObjCPropertyDecl:{ResultType double}{TypedText prop4} // CHECK-CC3-NOT: ObjCPropertyDecl:{ResultType double}{TypedText prop4} (35) // CHECK-CC1: restrict