15#include "clang/AST/Decl.h"
16#include "clang/Basic/DiagnosticFrontend.h"
17#include "clang/Frontend/CompilerInstance.h"
18#include "clang/Frontend/FrontendOptions.h"
19#include "clang/Lex/PPCallbacks.h"
20#include "clang/Lex/Preprocessor.h"
21#include "llvm/Support/Error.h"
22#include "gmock/gmock.h"
23#include "gtest/gtest.h"
32 struct Listener final : ASTListener {
33 Listener(TestModule &Module) : Module(Module) {}
35 void beforeBeginSourceFile(CompilerInstance &CI)
override {
36 if (Module.BeforeBeginSourceFile)
37 Module.BeforeBeginSourceFile(CI);
39 void beforePPCallbacks(CompilerInstance &CI)
override {
40 if (Module.BeforePPCallbacks)
41 Module.BeforePPCallbacks(CI);
43 void beforeExecute(CompilerInstance &CI)
override {
44 if (Module.BeforeExecute)
45 Module.BeforeExecute(CI);
47 void afterExecute(CompilerInstance &CI)
override {
48 if (Module.AfterExecute)
49 Module.AfterExecute(CI);
51 void sawDiagnostic(
const clang::Diagnostic &
Info,
52 clangd::Diag &Diag)
override {
53 if (Module.SawDiagnostic)
54 Module.SawDiagnostic(
Info, Diag);
56 void finalizeDiagnostic(clangd::Diag &Diag)
override {
57 if (Module.FinalizeDiagnostic)
58 Module.FinalizeDiagnostic(Diag);
65 std::unique_ptr<ASTListener> astListeners()
override {
66 return std::make_unique<Listener>(*
this);
69 std::function<void(CompilerInstance &)> BeforeBeginSourceFile;
70 std::function<void(CompilerInstance &)> BeforePPCallbacks;
71 std::function<void(CompilerInstance &)> BeforeExecute;
72 std::function<void(CompilerInstance &)> AfterExecute;
73 std::function<void(
const clang::Diagnostic &, clangd::Diag &)> SawDiagnostic;
74 std::function<void(clangd::Diag &)> FinalizeDiagnostic;
77TEST(FeatureModulesTest, ContributesTweak) {
78 static constexpr const char *TweakID =
"ModuleTweak";
80 struct ModuleTweak final :
public Tweak {
81 const char *id()
const override {
return TweakID; }
82 bool prepare(
const Selection &Sel)
override {
return true; }
83 Expected<Effect> apply(
const Selection &Sel)
override {
84 return error(
"not implemented");
86 std::string title()
const override {
return id(); }
87 llvm::StringLiteral kind()
const override {
88 return llvm::StringLiteral(
"");
92 void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out)
override {
93 Out.emplace_back(
new ModuleTweak);
98 Set.
add(std::make_unique<TweakContributingModule>());
106 ASSERT_TRUE(
bool(Actual));
107 EXPECT_EQ(Actual->get()->id(), TweakID);
110TEST(FeatureModulesTest, SuppressDiags) {
112 struct Listener :
public FeatureModule::ASTListener {
113 void sawDiagnostic(
const clang::Diagnostic &Info,
114 clangd::Diag &Diag)
override {
115 Diag.Severity = DiagnosticsEngine::Ignored;
118 std::unique_ptr<ASTListener> astListeners()
override {
119 return std::make_unique<Listener>();
123 FMS.
add(std::make_unique<DiagModifierModule>());
127 TU.
Code = Code.code().str();
130 auto AST = TU.build();
131 EXPECT_THAT(
AST.getDiagnostics(), testing::Not(testing::IsEmpty()));
134 TU.FeatureModules = &FMS;
136 auto AST = TU.build();
137 EXPECT_THAT(
AST.getDiagnostics(), testing::IsEmpty());
141TEST(FeatureModulesTest, BeforeBeginSourceFile) {
142 std::vector<frontend::ActionKind> Builds;
143 auto Module = std::make_unique<TestModule>();
144 Module->BeforeBeginSourceFile = [&](CompilerInstance &CI) {
145 Builds.push_back(CI.getFrontendOpts().ProgramAction);
153 TU.AdditionalFiles["header.h"] =
"struct HeaderType {};";
154 TU.FeatureModules = &Modules;
155 EXPECT_THAT(TU.build().getDiagnostics(), testing::IsEmpty());
158 EXPECT_THAT(Builds, testing::ElementsAre(frontend::ParseSyntaxOnly));
161TEST(FeatureModulesTest, BeforeBeginSourceFileDiagnostics) {
162 unsigned SeenDiagnostics = 0;
163 auto Module = std::make_unique<TestModule>();
164 Module->BeforeBeginSourceFile = [](CompilerInstance &CI) {
167 CI.getDiagnostics().setSeverity(
168 diag::warn_fe_macro_contains_embedded_newline, diag::Severity::Error,
171 Module->SawDiagnostic = [&](
const clang::Diagnostic &
Info, clangd::Diag &) {
172 if (
Info.getID() == diag::warn_fe_macro_contains_embedded_newline)
179 TU.ExtraArgs = {
"-DMACRO=first\nsecond"};
180 TU.FeatureModules = &Modules;
181 auto AST = TU.build();
184 EXPECT_EQ(
AST.getPreprocessor().getDiagnostics().getNumErrors(), 1u);
187 EXPECT_EQ(SeenDiagnostics, 0u);
190TEST(FeatureModulesTest, BeforePPCallbacks) {
191 struct IncludeRecorder :
public PPCallbacks {
192 IncludeRecorder(std::vector<std::string> &Includes) : Includes(Includes) {}
194 void InclusionDirective(SourceLocation,
const Token &, StringRef FileName,
195 bool, CharSourceRange, OptionalFileEntryRef,
196 StringRef, StringRef,
const clang::Module *,
bool,
197 SrcMgr::CharacteristicKind)
override {
198 Includes.push_back(FileName.str());
202 std::vector<std::string> &Includes;
204 std::vector<std::string> Includes;
205 auto Module = std::make_unique<TestModule>();
206 Module->BeforePPCallbacks = [&Includes](CompilerInstance &CI) {
213 if (CI.getFrontendOpts().ProgramAction == frontend::ParseSyntaxOnly)
214 CI.getPreprocessor().addPPCallbacks(
215 std::make_unique<IncludeRecorder>(Includes));
222 void mainFileFunc(); // Ends the preamble; parsed during the main-file build.
224 TU.AdditionalFiles["header.h"] =
"";
225 TU.FeatureModules = &FMS;
227 EXPECT_THAT(Includes, testing::ElementsAre(
"header.h"));
230TEST(FeatureModulesTest, BeforeExecute) {
231 auto Module = std::make_unique<TestModule>();
232 Module->BeforeExecute = [](CompilerInstance &CI) {
233 CI.getPreprocessor().SetSuppressIncludeNotFoundError(
true);
240 #include "not_found.h"
243 #include "not_found_not_preamble.h"
248 auto AST = TU.build();
249 EXPECT_THAT(
AST.getDiagnostics(), testing::Not(testing::IsEmpty()));
252 TU.FeatureModules = &FMS;
254 auto AST = TU.build();
255 EXPECT_THAT(
AST.getDiagnostics(), testing::IsEmpty());
259TEST(FeatureModulesTest, AfterExecute) {
260 std::vector<std::string> DeclNames;
261 auto Module = std::make_unique<TestModule>();
262 Module->AfterExecute = [&DeclNames](CompilerInstance &CI) {
263 for (Decl *D : CI.getASTContext().getTraversalScope())
264 if (
const auto *ND = llvm::dyn_cast<NamedDecl>(D))
265 DeclNames.push_back(ND->getNameAsString());
274 TU.AdditionalFiles["header.h"] =
"void headerFunc();";
275 TU.FeatureModules = &FMS;
280 EXPECT_THAT(DeclNames, testing::ElementsAre(
"mainFileFunc"));
283TEST(FeatureModulesTest, FinalizeDiagnostic) {
286 auto Module = std::make_unique<TestModule>();
287 Module->FinalizeDiagnostic = [&](clangd::Diag &
Diag) {
288 if (
Diag.
Message.find(
"undeclared identifier 'fooo'") == std::string::npos)
298 void bar() { fooo(); } // error-ok
300 TU.FeatureModules = &FMS;
301 EXPECT_THAT(TU.build().getDiagnostics(), testing::SizeIs(1));
302 EXPECT_EQ(Notes, 1u);
303 EXPECT_EQ(Fixes, 1u);
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
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)
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.