xref: /llvm-project/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp (revision 9e65dcac660723a06039c7e9b30f305b9b8ca652)
1 //===--- DiagnosticsTests.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 //===----------------------------------------------------------------------===//
8 
9 #include "../clang-tidy/ClangTidyOptions.h"
10 #include "Annotations.h"
11 #include "Config.h"
12 #include "Diagnostics.h"
13 #include "Feature.h"
14 #include "FeatureModule.h"
15 #include "ParsedAST.h"
16 #include "Protocol.h"
17 #include "TestFS.h"
18 #include "TestIndex.h"
19 #include "TestTU.h"
20 #include "TidyProvider.h"
21 #include "index/MemIndex.h"
22 #include "index/Ref.h"
23 #include "index/Relation.h"
24 #include "index/Symbol.h"
25 #include "support/Context.h"
26 #include "support/Path.h"
27 #include "clang/AST/Decl.h"
28 #include "clang/Basic/Diagnostic.h"
29 #include "clang/Basic/DiagnosticSema.h"
30 #include "clang/Basic/LLVM.h"
31 #include "clang/Basic/Specifiers.h"
32 #include "llvm/ADT/ArrayRef.h"
33 #include "llvm/ADT/StringRef.h"
34 #include "llvm/Support/JSON.h"
35 #include "llvm/Support/ScopedPrinter.h"
36 #include "llvm/Support/TargetSelect.h"
37 #include "llvm/Testing/Support/SupportHelpers.h"
38 #include "gmock/gmock.h"
39 #include "gtest/gtest.h"
40 #include <cstddef>
41 #include <memory>
42 #include <optional>
43 #include <string>
44 #include <utility>
45 #include <vector>
46 
47 namespace clang {
48 namespace clangd {
49 namespace {
50 
51 using ::testing::_;
52 using ::testing::AllOf;
53 using ::testing::Contains;
54 using ::testing::Each;
55 using ::testing::ElementsAre;
56 using ::testing::Field;
57 using ::testing::IsEmpty;
58 using ::testing::Not;
59 using ::testing::Pair;
60 using ::testing::SizeIs;
61 using ::testing::UnorderedElementsAre;
62 
63 ::testing::Matcher<const Diag &> withFix(::testing::Matcher<Fix> FixMatcher) {
64   return Field(&Diag::Fixes, ElementsAre(FixMatcher));
65 }
66 
67 ::testing::Matcher<const Diag &> withFix(::testing::Matcher<Fix> FixMatcher1,
68                                          ::testing::Matcher<Fix> FixMatcher2) {
69   return Field(&Diag::Fixes, UnorderedElementsAre(FixMatcher1, FixMatcher2));
70 }
71 
72 ::testing::Matcher<const Diag &> withID(unsigned ID) {
73   return Field(&Diag::ID, ID);
74 }
75 ::testing::Matcher<const Diag &>
76 withNote(::testing::Matcher<Note> NoteMatcher) {
77   return Field(&Diag::Notes, ElementsAre(NoteMatcher));
78 }
79 
80 ::testing::Matcher<const Diag &>
81 withNote(::testing::Matcher<Note> NoteMatcher1,
82          ::testing::Matcher<Note> NoteMatcher2) {
83   return Field(&Diag::Notes, UnorderedElementsAre(NoteMatcher1, NoteMatcher2));
84 }
85 
86 ::testing::Matcher<const Diag &>
87 withTag(::testing::Matcher<DiagnosticTag> TagMatcher) {
88   return Field(&Diag::Tags, Contains(TagMatcher));
89 }
90 
91 MATCHER_P(hasRange, Range, "") { return arg.Range == Range; }
92 
93 MATCHER_P2(Diag, Range, Message,
94            "Diag at " + llvm::to_string(Range) + " = [" + Message + "]") {
95   return arg.Range == Range && arg.Message == Message;
96 }
97 
98 MATCHER_P3(Fix, Range, Replacement, Message,
99            "Fix " + llvm::to_string(Range) + " => " +
100                ::testing::PrintToString(Replacement) + " = [" + Message + "]") {
101   return arg.Message == Message && arg.Edits.size() == 1 &&
102          arg.Edits[0].range == Range && arg.Edits[0].newText == Replacement;
103 }
104 
105 MATCHER_P(fixMessage, Message, "") { return arg.Message == Message; }
106 
107 MATCHER_P(equalToLSPDiag, LSPDiag,
108           "LSP diagnostic " + llvm::to_string(LSPDiag)) {
109   if (toJSON(arg) != toJSON(LSPDiag)) {
110     *result_listener << llvm::formatv("expected:\n{0:2}\ngot\n{1:2}",
111                                       toJSON(LSPDiag), toJSON(arg))
112                             .str();
113     return false;
114   }
115   return true;
116 }
117 
118 MATCHER_P(diagSource, S, "") { return arg.Source == S; }
119 MATCHER_P(diagName, N, "") { return arg.Name == N; }
120 MATCHER_P(diagSeverity, S, "") { return arg.Severity == S; }
121 
122 MATCHER_P(equalToFix, Fix, "LSP fix " + llvm::to_string(Fix)) {
123   if (arg.Message != Fix.Message)
124     return false;
125   if (arg.Edits.size() != Fix.Edits.size())
126     return false;
127   for (std::size_t I = 0; I < arg.Edits.size(); ++I) {
128     if (arg.Edits[I].range != Fix.Edits[I].range ||
129         arg.Edits[I].newText != Fix.Edits[I].newText)
130       return false;
131   }
132   return true;
133 }
134 
135 // Helper function to make tests shorter.
136 Position pos(int Line, int Character) {
137   Position Res;
138   Res.line = Line;
139   Res.character = Character;
140   return Res;
141 }
142 
143 // Normally returns the provided diagnostics matcher.
144 // If clang-tidy checks are not linked in, returns a matcher for no diagnostics!
145 // This is intended for tests where the diagnostics come from clang-tidy checks.
146 // We don't #ifdef each individual test as it's intrusive and we want to ensure
147 // that as much of the test is still compiled an run as possible.
148 ::testing::Matcher<std::vector<clangd::Diag>>
149 ifTidyChecks(::testing::Matcher<std::vector<clangd::Diag>> M) {
150   if (!CLANGD_TIDY_CHECKS)
151     return IsEmpty();
152   return M;
153 }
154 
155 TEST(DiagnosticsTest, DiagnosticRanges) {
156   // Check we report correct ranges, including various edge-cases.
157   Annotations Test(R"cpp(
158     // error-ok
159     #define ID(X) X
160     namespace test{};
161     void $decl[[foo]]();
162     int main() {
163       struct Container { int* begin(); int* end(); } *container;
164       for (auto i : $insertstar[[]]$range[[container]]) {
165       }
166 
167       $typo[[go\
168 o]]();
169       foo()$semicolon[[]]//with comments
170       $unk[[unknown]]();
171       double $type[[bar]] = "foo";
172       struct Foo { int x; }; Foo a;
173       a.$nomember[[y]];
174       test::$nomembernamespace[[test]];
175       $macro[[ID($macroarg[[fod]])]]();
176     }
177   )cpp");
178   auto TU = TestTU::withCode(Test.code());
179   EXPECT_THAT(
180       TU.build().getDiagnostics(),
181       ElementsAre(
182           // Make sure the whole token is highlighted.
183           AllOf(Diag(Test.range("range"),
184                      "invalid range expression of type 'struct Container *'; "
185                      "did you mean to dereference it with '*'?"),
186                 withFix(Fix(Test.range("insertstar"), "*", "insert '*'"))),
187           // This range spans lines.
188           AllOf(Diag(Test.range("typo"),
189                      "use of undeclared identifier 'goo'; did you mean 'foo'?"),
190                 diagSource(Diag::Clang), diagName("undeclared_var_use_suggest"),
191                 withFix(
192                     Fix(Test.range("typo"), "foo", "change 'go\\…' to 'foo'")),
193                 // This is a pretty normal range.
194                 withNote(Diag(Test.range("decl"), "'foo' declared here"))),
195           // This range is zero-width and insertion. Therefore make sure we are
196           // not expanding it into other tokens. Since we are not going to
197           // replace those.
198           AllOf(Diag(Test.range("semicolon"), "expected ';' after expression"),
199                 withFix(Fix(Test.range("semicolon"), ";", "insert ';'"))),
200           // This range isn't provided by clang, we expand to the token.
201           Diag(Test.range("unk"), "use of undeclared identifier 'unknown'"),
202           Diag(Test.range("type"),
203                "cannot initialize a variable of type 'double' with an lvalue "
204                "of type 'const char[4]'"),
205           Diag(Test.range("nomember"), "no member named 'y' in 'Foo'"),
206           Diag(Test.range("nomembernamespace"),
207                "no member named 'test' in namespace 'test'"),
208           AllOf(Diag(Test.range("macro"),
209                      "use of undeclared identifier 'fod'; did you mean 'foo'?"),
210                 withFix(Fix(Test.range("macroarg"), "foo",
211                             "change 'fod' to 'foo'")))));
212 }
213 
214 // Verify that the -Wswitch case-not-covered diagnostic range covers the
215 // whole expression. This is important because the "populate-switch" tweak
216 // fires for the full expression range (see tweaks/PopulateSwitchTests.cpp).
217 // The quickfix flow only works end-to-end if the tweak can be triggered on
218 // the diagnostic's range.
219 TEST(DiagnosticsTest, WSwitch) {
220   Annotations Test(R"cpp(
221     enum A { X };
222     struct B { A a; };
223     void foo(B b) {
224       switch ([[b.a]]) {}
225     }
226   )cpp");
227   auto TU = TestTU::withCode(Test.code());
228   TU.ExtraArgs = {"-Wswitch"};
229   EXPECT_THAT(TU.build().getDiagnostics(),
230               ElementsAre(Diag(Test.range(),
231                                "enumeration value 'X' not handled in switch")));
232 }
233 
234 TEST(DiagnosticsTest, FlagsMatter) {
235   Annotations Test("[[void]] main() {} // error-ok");
236   auto TU = TestTU::withCode(Test.code());
237   EXPECT_THAT(TU.build().getDiagnostics(),
238               ElementsAre(AllOf(Diag(Test.range(), "'main' must return 'int'"),
239                                 withFix(Fix(Test.range(), "int",
240                                             "change 'void' to 'int'")))));
241   // Same code built as C gets different diagnostics.
242   TU.Filename = "Plain.c";
243   EXPECT_THAT(
244       TU.build().getDiagnostics(),
245       ElementsAre(AllOf(
246           Diag(Test.range(), "return type of 'main' is not 'int'"),
247           withFix(Fix(Test.range(), "int", "change return type to 'int'")))));
248 }
249 
250 TEST(DiagnosticsTest, DiagnosticPreamble) {
251   Annotations Test(R"cpp(
252     #include $[["not-found.h"]] // error-ok
253   )cpp");
254 
255   auto TU = TestTU::withCode(Test.code());
256   EXPECT_THAT(TU.build().getDiagnostics(),
257               ElementsAre(::testing::AllOf(
258                   Diag(Test.range(), "'not-found.h' file not found"),
259                   diagSource(Diag::Clang), diagName("pp_file_not_found"))));
260 }
261 
262 TEST(DiagnosticsTest, DeduplicatedClangTidyDiagnostics) {
263   Annotations Test(R"cpp(
264     float foo = [[0.1f]];
265   )cpp");
266   auto TU = TestTU::withCode(Test.code());
267   // Enable alias clang-tidy checks, these check emits the same diagnostics
268   // (except the check name).
269   TU.ClangTidyProvider = addTidyChecks("readability-uppercase-literal-suffix,"
270                                        "hicpp-uppercase-literal-suffix");
271   // Verify that we filter out the duplicated diagnostic message.
272   EXPECT_THAT(
273       TU.build().getDiagnostics(),
274       ifTidyChecks(UnorderedElementsAre(::testing::AllOf(
275           Diag(Test.range(),
276                "floating point literal has suffix 'f', which is not uppercase"),
277           diagSource(Diag::ClangTidy)))));
278 
279   Test = Annotations(R"cpp(
280     template<typename T>
281     void func(T) {
282       float f = [[0.3f]];
283     }
284     void k() {
285       func(123);
286       func(2.0);
287     }
288   )cpp");
289   TU.Code = std::string(Test.code());
290   // The check doesn't handle template instantiations which ends up emitting
291   // duplicated messages, verify that we deduplicate them.
292   EXPECT_THAT(
293       TU.build().getDiagnostics(),
294       ifTidyChecks(UnorderedElementsAre(::testing::AllOf(
295           Diag(Test.range(),
296                "floating point literal has suffix 'f', which is not uppercase"),
297           diagSource(Diag::ClangTidy)))));
298 }
299 
300 TEST(DiagnosticsTest, ClangTidy) {
301   Annotations Test(R"cpp(
302     #include $deprecated[["assert.h"]]
303 
304     #define $macrodef[[SQUARE]](X) (X)*(X)
305     int $main[[main]]() {
306       int y = 4;
307       return SQUARE($macroarg[[++]]y);
308       return $doubled[[sizeof(sizeof(int))]];
309     }
310 
311     // misc-no-recursion uses a custom traversal from the TUDecl
312     void foo();
313     void $bar[[bar]]() {
314       foo();
315     }
316     void $foo[[foo]]() {
317       bar();
318     }
319   )cpp");
320   auto TU = TestTU::withCode(Test.code());
321   TU.HeaderFilename = "assert.h"; // Suppress "not found" error.
322   TU.ClangTidyProvider = addTidyChecks("bugprone-sizeof-expression,"
323                                        "bugprone-macro-repeated-side-effects,"
324                                        "modernize-deprecated-headers,"
325                                        "modernize-use-trailing-return-type,"
326                                        "misc-no-recursion");
327   TU.ExtraArgs.push_back("-Wno-unsequenced");
328   EXPECT_THAT(
329       TU.build().getDiagnostics(),
330       ifTidyChecks(UnorderedElementsAre(
331           AllOf(Diag(Test.range("deprecated"),
332                      "inclusion of deprecated C++ header 'assert.h'; consider "
333                      "using 'cassert' instead"),
334                 diagSource(Diag::ClangTidy),
335                 diagName("modernize-deprecated-headers"),
336                 withFix(Fix(Test.range("deprecated"), "<cassert>",
337                             "change '\"assert.h\"' to '<cassert>'"))),
338           Diag(Test.range("doubled"),
339                "suspicious usage of 'sizeof(sizeof(...))'"),
340           AllOf(Diag(Test.range("macroarg"),
341                      "side effects in the 1st macro argument 'X' are "
342                      "repeated in "
343                      "macro expansion"),
344                 diagSource(Diag::ClangTidy),
345                 diagName("bugprone-macro-repeated-side-effects"),
346                 withNote(Diag(Test.range("macrodef"),
347                               "macro 'SQUARE' defined here"))),
348           AllOf(Diag(Test.range("main"),
349                      "use a trailing return type for this function"),
350                 diagSource(Diag::ClangTidy),
351                 diagName("modernize-use-trailing-return-type"),
352                 // Verify there's no "[check-name]" suffix in the message.
353                 withFix(fixMessage(
354                     "use a trailing return type for this function"))),
355           Diag(Test.range("foo"),
356                "function 'foo' is within a recursive call chain"),
357           Diag(Test.range("bar"),
358                "function 'bar' is within a recursive call chain"))));
359 }
360 
361 TEST(DiagnosticsTest, ClangTidyEOF) {
362   // clang-format off
363   Annotations Test(R"cpp(
364   [[#]]include <b.h>
365   #include "a.h")cpp");
366   // clang-format on
367   auto TU = TestTU::withCode(Test.code());
368   TU.ExtraArgs = {"-isystem."};
369   TU.AdditionalFiles["a.h"] = TU.AdditionalFiles["b.h"] = "";
370   TU.ClangTidyProvider = addTidyChecks("llvm-include-order");
371   EXPECT_THAT(
372       TU.build().getDiagnostics(),
373       ifTidyChecks(Contains(
374           AllOf(Diag(Test.range(), "#includes are not sorted properly"),
375                 diagSource(Diag::ClangTidy), diagName("llvm-include-order")))));
376 }
377 
378 TEST(DiagnosticTest, TemplatesInHeaders) {
379   // Diagnostics from templates defined in headers are placed at the expansion.
380   Annotations Main(R"cpp(
381     Derived<int> [[y]]; // error-ok
382   )cpp");
383   Annotations Header(R"cpp(
384     template <typename T>
385     struct Derived : [[T]] {};
386   )cpp");
387   TestTU TU = TestTU::withCode(Main.code());
388   TU.HeaderCode = Header.code().str();
389   EXPECT_THAT(
390       TU.build().getDiagnostics(),
391       ElementsAre(AllOf(
392           Diag(Main.range(), "in template: base specifier must name a class"),
393           withNote(Diag(Header.range(), "error occurred here"),
394                    Diag(Main.range(), "in instantiation of template class "
395                                       "'Derived<int>' requested here")))));
396 }
397 
398 TEST(DiagnosticTest, MakeUnique) {
399   // We usually miss diagnostics from header functions as we don't parse them.
400   // std::make_unique is an exception.
401   Annotations Main(R"cpp(
402     struct S { S(char*); };
403     auto x = std::[[make_unique]]<S>(42); // error-ok
404   )cpp");
405   TestTU TU = TestTU::withCode(Main.code());
406   TU.HeaderCode = R"cpp(
407     namespace std {
408     // These mocks aren't quite right - we omit unique_ptr for simplicity.
409     // forward is included to show its body is not needed to get the diagnostic.
410     template <typename T> T&& forward(T& t);
411     template <typename T, typename... A> T* make_unique(A&&... args) {
412        return new T(std::forward<A>(args)...);
413     }
414     }
415   )cpp";
416   EXPECT_THAT(TU.build().getDiagnostics(),
417               UnorderedElementsAre(
418                   Diag(Main.range(),
419                        "in template: "
420                        "no matching constructor for initialization of 'S'")));
421 }
422 
423 TEST(DiagnosticTest, CoroutineInHeader) {
424   StringRef CoroutineH = R"cpp(
425 namespace std {
426 template <class Ret, typename... T>
427 struct coroutine_traits { using promise_type = typename Ret::promise_type; };
428 
429 template <class Promise = void>
430 struct coroutine_handle {
431   static coroutine_handle from_address(void *) noexcept;
432   static coroutine_handle from_promise(Promise &promise);
433   constexpr void* address() const noexcept;
434 };
435 template <>
436 struct coroutine_handle<void> {
437   template <class PromiseType>
438   coroutine_handle(coroutine_handle<PromiseType>) noexcept;
439   static coroutine_handle from_address(void *);
440   constexpr void* address() const noexcept;
441 };
442 
443 struct awaitable {
444   bool await_ready() noexcept { return false; }
445   void await_suspend(coroutine_handle<>) noexcept {}
446   void await_resume() noexcept {}
447 };
448 } // namespace std
449   )cpp";
450 
451   StringRef Header = R"cpp(
452 #include "coroutine.h"
453 template <typename T> struct [[clang::coro_return_type]] Gen {
454   struct promise_type {
455     Gen<T> get_return_object() {
456       return {};
457     }
458     std::awaitable  initial_suspend();
459     std::awaitable  final_suspend() noexcept;
460     void unhandled_exception();
461     void return_value(T t);
462   };
463 };
464 
465 Gen<int> foo_coro(int b) { co_return b; }
466   )cpp";
467   Annotations Main(R"cpp(
468 // error-ok
469 #include "header.hpp"
470 Gen<int> $[[bar_coro]](int b) { return foo_coro(b); }
471   )cpp");
472   TestTU TU = TestTU::withCode(Main.code());
473   TU.AdditionalFiles["coroutine.h"] = std::string(CoroutineH);
474   TU.AdditionalFiles["header.hpp"] = std::string(Header);
475   TU.ExtraArgs.push_back("--std=c++20");
476   EXPECT_THAT(TU.build().getDiagnostics(), ElementsAre(hasRange(Main.range())));
477 }
478 
479 TEST(DiagnosticTest, MakeShared) {
480   // We usually miss diagnostics from header functions as we don't parse them.
481   // std::make_shared is only parsed when --parse-forwarding-functions is set
482   Annotations Main(R"cpp(
483     struct S { S(char*); };
484     auto x = std::[[make_shared]]<S>(42); // error-ok
485   )cpp");
486   TestTU TU = TestTU::withCode(Main.code());
487   TU.HeaderCode = R"cpp(
488     namespace std {
489     // These mocks aren't quite right - we omit shared_ptr for simplicity.
490     // forward is included to show its body is not needed to get the diagnostic.
491     template <typename T> T&& forward(T& t);
492     template <typename T, typename... A> T* make_shared(A&&... args) {
493        return new T(std::forward<A>(args)...);
494     }
495     }
496   )cpp";
497   TU.ParseOpts.PreambleParseForwardingFunctions = true;
498   EXPECT_THAT(TU.build().getDiagnostics(),
499               UnorderedElementsAre(
500                   Diag(Main.range(),
501                        "in template: "
502                        "no matching constructor for initialization of 'S'")));
503 }
504 
505 TEST(DiagnosticTest, NoMultipleDiagnosticInFlight) {
506   Annotations Main(R"cpp(
507     template <typename T> struct Foo {
508       T *begin();
509       T *end();
510     };
511     struct LabelInfo {
512       int a;
513       bool b;
514     };
515 
516     void f() {
517       Foo<LabelInfo> label_info_map;
518       [[for]] (auto it = label_info_map.begin(); it != label_info_map.end(); ++it) {
519         auto S = *it;
520       }
521     }
522   )cpp");
523   TestTU TU = TestTU::withCode(Main.code());
524   TU.ClangTidyProvider = addTidyChecks("modernize-loop-convert");
525   EXPECT_THAT(
526       TU.build().getDiagnostics(),
527       ifTidyChecks(UnorderedElementsAre(::testing::AllOf(
528           Diag(Main.range(), "use range-based for loop instead"),
529           diagSource(Diag::ClangTidy), diagName("modernize-loop-convert")))));
530 }
531 
532 TEST(DiagnosticTest, RespectsDiagnosticConfig) {
533   Annotations Main(R"cpp(
534     // error-ok
535     void x() {
536       [[unknown]]();
537       $ret[[return]] 42;
538     }
539   )cpp");
540   auto TU = TestTU::withCode(Main.code());
541   EXPECT_THAT(
542       TU.build().getDiagnostics(),
543       ElementsAre(Diag(Main.range(), "use of undeclared identifier 'unknown'"),
544                   Diag(Main.range("ret"),
545                        "void function 'x' should not return a value")));
546   Config Cfg;
547   Cfg.Diagnostics.Suppress.insert("return-mismatch");
548   WithContextValue WithCfg(Config::Key, std::move(Cfg));
549   EXPECT_THAT(TU.build().getDiagnostics(),
550               ElementsAre(Diag(Main.range(),
551                                "use of undeclared identifier 'unknown'")));
552 }
553 
554 TEST(DiagnosticTest, RespectsDiagnosticConfigInHeader) {
555   Annotations Header(R"cpp(
556     int x = "42";  // error-ok
557   )cpp");
558   Annotations Main(R"cpp(
559     #include "header.hpp"
560   )cpp");
561   auto TU = TestTU::withCode(Main.code());
562   TU.AdditionalFiles["header.hpp"] = std::string(Header.code());
563   Config Cfg;
564   Cfg.Diagnostics.Suppress.insert("init_conversion_failed");
565   WithContextValue WithCfg(Config::Key, std::move(Cfg));
566   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
567 }
568 
569 TEST(DiagnosticTest, ClangTidySuppressionComment) {
570   Annotations Main(R"cpp(
571     int main() {
572       int i = 3;
573       double d = 8 / i;  // NOLINT
574       // NOLINTNEXTLINE
575       double e = 8 / i;
576       #define BAD 8 / i
577       double f = BAD;  // NOLINT
578       double g = [[8]] / i;
579       #define BAD2 BAD
580       double h = BAD2;  // NOLINT
581       // NOLINTBEGIN
582       double x = BAD2;
583       double y = BAD2;
584       // NOLINTEND
585 
586       // verify no crashes on unmatched nolints.
587       // NOLINTBEGIN
588     }
589   )cpp");
590   TestTU TU = TestTU::withCode(Main.code());
591   TU.ClangTidyProvider = addTidyChecks("bugprone-integer-division");
592   EXPECT_THAT(
593       TU.build().getDiagnostics(),
594       ifTidyChecks(UnorderedElementsAre(::testing::AllOf(
595           Diag(Main.range(), "result of integer division used in a floating "
596                              "point context; possible loss of precision"),
597           diagSource(Diag::ClangTidy),
598           diagName("bugprone-integer-division")))));
599 }
600 
601 TEST(DiagnosticTest, ClangTidySystemMacro) {
602   Annotations Main(R"cpp(
603     #include "user.h"
604     #include "system.h"
605     int i = 3;
606     double x = $inline[[8]] / i;
607     double y = $user[[DIVIDE_USER]](i);
608     double z = DIVIDE_SYS(i);
609   )cpp");
610 
611   auto TU = TestTU::withCode(Main.code());
612   TU.AdditionalFiles["user.h"] = R"cpp(
613     #define DIVIDE_USER(Y) 8/Y
614   )cpp";
615   TU.AdditionalFiles["system.h"] = R"cpp(
616     #pragma clang system_header
617     #define DIVIDE_SYS(Y) 8/Y
618   )cpp";
619 
620   TU.ClangTidyProvider = addTidyChecks("bugprone-integer-division");
621   std::string BadDivision = "result of integer division used in a floating "
622                             "point context; possible loss of precision";
623 
624   // Expect to see warning from user macros, but not system macros.
625   // This matches clang-tidy --system-headers=0 (the default).
626   EXPECT_THAT(TU.build().getDiagnostics(),
627               ifTidyChecks(
628                   UnorderedElementsAre(Diag(Main.range("inline"), BadDivision),
629                                        Diag(Main.range("user"), BadDivision))));
630 }
631 
632 TEST(DiagnosticTest, ClangTidyWarningAsError) {
633   Annotations Main(R"cpp(
634     int main() {
635       int i = 3;
636       double f = [[8]] / i; // error-ok
637     }
638   )cpp");
639   TestTU TU = TestTU::withCode(Main.code());
640   TU.ClangTidyProvider =
641       addTidyChecks("bugprone-integer-division", "bugprone-integer-division");
642   EXPECT_THAT(
643       TU.build().getDiagnostics(),
644       ifTidyChecks(UnorderedElementsAre(::testing::AllOf(
645           Diag(Main.range(), "result of integer division used in a floating "
646                              "point context; possible loss of precision"),
647           diagSource(Diag::ClangTidy), diagName("bugprone-integer-division"),
648           diagSeverity(DiagnosticsEngine::Error)))));
649 }
650 
651 TidyProvider addClangArgs(std::vector<llvm::StringRef> ExtraArgs,
652                           llvm::StringRef Checks) {
653   return [ExtraArgs = std::move(ExtraArgs), Checks = Checks.str()](
654              tidy::ClangTidyOptions &Opts, llvm::StringRef) {
655     if (!Opts.ExtraArgs)
656       Opts.ExtraArgs.emplace();
657     for (llvm::StringRef Arg : ExtraArgs)
658       Opts.ExtraArgs->emplace_back(Arg);
659     if (!Checks.empty())
660       Opts.Checks = Checks;
661   };
662 }
663 
664 TEST(DiagnosticTest, ClangTidyEnablesClangWarning) {
665   Annotations Main(R"cpp( // error-ok
666     static void [[foo]]() {}
667   )cpp");
668   TestTU TU = TestTU::withCode(Main.code());
669   // This is always emitted as a clang warning, not a clang-tidy diagnostic.
670   auto UnusedFooWarning =
671       AllOf(Diag(Main.range(), "unused function 'foo'"),
672             diagName("-Wunused-function"), diagSource(Diag::Clang),
673             diagSeverity(DiagnosticsEngine::Warning));
674 
675   // Check the -Wunused warning isn't initially on.
676   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
677 
678   // We enable warnings based on clang-tidy extra args, if the matching
679   // clang-diagnostic- is there.
680   TU.ClangTidyProvider =
681       addClangArgs({"-Wunused"}, "clang-diagnostic-unused-function");
682   EXPECT_THAT(TU.build().getDiagnostics(), ElementsAre(UnusedFooWarning));
683 
684   // clang-diagnostic-* is acceptable
685   TU.ClangTidyProvider = addClangArgs({"-Wunused"}, "clang-diagnostic-*");
686   EXPECT_THAT(TU.build().getDiagnostics(), ElementsAre(UnusedFooWarning));
687   // And plain * (may turn on other checks too).
688   TU.ClangTidyProvider = addClangArgs({"-Wunused"}, "*");
689   EXPECT_THAT(TU.build().getDiagnostics(), Contains(UnusedFooWarning));
690   // And we can explicitly exclude a category too.
691   TU.ClangTidyProvider = addClangArgs(
692       {"-Wunused"}, "clang-diagnostic-*,-clang-diagnostic-unused-function");
693   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
694 
695   // Without the exact check specified, the warnings are not enabled.
696   TU.ClangTidyProvider = addClangArgs({"-Wunused"}, "clang-diagnostic-unused");
697   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
698 
699   // We don't respect other args.
700   TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Dfoo=bar"},
701                                       "clang-diagnostic-unused-function");
702   EXPECT_THAT(TU.build().getDiagnostics(), ElementsAre(UnusedFooWarning))
703       << "Not unused function 'bar'!";
704 
705   // -Werror doesn't apply to warnings enabled by clang-tidy extra args.
706   TU.ExtraArgs = {"-Werror"};
707   TU.ClangTidyProvider =
708       addClangArgs({"-Wunused"}, "clang-diagnostic-unused-function");
709   EXPECT_THAT(TU.build().getDiagnostics(),
710               ElementsAre(diagSeverity(DiagnosticsEngine::Warning)));
711 
712   // But clang-tidy extra args won't *downgrade* errors to warnings either.
713   TU.ExtraArgs = {"-Wunused", "-Werror"};
714   TU.ClangTidyProvider =
715       addClangArgs({"-Wunused"}, "clang-diagnostic-unused-function");
716   EXPECT_THAT(TU.build().getDiagnostics(),
717               ElementsAre(diagSeverity(DiagnosticsEngine::Error)));
718 
719   // FIXME: we're erroneously downgrading the whole group, this should be Error.
720   TU.ExtraArgs = {"-Wunused-function", "-Werror"};
721   TU.ClangTidyProvider =
722       addClangArgs({"-Wunused"}, "clang-diagnostic-unused-label");
723   EXPECT_THAT(TU.build().getDiagnostics(),
724               ElementsAre(diagSeverity(DiagnosticsEngine::Warning)));
725 
726   // This looks silly, but it's the typical result if a warning is enabled by a
727   // high-level .clang-tidy file and disabled by a low-level one.
728   TU.ExtraArgs = {};
729   TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Wno-unused"},
730                                       "clang-diagnostic-unused-function");
731   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
732 
733   // Overriding only works in the proper order.
734   TU.ClangTidyProvider =
735       addClangArgs({"-Wunused"}, {"clang-diagnostic-unused-function"});
736   EXPECT_THAT(TU.build().getDiagnostics(), SizeIs(1));
737 
738   // More specific vs less-specific: match clang behavior
739   TU.ClangTidyProvider = addClangArgs({"-Wunused", "-Wno-unused-function"},
740                                       {"clang-diagnostic-unused-function"});
741   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
742   TU.ClangTidyProvider = addClangArgs({"-Wunused-function", "-Wno-unused"},
743                                       {"clang-diagnostic-unused-function"});
744   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
745 
746   // We do allow clang-tidy config to disable warnings from the compile
747   // command. It's unclear this is ideal, but it's hard to avoid.
748   TU.ExtraArgs = {"-Wunused"};
749   TU.ClangTidyProvider = addClangArgs({"-Wno-unused"}, {});
750   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
751 
752   TU.ExtraArgs = {"-Wno-unused"};
753   TU.ClangTidyProvider = addClangArgs({"-Wunused"}, {"-*, clang-diagnostic-*"});
754   EXPECT_THAT(TU.build().getDiagnostics(), SizeIs(1));
755 }
756 
757 TEST(DiagnosticTest, LongFixMessages) {
758   // We limit the size of printed code.
759   Annotations Source(R"cpp(
760     int main() {
761       // error-ok
762       int somereallyreallyreallyreallyreallyreallyreallyreallylongidentifier;
763       [[omereallyreallyreallyreallyreallyreallyreallyreallylongidentifier]]= 10;
764     }
765   )cpp");
766   TestTU TU = TestTU::withCode(Source.code());
767   EXPECT_THAT(
768       TU.build().getDiagnostics(),
769       ElementsAre(withFix(Fix(
770           Source.range(),
771           "somereallyreallyreallyreallyreallyreallyreallyreallylongidentifier",
772           "change 'omereallyreallyreallyreallyreallyreallyreallyreall…' to "
773           "'somereallyreallyreallyreallyreallyreallyreallyreal…'"))));
774   // Only show changes up to a first newline.
775   Source = Annotations(R"cpp(
776     // error-ok
777     int main() {
778       int ident;
779       [[ide\
780 n]] = 10; // error-ok
781     }
782   )cpp");
783   TU.Code = std::string(Source.code());
784   EXPECT_THAT(TU.build().getDiagnostics(),
785               ElementsAre(withFix(
786                   Fix(Source.range(), "ident", "change 'ide\\…' to 'ident'"))));
787 }
788 
789 TEST(DiagnosticTest, NewLineFixMessage) {
790   Annotations Source("int a;[[]]");
791   TestTU TU = TestTU::withCode(Source.code());
792   TU.ExtraArgs = {"-Wnewline-eof"};
793   EXPECT_THAT(
794       TU.build().getDiagnostics(),
795       ElementsAre(withFix((Fix(Source.range(), "\n", "insert '\\n'")))));
796 }
797 
798 TEST(DiagnosticTest, ClangTidySuppressionCommentTrumpsWarningAsError) {
799   Annotations Main(R"cpp(
800     int main() {
801       int i = 3;
802       double f = [[8]] / i;  // NOLINT
803     }
804   )cpp");
805   TestTU TU = TestTU::withCode(Main.code());
806   TU.ClangTidyProvider =
807       addTidyChecks("bugprone-integer-division", "bugprone-integer-division");
808   EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre());
809 }
810 
811 TEST(DiagnosticTest, ClangTidyNoLiteralDataInMacroToken) {
812   Annotations Main(R"cpp(
813     #define SIGTERM 15
814     using pthread_t = int;
815     int pthread_kill(pthread_t thread, int sig);
816     int func() {
817       pthread_t thread;
818       return pthread_kill(thread, 0);
819     }
820   )cpp");
821   TestTU TU = TestTU::withCode(Main.code());
822   TU.ClangTidyProvider = addTidyChecks("bugprone-bad-signal-to-kill-thread");
823   EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre()); // no-crash
824 }
825 
826 TEST(DiagnosticTest, ElseAfterReturnRange) {
827   Annotations Main(R"cpp(
828     int foo(int cond) {
829     if (cond == 1) {
830       return 42;
831     } [[else]] if (cond == 2) {
832       return 43;
833     }
834     return 44;
835     }
836   )cpp");
837   TestTU TU = TestTU::withCode(Main.code());
838   TU.ClangTidyProvider = addTidyChecks("llvm-else-after-return");
839   EXPECT_THAT(TU.build().getDiagnostics(),
840               ifTidyChecks(ElementsAre(
841                   Diag(Main.range(), "do not use 'else' after 'return'"))));
842 }
843 
844 TEST(DiagnosticTest, ClangTidySelfContainedDiags) {
845   Annotations Main(R"cpp($MathHeader[[]]
846     struct Foo{
847       int A, B;
848       Foo()$Fix[[]] {
849         $A[[A = 1;]]
850         $B[[B = 1;]]
851       }
852     };
853     void InitVariables() {
854       float $C[[C]]$CFix[[]];
855       double $D[[D]]$DFix[[]];
856     }
857   )cpp");
858   TestTU TU = TestTU::withCode(Main.code());
859   TU.ClangTidyProvider =
860       addTidyChecks("cppcoreguidelines-prefer-member-initializer,"
861                     "cppcoreguidelines-init-variables");
862   clangd::Fix ExpectedAFix;
863   ExpectedAFix.Message =
864       "'A' should be initialized in a member initializer of the constructor";
865   ExpectedAFix.Edits.push_back(TextEdit{Main.range("Fix"), " : A(1)"});
866   ExpectedAFix.Edits.push_back(TextEdit{Main.range("A"), ""});
867 
868   // When invoking clang-tidy normally, this code would produce `, B(1)` as the
869   // fix the `B` member, as it would think its already included the ` : ` from
870   // the previous `A` fix.
871   clangd::Fix ExpectedBFix;
872   ExpectedBFix.Message =
873       "'B' should be initialized in a member initializer of the constructor";
874   ExpectedBFix.Edits.push_back(TextEdit{Main.range("Fix"), " : B(1)"});
875   ExpectedBFix.Edits.push_back(TextEdit{Main.range("B"), ""});
876 
877   clangd::Fix ExpectedCFix;
878   ExpectedCFix.Message = "variable 'C' is not initialized";
879   ExpectedCFix.Edits.push_back(TextEdit{Main.range("CFix"), " = NAN"});
880   ExpectedCFix.Edits.push_back(
881       TextEdit{Main.range("MathHeader"), "#include <math.h>\n\n"});
882 
883   // Again in clang-tidy only the include directive would be emitted for the
884   // first warning. However we need the include attaching for both warnings.
885   clangd::Fix ExpectedDFix;
886   ExpectedDFix.Message = "variable 'D' is not initialized";
887   ExpectedDFix.Edits.push_back(TextEdit{Main.range("DFix"), " = NAN"});
888   ExpectedDFix.Edits.push_back(
889       TextEdit{Main.range("MathHeader"), "#include <math.h>\n\n"});
890   EXPECT_THAT(
891       TU.build().getDiagnostics(),
892       ifTidyChecks(UnorderedElementsAre(
893           AllOf(Diag(Main.range("A"), "'A' should be initialized in a member "
894                                       "initializer of the constructor"),
895                 withFix(equalToFix(ExpectedAFix))),
896           AllOf(Diag(Main.range("B"), "'B' should be initialized in a member "
897                                       "initializer of the constructor"),
898                 withFix(equalToFix(ExpectedBFix))),
899           AllOf(Diag(Main.range("C"), "variable 'C' is not initialized"),
900                 withFix(equalToFix(ExpectedCFix))),
901           AllOf(Diag(Main.range("D"), "variable 'D' is not initialized"),
902                 withFix(equalToFix(ExpectedDFix))))));
903 }
904 
905 TEST(DiagnosticTest, ClangTidySelfContainedDiagsFormatting) {
906   Annotations Main(R"cpp(
907     class Interface {
908     public:
909       virtual void Reset1() = 0;
910       virtual void Reset2() = 0;
911     };
912     class A : public Interface {
913       // This will be marked by clangd to use override instead of virtual
914       $virtual1[[virtual    ]]void $Reset1[[Reset1]]()$override1[[]];
915       $virtual2[[virtual      ]]/**/void $Reset2[[Reset2]]()$override2[[]];
916     };
917   )cpp");
918   TestTU TU = TestTU::withCode(Main.code());
919   TU.ClangTidyProvider =
920       addTidyChecks("cppcoreguidelines-explicit-virtual-functions,");
921   clangd::Fix const ExpectedFix1{
922       "prefer using 'override' or (rarely) 'final' "
923       "instead of 'virtual'",
924       {TextEdit{Main.range("override1"), " override"},
925        TextEdit{Main.range("virtual1"), ""}},
926       {}};
927   clangd::Fix const ExpectedFix2{
928       "prefer using 'override' or (rarely) 'final' "
929       "instead of 'virtual'",
930       {TextEdit{Main.range("override2"), " override"},
931        TextEdit{Main.range("virtual2"), ""}},
932       {}};
933   // Note that in the Fix we expect the "virtual" keyword and the following
934   // whitespace to be deleted
935   EXPECT_THAT(TU.build().getDiagnostics(),
936               ifTidyChecks(UnorderedElementsAre(
937                   AllOf(Diag(Main.range("Reset1"),
938                              "prefer using 'override' or (rarely) 'final' "
939                              "instead of 'virtual'"),
940                         withFix(equalToFix(ExpectedFix1))),
941                   AllOf(Diag(Main.range("Reset2"),
942                              "prefer using 'override' or (rarely) 'final' "
943                              "instead of 'virtual'"),
944                         withFix(equalToFix(ExpectedFix2))))));
945 }
946 
947 TEST(DiagnosticsTest, ClangTidyCallingIntoPreprocessor) {
948   std::string Main = R"cpp(
949     extern "C" {
950     #include "b.h"
951     }
952   )cpp";
953   std::string Header = R"cpp(
954     #define EXTERN extern
955     EXTERN int waldo();
956   )cpp";
957   auto TU = TestTU::withCode(Main);
958   TU.AdditionalFiles["b.h"] = Header;
959   TU.ClangTidyProvider = addTidyChecks("modernize-use-trailing-return-type");
960   // Check that no assertion failures occur during the build
961   TU.build();
962 }
963 
964 TEST(DiagnosticsTest, Preprocessor) {
965   // This looks like a preamble, but there's an #else in the middle!
966   // Check that:
967   //  - the #else doesn't generate diagnostics (we had this bug)
968   //  - we get diagnostics from the taken branch
969   //  - we get no diagnostics from the not taken branch
970   Annotations Test(R"cpp(
971     #ifndef FOO
972     #define FOO
973       int a = [[b]]; // error-ok
974     #else
975       int x = y;
976     #endif
977     )cpp");
978   EXPECT_THAT(
979       TestTU::withCode(Test.code()).build().getDiagnostics(),
980       ElementsAre(Diag(Test.range(), "use of undeclared identifier 'b'")));
981 }
982 
983 TEST(DiagnosticsTest, IgnoreVerify) {
984   auto TU = TestTU::withCode(R"cpp(
985     int a; // expected-error {{}}
986   )cpp");
987   TU.ExtraArgs.push_back("-Xclang");
988   TU.ExtraArgs.push_back("-verify");
989   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
990 }
991 
992 TEST(DiagnosticTest, IgnoreBEFilelistOptions) {
993   auto TU = TestTU::withCode("");
994   TU.ExtraArgs.push_back("-Xclang");
995   for (const auto *DisableOption :
996        {"-fsanitize-ignorelist=null", "-fprofile-list=null",
997         "-fxray-always-instrument=null", "-fxray-never-instrument=null",
998         "-fxray-attr-list=null"}) {
999     TU.ExtraArgs.push_back(DisableOption);
1000     EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
1001     TU.ExtraArgs.pop_back();
1002   }
1003 }
1004 
1005 // Recursive main-file include is diagnosed, and doesn't crash.
1006 TEST(DiagnosticsTest, RecursivePreamble) {
1007   auto TU = TestTU::withCode(R"cpp(
1008     #include "foo.h" // error-ok
1009     int symbol;
1010   )cpp");
1011   TU.Filename = "foo.h";
1012   EXPECT_THAT(TU.build().getDiagnostics(),
1013               ElementsAre(diagName("pp_including_mainfile_in_preamble")));
1014   EXPECT_THAT(TU.build().getLocalTopLevelDecls(), SizeIs(1));
1015 }
1016 
1017 // Recursive main-file include with #pragma once guard is OK.
1018 TEST(DiagnosticsTest, RecursivePreamblePragmaOnce) {
1019   auto TU = TestTU::withCode(R"cpp(
1020     #pragma once
1021     #include "foo.h"
1022     int symbol;
1023   )cpp");
1024   TU.Filename = "foo.h";
1025   EXPECT_THAT(TU.build().getDiagnostics(),
1026               Not(Contains(diagName("pp_including_mainfile_in_preamble"))));
1027   EXPECT_THAT(TU.build().getLocalTopLevelDecls(), SizeIs(1));
1028 }
1029 
1030 // Recursive main-file include with #ifndef guard should be OK.
1031 // However, it's not yet recognized (incomplete at end of preamble).
1032 TEST(DiagnosticsTest, RecursivePreambleIfndefGuard) {
1033   auto TU = TestTU::withCode(R"cpp(
1034     #ifndef FOO
1035     #define FOO
1036     #include "foo.h" // error-ok
1037     int symbol;
1038     #endif
1039   )cpp");
1040   TU.Filename = "foo.h";
1041   // FIXME: should be no errors here.
1042   EXPECT_THAT(TU.build().getDiagnostics(),
1043               ElementsAre(diagName("pp_including_mainfile_in_preamble")));
1044   EXPECT_THAT(TU.build().getLocalTopLevelDecls(), SizeIs(1));
1045 }
1046 
1047 TEST(DiagnosticsTest, PreambleWithPragmaAssumeNonnull) {
1048   auto TU = TestTU::withCode(R"cpp(
1049 #pragma clang assume_nonnull begin
1050 void foo(int *x);
1051 #pragma clang assume_nonnull end
1052 )cpp");
1053   auto AST = TU.build();
1054   EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
1055   const auto *X = cast<FunctionDecl>(findDecl(AST, "foo")).getParamDecl(0);
1056   ASSERT_TRUE(X->getOriginalType()->getNullability() ==
1057               NullabilityKind::NonNull);
1058 }
1059 
1060 TEST(DiagnosticsTest, PreambleHeaderWithBadPragmaAssumeNonnull) {
1061   Annotations Header(R"cpp(
1062 #pragma clang assume_nonnull begin  // error-ok
1063 void foo(int *X);
1064 )cpp");
1065   auto TU = TestTU::withCode(R"cpp(
1066 #include "foo.h"  // unterminated assume_nonnull should not affect bar.
1067 void bar(int *Y);
1068 )cpp");
1069   TU.AdditionalFiles = {{"foo.h", std::string(Header.code())}};
1070   auto AST = TU.build();
1071   EXPECT_THAT(AST.getDiagnostics(),
1072               ElementsAre(diagName("pp_eof_in_assume_nonnull")));
1073   const auto *X = cast<FunctionDecl>(findDecl(AST, "foo")).getParamDecl(0);
1074   ASSERT_TRUE(X->getOriginalType()->getNullability() ==
1075               NullabilityKind::NonNull);
1076   const auto *Y = cast<FunctionDecl>(findDecl(AST, "bar")).getParamDecl(0);
1077   ASSERT_FALSE(Y->getOriginalType()->getNullability());
1078 }
1079 
1080 TEST(DiagnosticsTest, InsideMacros) {
1081   Annotations Test(R"cpp(
1082     #define TEN 10
1083     #define RET(x) return x + 10
1084 
1085     int* foo() {
1086       RET($foo[[0]]); // error-ok
1087     }
1088     int* bar() {
1089       return $bar[[TEN]];
1090     }
1091     )cpp");
1092   EXPECT_THAT(TestTU::withCode(Test.code()).build().getDiagnostics(),
1093               ElementsAre(Diag(Test.range("foo"),
1094                                "cannot initialize return object of type "
1095                                "'int *' with an rvalue of type 'int'"),
1096                           Diag(Test.range("bar"),
1097                                "cannot initialize return object of type "
1098                                "'int *' with an rvalue of type 'int'")));
1099 }
1100 
1101 TEST(DiagnosticsTest, NoFixItInMacro) {
1102   Annotations Test(R"cpp(
1103     #define Define(name) void name() {}
1104 
1105     [[Define]](main) // error-ok
1106   )cpp");
1107   auto TU = TestTU::withCode(Test.code());
1108   EXPECT_THAT(TU.build().getDiagnostics(),
1109               ElementsAre(AllOf(Diag(Test.range(), "'main' must return 'int'"),
1110                                 Not(withFix(_)))));
1111 }
1112 
1113 TEST(DiagnosticsTest, PragmaSystemHeader) {
1114   Annotations Test("#pragma clang [[system_header]]\n");
1115   auto TU = TestTU::withCode(Test.code());
1116   EXPECT_THAT(
1117       TU.build().getDiagnostics(),
1118       ElementsAre(AllOf(
1119           Diag(Test.range(), "#pragma system_header ignored in main file"))));
1120   TU.Filename = "TestTU.h";
1121   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
1122 }
1123 
1124 TEST(ClangdTest, MSAsm) {
1125   // Parsing MS assembly tries to use the target MCAsmInfo, which we don't link.
1126   // We used to crash here. Now clang emits a diagnostic, which we filter out.
1127   llvm::InitializeAllTargetInfos(); // As in ClangdMain
1128   auto TU = TestTU::withCode("void fn() { __asm { cmp cl,64 } }");
1129   TU.ExtraArgs = {"-fms-extensions"};
1130   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
1131 }
1132 
1133 TEST(DiagnosticsTest, ToLSP) {
1134   URIForFile MainFile =
1135       URIForFile::canonicalize(testPath("foo/bar/main.cpp"), "");
1136   URIForFile HeaderFile =
1137       URIForFile::canonicalize(testPath("foo/bar/header.h"), "");
1138 
1139   clangd::Diag D;
1140   D.ID = clang::diag::err_undeclared_var_use;
1141   D.Tags = {DiagnosticTag::Unnecessary};
1142   D.Name = "undeclared_var_use";
1143   D.Source = clangd::Diag::Clang;
1144   D.Message = "something terrible happened";
1145   D.Range = {pos(1, 2), pos(3, 4)};
1146   D.InsideMainFile = true;
1147   D.Severity = DiagnosticsEngine::Error;
1148   D.File = "foo/bar/main.cpp";
1149   D.AbsFile = std::string(MainFile.file());
1150   D.OpaqueData["test"] = "bar";
1151 
1152   clangd::Note NoteInMain;
1153   NoteInMain.Message = "declared somewhere in the main file";
1154   NoteInMain.Range = {pos(5, 6), pos(7, 8)};
1155   NoteInMain.Severity = DiagnosticsEngine::Remark;
1156   NoteInMain.File = "../foo/bar/main.cpp";
1157   NoteInMain.InsideMainFile = true;
1158   NoteInMain.AbsFile = std::string(MainFile.file());
1159 
1160   D.Notes.push_back(NoteInMain);
1161 
1162   clangd::Note NoteInHeader;
1163   NoteInHeader.Message = "declared somewhere in the header file";
1164   NoteInHeader.Range = {pos(9, 10), pos(11, 12)};
1165   NoteInHeader.Severity = DiagnosticsEngine::Note;
1166   NoteInHeader.File = "../foo/baz/header.h";
1167   NoteInHeader.InsideMainFile = false;
1168   NoteInHeader.AbsFile = std::string(HeaderFile.file());
1169   D.Notes.push_back(NoteInHeader);
1170 
1171   clangd::Fix F;
1172   F.Message = "do something";
1173   D.Fixes.push_back(F);
1174 
1175   // Diagnostics should turn into these:
1176   clangd::Diagnostic MainLSP;
1177   MainLSP.range = D.Range;
1178   MainLSP.severity = getSeverity(DiagnosticsEngine::Error);
1179   MainLSP.code = "undeclared_var_use";
1180   MainLSP.source = "clang";
1181   MainLSP.message =
1182       R"(Something terrible happened (fix available)
1183 
1184 main.cpp:6:7: remark: declared somewhere in the main file
1185 
1186 ../foo/baz/header.h:10:11:
1187 note: declared somewhere in the header file)";
1188   MainLSP.tags = {DiagnosticTag::Unnecessary};
1189   MainLSP.data = D.OpaqueData;
1190 
1191   clangd::Diagnostic NoteInMainLSP;
1192   NoteInMainLSP.range = NoteInMain.Range;
1193   NoteInMainLSP.severity = getSeverity(DiagnosticsEngine::Remark);
1194   NoteInMainLSP.message = R"(Declared somewhere in the main file
1195 
1196 main.cpp:2:3: error: something terrible happened)";
1197 
1198   ClangdDiagnosticOptions Opts;
1199   // Transform diagnostics and check the results.
1200   std::vector<std::pair<clangd::Diagnostic, std::vector<clangd::Fix>>> LSPDiags;
1201   toLSPDiags(D, MainFile, Opts,
1202              [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix> Fixes) {
1203                LSPDiags.push_back(
1204                    {std::move(LSPDiag),
1205                     std::vector<clangd::Fix>(Fixes.begin(), Fixes.end())});
1206              });
1207 
1208   EXPECT_THAT(
1209       LSPDiags,
1210       ElementsAre(Pair(equalToLSPDiag(MainLSP), ElementsAre(equalToFix(F))),
1211                   Pair(equalToLSPDiag(NoteInMainLSP), IsEmpty())));
1212   EXPECT_EQ(LSPDiags[0].first.code, "undeclared_var_use");
1213   EXPECT_EQ(LSPDiags[0].first.source, "clang");
1214   EXPECT_EQ(LSPDiags[1].first.code, "");
1215   EXPECT_EQ(LSPDiags[1].first.source, "");
1216 
1217   // Same thing, but don't flatten notes into the main list.
1218   LSPDiags.clear();
1219   Opts.EmitRelatedLocations = true;
1220   toLSPDiags(D, MainFile, Opts,
1221              [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix> Fixes) {
1222                LSPDiags.push_back(
1223                    {std::move(LSPDiag),
1224                     std::vector<clangd::Fix>(Fixes.begin(), Fixes.end())});
1225              });
1226   MainLSP.message = "Something terrible happened (fix available)";
1227   DiagnosticRelatedInformation NoteInMainDRI;
1228   NoteInMainDRI.message = "Declared somewhere in the main file";
1229   NoteInMainDRI.location.range = NoteInMain.Range;
1230   NoteInMainDRI.location.uri = MainFile;
1231   MainLSP.relatedInformation = {NoteInMainDRI};
1232   DiagnosticRelatedInformation NoteInHeaderDRI;
1233   NoteInHeaderDRI.message = "Declared somewhere in the header file";
1234   NoteInHeaderDRI.location.range = NoteInHeader.Range;
1235   NoteInHeaderDRI.location.uri = HeaderFile;
1236   MainLSP.relatedInformation = {NoteInMainDRI, NoteInHeaderDRI};
1237   EXPECT_THAT(LSPDiags, ElementsAre(Pair(equalToLSPDiag(MainLSP),
1238                                          ElementsAre(equalToFix(F)))));
1239 }
1240 
1241 struct SymbolWithHeader {
1242   std::string QName;
1243   std::string DeclaringFile;
1244   std::string IncludeHeader;
1245 };
1246 
1247 std::unique_ptr<SymbolIndex>
1248 buildIndexWithSymbol(llvm::ArrayRef<SymbolWithHeader> Syms) {
1249   SymbolSlab::Builder Slab;
1250   for (const auto &S : Syms) {
1251     Symbol Sym = cls(S.QName);
1252     Sym.Flags |= Symbol::IndexedForCodeCompletion;
1253     Sym.CanonicalDeclaration.FileURI = S.DeclaringFile.c_str();
1254     Sym.Definition.FileURI = S.DeclaringFile.c_str();
1255     Sym.IncludeHeaders.emplace_back(S.IncludeHeader, 1, Symbol::Include);
1256     Slab.insert(Sym);
1257   }
1258   return MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab());
1259 }
1260 
1261 TEST(IncludeFixerTest, IncompleteType) {
1262   auto TU = TestTU::withHeaderCode("namespace ns { class X; } ns::X *x;");
1263   TU.ExtraArgs.push_back("-std=c++20");
1264   auto Index = buildIndexWithSymbol(
1265       {SymbolWithHeader{"ns::X", "unittest:///x.h", "\"x.h\""}});
1266   TU.ExternalIndex = Index.get();
1267 
1268   std::vector<std::pair<llvm::StringRef, llvm::StringRef>> Tests{
1269       {"incomplete_nested_name_spec", "[[ns::X::]]Nested n;"},
1270       {"incomplete_base_class", "class Y : [[ns::X]] {};"},
1271       {"incomplete_member_access", "auto i = x[[->]]f();"},
1272       {"incomplete_type", "auto& [[[]]m] = *x;"},
1273       {"init_incomplete_type",
1274        "struct C { static int f(ns::X&); }; int i = C::f([[{]]});"},
1275       {"bad_cast_incomplete", "auto a = [[static_cast]]<ns::X>(0);"},
1276       {"template_nontype_parm_incomplete", "template <ns::X [[foo]]> int a;"},
1277       {"typecheck_decl_incomplete_type", "ns::X [[var]];"},
1278       {"typecheck_incomplete_tag", "auto i = [[(*x)]]->f();"},
1279       {"typecheck_nonviable_condition_incomplete",
1280        "struct A { operator ns::X(); } a; const ns::X &[[b]] = a;"},
1281       {"invalid_incomplete_type_use", "auto var = [[ns::X()]];"},
1282       {"sizeof_alignof_incomplete_or_sizeless_type",
1283        "auto s = [[sizeof]](ns::X);"},
1284       {"for_range_incomplete_type", "void foo() { for (auto i : [[*]]x ) {} }"},
1285       {"func_def_incomplete_result", "ns::X [[func]] () {}"},
1286       {"field_incomplete_or_sizeless", "class M { ns::X [[member]]; };"},
1287       {"array_incomplete_or_sizeless_type", "auto s = [[(ns::X[]){}]];"},
1288       {"call_incomplete_return", "ns::X f(); auto fp = &f; auto z = [[fp()]];"},
1289       {"call_function_incomplete_return", "ns::X foo(); auto a = [[foo()]];"},
1290       {"call_incomplete_argument", "int m(ns::X); int i = m([[*x]]);"},
1291       {"switch_incomplete_class_type", "void a() { [[switch]](*x) {} }"},
1292       {"delete_incomplete_class_type", "void f() { [[delete]] *x; }"},
1293       {"-Wdelete-incomplete", "void f() { [[delete]] x; }"},
1294       {"dereference_incomplete_type",
1295        R"cpp(void f() { asm("" : "=r"([[*]]x)::); })cpp"},
1296   };
1297   for (auto Case : Tests) {
1298     Annotations Main(Case.second);
1299     TU.Code = Main.code().str() + "\n // error-ok";
1300     EXPECT_THAT(
1301         TU.build().getDiagnostics(),
1302         ElementsAre(AllOf(diagName(Case.first), hasRange(Main.range()),
1303                           withFix(Fix(Range{}, "#include \"x.h\"\n",
1304                                       "Include \"x.h\" for symbol ns::X")))))
1305         << Case.second;
1306   }
1307 }
1308 
1309 TEST(IncludeFixerTest, IncompleteEnum) {
1310   Symbol Sym = enm("X");
1311   Sym.Flags |= Symbol::IndexedForCodeCompletion;
1312   Sym.CanonicalDeclaration.FileURI = Sym.Definition.FileURI = "unittest:///x.h";
1313   Sym.IncludeHeaders.emplace_back("\"x.h\"", 1, Symbol::Include);
1314   SymbolSlab::Builder Slab;
1315   Slab.insert(Sym);
1316   auto Index =
1317       MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab());
1318 
1319   TestTU TU;
1320   TU.ExternalIndex = Index.get();
1321   TU.ExtraArgs.push_back("-std=c++20");
1322   TU.ExtraArgs.push_back("-fno-ms-compatibility"); // else incomplete enum is OK
1323 
1324   std::vector<std::pair<llvm::StringRef, llvm::StringRef>> Tests{
1325       {"incomplete_enum", "enum class X : int; using enum [[X]];"},
1326       {"underlying_type_of_incomplete_enum",
1327        "[[__underlying_type]](enum X) i;"},
1328   };
1329   for (auto Case : Tests) {
1330     Annotations Main(Case.second);
1331     TU.Code = Main.code().str() + "\n // error-ok";
1332     EXPECT_THAT(TU.build().getDiagnostics(),
1333                 Contains(AllOf(diagName(Case.first), hasRange(Main.range()),
1334                                withFix(Fix(Range{}, "#include \"x.h\"\n",
1335                                            "Include \"x.h\" for symbol X")))))
1336         << Case.second;
1337   }
1338 }
1339 
1340 TEST(IncludeFixerTest, NoSuggestIncludeWhenNoDefinitionInHeader) {
1341   Annotations Test(R"cpp(// error-ok
1342 $insert[[]]namespace ns {
1343   class X;
1344 }
1345 class Y : $base[[public ns::X]] {};
1346 int main() {
1347   ns::X *x;
1348   x$access[[->]]f();
1349 }
1350   )cpp");
1351   auto TU = TestTU::withCode(Test.code());
1352   Symbol Sym = cls("ns::X");
1353   Sym.Flags |= Symbol::IndexedForCodeCompletion;
1354   Sym.CanonicalDeclaration.FileURI = "unittest:///x.h";
1355   Sym.Definition.FileURI = "unittest:///x.cc";
1356   Sym.IncludeHeaders.emplace_back("\"x.h\"", 1, Symbol::Include);
1357 
1358   SymbolSlab::Builder Slab;
1359   Slab.insert(Sym);
1360   auto Index =
1361       MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab());
1362   TU.ExternalIndex = Index.get();
1363 
1364   EXPECT_THAT(TU.build().getDiagnostics(),
1365               UnorderedElementsAre(
1366                   Diag(Test.range("base"), "base class has incomplete type"),
1367                   Diag(Test.range("access"),
1368                        "member access into incomplete type 'ns::X'")));
1369 }
1370 
1371 TEST(IncludeFixerTest, Typo) {
1372   Annotations Test(R"cpp(// error-ok
1373 $insert[[]]namespace ns {
1374 void foo() {
1375   $unqualified1[[X]] x;
1376   // No fix if the unresolved type is used as specifier. (ns::)X::Nested will be
1377   // considered the unresolved type.
1378   $unqualified2[[X]]::Nested n;
1379 }
1380 struct S : $base[[X]] {};
1381 }
1382 void bar() {
1383   ns::$qualified1[[X]] x; // ns:: is valid.
1384   ns::$qualified2[[X]](); // Error: no member in namespace
1385 
1386   ::$global[[Global]] glob;
1387 }
1388 using Type = ns::$template[[Foo]]<int>;
1389   )cpp");
1390   auto TU = TestTU::withCode(Test.code());
1391   auto Index = buildIndexWithSymbol(
1392       {SymbolWithHeader{"ns::X", "unittest:///x.h", "\"x.h\""},
1393        SymbolWithHeader{"Global", "unittest:///global.h", "\"global.h\""},
1394        SymbolWithHeader{"ns::Foo", "unittest:///foo.h", "\"foo.h\""}});
1395   TU.ExternalIndex = Index.get();
1396 
1397   EXPECT_THAT(
1398       TU.build().getDiagnostics(),
1399       UnorderedElementsAre(
1400           AllOf(Diag(Test.range("unqualified1"), "unknown type name 'X'"),
1401                 diagName("unknown_typename"),
1402                 withFix(Fix(Test.range("insert"), "#include \"x.h\"\n",
1403                             "Include \"x.h\" for symbol ns::X"))),
1404           Diag(Test.range("unqualified2"), "use of undeclared identifier 'X'"),
1405           AllOf(Diag(Test.range("qualified1"),
1406                      "no type named 'X' in namespace 'ns'"),
1407                 diagName("typename_nested_not_found"),
1408                 withFix(Fix(Test.range("insert"), "#include \"x.h\"\n",
1409                             "Include \"x.h\" for symbol ns::X"))),
1410           AllOf(Diag(Test.range("qualified2"),
1411                      "no member named 'X' in namespace 'ns'"),
1412                 diagName("no_member"),
1413                 withFix(Fix(Test.range("insert"), "#include \"x.h\"\n",
1414                             "Include \"x.h\" for symbol ns::X"))),
1415           AllOf(Diag(Test.range("global"),
1416                      "no type named 'Global' in the global namespace"),
1417                 diagName("typename_nested_not_found"),
1418                 withFix(Fix(Test.range("insert"), "#include \"global.h\"\n",
1419                             "Include \"global.h\" for symbol Global"))),
1420           AllOf(Diag(Test.range("template"),
1421                      "no template named 'Foo' in namespace 'ns'"),
1422                 diagName("no_member_template"),
1423                 withFix(Fix(Test.range("insert"), "#include \"foo.h\"\n",
1424                             "Include \"foo.h\" for symbol ns::Foo"))),
1425           AllOf(Diag(Test.range("base"), "expected class name"),
1426                 diagName("expected_class_name"),
1427                 withFix(Fix(Test.range("insert"), "#include \"x.h\"\n",
1428                             "Include \"x.h\" for symbol ns::X")))));
1429 }
1430 
1431 TEST(IncludeFixerTest, TypoInMacro) {
1432   auto TU = TestTU::withCode(R"cpp(// error-ok
1433 #define ID(T) T
1434 X a1;
1435 ID(X a2);
1436 ns::X a3;
1437 ID(ns::X a4);
1438 namespace ns{};
1439 ns::X a5;
1440 ID(ns::X a6);
1441 )cpp");
1442   auto Index = buildIndexWithSymbol(
1443       {SymbolWithHeader{"X", "unittest:///x.h", "\"x.h\""},
1444        SymbolWithHeader{"ns::X", "unittest:///ns.h", "\"x.h\""}});
1445   TU.ExternalIndex = Index.get();
1446   // FIXME: -fms-compatibility (which is default on windows) breaks the
1447   // ns::X cases when the namespace is undeclared. Find out why!
1448   TU.ExtraArgs = {"-fno-ms-compatibility"};
1449   EXPECT_THAT(TU.build().getDiagnostics(), Each(withFix(_)));
1450 }
1451 
1452 TEST(IncludeFixerTest, MultipleMatchedSymbols) {
1453   Annotations Test(R"cpp(// error-ok
1454 $insert[[]]namespace na {
1455 namespace nb {
1456 void foo() {
1457   $unqualified[[X]] x;
1458 }
1459 }
1460 }
1461   )cpp");
1462   auto TU = TestTU::withCode(Test.code());
1463   auto Index = buildIndexWithSymbol(
1464       {SymbolWithHeader{"na::X", "unittest:///a.h", "\"a.h\""},
1465        SymbolWithHeader{"na::nb::X", "unittest:///b.h", "\"b.h\""}});
1466   TU.ExternalIndex = Index.get();
1467 
1468   EXPECT_THAT(TU.build().getDiagnostics(),
1469               UnorderedElementsAre(AllOf(
1470                   Diag(Test.range("unqualified"), "unknown type name 'X'"),
1471                   diagName("unknown_typename"),
1472                   withFix(Fix(Test.range("insert"), "#include \"a.h\"\n",
1473                               "Include \"a.h\" for symbol na::X"),
1474                           Fix(Test.range("insert"), "#include \"b.h\"\n",
1475                               "Include \"b.h\" for symbol na::nb::X")))));
1476 }
1477 
1478 TEST(IncludeFixerTest, NoCrashMemberAccess) {
1479   Annotations Test(R"cpp(// error-ok
1480     struct X { int  xyz; };
1481     void g() { X x; x.$[[xy]]; }
1482   )cpp");
1483   auto TU = TestTU::withCode(Test.code());
1484   auto Index = buildIndexWithSymbol(
1485       SymbolWithHeader{"na::X", "unittest:///a.h", "\"a.h\""});
1486   TU.ExternalIndex = Index.get();
1487 
1488   EXPECT_THAT(
1489       TU.build().getDiagnostics(),
1490       UnorderedElementsAre(Diag(Test.range(), "no member named 'xy' in 'X'")));
1491 }
1492 
1493 TEST(IncludeFixerTest, UseCachedIndexResults) {
1494   // As index results for the identical request are cached, more than 5 fixes
1495   // are generated.
1496   Annotations Test(R"cpp(// error-ok
1497 $insert[[]]void foo() {
1498   $x1[[X]] x;
1499   $x2[[X]] x;
1500   $x3[[X]] x;
1501   $x4[[X]] x;
1502   $x5[[X]] x;
1503   $x6[[X]] x;
1504   $x7[[X]] x;
1505 }
1506 
1507 class X;
1508 void bar(X *x) {
1509   x$a1[[->]]f();
1510   x$a2[[->]]f();
1511   x$a3[[->]]f();
1512   x$a4[[->]]f();
1513   x$a5[[->]]f();
1514   x$a6[[->]]f();
1515   x$a7[[->]]f();
1516 }
1517   )cpp");
1518   auto TU = TestTU::withCode(Test.code());
1519   auto Index =
1520       buildIndexWithSymbol(SymbolWithHeader{"X", "unittest:///a.h", "\"a.h\""});
1521   TU.ExternalIndex = Index.get();
1522 
1523   auto Parsed = TU.build();
1524   for (const auto &D : Parsed.getDiagnostics()) {
1525     if (D.Fixes.size() != 1) {
1526       ADD_FAILURE() << "D.Fixes.size() != 1";
1527       continue;
1528     }
1529     EXPECT_EQ(D.Fixes[0].Message, std::string("Include \"a.h\" for symbol X"));
1530   }
1531 }
1532 
1533 TEST(IncludeFixerTest, UnresolvedNameAsSpecifier) {
1534   Annotations Test(R"cpp(// error-ok
1535 $insert[[]]namespace ns {
1536 }
1537 void g() {  ns::$[[scope]]::X_Y();  }
1538   )cpp");
1539   TestTU TU;
1540   TU.Code = std::string(Test.code());
1541   // FIXME: Figure out why this is needed and remove it, PR43662.
1542   TU.ExtraArgs.push_back("-fno-ms-compatibility");
1543   auto Index = buildIndexWithSymbol(
1544       SymbolWithHeader{"ns::scope::X_Y", "unittest:///x.h", "\"x.h\""});
1545   TU.ExternalIndex = Index.get();
1546 
1547   EXPECT_THAT(
1548       TU.build().getDiagnostics(),
1549       UnorderedElementsAre(
1550           AllOf(Diag(Test.range(), "no member named 'scope' in namespace 'ns'"),
1551                 diagName("no_member"),
1552                 withFix(Fix(Test.range("insert"), "#include \"x.h\"\n",
1553                             "Include \"x.h\" for symbol ns::scope::X_Y")))));
1554 }
1555 
1556 TEST(IncludeFixerTest, UnresolvedSpecifierWithSemaCorrection) {
1557   Annotations Test(R"cpp(// error-ok
1558 $insert[[]]namespace clang {
1559 void f() {
1560   // "clangd::" will be corrected to "clang::" by Sema.
1561   $q1[[clangd]]::$x[[X]] x;
1562   $q2[[clangd]]::$ns[[ns]]::Y y;
1563 }
1564 }
1565   )cpp");
1566   TestTU TU;
1567   TU.Code = std::string(Test.code());
1568   // FIXME: Figure out why this is needed and remove it, PR43662.
1569   TU.ExtraArgs.push_back("-fno-ms-compatibility");
1570   auto Index = buildIndexWithSymbol(
1571       {SymbolWithHeader{"clang::clangd::X", "unittest:///x.h", "\"x.h\""},
1572        SymbolWithHeader{"clang::clangd::ns::Y", "unittest:///y.h", "\"y.h\""}});
1573   TU.ExternalIndex = Index.get();
1574 
1575   EXPECT_THAT(
1576       TU.build().getDiagnostics(),
1577       UnorderedElementsAre(
1578           AllOf(Diag(Test.range("q1"), "use of undeclared identifier 'clangd'; "
1579                                        "did you mean 'clang'?"),
1580                 diagName("undeclared_var_use_suggest"),
1581                 withFix(_, // change clangd to clang
1582                         Fix(Test.range("insert"), "#include \"x.h\"\n",
1583                             "Include \"x.h\" for symbol clang::clangd::X"))),
1584           AllOf(Diag(Test.range("x"), "no type named 'X' in namespace 'clang'"),
1585                 diagName("typename_nested_not_found"),
1586                 withFix(Fix(Test.range("insert"), "#include \"x.h\"\n",
1587                             "Include \"x.h\" for symbol clang::clangd::X"))),
1588           AllOf(
1589               Diag(Test.range("q2"), "use of undeclared identifier 'clangd'; "
1590                                      "did you mean 'clang'?"),
1591               diagName("undeclared_var_use_suggest"),
1592               withFix(_, // change clangd to clang
1593                       Fix(Test.range("insert"), "#include \"y.h\"\n",
1594                           "Include \"y.h\" for symbol clang::clangd::ns::Y"))),
1595           AllOf(Diag(Test.range("ns"),
1596                      "no member named 'ns' in namespace 'clang'"),
1597                 diagName("no_member"),
1598                 withFix(
1599                     Fix(Test.range("insert"), "#include \"y.h\"\n",
1600                         "Include \"y.h\" for symbol clang::clangd::ns::Y")))));
1601 }
1602 
1603 TEST(IncludeFixerTest, SpecifiedScopeIsNamespaceAlias) {
1604   Annotations Test(R"cpp(// error-ok
1605 $insert[[]]namespace a {}
1606 namespace b = a;
1607 namespace c {
1608   b::$[[X]] x;
1609 }
1610   )cpp");
1611   auto TU = TestTU::withCode(Test.code());
1612   auto Index = buildIndexWithSymbol(
1613       SymbolWithHeader{"a::X", "unittest:///x.h", "\"x.h\""});
1614   TU.ExternalIndex = Index.get();
1615 
1616   EXPECT_THAT(TU.build().getDiagnostics(),
1617               UnorderedElementsAre(AllOf(
1618                   Diag(Test.range(), "no type named 'X' in namespace 'a'"),
1619                   diagName("typename_nested_not_found"),
1620                   withFix(Fix(Test.range("insert"), "#include \"x.h\"\n",
1621                               "Include \"x.h\" for symbol a::X")))));
1622 }
1623 
1624 TEST(IncludeFixerTest, NoCrashOnTemplateInstantiations) {
1625   Annotations Test(R"cpp(
1626     template <typename T> struct Templ {
1627       template <typename U>
1628       typename U::type operator=(const U &);
1629     };
1630 
1631     struct A {
1632       Templ<char> s;
1633       A() { [[a]]; /*error-ok*/ } // crash if we compute scopes lazily.
1634     };
1635   )cpp");
1636 
1637   auto TU = TestTU::withCode(Test.code());
1638   auto Index = buildIndexWithSymbol({});
1639   TU.ExternalIndex = Index.get();
1640 
1641   EXPECT_THAT(
1642       TU.build().getDiagnostics(),
1643       ElementsAre(Diag(Test.range(), "use of undeclared identifier 'a'")));
1644 }
1645 
1646 TEST(IncludeFixerTest, HeaderNamedInDiag) {
1647   Annotations Test(R"cpp(
1648     $insert[[]]int main() {
1649       [[printf]]("");
1650     }
1651   )cpp");
1652   auto TU = TestTU::withCode(Test.code());
1653   TU.ExtraArgs = {"-xc", "-std=c99",
1654                   "-Wno-error=implicit-function-declaration"};
1655   auto Index = buildIndexWithSymbol({});
1656   TU.ExternalIndex = Index.get();
1657 
1658   EXPECT_THAT(
1659       TU.build().getDiagnostics(),
1660       ElementsAre(AllOf(
1661           Diag(Test.range(), "call to undeclared library function 'printf' "
1662                              "with type 'int (const char *, ...)'; ISO C99 "
1663                              "and later do not support implicit function "
1664                              "declarations"),
1665           withFix(Fix(Test.range("insert"), "#include <stdio.h>\n",
1666                       "Include <stdio.h> for symbol printf")))));
1667 
1668   TU.ExtraArgs = {"-xc", "-std=c89"};
1669   EXPECT_THAT(
1670       TU.build().getDiagnostics(),
1671       ElementsAre(AllOf(
1672           Diag(Test.range(), "implicitly declaring library function 'printf' "
1673                              "with type 'int (const char *, ...)'"),
1674           withFix(Fix(Test.range("insert"), "#include <stdio.h>\n",
1675                       "Include <stdio.h> for symbol printf")))));
1676 }
1677 
1678 TEST(IncludeFixerTest, CImplicitFunctionDecl) {
1679   Annotations Test("void x() { [[foo]](); }");
1680   auto TU = TestTU::withCode(Test.code());
1681   TU.Filename = "test.c";
1682   TU.ExtraArgs = {"-std=c99", "-Wno-error=implicit-function-declaration"};
1683 
1684   Symbol Sym = func("foo");
1685   Sym.Flags |= Symbol::IndexedForCodeCompletion;
1686   Sym.CanonicalDeclaration.FileURI = "unittest:///foo.h";
1687   Sym.IncludeHeaders.emplace_back("\"foo.h\"", 1, Symbol::Include);
1688 
1689   SymbolSlab::Builder Slab;
1690   Slab.insert(Sym);
1691   auto Index =
1692       MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab());
1693   TU.ExternalIndex = Index.get();
1694 
1695   EXPECT_THAT(
1696       TU.build().getDiagnostics(),
1697       ElementsAre(AllOf(
1698           Diag(Test.range(),
1699                "call to undeclared function 'foo'; ISO C99 and later do not "
1700                "support implicit function declarations"),
1701           withFix(Fix(Range{}, "#include \"foo.h\"\n",
1702                       "Include \"foo.h\" for symbol foo")))));
1703 
1704   TU.ExtraArgs = {"-std=c89", "-Wall"};
1705   EXPECT_THAT(TU.build().getDiagnostics(),
1706               ElementsAre(AllOf(
1707                   Diag(Test.range(), "implicit declaration of function 'foo'"),
1708                   withFix(Fix(Range{}, "#include \"foo.h\"\n",
1709                               "Include \"foo.h\" for symbol foo")))));
1710 }
1711 
1712 TEST(DiagsInHeaders, DiagInsideHeader) {
1713   Annotations Main(R"cpp(
1714     #include [["a.h"]]
1715     void foo() {})cpp");
1716   Annotations Header("[[no_type_spec]]; // error-ok");
1717   TestTU TU = TestTU::withCode(Main.code());
1718   TU.AdditionalFiles = {{"a.h", std::string(Header.code())}};
1719   EXPECT_THAT(TU.build().getDiagnostics(),
1720               UnorderedElementsAre(AllOf(
1721                   Diag(Main.range(), "in included file: a type specifier is "
1722                                      "required for all declarations"),
1723                   withNote(Diag(Header.range(), "error occurred here")))));
1724 }
1725 
1726 TEST(DiagsInHeaders, DiagInTransitiveInclude) {
1727   Annotations Main(R"cpp(
1728     #include [["a.h"]]
1729     void foo() {})cpp");
1730   TestTU TU = TestTU::withCode(Main.code());
1731   TU.AdditionalFiles = {{"a.h", "#include \"b.h\""},
1732                         {"b.h", "no_type_spec; // error-ok"}};
1733   EXPECT_THAT(TU.build().getDiagnostics(),
1734               UnorderedElementsAre(Diag(Main.range(),
1735                                         "in included file: a type specifier is "
1736                                         "required for all declarations")));
1737 }
1738 
1739 TEST(DiagsInHeaders, DiagInMultipleHeaders) {
1740   Annotations Main(R"cpp(
1741     #include $a[["a.h"]]
1742     #include $b[["b.h"]]
1743     void foo() {})cpp");
1744   TestTU TU = TestTU::withCode(Main.code());
1745   TU.AdditionalFiles = {{"a.h", "no_type_spec; // error-ok"},
1746                         {"b.h", "no_type_spec; // error-ok"}};
1747   EXPECT_THAT(TU.build().getDiagnostics(),
1748               UnorderedElementsAre(
1749                   Diag(Main.range("a"), "in included file: a type specifier is "
1750                                         "required for all declarations"),
1751                   Diag(Main.range("b"), "in included file: a type specifier is "
1752                                         "required for all declarations")));
1753 }
1754 
1755 TEST(DiagsInHeaders, PreferExpansionLocation) {
1756   Annotations Main(R"cpp(
1757     #include [["a.h"]]
1758     #include "b.h"
1759     void foo() {})cpp");
1760   TestTU TU = TestTU::withCode(Main.code());
1761   TU.AdditionalFiles = {
1762       {"a.h", "#include \"b.h\"\n"},
1763       {"b.h", "#ifndef X\n#define X\nno_type_spec; // error-ok\n#endif"}};
1764   EXPECT_THAT(TU.build().getDiagnostics(),
1765               Contains(Diag(Main.range(), "in included file: a type specifier "
1766                                           "is required for all declarations")));
1767 }
1768 
1769 TEST(DiagsInHeaders, PreferExpansionLocationMacros) {
1770   Annotations Main(R"cpp(
1771     #define X
1772     #include "a.h"
1773     #undef X
1774     #include [["b.h"]]
1775     void foo() {})cpp");
1776   TestTU TU = TestTU::withCode(Main.code());
1777   TU.AdditionalFiles = {
1778       {"a.h", "#include \"c.h\"\n"},
1779       {"b.h", "#include \"c.h\"\n"},
1780       {"c.h", "#ifndef X\n#define X\nno_type_spec; // error-ok\n#endif"}};
1781   EXPECT_THAT(TU.build().getDiagnostics(),
1782               UnorderedElementsAre(Diag(Main.range(),
1783                                         "in included file: a type specifier is "
1784                                         "required for all declarations")));
1785 }
1786 
1787 TEST(DiagsInHeaders, LimitDiagsOutsideMainFile) {
1788   Annotations Main(R"cpp(
1789     #include [["a.h"]]
1790     #include "b.h"
1791     void foo() {})cpp");
1792   TestTU TU = TestTU::withCode(Main.code());
1793   TU.AdditionalFiles = {{"a.h", "#include \"c.h\"\n"},
1794                         {"b.h", "#include \"c.h\"\n"},
1795                         {"c.h", R"cpp(
1796       #ifndef X
1797       #define X
1798       no_type_spec_0; // error-ok
1799       no_type_spec_1;
1800       no_type_spec_2;
1801       no_type_spec_3;
1802       no_type_spec_4;
1803       no_type_spec_5;
1804       no_type_spec_6;
1805       no_type_spec_7;
1806       no_type_spec_8;
1807       no_type_spec_9;
1808       no_type_spec_10;
1809       #endif)cpp"}};
1810   EXPECT_THAT(TU.build().getDiagnostics(),
1811               UnorderedElementsAre(Diag(Main.range(),
1812                                         "in included file: a type specifier is "
1813                                         "required for all declarations")));
1814 }
1815 
1816 TEST(DiagsInHeaders, OnlyErrorOrFatal) {
1817   Annotations Main(R"cpp(
1818     #include [["a.h"]]
1819     void foo() {})cpp");
1820   Annotations Header(R"cpp(
1821     [[no_type_spec]]; // error-ok
1822     int x = 5/0;)cpp");
1823   TestTU TU = TestTU::withCode(Main.code());
1824   TU.AdditionalFiles = {{"a.h", std::string(Header.code())}};
1825   EXPECT_THAT(TU.build().getDiagnostics(),
1826               UnorderedElementsAre(AllOf(
1827                   Diag(Main.range(), "in included file: a type specifier is "
1828                                      "required for all declarations"),
1829                   withNote(Diag(Header.range(), "error occurred here")))));
1830 }
1831 
1832 TEST(DiagsInHeaders, OnlyDefaultErrorOrFatal) {
1833   Annotations Main(R"cpp(
1834     #include [["a.h"]] // get unused "foo" warning when building preamble.
1835     )cpp");
1836   Annotations Header(R"cpp(
1837     namespace { void foo() {} }
1838     void func() {foo();} ;)cpp");
1839   TestTU TU = TestTU::withCode(Main.code());
1840   TU.AdditionalFiles = {{"a.h", std::string(Header.code())}};
1841   // promote warnings to errors.
1842   TU.ExtraArgs = {"-Werror", "-Wunused"};
1843   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
1844 }
1845 
1846 TEST(DiagsInHeaders, FromNonWrittenSources) {
1847   Annotations Main(R"cpp(
1848     #include [["a.h"]]
1849     void foo() {})cpp");
1850   Annotations Header(R"cpp(
1851     int x = 5/0;
1852     int b = [[FOO]]; // error-ok)cpp");
1853   TestTU TU = TestTU::withCode(Main.code());
1854   TU.AdditionalFiles = {{"a.h", std::string(Header.code())}};
1855   TU.ExtraArgs = {"-DFOO=NOOO"};
1856   EXPECT_THAT(TU.build().getDiagnostics(),
1857               UnorderedElementsAre(AllOf(
1858                   Diag(Main.range(),
1859                        "in included file: use of undeclared identifier 'NOOO'"),
1860                   withNote(Diag(Header.range(), "error occurred here")))));
1861 }
1862 
1863 TEST(DiagsInHeaders, ErrorFromMacroExpansion) {
1864   Annotations Main(R"cpp(
1865   void bar() {
1866     int fo; // error-ok
1867     #include [["a.h"]]
1868   })cpp");
1869   Annotations Header(R"cpp(
1870   #define X foo
1871   X;)cpp");
1872   TestTU TU = TestTU::withCode(Main.code());
1873   TU.AdditionalFiles = {{"a.h", std::string(Header.code())}};
1874   EXPECT_THAT(TU.build().getDiagnostics(),
1875               UnorderedElementsAre(
1876                   Diag(Main.range(), "in included file: use of undeclared "
1877                                      "identifier 'foo'; did you mean 'fo'?")));
1878 }
1879 
1880 TEST(DiagsInHeaders, ErrorFromMacroArgument) {
1881   Annotations Main(R"cpp(
1882   void bar() {
1883     int fo; // error-ok
1884     #include [["a.h"]]
1885   })cpp");
1886   Annotations Header(R"cpp(
1887   #define X(arg) arg
1888   X(foo);)cpp");
1889   TestTU TU = TestTU::withCode(Main.code());
1890   TU.AdditionalFiles = {{"a.h", std::string(Header.code())}};
1891   EXPECT_THAT(TU.build().getDiagnostics(),
1892               UnorderedElementsAre(
1893                   Diag(Main.range(), "in included file: use of undeclared "
1894                                      "identifier 'foo'; did you mean 'fo'?")));
1895 }
1896 
1897 TEST(IgnoreDiags, FromNonWrittenInclude) {
1898   TestTU TU;
1899   TU.ExtraArgs.push_back("--include=a.h");
1900   TU.AdditionalFiles = {{"a.h", "void main();"}};
1901   // The diagnostic "main must return int" is from the header, we don't attempt
1902   // to render it in the main file as there is no written location there.
1903   EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre());
1904 }
1905 
1906 TEST(ToLSPDiag, RangeIsInMain) {
1907   ClangdDiagnosticOptions Opts;
1908   clangd::Diag D;
1909   D.Range = {pos(1, 2), pos(3, 4)};
1910   D.Notes.emplace_back();
1911   Note &N = D.Notes.back();
1912   N.Range = {pos(2, 3), pos(3, 4)};
1913 
1914   D.InsideMainFile = true;
1915   N.InsideMainFile = false;
1916   toLSPDiags(D, {}, Opts,
1917              [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>) {
1918                EXPECT_EQ(LSPDiag.range, D.Range);
1919              });
1920 
1921   D.InsideMainFile = false;
1922   N.InsideMainFile = true;
1923   toLSPDiags(D, {}, Opts,
1924              [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>) {
1925                EXPECT_EQ(LSPDiag.range, N.Range);
1926              });
1927 }
1928 
1929 TEST(ParsedASTTest, ModuleSawDiag) {
1930   TestTU TU;
1931 
1932   auto AST = TU.build();
1933         #if 0
1934   EXPECT_THAT(AST.getDiagnostics(),
1935               testing::Contains(Diag(Code.range(), KDiagMsg.str())));
1936         #endif
1937 }
1938 
1939 TEST(Preamble, EndsOnNonEmptyLine) {
1940   TestTU TU;
1941   TU.ExtraArgs = {"-Wnewline-eof"};
1942 
1943   {
1944     TU.Code = "#define FOO\n  void bar();\n";
1945     auto AST = TU.build();
1946     EXPECT_THAT(AST.getDiagnostics(), IsEmpty());
1947   }
1948   {
1949     Annotations Code("#define FOO[[]]");
1950     TU.Code = Code.code().str();
1951     auto AST = TU.build();
1952     EXPECT_THAT(
1953         AST.getDiagnostics(),
1954         testing::Contains(Diag(Code.range(), "no newline at end of file")));
1955   }
1956 }
1957 
1958 TEST(Diagnostics, Tags) {
1959   TestTU TU;
1960   TU.ExtraArgs = {"-Wunused", "-Wdeprecated"};
1961   Annotations Test(R"cpp(
1962   void bar() __attribute__((deprecated));
1963   void foo() {
1964     int $unused[[x]];
1965     $deprecated[[bar]]();
1966   })cpp");
1967   TU.Code = Test.code().str();
1968   EXPECT_THAT(TU.build().getDiagnostics(),
1969               UnorderedElementsAre(
1970                   AllOf(Diag(Test.range("unused"), "unused variable 'x'"),
1971                         withTag(DiagnosticTag::Unnecessary)),
1972                   AllOf(Diag(Test.range("deprecated"), "'bar' is deprecated"),
1973                         withTag(DiagnosticTag::Deprecated))));
1974 
1975   Test = Annotations(R"cpp(
1976     $typedef[[typedef int INT]];
1977   )cpp");
1978   TU.Code = Test.code();
1979   TU.ClangTidyProvider = addTidyChecks("modernize-use-using");
1980   EXPECT_THAT(
1981       TU.build().getDiagnostics(),
1982       ifTidyChecks(UnorderedElementsAre(
1983           AllOf(Diag(Test.range("typedef"), "use 'using' instead of 'typedef'"),
1984                 withTag(DiagnosticTag::Deprecated)))));
1985 }
1986 
1987 TEST(Diagnostics, TidyDiagsArentAffectedFromWerror) {
1988   TestTU TU;
1989   TU.ExtraArgs = {"-Werror"};
1990   Annotations Test(R"cpp($typedef[[typedef int INT]]; // error-ok)cpp");
1991   TU.Code = Test.code().str();
1992   TU.ClangTidyProvider = addTidyChecks("modernize-use-using");
1993   EXPECT_THAT(
1994       TU.build().getDiagnostics(),
1995       ifTidyChecks(UnorderedElementsAre(
1996           AllOf(Diag(Test.range("typedef"), "use 'using' instead of 'typedef'"),
1997                 // Make sure severity for clang-tidy finding isn't bumped to
1998                 // error due to Werror in compile flags.
1999                 diagSeverity(DiagnosticsEngine::Warning)))));
2000 
2001   TU.ClangTidyProvider =
2002       addTidyChecks("modernize-use-using", /*WarningsAsErrors=*/"modernize-*");
2003   EXPECT_THAT(
2004       TU.build().getDiagnostics(),
2005       ifTidyChecks(UnorderedElementsAre(
2006           AllOf(Diag(Test.range("typedef"), "use 'using' instead of 'typedef'"),
2007                 // Unless bumped explicitly with WarnAsError.
2008                 diagSeverity(DiagnosticsEngine::Error)))));
2009 }
2010 
2011 TEST(Diagnostics, DeprecatedDiagsAreHints) {
2012   ClangdDiagnosticOptions Opts;
2013   std::optional<clangd::Diagnostic> Diag;
2014   clangd::Diag D;
2015   D.Range = {pos(1, 2), pos(3, 4)};
2016   D.InsideMainFile = true;
2017 
2018   // Downgrade warnings with deprecated tags to remark.
2019   D.Tags = {Deprecated};
2020   D.Severity = DiagnosticsEngine::Warning;
2021   toLSPDiags(D, {}, Opts,
2022              [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>) {
2023                Diag = std::move(LSPDiag);
2024              });
2025   EXPECT_EQ(Diag->severity, getSeverity(DiagnosticsEngine::Remark));
2026   Diag.reset();
2027 
2028   // Preserve errors.
2029   D.Severity = DiagnosticsEngine::Error;
2030   toLSPDiags(D, {}, Opts,
2031              [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>) {
2032                Diag = std::move(LSPDiag);
2033              });
2034   EXPECT_EQ(Diag->severity, getSeverity(DiagnosticsEngine::Error));
2035   Diag.reset();
2036 
2037   // No-op without tag.
2038   D.Tags = {};
2039   D.Severity = DiagnosticsEngine::Warning;
2040   toLSPDiags(D, {}, Opts,
2041              [&](clangd::Diagnostic LSPDiag, ArrayRef<clangd::Fix>) {
2042                Diag = std::move(LSPDiag);
2043              });
2044   EXPECT_EQ(Diag->severity, getSeverity(DiagnosticsEngine::Warning));
2045 }
2046 
2047 TEST(DiagnosticsTest, IncludeCleaner) {
2048   Annotations Test(R"cpp(
2049 $fix[[  $diag[[#include "unused.h"]]
2050 ]]
2051   #include "used.h"
2052 
2053   #include "ignore.h"
2054 
2055   #include <system_header.h>
2056 
2057   void foo() {
2058     used();
2059   }
2060   )cpp");
2061   TestTU TU;
2062   TU.Code = Test.code().str();
2063   TU.AdditionalFiles["unused.h"] = R"cpp(
2064     #pragma once
2065     void unused() {}
2066   )cpp";
2067   TU.AdditionalFiles["used.h"] = R"cpp(
2068     #pragma once
2069     void used() {}
2070   )cpp";
2071   TU.AdditionalFiles["ignore.h"] = R"cpp(
2072     #pragma once
2073     void ignore() {}
2074   )cpp";
2075   TU.AdditionalFiles["system/system_header.h"] = "";
2076   TU.ExtraArgs = {"-isystem" + testPath("system")};
2077   Config Cfg;
2078   Cfg.Diagnostics.UnusedIncludes = Config::IncludesPolicy::Strict;
2079   // Set filtering.
2080   Cfg.Diagnostics.Includes.IgnoreHeader.emplace_back(
2081       [](llvm::StringRef Header) { return Header.ends_with("ignore.h"); });
2082   WithContextValue WithCfg(Config::Key, std::move(Cfg));
2083   auto AST = TU.build();
2084   EXPECT_THAT(
2085       AST.getDiagnostics(),
2086       Contains(AllOf(
2087           Diag(Test.range("diag"),
2088                "included header unused.h is not used directly"),
2089           withTag(DiagnosticTag::Unnecessary), diagSource(Diag::Clangd),
2090           withFix(Fix(Test.range("fix"), "", "remove #include directive")))));
2091   auto &Diag = AST.getDiagnostics().front();
2092   EXPECT_THAT(getDiagnosticDocURI(Diag.Source, Diag.ID, Diag.Name),
2093               llvm::ValueIs(Not(IsEmpty())));
2094   Cfg.Diagnostics.SuppressAll = true;
2095   WithContextValue SuppressAllWithCfg(Config::Key, std::move(Cfg));
2096   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
2097   Cfg.Diagnostics.SuppressAll = false;
2098   Cfg.Diagnostics.Suppress = {"unused-includes"};
2099   WithContextValue SuppressFilterWithCfg(Config::Key, std::move(Cfg));
2100   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
2101 }
2102 
2103 TEST(DiagnosticsTest, FixItFromHeader) {
2104   llvm::StringLiteral Header(R"cpp(
2105     void foo(int *);
2106     void foo(int *, int);)cpp");
2107   Annotations Source(R"cpp(
2108   /*error-ok*/
2109     void bar() {
2110       int x;
2111       $diag[[foo]]($fix[[]]x, 1);
2112     })cpp");
2113   TestTU TU;
2114   TU.Code = Source.code().str();
2115   TU.HeaderCode = Header.str();
2116   EXPECT_THAT(
2117       TU.build().getDiagnostics(),
2118       UnorderedElementsAre(AllOf(
2119           Diag(Source.range("diag"), "no matching function for call to 'foo'"),
2120           withFix(Fix(Source.range("fix"), "&",
2121                       "candidate function not viable: no known conversion from "
2122                       "'int' to 'int *' for 1st argument; take the address of "
2123                       "the argument with &")))));
2124 }
2125 
2126 TEST(DiagnosticsTest, UnusedInHeader) {
2127   // Clang diagnoses unused static inline functions outside headers.
2128   auto TU = TestTU::withCode("static inline void foo(void) {}");
2129   TU.ExtraArgs.push_back("-Wunused-function");
2130   TU.Filename = "test.c";
2131   EXPECT_THAT(TU.build().getDiagnostics(),
2132               ElementsAre(withID(diag::warn_unused_function)));
2133   // Sema should recognize a *.h file open in clangd as a header.
2134   // https://github.com/clangd/vscode-clangd/issues/360
2135   TU.Filename = "test.h";
2136   EXPECT_THAT(TU.build().getDiagnostics(), IsEmpty());
2137 }
2138 
2139 } // namespace
2140 } // namespace clangd
2141 } // namespace clang
2142