reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
//===--- PrintASTTests.cpp ----------------------------------------- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "AST.h"
#include "Annotations.h"
#include "Protocol.h"
#include "SourceCode.h"
#include "TestTU.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "gmock/gmock.h"
#include "gtest/gtest-param-test.h"
#include "gtest/gtest.h"

namespace clang {
namespace clangd {
namespace {

using ::testing::ElementsAreArray;

struct Case {
  const char *AnnotatedCode;
  std::vector<const char *> Expected;
};
class ASTUtils : public ::testing::Test,
                 public ::testing::WithParamInterface<Case> {};

TEST_P(ASTUtils, PrintTemplateArgs) {
  auto Pair = GetParam();
  Annotations Test(Pair.AnnotatedCode);
  auto AST = TestTU::withCode(Test.code()).build();
  struct Visitor : RecursiveASTVisitor<Visitor> {
    Visitor(std::vector<Position> Points) : Points(std::move(Points)) {}
    bool VisitNamedDecl(const NamedDecl *ND) {
      if (TemplateArgsAtPoints.size() == Points.size())
        return true;
      auto Pos = sourceLocToPosition(ND->getASTContext().getSourceManager(),
                                     ND->getLocation());
      if (Pos != Points[TemplateArgsAtPoints.size()])
        return true;
      TemplateArgsAtPoints.push_back(printTemplateSpecializationArgs(*ND));
      return true;
    }
    std::vector<std::string> TemplateArgsAtPoints;
    const std::vector<Position> Points;
  };
  Visitor V(Test.points());
  V.TraverseDecl(AST.getASTContext().getTranslationUnitDecl());
  EXPECT_THAT(V.TemplateArgsAtPoints, ElementsAreArray(Pair.Expected));
}

INSTANTIATE_TEST_CASE_P(ASTUtilsTests, ASTUtils,
                        ::testing::ValuesIn(std::vector<Case>({
                            {
                                R"cpp(
                                  template <class X> class Bar {};
                                  template <> class ^Bar<double> {};)cpp",
                                {"<double>"}},
                            {
                                R"cpp(
                                  template <class X> class Bar {};
                                  template <class T, class U,
                                  template<typename> class Z, int Q>
                                  struct Foo {};
                                  template struct ^Foo<int, bool, Bar, 8>;
                                  template <typename T>
                                  struct ^Foo<T *, T, Bar, 3> {};)cpp",
                                {"<int, bool, Bar, 8>", "<T *, T, Bar, 3>"}},
                            {
                                R"cpp(
                                  template <int ...> void Foz() {};
                                  template <> void ^Foz<3, 5, 8>() {};)cpp",
                                {"<3, 5, 8>"}},
                            {
                                R"cpp(
                                  template <class X> class Bar {};
                                  template <template <class> class ...>
                                  class Aux {};
                                  template <> class ^Aux<Bar, Bar> {};
                                  template <template <class> T>
                                  class ^Aux<T, T> {};)cpp",
                                {"<Bar, Bar>", "<T, T>"}},
                            {
                                R"cpp(
                                  template <typename T> T var = 1234;
                                  template <> int ^var<int> = 1;)cpp",
                                {"<int>"}},
                            {
                                R"cpp(
                                  template <typename T> struct Foo;
                                  struct Bar { friend class Foo<int>; };
                                  template <> struct ^Foo<int> {};)cpp",
                                {"<int>"}},
                            {
                                R"cpp(
                                  template<class T>
                                  T S = T(10);
                                  template <class T>
                                  int ^S<T*> = 0;
                                  template <>
                                  int ^S<double> = 0;)cpp",
                                {"<T *>", "<double>"}},
                        })),);
} // namespace
} // namespace clangd
} // namespace clang