r343568 - [clang] Implement Override Suggestions in Sema.

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 2 02:42:31 PDT 2018


Author: kadircet
Date: Tue Oct  2 02:42:31 2018
New Revision: 343568

URL: http://llvm.org/viewvc/llvm-project?rev=343568&view=rev
Log:
[clang] Implement Override Suggestions in Sema.

Summary:
In clangd we had a new type of completion suggestions for cpp
class/struct/unions that will show override signatures for virtual methods in
base classes. This patch implements it in sema because it is hard to deduce more
info about completion token outside of Sema and handle itchy cases.

See the patch D50898 for more info on the functionality.

In addition to above patch this one also converts the suggestion into a
CK_Pattern with whole insertion text as the name of the suggestion and factors
out CodeCompletionString generation for declerations so that it can be re-used
by others.

Reviewers: ioeric, ilya-biryukov

Reviewed By: ioeric

Subscribers: cfe-commits

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

Added:
    cfe/trunk/test/CodeCompletion/overrides.cpp
Modified:
    cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp

Modified: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h?rev=343568&r1=343567&r2=343568&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h (original)
+++ cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h Tue Oct  2 02:42:31 2018
@@ -946,6 +946,16 @@ public:
                                      CodeCompletionAllocator &Allocator,
                                      CodeCompletionTUInfo &CCTUInfo);
 
+  CodeCompletionString *createCodeCompletionStringForDecl(
+      Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,
+      bool IncludeBriefComments, const CodeCompletionContext &CCContext,
+      PrintingPolicy &Policy);
+
+  CodeCompletionString *createCodeCompletionStringForOverride(
+      Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,
+      bool IncludeBriefComments, const CodeCompletionContext &CCContext,
+      PrintingPolicy &Policy);
+
   /// Retrieve the name that should be used to order a result.
   ///
   /// If the name needs to be constructed as a string, that string will be

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=343568&r1=343567&r2=343568&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Tue Oct  2 02:42:31 2018
@@ -1598,6 +1598,74 @@ static void AddStaticAssertResult(CodeCo
   Results.AddResult(CodeCompletionResult(Builder.TakeString()));
 }
 
+namespace {
+void printOverrideString(llvm::raw_ostream &OS, CodeCompletionString *CCS) {
+  for (const auto &C : *CCS) {
+    if (C.Kind == CodeCompletionString::CK_Optional)
+      printOverrideString(OS, C.Optional);
+    else
+      OS << C.Text;
+    // Add a space after return type.
+    if (C.Kind == CodeCompletionString::CK_ResultType)
+      OS << ' ';
+  }
+}
+} // namespace
+
+static void AddOverrideResults(ResultBuilder &Results,
+                               const CodeCompletionContext &CCContext,
+                               CodeCompletionBuilder &Builder) {
+  Sema &S = Results.getSema();
+  const auto *CR = llvm::dyn_cast<CXXRecordDecl>(S.CurContext);
+  // If not inside a class/struct/union return empty.
+  if (!CR)
+    return;
+  // First store overrides within current class.
+  // These are stored by name to make querying fast in the later step.
+  llvm::StringMap<std::vector<FunctionDecl *>> Overrides;
+  for (auto *Method : CR->methods()) {
+    if (!Method->isVirtual() || !Method->getIdentifier())
+      continue;
+    Overrides[Method->getName()].push_back(Method);
+  }
+
+  for (const auto &Base : CR->bases()) {
+    const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl();
+    if (!BR)
+      continue;
+    for (auto *Method : BR->methods()) {
+      if (!Method->isVirtual() || !Method->getIdentifier())
+        continue;
+      const auto it = Overrides.find(Method->getName());
+      bool IsOverriden = false;
+      if (it != Overrides.end()) {
+        for (auto *MD : it->second) {
+          // If the method in current body is not an overload of this virtual
+          // function, then it overrides this one.
+          if (!S.IsOverload(MD, Method, false)) {
+            IsOverriden = true;
+            break;
+          }
+        }
+      }
+      if (!IsOverriden) {
+        // Generates a new CodeCompletionResult by taking this function and
+        // converting it into an override declaration with only one chunk in the
+        // final CodeCompletionString as a TypedTextChunk.
+        std::string OverrideSignature;
+        llvm::raw_string_ostream OS(OverrideSignature);
+        CodeCompletionResult CCR(Method, 0);
+        PrintingPolicy Policy =
+            getCompletionPrintingPolicy(S.getASTContext(), S.getPreprocessor());
+        auto *CCS = CCR.createCodeCompletionStringForOverride(
+            S.getPreprocessor(), S.getASTContext(), Builder,
+            /*IncludeBriefComments=*/false, CCContext, Policy);
+        Results.AddResult(CodeCompletionResult(CCS, Method, CCP_CodePattern));
+      }
+    }
+  }
+}
+
 /// Add language constructs that show up for "ordinary" names.
 static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
                                    Scope *S,
