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