File: XRefsTests.cpp

package info (click to toggle)
llvm-toolchain-6.0 1%3A6.0.1-10
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 598,080 kB
  • sloc: cpp: 3,046,253; ansic: 595,057; asm: 271,965; python: 128,926; objc: 106,554; sh: 21,906; lisp: 10,191; pascal: 6,094; ml: 5,544; perl: 5,265; makefile: 2,227; cs: 2,027; xml: 686; php: 212; csh: 117
file content (218 lines) | stat: -rw-r--r-- 5,545 bytes parent folder | download
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//===-- XRefsTests.cpp  ---------------------------*- C++ -*--------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Annotations.h"
#include "ClangdUnit.h"
#include "Matchers.h"
#include "XRefs.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Frontend/Utils.h"
#include "llvm/Support/Path.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace clang {
namespace clangd {
using namespace llvm;

void PrintTo(const DocumentHighlight &V, std::ostream *O) {
  llvm::raw_os_ostream OS(*O);
  OS << V.range;
  if (V.kind == DocumentHighlightKind::Read)
    OS << "(r)";
  if (V.kind == DocumentHighlightKind::Write)
    OS << "(w)";
}

namespace {
using testing::ElementsAre;
using testing::Field;
using testing::Matcher;
using testing::UnorderedElementsAreArray;

// FIXME: this is duplicated with FileIndexTests. Share it.
ParsedAST build(StringRef Code) {
  auto CI = createInvocationFromCommandLine({"clang", "-xc++", "Foo.cpp"});
  auto Buf = MemoryBuffer::getMemBuffer(Code);
  auto AST = ParsedAST::Build(
      Context::empty(), std::move(CI), nullptr, std::move(Buf),
      std::make_shared<PCHContainerOperations>(), vfs::getRealFileSystem());
  assert(AST.hasValue());
  return std::move(*AST);
}

// Extracts ranges from an annotated example, and constructs a matcher for a
// highlight set. Ranges should be named $read/$write as appropriate.
Matcher<const std::vector<DocumentHighlight> &>
HighlightsFrom(const Annotations &Test) {
  std::vector<DocumentHighlight> Expected;
  auto Add = [&](const Range &R, DocumentHighlightKind K) {
    Expected.emplace_back();
    Expected.back().range = R;
    Expected.back().kind = K;
  };
  for (const auto &Range : Test.ranges())
    Add(Range, DocumentHighlightKind::Text);
  for (const auto &Range : Test.ranges("read"))
    Add(Range, DocumentHighlightKind::Read);
  for (const auto &Range : Test.ranges("write"))
    Add(Range, DocumentHighlightKind::Write);
  return UnorderedElementsAreArray(Expected);
}

TEST(HighlightsTest, All) {
  const char *Tests[] = {
      R"cpp(// Local variable
        int main() {
          int [[bonjour]];
          $write[[^bonjour]] = 2;
          int test1 = $read[[bonjour]];
        }
      )cpp",

      R"cpp(// Struct
        namespace ns1 {
        struct [[MyClass]] {
          static void foo([[MyClass]]*) {}
        };
        } // namespace ns1
        int main() {
          ns1::[[My^Class]]* Params;
        }
      )cpp",

      R"cpp(// Function
        int [[^foo]](int) {}
        int main() {
          [[foo]]([[foo]](42));
          auto *X = &[[foo]];
        }
      )cpp",
  };
  for (const char *Test : Tests) {
    Annotations T(Test);
    auto AST = build(T.code());
    EXPECT_THAT(findDocumentHighlights(Context::empty(), AST, T.point()),
                HighlightsFrom(T))
        << Test;
  }
}

MATCHER_P(RangeIs, R, "") { return arg.range == R; }

TEST(GoToDefinition, All) {
  const char *Tests[] = {
      R"cpp(// Local variable
        int main() {
          [[int bonjour]];
          ^bonjour = 2;
          int test1 = bonjour;
        }
      )cpp",

      R"cpp(// Struct
        namespace ns1 {
        [[struct MyClass {}]];
        } // namespace ns1
        int main() {
          ns1::My^Class* Params;
        }
      )cpp",

      R"cpp(// Function definition via pointer
        [[int foo(int) {}]]
        int main() {
          auto *X = &^foo;
        }
      )cpp",

      R"cpp(// Function declaration via call
        [[int foo(int)]];
        int main() {
          return ^foo(42);
        }
      )cpp",

      R"cpp(// Field
        struct Foo { [[int x]]; };
        int main() {
          Foo bar;
          bar.^x;
        }
      )cpp",

      R"cpp(// Field, member initializer
        struct Foo {
          [[int x]];
          Foo() : ^x(0) {}
        };
      )cpp",

      R"cpp(// Field, GNU old-style field designator
        struct Foo { [[int x]]; };
        int main() {
          Foo bar = { ^x : 1 };
        }
      )cpp",

      R"cpp(// Field, field designator
        struct Foo { [[int x]]; };
        int main() {
          Foo bar = { .^x = 2 };
        }
      )cpp",

      R"cpp(// Method call
        struct Foo { [[int x()]]; };
        int main() {
          Foo bar;
          bar.^x();
        }
      )cpp",

      R"cpp(// Typedef
        [[typedef int Foo]];
        int main() {
          ^Foo bar;
        }
      )cpp",

      /* FIXME: clangIndex doesn't handle template type parameters
      R"cpp(// Template type parameter
        template <[[typename T]]>
        void foo() { ^T t; }
      )cpp", */

      R"cpp(// Namespace
        [[namespace ns {
        struct Foo { static void bar(); }
        }]] // namespace ns
        int main() { ^ns::Foo::bar(); }
      )cpp",

      R"cpp(// Macro
        #define MACRO 0
        #define [[MACRO 1]]
        int main() { return ^MACRO; }
        #define MACRO 2
        #undef macro
      )cpp",
  };
  for (const char *Test : Tests) {
    Annotations T(Test);
    auto AST = build(T.code());
    EXPECT_THAT(findDefinitions(Context::empty(), AST, T.point()),
                ElementsAre(RangeIs(T.range())))
        << Test;
  }
}

} // namespace
} // namespace clangd
} // namespace clang