diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -283,15 +283,21 @@ llvm::Optional Patch; bool PreserveDiags = true; + // We might use an ignoring diagnostic consumer if they are going to be + // dropped later on to not pay for extra latency by processing them. + DiagnosticConsumer *DiagConsumer = &ASTDiags; + IgnoreDiagnostics DropDiags; if (Preamble) { Patch = PreamblePatch::createFullPatch(Filename, Inputs, *Preamble); Patch->apply(*CI); PreserveDiags = Patch->preserveDiagnostics(); + if (!PreserveDiags) + DiagConsumer = &DropDiags; } auto Clang = prepareCompilerInstance( std::move(CI), PreamblePCH, llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS, - ASTDiags); + *DiagConsumer); if (!Clang) { // The last diagnostic contains information about the reason of this // failure. @@ -301,6 +307,10 @@ : "unknown error"); return None; } + if (!PreserveDiags) { + // Skips some analysis. + Clang->getDiagnosticOpts().IgnoreWarnings = true; + } auto Action = std::make_unique(); const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0]; @@ -329,7 +339,10 @@ std::vector> CTChecks; ast_matchers::MatchFinder CTFinder; llvm::Optional CTContext; - { + llvm::Optional FixIncludes; + // No need to run clang-tidy or IncludeFixerif we are not going to surface + // diagnostics. + if (PreserveDiags) { trace::Span Tracer("ClangTidyInit"); tidy::ClangTidyOptions ClangTidyOpts = getTidyOptionsForFile(Inputs.ClangTidyProvider, Filename); @@ -389,28 +402,28 @@ } return DiagLevel; }); - } - // Add IncludeFixer which can recover diagnostics caused by missing includes - // (e.g. incomplete type) and attach include insertion fixes to diagnostics. - llvm::Optional FixIncludes; - auto BuildDir = VFS->getCurrentWorkingDirectory(); - if (Inputs.Index && !BuildDir.getError()) { - auto Style = getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS); - auto Inserter = std::make_shared( - Filename, Inputs.Contents, Style, BuildDir.get(), - &Clang->getPreprocessor().getHeaderSearchInfo()); - if (Preamble) { - for (const auto &Inc : Preamble->Includes.MainFileIncludes) - Inserter->addExisting(Inc); + // Add IncludeFixer which can recover diagnostics caused by missing includes + // (e.g. incomplete type) and attach include insertion fixes to diagnostics. + auto BuildDir = VFS->getCurrentWorkingDirectory(); + if (Inputs.Index && !BuildDir.getError()) { + auto Style = + getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS); + auto Inserter = std::make_shared( + Filename, Inputs.Contents, Style, BuildDir.get(), + &Clang->getPreprocessor().getHeaderSearchInfo()); + if (Preamble) { + for (const auto &Inc : Preamble->Includes.MainFileIncludes) + Inserter->addExisting(Inc); + } + FixIncludes.emplace(Filename, Inserter, *Inputs.Index, + /*IndexRequestLimit=*/5); + ASTDiags.contributeFixes([&FixIncludes](DiagnosticsEngine::Level DiagLevl, + const clang::Diagnostic &Info) { + return FixIncludes->fix(DiagLevl, Info); + }); + Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder()); } - FixIncludes.emplace(Filename, Inserter, *Inputs.Index, - /*IndexRequestLimit=*/5); - ASTDiags.contributeFixes([&FixIncludes](DiagnosticsEngine::Level DiagLevl, - const clang::Diagnostic &Info) { - return FixIncludes->fix(DiagLevl, Info); - }); - Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder()); } IncludeStructure Includes; diff --git a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp --- a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp @@ -460,77 +460,6 @@ Code.substr(FileRange.Begin - 1, FileRange.End - FileRange.Begin + 2)); EXPECT_EQ(SkippedFiles[I].kind(), tok::header_name); } - - TU.AdditionalFiles["a.h"] = ""; - TU.AdditionalFiles["b.h"] = ""; - TU.AdditionalFiles["c.h"] = ""; - // Make sure replay logic works with patched preambles. - llvm::StringLiteral Baseline = R"cpp( - #include "a.h" - #include "c.h")cpp"; - MockFS FS; - TU.Code = Baseline.str(); - auto Inputs = TU.inputs(FS); - auto BaselinePreamble = TU.preamble(); - ASSERT_TRUE(BaselinePreamble); - - // First make sure we don't crash on various modifications to the preamble. - llvm::StringLiteral Cases[] = { - // clang-format off - // New include in middle. - R"cpp( - #include "a.h" - #include "b.h" - #include "c.h")cpp", - // New include at top. - R"cpp( - #include "b.h" - #include "a.h" - #include "c.h")cpp", - // New include at bottom. - R"cpp( - #include "a.h" - #include "c.h" - #include "b.h")cpp", - // Same size with a missing include. - R"cpp( - #include "a.h" - #include "b.h")cpp", - // Smaller with no new includes. - R"cpp( - #include "a.h")cpp", - // Smaller with a new includes. - R"cpp( - #include "b.h")cpp", - // clang-format on - }; - for (llvm::StringLiteral Case : Cases) { - TU.Code = Case.str(); - - IgnoreDiagnostics Diags; - auto CI = buildCompilerInvocation(TU.inputs(FS), Diags); - auto PatchedAST = ParsedAST::build(testPath(TU.Filename), TU.inputs(FS), - std::move(CI), {}, BaselinePreamble); - ASSERT_TRUE(PatchedAST); - EXPECT_FALSE(PatchedAST->getDiagnostics()); - } - - // Then ensure correctness by making sure includes were seen only once. - // Note that we first see the includes from the patch, as preamble includes - // are replayed after exiting the built-in file. - Includes.clear(); - TU.Code = R"cpp( - #include "a.h" - #include "b.h")cpp"; - IgnoreDiagnostics Diags; - auto CI = buildCompilerInvocation(TU.inputs(FS), Diags); - auto PatchedAST = ParsedAST::build(testPath(TU.Filename), TU.inputs(FS), - std::move(CI), {}, BaselinePreamble); - ASSERT_TRUE(PatchedAST); - EXPECT_FALSE(PatchedAST->getDiagnostics()); - EXPECT_THAT(Includes, - ElementsAre(WithFileName(testPath("__preamble_patch__.h")), - WithFileName("b.h"), WithFileName("a.h"))); } TEST(ParsedASTTest, PatchesAdditionalIncludes) {