1 //===- unittests/Interpreter/CodeCompletionTest.cpp -----------------------===// 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 "InterpreterTestFixture.h" 10 11 #include "clang/Interpreter/CodeCompletion.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/Interpreter/Interpreter.h" 14 #include "clang/Lex/Preprocessor.h" 15 #include "clang/Sema/CodeCompleteConsumer.h" 16 #include "clang/Sema/Sema.h" 17 #include "llvm/LineEditor/LineEditor.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 #include "gmock/gmock.h" 21 #include "gtest/gtest.h" 22 23 using namespace clang; 24 namespace { 25 auto CB = clang::IncrementalCompilerBuilder(); 26 27 class CodeCompletionTest : public InterpreterTestBase { 28 public: 29 std::unique_ptr<clang::Interpreter> Interp; 30 31 void SetUp() override { 32 if (!HostSupportsJIT()) 33 GTEST_SKIP(); 34 std::unique_ptr<CompilerInstance> CI = cantFail(CB.CreateCpp()); 35 this->Interp = cantFail(clang::Interpreter::create(std::move(CI))); 36 } 37 38 std::vector<std::string> runComp(llvm::StringRef Input, llvm::Error &ErrR) { 39 auto ComplCI = CB.CreateCpp(); 40 if (auto Err = ComplCI.takeError()) { 41 ErrR = std::move(Err); 42 return {}; 43 } 44 45 auto ComplInterp = clang::Interpreter::create(std::move(*ComplCI)); 46 if (auto Err = ComplInterp.takeError()) { 47 ErrR = std::move(Err); 48 return {}; 49 } 50 51 std::vector<std::string> Results; 52 std::vector<std::string> Comps; 53 auto *ParentCI = this->Interp->getCompilerInstance(); 54 auto *MainCI = (*ComplInterp)->getCompilerInstance(); 55 auto CC = ReplCodeCompleter(); 56 CC.codeComplete(MainCI, Input, /* Lines */ 1, Input.size() + 1, ParentCI, 57 Results); 58 59 for (auto Res : Results) 60 if (Res.find(CC.Prefix) == 0) 61 Comps.push_back(Res); 62 return Comps; 63 } 64 }; 65 66 TEST_F(CodeCompletionTest, Sanity) { 67 cantFail(Interp->Parse("int foo = 12;")); 68 auto Err = llvm::Error::success(); 69 auto comps = runComp("f", Err); 70 EXPECT_EQ((size_t)2, comps.size()); // float and foo 71 EXPECT_EQ(comps[0], std::string("float")); 72 EXPECT_EQ(comps[1], std::string("foo")); 73 EXPECT_EQ((bool)Err, false); 74 } 75 76 TEST_F(CodeCompletionTest, SanityNoneValid) { 77 cantFail(Interp->Parse("int foo = 12;")); 78 auto Err = llvm::Error::success(); 79 auto comps = runComp("babanana", Err); 80 EXPECT_EQ((size_t)0, comps.size()); // foo and float 81 EXPECT_EQ((bool)Err, false); 82 } 83 84 TEST_F(CodeCompletionTest, TwoDecls) { 85 cantFail(Interp->Parse("int application = 12;")); 86 cantFail(Interp->Parse("int apple = 12;")); 87 auto Err = llvm::Error::success(); 88 auto comps = runComp("app", Err); 89 EXPECT_EQ((size_t)2, comps.size()); 90 EXPECT_EQ((bool)Err, false); 91 } 92 93 TEST_F(CodeCompletionTest, CompFunDeclsNoError) { 94 auto Err = llvm::Error::success(); 95 auto comps = runComp("void app(", Err); 96 EXPECT_EQ((bool)Err, false); 97 } 98 99 TEST_F(CodeCompletionTest, TypedDirected) { 100 cantFail(Interp->Parse("int application = 12;")); 101 cantFail(Interp->Parse("char apple = '2';")); 102 cantFail(Interp->Parse("void add(int &SomeInt){}")); 103 { 104 auto Err = llvm::Error::success(); 105 auto comps = runComp(std::string("add("), Err); 106 EXPECT_EQ((size_t)1, comps.size()); 107 EXPECT_EQ((bool)Err, false); 108 } 109 110 cantFail(Interp->Parse("int banana = 42;")); 111 112 { 113 auto Err = llvm::Error::success(); 114 auto comps = runComp(std::string("add("), Err); 115 EXPECT_EQ((size_t)2, comps.size()); 116 EXPECT_EQ(comps[0], "application"); 117 EXPECT_EQ(comps[1], "banana"); 118 EXPECT_EQ((bool)Err, false); 119 } 120 121 { 122 auto Err = llvm::Error::success(); 123 auto comps = runComp(std::string("add(b"), Err); 124 EXPECT_EQ((size_t)1, comps.size()); 125 EXPECT_EQ(comps[0], "banana"); 126 EXPECT_EQ((bool)Err, false); 127 } 128 } 129 130 TEST_F(CodeCompletionTest, SanityClasses) { 131 cantFail(Interp->Parse("struct Apple{};")); 132 cantFail(Interp->Parse("void takeApple(Apple &a1){}")); 133 cantFail(Interp->Parse("Apple a1;")); 134 cantFail(Interp->Parse("void takeAppleCopy(Apple a1){}")); 135 136 { 137 auto Err = llvm::Error::success(); 138 auto comps = runComp("takeApple(", Err); 139 EXPECT_EQ((size_t)1, comps.size()); 140 EXPECT_EQ(comps[0], std::string("a1")); 141 EXPECT_EQ((bool)Err, false); 142 } 143 { 144 auto Err = llvm::Error::success(); 145 auto comps = runComp(std::string("takeAppleCopy("), Err); 146 EXPECT_EQ((size_t)1, comps.size()); 147 EXPECT_EQ(comps[0], std::string("a1")); 148 EXPECT_EQ((bool)Err, false); 149 } 150 } 151 152 TEST_F(CodeCompletionTest, SubClassing) { 153 cantFail(Interp->Parse("struct Fruit {};")); 154 cantFail(Interp->Parse("struct Apple : Fruit{};")); 155 cantFail(Interp->Parse("void takeFruit(Fruit &f){}")); 156 cantFail(Interp->Parse("Apple a1;")); 157 cantFail(Interp->Parse("Fruit f1;")); 158 auto Err = llvm::Error::success(); 159 auto comps = runComp(std::string("takeFruit("), Err); 160 EXPECT_EQ((size_t)2, comps.size()); 161 EXPECT_EQ(comps[0], std::string("a1")); 162 EXPECT_EQ(comps[1], std::string("f1")); 163 EXPECT_EQ((bool)Err, false); 164 } 165 166 TEST_F(CodeCompletionTest, MultipleArguments) { 167 cantFail(Interp->Parse("int foo = 42;")); 168 cantFail(Interp->Parse("char fowl = 'A';")); 169 cantFail(Interp->Parse("void takeTwo(int &a, char b){}")); 170 auto Err = llvm::Error::success(); 171 auto comps = runComp(std::string("takeTwo(foo, "), Err); 172 EXPECT_EQ((size_t)1, comps.size()); 173 EXPECT_EQ(comps[0], std::string("fowl")); 174 EXPECT_EQ((bool)Err, false); 175 } 176 177 TEST_F(CodeCompletionTest, Methods) { 178 cantFail(Interp->Parse( 179 "struct Foo{int add(int a){return 42;} int par(int b){return 42;}};")); 180 cantFail(Interp->Parse("Foo f1;")); 181 182 auto Err = llvm::Error::success(); 183 auto comps = runComp(std::string("f1."), Err); 184 EXPECT_EQ((size_t)2, comps.size()); 185 EXPECT_EQ(comps[0], std::string("add")); 186 EXPECT_EQ(comps[1], std::string("par")); 187 EXPECT_EQ((bool)Err, false); 188 } 189 190 TEST_F(CodeCompletionTest, MethodsInvocations) { 191 cantFail(Interp->Parse( 192 "struct Foo{int add(int a){return 42;} int par(int b){return 42;}};")); 193 cantFail(Interp->Parse("Foo f1;")); 194 cantFail(Interp->Parse("int a = 84;")); 195 196 auto Err = llvm::Error::success(); 197 auto comps = runComp(std::string("f1.add("), Err); 198 EXPECT_EQ((size_t)1, comps.size()); 199 EXPECT_EQ(comps[0], std::string("a")); 200 EXPECT_EQ((bool)Err, false); 201 } 202 203 TEST_F(CodeCompletionTest, NestedInvocations) { 204 cantFail(Interp->Parse( 205 "struct Foo{int add(int a){return 42;} int par(int b){return 42;}};")); 206 cantFail(Interp->Parse("Foo f1;")); 207 cantFail(Interp->Parse("int a = 84;")); 208 cantFail(Interp->Parse("int plus(int a, int b) { return a + b; }")); 209 210 auto Err = llvm::Error::success(); 211 auto comps = runComp(std::string("plus(42, f1.add("), Err); 212 EXPECT_EQ((size_t)1, comps.size()); 213 EXPECT_EQ(comps[0], std::string("a")); 214 EXPECT_EQ((bool)Err, false); 215 } 216 217 TEST_F(CodeCompletionTest, TemplateFunctions) { 218 cantFail( 219 Interp->Parse("template <typename T> T id(T a) { return a;} ")); 220 cantFail(Interp->Parse("int apple = 84;")); 221 { 222 auto Err = llvm::Error::success(); 223 auto comps = runComp(std::string("id<int>("), Err); 224 EXPECT_EQ((size_t)1, comps.size()); 225 EXPECT_EQ(comps[0], std::string("apple")); 226 EXPECT_EQ((bool)Err, false); 227 } 228 229 cantFail(Interp->Parse( 230 "template <typename T> T pickFirst(T a, T b) { return a;} ")); 231 cantFail(Interp->Parse("char pear = '4';")); 232 { 233 auto Err = llvm::Error::success(); 234 auto comps = runComp(std::string("pickFirst(apple, "), Err); 235 EXPECT_EQ((size_t)1, comps.size()); 236 EXPECT_EQ(comps[0], std::string("apple")); 237 EXPECT_EQ((bool)Err, false); 238 } 239 } 240 241 } // anonymous namespace 242