14#include "../../clang-tidy/ClangTidyCheck.h"
15#include "../../clang-tidy/ClangTidyModule.h"
16#include "../../clang-tidy/ClangTidyModuleRegistry.h"
30#include "clang/AST/DeclTemplate.h"
31#include "clang/Basic/FileEntry.h"
32#include "clang/Basic/SourceLocation.h"
33#include "clang/Basic/SourceManager.h"
34#include "clang/Basic/TokenKinds.h"
35#include "clang/Lex/PPCallbacks.h"
36#include "clang/Tooling/Syntax/Tokens.h"
37#include "llvm/ADT/StringRef.h"
38#include "llvm/Testing/Annotations/Annotations.h"
39#include "llvm/Testing/Support/Error.h"
40#include "gmock/gmock-matchers.h"
41#include "gmock/gmock.h"
42#include "gtest/gtest.h"
51using ::testing::AllOf;
52using ::testing::Contains;
53using ::testing::ElementsAre;
54using ::testing::ElementsAreArray;
55using ::testing::IsEmpty;
58 if (NamedDecl *ND = dyn_cast<NamedDecl>(arg))
59 if (ND->getName() ==
Name)
61 if (
auto *Stream = result_listener->stream()) {
62 llvm::raw_os_ostream
OS(*Stream);
69 if (NamedDecl *ND = dyn_cast<NamedDecl>(arg))
70 if (ND->getDeclKindName() == llvm::StringRef(
Kind))
72 if (
auto *Stream = result_listener->stream()) {
73 llvm::raw_os_ostream
OS(*Stream);
82 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(arg)) {
83 if (
const auto *
Args = FD->getTemplateSpecializationArgs()) {
84 std::string SpecializationArgs;
87 PrintingPolicy Policy(LO);
88 Policy.adjustForCPlusPlus();
89 for (
const auto &Arg :
Args->asArray()) {
90 if (SpecializationArgs.size() > 0)
91 SpecializationArgs +=
",";
92 SpecializationArgs += Arg.getAsType().getAsString(Policy);
94 if (
Args->size() == 0)
95 return ArgName == SpecializationArgs;
96 return ArgName ==
"<" + SpecializationArgs +
">";
99 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(arg))
104MATCHER_P(pragmaTrivia, P,
"") {
return arg.Trivia == P; }
107 Inclusion Actual = testing::get<0>(arg);
108 Inclusion
Expected = testing::get<1>(arg);
109 return std::tie(Actual.HashLine, Actual.Written) ==
113TEST(ParsedASTTest, TopLevelDecls) {
121 template <typename> bool X = true;
123 auto AST = TU.build();
124 EXPECT_THAT(
AST.getLocalTopLevelDecls(),
125 testing::UnorderedElementsAreArray(
126 {AllOf(declNamed(
"main"), declKind(
"Function")),
127 AllOf(declNamed(
"X"), declKind(
"VarTemplate"))}));
130TEST(ParsedASTTest, DoesNotGetIncludedTopDecls) {
132 TU.HeaderCode = R
"cpp(
133 #define LL void foo(){}
146 auto AST = TU.build();
147 EXPECT_THAT(
AST.getLocalTopLevelDecls(), ElementsAre(declNamed(
"main")));
150TEST(ParsedASTTest, DoesNotGetImplicitTemplateTopDecls) {
160 auto AST = TU.build();
161 EXPECT_THAT(
AST.getLocalTopLevelDecls(),
162 ElementsAre(declNamed(
"f"), declNamed(
"s")));
166 GetsExplicitInstantiationAndSpecializationTemplateTopDecls) {
169 template <typename T>
173 template void f(double);
185 double d = foo<double>;
193 auto AST = TU.build();
195 AST.getLocalTopLevelDecls(),
196 ElementsAreArray({AllOf(declNamed(
"f"), withTemplateArgs(
"")),
197 AllOf(declNamed(
"f"), withTemplateArgs(
"<bool>")),
198 AllOf(declNamed(
"f"), withTemplateArgs(
"<double>")),
199 AllOf(declNamed(
"V"), withTemplateArgs(
"")),
200 AllOf(declNamed(
"V"), withTemplateArgs(
"<T *>")),
201 AllOf(declNamed(
"V"), withTemplateArgs(
"<bool>")),
202 AllOf(declNamed(
"foo"), withTemplateArgs(
"")),
203 AllOf(declNamed(
"i"), withTemplateArgs(
"")),
204 AllOf(declNamed(
"d"), withTemplateArgs(
"")),
205 AllOf(declNamed(
"foo"), withTemplateArgs(
"<T *>")),
206 AllOf(declNamed(
"foo"), withTemplateArgs(
"<bool>"))}));
209TEST(ParsedASTTest, IgnoresDelayedTemplateParsing) {
211 template <typename T> void xxx() {
215 TU.ExtraArgs.push_back("-fdelayed-template-parsing");
216 auto AST = TU.build();
220TEST(ParsedASTTest, TokensAfterPreamble) {
222 TU.AdditionalFiles[
"foo.h"] = R
"(
229 // error-ok: invalid syntax, just examining token stream
233 auto AST = TU.build();
234 const syntax::TokenBuffer &T =
AST.getTokens();
235 const auto &SM =
AST.getSourceManager();
237 ASSERT_GT(T.expandedTokens().size(), 2u);
239 EXPECT_EQ(T.expandedTokens().front().text(SM),
"first_token");
241 EXPECT_EQ(T.expandedTokens().back().kind(), tok::eof);
243 EXPECT_EQ(T.expandedTokens().drop_back().back().text(SM),
"last_token");
246 auto Spelled = T.spelledTokens(SM.getMainFileID());
248 EXPECT_EQ(
Spelled.front().kind(), tok::hash);
249 EXPECT_EQ(
Spelled.back().text(SM),
"last_token");
252TEST(ParsedASTTest, NoCrashOnTokensWithTidyCheck) {
256 TU.ClangTidyProvider =
addTidyChecks(
"modernize-use-trailing-return-type");
257 TU.Code =
"inline int foo() {}";
259 auto AST = TU.build();
260 const syntax::TokenBuffer &T =
AST.getTokens();
261 const auto &SM =
AST.getSourceManager();
263 ASSERT_GT(T.expandedTokens().size(), 7u);
265 EXPECT_EQ(T.expandedTokens().front().text(SM),
"inline");
267 EXPECT_EQ(T.expandedTokens().back().kind(), tok::eof);
269 EXPECT_EQ(T.expandedTokens().drop_back().back().text(SM),
"}");
272TEST(ParsedASTTest, CanBuildInvocationWithUnknownArgs) {
274 FS.Files = {{
testPath(
"foo.cpp"),
"void test() {}"}};
278 Inputs.
CompileCommand.CommandLine = {
"clang",
"-fsome-unknown-flag",
285 "clang",
"-Xclang",
"-fsome-unknown-flag",
testPath(
"foo.cpp")};
289TEST(ParsedASTTest, CollectsMainFileMacroExpansions) {
290 llvm::Annotations TestCase(R
"cpp(
291 #define ^MACRO_ARGS(X, Y) X Y
294 // Macro arguments included.
295 ^MACRO_ARGS(^MACRO_ARGS(^MACRO_EXP(int), E), ^ID(= 2));
297 // Macro names inside other macros not included.
298 #define ^MACRO_ARGS2(X, Y) X Y
303 // Macros from token concatenations not included.
304 #define ^CONCAT(X) X##A()
305 #define ^PREPEND(X) MACRO##X()
306 #define ^MACROA() 123
307 int G = ^CONCAT(MACRO);
310 // Macros included not from preamble not included.
313 int printf(const char*, ...);
315 #define ^assert(COND) if (!(COND)) { printf("%s", #COND); exit(0); }
318 // Includes macro expansions in arguments that are expressions
325 #define ^MULTIPLE_DEFINITION 1
326 #undef ^MULTIPLE_DEFINITION
328 #define ^MULTIPLE_DEFINITION 2
329 #undef ^MULTIPLE_DEFINITION
332 TU.HeaderCode = R
"cpp(
334 #define MACRO_EXP(X) ID(X)
337 TU.AdditionalFiles["foo.inc"] = R
"cpp(
342 ParsedAST AST = TU.build();
343 std::vector<size_t> MacroExpansionPositions;
344 for (
const auto &SIDToRefs :
AST.getMacros().MacroRefs) {
345 for (
const auto &R : SIDToRefs.second)
346 MacroExpansionPositions.push_back(R.StartOffset);
348 for (
const auto &R :
AST.getMacros().UnknownMacros)
349 MacroExpansionPositions.push_back(R.StartOffset);
351 MacroExpansionPositions,
352 testing::UnorderedElementsAreArray(TestCase.points()));
355MATCHER_P(withFileName, Inc,
"") {
return arg.FileName == Inc; }
357TEST(ParsedASTTest, PatchesAdditionalIncludes) {
358 llvm::StringLiteral ModifiedContents = R
"cpp(
369 TU.Filename =
"foo.cpp";
370 TU.AdditionalFiles[
"foo.h"] =
"void foo();";
371 TU.AdditionalFiles[
"sub/baz.h"] =
"void baz();";
372 TU.AdditionalFiles[
"sub/aux.h"] =
"void aux();";
373 TU.ExtraArgs = {
"-I" +
testPath(
"sub")};
374 TU.Code = ModifiedContents.str();
375 auto ExpectedAST = TU.build();
381 auto Inputs = TU.inputs(FS);
385 ASSERT_TRUE(EmptyPreamble);
386 EXPECT_THAT(EmptyPreamble->Includes.MainFileIncludes, IsEmpty());
389 TU.Code = ModifiedContents.str();
390 Inputs = TU.inputs(FS);
393 ASSERT_TRUE(PatchedAST);
396 EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
398 eqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes));
400 auto &SM = PatchedAST->getSourceManager();
401 auto &FM = SM.getFileManager();
403 IncludeStructure Includes = PatchedAST->getIncludeStructure();
404 auto MainFE = FM.getFile(
testPath(
"foo.cpp"));
406 auto MainID = Includes.
getID(*MainFE);
407 auto AuxFE = FM.getFile(
testPath(
"sub/aux.h"));
409 auto AuxID = Includes.
getID(*AuxFE);
413TEST(ParsedASTTest, PatchesDeletedIncludes) {
415 TU.Filename =
"foo.cpp";
417 auto ExpectedAST = TU.build();
420 TU.Code = R
"cpp(#include <foo.h>)cpp";
423 auto Inputs = TU.inputs(FS);
425 auto BaselinePreamble =
427 ASSERT_TRUE(BaselinePreamble);
428 EXPECT_THAT(BaselinePreamble->Includes.MainFileIncludes,
434 Inputs = TU.inputs(FS);
436 {}, BaselinePreamble);
437 ASSERT_TRUE(PatchedAST);
440 EXPECT_THAT(PatchedAST->getIncludeStructure().MainFileIncludes,
442 eqInc(), ExpectedAST.getIncludeStructure().MainFileIncludes));
444 auto &SM = ExpectedAST.getSourceManager();
445 auto &FM = SM.getFileManager();
447 IncludeStructure Includes = ExpectedAST.getIncludeStructure();
448 auto MainFE = FM.getFileRef(
testPath(
"foo.cpp"));
449 ASSERT_THAT_EXPECTED(MainFE, llvm::Succeeded());
451 auto &PatchedFM = PatchedAST->getSourceManager().getFileManager();
452 IncludeStructure PatchedIncludes = PatchedAST->getIncludeStructure();
453 auto PatchedMainFE = PatchedFM.getFileRef(
testPath(
"foo.cpp"));
454 ASSERT_THAT_EXPECTED(PatchedMainFE, llvm::Succeeded());
455 auto PatchedMainID = PatchedIncludes.getOrCreateID(*PatchedMainFE);
457 PatchedIncludes.includeDepth(PatchedMainID)[PatchedMainID]);
461std::string guard(llvm::StringRef
Code) {
462 static int GuardID = 0;
463 std::string GuardName = (
"GUARD_" + llvm::Twine(++GuardID)).str();
464 return llvm::formatv(
"#ifndef {0}\n#define {0}\n{1}\n#endif\n", GuardName,
468std::string once(llvm::StringRef
Code) {
469 return llvm::formatv(
"#pragma once\n{0}\n",
Code);
472bool mainIsGuarded(
const ParsedAST &
AST) {
473 const auto &SM =
AST.getSourceManager();
474 OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
475 return AST.getPreprocessor()
476 .getHeaderSearchInfo()
477 .isFileMultipleIncludeGuarded(*MainFE);
481 return llvm::StringRef(arg.Message).contains(Desc);
485TEST(ParsedASTTest, HeaderGuards) {
487 TU.ImplicitHeaderGuard =
false;
490 EXPECT_FALSE(mainIsGuarded(TU.build()));
492 TU.Code = guard(
";");
493 EXPECT_TRUE(mainIsGuarded(TU.build()));
496 EXPECT_TRUE(mainIsGuarded(TU.build()));
502 EXPECT_FALSE(mainIsGuarded(TU.build()));
511 EXPECT_FALSE(mainIsGuarded(TU.build()));
524TEST(ParsedASTTest, HeaderGuardsSelfInclude) {
533 TU.ImplicitHeaderGuard =
false;
534 TU.Filename =
"self.h";
537 #include "self.h" // error-ok
540 auto AST = TU.build();
541 EXPECT_THAT(
AST.getDiagnostics(),
542 ElementsAre(diag(
"recursively when building a preamble")));
543 EXPECT_FALSE(mainIsGuarded(
AST));
547 #include "self.h" // error-ok
550 EXPECT_THAT(AST.getDiagnostics(), ElementsAre(diag("nested too deeply")));
551 EXPECT_FALSE(mainIsGuarded(
AST));
559 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
560 EXPECT_TRUE(mainIsGuarded(AST));
568 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
569 EXPECT_TRUE(mainIsGuarded(AST));
577 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
578 EXPECT_TRUE(mainIsGuarded(AST));
583 #include "self.h" // error-ok: FIXME, this would be nice to support
588 EXPECT_THAT(AST.getDiagnostics(),
589 ElementsAre(diag("recursively when building a preamble")));
590 EXPECT_TRUE(mainIsGuarded(
AST));
600 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
601 EXPECT_TRUE(mainIsGuarded(AST));
605 #include "self.h" // error-ok
612 EXPECT_THAT(AST.getDiagnostics(),
613 ElementsAre(diag("recursively when building a preamble")));
614 EXPECT_FALSE(mainIsGuarded(
AST));
617 #include "self.h" // error-ok
624 EXPECT_THAT(AST.getDiagnostics(),
625 ElementsAre(diag("recursively when building a preamble")));
626 EXPECT_FALSE(mainIsGuarded(
AST));
636 EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
637 EXPECT_FALSE(mainIsGuarded(AST));
640 #include "self.h" // error-ok
645 EXPECT_THAT(AST.getDiagnostics(),
646 ElementsAre(diag("recursively when building a preamble")));
647 EXPECT_TRUE(mainIsGuarded(
AST));
650 #include "self.h" // error-ok
655 EXPECT_THAT(AST.getDiagnostics(),
656 ElementsAre(diag("recursively when building a preamble")));
657 EXPECT_TRUE(mainIsGuarded(
AST));
664TEST(ParsedASTTest, HeaderGuardsImplIface) {
666 // error-ok: we assert on diagnostics explicitly
667 template <class T> struct Traits {
673 // error-ok: we assert on diagnostics explicitly
675 template <class T> unsigned Traits<T>::size() {
681 TU.ImplicitHeaderGuard = false;
682 TU.ExtraArgs.push_back(
"-xc++-header");
686 TU.Filename =
"iface.h";
689 auto AST = TU.build();
690 EXPECT_THAT(
AST.getDiagnostics(), IsEmpty());
691 EXPECT_TRUE(mainIsGuarded(
AST));
696 EXPECT_THAT(
AST.getDiagnostics(), IsEmpty());
697 EXPECT_TRUE(mainIsGuarded(
AST));
700 TU.Filename =
"impl.h";
702 TU.AdditionalFiles = {{
"iface.h", guard(
Interface)}};
706 EXPECT_THAT(
AST.getDiagnostics(),
707 ElementsAre(diag(
"in included file: main file cannot be included "
708 "recursively when building a preamble")));
709 EXPECT_FALSE(mainIsGuarded(
AST));
711 TU.AdditionalFiles = {{
"iface.h", once(
Interface)}};
713 EXPECT_THAT(
AST.getDiagnostics(),
714 ElementsAre(diag(
"in included file: main file cannot be included "
715 "recursively when building a preamble")));
716 EXPECT_FALSE(mainIsGuarded(
AST));
719TEST(ParsedASTTest, DiscoversPragmaMarks) {
721 TU.AdditionalFiles[
"Header.h"] = R
"(
722 #pragma mark - Something API
724 #pragma mark Something else
728 #pragma mark In Preamble
729 #pragma mark - Something Impl
730 int something() { return 1; }
733 auto AST = TU.build();
735 EXPECT_THAT(
AST.getMarks(), ElementsAre(pragmaTrivia(
" In Preamble"),
736 pragmaTrivia(
" - Something Impl"),
737 pragmaTrivia(
" End")));
740TEST(ParsedASTTest, GracefulFailureOnAssemblyFile) {
742 std::string
Code = R
"S(
753 FS.Files[FullFilename] =
Code;
757 Argv.push_back(FullFilename);
764 assert(
CI &&
"Failed to build compilation invocation.");
767 EXPECT_FALSE(
AST.has_value())
768 <<
"Should not try to build AST for assembly source file";
llvm::SmallString< 256U > Name
std::function< std::unique_ptr< Command >()> Implementation
std::string Filename
Filename as a string.
std::vector< const char * > Expected
std::unique_ptr< CompilerInvocation > CI
llvm::raw_string_ostream OS
llvm::DenseMap< HeaderID, unsigned > includeDepth(HeaderID Root=MainFileID) const
HeaderID getOrCreateID(FileEntryRef Entry)
std::optional< HeaderID > getID(const FileEntry *Entry) const
llvm::DenseMap< HeaderID, SmallVector< HeaderID > > IncludeChildren
static std::optional< ParsedAST > build(llvm::StringRef Filename, const ParseInputs &Inputs, std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble)
Attempts to run Clang and store the parsed AST.
std::string printTemplateSpecializationArgs(const NamedDecl &ND)
Prints template arguments of a decl as written in the source code, including enclosing '<' and '>',...
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation CI, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback, PreambleBuildStats *Stats)
Build a preamble for the new inputs unless an old one can be reused.
TidyProvider addTidyChecks(llvm::StringRef Checks, llvm::StringRef WarningsAsErrors)
Provider the enables a specific set of checks and warnings as errors.
TEST(BackgroundQueueTest, Priority)
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static clangd::Key< Config > Key
Context key which can be used to set the current Config.
IncludesPolicy UnusedIncludes
IncludesPolicy MissingIncludes
struct clang::clangd::Config::@4 Diagnostics
Controls warnings and errors when parsing code.
static TestTU withCode(llvm::StringRef Code)