• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //===----------------------------------------------------------------------===//
8 
9 #include "AST.h"
10 
11 #include "Annotations.h"
12 #include "ParsedAST.h"
13 #include "TestTU.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/DeclBase.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Casting.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include <cstddef>
22 #include <string>
23 #include <vector>
24 
25 namespace clang {
26 namespace clangd {
27 namespace {
28 
TEST(GetDeducedType,KwAutoExpansion)29 TEST(GetDeducedType, KwAutoExpansion) {
30   struct Test {
31     StringRef AnnotatedCode;
32     const char *DeducedType;
33   } Tests[] = {
34       {"^auto i = 0;", "int"},
35       {"^auto f(){ return 1;};", "int"},
36   };
37   for (Test T : Tests) {
38     Annotations File(T.AnnotatedCode);
39     auto AST = TestTU::withCode(File.code()).build();
40     SourceManagerForFile SM("foo.cpp", File.code());
41 
42     for (Position Pos : File.points()) {
43       auto Location = sourceLocationInMainFile(SM.get(), Pos);
44       ASSERT_TRUE(!!Location) << llvm::toString(Location.takeError());
45       auto DeducedType = getDeducedType(AST.getASTContext(), *Location);
46       EXPECT_EQ(DeducedType->getAsString(), T.DeducedType);
47     }
48   }
49 }
50 
TEST(ClangdAST,GetQualification)51 TEST(ClangdAST, GetQualification) {
52   // Tries to insert the decl `Foo` into position of each decl named `insert`.
53   // This is done to get an appropriate DeclContext for the insertion location.
54   // Qualifications are the required nested name specifier to spell `Foo` at the
55   // `insert`ion location.
56   // VisibleNamespaces are assumed to be visible at every insertion location.
57   const struct {
58     llvm::StringRef Test;
59     std::vector<llvm::StringRef> Qualifications;
60     std::vector<std::string> VisibleNamespaces;
61   } Cases[] = {
62       {
63           R"cpp(
64             namespace ns1 { namespace ns2 { class Foo {}; } }
65             void insert(); // ns1::ns2::Foo
66             namespace ns1 {
67               void insert(); // ns2::Foo
68               namespace ns2 {
69                 void insert(); // Foo
70               }
71               using namespace ns2;
72               void insert(); // Foo
73             }
74             using namespace ns1;
75             void insert(); // ns2::Foo
76             using namespace ns2;
77             void insert(); // Foo
78           )cpp",
79           {"ns1::ns2::", "ns2::", "", "", "ns2::", ""},
80           {},
81       },
82       {
83           R"cpp(
84             namespace ns1 { namespace ns2 { class Bar { void Foo(); }; } }
85             void insert(); // ns1::ns2::Bar::Foo
86             namespace ns1 {
87               void insert(); // ns2::Bar::Foo
88               namespace ns2 {
89                 void insert(); // Bar::Foo
90               }
91               using namespace ns2;
92               void insert(); // Bar::Foo
93             }
94             using namespace ns1;
95             void insert(); // ns2::Bar::Foo
96             using namespace ns2;
97             void insert(); // Bar::Foo
98           )cpp",
99           {"ns1::ns2::Bar::", "ns2::Bar::", "Bar::", "Bar::", "ns2::Bar::",
100            "Bar::"},
101           {},
102       },
103       {
104           R"cpp(
105             namespace ns1 { namespace ns2 { void Foo(); } }
106             void insert(); // ns2::Foo
107             namespace ns1 {
108               void insert(); // ns2::Foo
109               namespace ns2 {
110                 void insert(); // Foo
111               }
112             }
113           )cpp",
114           {"ns2::", "ns2::", ""},
115           {"ns1::"},
116       },
117   };
118   for (const auto &Case : Cases) {
119     Annotations Test(Case.Test);
120     TestTU TU = TestTU::withCode(Test.code());
121     ParsedAST AST = TU.build();
122     std::vector<const Decl *> InsertionPoints;
123     const NamedDecl *TargetDecl;
124     findDecl(AST, [&](const NamedDecl &ND) {
125       if (ND.getNameAsString() == "Foo") {
126         TargetDecl = &ND;
127         return true;
128       }
129 
130       if (ND.getNameAsString() == "insert")
131         InsertionPoints.push_back(&ND);
132       return false;
133     });
134 
135     ASSERT_EQ(InsertionPoints.size(), Case.Qualifications.size());
136     for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
137       const Decl *D = InsertionPoints[I];
138       if (Case.VisibleNamespaces.empty()) {
139         EXPECT_EQ(getQualification(AST.getASTContext(),
140                                    D->getLexicalDeclContext(), D->getBeginLoc(),
141                                    TargetDecl),
142                   Case.Qualifications[I]);
143       } else {
144         EXPECT_EQ(getQualification(AST.getASTContext(),
145                                    D->getLexicalDeclContext(), TargetDecl,
146                                    Case.VisibleNamespaces),
147                   Case.Qualifications[I]);
148       }
149     }
150   }
151 }
152 
TEST(ClangdAST,PrintType)153 TEST(ClangdAST, PrintType) {
154   const struct {
155     llvm::StringRef Test;
156     std::vector<llvm::StringRef> Types;
157   } Cases[] = {
158       {
159           R"cpp(
160             namespace ns1 { namespace ns2 { class Foo {}; } }
161             void insert(); // ns1::ns2::Foo
162             namespace ns1 {
163               void insert(); // ns2::Foo
164               namespace ns2 {
165                 void insert(); // Foo
166               }
167             }
168           )cpp",
169           {"ns1::ns2::Foo", "ns2::Foo", "Foo"},
170       },
171       {
172           R"cpp(
173             namespace ns1 {
174               typedef int Foo;
175             }
176             void insert(); // ns1::Foo
177             namespace ns1 {
178               void insert(); // Foo
179             }
180           )cpp",
181           {"ns1::Foo", "Foo"},
182       },
183   };
184   for (const auto &Case : Cases) {
185     Annotations Test(Case.Test);
186     TestTU TU = TestTU::withCode(Test.code());
187     ParsedAST AST = TU.build();
188     std::vector<const DeclContext *> InsertionPoints;
189     const TypeDecl *TargetDecl = nullptr;
190     findDecl(AST, [&](const NamedDecl &ND) {
191       if (ND.getNameAsString() == "Foo") {
192         if (const auto *TD = llvm::dyn_cast<TypeDecl>(&ND)) {
193           TargetDecl = TD;
194           return true;
195         }
196       } else if (ND.getNameAsString() == "insert")
197         InsertionPoints.push_back(ND.getDeclContext());
198       return false;
199     });
200 
201     ASSERT_EQ(InsertionPoints.size(), Case.Types.size());
202     for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
203       const auto *DC = InsertionPoints[I];
204       EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC),
205                 Case.Types[I]);
206     }
207   }
208 }
209 } // namespace
210 } // namespace clangd
211 } // namespace clang
212