1 //===--- PrintASTTests.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 #include "Annotations.h"
11 #include "Protocol.h"
12 #include "SourceCode.h"
13 #include "TestTU.h"
14 #include "clang/AST/RecursiveASTVisitor.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest-param-test.h"
17 #include "gtest/gtest.h"
18
19 namespace clang {
20 namespace clangd {
21 namespace {
22
23 using ::testing::ElementsAreArray;
24
25 struct Case {
26 const char *AnnotatedCode;
27 std::vector<const char *> Expected;
28 };
29 class ASTUtils : public ::testing::Test,
30 public ::testing::WithParamInterface<Case> {};
31
TEST_P(ASTUtils,PrintTemplateArgs)32 TEST_P(ASTUtils, PrintTemplateArgs) {
33 auto Pair = GetParam();
34 Annotations Test(Pair.AnnotatedCode);
35 auto AST = TestTU::withCode(Test.code()).build();
36 struct Visitor : RecursiveASTVisitor<Visitor> {
37 Visitor(std::vector<Position> Points) : Points(std::move(Points)) {}
38 bool VisitNamedDecl(const NamedDecl *ND) {
39 if (TemplateArgsAtPoints.size() == Points.size())
40 return true;
41 auto Pos = sourceLocToPosition(ND->getASTContext().getSourceManager(),
42 ND->getLocation());
43 if (Pos != Points[TemplateArgsAtPoints.size()])
44 return true;
45 TemplateArgsAtPoints.push_back(printTemplateSpecializationArgs(*ND));
46 return true;
47 }
48 std::vector<std::string> TemplateArgsAtPoints;
49 const std::vector<Position> Points;
50 };
51 Visitor V(Test.points());
52 V.TraverseDecl(AST.getASTContext().getTranslationUnitDecl());
53 EXPECT_THAT(V.TemplateArgsAtPoints, ElementsAreArray(Pair.Expected));
54 }
55
56 INSTANTIATE_TEST_SUITE_P(ASTUtilsTests, ASTUtils,
57 ::testing::ValuesIn(std::vector<Case>({
58 {
59 R"cpp(
60 template <class X> class Bar {};
61 template <> class ^Bar<double> {};)cpp",
62 {"<double>"}},
63 {
64 R"cpp(
65 template <class X> class Bar {};
66 template <class T, class U,
67 template<typename> class Z, int Q>
68 struct Foo {};
69 template struct ^Foo<int, bool, Bar, 8>;
70 template <typename T>
71 struct ^Foo<T *, T, Bar, 3> {};)cpp",
72 {"<int, bool, Bar, 8>", "<T *, T, Bar, 3>"}},
73 {
74 R"cpp(
75 template <int ...> void Foz() {};
76 template <> void ^Foz<3, 5, 8>() {};)cpp",
77 {"<3, 5, 8>"}},
78 {
79 R"cpp(
80 template <class X> class Bar {};
81 template <template <class> class ...>
82 class Aux {};
83 template <> class ^Aux<Bar, Bar> {};
84 template <template <class> class T>
85 class ^Aux<T, T> {};)cpp",
86 {"<Bar, Bar>", "<T, T>"}},
87 {
88 R"cpp(
89 template <typename T> T var = 1234;
90 template <> int ^var<int> = 1;)cpp",
91 {"<int>"}},
92 {
93 R"cpp(
94 template <typename T> struct Foo;
95 struct Bar { friend class Foo<int>; };
96 template <> struct ^Foo<int> {};)cpp",
97 {"<int>"}},
98 {
99 R"cpp(
100 template<class T>
101 T S = T(10);
102 template <class T>
103 int ^S<T*> = 0;
104 template <>
105 int ^S<double> = 0;)cpp",
106 {"<T *>", "<double>"}},
107 })));
108 } // namespace
109 } // namespace clangd
110 } // namespace clang
111