18#include "clang/AST/Decl.h"
19#include "clang/Basic/DiagnosticFrontend.h"
20#include "clang/Frontend/CompilerInstance.h"
21#include "clang/Frontend/FrontendOptions.h"
22#include "clang/Frontend/MultiplexConsumer.h"
23#include "clang/Lex/PPCallbacks.h"
24#include "clang/Lex/Preprocessor.h"
25#include "llvm/Support/Error.h"
26#include "gmock/gmock.h"
27#include "gtest/gtest.h"
36 struct Listener final : ASTListener {
37 Listener(TestModule &Module) : Module(Module) {}
39 void beforeBeginSourceFile(CompilerInstance &CI)
override {
40 if (Module.BeforeBeginSourceFile)
41 Module.BeforeBeginSourceFile(CI);
43 void beforePPCallbacks(CompilerInstance &CI)
override {
44 if (Module.BeforePPCallbacks)
45 Module.BeforePPCallbacks(CI);
47 void beforeExecute(CompilerInstance &CI)
override {
48 if (Module.BeforeExecute)
49 Module.BeforeExecute(CI);
51 void afterExecute(CompilerInstance &CI)
override {
52 if (Module.AfterExecute)
53 Module.AfterExecute(CI);
55 void sawDiagnostic(
const clang::Diagnostic &
Info,
56 clangd::Diag &Diag)
override {
57 if (Module.SawDiagnostic)
58 Module.SawDiagnostic(
Info, Diag);
60 void finalizeDiagnostic(clangd::Diag &Diag)
override {
61 if (Module.FinalizeDiagnostic)
62 Module.FinalizeDiagnostic(Diag);
69 std::unique_ptr<ASTListener> astListeners()
override {
70 return std::make_unique<Listener>(*
this);
73 std::function<void(CompilerInstance &)> BeforeBeginSourceFile;
74 std::function<void(CompilerInstance &)> BeforePPCallbacks;
75 std::function<void(CompilerInstance &)> BeforeExecute;
76 std::function<void(CompilerInstance &)> AfterExecute;
77 std::function<void(
const clang::Diagnostic &, clangd::Diag &)> SawDiagnostic;
78 std::function<void(clangd::Diag &)> FinalizeDiagnostic;
81TEST(FeatureModulesTest, ContributesTweak) {
82 static constexpr const char *TweakID =
"ModuleTweak";
84 struct ModuleTweak final :
public Tweak {
85 const char *id()
const override {
return TweakID; }
86 bool prepare(
const Selection &Sel)
override {
return true; }
87 Expected<Effect> apply(
const Selection &Sel)
override {
88 return error(
"not implemented");
90 std::string title()
const override {
return id(); }
91 llvm::StringLiteral kind()
const override {
92 return llvm::StringLiteral(
"");
96 void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out)
override {
97 Out.emplace_back(
new ModuleTweak);
102 Set.
add(std::make_unique<TweakContributingModule>());
110 ASSERT_TRUE(
bool(Actual));
111 EXPECT_EQ(Actual->get()->id(), TweakID);
114TEST(FeatureModulesTest, SuppressDiags) {
116 struct Listener :
public FeatureModule::ASTListener {
117 void sawDiagnostic(
const clang::Diagnostic &Info,
118 clangd::Diag &Diag)
override {
119 Diag.Severity = DiagnosticsEngine::Ignored;
122 std::unique_ptr<ASTListener> astListeners()
override {
123 return std::make_unique<Listener>();
127 FMS.
add(std::make_unique<DiagModifierModule>());
131 TU.
Code = Code.code().str();
134 auto AST = TU.build();
135 EXPECT_THAT(
AST.getDiagnostics(), testing::Not(testing::IsEmpty()));
138 TU.FeatureModules = &FMS;
140 auto AST = TU.build();
141 EXPECT_THAT(
AST.getDiagnostics(), testing::IsEmpty());
145TEST(FeatureModulesTest, BeforeBeginSourceFile) {
146 std::vector<frontend::ActionKind> Builds;
147 auto Module = std::make_unique<TestModule>();
148 Module->BeforeBeginSourceFile = [&](CompilerInstance &CI) {
149 Builds.push_back(CI.getFrontendOpts().ProgramAction);
157 TU.AdditionalFiles["header.h"] =
"struct HeaderType {};";
158 TU.FeatureModules = &Modules;
159 EXPECT_THAT(TU.build().getDiagnostics(), testing::IsEmpty());
162 EXPECT_THAT(Builds, testing::ElementsAre(frontend::ParseSyntaxOnly));
165TEST(FeatureModulesTest, BeforeBeginSourceFileDiagnostics) {
166 unsigned SeenDiagnostics = 0;
167 auto Module = std::make_unique<TestModule>();
168 Module->BeforeBeginSourceFile = [](CompilerInstance &CI) {
171 CI.getDiagnostics().setSeverity(
172 diag::warn_fe_macro_contains_embedded_newline, diag::Severity::Error,
175 Module->SawDiagnostic = [&](
const clang::Diagnostic &
Info, clangd::Diag &) {
176 if (
Info.getID() == diag::warn_fe_macro_contains_embedded_newline)
183 TU.ExtraArgs = {
"-DMACRO=first\nsecond"};
184 TU.FeatureModules = &Modules;
185 auto AST = TU.build();
188 EXPECT_EQ(
AST.getPreprocessor().getDiagnostics().getNumErrors(), 1u);
191 EXPECT_EQ(SeenDiagnostics, 0u);
194TEST(FeatureModulesTest, BeforePPCallbacks) {
195 struct IncludeRecorder :
public PPCallbacks {
196 IncludeRecorder(std::vector<std::string> &Includes) : Includes(Includes) {}
198 void InclusionDirective(SourceLocation,
const Token &, StringRef FileName,
199 bool, CharSourceRange, OptionalFileEntryRef,
200 StringRef, StringRef,
const clang::Module *,
bool,
201 SrcMgr::CharacteristicKind)
override {
202 Includes.push_back(FileName.str());
206 std::vector<std::string> &Includes;
208 std::vector<std::string> Includes;
209 auto Module = std::make_unique<TestModule>();
210 Module->BeforePPCallbacks = [&Includes](CompilerInstance &CI) {
217 if (CI.getFrontendOpts().ProgramAction == frontend::ParseSyntaxOnly)
218 CI.getPreprocessor().addPPCallbacks(
219 std::make_unique<IncludeRecorder>(Includes));
226 void mainFileFunc(); // Ends the preamble; parsed during the main-file build.
228 TU.AdditionalFiles["header.h"] =
"";
229 TU.FeatureModules = &FMS;
231 EXPECT_THAT(Includes, testing::ElementsAre(
"header.h"));
234TEST(FeatureModulesTest, BeforeExecute) {
235 auto Module = std::make_unique<TestModule>();
236 Module->BeforeExecute = [](CompilerInstance &CI) {
237 CI.getPreprocessor().SetSuppressIncludeNotFoundError(
true);
244 #include "not_found.h"
247 #include "not_found_not_preamble.h"
252 auto AST = TU.build();
253 EXPECT_THAT(
AST.getDiagnostics(), testing::Not(testing::IsEmpty()));
256 TU.FeatureModules = &FMS;
258 auto AST = TU.build();
259 EXPECT_THAT(
AST.getDiagnostics(), testing::IsEmpty());
263TEST(FeatureModulesTest, AfterExecute) {
264 std::vector<std::string> DeclNames;
265 auto Module = std::make_unique<TestModule>();
266 Module->AfterExecute = [&DeclNames](CompilerInstance &CI) {
267 for (Decl *D : CI.getASTContext().getTraversalScope())
268 if (
const auto *ND = llvm::dyn_cast<NamedDecl>(D))
269 DeclNames.push_back(ND->getNameAsString());
278 TU.AdditionalFiles["header.h"] =
"void headerFunc();";
279 TU.FeatureModules = &FMS;
284 EXPECT_THAT(DeclNames, testing::ElementsAre(
"mainFileFunc"));
287TEST(FeatureModulesTest, FinalizeDiagnostic) {
290 auto Module = std::make_unique<TestModule>();
291 Module->FinalizeDiagnostic = [&](clangd::Diag &
Diag) {
292 if (
Diag.
Message.find(
"undeclared identifier 'fooo'") == std::string::npos)
302 void bar() { fooo(); } // error-ok
304 TU.FeatureModules = &FMS;
305 EXPECT_THAT(TU.build().getDiagnostics(), testing::SizeIs(1));
306 EXPECT_EQ(Notes, 1u);
307 EXPECT_EQ(Fixes, 1u);
310TEST(FeatureModulesTest, ClangTidyTemporaryProvider) {
311 if (!CLANGD_TIDY_CHECKS)
312 GTEST_SKIP() <<
"Requires clang-tidy checks";
314 Modules.
add(std::make_unique<ClangTidyFeatureModule>(
317 TU.FeatureModules = &Modules;
319 auto Provider = std::make_shared<const TidyProvider>(
addTidyChecks(
"-*"));
322 Tidy->swapProvider(Provider);
323 EXPECT_THAT(TU.build().getDiagnostics(), testing::IsEmpty());
324 Tidy->swapProvider(Provider);
325 auto AST = TU.build();
326 ASSERT_THAT(
AST.getDiagnostics(), testing::SizeIs(1));
327 EXPECT_EQ(
AST.getDiagnostics().front().Name,
"modernize-use-nullptr");
330TEST(FeatureModulesTest, ClangTidyDoesNotReinitializeConsumer) {
331 if (!CLANGD_TIDY_CHECKS)
332 GTEST_SKIP() <<
"Requires clang-tidy checks";
333 class InitializationGuard final :
public MultiplexConsumer {
335 using MultiplexConsumer::MultiplexConsumer;
336 void Initialize(ASTContext &Ctx)
override {
337 EXPECT_FALSE(Initialized);
339 MultiplexConsumer::Initialize(Ctx);
343 bool Initialized =
false;
345 auto Module = std::make_unique<TestModule>();
346 Module->BeforePPCallbacks = [](CompilerInstance &CI) {
347 if (CI.getFrontendOpts().ProgramAction == frontend::ParseSyntaxOnly)
349 std::make_unique<InitializationGuard>(CI.takeASTConsumer()));
354 TU.FeatureModules = &Modules;
355 Modules.add(std::make_unique<ClangTidyFeatureModule>(
358 EXPECT_THAT(TU.build().getDiagnostics(), testing::SizeIs(1));
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Runs clang-tidy checks as part of clangd's AST build.
A FeatureModuleSet is a collection of feature modules installed in clangd.
void add(std::unique_ptr< FeatureModule > M)
A FeatureModule contributes a vertical feature to clangd.
static SelectionTree createRight(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End)
llvm::Error error(std::error_code, std::string &&)
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
@ Info
An information message.
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S, const FeatureModuleSet *Modules)
TidyProvider addTidyChecks(llvm::StringRef Checks, llvm::StringRef WarningsAsErrors)
Provider the enables a specific set of checks and warnings as errors.
TEST(BackgroundQueueTest, Priority)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A top-level diagnostic that may have Notes and Fixes.
std::vector< Fix > Fixes
Alternative fixes for this diagnostic, one should be chosen.
std::vector< Note > Notes
Elaborate on the problem, usually pointing to a related piece of code.
static TestTU withCode(llvm::StringRef Code)
Input to prepare and apply tweaks.