Skip to content

[ClangRepl] Type Directed Code Completion #67349

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 23, 2023
Merged

Conversation

capfredf
Copy link
Contributor

Differential Revision: https://reviews.llvm.org/D159128

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 25, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 25, 2023

@llvm/pr-subscribers-clang

Changes

Differential Revision: https://reviews.llvm.org/D159128


Patch is 20.30 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/67349.diff

5 Files Affected:

  • (modified) clang/include/clang/Interpreter/CodeCompletion.h (+7-3)
  • (modified) clang/lib/Interpreter/CodeCompletion.cpp (+127-20)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+4)
  • (modified) clang/tools/clang-repl/ClangRepl.cpp (+7-15)
  • (modified) clang/unittests/Interpreter/CodeCompletionTest.cpp (+185-10)
diff --git a/clang/include/clang/Interpreter/CodeCompletion.h b/clang/include/clang/Interpreter/CodeCompletion.h
index 9adcdf0dc3afac6..d78072cec1a2666 100644
--- a/clang/include/clang/Interpreter/CodeCompletion.h
+++ b/clang/include/clang/Interpreter/CodeCompletion.h
@@ -23,8 +23,12 @@ namespace clang {
 class CodeCompletionResult;
 class CompilerInstance;
 
-void codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content,
-                  unsigned Line, unsigned Col, const CompilerInstance *ParentCI,
-                  std::vector<std::string> &CCResults);
+struct ReplCodeCompletion {
+  ReplCodeCompletion() = default;
+  std::string Prefix;
+  void codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content,
+                    unsigned Line, unsigned Col, const CompilerInstance *ParentCI,
+                    std::vector<std::string> &CCResults);
+};
 } // namespace clang
 #endif