@@ -1706,6 +1774,12 @@ static void AddOrdinaryNameResults(Sema:
         if (IsNotInheritanceScope && Results.includeCodePatterns())
           Builder.AddChunk(CodeCompletionString::CK_Colon);
         Results.AddResult(Result(Builder.TakeString()));
+
+        // FIXME: This adds override results only if we are at the first word of
+        // the declaration/definition. Also call this from other sides to have
+        // more use-cases.
+        AddOverrideResults(Results, CodeCompletionContext::CCC_ClassStructUnion,
+                           Builder);
       }
     }
     LLVM_FALLTHROUGH;
@@ -2834,6 +2908,30 @@ CodeCompletionResult::CreateCodeCompleti
     return Result.TakeString();
   }
   assert(Kind == RK_Declaration && "Missed a result kind?");
+  return createCodeCompletionStringForDecl(PP, Ctx, Result, IncludeBriefComments,
+                                    CCContext, Policy);
+}
+
+CodeCompletionString *
+CodeCompletionResult::createCodeCompletionStringForOverride(
+    Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,
+    bool IncludeBriefComments, const CodeCompletionContext &CCContext,
+    PrintingPolicy &Policy) {
+  std::string OverrideSignature;
+  llvm::raw_string_ostream OS(OverrideSignature);
+  auto *CCS = createCodeCompletionStringForDecl(PP, Ctx, Result,
+                                                /*IncludeBriefComments=*/false,
+                                                CCContext, Policy);
+  printOverrideString(OS, CCS);
+  OS << " override";
+  Result.AddTypedTextChunk(Result.getAllocator().CopyString(OS.str()));
+  return Result.TakeString();
+}
+
+CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
+    Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,
+    bool IncludeBriefComments, const CodeCompletionContext &CCContext,
+    PrintingPolicy &Policy) {
   const NamedDecl *ND = Declaration;
   Result.addParentContext(ND->getDeclContext());
 
@@ -2931,7 +3029,6 @@ CodeCompletionResult::CreateCodeCompleti
     Result.AddChunk(CodeCompletionString::CK_RightAngle);
     return Result.TakeString();
   }
-
   if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
     Selector Sel = Method->getSelector();
     if (Sel.isUnarySelector()) {
@@ -3027,7 +3124,7 @@ CodeCompletionResult::CreateCodeCompleti
                                    Ctx, Policy);
 
   Result.AddTypedTextChunk(
-                       Result.getAllocator().CopyString(ND->getNameAsString()));
+      Result.getAllocator().CopyString(ND->getNameAsString()));
   return Result.TakeString();
 }
 

Added: cfe/trunk/test/CodeCompletion/overrides.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/overrides.cpp?rev=343568&view=auto
==============================================================================
--- cfe/trunk/test/CodeCompletion/overrides.cpp (added)
+++ cfe/trunk/test/CodeCompletion/overrides.cpp Tue Oct  2 02:42:31 2018
@@ -0,0 +1,33 @@
+class A {
+ public:
+  virtual void vfunc(bool param);
+  virtual void vfunc(bool param, int p);
+  void func(bool param);
+};
+class B : public A {
+virtual int ttt(bool param, int x = 3) const;
+void vfunc(bool param, int p) override;
+};
+class C : public B {
+ public:
+  void vfunc(bool param) override;
+  void
+};
+
+// Runs completion at ^void.
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:3 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: COMPLETION: Pattern : int ttt(bool param, int x = 3) const override{{$}}
+// CHECK-CC1: COMPLETION: Pattern : void vfunc(bool param, int p) override{{$}}
+// CHECK-CC1-NOT: COMPLETION: Pattern : void vfunc(bool param) override{{$}}
+//
+// Runs completion at vo^id.
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:5 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: COMPLETION: Pattern : void vfunc(bool param, int p) override{{$}}
+// CHECK-CC2-NOT: COMPLETION: Pattern : int ttt(bool param, int x = 3) const override{{$}}
+// CHECK-CC2-NOT: COMPLETION: Pattern : void vfunc(bool param) override{{$}}
+//
+// Runs completion at void ^.
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3-NOT: COMPLETION: Pattern : int ttt(bool param, int x = 3) const override{{$}}
+// CHECK-CC3-NOT: COMPLETION: Pattern : void vfunc(bool param, int p) override{{$}}
+// CHECK-CC3-NOT: COMPLETION: Pattern : void vfunc(bool param) override{{$}}




More information about the cfe-commits mailing list