r272963 - Fix a few issues while skipping function bodies
Olivier Goffart via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 16 14:40:07 PDT 2016
Author: ogoffart
Date: Thu Jun 16 16:40:06 2016
New Revision: 272963
URL: http://llvm.org/viewvc/llvm-project?rev=272963&view=rev
Log:
Fix a few issues while skipping function bodies
- In functions with try { } catch { }, only the try block would be
skipped, not the catch blocks
- The template functions would still be parsed.
- The initializers within a constructor would still be parsed.
- The inline functions within class would still be stored, only to be
discared later.
- Invalid code with try would assert (as in "int foo() try assert_here")
This attempt to do even less while skipping function bodies.
Differential Revision: http://reviews.llvm.org/D20821
Added:
cfe/trunk/test/CodeCompletion/ctor-initializer.cpp
Modified:
cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/unittests/Tooling/ToolingTest.cpp
Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=272963&r1=272962&r2=272963&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Thu Jun 16 16:40:06 2016
@@ -101,6 +101,12 @@ NamedDecl *Parser::ParseCXXInlineMethodD
return FnD;
}
+ if (SkipFunctionBodies && (!FnD || Actions.canSkipFunctionBody(FnD)) &&
+ trySkippingFunctionBody()) {
+ Actions.ActOnSkippedFunctionBody(FnD);
+ return FnD;
+ }
+
// In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit.
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=272963&r1=272962&r2=272963&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Thu Jun 16 16:40:06 2016
@@ -2656,6 +2656,12 @@ Parser::ParseObjCAutoreleasePoolStmt(Sou
/// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
/// for later parsing.
void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
+ if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
+ trySkippingFunctionBody()) {
+ Actions.ActOnSkippedFunctionBody(MDecl);
+ return;
+ }
+
LexedMethod* LM = new LexedMethod(this, MDecl);
CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
CachedTokens &Toks = LM->Toks;
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=272963&r1=272962&r2=272963&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Thu Jun 16 16:40:06 2016
@@ -1916,12 +1916,6 @@ Decl *Parser::ParseFunctionStatementBody
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
- if (SkipFunctionBodies && (!Decl || Actions.canSkipFunctionBody(Decl)) &&
- trySkippingFunctionBody()) {
- BodyScope.Exit();
- return Actions.ActOnSkippedFunctionBody(Decl);
- }
-
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
"parsing function body");
@@ -1964,12 +1958,6 @@ Decl *Parser::ParseFunctionTryBlock(Decl
else
Actions.ActOnDefaultCtorInitializers(Decl);
- if (SkipFunctionBodies && Actions.canSkipFunctionBody(Decl) &&
- trySkippingFunctionBody()) {
- BodyScope.Exit();
- return Actions.ActOnSkippedFunctionBody(Decl);
- }
-
// Save and reset current vtordisp stack if we have entered a C++ method body.
bool IsCXXMethod =
getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
@@ -1990,27 +1978,43 @@ Decl *Parser::ParseFunctionTryBlock(Decl
}
bool Parser::trySkippingFunctionBody() {
- assert(Tok.is(tok::l_brace));
assert(SkipFunctionBodies &&
"Should only be called when SkipFunctionBodies is enabled");
-
if (!PP.isCodeCompletionEnabled()) {
- ConsumeBrace();
- SkipUntil(tok::r_brace);
+ SkipFunctionBody();
return true;
}
// 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, StopAtCodeCompletion)) {
+ bool IsTryCatch = Tok.is(tok::kw_try);
+ CachedTokens Toks;
+ bool ErrorInPrologue = ConsumeAndStoreFunctionPrologue(Toks);
+ if (llvm::any_of(Toks, [](const Token &Tok) {
+ return Tok.is(tok::code_completion);
+ })) {
+ PA.Revert();
+ return false;
+ }
+ if (ErrorInPrologue) {
PA.Commit();
+ SkipMalformedDecl();
return true;
}
-
- PA.Revert();
- return false;
+ if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
+ PA.Revert();
+ return false;
+ }
+ while (IsTryCatch && Tok.is(tok::kw_catch)) {
+ if (!SkipUntil(tok::l_brace, StopAtCodeCompletion) ||
+ !SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
+ PA.Revert();
+ return false;
+ }
+ }
+ PA.Commit();
+ return true;
}
/// ParseCXXTryBlock - Parse a C++ try-block.
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=272963&r1=272962&r2=272963&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Thu Jun 16 16:40:06 2016
@@ -1044,6 +1044,12 @@ Decl *Parser::ParseFunctionDefinition(Pa
D.complete(DP);
D.getMutableDeclSpec().abort();
+ if (SkipFunctionBodies && (!DP || Actions.canSkipFunctionBody(DP)) &&
+ trySkippingFunctionBody()) {
+ BodyScope.Exit();
+ return Actions.ActOnSkippedFunctionBody(DP);
+ }
+
CachedTokens Toks;
LexTemplateFunctionForLateParsing(Toks);
@@ -1136,6 +1142,13 @@ Decl *Parser::ParseFunctionDefinition(Pa
return Res;
}
+ if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) &&
+ trySkippingFunctionBody()) {
+ BodyScope.Exit();
+ Actions.ActOnSkippedFunctionBody(Res);
+ return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
+ }
+
if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res, BodyScope);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=272963&r1=272962&r2=272963&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jun 16 16:40:06 2016
@@ -11384,7 +11384,7 @@ Decl *Sema::ActOnSkippedFunctionBody(Dec
FD->setHasSkippedBody();
else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(Decl))
MD->setHasSkippedBody();
- return ActOnFinishFunctionBody(Decl, nullptr);
+ return Decl;
}
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
Added: cfe/trunk/test/CodeCompletion/ctor-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/ctor-initializer.cpp?rev=272963&view=auto
==============================================================================
--- cfe/trunk/test/CodeCompletion/ctor-initializer.cpp (added)
+++ cfe/trunk/test/CodeCompletion/ctor-initializer.cpp Thu Jun 16 16:40:06 2016
@@ -0,0 +1,41 @@
+struct Base1 {
+ Base1() : {}
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:2:12 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+ // CHECK-CC1: COMPLETION: Pattern : member1(<#args#>)
+ // CHECK-CC1: COMPLETION: Pattern : member2(<#args#>
+
+ Base1(int) : member1(123), {}
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:7:30 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+ // CHECK-CC2-NOT: COMPLETION: Pattern : member1(<#args#>)
+ // CHECK-CC2: COMPLETION: Pattern : member2(<#args#>
+
+ int member1;
+ float member2;
+};
+
+struct Derived : public Base1 {
+ Derived();
+ Derived(int);
+ Derived(float);
+ int deriv1;
+};
+
+Derived::Derived() : {}
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:23:22 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: COMPLETION: Pattern : Base1(<#args#>)
+// CHECK-CC3: COMPLETION: Pattern : deriv1(<#args#>)
+
+Derived::Derived(int) try : {
+} catch (...) {
+}
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:28:29 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: COMPLETION: Pattern : Base1(<#args#>)
+// CHECK-CC4: COMPLETION: Pattern : deriv1(<#args#>)
+
+Derived::Derived(float) try : Base1(),
+{
+} catch (...) {
+}
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:35:39 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5-NOT: COMPLETION: Pattern : Base1(<#args#>)
+// CHECK-CC5: COMPLETION: Pattern : deriv1(<#args#>)
Modified: cfe/trunk/unittests/Tooling/ToolingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ToolingTest.cpp?rev=272963&r1=272962&r2=272963&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/ToolingTest.cpp (original)
+++ cfe/trunk/unittests/Tooling/ToolingTest.cpp Thu Jun 16 16:40:06 2016
@@ -241,7 +241,7 @@ TEST(newFrontendActionFactory, InjectsSo
struct SkipBodyConsumer : public clang::ASTConsumer {
/// Skip the 'skipMe' function.
bool shouldSkipFunctionBody(Decl *D) override {
- FunctionDecl *F = dyn_cast<FunctionDecl>(D);
+ NamedDecl *F = dyn_cast<NamedDecl>(D);
return F && F->getNameAsString() == "skipMe";
}
};
@@ -255,10 +255,64 @@ struct SkipBodyAction : public clang::AS
};
TEST(runToolOnCode, TestSkipFunctionBody) {
+ std::vector<std::string> Args = {"-std=c++11"};
+
EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
"int skipMe() { an_error_here }"));
EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
"int skipMeNot() { an_error_here }"));
+
+ // Test constructors with initializers
+ EXPECT_TRUE(runToolOnCodeWithArgs(
+ new SkipBodyAction,
+ "struct skipMe { skipMe() : an_error() { more error } };", Args));
+ EXPECT_TRUE(runToolOnCodeWithArgs(
+ new SkipBodyAction, "struct skipMe { skipMe(); };"
+ "skipMe::skipMe() : an_error([](){;}) { more error }",
+ Args));
+ EXPECT_TRUE(runToolOnCodeWithArgs(
+ new SkipBodyAction, "struct skipMe { skipMe(); };"
+ "skipMe::skipMe() : an_error{[](){;}} { more error }",
+ Args));
+ EXPECT_TRUE(runToolOnCodeWithArgs(
+ new SkipBodyAction,
+ "struct skipMe { skipMe(); };"
+ "skipMe::skipMe() : a<b<c>(e)>>(), f{}, g() { error }",
+ Args));
+ EXPECT_TRUE(runToolOnCodeWithArgs(
+ new SkipBodyAction, "struct skipMe { skipMe() : bases()... { error } };",
+ Args));
+
+ EXPECT_FALSE(runToolOnCodeWithArgs(
+ new SkipBodyAction, "struct skipMeNot { skipMeNot() : an_error() { } };",
+ Args));
+ EXPECT_FALSE(runToolOnCodeWithArgs(new SkipBodyAction,
+ "struct skipMeNot { skipMeNot(); };"
+ "skipMeNot::skipMeNot() : an_error() { }",
+ Args));
+
+ // Try/catch
+ EXPECT_TRUE(runToolOnCode(
+ new SkipBodyAction,
+ "void skipMe() try { an_error() } catch(error) { error };"));
+ EXPECT_TRUE(runToolOnCode(
+ new SkipBodyAction,
+ "struct S { void skipMe() try { an_error() } catch(error) { error } };"));
+ EXPECT_TRUE(
+ runToolOnCode(new SkipBodyAction,
+ "void skipMe() try { an_error() } catch(error) { error; }"
+ "catch(error) { error } catch (error) { }"));
+ EXPECT_FALSE(runToolOnCode(
+ new SkipBodyAction,
+ "void skipMe() try something;")); // don't crash while parsing
+
+ // Template
+ EXPECT_TRUE(runToolOnCode(
+ new SkipBodyAction, "template<typename T> int skipMe() { an_error_here }"
+ "int x = skipMe<int>();"));
+ EXPECT_FALSE(
+ runToolOnCode(new SkipBodyAction,
+ "template<typename T> int skipMeNot() { an_error_here }"));
}
TEST(runToolOnCodeWithArgs, TestNoDepFile) {
More information about the cfe-commits
mailing list