llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangd Author: Yihan Wang (yronglin) <details> <summary>Changes</summary> In code-completion mode, `Parser::trySkippingFunctionBody()` uses a TentativeParsingAction to decide whether a function body can be skipped. We use `SkipUntil(tok::r_brace, StopAtCodeCompletion)`, which consumes the matching closing brace while the tentative parse is still active. Consuming that brace lexes one token past the skipped function body. In clangd, when the completion point is reached while unwinding a self-include, this can hit the code-completion `EOF` path before the tentative parse has committed. That `EOF` path restores the lexer callback to `CLK_CachingLexer`. When control returns to CachingLex(), it tries to enter caching lex mode again and encounters the assertion (We tried to re-enter CachineLexMode while the Preprocessor was already in CachineLexMode.). We fix this by stopping before the function body's closing brace while the tentative parse is active. Once we know the body does not contain the code-completion token, commit the tentative parse first, then consume the closing brace outside backtracking/caching mode. Function try blocks conservatively fall back to normal parsing in code-completion mode, because determining the end of the full try/catch sequence requires lexing across body/catch boundaries while the tentative parse is active. Add a clangd regression test covering a self-include file where signature help is requested at the main-file #endif after the included function body. Fixes https://github.com/llvm/llvm-project/issues/200677 --- Full diff: https://github.com/llvm/llvm-project/pull/203716.diff 2 Files Affected: - (modified) clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp (+17) - (modified) clang/lib/Parse/ParseStmt.cpp (+5-9) ``````````diff diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 5808b2145965f..dc94af4dddf8c 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -1918,6 +1918,23 @@ TEST(SignatureHelpTest, StalePreamble) { EXPECT_EQ(0, Results.activeParameter); } +TEST(SignatureHelpTest, EOFInSkippedFunctionBody) { + Annotations Test(R"cpp( +#ifdef IS_HEADER +void frameSizeBlocksWarning() { + auto fn = []() { + }; + fn(); +} +#else +#define IS_HEADER +#include __FILE__ +#^endif +)cpp"); + auto Results = signatures(Test.code(), Test.point()); + EXPECT_THAT(Results.signatures, IsEmpty()); +} + class IndexRequestCollector : public SymbolIndex { public: IndexRequestCollector(std::vector<Symbol> Syms = {}) : Symbols(Syms) {} diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 37f142e059930..e77d6066847b2 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -2496,8 +2496,10 @@ bool Parser::trySkippingFunctionBody() { // We're in code-completion mode. Skip parsing for all function bodies unless // the body contains the code-completion point. + if (Tok.is(tok::kw_try)) + return false; + TentativeParsingAction PA(*this); - bool IsTryCatch = Tok.is(tok::kw_try); CachedTokens Toks; bool ErrorInPrologue = ConsumeAndStoreFunctionPrologue(Toks); if (llvm::any_of(Toks, [](const Token &Tok) { @@ -2511,18 +2513,12 @@ bool Parser::trySkippingFunctionBody() { SkipMalformedDecl(); return true; } - if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) { + if (!SkipUntil(tok::r_brace, StopAtCodeCompletion | StopBeforeMatch)) { 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(); + ConsumeBrace(); return true; } `````````` </details> https://github.com/llvm/llvm-project/pull/203716 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
