xref: /llvm-project/clang/unittests/Interpreter/CodeCompletionTest.cpp (revision 35b366ace73d0ede3cdeeb4d09150a9945750b7f)
1 #include "clang/Interpreter/CodeCompletion.h"
2 #include "clang/Frontend/CompilerInstance.h"
3 #include "clang/Interpreter/Interpreter.h"
4 #include "clang/Lex/Preprocessor.h"
5 #include "clang/Sema/CodeCompleteConsumer.h"
6 #include "clang/Sema/Sema.h"
7 #include "llvm/LineEditor/LineEditor.h"
8 #include "llvm/Support/Error.h"
9 #include "llvm/Support/raw_ostream.h"
10 
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 
14 using namespace clang;
15 namespace {
16 auto CB = clang::IncrementalCompilerBuilder();
17 
18 static std::unique_ptr<Interpreter> createInterpreter() {
19   auto CI = cantFail(CB.CreateCpp());
20   return cantFail(clang::Interpreter::create(std::move(CI)));
21 }
22 
23 static std::vector<std::string> runComp(clang::Interpreter &MainInterp,
24                                         llvm::StringRef Input,
25                                         llvm::Error &ErrR) {
26   auto CI = CB.CreateCpp();
27   if (auto Err = CI.takeError()) {
28     ErrR = std::move(Err);
29     return {};
30   }
31 
32   auto Interp = clang::Interpreter::create(std::move(*CI));
33   if (auto Err = Interp.takeError()) {
34     // log the error and returns an empty vector;
35     ErrR = std::move(Err);
36 
37     return {};
38   }
39 
40   std::vector<std::string> Results;
41   std::vector<std::string> Comps;
42   auto *MainCI = (*Interp)->getCompilerInstance();
43   auto CC = ReplCodeCompleter();
44   CC.codeComplete(MainCI, Input, /* Lines */ 1, Input.size() + 1,
45                   MainInterp.getCompilerInstance(), Results);
46 
47   for (auto Res : Results)
48     if (Res.find(CC.Prefix) == 0)
49       Comps.push_back(Res);
50   return Comps;
51 }
52 
53 #ifdef _AIX
54 TEST(CodeCompletionTest, DISABLED_Sanity) {
55 #else
56 TEST(CodeCompletionTest, Sanity) {
57 #endif
58   auto Interp = createInterpreter();
59   if (auto R = Interp->ParseAndExecute("int foo = 12;")) {
60     consumeError(std::move(R));
61     return;
62   }
63   auto Err = llvm::Error::success();
64   auto comps = runComp(*Interp, "f", Err);
65   EXPECT_EQ((size_t)2, comps.size()); // float and foo
66   EXPECT_EQ(comps[0], std::string("float"));
67   EXPECT_EQ(comps[1], std::string("foo"));
68   EXPECT_EQ((bool)Err, false);
69 }
70 
71 #ifdef _AIX
72 TEST(CodeCompletionTest, DISABLED_SanityNoneValid) {
73 #else
74 TEST(CodeCompletionTest, SanityNoneValid) {
75 #endif
76   auto Interp = createInterpreter();
77   if (auto R = Interp->ParseAndExecute("int foo = 12;")) {
78     consumeError(std::move(R));
79     return;
80   }
81   auto Err = llvm::Error::success();
82   auto comps = runComp(*Interp, "babanana", Err);
83   EXPECT_EQ((size_t)0, comps.size()); // foo and float
84   EXPECT_EQ((bool)Err, false);
85 }
86 
87 #ifdef _AIX
88 TEST(CodeCompletionTest, DISABLED_TwoDecls) {
89 #else
90 TEST(CodeCompletionTest, TwoDecls) {
91 #endif
92   auto Interp = createInterpreter();
93   if (auto R = Interp->ParseAndExecute("int application = 12;")) {
94     consumeError(std::move(R));
95     return;
96   }
97   if (auto R = Interp->ParseAndExecute("int apple = 12;")) {
98     consumeError(std::move(R));
99     return;
100   }
101   auto Err = llvm::Error::success();
102   auto comps = runComp(*Interp, "app", Err);
103   EXPECT_EQ((size_t)2, comps.size());
104   EXPECT_EQ((bool)Err, false);
105 }
106 
107 TEST(CodeCompletionTest, CompFunDeclsNoError) {
108   auto Interp = createInterpreter();
109   auto Err = llvm::Error::success();
110   auto comps = runComp(*Interp, "void app(", Err);
111   EXPECT_EQ((bool)Err, false);
112 }
113 
114 TEST(CodeCompletionTest, TypedDirected) {
115   auto Interp = createInterpreter();
116   if (auto R = Interp->ParseAndExecute("int application = 12;")) {
117     consumeError(std::move(R));
118     return;
119   }
120   if (auto R = Interp->ParseAndExecute("char apple = '2';")) {
121     consumeError(std::move(R));
122     return;
123   }
124   if (auto R = Interp->ParseAndExecute("void add(int &SomeInt){}")) {
125     consumeError(std::move(R));
126     return;
127   }
128   {
129     auto Err = llvm::Error::success();
130     auto comps = runComp(*Interp, std::string("add("), Err);
131     EXPECT_EQ((size_t)1, comps.size());
132     EXPECT_EQ((bool)Err, false);
133   }
134 
135   if (auto R = Interp->ParseAndExecute("int banana = 42;")) {
136     consumeError(std::move(R));
137     return;
138   }
139 
140   {
141     auto Err = llvm::Error::success();
142     auto comps = runComp(*Interp, std::string("add("), Err);
143     EXPECT_EQ((size_t)2, comps.size());
144     EXPECT_EQ(comps[0], "application");
145     EXPECT_EQ(comps[1], "banana");
146     EXPECT_EQ((bool)Err, false);
147   }
148 
149   {
150     auto Err = llvm::Error::success();
151     auto comps = runComp(*Interp, std::string("add(b"), Err);
152     EXPECT_EQ((size_t)1, comps.size());
153     EXPECT_EQ(comps[0], "banana");
154     EXPECT_EQ((bool)Err, false);
155   }
156 }
157 
158 TEST(CodeCompletionTest, SanityClasses) {
159   auto Interp = createInterpreter();
160   if (auto R = Interp->ParseAndExecute("struct Apple{};")) {
161     consumeError(std::move(R));
162     return;
163   }
164   if (auto R = Interp->ParseAndExecute("void takeApple(Apple &a1){}")) {
165     consumeError(std::move(R));
166     return;
167   }
168   if (auto R = Interp->ParseAndExecute("Apple a1;")) {
169     consumeError(std::move(R));
170     return;
171   }
172   if (auto R = Interp->ParseAndExecute("void takeAppleCopy(Apple a1){}")) {
173     consumeError(std::move(R));
174     return;
175   }
176 
177   {
178     auto Err = llvm::Error::success();
179     auto comps = runComp(*Interp, "takeApple(", Err);
180     EXPECT_EQ((size_t)1, comps.size());
181     EXPECT_EQ(comps[0], std::string("a1"));
182     EXPECT_EQ((bool)Err, false);
183   }
184   {
185     auto Err = llvm::Error::success();
186     auto comps = runComp(*Interp, std::string("takeAppleCopy("), Err);
187     EXPECT_EQ((size_t)1, comps.size());
188     EXPECT_EQ(comps[0], std::string("a1"));
189     EXPECT_EQ((bool)Err, false);
190   }
191 }
192 
193 TEST(CodeCompletionTest, SubClassing) {
194   auto Interp = createInterpreter();
195   if (auto R = Interp->ParseAndExecute("struct Fruit {};")) {
196     consumeError(std::move(R));
197     return;
198   }
199   if (auto R = Interp->ParseAndExecute("struct Apple : Fruit{};")) {
200     consumeError(std::move(R));
201     return;
202   }
203   if (auto R = Interp->ParseAndExecute("void takeFruit(Fruit &f){}")) {
204     consumeError(std::move(R));
205     return;
206   }
207   if (auto R = Interp->ParseAndExecute("Apple a1;")) {
208     consumeError(std::move(R));
209     return;
210   }
211   if (auto R = Interp->ParseAndExecute("Fruit f1;")) {
212     consumeError(std::move(R));
213     return;
214   }
215   auto Err = llvm::Error::success();
216   auto comps = runComp(*Interp, std::string("takeFruit("), Err);
217   EXPECT_EQ((size_t)2, comps.size());
218   EXPECT_EQ(comps[0], std::string("a1"));
219   EXPECT_EQ(comps[1], std::string("f1"));
220   EXPECT_EQ((bool)Err, false);
221 }
222 
223 TEST(CodeCompletionTest, MultipleArguments) {
224   auto Interp = createInterpreter();
225   if (auto R = Interp->ParseAndExecute("int foo = 42;")) {
226     consumeError(std::move(R));
227     return;
228   }
229   if (auto R = Interp->ParseAndExecute("char fowl = 'A';")) {
230     consumeError(std::move(R));
231     return;
232   }
233   if (auto R = Interp->ParseAndExecute("void takeTwo(int &a, char b){}")) {
234     consumeError(std::move(R));
235     return;
236   }
237   auto Err = llvm::Error::success();
238   auto comps = runComp(*Interp, std::string("takeTwo(foo,  "), Err);
239   EXPECT_EQ((size_t)1, comps.size());
240   EXPECT_EQ(comps[0], std::string("fowl"));
241   EXPECT_EQ((bool)Err, false);
242 }
243 
244 TEST(CodeCompletionTest, Methods) {
245   auto Interp = createInterpreter();
246   cantFail(Interp->ParseAndExecute(
247       "struct Foo{int add(int a){return 42;} int par(int b){return 42;}};"));
248   cantFail(Interp->ParseAndExecute("Foo f1;"));
249 
250   auto Err = llvm::Error::success();
251   auto comps = runComp(*Interp, std::string("f1."), Err);
252   EXPECT_EQ((size_t)2, comps.size());
253   EXPECT_EQ(comps[0], std::string("add"));
254   EXPECT_EQ(comps[1], std::string("par"));
255   EXPECT_EQ((bool)Err, false);
256 }
257 
258 TEST(CodeCompletionTest, MethodsInvocations) {
259   auto Interp = createInterpreter();
260   cantFail(Interp->ParseAndExecute(
261       "struct Foo{int add(int a){return 42;} int par(int b){return 42;}};"));
262   cantFail(Interp->ParseAndExecute("Foo f1;"));
263   cantFail(Interp->ParseAndExecute("int a = 84;"));
264 
265   auto Err = llvm::Error::success();
266   auto comps = runComp(*Interp, std::string("f1.add("), Err);
267   EXPECT_EQ((size_t)1, comps.size());
268   EXPECT_EQ(comps[0], std::string("a"));
269   EXPECT_EQ((bool)Err, false);
270 }
271 
272 TEST(CodeCompletionTest, NestedInvocations) {
273   auto Interp = createInterpreter();
274   cantFail(Interp->ParseAndExecute(
275       "struct Foo{int add(int a){return 42;} int par(int b){return 42;}};"));
276   cantFail(Interp->ParseAndExecute("Foo f1;"));
277   cantFail(Interp->ParseAndExecute("int a = 84;"));
278   cantFail(Interp->ParseAndExecute("int plus(int a, int b) { return a + b; }"));
279 
280   auto Err = llvm::Error::success();
281   auto comps = runComp(*Interp, std::string("plus(42, f1.add("), Err);
282   EXPECT_EQ((size_t)1, comps.size());
283   EXPECT_EQ(comps[0], std::string("a"));
284   EXPECT_EQ((bool)Err, false);
285 }
286 
287 TEST(CodeCompletionTest, TemplateFunctions) {
288   auto Interp = createInterpreter();
289   cantFail(
290       Interp->ParseAndExecute("template <typename T> T id(T a) { return a;} "));
291   cantFail(Interp->ParseAndExecute("int apple = 84;"));
292   {
293     auto Err = llvm::Error::success();
294     auto comps = runComp(*Interp, std::string("id<int>("), Err);
295     EXPECT_EQ((size_t)1, comps.size());
296     EXPECT_EQ(comps[0], std::string("apple"));
297     EXPECT_EQ((bool)Err, false);
298   }
299 
300   cantFail(Interp->ParseAndExecute(
301       "template <typename T> T pickFirst(T a, T b) { return a;} "));
302   cantFail(Interp->ParseAndExecute("char pear = '4';"));
303   {
304     auto Err = llvm::Error::success();
305     auto comps = runComp(*Interp, std::string("pickFirst(apple, "), Err);
306     EXPECT_EQ((size_t)1, comps.size());
307     EXPECT_EQ(comps[0], std::string("apple"));
308     EXPECT_EQ((bool)Err, false);
309   }
310 }
311 
312 } // anonymous namespace
313