[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clangd / unittests / ReplayPeambleTests.cpp
blob32942e6bbfdc8f94862245af4c04380e55fd5558
1 //===-- ReplayPreambleTests.cpp -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // These tests cover clangd's logic to replay PP events from preamble to
10 // clang-tidy checks.
12 //===----------------------------------------------------------------------===//
14 #include "../../clang-tidy/ClangTidyCheck.h"
15 #include "../../clang-tidy/ClangTidyModule.h"
16 #include "../../clang-tidy/ClangTidyModuleRegistry.h"
17 #include "AST.h"
18 #include "Config.h"
19 #include "Diagnostics.h"
20 #include "ParsedAST.h"
21 #include "SourceCode.h"
22 #include "TestTU.h"
23 #include "TidyProvider.h"
24 #include "support/Context.h"
25 #include "clang/AST/DeclTemplate.h"
26 #include "clang/Basic/FileEntry.h"
27 #include "clang/Basic/LLVM.h"
28 #include "clang/Basic/SourceLocation.h"
29 #include "clang/Basic/SourceManager.h"
30 #include "clang/Basic/TokenKinds.h"
31 #include "clang/Lex/PPCallbacks.h"
32 #include "clang/Lex/Token.h"
33 #include "clang/Tooling/Syntax/Tokens.h"
34 #include "llvm/ADT/StringRef.h"
35 #include "llvm/Support/Registry.h"
36 #include "llvm/Testing/Annotations/Annotations.h"
37 #include "gmock/gmock-matchers.h"
38 #include "gmock/gmock.h"
39 #include "gtest/gtest.h"
40 #include <cstddef>
41 #include <memory>
42 #include <vector>
44 namespace clang {
46 class Module;
48 namespace clangd {
49 namespace {
50 struct Inclusion {
51 Inclusion(const SourceManager &SM, SourceLocation HashLoc,
52 const Token &IncludeTok, llvm::StringRef FileName, bool IsAngled,
53 CharSourceRange FilenameRange)
54 : HashOffset(SM.getDecomposedLoc(HashLoc).second), IncTok(IncludeTok),
55 IncDirective(IncludeTok.getIdentifierInfo()->getName()),
56 FileNameOffset(SM.getDecomposedLoc(FilenameRange.getBegin()).second),
57 FileName(FileName), IsAngled(IsAngled) {
58 EXPECT_EQ(
59 toSourceCode(SM, FilenameRange.getAsRange()).drop_back().drop_front(),
60 FileName);
62 size_t HashOffset;
63 syntax::Token IncTok;
64 llvm::StringRef IncDirective;
65 size_t FileNameOffset;
66 llvm::StringRef FileName;
67 bool IsAngled;
69 static std::vector<Inclusion> Includes;
70 static std::vector<syntax::Token> SkippedFiles;
71 struct ReplayPreamblePPCallback : public PPCallbacks {
72 const SourceManager &SM;
73 explicit ReplayPreamblePPCallback(const SourceManager &SM) : SM(SM) {}
75 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
76 StringRef FileName, bool IsAngled,
77 CharSourceRange FilenameRange, OptionalFileEntryRef,
78 StringRef, StringRef, const clang::Module *, bool,
79 SrcMgr::CharacteristicKind) override {
80 Includes.emplace_back(SM, HashLoc, IncludeTok, FileName, IsAngled,
81 FilenameRange);
84 void FileSkipped(const FileEntryRef &, const Token &FilenameTok,
85 SrcMgr::CharacteristicKind) override {
86 SkippedFiles.emplace_back(FilenameTok);
89 struct ReplayPreambleCheck : public tidy::ClangTidyCheck {
90 ReplayPreambleCheck(StringRef Name, tidy::ClangTidyContext *Context)
91 : ClangTidyCheck(Name, Context) {}
92 void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
93 Preprocessor *ModuleExpanderPP) override {
94 PP->addPPCallbacks(::std::make_unique<ReplayPreamblePPCallback>(SM));
97 llvm::StringLiteral CheckName = "replay-preamble-check";
98 struct ReplayPreambleModule : public tidy::ClangTidyModule {
99 void
100 addCheckFactories(tidy::ClangTidyCheckFactories &CheckFactories) override {
101 CheckFactories.registerCheck<ReplayPreambleCheck>(CheckName);
104 static tidy::ClangTidyModuleRegistry::Add<ReplayPreambleModule>
105 X("replay-preamble-module", "");
107 MATCHER_P(rangeIs, R, "") {
108 return arg.beginOffset() == R.Begin && arg.endOffset() == R.End;
111 TEST(ReplayPreambleTest, IncludesAndSkippedFiles) {
112 TestTU TU;
113 // This check records inclusion directives replayed by clangd.
114 TU.ClangTidyProvider = addTidyChecks(CheckName);
115 llvm::Annotations Test(R"cpp(
116 $hash^#$include[[import]] $filebegin^"$filerange[[bar.h]]"
117 $hash^#$include[[include_next]] $filebegin^"$filerange[[baz.h]]"
118 $hash^#$include[[include]] $filebegin^<$filerange[[a.h]]>)cpp");
119 llvm::StringRef Code = Test.code();
120 TU.Code = Code.str();
121 TU.AdditionalFiles["bar.h"] = "";
122 TU.AdditionalFiles["baz.h"] = "";
123 TU.AdditionalFiles["a.h"] = "";
124 // Since we are also testing #import directives, and they don't make much
125 // sense in c++ (also they actually break on windows), just set language to
126 // obj-c.
127 TU.ExtraArgs = {"-isystem.", "-xobjective-c"};
129 // Allow the check to run even though not marked as fast.
130 Config Cfg;
131 Cfg.Diagnostics.ClangTidy.FastCheckFilter = Config::FastCheckPolicy::Loose;
132 WithContextValue WithCfg(Config::Key, std::move(Cfg));
134 const auto &AST = TU.build();
135 const auto &SM = AST.getSourceManager();
137 auto HashLocs = Test.points("hash");
138 ASSERT_EQ(HashLocs.size(), Includes.size());
139 auto IncludeRanges = Test.ranges("include");
140 ASSERT_EQ(IncludeRanges.size(), Includes.size());
141 auto FileBeginLocs = Test.points("filebegin");
142 ASSERT_EQ(FileBeginLocs.size(), Includes.size());
143 auto FileRanges = Test.ranges("filerange");
144 ASSERT_EQ(FileRanges.size(), Includes.size());
146 ASSERT_EQ(SkippedFiles.size(), Includes.size());
147 for (size_t I = 0; I < Includes.size(); ++I) {
148 const auto &Inc = Includes[I];
150 EXPECT_EQ(Inc.HashOffset, HashLocs[I]);
152 auto IncRange = IncludeRanges[I];
153 EXPECT_THAT(Inc.IncTok.range(SM), rangeIs(IncRange));
154 EXPECT_EQ(Inc.IncTok.kind(), tok::identifier);
155 EXPECT_EQ(Inc.IncDirective,
156 Code.substr(IncRange.Begin, IncRange.End - IncRange.Begin));
158 EXPECT_EQ(Inc.FileNameOffset, FileBeginLocs[I]);
159 EXPECT_EQ(Inc.IsAngled, Code[FileBeginLocs[I]] == '<');
161 auto FileRange = FileRanges[I];
162 EXPECT_EQ(Inc.FileName,
163 Code.substr(FileRange.Begin, FileRange.End - FileRange.Begin));
165 EXPECT_EQ(SM.getDecomposedLoc(SkippedFiles[I].location()).second,
166 Inc.FileNameOffset);
167 // This also contains quotes/angles so increment the range by one from both
168 // sides.
169 EXPECT_EQ(
170 SkippedFiles[I].text(SM),
171 Code.substr(FileRange.Begin - 1, FileRange.End - FileRange.Begin + 2));
172 EXPECT_EQ(SkippedFiles[I].kind(), tok::header_name);
175 } // namespace
176 } // namespace clangd
177 } // namespace clang