17#include "clang-include-cleaner/Analysis.h"
18#include "clang-include-cleaner/Types.h"
19#include "clang/AST/DeclBase.h"
20#include "clang/Basic/SourceManager.h"
21#include "clang/Tooling/Syntax/Tokens.h"
22#include "llvm/ADT/ArrayRef.h"
23#include "llvm/ADT/ScopeExit.h"
24#include "llvm/ADT/StringMap.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/Support/Casting.h"
27#include "llvm/Support/Error.h"
28#include "llvm/Support/ScopedPrinter.h"
29#include "gmock/gmock.h"
30#include "gtest/gtest.h"
40using ::testing::AllOf;
41using ::testing::ElementsAre;
42using ::testing::IsEmpty;
43using ::testing::Matcher;
44using ::testing::Pointee;
45using ::testing::UnorderedElementsAre;
48withFix(std::vector<::testing::Matcher<Fix>> FixMatcheres) {
49 return Field(&
Diag::Fixes, testing::UnorderedElementsAreArray(FixMatcheres));
53 "Diag at " + llvm::to_string(
Range) +
" = [" + Message +
"]") {
54 return arg.Range ==
Range && arg.Message == Message;
57MATCHER_P3(
Fix,
Range, Replacement, Message,
58 "Fix " + llvm::to_string(
Range) +
" => " +
59 ::testing::PrintToString(Replacement) +
" = [" + Message +
"]") {
60 return arg.Message == Message && arg.Edits.size() == 1 &&
61 arg.Edits[0].range ==
Range && arg.Edits[0].newText == Replacement;
63MATCHER_P(FixMessage, Message,
"") {
return arg.Message == Message; }
65std::string guard(llvm::StringRef Code) {
66 return "#pragma once\n" + Code.str();
70 if (arg.Written != Written)
71 *result_listener << arg.Written;
72 return arg.Written == Written;
75TEST(IncludeCleaner, StdlibUnused) {
79 #include <vector> // IWYU pragma: keep
80 #include <string> // IWYU pragma: export
84 TU.AdditionalFiles[
"bits"] = R
"cpp(
87 template <typename> class list {};
88 template <typename> class queue {};
89 template <typename> class vector {};
92 TU.AdditionalFiles["list"] = guard(
"#include <bits>");
93 TU.AdditionalFiles[
"queue"] = guard(
"#include <bits>");
94 TU.AdditionalFiles[
"vector"] = guard(
"#include <bits>");
95 TU.AdditionalFiles[
"string"] = guard(
"#include <bits>");
96 TU.ExtraArgs = {
"-isystem",
testRoot()};
97 auto AST = TU.build();
99 EXPECT_THAT(Findings.UnusedIncludes,
100 ElementsAre(
Pointee(writtenInclusion(
"<queue>"))));
103TEST(IncludeCleaner, GetUnusedHeaders) {
104 llvm::StringLiteral MainFile = R
"cpp(
108 #include "dir/unused.h"
109 #include "unguarded.h"
111 #include <system_header.h>
112 #include <non_system_angled_header.h>
121 TU.AdditionalFiles[
"foo.h"] = guard(
"void foo();");
122 TU.AdditionalFiles[
"a.h"] = guard(
"void a();");
123 TU.AdditionalFiles[
"b.h"] = guard(
"void b();");
124 TU.AdditionalFiles[
"dir/c.h"] = guard(
"void c();");
125 TU.AdditionalFiles[
"unused.h"] = guard(
"void unused();");
126 TU.AdditionalFiles[
"dir/unused.h"] = guard(
"void dirUnused();");
127 TU.AdditionalFiles[
"dir/non_system_angled_header.h"] = guard(
"");
128 TU.AdditionalFiles[
"system/system_header.h"] = guard(
"");
129 TU.AdditionalFiles[
"unguarded.h"] =
"";
130 TU.ExtraArgs.push_back(
"-I" +
testPath(
"dir"));
131 TU.ExtraArgs.push_back(
"-isystem" +
testPath(
"system"));
132 TU.Code = MainFile.str();
136 Findings.UnusedIncludes,
137 UnorderedElementsAre(
Pointee(writtenInclusion(
"\"unused.h\"")),
138 Pointee(writtenInclusion(
"\"dir/unused.h\""))));
141TEST(IncludeCleaner, IgnoredAngledHeaders) {
144 #include <system_header.h>
145 #include <system_unused.h>
146 #include <non_system_angled_unused.h>
149 TU.AdditionalFiles["system/system_header.h"] = guard(
"class SystemClass {};");
150 TU.AdditionalFiles[
"system/system_unused.h"] = guard(
"");
151 TU.AdditionalFiles[
"dir/non_system_angled_unused.h"] = guard(
"");
156 auto AST = TU.build();
158 EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
161TEST(IncludeCleaner, UnusedAngledHeaders) {
163 #include <system_header.h>
164 #include <system_unused.h>
165 #include <non_system_angled_unused.h>
168 TU.AdditionalFiles["system/system_header.h"] = guard(
"class SystemClass {};");
169 TU.AdditionalFiles[
"system/system_unused.h"] = guard(
"");
170 TU.AdditionalFiles[
"dir/non_system_angled_unused.h"] = guard(
"");
175 auto AST = TU.build();
177 EXPECT_THAT(Findings.UnusedIncludes,
178 UnorderedElementsAre(
179 Pointee(writtenInclusion(
"<system_unused.h>")),
180 Pointee(writtenInclusion(
"<non_system_angled_unused.h>"))));
183TEST(IncludeCleaner, ComputeMissingHeaders) {
192 TU.AdditionalFiles[
"a.h"] = guard(
"#include \"b.h\"");
193 TU.AdditionalFiles[
"b.h"] = guard(
"void b();");
195 TU.Code = MainFile.code();
199 const SourceManager &SM =
AST.getSourceManager();
200 const NamedDecl *BDecl =
nullptr;
201 for (Decl *D :
AST.getASTContext().getTranslationUnitDecl()->decls()) {
202 const NamedDecl *CandidateDecl = llvm::dyn_cast<NamedDecl>(D);
203 std::string Name = CandidateDecl->getQualifiedNameAsString();
206 BDecl = CandidateDecl;
209 include_cleaner::Symbol
B{*BDecl};
210 auto Range = MainFile.range(
"b");
213 syntax::FileRange BRange{SM.getMainFileID(),
static_cast<unsigned int>(Start),
214 static_cast<unsigned int>(End)};
215 include_cleaner::Header Header{
216 *SM.getFileManager().getOptionalFileRef(
"b.h")};
218 EXPECT_THAT(Findings.MissingIncludes, ElementsAre(BInfo));
221TEST(IncludeCleaner, GenerateMissingHeaderDiags) {
224#include "angled_wrapper.h"
226$insert_b[[]]#include "baz.h"
228$insert_d[[]]$insert_foo[[]]#include "fuzz.h"
230$insert_foobar[[]]$insert_quoted[[]]$insert_quoted2[[]]#include "quoted_wrapper.h"
231$insert_angled[[]]#include <e.h>
232$insert_f[[]]#include <quoted2_wrapper.h>
235#define DEF(X) const Foo *X;
236#define BAZ(X) const X x
238// No missing include insertion for ambiguous macro refs.
246 $quoted2[[quoted2]]();
252 // this should not be diagnosed, because it's ignored in the config
257 std::$vector[[vector]] v;
259 int var = $FOO[[FOO]];
270 TU.AdditionalFiles[
"a.h"] = guard(
"#include \"b.h\"");
271 TU.AdditionalFiles[
"b.h"] = guard(
"void b();");
273 TU.AdditionalFiles[
"angled_wrapper.h"] = guard(
"#include <angled.h>");
274 TU.AdditionalFiles[
"angled.h"] = guard(
"void angled();");
275 TU.ExtraArgs.push_back(
"-I" +
testPath(
"."));
277 TU.AdditionalFiles[
"quoted_wrapper.h"] = guard(
"#include \"quoted.h\"");
278 TU.AdditionalFiles[
"quoted.h"] = guard(
"void quoted();");
280 TU.AdditionalFiles[
"dir/c.h"] = guard(
"#include \"d.h\"");
281 TU.AdditionalFiles[
"dir/d.h"] =
282 guard(
"namespace ns { struct Bar { void d(); }; }");
284 TU.AdditionalFiles[
"system/e.h"] = guard(
"#include <f.h>");
285 TU.AdditionalFiles[
"system/f.h"] = guard(
"void f();");
286 TU.AdditionalFiles[
"system/quoted2_wrapper.h"] =
287 guard(
"#include <system/quoted2.h>");
288 TU.AdditionalFiles[
"system/quoted2.h"] = guard(
"void quoted2();");
289 TU.ExtraArgs.push_back(
"-isystem" +
testPath(
"system"));
291 TU.AdditionalFiles[
"fuzz.h"] = guard(
"#include \"buzz.h\"");
292 TU.AdditionalFiles[
"buzz.h"] = guard(
"void buzz();");
294 TU.AdditionalFiles[
"baz.h"] = guard(
"#include \"private.h\"");
295 TU.AdditionalFiles[
"private.h"] = guard(R
"cpp(
296 // IWYU pragma: private, include "public.h"
299 TU.AdditionalFiles["header.h"] = guard(R
"cpp(
300 namespace std { class vector {}; }
303 TU.AdditionalFiles["all.h"] = guard(
"#include \"foo.h\"");
304 TU.AdditionalFiles[
"foo.h"] = guard(R
"cpp(
305 #define BAR(x) Foo *x
310 TU.Code = MainFile.code();
314 Findings.UnusedIncludes.clear();
317 {[](llvm::StringRef Header) {
318 return Header.ends_with(
"buzz.h");
320 {[](llvm::StringRef Header) {
321 return Header.contains(
"angled.h");
323 {[](llvm::StringRef Header) {
324 return Header.contains(
"quoted.h") || Header.contains(
"quoted2.h");
328 UnorderedElementsAre(
329 AllOf(
Diag(MainFile.range(
"b"),
330 "No header providing \"b\" is directly included"),
331 withFix({
Fix(MainFile.range(
"insert_b"),
"#include \"b.h\"\n",
333 FixMessage(
"add all missing includes")})),
334 AllOf(
Diag(MainFile.range(
"angled"),
335 "No header providing \"angled\" is directly included"),
336 withFix({
Fix(MainFile.range(
"insert_angled"),
337 "#include <angled.h>\n",
"#include <angled.h>"),
338 FixMessage(
"add all missing includes")})),
340 Diag(MainFile.range(
"quoted"),
341 "No header providing \"quoted\" is directly included"),
342 withFix({
Fix(MainFile.range(
"insert_quoted"),
343 "#include \"quoted.h\"\n",
"#include \"quoted.h\""),
344 FixMessage(
"add all missing includes")})),
345 AllOf(
Diag(MainFile.range(
"quoted2"),
346 "No header providing \"quoted2\" is directly included"),
348 {
Fix(MainFile.range(
"insert_quoted2"),
349 "#include \"quoted2.h\"\n",
"#include \"quoted2.h\""),
350 FixMessage(
"add all missing includes")})),
351 AllOf(
Diag(MainFile.range(
"bar"),
352 "No header providing \"ns::Bar\" is directly included"),
353 withFix({
Fix(MainFile.range(
"insert_d"),
354 "#include \"dir/d.h\"\n",
"#include \"dir/d.h\""),
355 FixMessage(
"add all missing includes")})),
356 AllOf(
Diag(MainFile.range(
"f"),
357 "No header providing \"f\" is directly included"),
358 withFix({
Fix(MainFile.range(
"insert_f"),
"#include <f.h>\n",
360 FixMessage(
"add all missing includes")})),
362 Diag(MainFile.range(
"foobar"),
363 "No header providing \"foobar\" is directly included"),
364 withFix({
Fix(MainFile.range(
"insert_foobar"),
365 "#include \"public.h\"\n",
"#include \"public.h\""),
366 FixMessage(
"add all missing includes")})),
368 Diag(MainFile.range(
"vector"),
369 "No header providing \"std::vector\" is directly included"),
371 Fix(MainFile.range(
"insert_vector"),
"#include <vector>\n",
372 "#include <vector>"),
373 FixMessage(
"add all missing includes"),
375 AllOf(
Diag(MainFile.range(
"FOO"),
376 "No header providing \"FOO\" is directly included"),
377 withFix({
Fix(MainFile.range(
"insert_foo"),
378 "#include \"foo.h\"\n",
"#include \"foo.h\""),
379 FixMessage(
"add all missing includes")})),
380 AllOf(
Diag(MainFile.range(
"DEF"),
381 "No header providing \"Foo\" is directly included"),
382 withFix({
Fix(MainFile.range(
"insert_foo"),
383 "#include \"foo.h\"\n",
"#include \"foo.h\""),
384 FixMessage(
"add all missing includes")})),
385 AllOf(
Diag(MainFile.range(
"BAR"),
386 "No header providing \"BAR\" is directly included"),
387 withFix({
Fix(MainFile.range(
"insert_foo"),
388 "#include \"foo.h\"\n",
"#include \"foo.h\""),
389 FixMessage(
"add all missing includes")})),
390 AllOf(
Diag(MainFile.range(
"Foo"),
391 "No header providing \"Foo\" is directly included"),
392 withFix({
Fix(MainFile.range(
"insert_foo"),
393 "#include \"foo.h\"\n",
"#include \"foo.h\""),
394 FixMessage(
"add all missing includes")}))));
397TEST(IncludeCleaner, IWYUPragmas) {
400 #include "behind_keep.h" // IWYU pragma: keep
401 #include "exported.h" // IWYU pragma: export
404 void bar() { foo(); }
405 #include "keep_main_file.h" // IWYU pragma: keep
407 TU.AdditionalFiles["behind_keep.h"] = guard(
"");
408 TU.AdditionalFiles[
"keep_main_file.h"] = guard(
"");
409 TU.AdditionalFiles[
"exported.h"] = guard(
"");
410 TU.AdditionalFiles[
"public.h"] = guard(
"#include \"private.h\"");
411 TU.AdditionalFiles[
"private.h"] = guard(R
"cpp(
412 // IWYU pragma: private, include "public.h"
417 EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
420TEST(IncludeCleaner, IWYUPragmaExport) {
425 TU.AdditionalFiles["foo.h"] = R
"cpp(
429 #include "bar.h" // IWYU pragma: export
433 TU.AdditionalFiles["bar.h"] = guard(R
"cpp(
439 EXPECT_THAT(Findings.UnusedIncludes,
440 ElementsAre(Pointee(writtenInclusion("\"foo.h\""))));
443TEST(IncludeCleaner, NoDiagsForObjC) {
450 TU.AdditionalFiles["foo.h"] = R
"cpp(
456 TU.ExtraArgs.emplace_back("-xobjective-c");
460 EXPECT_THAT(Findings.MissingIncludes, IsEmpty());
461 EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
464TEST(IncludeCleaner, UmbrellaUsesPrivate) {
469 TU.AdditionalFiles["private.h"] = guard(R
"cpp(
470 // IWYU pragma: private, include "public.h"
473 TU.Filename = "public.h";
476 EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
479TEST(IncludeCleaner, MacroExpandedThroughIncludes) {
482 #define FOO(X) const Foo *X
484 #include [["expander.inc"]]
490 TU.AdditionalFiles[
"foo.h"] = guard(
"struct Foo {};");
491 TU.AdditionalFiles[
"all.h"] = guard(
"#include \"foo.h\"");
493 TU.Code = MainFile.code();
497 EXPECT_THAT(Findings, testing::SizeIs(1));
498 auto RefRange = Findings.front().SymRefRange;
499 auto &SM =
AST.getSourceManager();
500 EXPECT_EQ(RefRange.file(), SM.getMainFileID());
502 EXPECT_EQ(
halfOpenToRange(SM, RefRange.toCharRange(SM)), MainFile.range());
505TEST(IncludeCleaner, MissingIncludesAreUnique) {
513 TU.AdditionalFiles[
"all.h"] = guard(R
"cpp(
515 #define FOO(X) X y; X z
518 TU.Code = MainFile.code();
522 EXPECT_THAT(Findings, testing::SizeIs(1));
523 auto RefRange = Findings.front().SymRefRange;
524 auto &SM =
AST.getSourceManager();
525 EXPECT_EQ(RefRange.file(), SM.getMainFileID());
526 EXPECT_EQ(
halfOpenToRange(SM, RefRange.toCharRange(SM)), MainFile.range());
529TEST(IncludeCleaner, NoHangOnRefExpandedInsidePreamblePatchInclude) {
530 llvm::StringLiteral Baseline = R
"cpp(// comment
537#include [["rettype.inc"]]
543 TU.AdditionalFiles[
"all.h"] = guard(
"#include \"foo.h\"");
544 TU.AdditionalFiles[
"rettype.inc"] =
"RET\n";
546 TU.Code = Baseline.str();
547 auto BaselinePreamble = TU.preamble();
548 ASSERT_TRUE(BaselinePreamble);
552 TU.Code = Modified.code().str();
556 std::move(CI), {}, std::move(BaselinePreamble));
559 ASSERT_THAT(Findings, testing::SizeIs(1));
560 auto RefRange = Findings.front().SymRefRange;
561 const auto &SM =
AST->getSourceManager();
562 EXPECT_EQ(RefRange.file(), SM.getMainFileID());
563 EXPECT_EQ(
halfOpenToRange(SM, RefRange.toCharRange(SM)), Modified.range());
566TEST(IncludeCleaner, NoCrash) {
574 TU.Code = MainCode.code();
575 TU.AdditionalFiles["foo.h"] =
576 guard(
"int operator\"\"s(unsigned long long) { return 0; }");
577 TU.AdditionalFiles[
"all.h"] = guard(
"#include \"foo.h\"");
579 const auto &MissingIncludes =
581 EXPECT_THAT(MissingIncludes, testing::SizeIs(1));
582 auto &SM =
AST.getSourceManager();
584 halfOpenToRange(SM, MissingIncludes.front().SymRefRange.toCharRange(SM)),
588TEST(IncludeCleaner, IsPreferredProvider) {
594 TU.AdditionalFiles["decl.h"] =
"";
595 TU.AdditionalFiles[
"def.h"] =
"";
597 auto AST = TU.build();
598 auto &IncludeDecl =
AST.getIncludeStructure().MainFileIncludes[0];
599 auto &IncludeDef1 =
AST.getIncludeStructure().MainFileIncludes[1];
600 auto &IncludeDef2 =
AST.getIncludeStructure().MainFileIncludes[2];
602 auto &FM =
AST.getSourceManager().getFileManager();
603 auto DeclH = *FM.getOptionalFileRef(
"decl.h");
604 auto DefH = *FM.getOptionalFileRef(
"def.h");
607 std::vector<include_cleaner::Header> Providers = {
608 include_cleaner::Header(DefH), include_cleaner::Header(DeclH)};
614TEST(IncludeCleaner, BatchFix) {
617 TU.AdditionalFiles[
"foo.h"] = guard(
"class Foo;");
618 TU.AdditionalFiles[
"bar.h"] = guard(
"class Bar;");
619 TU.AdditionalFiles[
"all.h"] = guard(R
"cpp(
629 auto AST = TU.build();
633 UnorderedElementsAre(withFix({FixMessage(
"#include \"foo.h\""),
634 FixMessage(
"fix all includes")}),
635 withFix({FixMessage(
"remove #include directive"),
636 FixMessage(
"fix all includes")})));
648 UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
649 FixMessage(
"fix all includes")}),
650 withFix({FixMessage(
"remove #include directive"),
651 FixMessage(
"remove all unused includes"),
652 FixMessage(
"fix all includes")}),
653 withFix({FixMessage(
"remove #include directive"),
654 FixMessage(
"remove all unused includes"),
655 FixMessage(
"fix all includes")})));
667 UnorderedElementsAre(withFix({FixMessage("#include \"foo.h\""),
668 FixMessage(
"add all missing includes"),
669 FixMessage(
"fix all includes")}),
670 withFix({FixMessage(
"#include \"bar.h\""),
671 FixMessage(
"add all missing includes"),
672 FixMessage(
"fix all includes")}),
673 withFix({FixMessage(
"remove #include directive"),
674 FixMessage(
"fix all includes")})));
679TEST(IncludeCleaner, VerbatimEquivalence) {
681 #include "lib/rel/public.h"
684 TU.AdditionalFiles["repo/lib/rel/private.h"] = R
"cpp(
686 // IWYU pragma: private, include "rel/public.h"
689 TU.AdditionalFiles["repo/lib/rel/public.h"] = R
"cpp(
691 #include "rel/private.h"
694 TU.ExtraArgs.push_back("-Irepo");
695 TU.ExtraArgs.push_back(
"-Irepo/lib");
697 auto AST = TU.build();
699 EXPECT_THAT(Findings.MissingIncludes, IsEmpty());
700 EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
703TEST(IncludeCleaner, ResourceDirIsIgnored) {
705 #include <amintrin.h>
706 #include <imintrin.h>
711 TU.ExtraArgs.push_back("-resource-dir");
712 TU.ExtraArgs.push_back(
testPath(
"resources"));
713 TU.AdditionalFiles[
"resources/include/amintrin.h"] = guard(
"");
714 TU.AdditionalFiles[
"resources/include/imintrin.h"] = guard(R
"cpp(
715 #include <emintrin.h>
717 TU.AdditionalFiles["resources/include/emintrin.h"] = guard(R
"cpp(
720 auto AST = TU.build();
722 EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
723 EXPECT_THAT(Findings.MissingIncludes, IsEmpty());
726TEST(IncludeCleaner, DifferentHeaderSameSpelling) {
736 TU.AdditionalFiles["foo/foo.h"] = guard(
"#include_next <foo.h>");
737 TU.AdditionalFiles[
"foo_inner/foo.h"] = guard(R
"cpp(
740 TU.ExtraArgs.push_back("-Ifoo");
741 TU.ExtraArgs.push_back(
"-Ifoo_inner");
743 auto AST = TU.build();
745 EXPECT_THAT(Findings.UnusedIncludes, IsEmpty());
746 EXPECT_THAT(Findings.MissingIncludes, IsEmpty());
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
Include Cleaner is clangd functionality for providing diagnostics for misuse of transitive headers an...
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Stores and provides access to parsed AST.
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.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
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.
MATCHER_P2(hasFlag, Flag, Path, "")
include_cleaner::Includes convertIncludes(const ParsedAST &AST)
Converts the clangd include representation to include-cleaner include representation.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
TEST(BackgroundQueueTest, Priority)
bool isPreferredProvider(const Inclusion &Inc, const include_cleaner::Includes &Includes, llvm::ArrayRef< include_cleaner::Header > Providers)
Whether this include is considered to provide a particular symbol.
IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST, bool AnalyzeAngledIncludes)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
std::vector< Diag > issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code, const IncludeCleanerFindings &Findings, const ThreadsafeFS &TFS, HeaderFilter IgnoreHeaders, HeaderFilter AngledHeaders, HeaderFilter QuotedHeaders)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A top-level diagnostic that may have Notes and Fixes.
std::vector< Fix > Fixes
Alternative fixes for this diagnostic, one should be chosen.
Represents a single fix-it that editor can apply to fix the error.
std::vector< MissingIncludeDiagInfo > MissingIncludes
Position start
The range's start position.
Position end
The range's end position.
static TestTU withCode(llvm::StringRef Code)
llvm::StringMap< std::string > AdditionalFiles