18 #include "clang/Format/Format.h"
19 #include "clang/Frontend/PrecompiledPreamble.h"
20 #include "clang/Lex/PreprocessorOptions.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/VirtualFileSystem.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include <clang/Frontend/FrontendActions.h>
34 using testing::Contains;
36 using testing::Matcher;
37 using testing::MatchesRegex;
43 MATCHER_P2(Distance, File, D,
"") {
44 return arg.first() == File && arg.second == D;
50 collectPatchedIncludes(llvm::StringRef ModifiedContents,
51 llvm::StringRef BaselineContents,
52 llvm::StringRef MainFileName =
"main.cpp") {
55 TU.Filename = MainFileName.str();
57 TU.ExtraArgs = {
"-fno-ms-compatibility"};
58 auto BaselinePreamble = TU.preamble();
60 TU.Code = ModifiedContents.str();
61 auto PI = TU.inputs(
FS);
64 IgnoreDiagnostics
Diags;
72 auto Bounds = Lexer::ComputePreamble(ModifiedContents, *
CI->getLangOpts());
75 llvm::MemoryBuffer::getMemBufferCopy(
76 ModifiedContents.slice(0,
Bounds.Size).str()),
77 PI.TFS->view(PI.CompileCommand.Directory),
Diags);
78 PreprocessOnlyAction
Action;
79 if (!
Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
80 ADD_FAILURE() <<
"failed begin source file";
83 IncludeStructure Includes;
84 Clang->getPreprocessor().addPPCallbacks(
87 ADD_FAILURE() <<
"failed to execute action: " << std::move(Err);
96 TEST(PreamblePatchTest, IncludeParsing) {
98 llvm::StringRef Cases[] = {
100 R
"cpp(^#include "a.h")cpp",
104 garbage, finishes preamble
120 ^#include <b.h>)cpp",
125 #/**/include <b.h>)cpp",
128 for (
const auto &Case : Cases) {
129 Annotations Test(Case);
130 const auto Code = Test.code();
135 auto Points = Test.points();
136 ASSERT_EQ(Includes.size(), Points.size());
137 for (
size_t I = 0,
E = Includes.size(); I !=
E; ++I)
138 EXPECT_EQ(Includes[I].HashLine, Points[I].line);
142 TEST(PreamblePatchTest, ContainsNewIncludes) {
143 constexpr llvm::StringLiteral BaselineContents = R
"cpp(
145 #include <b.h> // This will be removed
148 constexpr llvm::StringLiteral ModifiedContents = R"cpp(
150 #include <c.h> // This has changed a line.
151 #include <c.h> // This is a duplicate.
152 #include <d.h> // This is newly introduced.
154 auto Includes = collectPatchedIncludes(ModifiedContents, BaselineContents)
160 TEST(PreamblePatchTest, MainFileIsEscaped) {
161 auto Includes = collectPatchedIncludes(
"#include <a.h>",
"",
"file\"name.cpp")
167 TEST(PreamblePatchTest, PatchesPreambleIncludes) {
169 IgnoreDiagnostics
Diags;
174 TU.AdditionalFiles["a.h"] =
"#include \"b.h\"";
175 TU.AdditionalFiles[
"b.h"] =
"";
176 TU.AdditionalFiles[
"c.h"] =
"";
177 auto PI = TU.inputs(
FS);
190 EXPECT_THAT(
PP.preambleIncludes(),
195 llvm::Optional<ParsedAST> createPatchedAST(llvm::StringRef Baseline,
196 llvm::StringRef Modified) {
198 if (!BaselinePreamble) {
199 ADD_FAILURE() <<
"Failed to build baseline preamble";
203 IgnoreDiagnostics
Diags;
208 ADD_FAILURE() <<
"Failed to build compiler invocation";
212 {}, BaselinePreamble);
215 std::string getPreamblePatch(llvm::StringRef Baseline,
216 llvm::StringRef Modified) {
218 if (!BaselinePreamble) {
219 ADD_FAILURE() <<
"Failed to build baseline preamble";
230 TEST(PreamblePatchTest, Define) {
234 const char *
const ExpectedPatch;
240 R"cpp(#line 0 ".*main.cpp"
251 R"cpp(#line 0 ".*main.cpp"
262 R"cpp(#line 0 ".*main.cpp"
269 for (
const auto &Case : Cases) {
270 SCOPED_TRACE(Case.Contents);
271 Annotations Modified(Case.Contents);
272 EXPECT_THAT(getPreamblePatch(
"", Modified.code()),
273 MatchesRegex(Case.ExpectedPatch));
275 auto AST = createPatchedAST(
"", Modified.code());
282 TEST(PreamblePatchTest, OrderingPreserved) {
283 llvm::StringLiteral Baseline =
"#define BAR(X) X";
284 Annotations Modified(R
"cpp(
285 #define BAR(X, Y) X Y
290 llvm::StringLiteral ExpectedPatch(R"cpp(#line 0 ".*main.cpp"
292 #define BAR\(X, Y\) X Y
296 EXPECT_THAT(getPreamblePatch(Baseline, Modified.code()),
297 MatchesRegex(ExpectedPatch.str()));
299 auto AST = createPatchedAST(Baseline, Modified.code());
305 TEST(PreamblePatchTest, LocateMacroAtWorks) {
307 const char *
const Baseline;
308 const char *
const Modified;
322 #undef $use^FOO)cpp",
358 for (
const auto &Case : Cases) {
359 SCOPED_TRACE(Case.Modified);
360 llvm::Annotations Modified(Case.Modified);
361 auto AST = createPatchedAST(Case.Baseline, Modified.code());
365 auto *MacroTok = AST->
getTokens().spelledTokenAt(
366 SM.getComposedLoc(SM.getMainFileID(), Modified.point(
"use")));
367 ASSERT_TRUE(MacroTok);
370 ASSERT_TRUE(FoundMacro);
371 EXPECT_THAT(FoundMacro->Name,
"FOO");
373 auto MacroLoc = FoundMacro->NameLoc;
374 EXPECT_EQ(SM.getFileID(MacroLoc), SM.getMainFileID());
375 EXPECT_EQ(SM.getFileOffset(MacroLoc), Modified.point(
"def"));
379 TEST(PreamblePatchTest, LocateMacroAtDeletion) {
382 llvm::StringLiteral Baseline =
"#define FOO";
383 llvm::Annotations Modified(
"^FOO");
385 auto AST = createPatchedAST(Baseline, Modified.code());
389 auto *MacroTok = AST->
getTokens().spelledTokenAt(
390 SM.getComposedLoc(SM.getMainFileID(), Modified.point()));
391 ASSERT_TRUE(MacroTok);
394 ASSERT_TRUE(FoundMacro);
395 EXPECT_THAT(FoundMacro->Name,
"FOO");
398 format::getLLVMStyle(),
nullptr);
400 EXPECT_THAT(HI->Definition, testing::IsEmpty());
405 llvm::StringLiteral Baseline =
"#define FOO";
406 Annotations Modified(R
"cpp(#define BAR
409 auto AST = createPatchedAST(Baseline, Modified.code());
412 auto HI =
getHover(*AST, Modified.point(), format::getLLVMStyle(),
nullptr);
414 EXPECT_THAT(HI->Definition,
"#define BAR");
418 TEST(PreamblePatchTest, RefsToMacros) {
420 const char *
const Baseline;
421 const char *
const Modified;
447 for (
const auto &Case : Cases) {
448 Annotations Modified(Case.Modified);
449 auto AST = createPatchedAST(
"", Modified.code());
453 std::vector<Matcher<Location>> ExpectedLocations;
454 for (
const auto &R : Modified.ranges())
457 for (
const auto &P : Modified.points()) {
458 auto *MacroTok = AST->
getTokens().spelledTokenAt(SM.getComposedLoc(
461 ASSERT_TRUE(MacroTok);
463 testing::ElementsAreArray(ExpectedLocations));
468 TEST(TranslatePreamblePatchLocation, Simple) {
473 TU.Code = R
"cpp(// line 1
477 TU.Filename = "main.cpp";
478 TU.HeaderFilename =
"__preamble_patch__.h";
479 TU.ImplicitHeaderGuard =
false;
481 auto AST = TU.
build();
484 EXPECT_NE(SM.getFileID(ND.getLocation()), SM.getMainFileID());
487 auto DecompLoc = SM.getDecomposedLoc(TranslatedLoc);
488 EXPECT_EQ(DecompLoc.first, SM.getMainFileID());
489 EXPECT_EQ(SM.getLineNumber(DecompLoc.first, DecompLoc.second), 3U);
492 TEST(PreamblePatch, ModifiedBounds) {
494 const char *
const Baseline;
495 const char *
const Modified;
505 {
"#define FOO",
"#define BAR"},
514 for (
const auto &Case : Cases) {
516 auto BaselinePreamble = TU.preamble();
517 ASSERT_TRUE(BaselinePreamble);
519 Annotations Modified(Case.Modified);
520 TU.Code = Modified.code().str();
525 IgnoreDiagnostics
Diags;
529 const auto ExpectedBounds =
530 Lexer::ComputePreamble(Case.Modified, *
CI->getLangOpts());
531 EXPECT_EQ(
PP.modifiedBounds().Size, ExpectedBounds.Size);
532 EXPECT_EQ(
PP.modifiedBounds().PreambleEndsAtStartOfLine,
533 ExpectedBounds.PreambleEndsAtStartOfLine);