14#include "../../clang-tidy/ClangTidyCheck.h"
15#include "../../clang-tidy/ClangTidyModule.h"
16#include "../../clang-tidy/ClangTidyModuleRegistry.h"
25#include "clang/AST/DeclTemplate.h"
26#include "clang/Basic/FileEntry.h"
27#include "clang/Basic/LLVM.h"
28#include "clang/Basic/Module.h"
29#include "clang/Basic/SourceLocation.h"
30#include "clang/Basic/SourceManager.h"
31#include "clang/Basic/TokenKinds.h"
32#include "clang/Lex/PPCallbacks.h"
33#include "clang/Lex/Token.h"
34#include "clang/Tooling/Syntax/Tokens.h"
35#include "llvm/ADT/StringRef.h"
36#include "llvm/Support/Registry.h"
37#include "llvm/Testing/Annotations/Annotations.h"
38#include "gmock/gmock-matchers.h"
39#include "gmock/gmock.h"
40#include "gtest/gtest.h"
48 Inclusion(
const SourceManager &SM, SourceLocation HashLoc,
50 CharSourceRange FilenameRange)
53 FileNameOffset(SM.getDecomposedLoc(FilenameRange.getBegin()).second),
56 toSourceCode(SM, FilenameRange.getAsRange()).drop_back().drop_front(),
66static std::vector<Inclusion> Includes;
67static std::vector<syntax::Token> SkippedFiles;
68struct ReplayPreamblePPCallback :
public PPCallbacks {
69 const SourceManager &SM;
70 explicit ReplayPreamblePPCallback(
const SourceManager &SM) : SM(SM) {}
72 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
74 CharSourceRange FilenameRange, OptionalFileEntryRef,
75 StringRef, StringRef,
const clang::Module *,
bool,
76 SrcMgr::CharacteristicKind)
override {
81 void FileSkipped(
const FileEntryRef &,
const Token &FilenameTok,
82 SrcMgr::CharacteristicKind)
override {
83 SkippedFiles.emplace_back(FilenameTok);
86struct ReplayPreambleCheck :
public tidy::ClangTidyCheck {
87 ReplayPreambleCheck(StringRef
Name, tidy::ClangTidyContext *Context)
88 : ClangTidyCheck(
Name, Context) {}
89 void registerPPCallbacks(
const SourceManager &SM, Preprocessor *PP,
90 Preprocessor *ModuleExpanderPP)
override {
91 PP->addPPCallbacks(::std::make_unique<ReplayPreamblePPCallback>(SM));
94llvm::StringLiteral CheckName =
"replay-preamble-check";
95struct ReplayPreambleModule :
public tidy::ClangTidyModule {
97 addCheckFactories(tidy::ClangTidyCheckFactories &CheckFactories)
override {
98 CheckFactories.registerCheck<ReplayPreambleCheck>(CheckName);
101static tidy::ClangTidyModuleRegistry::Add<ReplayPreambleModule>
102 X(
"replay-preamble-module",
"");
105 return arg.beginOffset() == R.Begin && arg.endOffset() == R.End;
108TEST(ReplayPreambleTest, IncludesAndSkippedFiles) {
112 llvm::Annotations Test(R
"cpp(
113 $hash^#$include[[import]] $filebegin^"$filerange[[bar.h]]"
114 $hash^#$include[[include_next]] $filebegin^"$filerange[[baz.h]]"
115 $hash^#$include[[include]] $filebegin^<$filerange[[a.h]]>)cpp");
116 llvm::StringRef Code = Test.code();
117 TU.Code = Code.str();
118 TU.AdditionalFiles["bar.h"] =
"";
119 TU.AdditionalFiles[
"baz.h"] =
"";
120 TU.AdditionalFiles[
"a.h"] =
"";
124 TU.ExtraArgs = {
"-isystem.",
"-xobjective-c"};
129 WithContextValue WithCfg(
Config::Key, std::move(Cfg));
131 const auto &
AST = TU.build();
132 const auto &SM =
AST.getSourceManager();
134 auto HashLocs = Test.points(
"hash");
135 ASSERT_EQ(HashLocs.size(), Includes.size());
136 auto IncludeRanges = Test.ranges(
"include");
137 ASSERT_EQ(IncludeRanges.size(), Includes.size());
138 auto FileBeginLocs = Test.points(
"filebegin");
139 ASSERT_EQ(FileBeginLocs.size(), Includes.size());
140 auto FileRanges = Test.ranges(
"filerange");
141 ASSERT_EQ(FileRanges.size(), Includes.size());
143 ASSERT_EQ(SkippedFiles.size(), Includes.size());
144 for (
size_t I = 0; I < Includes.size(); ++I) {
145 const auto &Inc = Includes[I];
147 EXPECT_EQ(Inc.HashOffset, HashLocs[I]);
149 auto IncRange = IncludeRanges[I];
150 EXPECT_THAT(Inc.IncTok.range(SM), rangeIs(IncRange));
151 EXPECT_EQ(Inc.IncTok.kind(), tok::identifier);
152 EXPECT_EQ(Inc.IncDirective,
153 Code.substr(IncRange.Begin, IncRange.End - IncRange.Begin));
155 EXPECT_EQ(Inc.FileNameOffset, FileBeginLocs[I]);
156 EXPECT_EQ(Inc.IsAngled,
Code[FileBeginLocs[I]] ==
'<');
158 auto FileRange = FileRanges[I];
159 EXPECT_EQ(Inc.FileName,
160 Code.substr(FileRange.Begin, FileRange.End - FileRange.Begin));
162 EXPECT_EQ(SM.getDecomposedLoc(SkippedFiles[I].location()).second,
167 SkippedFiles[I].text(SM),
168 Code.substr(FileRange.Begin - 1, FileRange.End - FileRange.Begin + 2));
169 EXPECT_EQ(SkippedFiles[I].kind(), tok::header_name);
llvm::SmallString< 256U > Name
bool IsAngled
true if this was an include with angle brackets
llvm::StringRef IncDirective
TidyProvider addTidyChecks(llvm::StringRef Checks, llvm::StringRef WarningsAsErrors)
Provider the enables a specific set of checks and warnings as errors.
TEST(BackgroundQueueTest, Priority)
llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R)
Returns the source code covered by the source range.
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
FastCheckPolicy FastCheckFilter
struct clang::clangd::Config::@4::@12 ClangTidy
Configures what clang-tidy checks to run and options to use with them.
struct clang::clangd::Config::@4 Diagnostics
Controls warnings and errors when parsing code.