15#include "clang/AST/Decl.h"
16#include "clang/Frontend/FrontendOptions.h"
17#include "clang/Lex/PPCallbacks.h"
18#include "clang/Lex/PreprocessorOptions.h"
19#include "llvm/Support/Error.h"
20#include "gmock/gmock.h"
21#include "gtest/gtest.h"
30 struct Listener final : ASTListener {
31 Listener(TestModule &Module) : Module(Module) {}
33 void beforePPCallbacks(CompilerInstance &CI)
override {
34 if (Module.BeforePPCallbacks)
35 Module.BeforePPCallbacks(CI);
37 void beforeExecute(CompilerInstance &CI)
override {
38 if (Module.BeforeExecute)
39 Module.BeforeExecute(CI);
41 void afterExecute(CompilerInstance &CI)
override {
42 if (Module.AfterExecute)
43 Module.AfterExecute(CI);
45 void finalizeDiagnostic(clangd::Diag &Diag)
override {
46 if (Module.FinalizeDiagnostic)
47 Module.FinalizeDiagnostic(Diag);
54 std::unique_ptr<ASTListener> astListeners()
override {
55 return std::make_unique<Listener>(*
this);
58 std::function<void(CompilerInstance &)> BeforePPCallbacks;
59 std::function<void(CompilerInstance &)> BeforeExecute;
60 std::function<void(CompilerInstance &)> AfterExecute;
61 std::function<void(clangd::Diag &)> FinalizeDiagnostic;
64TEST(FeatureModulesTest, ContributesTweak) {
65 static constexpr const char *TweakID =
"ModuleTweak";
67 struct ModuleTweak final :
public Tweak {
68 const char *id()
const override {
return TweakID; }
69 bool prepare(
const Selection &Sel)
override {
return true; }
70 Expected<Effect> apply(
const Selection &Sel)
override {
71 return error(
"not implemented");
73 std::string title()
const override {
return id(); }
74 llvm::StringLiteral kind()
const override {
75 return llvm::StringLiteral(
"");
79 void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out)
override {
80 Out.emplace_back(
new ModuleTweak);
85 Set.
add(std::make_unique<TweakContributingModule>());
93 ASSERT_TRUE(
bool(Actual));
94 EXPECT_EQ(Actual->get()->id(), TweakID);
97TEST(FeatureModulesTest, SuppressDiags) {
99 struct Listener :
public FeatureModule::ASTListener {
100 void sawDiagnostic(
const clang::Diagnostic &Info,
101 clangd::Diag &Diag)
override {
102 Diag.Severity = DiagnosticsEngine::Ignored;
105 std::unique_ptr<ASTListener> astListeners()
override {
106 return std::make_unique<Listener>();
110 FMS.
add(std::make_unique<DiagModifierModule>());
114 TU.
Code = Code.code().str();
117 auto AST = TU.build();
118 EXPECT_THAT(
AST.getDiagnostics(), testing::Not(testing::IsEmpty()));
121 TU.FeatureModules = &FMS;
123 auto AST = TU.build();
124 EXPECT_THAT(
AST.getDiagnostics(), testing::IsEmpty());
128TEST(FeatureModulesTest, BeforePPCallbacks) {
129 struct IncludeRecorder :
public PPCallbacks {
130 IncludeRecorder(std::vector<std::string> &Includes) : Includes(Includes) {}
132 void InclusionDirective(SourceLocation,
const Token &, StringRef FileName,
133 bool, CharSourceRange, OptionalFileEntryRef,
134 StringRef, StringRef,
const clang::Module *,
bool,
135 SrcMgr::CharacteristicKind)
override {
136 Includes.push_back(FileName.str());
140 std::vector<std::string> &Includes;
142 std::vector<std::string> Includes;
143 auto Module = std::make_unique<TestModule>();
144 Module->BeforePPCallbacks = [&Includes](CompilerInstance &CI) {
151 if (CI.getFrontendOpts().ProgramAction == frontend::ParseSyntaxOnly)
152 CI.getPreprocessor().addPPCallbacks(
153 std::make_unique<IncludeRecorder>(Includes));
160 void mainFileFunc(); // Ends the preamble; parsed during the main-file build.
162 TU.AdditionalFiles["header.h"] =
"";
163 TU.FeatureModules = &FMS;
165 EXPECT_THAT(Includes, testing::ElementsAre(
"header.h"));
168TEST(FeatureModulesTest, BeforeExecute) {
169 auto Module = std::make_unique<TestModule>();
170 Module->BeforeExecute = [](CompilerInstance &CI) {
171 CI.getPreprocessor().SetSuppressIncludeNotFoundError(
true);
178 #include "not_found.h"
181 #include "not_found_not_preamble.h"
186 auto AST = TU.build();
187 EXPECT_THAT(
AST.getDiagnostics(), testing::Not(testing::IsEmpty()));
190 TU.FeatureModules = &FMS;
192 auto AST = TU.build();
193 EXPECT_THAT(
AST.getDiagnostics(), testing::IsEmpty());
197TEST(FeatureModulesTest, AfterExecute) {
198 std::vector<std::string> DeclNames;
199 auto Module = std::make_unique<TestModule>();
200 Module->AfterExecute = [&DeclNames](CompilerInstance &CI) {
201 for (Decl *D : CI.getASTContext().getTraversalScope())
202 if (
const auto *ND = llvm::dyn_cast<NamedDecl>(D))
203 DeclNames.push_back(ND->getNameAsString());
212 TU.AdditionalFiles["header.h"] =
"void headerFunc();";
213 TU.FeatureModules = &FMS;
218 EXPECT_THAT(DeclNames, testing::ElementsAre(
"mainFileFunc"));
221TEST(FeatureModulesTest, FinalizeDiagnostic) {
224 auto Module = std::make_unique<TestModule>();
225 Module->FinalizeDiagnostic = [&](clangd::Diag &
Diag) {
226 if (
Diag.
Message.find(
"undeclared identifier 'fooo'") == std::string::npos)
236 void bar() { fooo(); } // error-ok
238 TU.FeatureModules = &FMS;
239 EXPECT_THAT(TU.build().getDiagnostics(), testing::SizeIs(1));
240 EXPECT_EQ(Notes, 1u);
241 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.
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.