diff options
| -rw-r--r-- | clang-tools-extra/clangd/ClangdUnit.cpp | 11 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp | 21 | 
2 files changed, 28 insertions, 4 deletions
diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp index 3beec0aa228..b337d851d0f 100644 --- a/clang-tools-extra/clangd/ClangdUnit.cpp +++ b/clang-tools-extra/clangd/ClangdUnit.cpp @@ -421,12 +421,16 @@ ParsedAST::build(std::unique_ptr<CompilerInvocation> CI,    Clang->getPreprocessor().addCommentHandler(IWYUHandler.get());    // Collect tokens of the main file. -  syntax::TokenCollector Tokens(Clang->getPreprocessor()); +  syntax::TokenCollector CollectTokens(Clang->getPreprocessor());    if (llvm::Error Err = Action->Execute())      log("Execute() failed when building AST for {0}: {1}", MainInput.getFile(),          toString(std::move(Err))); +  // We have to consume the tokens before running clang-tidy to avoid collecting +  // tokens from running the preprocessor inside the checks (only +  // modernize-use-trailing-return-type does that today). +  syntax::TokenBuffer Tokens = std::move(CollectTokens).consume();    std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();    // AST traversals should exclude the preamble, to avoid performance cliffs.    Clang->getASTContext().setTraversalScope(ParsedDecls); @@ -452,9 +456,8 @@ ParsedAST::build(std::unique_ptr<CompilerInvocation> CI,    if (Preamble)      Diags.insert(Diags.begin(), Preamble->Diags.begin(), Preamble->Diags.end());    return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action), -                   std::move(Tokens).consume(), std::move(ParsedDecls), -                   std::move(Diags), std::move(Includes), -                   std::move(CanonIncludes)); +                   std::move(Tokens), std::move(ParsedDecls), std::move(Diags), +                   std::move(Includes), std::move(CanonIncludes));  }  ParsedAST::ParsedAST(ParsedAST &&Other) = default; diff --git a/clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp b/clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp index 3b5920e947d..47c353ee106 100644 --- a/clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdUnitTests.cpp @@ -134,6 +134,27 @@ TEST(ClangdUnitTest, TokensAfterPreamble) {    EXPECT_EQ(Spelled.back().text(SM), "last_token");  } + +TEST(ClangdUnitTest, NoCrashOnTokensWithTidyCheck) { +  TestTU TU; +  // this check runs the preprocessor, we need to make sure it does not break +  // our recording logic. +  TU.ClangTidyChecks = "modernize-use-trailing-return-type"; +  TU.Code = "inline int foo() {}"; + +  auto AST = TU.build(); +  const syntax::TokenBuffer &T = AST.getTokens(); +  const auto &SM = AST.getSourceManager(); + +  ASSERT_GT(T.expandedTokens().size(), 7u); +  // Check first token after the preamble. +  EXPECT_EQ(T.expandedTokens().front().text(SM), "inline"); +  // Last token is always 'eof'. +  EXPECT_EQ(T.expandedTokens().back().kind(), tok::eof); +  // Check the token before 'eof'. +  EXPECT_EQ(T.expandedTokens().drop_back().back().text(SM), "}"); +} +  } // namespace  } // namespace clangd  } // namespace clang  | 

