[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clangd / unittests / PreambleTests.cpp
blob03dfa2eaa338636a52d59c5dc8556cf2f9e6581a
1 //===--- PreambleTests.cpp --------------------------------------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
9 #include "Annotations.h"
10 #include "Compiler.h"
11 #include "Config.h"
12 #include "Diagnostics.h"
13 #include "Headers.h"
14 #include "Hover.h"
15 #include "ParsedAST.h"
16 #include "Preamble.h"
17 #include "Protocol.h"
18 #include "SourceCode.h"
19 #include "TestFS.h"
20 #include "TestTU.h"
21 #include "XRefs.h"
22 #include "support/Context.h"
23 #include "clang/Basic/SourceManager.h"
24 #include "clang/Format/Format.h"
25 #include "clang/Frontend/FrontendActions.h"
26 #include "clang/Frontend/PrecompiledPreamble.h"
27 #include "llvm/ADT/StringMap.h"
28 #include "llvm/ADT/StringRef.h"
29 #include "llvm/Support/Error.h"
30 #include "llvm/Support/MemoryBuffer.h"
31 #include "llvm/Support/ScopedPrinter.h"
32 #include "llvm/Support/VirtualFileSystem.h"
33 #include "llvm/Testing/Annotations/Annotations.h"
34 #include "gmock/gmock.h"
35 #include "gtest/gtest-matchers.h"
36 #include "gtest/gtest.h"
37 #include <memory>
38 #include <optional>
39 #include <string>
40 #include <utility>
41 #include <vector>
43 using testing::AllOf;
44 using testing::Contains;
45 using testing::ElementsAre;
46 using testing::ElementsAreArray;
47 using testing::Eq;
48 using testing::Field;
49 using testing::HasSubstr;
50 using testing::IsEmpty;
51 using testing::Matcher;
52 using testing::MatchesRegex;
53 using testing::Not;
54 using testing::UnorderedElementsAre;
55 using testing::UnorderedElementsAreArray;
57 namespace clang {
58 namespace clangd {
59 namespace {
61 MATCHER_P2(Distance, File, D, "") {
62 return arg.first() == File && arg.second == D;
65 // Builds a preamble for BaselineContents, patches it for ModifiedContents and
66 // returns the includes in the patch.
67 IncludeStructure
68 collectPatchedIncludes(llvm::StringRef ModifiedContents,
69 llvm::StringRef BaselineContents,
70 llvm::StringRef MainFileName = "main.cpp") {
71 MockFS FS;
72 auto TU = TestTU::withCode(BaselineContents);
73 TU.Filename = MainFileName.str();
74 // ms-compatibility changes meaning of #import, make sure it is turned off.
75 TU.ExtraArgs = {"-fno-ms-compatibility"};
76 auto BaselinePreamble = TU.preamble();
77 // Create the patch.
78 TU.Code = ModifiedContents.str();
79 auto PI = TU.inputs(FS);
80 auto PP = PreamblePatch::createFullPatch(testPath(TU.Filename), PI,
81 *BaselinePreamble);
82 // Collect patch contents.
83 IgnoreDiagnostics Diags;
84 auto CI = buildCompilerInvocation(PI, Diags);
85 PP.apply(*CI);
86 // Run preprocessor over the modified contents with patched Invocation. We
87 // provide a preamble and trim contents to ensure only the implicit header
88 // introduced by the patch is parsed and nothing else.
89 // We don't run PP directly over the patch cotents to test production
90 // behaviour.
91 auto Bounds = Lexer::ComputePreamble(ModifiedContents, *CI->getLangOpts());
92 auto Clang =
93 prepareCompilerInstance(std::move(CI), &BaselinePreamble->Preamble,
94 llvm::MemoryBuffer::getMemBufferCopy(
95 ModifiedContents.slice(0, Bounds.Size).str()),
96 PI.TFS->view(PI.CompileCommand.Directory), Diags);
97 PreprocessOnlyAction Action;
98 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
99 ADD_FAILURE() << "failed begin source file";
100 return {};
102 IncludeStructure Includes;
103 Includes.collect(*Clang);
104 if (llvm::Error Err = Action.Execute()) {
105 ADD_FAILURE() << "failed to execute action: " << std::move(Err);
106 return {};
108 Action.EndSourceFile();
109 return Includes;
112 // Check preamble lexing logic by building an empty preamble and patching it
113 // with all the contents.
114 TEST(PreamblePatchTest, IncludeParsing) {
115 // We expect any line with a point to show up in the patch.
116 llvm::StringRef Cases[] = {
117 // Only preamble
118 R"cpp(^#include "a.h")cpp",
119 // Both preamble and mainfile
120 R"cpp(
121 ^#include "a.h"
122 garbage, finishes preamble
123 #include "a.h")cpp",
124 // Mixed directives
125 R"cpp(
126 ^#include "a.h"
127 #pragma directive
128 // some comments
129 ^#include_next <a.h>
130 #ifdef skipped
131 ^#import "a.h"
132 #endif)cpp",
133 // Broken directives
134 R"cpp(
135 #include "a
136 ^#include "a.h"
137 #include <b
138 ^#include <b.h>)cpp",
139 // Directive is not part of preamble if it is not the token immediately
140 // followed by the hash (#).
141 R"cpp(
142 ^#include "a.h"
143 #/**/include <b.h>)cpp",
146 for (const auto &Case : Cases) {
147 Annotations Test(Case);
148 const auto Code = Test.code();
149 SCOPED_TRACE(Code);
151 auto Includes =
152 collectPatchedIncludes(Code, /*BaselineContents=*/"").MainFileIncludes;
153 auto Points = Test.points();
154 ASSERT_EQ(Includes.size(), Points.size());
155 for (size_t I = 0, E = Includes.size(); I != E; ++I)
156 EXPECT_EQ(Includes[I].HashLine, Points[I].line);
160 TEST(PreamblePatchTest, ContainsNewIncludes) {
161 constexpr llvm::StringLiteral BaselineContents = R"cpp(
162 #include <a.h>
163 #include <b.h> // This will be removed
164 #include <c.h>
165 )cpp";
166 constexpr llvm::StringLiteral ModifiedContents = R"cpp(
167 #include <a.h>
168 #include <c.h> // This has changed a line.
169 #include <c.h> // This is a duplicate.
170 #include <d.h> // This is newly introduced.
171 )cpp";
172 auto Includes = collectPatchedIncludes(ModifiedContents, BaselineContents)
173 .MainFileIncludes;
174 EXPECT_THAT(Includes, ElementsAre(AllOf(Field(&Inclusion::Written, "<d.h>"),
175 Field(&Inclusion::HashLine, 4))));
178 TEST(PreamblePatchTest, MainFileIsEscaped) {
179 auto Includes = collectPatchedIncludes("#include <a.h>", "", "file\"name.cpp")
180 .MainFileIncludes;
181 EXPECT_THAT(Includes, ElementsAre(AllOf(Field(&Inclusion::Written, "<a.h>"),
182 Field(&Inclusion::HashLine, 0))));
185 TEST(PreamblePatchTest, PatchesPreambleIncludes) {
186 MockFS FS;
187 IgnoreDiagnostics Diags;
188 auto TU = TestTU::withCode(R"cpp(
189 #include "a.h" // IWYU pragma: keep
190 #include "c.h"
191 #ifdef FOO
192 #include "d.h"
193 #endif
194 )cpp");
195 TU.AdditionalFiles["a.h"] = "#include \"b.h\"";
196 TU.AdditionalFiles["b.h"] = "";
197 TU.AdditionalFiles["c.h"] = "";
198 auto PI = TU.inputs(FS);
199 auto BaselinePreamble = buildPreamble(
200 TU.Filename, *buildCompilerInvocation(PI, Diags), PI, true, nullptr);
201 // We drop c.h from modified and add a new header. Since the latter is patched
202 // we should only get a.h in preamble includes. d.h shouldn't be part of the
203 // preamble, as it's coming from a disabled region.
204 TU.Code = R"cpp(
205 #include "a.h"
206 #include "b.h"
207 #ifdef FOO
208 #include "d.h"
209 #endif
210 )cpp";
211 auto PP = PreamblePatch::createFullPatch(testPath(TU.Filename), TU.inputs(FS),
212 *BaselinePreamble);
213 // Only a.h should exists in the preamble, as c.h has been dropped and b.h was
214 // newly introduced.
215 EXPECT_THAT(
216 PP.preambleIncludes(),
217 ElementsAre(AllOf(
218 Field(&Inclusion::Written, "\"a.h\""),
219 Field(&Inclusion::Resolved, testPath("a.h")),
220 Field(&Inclusion::HeaderID, testing::Not(testing::Eq(std::nullopt))),
221 Field(&Inclusion::FileKind, SrcMgr::CharacteristicKind::C_User))));
224 std::optional<ParsedAST>
225 createPatchedAST(llvm::StringRef Baseline, llvm::StringRef Modified,
226 llvm::StringMap<std::string> AdditionalFiles = {}) {
227 auto TU = TestTU::withCode(Baseline);
228 TU.AdditionalFiles = std::move(AdditionalFiles);
229 auto BaselinePreamble = TU.preamble();
230 if (!BaselinePreamble) {
231 ADD_FAILURE() << "Failed to build baseline preamble";
232 return std::nullopt;
235 IgnoreDiagnostics Diags;
236 MockFS FS;
237 TU.Code = Modified.str();
238 auto CI = buildCompilerInvocation(TU.inputs(FS), Diags);
239 if (!CI) {
240 ADD_FAILURE() << "Failed to build compiler invocation";
241 return std::nullopt;
243 return ParsedAST::build(testPath(TU.Filename), TU.inputs(FS), std::move(CI),
244 {}, BaselinePreamble);
247 std::string getPreamblePatch(llvm::StringRef Baseline,
248 llvm::StringRef Modified) {
249 auto BaselinePreamble = TestTU::withCode(Baseline).preamble();
250 if (!BaselinePreamble) {
251 ADD_FAILURE() << "Failed to build baseline preamble";
252 return "";
254 MockFS FS;
255 auto TU = TestTU::withCode(Modified);
256 return PreamblePatch::createFullPatch(testPath("main.cpp"), TU.inputs(FS),
257 *BaselinePreamble)
258 .text()
259 .str();
262 TEST(PreamblePatchTest, IncludesArePreserved) {
263 llvm::StringLiteral Baseline = R"(//error-ok
264 #include <foo>
265 #include <bar>
267 llvm::StringLiteral Modified = R"(//error-ok
268 #include <foo>
269 #include <bar>
270 #define FOO)";
272 auto Includes = createPatchedAST(Baseline, Modified.str())
273 ->getIncludeStructure()
274 .MainFileIncludes;
275 EXPECT_TRUE(!Includes.empty());
276 EXPECT_EQ(Includes, TestTU::withCode(Baseline)
277 .build()
278 .getIncludeStructure()
279 .MainFileIncludes);
282 TEST(PreamblePatchTest, Define) {
283 // BAR should be defined while parsing the AST.
284 struct {
285 const char *const Contents;
286 const char *const ExpectedPatch;
287 } Cases[] = {
289 R"cpp(
290 #define BAR
291 [[BAR]])cpp",
292 R"cpp(#line 0 ".*main.cpp"
293 #undef BAR
294 #line 2
295 #define BAR
296 )cpp",
298 // multiline macro
300 R"cpp(
301 #define BAR \
303 [[BAR]])cpp",
304 R"cpp(#line 0 ".*main.cpp"
305 #undef BAR
306 #line 2
307 #define BAR
308 )cpp",
310 // multiline macro
312 R"cpp(
313 #define \
315 [[BAR]])cpp",
316 R"cpp(#line 0 ".*main.cpp"
317 #undef BAR
318 #line 3
319 #define BAR
320 )cpp",
324 for (const auto &Case : Cases) {
325 SCOPED_TRACE(Case.Contents);
326 llvm::Annotations Modified(Case.Contents);
327 EXPECT_THAT(getPreamblePatch("", Modified.code()),
328 MatchesRegex(Case.ExpectedPatch));
330 auto AST = createPatchedAST("", Modified.code());
331 ASSERT_TRUE(AST);
332 std::vector<llvm::Annotations::Range> MacroRefRanges;
333 for (auto &M : AST->getMacros().MacroRefs) {
334 for (auto &O : M.getSecond())
335 MacroRefRanges.push_back({O.StartOffset, O.EndOffset});
337 EXPECT_THAT(MacroRefRanges, Contains(Modified.range()));
341 TEST(PreamblePatchTest, OrderingPreserved) {
342 llvm::StringLiteral Baseline = "#define BAR(X) X";
343 Annotations Modified(R"cpp(
344 #define BAR(X, Y) X Y
345 #define BAR(X) X
346 [[BAR]](int y);
347 )cpp");
349 llvm::StringLiteral ExpectedPatch(R"cpp(#line 0 ".*main.cpp"
350 #undef BAR
351 #line 2
352 #define BAR\(X, Y\) X Y
353 #undef BAR
354 #line 3
355 #define BAR\(X\) X
356 )cpp");
357 EXPECT_THAT(getPreamblePatch(Baseline, Modified.code()),
358 MatchesRegex(ExpectedPatch.str()));
360 auto AST = createPatchedAST(Baseline, Modified.code());
361 ASSERT_TRUE(AST);
364 TEST(PreamblePatchTest, LocateMacroAtWorks) {
365 struct {
366 const char *const Baseline;
367 const char *const Modified;
368 } Cases[] = {
369 // Addition of new directive
372 R"cpp(
373 #define $def^FOO
374 $use^FOO)cpp",
376 // Available inside preamble section
379 R"cpp(
380 #define $def^FOO
381 #undef $use^FOO)cpp",
383 // Available after undef, as we don't patch those
386 R"cpp(
387 #define $def^FOO
388 #undef FOO
389 $use^FOO)cpp",
391 // Identifier on a different line
394 R"cpp(
395 #define \
396 $def^FOO
397 $use^FOO)cpp",
399 // In presence of comment tokens
402 R"cpp(
404 define /* FOO */\
405 /* FOO */ $def^FOO
406 $use^FOO)cpp",
408 // Moved around
410 "#define FOO",
411 R"cpp(
412 #define BAR
413 #define $def^FOO
414 $use^FOO)cpp",
417 for (const auto &Case : Cases) {
418 SCOPED_TRACE(Case.Modified);
419 llvm::Annotations Modified(Case.Modified);
420 auto AST = createPatchedAST(Case.Baseline, Modified.code());
421 ASSERT_TRUE(AST);
423 const auto &SM = AST->getSourceManager();
424 auto *MacroTok = AST->getTokens().spelledTokenAt(
425 SM.getComposedLoc(SM.getMainFileID(), Modified.point("use")));
426 ASSERT_TRUE(MacroTok);
428 auto FoundMacro = locateMacroAt(*MacroTok, AST->getPreprocessor());
429 ASSERT_TRUE(FoundMacro);
430 EXPECT_THAT(FoundMacro->Name, "FOO");
432 auto MacroLoc = FoundMacro->NameLoc;
433 EXPECT_EQ(SM.getFileID(MacroLoc), SM.getMainFileID());
434 EXPECT_EQ(SM.getFileOffset(MacroLoc), Modified.point("def"));
438 TEST(PreamblePatchTest, LocateMacroAtDeletion) {
440 // We don't patch deleted define directives, make sure we don't crash.
441 llvm::StringLiteral Baseline = "#define FOO";
442 llvm::Annotations Modified("^FOO");
444 auto AST = createPatchedAST(Baseline, Modified.code());
445 ASSERT_TRUE(AST);
447 const auto &SM = AST->getSourceManager();
448 auto *MacroTok = AST->getTokens().spelledTokenAt(
449 SM.getComposedLoc(SM.getMainFileID(), Modified.point()));
450 ASSERT_TRUE(MacroTok);
452 auto FoundMacro = locateMacroAt(*MacroTok, AST->getPreprocessor());
453 ASSERT_TRUE(FoundMacro);
454 EXPECT_THAT(FoundMacro->Name, "FOO");
455 auto HI =
456 getHover(*AST, offsetToPosition(Modified.code(), Modified.point()),
457 format::getLLVMStyle(), nullptr);
458 ASSERT_TRUE(HI);
459 EXPECT_THAT(HI->Definition, testing::IsEmpty());
463 // Offset is valid, but underlying text is different.
464 llvm::StringLiteral Baseline = "#define FOO";
465 Annotations Modified(R"cpp(#define BAR
466 ^FOO")cpp");
468 auto AST = createPatchedAST(Baseline, Modified.code());
469 ASSERT_TRUE(AST);
471 auto HI = getHover(*AST, Modified.point(), format::getLLVMStyle(), nullptr);
472 ASSERT_TRUE(HI);
473 EXPECT_THAT(HI->Definition, "#define BAR");
477 MATCHER_P(referenceRangeIs, R, "") { return arg.Loc.range == R; }
479 TEST(PreamblePatchTest, RefsToMacros) {
480 struct {
481 const char *const Baseline;
482 const char *const Modified;
483 } Cases[] = {
484 // Newly added
487 R"cpp(
488 #define ^FOO
489 ^[[FOO]])cpp",
491 // Moved around
493 "#define FOO",
494 R"cpp(
495 #define BAR
496 #define ^FOO
497 ^[[FOO]])cpp",
499 // Ref in preamble section
502 R"cpp(
503 #define ^FOO
504 #undef ^FOO)cpp",
508 for (const auto &Case : Cases) {
509 Annotations Modified(Case.Modified);
510 auto AST = createPatchedAST("", Modified.code());
511 ASSERT_TRUE(AST);
513 const auto &SM = AST->getSourceManager();
514 std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
515 for (const auto &R : Modified.ranges())
516 ExpectedLocations.push_back(referenceRangeIs(R));
518 for (const auto &P : Modified.points()) {
519 auto *MacroTok = AST->getTokens().spelledTokenAt(SM.getComposedLoc(
520 SM.getMainFileID(),
521 llvm::cantFail(positionToOffset(Modified.code(), P))));
522 ASSERT_TRUE(MacroTok);
523 EXPECT_THAT(findReferences(*AST, P, 0).References,
524 testing::ElementsAreArray(ExpectedLocations));
529 TEST(TranslatePreamblePatchLocation, Simple) {
530 auto TU = TestTU::withHeaderCode(R"cpp(
531 #line 3 "main.cpp"
532 int foo();)cpp");
533 // Presumed line/col needs to be valid in the main file.
534 TU.Code = R"cpp(// line 1
535 // line 2
536 // line 3
537 // line 4)cpp";
538 TU.Filename = "main.cpp";
539 TU.HeaderFilename = "__preamble_patch__.h";
540 TU.ImplicitHeaderGuard = false;
542 auto AST = TU.build();
543 auto &SM = AST.getSourceManager();
544 auto &ND = findDecl(AST, "foo");
545 EXPECT_NE(SM.getFileID(ND.getLocation()), SM.getMainFileID());
547 auto TranslatedLoc = translatePreamblePatchLocation(ND.getLocation(), SM);
548 auto DecompLoc = SM.getDecomposedLoc(TranslatedLoc);
549 EXPECT_EQ(DecompLoc.first, SM.getMainFileID());
550 EXPECT_EQ(SM.getLineNumber(DecompLoc.first, DecompLoc.second), 3U);
553 TEST(PreamblePatch, ModifiedBounds) {
554 struct {
555 const char *const Baseline;
556 const char *const Modified;
557 } Cases[] = {
558 // Size increased
561 R"cpp(
562 #define FOO
563 FOO)cpp",
565 // Stayed same
566 {"#define FOO", "#define BAR"},
567 // Got smaller
569 R"cpp(
570 #define FOO
571 #undef FOO)cpp",
572 "#define FOO"},
575 for (const auto &Case : Cases) {
576 auto TU = TestTU::withCode(Case.Baseline);
577 auto BaselinePreamble = TU.preamble();
578 ASSERT_TRUE(BaselinePreamble);
580 Annotations Modified(Case.Modified);
581 TU.Code = Modified.code().str();
582 MockFS FS;
583 auto PP = PreamblePatch::createFullPatch(testPath(TU.Filename),
584 TU.inputs(FS), *BaselinePreamble);
586 IgnoreDiagnostics Diags;
587 auto CI = buildCompilerInvocation(TU.inputs(FS), Diags);
588 ASSERT_TRUE(CI);
590 const auto ExpectedBounds =
591 Lexer::ComputePreamble(Case.Modified, *CI->getLangOpts());
592 EXPECT_EQ(PP.modifiedBounds().Size, ExpectedBounds.Size);
593 EXPECT_EQ(PP.modifiedBounds().PreambleEndsAtStartOfLine,
594 ExpectedBounds.PreambleEndsAtStartOfLine);
598 TEST(PreamblePatch, MacroLoc) {
599 llvm::StringLiteral Baseline = "\n#define MACRO 12\nint num = MACRO;";
600 llvm::StringLiteral Modified = " \n#define MACRO 12\nint num = MACRO;";
601 auto AST = createPatchedAST(Baseline, Modified);
602 ASSERT_TRUE(AST);
605 TEST(PreamblePatch, NoopWhenNotRequested) {
606 llvm::StringLiteral Baseline = "#define M\nint num = M;";
607 llvm::StringLiteral Modified = "#define M\n#include <foo.h>\nint num = M;";
608 auto TU = TestTU::withCode(Baseline);
609 auto BaselinePreamble = TU.preamble();
610 ASSERT_TRUE(BaselinePreamble);
612 TU.Code = Modified.str();
613 MockFS FS;
614 auto PP = PreamblePatch::createMacroPatch(testPath(TU.Filename),
615 TU.inputs(FS), *BaselinePreamble);
616 EXPECT_TRUE(PP.text().empty());
619 ::testing::Matcher<const Diag &>
620 withNote(::testing::Matcher<Note> NoteMatcher) {
621 return Field(&Diag::Notes, ElementsAre(NoteMatcher));
623 MATCHER_P(Diag, Range, "Diag at " + llvm::to_string(Range)) {
624 return arg.Range == Range;
626 MATCHER_P2(Diag, Range, Name,
627 "Diag at " + llvm::to_string(Range) + " = [" + Name + "]") {
628 return arg.Range == Range && arg.Name == Name;
631 TEST(PreamblePatch, DiagnosticsFromMainASTAreInRightPlace) {
633 Annotations Code("#define FOO");
634 // Check with removals from preamble.
635 Annotations NewCode("[[x]];/* error-ok */");
636 auto AST = createPatchedAST(Code.code(), NewCode.code());
637 EXPECT_THAT(AST->getDiagnostics(),
638 ElementsAre(Diag(NewCode.range(), "missing_type_specifier")));
641 // Check with additions to preamble.
642 Annotations Code("#define FOO");
643 Annotations NewCode(R"(
644 #define FOO
645 #define BAR
646 [[x]];/* error-ok */)");
647 auto AST = createPatchedAST(Code.code(), NewCode.code());
648 EXPECT_THAT(AST->getDiagnostics(),
649 ElementsAre(Diag(NewCode.range(), "missing_type_specifier")));
653 TEST(PreamblePatch, DiagnosticsToPreamble) {
654 Config Cfg;
655 Cfg.Diagnostics.UnusedIncludes = Config::IncludesPolicy::Strict;
656 Cfg.Diagnostics.MissingIncludes = Config::IncludesPolicy::Strict;
657 WithContextValue WithCfg(Config::Key, std::move(Cfg));
659 llvm::StringMap<std::string> AdditionalFiles;
660 AdditionalFiles["foo.h"] = "#pragma once";
661 AdditionalFiles["bar.h"] = "#pragma once";
663 Annotations Code(R"(
664 // Test comment
665 [[#include "foo.h"]])");
666 // Check with removals from preamble.
667 Annotations NewCode(R"([[# include "foo.h"]])");
668 auto AST = createPatchedAST(Code.code(), NewCode.code(), AdditionalFiles);
669 EXPECT_THAT(AST->getDiagnostics(),
670 ElementsAre(Diag(NewCode.range(), "unused-includes")));
673 // Check with additions to preamble.
674 Annotations Code(R"(
675 // Test comment
676 [[#include "foo.h"]])");
677 Annotations NewCode(R"(
678 $bar[[#include "bar.h"]]
679 // Test comment
680 $foo[[#include "foo.h"]])");
681 auto AST = createPatchedAST(Code.code(), NewCode.code(), AdditionalFiles);
682 EXPECT_THAT(
683 AST->getDiagnostics(),
684 UnorderedElementsAre(Diag(NewCode.range("bar"), "unused-includes"),
685 Diag(NewCode.range("foo"), "unused-includes")));
688 Annotations Code("#define [[FOO]] 1\n");
689 // Check ranges for notes.
690 // This also makes sure we don't generate missing-include diagnostics
691 // because macros are redefined in preamble-patch.
692 Annotations NewCode(R"(#define BARXYZ 1
693 #define $foo1[[FOO]] 1
694 void foo();
695 #define $foo2[[FOO]] 2)");
696 auto AST = createPatchedAST(Code.code(), NewCode.code(), AdditionalFiles);
697 EXPECT_THAT(
698 AST->getDiagnostics(),
699 ElementsAre(AllOf(Diag(NewCode.range("foo2"), "-Wmacro-redefined"),
700 withNote(Diag(NewCode.range("foo1"))))));
704 TEST(PreamblePatch, TranslatesDiagnosticsInPreamble) {
706 // Check with additions to preamble.
707 Annotations Code("#include [[<foo>]]");
708 Annotations NewCode(R"(
709 #define BAR
710 #include [[<foo>]])");
711 auto AST = createPatchedAST(Code.code(), NewCode.code());
712 EXPECT_THAT(AST->getDiagnostics(),
713 ElementsAre(Diag(NewCode.range(), "pp_file_not_found")));
716 // Check with removals from preamble.
717 Annotations Code(R"(
718 #define BAR
719 #include [[<foo>]])");
720 Annotations NewCode("#include [[<foo>]]");
721 auto AST = createPatchedAST(Code.code(), NewCode.code());
722 EXPECT_THAT(AST->getDiagnostics(),
723 ElementsAre(Diag(NewCode.range(), "pp_file_not_found")));
726 // Drop line with diags.
727 Annotations Code("#include [[<foo>]]");
728 Annotations NewCode("#define BAR\n#define BAZ\n");
729 auto AST = createPatchedAST(Code.code(), NewCode.code());
730 EXPECT_THAT(AST->getDiagnostics(), IsEmpty());
733 // Picks closest line in case of multiple alternatives.
734 Annotations Code("#include [[<foo>]]");
735 Annotations NewCode(R"(
736 #define BAR
737 #include [[<foo>]]
738 #define BAR
739 #include <foo>)");
740 auto AST = createPatchedAST(Code.code(), NewCode.code());
741 EXPECT_THAT(AST->getDiagnostics(),
742 ElementsAre(Diag(NewCode.range(), "pp_file_not_found")));
745 // Drop diag if line spelling has changed.
746 Annotations Code("#include [[<foo>]]");
747 Annotations NewCode(" # include <foo>");
748 auto AST = createPatchedAST(Code.code(), NewCode.code());
749 EXPECT_THAT(AST->getDiagnostics(), IsEmpty());
752 // Multiple lines.
753 Annotations Code(R"(
754 #define BAR
755 #include [[<fo\
756 o>]])");
757 Annotations NewCode(R"(#include [[<fo\
758 o>]])");
759 auto AST = createPatchedAST(Code.code(), NewCode.code());
760 EXPECT_THAT(AST->getDiagnostics(),
761 ElementsAre(Diag(NewCode.range(), "pp_file_not_found")));
764 // Multiple lines with change.
765 Annotations Code(R"(
766 #define BAR
767 #include <fox>
768 #include [[<fo\
769 o>]])");
770 Annotations NewCode(R"(#include <fo\
771 x>)");
772 auto AST = createPatchedAST(Code.code(), NewCode.code());
773 EXPECT_THAT(AST->getDiagnostics(), IsEmpty());
776 // Preserves notes.
777 Annotations Code(R"(
778 #define $note[[BAR]] 1
779 #define $main[[BAR]] 2)");
780 Annotations NewCode(R"(
781 #define BAZ 0
782 #define $note[[BAR]] 1
783 #define BAZ 0
784 #define $main[[BAR]] 2)");
785 auto AST = createPatchedAST(Code.code(), NewCode.code());
786 EXPECT_THAT(
787 AST->getDiagnostics(),
788 ElementsAre(AllOf(Diag(NewCode.range("main"), "-Wmacro-redefined"),
789 withNote(Diag(NewCode.range("note"))))));
792 // Preserves diag without note.
793 Annotations Code(R"(
794 #define $note[[BAR]] 1
795 #define $main[[BAR]] 2)");
796 Annotations NewCode(R"(
797 #define $main[[BAR]] 2)");
798 auto AST = createPatchedAST(Code.code(), NewCode.code());
799 EXPECT_THAT(
800 AST->getDiagnostics(),
801 ElementsAre(AllOf(Diag(NewCode.range("main"), "-Wmacro-redefined"),
802 Field(&Diag::Notes, IsEmpty()))));
805 // Make sure orphaned notes are not promoted to diags.
806 Annotations Code(R"(
807 #define $note[[BAR]] 1
808 #define $main[[BAR]] 2)");
809 Annotations NewCode(R"(
810 #define BAZ 0
811 #define BAR 1)");
812 auto AST = createPatchedAST(Code.code(), NewCode.code());
813 EXPECT_THAT(AST->getDiagnostics(), IsEmpty());
816 Annotations Code(R"(
817 #ifndef FOO
818 #define FOO
819 void foo();
820 #endif)");
821 // This code will emit a diagnostic for unterminated #ifndef (as stale
822 // preamble has the conditional but main file doesn't terminate it).
823 // We shouldn't emit any diagnotiscs (and shouldn't crash).
824 Annotations NewCode("");
825 auto AST = createPatchedAST(Code.code(), NewCode.code());
826 EXPECT_THAT(AST->getDiagnostics(), IsEmpty());
829 Annotations Code(R"(
830 #ifndef FOO
831 #define FOO
832 void foo();
833 #endif)");
834 // This code will emit a diagnostic for unterminated #ifndef (as stale
835 // preamble has the conditional but main file doesn't terminate it).
836 // We shouldn't emit any diagnotiscs (and shouldn't crash).
837 // FIXME: Patch/ignore diagnostics in such cases.
838 Annotations NewCode(R"(
839 i[[nt]] xyz;
840 )");
841 auto AST = createPatchedAST(Code.code(), NewCode.code());
842 EXPECT_THAT(
843 AST->getDiagnostics(),
844 ElementsAre(Diag(NewCode.range(), "pp_unterminated_conditional")));
848 MATCHER_P2(Mark, Range, Text, "") {
849 return std::tie(arg.Rng, arg.Trivia) == std::tie(Range, Text);
852 TEST(PreamblePatch, MacroAndMarkHandling) {
854 Annotations Code(R"cpp(
855 #ifndef FOO
856 #define FOO
857 // Some comments
858 #pragma mark XX
859 #define BAR
861 #endif)cpp");
862 Annotations NewCode(R"cpp(
863 #ifndef FOO
864 #define FOO
865 #define BAR
866 #pragma $x[[mark XX
868 #pragma $y[[mark YY
870 #define BAZ
872 #endif)cpp");
873 auto AST = createPatchedAST(Code.code(), NewCode.code());
874 EXPECT_THAT(AST->getMacros().Names.keys(),
875 UnorderedElementsAreArray({"FOO", "BAR", "BAZ"}));
876 EXPECT_THAT(AST->getMarks(),
877 UnorderedElementsAre(Mark(NewCode.range("x"), " XX"),
878 Mark(NewCode.range("y"), " YY")));
882 TEST(PreamblePatch, PatchFileEntry) {
883 Annotations Code(R"cpp(#define FOO)cpp");
884 Annotations NewCode(R"cpp(
885 #define BAR
886 #define FOO)cpp");
888 auto AST = createPatchedAST(Code.code(), Code.code());
889 EXPECT_EQ(
890 PreamblePatch::getPatchEntry(AST->tuPath(), AST->getSourceManager()),
891 nullptr);
894 auto AST = createPatchedAST(Code.code(), NewCode.code());
895 auto *FE =
896 PreamblePatch::getPatchEntry(AST->tuPath(), AST->getSourceManager());
897 ASSERT_NE(FE, nullptr);
898 EXPECT_THAT(FE->getName().str(),
899 testing::EndsWith(PreamblePatch::HeaderName.str()));
903 } // namespace
904 } // namespace clangd
905 } // namespace clang