1 //===--- PreambleTests.cpp --------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "Annotations.h"
12 #include "Diagnostics.h"
15 #include "ParsedAST.h"
18 #include "SourceCode.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"
44 using testing::Contains
;
45 using testing::ElementsAre
;
46 using testing::ElementsAreArray
;
49 using testing::HasSubstr
;
50 using testing::IsEmpty
;
51 using testing::Matcher
;
52 using testing::MatchesRegex
;
54 using testing::UnorderedElementsAre
;
55 using testing::UnorderedElementsAreArray
;
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.
68 collectPatchedIncludes(llvm::StringRef ModifiedContents
,
69 llvm::StringRef BaselineContents
,
70 llvm::StringRef MainFileName
= "main.cpp") {
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();
78 TU
.Code
= ModifiedContents
.str();
79 auto PI
= TU
.inputs(FS
);
80 auto PP
= PreamblePatch::createFullPatch(testPath(TU
.Filename
), PI
,
82 // Collect patch contents.
83 IgnoreDiagnostics Diags
;
84 auto CI
= buildCompilerInvocation(PI
, Diags
);
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
91 auto Bounds
= Lexer::ComputePreamble(ModifiedContents
, *CI
->getLangOpts());
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";
102 IncludeStructure Includes
;
103 Includes
.collect(*Clang
);
104 if (llvm::Error Err
= Action
.Execute()) {
105 ADD_FAILURE() << "failed to execute action: " << std::move(Err
);
108 Action
.EndSourceFile();
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
[] = {
118 R
"cpp(^#include "a
.h
")cpp",
119 // Both preamble and mainfile
122 garbage, finishes preamble
138 ^#include <b.h>)cpp",
139 // Directive is not part of preamble if it is not the token immediately
140 // followed by the hash (#).
143 #/**/include <b.h>)cpp",
146 for (const auto &Case : Cases) {
147 Annotations Test(Case);
148 const auto Code = Test.code();
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(
163 #include <b.h> // This will be removed
166 constexpr llvm::StringLiteral ModifiedContents = R"cpp(
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.
172 auto Includes = collectPatchedIncludes(ModifiedContents, BaselineContents)
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")
181 EXPECT_THAT(Includes, ElementsAre(AllOf(Field(&Inclusion::Written, "<a.h>"),
182 Field(&Inclusion::HashLine, 0))));
185 TEST(PreamblePatchTest, PatchesPreambleIncludes) {
187 IgnoreDiagnostics Diags;
188 auto TU = TestTU::withCode(R"cpp(
189 #include "a.h" // IWYU pragma: keep
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.
211 auto PP = PreamblePatch::createFullPatch(testPath(TU.Filename), TU.inputs(FS),
213 // Only a.h should exists in the preamble, as c.h has been dropped and b.h was
216 PP.preambleIncludes(),
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
";
235 IgnoreDiagnostics Diags;
237 TU.Code = Modified.str();
238 auto CI = buildCompilerInvocation(TU.inputs(FS), Diags);
240 ADD_FAILURE() << "Failed to build compiler invocation
";
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
";
255 auto TU = TestTU::withCode(Modified);
256 return PreamblePatch::createFullPatch(testPath("main
.cpp
"), TU.inputs(FS),
262 TEST(PreamblePatchTest, IncludesArePreserved) {
263 llvm::StringLiteral Baseline = R"(//error-ok
267 llvm::StringLiteral Modified = R"(//error-ok
272 auto Includes = createPatchedAST(Baseline, Modified.str())
273 ->getIncludeStructure()
275 EXPECT_TRUE(!Includes.empty());
276 EXPECT_EQ(Includes, TestTU::withCode(Baseline)
278 .getIncludeStructure()
282 TEST(PreamblePatchTest, Define) {
283 // BAR should be defined while parsing the AST.
285 const char *const Contents;
286 const char *const ExpectedPatch;
292 R"cpp(#line 0 ".*main.cpp"
304 R"cpp(#line 0 ".*main.cpp"
316 R"cpp(#line 0 ".*main.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());
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
349 llvm::StringLiteral ExpectedPatch(R"cpp(#line 0 ".*main.cpp"
352 #define BAR\(X, Y\) X Y
357 EXPECT_THAT(getPreamblePatch(Baseline, Modified.code()),
358 MatchesRegex(ExpectedPatch.str()));
360 auto AST = createPatchedAST(Baseline, Modified.code());
364 TEST(PreamblePatchTest, LocateMacroAtWorks) {
366 const char *const Baseline;
367 const char *const Modified;
369 // Addition of new directive
376 // Available inside preamble section
381 #undef $use^FOO)cpp",
383 // Available after undef, as we don't patch those
391 // Identifier on a different line
399 // In presence of comment tokens
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());
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());
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");
456 getHover(*AST, offsetToPosition(Modified.code(), Modified.point()),
457 format::getLLVMStyle(), nullptr);
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
468 auto AST
= createPatchedAST(Baseline
, Modified
.code());
471 auto HI
= getHover(*AST
, Modified
.point(), format::getLLVMStyle(), nullptr);
473 EXPECT_THAT(HI
->Definition
, "#define BAR");
477 MATCHER_P(referenceRangeIs
, R
, "") { return arg
.Loc
.range
== R
; }
479 TEST(PreamblePatchTest
, RefsToMacros
) {
481 const char *const Baseline
;
482 const char *const Modified
;
499 // Ref in preamble section
508 for (const auto &Case
: Cases
) {
509 Annotations
Modified(Case
.Modified
);
510 auto AST
= createPatchedAST("", Modified
.code());
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(
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(
533 // Presumed line/col needs to be valid in the main file.
534 TU
.Code
= R
"cpp(// line 1
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
) {
555 const char *const Baseline
;
556 const char *const Modified
;
566 {"#define FOO", "#define BAR"},
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();
583 auto PP
= PreamblePatch::createFullPatch(testPath(TU
.Filename
),
584 TU
.inputs(FS
), *BaselinePreamble
);
586 IgnoreDiagnostics Diags
;
587 auto CI
= buildCompilerInvocation(TU
.inputs(FS
), Diags
);
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
);
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();
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
"(
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
) {
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";
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.
676 [[#include "foo
.h
"]])");
677 Annotations
NewCode(R
"(
678 $bar[[#include "bar
.h
"]]
680 $foo[[#include "foo
.h
"]])");
681 auto AST
= createPatchedAST(Code
.code(), NewCode
.code(), AdditionalFiles
);
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
695 #define $foo2[[FOO]] 2)");
696 auto AST
= createPatchedAST(Code
.code(), NewCode
.code(), AdditionalFiles
);
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
"(
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.
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
"(
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());
757 Annotations
NewCode(R
"(#include [[<fo\
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.
770 Annotations
NewCode(R
"(#include <fo\
772 auto AST
= createPatchedAST(Code
.code(), NewCode
.code());
773 EXPECT_THAT(AST
->getDiagnostics(), IsEmpty());
778 #define $note[[BAR]] 1
779 #define $main[[BAR]] 2)");
780 Annotations
NewCode(R
"(
782 #define $note[[BAR]] 1
784 #define $main[[BAR]] 2)");
785 auto AST
= createPatchedAST(Code
.code(), NewCode
.code());
787 AST
->getDiagnostics(),
788 ElementsAre(AllOf(Diag(NewCode
.range("main"), "-Wmacro-redefined"),
789 withNote(Diag(NewCode
.range("note"))))));
792 // Preserves diag without note.
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());
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.
807 #define $note[[BAR]] 1
808 #define $main[[BAR]] 2)");
809 Annotations
NewCode(R
"(
812 auto AST
= createPatchedAST(Code
.code(), NewCode
.code());
813 EXPECT_THAT(AST
->getDiagnostics(), IsEmpty());
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());
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
"(
841 auto AST
= createPatchedAST(Code
.code(), NewCode
.code());
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(
862 Annotations
NewCode(R
"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(
888 auto AST
= createPatchedAST(Code
.code(), Code
.code());
890 PreamblePatch::getPatchEntry(AST
->tuPath(), AST
->getSourceManager()),
894 auto AST
= createPatchedAST(Code
.code(), NewCode
.code());
896 PreamblePatch::getPatchEntry(AST
->tuPath(), AST
->getSourceManager());
897 ASSERT_NE(FE
, nullptr);
898 EXPECT_THAT(FE
->getName().str(),
899 testing::EndsWith(PreamblePatch::HeaderName
.str()));
904 } // namespace clangd