diff --git a/clang/lib/Interpreter/CodeCompletion.cpp b/clang/lib/Interpreter/CodeCompletion.cpp
index c40e11b9d1ece0a..9c812c28f677726 100644
--- a/clang/lib/Interpreter/CodeCompletion.cpp
+++ b/clang/lib/Interpreter/CodeCompletion.cpp
@@ -23,6 +23,9 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/CodeCompleteOptions.h"
 #include "clang/Sema/Sema.h"
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "REPLCC"
+
 
 namespace clang {
 
@@ -37,12 +40,22 @@ clang::CodeCompleteOptions getClangCompleteOpts() {
   return Opts;
 }
 
+class CodeCompletionSubContext {
+public:
+  virtual ~CodeCompletionSubContext(){};
+  virtual void
+  HandleCodeCompleteResults(class Sema &S, CodeCompletionResult *InResults,
+                            unsigned NumResults,
+                            std::vector<std::string> &Results) = 0;
+};
+
 class ReplCompletionConsumer : public CodeCompleteConsumer {
 public:
-  ReplCompletionConsumer(std::vector<std::string> &Results)
+  ReplCompletionConsumer(std::vector<std::string> &Results, ReplCodeCompletion& CC)
       : CodeCompleteConsumer(getClangCompleteOpts()),
         CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
-        CCTUInfo(CCAllocator), Results(Results){};
+        CCTUInfo(CCAllocator), Results(Results), CC(CC) {
+ }
 
   void ProcessCodeCompleteResults(class Sema &S, CodeCompletionContext Context,
                                   CodeCompletionResult *InResults,
@@ -56,26 +69,90 @@ class ReplCompletionConsumer : public CodeCompleteConsumer {
   std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
   CodeCompletionTUInfo CCTUInfo;
   std::vector<std::string> &Results;
+  ReplCodeCompletion& CC;
 };
 
 void ReplCompletionConsumer::ProcessCodeCompleteResults(
     class Sema &S, CodeCompletionContext Context,
     CodeCompletionResult *InResults, unsigned NumResults) {
-  for (unsigned I = 0; I < NumResults; ++I) {
-    auto &Result = InResults[I];
-    switch (Result.Kind) {
-    case CodeCompletionResult::RK_Declaration:
-      if (auto *ID = Result.Declaration->getIdentifier()) {
-        Results.push_back(ID->getName().str());
+
+  // auto& a = S.Context.Idents.get("f1");
+  // LLVM_DEBUG(llvm::dbgs() << "\n FFFFF111111 : " << a.getName() << "\n" );
+  auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
+  CC.Prefix = Prefix;
+  switch (Context.getKind()) {
+  case CodeCompletionContext::CCC_DotMemberAccess: {
+    // FIXME: check BaseType is dependent, or from a typo
+    auto BaseType = Context.getBaseType();
+    LLVM_DEBUG(llvm::dbgs() << "BaseType : " <<  BaseType.getAsString() << "\n" );
+    for (unsigned I = 0; I < NumResults; ++I) {
+      auto &Result = InResults[I];
+      switch (Result.Kind) {
+      case CodeCompletionResult::RK_Declaration:
+        if (auto *ID = Result.Declaration->getIdentifier()) {
+          if (const auto *Fun = llvm::dyn_cast<CXXMethodDecl>(Result.Declaration)) {
+            if (Fun->getParent()->getCanonicalDecl() == BaseType->getAsCXXRecordDecl()->getCanonicalDecl()) {
+              LLVM_DEBUG(llvm::dbgs() << "[In HandleCodeCompleteDOT] Name : " << ID->getName() << "\n");
+              Results.push_back(ID->getName().str());
+            }
+          }
+        }
+        break;
+      default:
+        break;
       }
-      break;
-    case CodeCompletionResult::RK_Keyword:
-      Results.push_back(Result.Keyword);
-      break;
-    default:
-      break;
     }
+    break;
   }
+  default:
+    auto PreferredType = Context.getPreferredType();
+    for (unsigned I = 0; I < NumResults; I++) {
+      auto &Result = InResults[I];
+      switch (Result.Kind) {
+      case CodeCompletionResult::RK_Declaration:
+        if (Result.Hidden) {
+          break;
+        }
+        if (!Result.Declaration->getDeclName().isIdentifier() || !Result.Declaration->getName().startswith(Prefix)) {
+          break;
+        }
+        if (!PreferredType.isNull()) {
+          if (auto* VD  = dyn_cast<VarDecl>(Result.Declaration)) {
+            auto ArgumentType = VD->getType();
+            if (PreferredType->isReferenceType()) {
+              QualType RT = PreferredType->castAs<ReferenceType>()->getPointeeType();
+              Sema::ReferenceConversions RefConv;
+              Sema::ReferenceCompareResult RefRelationship =
+                S.CompareReferenceRelationship(SourceLocation(), RT, ArgumentType,
+                                               &RefConv);
+              switch (RefRelationship) {
+              case Sema::Ref_Compatible:
+              case Sema::Ref_Related:
+                Results.push_back(VD->getName().str());
+                break;
+              case Sema::Ref_Incompatible:
+                break;
+              }
+            } else if (S.Context.hasSameType(ArgumentType, PreferredType)) {
+              Results.push_back(VD->getName().str());
+            }
+          }
+        } else
+          Results.push_back(Result.Declaration->getName().str());
+        break;
+      case CodeCompletionResult::RK_Keyword:
+        // add keyword to the completion results only if we are in a type-aware situation.
+        if (!Context.getBaseType().isNull() || !PreferredType.isNull())
+          break;
+        if (StringRef(Result.Keyword).startswith(Prefix))
+          Results.push_back(Result.Keyword);
+        break;
+      default:
+        break;
+      }
+    }
+  }
+  std::sort(Results.begin(), Results.end());
 }
 
 class IncrementalSyntaxOnlyAction : public SyntaxOnlyAction {
@@ -101,8 +178,8 @@ class ExternalSource : public clang::ExternalASTSource {
                  ASTContext &ParentASTCtxt, FileManager &ParentFM);
   bool FindExternalVisibleDeclsByName(const DeclContext *DC,
                                       DeclarationName Name) override;
-  void
-  completeVisibleDeclsMap(const clang::DeclContext *childDeclContext) override;
+  // void CompleteType(TagDecl *Tag) override;
+  void completeVisibleDeclsMap(const clang::DeclContext *childDeclContext) override;
 };
 
 // This method is intended to set up `ExternalASTSource` to the running
@@ -134,6 +211,7 @@ ExternalSource::ExternalSource(ASTContext &ChildASTCtxt, FileManager &ChildFM,
 
 bool ExternalSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
                                                     DeclarationName Name) {
+
   IdentifierTable &ParentIdTable = ParentASTCtxt.Idents;
 
   auto ParentDeclName =
@@ -148,6 +226,10 @@ bool ExternalSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
   return false;
 }
 
+// void ExternalSource::CompleteType(TagDecl *Tag) {
+//   LLVM_DEBUG(llvm::dbgs() << "\n CompleteType " << Tag->getName() << ":\n");
+// }
+
 void ExternalSource::completeVisibleDeclsMap(
     const DeclContext *ChildDeclContext) {
   assert(ChildDeclContext && ChildDeclContext == ChildTUDeclCtxt &&
@@ -162,12 +244,36 @@ void ExternalSource::completeVisibleDeclsMap(
       if (NamedDecl *Decl = llvm::dyn_cast<NamedDecl>(IDeclContext)) {
         if (auto DeclOrErr = Importer->Import(Decl)) {
           if (NamedDecl *importedNamedDecl =
-                  llvm::dyn_cast<NamedDecl>(*DeclOrErr)) {
+              llvm::dyn_cast<NamedDecl>(*DeclOrErr)) {
+            // LLVM_DEBUG(llvm::dbgs() << "\nImporting : " << importedNamedDecl->getName() << "\n");
             SetExternalVisibleDeclsForName(ChildDeclContext,
                                            importedNamedDecl->getDeclName(),
                                            importedNamedDecl);
-          }
+              if (auto *Record =  llvm::dyn_cast<CXXRecordDecl>(importedNamedDecl)) {
+                if (auto Err = Importer->ImportDefinition(Decl))
+                  consumeError(std::move(Err));
+                // LLVM_DEBUG(llvm::dbgs() << "\nHello :\n");
+                // Record->getTypeForDecl()->dump();
+                Record->setHasLoadedFieldsFromExternalStorage(true);
+                // auto ToOrErr = Importer->Import(->getTypeForDecl());
+                // if (!ToOrErr) {
+                //   consumeError(std::move(ToOrErr.takeError()));
+                // }
+                LLVM_DEBUG(llvm::dbgs()
+                           << "\nCXXRecrod : " << Record->getName()
+                           << " size(methods): " << std::distance(Record->method_begin(), Record->method_end())
+                           << " has def?:  " << Record->hasDefinition()
+                           << " # (methods): " << std::distance(Record->getDefinition()->method_begin(), Record->getDefinition()->method_end())
+                           << "\n");
+                for (auto *Meth : Record->methods()) {
+                  SetExternalVisibleDeclsForName(ChildDeclContext, Meth->getDeclName(), Meth);
+                  // if (Meth->getDeclName().isIdentifier()) {
+                  // LLVM_DEBUG(llvm::dbgs() << "CXXRecrod Method: " << Meth->getName() << "\n");
 
+                  // }
+                }
+              }
+            }
         } else {
           llvm::consumeError(DeclOrErr.takeError());
         }
@@ -177,11 +283,12 @@ void ExternalSource::completeVisibleDeclsMap(
   }
 }
 
-void codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content,
+
+void ReplCodeCompletion::codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content,
                   unsigned Line, unsigned Col, const CompilerInstance *ParentCI,
                   std::vector<std::string> &CCResults) {
   auto DiagOpts = DiagnosticOptions();
-  auto consumer = ReplCompletionConsumer(CCResults);
+  auto consumer = ReplCompletionConsumer(CCResults, *this);
 
   auto diag = InterpCI->getDiagnosticsPtr();
   std::unique_ptr<ASTUnit> AU(ASTUnit::LoadFromCompilerInvocationAction(
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 7dd96e3155e1dd4..522855640921554 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -51,6 +51,8 @@
 #include <vector>
 
 #include "OpenCLBuiltins.inc"
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "REPLCC"
 
 using namespace clang;
 using namespace sema;
@@ -2748,6 +2750,8 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
     return false;
   }
 
+  Context.getTranslationUnitDecl()->lookups();
+
   // Perform unqualified name lookup starting in the given scope.
   return LookupName(R, S, AllowBuiltinCreation);
 }
diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp
index 51741fd1a27ef4a..b0d40d5adcf49b3 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -15,6 +15,8 @@
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Interpreter/CodeCompletion.h"
 #include "clang/Interpreter/Interpreter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Sema.h"
 
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
 #include "llvm/LineEditor/LineEditor.h"
@@ -115,22 +117,12 @@ ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos,
 
     return {};
   }
-
-  codeComplete(
-      const_cast<clang::CompilerInstance *>((*Interp)->getCompilerInstance()),
-      Buffer, Lines, Pos + 1, MainInterp.getCompilerInstance(), Results);
-
-  size_t space_pos = Buffer.rfind(" ");
-  llvm::StringRef Prefix;
-  if (space_pos == llvm::StringRef::npos) {
-    Prefix = Buffer;
-  } else {
-    Prefix = Buffer.substr(space_pos + 1);
-  }
-
+  auto *MainCI = const_cast<clang::CompilerInstance *>((*Interp)->getCompilerInstance());
+  auto CC = clang::ReplCodeCompletion();
+  CC.codeComplete(MainCI, Buffer, Lines, Pos + 1, MainInterp.getCompilerInstance(), Results);
   for (auto c : Results) {
-    if (c.find(Prefix) == 0)
-      Comps.push_back(llvm::LineEditor::Completion(c.substr(Prefix.size()), c));
+    if (c.find(CC.Prefix) == 0)
+      Comps.push_back(llvm::LineEditor::Completion(c.substr(CC.Prefix.size()), c));
   }
   return Comps;
 }
diff --git a/clang/unittests/Interpreter/CodeCompletionTest.cpp b/clang/unittests/Interpreter/CodeCompletionTest.cpp
index d616afebc7d0046..7f359a2a754ca57 100644
--- a/clang/unittests/Interpreter/CodeCompletionTest.cpp
+++ b/clang/unittests/Interpreter/CodeCompletionTest.cpp
@@ -1,7 +1,9 @@
 #include "clang/Interpreter/CodeCompletion.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Interpreter/Interpreter.h"
+#include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/Sema.h"
 #include "llvm/LineEditor/LineEditor.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/raw_ostream.h"
@@ -19,7 +21,7 @@ static std::unique_ptr<Interpreter> createInterpreter() {
 }
 
 static std::vector<std::string> runComp(clang::Interpreter &MainInterp,
-                                        llvm::StringRef Prefix,
+                                        llvm::StringRef Input,
                                         llvm::Error &ErrR) {
   auto CI = CB.CreateCpp();
   if (auto Err = CI.takeError()) {
@@ -37,17 +39,17 @@ static std::vector<std::string> runComp(clang::Interpreter &MainInterp,
 
   std::vector<std::string> Results;
   std::vector<std::string> Comps;
-
-  codeComplete(
-      const_cast<clang::CompilerInstance *>((*Interp)->getCompilerInstance()),
-      Prefix, /* Lines */ 1, Prefix.size(), MainInterp.getCompilerInstance(),
-      Results);
+  auto *MainCI = const_cast<clang::CompilerInstance *>((*Interp)->getCompilerInstance());
+  auto CC = ReplCodeCompletion();
+  CC.codeComplete(MainCI,
+                  Input, /* Lines */ 1, Input.size()+1, MainInterp.getCompilerInstance(),
+                  Results);
 
   for (auto Res : Results)
-    if (Res.find(Prefix) == 0)
+    if (Res.find(CC.Prefix) == 0)
       Comps.push_back(Res);
-
   return Comps;
+
 }
 
 TEST(CodeCompletionTest, Sanity) {
@@ -58,8 +60,9 @@ TEST(CodeCompletionTest, Sanity) {
   }
   auto Err = llvm::Error::success();
   auto comps = runComp(*Interp, "f", Err);
-  EXPECT_EQ((size_t)2, comps.size()); // foo and float
-  EXPECT_EQ(comps[0], std::string("foo"));
+  EXPECT_EQ((size_t)2, comps.size()); // float and foo
+  EXPECT_EQ(comps[0], std::string("float"));
+  EXPECT_EQ(comps[1], std::string("foo"));
   EXPECT_EQ((bool)Err, false);
 }
 
@@ -98,4 +101,176 @@ TEST(CodeCompletionTest, CompFunDeclsNoError) {
   EXPECT_EQ((bool)Err, false);
 }
 
+TEST(CodeCompletionTest, TypedDirected) {
+  auto Interp = createInterpreter();
+  if (auto R = Interp->ParseAndExecute("int application = 12;")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("char apple = '2';")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("void add(int &SomeInt){}")) {
+    consumeError(std::move(R));
+    return;
+  }
+  {
+    auto Err = llvm::Error::success();
+    auto comps = runComp(*Interp, std::string("add("), Err);
+    EXPECT_EQ((size_t)1, comps.size());
+    EXPECT_EQ((bool)Err, false);
+  }
+
+  if (auto R = Interp->ParseAndExecute("int banana = 42;")) {
+    consumeError(std::move(R));
+    return;
+  }
+
+  {
+    auto Err = llvm::Error::success();
+    auto comps = runComp(*Interp, std::string("add("), Err);
+    EXPECT_EQ((size_t)2, comps.size());
+    EXPECT_EQ(comps[0], "application");
+    EXPECT_EQ(comps[1], "banana");
+    EXPECT_EQ((bool)Err, false);
+  }
+
+  {
+    auto Err = llvm::Error::success();
+    auto comps = runComp(*Interp, std::string("add(b"), Err);
+    EXPECT_EQ((size_t)1, comps.size());
+    EXPECT_EQ(comps[0], "banana");
+    EXPECT_EQ((bool)Err, false);
+  }
+}
+
+TEST(CodeCompletionTest, SanityClasses) {
+  auto Interp = createInterpreter();
+  if (auto R = Interp->ParseAndExecute("struct Apple{};")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("void takeApple(Apple &a1){}")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("Apple a1;")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("void takeAppleCopy(Apple a1){}")) {
+    consumeError(std::move(R));
+    return;
+  }
+
+  {
+    auto Err = llvm::Error::success();
+    auto comps = runComp(*Interp, "takeApple(", Err);
+    EXPECT_EQ((size_t)1, comps.size());
+    EXPECT_EQ(comps[0], std::string("a1"));
+    EXPECT_EQ((bool)Err, false);
+  }
+  {
+    auto Err = llvm::Error::success();
+    auto comps = runComp(*Interp, std::string("takeAppleCopy("), Err);
+    EXPECT_EQ((size_t)1, comps.size());
+    EXPECT_EQ(comps[0], std::string("a1"));
+    EXPECT_EQ((bool)Err, false);
+  }
+}
+
+TEST(CodeCompletionTest, SubClassing) {
+  auto Interp = createInterpreter();
+  if (auto R = Interp->ParseAndExecute("struct Fruit {};")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("struct Apple : Fruit{};")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("void takeFruit(Fruit &f){}")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("Apple a1;")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("Fruit f1;")) {
+    consumeError(std::move(R));
+    return;
+  }
+  auto Err = llvm::Error::success();
+  auto comps = runComp(*Interp, std::string("takeFruit("), Err);
+  EXPECT_EQ((size_t)2, comps.size());
+  EXPECT_EQ(comps[0], std::string("a1"));
+  EXPECT_EQ(comps[1], std::string("f1"));
+  EXPECT_EQ((bool)Err, false);
+}
+
+TEST(CodeCompletionTest, MultipleArguments) {
+  auto Interp = createInterpreter();
+  if (auto R = Interp->ParseAndExecute("int foo = 42;")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("char fowl = 'A';")) {
+    consumeError(std::move(R));
+    return;
+  }
+  if (auto R = Interp->ParseAndExecute("void takeTwo(int &a, char b){}")) {
+    consumeError(std::move(R));
+    return;
+  }
+  auto Err = llvm::Error::success();
+  auto comps = runComp(*Interp, std::string("takeTwo(foo,  "), Err);
+  EXPECT_EQ((size_t)1, comps.size());
+  EXPECT_EQ(comps[0], std::string("fowl"));
+  EXPECT_EQ((bool)Err, false);
+}
+
+TEST(CodeCompletionTest, Methods) {
+  auto Interp = createInterpreter();
+  cantFail(Interp->ParseAndExecute("struct Foo{int add(int a){return 42;} int par(int b){return 42;}};"));
+  cantFail(Interp->ParseAndExecute("Foo f1;"));
+
+  auto Err = llvm::Error::success();
+  auto comps = runComp(*Interp, std::string("f1."), Err);
+  EXPECT_EQ((size_t)2, comps.size());
+  EXPECT_EQ(comps[0], std::string("add"));
+  EXPECT_EQ(comps[1], std::string("par"));
+  EXPECT_EQ((bool)Err, false);
+}
+
+TEST(CodeCompletionTest, MethodsInvocations) {
+  auto Interp = createInterpreter();
+  cantFail(Interp->ParseAndExecute("struct Foo{int add(int a){return 42;} int par(int b){return 42;}};"));
+  cantFail(Interp->ParseAndExecute("Foo f1;"));
+  cantFail(Interp->ParseAndExecute("int a = 84;"));
+
+  auto Err = llvm::Error::success();
+  auto comps = runComp(*Interp, std::string("f1.add("), Err);
+  EXPECT_EQ((size_t)1, comps.size());
+  EXPECT_EQ(comps[0], std::string("a"));
+  EXPECT_EQ((bool)Err, false);
+}
+
+TEST(CodeCompletionTest, NestedInvocations) {
+  auto Interp = createInterpreter();
+  cantFail(Interp->ParseAndExecute("struct Foo{int add(int a){return 42;} int par(int b){return 42;}};"));
+  cantFail(Interp->ParseAndExecute("Foo f1;"));
+  cantFail(Interp->ParseAndExecute("int a = 84;"));
+  cantFail(Interp->ParseAndExecu...
[truncated]

@capfredf capfredf force-pushed the new-sema-comp branch 2 times, most recently from 218c261 to 623290d Compare September 25, 2023 19:00
@github-actions
Copy link

github-actions bot commented Sep 25, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@capfredf capfredf marked this pull request as ready for review October 26, 2023 16:43
@capfredf capfredf force-pushed the new-sema-comp branch 2 times, most recently from 61bb4c4 to 582f652 Compare October 26, 2023 16:50
@capfredf
Copy link
Contributor Author

capfredf commented Nov 1, 2023

@vgvassilev

Copy link
Contributor

@vgvassilev vgvassilev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is heading in a good direction. Thank you!

@capfredf capfredf force-pushed the new-sema-comp branch 2 times, most recently from 3393f32 to 304c772 Compare November 14, 2023 17:11
@capfredf
Copy link
Contributor Author

ping @vgvassilev

Copy link
Contributor

@vgvassilev vgvassilev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you!

@vgvassilev
Copy link
Contributor

@capfredf, can you rebase the PR to trigger a rebuild - the test failure seems unrelated to our changes but maybe it was fixed meanwhile.

use CodeCompletionContext to implement this feature.
@vgvassilev vgvassilev merged commit 002d471 into llvm:main Nov 23, 2023
@capfredf
Copy link
Contributor Author

@vgvassilev Thank you very much!

@capfredf capfredf deleted the new-sema-comp branch November 23, 2023 19:00
@capfredf
Copy link
Contributor Author

@vgvassilev there are some issues reported by sanitizers. Let's revert the patch. I will fix those issues and then re-land the patch

capfredf added a commit to capfredf/llvm-project that referenced this pull request Nov 23, 2023
vgvassilev pushed a commit that referenced this pull request Nov 23, 2023
Reverts #67349

There are some issues with the sanitizers. We will reland once that's fixed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants