[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clangd / unittests / ASTTests.cpp
blob3101bf34acd717c0b1bd785f9c4cc86533f7900a
1 //===-- ASTTests.cpp --------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "AST.h"
11 #include "Annotations.h"
12 #include "ParsedAST.h"
13 #include "TestTU.h"
14 #include "index/Symbol.h"
15 #include "clang/AST/ASTTypeTraits.h"
16 #include "clang/AST/Attr.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclBase.h"
19 #include "clang/Basic/AttrKinds.h"
20 #include "clang/Basic/SourceManager.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/Casting.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include <cstddef>
26 #include <string>
27 #include <vector>
29 namespace clang {
30 namespace clangd {
31 namespace {
32 using testing::Contains;
33 using testing::Each;
34 using testing::IsEmpty;
36 TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
37 struct Test {
38 StringRef AnnotatedCode;
39 const char *DeducedType;
40 } Tests[] = {
41 {"^auto i = 0;", "int"},
42 {"^auto f(){ return 1;};", "int"},
44 R"cpp( // auto on struct in a namespace
45 namespace ns1 { struct S {}; }
46 ^auto v = ns1::S{};
47 )cpp",
48 "ns1::S",
51 R"cpp( // decltype on struct
52 namespace ns1 { struct S {}; }
53 ns1::S i;
54 ^decltype(i) j;
55 )cpp",
56 "ns1::S",
59 R"cpp(// decltype(auto) on struct&
60 namespace ns1 {
61 struct S {};
62 } // namespace ns1
64 ns1::S i;
65 ns1::S& j = i;
66 ^decltype(auto) k = j;
67 )cpp",
68 "ns1::S &",
71 R"cpp( // auto on template class
72 class X;
73 template<typename T> class Foo {};
74 ^auto v = Foo<X>();
75 )cpp",
76 "Foo<X>",
79 R"cpp( // auto on initializer list.
80 namespace std
82 template<class _E>
83 class [[initializer_list]] {};
86 ^auto i = {1,2};
87 )cpp",
88 "std::initializer_list<int>",
91 R"cpp( // auto in function return type with trailing return type
92 struct Foo {};
93 ^auto test() -> decltype(Foo()) {
94 return Foo();
96 )cpp",
97 "Foo",
100 R"cpp( // decltype in trailing return type
101 struct Foo {};
102 auto test() -> ^decltype(Foo()) {
103 return Foo();
105 )cpp",
106 "Foo",
109 R"cpp( // auto in function return type
110 struct Foo {};
111 ^auto test() {
112 return Foo();
114 )cpp",
115 "Foo",
118 R"cpp( // auto& in function return type
119 struct Foo {};
120 ^auto& test() {
121 static Foo x;
122 return x;
124 )cpp",
125 "Foo",
128 R"cpp( // auto* in function return type
129 struct Foo {};
130 ^auto* test() {
131 Foo *x;
132 return x;
134 )cpp",
135 "Foo",
138 R"cpp( // const auto& in function return type
139 struct Foo {};
140 const ^auto& test() {
141 static Foo x;
142 return x;
144 )cpp",
145 "Foo",
148 R"cpp( // decltype(auto) in function return (value)
149 struct Foo {};
150 ^decltype(auto) test() {
151 return Foo();
153 )cpp",
154 "Foo",
157 R"cpp( // decltype(auto) in function return (ref)
158 struct Foo {};
159 ^decltype(auto) test() {
160 static Foo x;
161 return (x);
163 )cpp",
164 "Foo &",
167 R"cpp( // decltype(auto) in function return (const ref)
168 struct Foo {};
169 ^decltype(auto) test() {
170 static const Foo x;
171 return (x);
173 )cpp",
174 "const Foo &",
177 R"cpp( // auto on alias
178 struct Foo {};
179 using Bar = Foo;
180 ^auto x = Bar();
181 )cpp",
182 "Bar",
185 R"cpp(
186 // Generic lambda param.
187 struct Foo{};
188 auto Generic = [](^auto x) { return 0; };
189 int m = Generic(Foo{});
190 )cpp",
191 "struct Foo",
194 R"cpp(
195 // Generic lambda instantiated twice, matching deduction.
196 struct Foo{};
197 auto Generic = [](^auto x, auto y) { return 0; };
198 int m = Generic(Foo{}, "one");
199 int n = Generic(Foo{}, 2);
200 )cpp",
201 // No deduction although both instantiations yield the same result :-(
202 nullptr,
205 R"cpp(
206 // Generic lambda instantiated twice, conflicting deduction.
207 struct Foo{};
208 auto Generic = [](^auto y) { return 0; };
209 int m = Generic("one");
210 int n = Generic(2);
211 )cpp",
212 nullptr,
215 R"cpp(
216 // Generic function param.
217 struct Foo{};
218 int generic(^auto x) { return 0; }
219 int m = generic(Foo{});
220 )cpp",
221 "struct Foo",
224 R"cpp(
225 // More complicated param type involving auto.
226 template <class> concept C = true;
227 struct Foo{};
228 int generic(C ^auto *x) { return 0; }
229 const Foo *Ptr = nullptr;
230 int m = generic(Ptr);
231 )cpp",
232 "const struct Foo",
235 for (Test T : Tests) {
236 Annotations File(T.AnnotatedCode);
237 auto TU = TestTU::withCode(File.code());
238 TU.ExtraArgs.push_back("-std=c++20");
239 auto AST = TU.build();
240 SourceManagerForFile SM("foo.cpp", File.code());
242 SCOPED_TRACE(T.AnnotatedCode);
243 EXPECT_FALSE(File.points().empty());
244 for (Position Pos : File.points()) {
245 auto Location = sourceLocationInMainFile(SM.get(), Pos);
246 ASSERT_TRUE(!!Location) << llvm::toString(Location.takeError());
247 auto DeducedType = getDeducedType(AST.getASTContext(), *Location);
248 if (T.DeducedType == nullptr) {
249 EXPECT_FALSE(DeducedType);
250 } else {
251 ASSERT_TRUE(DeducedType);
252 EXPECT_EQ(DeducedType->getAsString(), T.DeducedType);
258 TEST(ClangdAST, GetOnlyInstantiation) {
259 struct {
260 const char *Code;
261 llvm::StringLiteral NodeType;
262 const char *Name;
263 } Cases[] = {
265 R"cpp(
266 template <typename> class X {};
267 X<int> x;
268 )cpp",
269 "CXXRecord",
270 "template<> class X<int> {}",
273 R"cpp(
274 template <typename T> T X = T{};
275 int y = X<char>;
276 )cpp",
277 "Var",
278 // VarTemplateSpecializationDecl doesn't print as template<>...
279 "char X = char{}",
282 R"cpp(
283 template <typename T> int X(T) { return 42; }
284 int y = X("text");
285 )cpp",
286 "Function",
287 "template<> int X<const char *>(const char *)",
290 R"cpp(
291 int X(auto *x) { return 42; }
292 int y = X("text");
293 )cpp",
294 "Function",
295 "template<> int X<const char>(const char *x)",
299 for (const auto &Case : Cases) {
300 SCOPED_TRACE(Case.Code);
301 auto TU = TestTU::withCode(Case.Code);
302 TU.ExtraArgs.push_back("-std=c++20");
303 auto AST = TU.build();
304 PrintingPolicy PP = AST.getASTContext().getPrintingPolicy();
305 PP.TerseOutput = true;
306 std::string Name;
307 if (auto *Result = getOnlyInstantiation(
308 const_cast<NamedDecl *>(&findDecl(AST, [&](const NamedDecl &D) {
309 return D.getDescribedTemplate() != nullptr &&
310 D.getDeclKindName() == Case.NodeType;
311 })))) {
312 llvm::raw_string_ostream OS(Name);
313 Result->print(OS, PP);
316 if (Case.Name)
317 EXPECT_EQ(Case.Name, Name);
318 else
319 EXPECT_THAT(Name, IsEmpty());
323 TEST(ClangdAST, GetContainedAutoParamType) {
324 auto TU = TestTU::withCode(R"cpp(
325 int withAuto(
326 auto a,
327 auto *b,
328 const auto *c,
329 auto &&d,
330 auto *&e,
331 auto (*f)(int)
332 ){};
334 int withoutAuto(
335 int a,
336 int *b,
337 const int *c,
338 int &&d,
339 int *&e,
340 int (*f)(int)
341 ){};
342 )cpp");
343 TU.ExtraArgs.push_back("-std=c++20");
344 auto AST = TU.build();
346 const auto &WithAuto =
347 llvm::cast<FunctionTemplateDecl>(findDecl(AST, "withAuto"));
348 auto ParamsWithAuto = WithAuto.getTemplatedDecl()->parameters();
349 auto *TemplateParamsWithAuto = WithAuto.getTemplateParameters();
350 ASSERT_EQ(ParamsWithAuto.size(), TemplateParamsWithAuto->size());
352 for (unsigned I = 0; I < ParamsWithAuto.size(); ++I) {
353 SCOPED_TRACE(ParamsWithAuto[I]->getNameAsString());
354 auto Loc = getContainedAutoParamType(
355 ParamsWithAuto[I]->getTypeSourceInfo()->getTypeLoc());
356 ASSERT_FALSE(Loc.isNull());
357 EXPECT_EQ(Loc.getTypePtr()->getDecl(), TemplateParamsWithAuto->getParam(I));
360 const auto &WithoutAuto =
361 llvm::cast<FunctionDecl>(findDecl(AST, "withoutAuto"));
362 for (auto *ParamWithoutAuto : WithoutAuto.parameters()) {
363 ASSERT_TRUE(getContainedAutoParamType(
364 ParamWithoutAuto->getTypeSourceInfo()->getTypeLoc())
365 .isNull());
369 TEST(ClangdAST, GetQualification) {
370 // Tries to insert the decl `Foo` into position of each decl named `insert`.
371 // This is done to get an appropriate DeclContext for the insertion location.
372 // Qualifications are the required nested name specifier to spell `Foo` at the
373 // `insert`ion location.
374 // VisibleNamespaces are assumed to be visible at every insertion location.
375 const struct {
376 llvm::StringRef Test;
377 std::vector<llvm::StringRef> Qualifications;
378 std::vector<std::string> VisibleNamespaces;
379 } Cases[] = {
381 R"cpp(
382 namespace ns1 { namespace ns2 { class Foo {}; } }
383 void insert(); // ns1::ns2::Foo
384 namespace ns1 {
385 void insert(); // ns2::Foo
386 namespace ns2 {
387 void insert(); // Foo
389 using namespace ns2;
390 void insert(); // Foo
392 using namespace ns1;
393 void insert(); // ns2::Foo
394 using namespace ns2;
395 void insert(); // Foo
396 )cpp",
397 {"ns1::ns2::", "ns2::", "", "", "ns2::", ""},
401 R"cpp(
402 namespace ns1 { namespace ns2 { class Bar { void Foo(); }; } }
403 void insert(); // ns1::ns2::Bar::Foo
404 namespace ns1 {
405 void insert(); // ns2::Bar::Foo
406 namespace ns2 {
407 void insert(); // Bar::Foo
409 using namespace ns2;
410 void insert(); // Bar::Foo
412 using namespace ns1;
413 void insert(); // ns2::Bar::Foo
414 using namespace ns2;
415 void insert(); // Bar::Foo
416 )cpp",
417 {"ns1::ns2::Bar::", "ns2::Bar::", "Bar::", "Bar::", "ns2::Bar::",
418 "Bar::"},
422 R"cpp(
423 namespace ns1 { namespace ns2 { void Foo(); } }
424 void insert(); // ns2::Foo
425 namespace ns1 {
426 void insert(); // ns2::Foo
427 namespace ns2 {
428 void insert(); // Foo
431 )cpp",
432 {"ns2::", "ns2::", ""},
433 {"ns1::"},
436 R"cpp(
437 namespace ns {
438 extern "C" {
439 typedef int Foo;
442 void insert(); // ns::Foo
443 )cpp",
444 {"ns::"},
448 for (const auto &Case : Cases) {
449 Annotations Test(Case.Test);
450 TestTU TU = TestTU::withCode(Test.code());
451 ParsedAST AST = TU.build();
452 std::vector<const Decl *> InsertionPoints;
453 const NamedDecl *TargetDecl;
454 findDecl(AST, [&](const NamedDecl &ND) {
455 if (ND.getNameAsString() == "Foo") {
456 TargetDecl = &ND;
457 return true;
460 if (ND.getNameAsString() == "insert")
461 InsertionPoints.push_back(&ND);
462 return false;
465 ASSERT_EQ(InsertionPoints.size(), Case.Qualifications.size());
466 for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
467 const Decl *D = InsertionPoints[I];
468 if (Case.VisibleNamespaces.empty()) {
469 EXPECT_EQ(getQualification(AST.getASTContext(),
470 D->getLexicalDeclContext(), D->getBeginLoc(),
471 TargetDecl),
472 Case.Qualifications[I]);
473 } else {
474 EXPECT_EQ(getQualification(AST.getASTContext(),
475 D->getLexicalDeclContext(), TargetDecl,
476 Case.VisibleNamespaces),
477 Case.Qualifications[I]);
483 TEST(ClangdAST, PrintType) {
484 const struct {
485 llvm::StringRef Test;
486 std::vector<llvm::StringRef> Types;
487 } Cases[] = {
489 R"cpp(
490 namespace ns1 { namespace ns2 { class Foo {}; } }
491 void insert(); // ns1::ns2::Foo
492 namespace ns1 {
493 void insert(); // ns2::Foo
494 namespace ns2 {
495 void insert(); // Foo
498 )cpp",
499 {"ns1::ns2::Foo", "ns2::Foo", "Foo"},
502 R"cpp(
503 namespace ns1 {
504 typedef int Foo;
506 void insert(); // ns1::Foo
507 namespace ns1 {
508 void insert(); // Foo
510 )cpp",
511 {"ns1::Foo", "Foo"},
514 for (const auto &Case : Cases) {
515 Annotations Test(Case.Test);
516 TestTU TU = TestTU::withCode(Test.code());
517 ParsedAST AST = TU.build();
518 std::vector<const DeclContext *> InsertionPoints;
519 const TypeDecl *TargetDecl = nullptr;
520 findDecl(AST, [&](const NamedDecl &ND) {
521 if (ND.getNameAsString() == "Foo") {
522 if (const auto *TD = llvm::dyn_cast<TypeDecl>(&ND)) {
523 TargetDecl = TD;
524 return true;
526 } else if (ND.getNameAsString() == "insert")
527 InsertionPoints.push_back(ND.getDeclContext());
528 return false;
531 ASSERT_EQ(InsertionPoints.size(), Case.Types.size());
532 for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
533 const auto *DC = InsertionPoints[I];
534 EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC),
535 Case.Types[I]);
540 TEST(ClangdAST, IsDeeplyNested) {
541 Annotations Test(
542 R"cpp(
543 namespace ns {
544 class Foo {
545 void bar() {
546 class Bar {};
549 })cpp");
550 TestTU TU = TestTU::withCode(Test.code());
551 ParsedAST AST = TU.build();
553 EXPECT_TRUE(isDeeplyNested(&findUnqualifiedDecl(AST, "Foo"), /*MaxDepth=*/1));
554 EXPECT_FALSE(
555 isDeeplyNested(&findUnqualifiedDecl(AST, "Foo"), /*MaxDepth=*/2));
557 EXPECT_TRUE(isDeeplyNested(&findUnqualifiedDecl(AST, "bar"), /*MaxDepth=*/2));
558 EXPECT_FALSE(
559 isDeeplyNested(&findUnqualifiedDecl(AST, "bar"), /*MaxDepth=*/3));
561 EXPECT_TRUE(isDeeplyNested(&findUnqualifiedDecl(AST, "Bar"), /*MaxDepth=*/3));
562 EXPECT_FALSE(
563 isDeeplyNested(&findUnqualifiedDecl(AST, "Bar"), /*MaxDepth=*/4));
566 MATCHER_P(attrKind, K, "") { return arg->getKind() == K; }
568 MATCHER(implicitAttr, "") { return arg->isImplicit(); }
570 TEST(ClangdAST, GetAttributes) {
571 const char *Code = R"cpp(
572 class X{};
573 class [[nodiscard]] Y{};
574 void f(int * a, int * __attribute__((nonnull)) b);
575 void foo(bool c) {
576 if (c)
577 [[unlikely]] return;
579 )cpp";
580 ParsedAST AST = TestTU::withCode(Code).build();
581 auto DeclAttrs = [&](llvm::StringRef Name) {
582 return getAttributes(DynTypedNode::create(findUnqualifiedDecl(AST, Name)));
584 // Implicit attributes may be present (e.g. visibility on windows).
585 ASSERT_THAT(DeclAttrs("X"), Each(implicitAttr()));
586 ASSERT_THAT(DeclAttrs("Y"), Contains(attrKind(attr::WarnUnusedResult)));
587 ASSERT_THAT(DeclAttrs("f"), Each(implicitAttr()));
588 ASSERT_THAT(DeclAttrs("a"), Each(implicitAttr()));
589 ASSERT_THAT(DeclAttrs("b"), Contains(attrKind(attr::NonNull)));
591 Stmt *FooBody = cast<FunctionDecl>(findDecl(AST, "foo")).getBody();
592 IfStmt *FooIf = cast<IfStmt>(cast<CompoundStmt>(FooBody)->body_front());
593 ASSERT_THAT(getAttributes(DynTypedNode::create(*FooIf)),
594 Each(implicitAttr()));
595 ASSERT_THAT(getAttributes(DynTypedNode::create(*FooIf->getThen())),
596 Contains(attrKind(attr::Unlikely)));
599 TEST(ClangdAST, HasReservedName) {
600 ParsedAST AST = TestTU::withCode(R"cpp(
601 void __foo();
602 namespace std {
603 inline namespace __1 { class error_code; }
604 namespace __detail { int secret; }
606 )cpp")
607 .build();
609 EXPECT_TRUE(hasReservedName(findUnqualifiedDecl(AST, "__foo")));
610 EXPECT_FALSE(
611 hasReservedScope(*findUnqualifiedDecl(AST, "__foo").getDeclContext()));
613 EXPECT_FALSE(hasReservedName(findUnqualifiedDecl(AST, "error_code")));
614 EXPECT_FALSE(hasReservedScope(
615 *findUnqualifiedDecl(AST, "error_code").getDeclContext()));
617 EXPECT_FALSE(hasReservedName(findUnqualifiedDecl(AST, "secret")));
618 EXPECT_TRUE(
619 hasReservedScope(*findUnqualifiedDecl(AST, "secret").getDeclContext()));
622 TEST(ClangdAST, PreferredIncludeDirective) {
623 auto ComputePreferredDirective = [](TestTU &TU) {
624 auto AST = TU.build();
625 return preferredIncludeDirective(AST.tuPath(), AST.getLangOpts(),
626 AST.getIncludeStructure().MainFileIncludes,
627 AST.getLocalTopLevelDecls());
629 TestTU ObjCTU = TestTU::withCode(R"cpp(
630 int main() {}
631 )cpp");
632 ObjCTU.Filename = "TestTU.m";
633 EXPECT_EQ(ComputePreferredDirective(ObjCTU),
634 Symbol::IncludeDirective::Import);
636 TestTU HeaderTU = TestTU::withCode(R"cpp(
637 #import "TestTU.h"
638 )cpp");
639 HeaderTU.Filename = "TestTUHeader.h";
640 HeaderTU.ExtraArgs = {"-xobjective-c++-header"};
641 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
642 Symbol::IncludeDirective::Import);
644 // ObjC language option is not enough for headers.
645 HeaderTU.Code = R"cpp(
646 #include "TestTU.h"
647 )cpp";
648 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
649 Symbol::IncludeDirective::Include);
651 HeaderTU.Code = R"cpp(
652 @interface Foo
653 @end
655 Foo * getFoo();
656 )cpp";
657 EXPECT_EQ(ComputePreferredDirective(HeaderTU),
658 Symbol::IncludeDirective::Import);
661 } // namespace
662 } // namespace clangd
663 } // namespace clang