blob: 421ff11665226a5e64ae44893d5cebe4e0c559e8 [file] [log] [blame]
Haojian Wu10d95c52018-01-17 14:29:25 +00001//=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/Frontend/CompilerInstance.h"
11#include "clang/Frontend/FrontendActions.h"
12#include "clang/Lex/Preprocessor.h"
13#include "clang/Parse/ParseAST.h"
14#include "clang/Sema/Sema.h"
15#include "clang/Sema/SemaDiagnostic.h"
16#include "clang/Tooling/Tooling.h"
Haojian Wu10d95c52018-01-17 14:29:25 +000017#include "gmock/gmock.h"
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000018#include "gtest/gtest.h"
19#include <cstddef>
20#include <string>
Haojian Wu10d95c52018-01-17 14:29:25 +000021
22namespace {
23
24using namespace clang;
25using namespace clang::tooling;
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000026using ::testing::Each;
Haojian Wu10d95c52018-01-17 14:29:25 +000027using ::testing::UnorderedElementsAre;
28
29const char TestCCName[] = "test.cc";
Haojian Wu10d95c52018-01-17 14:29:25 +000030
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000031struct CompletionContext {
32 std::vector<std::string> VisitedNamespaces;
33 std::string PreferredType;
34};
35
36class VisitedContextFinder : public CodeCompleteConsumer {
Haojian Wu10d95c52018-01-17 14:29:25 +000037public:
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000038 VisitedContextFinder(CompletionContext &ResultCtx)
Haojian Wu10d95c52018-01-17 14:29:25 +000039 : CodeCompleteConsumer(/*CodeCompleteOpts=*/{},
40 /*CodeCompleteConsumer*/ false),
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000041 ResultCtx(ResultCtx),
Haojian Wu10d95c52018-01-17 14:29:25 +000042 CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
43
44 void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
45 CodeCompletionResult *Results,
46 unsigned NumResults) override {
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000047 ResultCtx.VisitedNamespaces =
48 getVisitedNamespace(Context.getVisitedContexts());
49 ResultCtx.PreferredType = Context.getPreferredType().getAsString();
Haojian Wu10d95c52018-01-17 14:29:25 +000050 }
51
52 CodeCompletionAllocator &getAllocator() override {
53 return CCTUInfo.getAllocator();
54 }
55
56 CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
57
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000058private:
59 std::vector<std::string> getVisitedNamespace(
60 CodeCompletionContext::VisitedContextSet VisitedContexts) const {
Haojian Wu10d95c52018-01-17 14:29:25 +000061 std::vector<std::string> NSNames;
62 for (const auto *Context : VisitedContexts)
63 if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
64 NSNames.push_back(NS->getQualifiedNameAsString());
65 return NSNames;
66 }
67
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000068 CompletionContext &ResultCtx;
Haojian Wu10d95c52018-01-17 14:29:25 +000069 CodeCompletionTUInfo CCTUInfo;
Haojian Wu10d95c52018-01-17 14:29:25 +000070};
71
72class CodeCompleteAction : public SyntaxOnlyAction {
73public:
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000074 CodeCompleteAction(ParsedSourceLocation P, CompletionContext &ResultCtx)
75 : CompletePosition(std::move(P)), ResultCtx(ResultCtx) {}
Haojian Wu10d95c52018-01-17 14:29:25 +000076
77 bool BeginInvocation(CompilerInstance &CI) override {
78 CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000079 CI.setCodeCompletionConsumer(new VisitedContextFinder(ResultCtx));
Haojian Wu10d95c52018-01-17 14:29:25 +000080 return true;
81 }
82
83private:
84 // 1-based code complete position <Line, Col>;
85 ParsedSourceLocation CompletePosition;
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000086 CompletionContext &ResultCtx;
Haojian Wu10d95c52018-01-17 14:29:25 +000087};
88
89ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
90 Offset = std::min(Code.size(), Offset);
91 StringRef Before = Code.substr(0, Offset);
92 int Lines = Before.count('\n');
93 size_t PrevNL = Before.rfind('\n');
94 size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
95 return {TestCCName, static_cast<unsigned>(Lines + 1),
96 static_cast<unsigned>(Offset - StartOfLine + 1)};
97}
98
Ilya Biryukov4974d75d2018-12-13 16:06:11 +000099CompletionContext runCompletion(StringRef Code, size_t Offset) {
100 CompletionContext ResultCtx;
Haojian Wu10d95c52018-01-17 14:29:25 +0000101 auto Action = llvm::make_unique<CodeCompleteAction>(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000102 offsetToPosition(Code, Offset), ResultCtx);
Roman Lebedev497fd982018-02-27 15:54:55 +0000103 clang::tooling::runToolOnCodeWithArgs(Action.release(), Code, {"-std=c++11"},
Haojian Wu10d95c52018-01-17 14:29:25 +0000104 TestCCName);
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000105 return ResultCtx;
106}
107
108struct ParsedAnnotations {
109 std::vector<size_t> Points;
110 std::string Code;
111};
112
113ParsedAnnotations parseAnnotations(StringRef AnnotatedCode) {
114 ParsedAnnotations R;
115 while (!AnnotatedCode.empty()) {
116 size_t NextPoint = AnnotatedCode.find('^');
117 if (NextPoint == StringRef::npos) {
118 R.Code += AnnotatedCode;
119 AnnotatedCode = "";
120 break;
121 }
122 R.Code += AnnotatedCode.substr(0, NextPoint);
123 R.Points.push_back(R.Code.size());
124
125 AnnotatedCode = AnnotatedCode.substr(NextPoint + 1);
126 }
127 return R;
128}
129
130CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
131 ParsedAnnotations P = parseAnnotations(AnnotatedCode);
132 assert(P.Points.size() == 1 && "expected exactly one annotation point");
133 return runCompletion(P.Code, P.Points.front());
134}
135
136std::vector<std::string> collectPreferredTypes(StringRef AnnotatedCode) {
137 ParsedAnnotations P = parseAnnotations(AnnotatedCode);
138 std::vector<std::string> Types;
139 for (size_t Point : P.Points)
140 Types.push_back(runCompletion(P.Code, Point).PreferredType);
141 return Types;
Haojian Wu10d95c52018-01-17 14:29:25 +0000142}
143
144TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
145 auto VisitedNS = runCodeCompleteOnCode(R"cpp(
146 namespace ns1 {}
147 namespace ns2 {}
148 namespace ns3 {}
149 namespace ns3 { namespace nns3 {} }
150
151 namespace foo {
152 using namespace ns1;
153 namespace ns4 {} // not visited
154 namespace { using namespace ns2; }
155 inline namespace bar { using namespace ns3::nns3; }
156 } // foo
157 namespace ns { foo::^ }
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000158 )cpp")
159 .VisitedNamespaces;
Haojian Wu10d95c52018-01-17 14:29:25 +0000160 EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
161 "foo::(anonymous)"));
162}
163
164TEST(SemaCodeCompleteTest, VisitedNSForInvalideQualifiedId) {
165 auto VisitedNS = runCodeCompleteOnCode(R"cpp(
166 namespace ns { foo::^ }
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000167 )cpp")
168 .VisitedNamespaces;
Haojian Wu10d95c52018-01-17 14:29:25 +0000169 EXPECT_TRUE(VisitedNS.empty());
170}
171
Eric Liuf5ba09f2018-07-04 10:01:18 +0000172TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
173 auto VisitedNS = runCodeCompleteOnCode(R"cpp(
174 namespace n1 {
175 namespace n2 {
176 void f(^) {}
177 }
178 }
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000179 )cpp")
180 .VisitedNamespaces;
Eric Liuf5ba09f2018-07-04 10:01:18 +0000181 EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));
182}
183
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000184TEST(PreferredTypeTest, BinaryExpr) {
185 // Check various operations for arithmetic types.
David Green0250e292018-12-13 17:20:06 +0000186 StringRef code1 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000187 void test(int x) {
188 x = ^10;
189 x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
190 x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
David Green0250e292018-12-13 17:20:06 +0000191 })cpp";
192 EXPECT_THAT(collectPreferredTypes(code1), Each("int"));
193 StringRef code2 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000194 void test(float x) {
195 x = ^10;
196 x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
197 x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
David Green0250e292018-12-13 17:20:06 +0000198 })cpp";
199 EXPECT_THAT(collectPreferredTypes(code2), Each("float"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000200
201 // Pointer types.
David Green0250e292018-12-13 17:20:06 +0000202 StringRef code3 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000203 void test(int *ptr) {
204 ptr - ^ptr;
205 ptr = ^ptr;
David Green0250e292018-12-13 17:20:06 +0000206 })cpp";
207 EXPECT_THAT(collectPreferredTypes(code3), Each("int *"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000208
David Green0250e292018-12-13 17:20:06 +0000209 StringRef code4 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000210 void test(int *ptr) {
211 ptr + ^10;
212 ptr += ^10;
213 ptr -= ^10;
David Green0250e292018-12-13 17:20:06 +0000214 })cpp";
215 EXPECT_THAT(collectPreferredTypes(code4), Each("long")); // long is normalized 'ptrdiff_t'.
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000216
217 // Comparison operators.
David Green0250e292018-12-13 17:20:06 +0000218 StringRef code5 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000219 void test(int i) {
220 i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;
221 }
David Green0250e292018-12-13 17:20:06 +0000222 )cpp";
223 EXPECT_THAT(collectPreferredTypes(code5), Each("int"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000224
David Green0250e292018-12-13 17:20:06 +0000225 StringRef code6 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000226 void test(int *ptr) {
227 ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;
228 ptr == ^ptr; ptr != ^ptr;
229 }
David Green0250e292018-12-13 17:20:06 +0000230 )cpp";
231 EXPECT_THAT(collectPreferredTypes(code6), Each("int *"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000232
233 // Relational operations.
David Green0250e292018-12-13 17:20:06 +0000234 StringRef code7 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000235 void test(int i, int *ptr) {
236 i && ^1; i || ^1;
237 ptr && ^1; ptr || ^1;
238 }
David Green0250e292018-12-13 17:20:06 +0000239 )cpp";
240 EXPECT_THAT(collectPreferredTypes(code7), Each("_Bool"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000241
242 // Bitwise operations.
David Green0250e292018-12-13 17:20:06 +0000243 StringRef code8 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000244 void test(long long ll) {
245 ll | ^1; ll & ^1;
246 }
David Green0250e292018-12-13 17:20:06 +0000247 )cpp";
248 EXPECT_THAT(collectPreferredTypes(code8), Each("long long"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000249
David Green0250e292018-12-13 17:20:06 +0000250 StringRef code9 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000251 enum A {};
252 void test(A a) {
253 a | ^1; a & ^1;
254 }
David Green0250e292018-12-13 17:20:06 +0000255 )cpp";
256 EXPECT_THAT(collectPreferredTypes(code9), Each("enum A"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000257
David Green0250e292018-12-13 17:20:06 +0000258 StringRef code10 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000259 enum class A {};
260 void test(A a) {
261 // This is technically illegal with the 'enum class' without overloaded
262 // operators, but we pretend it's fine.
263 a | ^a; a & ^a;
264 }
David Green0250e292018-12-13 17:20:06 +0000265 )cpp";
266 EXPECT_THAT(collectPreferredTypes(code10), Each("enum A"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000267
268 // Binary shifts.
David Green0250e292018-12-13 17:20:06 +0000269 StringRef code11 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000270 void test(int i, long long ll) {
271 i << ^1; ll << ^1;
272 i <<= ^1; i <<= ^1;
273 i >> ^1; ll >> ^1;
274 i >>= ^1; i >>= ^1;
275 }
David Green0250e292018-12-13 17:20:06 +0000276 )cpp";
277 EXPECT_THAT(collectPreferredTypes(code11), Each("int"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000278
279 // Comma does not provide any useful information.
David Green0250e292018-12-13 17:20:06 +0000280 StringRef code12 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000281 class Cls {};
282 void test(int i, int* ptr, Cls x) {
283 (i, ^i);
284 (ptr, ^ptr);
285 (x, ^x);
286 }
David Green0250e292018-12-13 17:20:06 +0000287 )cpp";
288 EXPECT_THAT(collectPreferredTypes(code12), Each("NULL TYPE"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000289
290 // User-defined types do not take operator overloading into account.
291 // However, they provide heuristics for some common cases.
David Green0250e292018-12-13 17:20:06 +0000292 StringRef code13 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000293 class Cls {};
294 void test(Cls c) {
295 // we assume arithmetic and comparions ops take the same type.
296 c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;
297 c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;
298 // same for the assignments.
299 c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;
300 }
David Green0250e292018-12-13 17:20:06 +0000301 )cpp";
302 EXPECT_THAT(collectPreferredTypes(code13), Each("class Cls"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000303
David Green0250e292018-12-13 17:20:06 +0000304 StringRef code14 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000305 class Cls {};
306 void test(Cls c) {
307 // we assume relational ops operate on bools.
308 c && ^c; c || ^c;
309 }
David Green0250e292018-12-13 17:20:06 +0000310 )cpp";
311 EXPECT_THAT(collectPreferredTypes(code14), Each("_Bool"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000312
David Green0250e292018-12-13 17:20:06 +0000313 StringRef code15 = R"cpp(
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000314 class Cls {};
315 void test(Cls c) {
316 // we make no assumptions about the following operators, since they are
317 // often overloaded with a non-standard meaning.
318 c << ^c; c >> ^c; c | ^c; c & ^c;
319 c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;
320 }
David Green0250e292018-12-13 17:20:06 +0000321 )cpp";
322 EXPECT_THAT(collectPreferredTypes(code15), Each("NULL TYPE"));
Ilya Biryukov4974d75d2018-12-13 16:06:11 +0000323}
324
Haojian Wu10d95c52018-01-17 14:29:25 +0000325} // namespace