yvvan updated this revision to Diff 130384.
yvvan added a comment.

Rebased. Applies for current master.

Also ping again...


https://reviews.llvm.org/D41537

Files:
  include/clang-c/Index.h
  include/clang/Sema/CodeCompleteConsumer.h
  include/clang/Sema/CodeCompleteOptions.h
  lib/Frontend/ASTUnit.cpp
  lib/Sema/CodeCompleteConsumer.cpp
  lib/Sema/SemaCodeComplete.cpp
  tools/c-index-test/c-index-test.c
  tools/libclang/CIndexCodeCompletion.cpp
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===================================================================
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -173,6 +173,7 @@
 clang_getCompletionNumAnnotations
 clang_getCompletionParent
 clang_getCompletionPriority
+clang_getCompletionRequiresDotToArrowCorrection
 clang_getCursor
 clang_getCursorAvailability
 clang_getCursorCompletionString
Index: tools/libclang/CIndexCodeCompletion.cpp
===================================================================
--- tools/libclang/CIndexCodeCompletion.cpp
+++ tools/libclang/CIndexCodeCompletion.cpp
@@ -238,6 +238,16 @@
   return cxstring::createRef(CCStr->getBriefComment());
 }
 
+unsigned
+clang_getCompletionRequiresDotToArrowCorrection(CXCompletionString completion_string) {
+  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+
+  if (!CCStr)
+    return false;
+
+  return CCStr->requiresDotToArrowCorrection();
+}
+
 namespace {
 
 /// \brief The CXCodeCompleteResults structure we allocate internally;
@@ -644,13 +654,13 @@
                           unsigned options) {
   bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments;
   bool SkipPreamble = options & CXCodeComplete_SkipPreamble;
+  bool TryArrowInsteadOfDot = options & CXCodeComplete_TryArrowInsteadOfDot;
 
 #ifdef UDP_CODE_COMPLETION_LOGGER
 #ifdef UDP_CODE_COMPLETION_LOGGER_PORT
   const llvm::TimeRecord &StartTime =  llvm::TimeRecord::getCurrentTime();
 #endif
 #endif
-
   bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr;
 
   if (cxtu::isNotUsableTU(TU)) {
@@ -691,6 +701,7 @@
   CodeCompleteOptions Opts;
   Opts.IncludeBriefComments = IncludeBriefComments;
   Opts.LoadExternal = !SkipPreamble;
+  Opts.TryArrowInsteadOfDot = TryArrowInsteadOfDot;
   CaptureCompletionResults Capture(Opts, *Results, &TU);
 
   // Perform completion.
Index: tools/c-index-test/c-index-test.c
===================================================================
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -2322,7 +2322,13 @@
     fprintf(file, "(brief comment: %s)", BriefCommentCString);
   }
   clang_disposeString(BriefComment);
-  
+
+  unsigned RequiresDotToArrowCorrection =
+      clang_getCompletionRequiresDotToArrowCorrection(
+          completion_result->CompletionString);
+  if (RequiresDotToArrowCorrection) {
+    fprintf(file, " (requires correction: \".\" to \"->\")");
+  }
   fprintf(file, "\n");
 }
 
@@ -2421,6 +2427,8 @@
     completionOptions |= CXCodeComplete_IncludeBriefComments;
   if (getenv("CINDEXTEST_COMPLETION_SKIP_PREAMBLE"))
     completionOptions |= CXCodeComplete_SkipPreamble;
+  if (getenv("CINDEXTEST_COMPLETION_TRY_ARROW_INSTEAD_OF_DOT"))
+    completionOptions |= CXCodeComplete_TryArrowInsteadOfDot;
   
   if (timing_only)
     input += strlen("-code-completion-timing=");
Index: lib/Sema/SemaCodeComplete.cpp
===================================================================
--- lib/Sema/SemaCodeComplete.cpp
+++ lib/Sema/SemaCodeComplete.cpp
@@ -2749,7 +2749,8 @@
                                            CodeCompletionAllocator &Allocator,
                                            CodeCompletionTUInfo &CCTUInfo,
                                            bool IncludeBriefComments) {
-  CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability);
+  CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability,
+                               RequiresDotToArrowCorrection);
   
   PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP);
   if (Kind == RK_Pattern) {
@@ -3974,62 +3975,41 @@
   }
 }
 
-void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
-                                           SourceLocation OpLoc, bool IsArrow,
-                                           bool IsBaseExprStatement) {
-  if (!Base || !CodeCompleter)
-    return;
-  
-  ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow);
-  if (ConvertedBase.isInvalid())
-    return;
-  Base = ConvertedBase.get();
-  
-  QualType BaseType = Base->getType();
-
-  if (IsArrow) {
-    if (const PointerType *Ptr = BaseType->getAs<PointerType>())
-      BaseType = Ptr->getPointeeType();
-    else if (BaseType->isObjCObjectPointerType())
-      /*Do nothing*/ ;
-    else
-      return;
-  }
-  
+static ResultBuilder
+GetCodeCompleteMemberReferenceResults(Sema &SemaRef, Scope *S,
+                                      QualType BaseType, bool IsArrow,
+                                      bool IsBaseExprStatement) {
   enum CodeCompletionContext::Kind contextKind;
-  
+
   if (IsArrow) {
     contextKind = CodeCompletionContext::CCC_ArrowMemberAccess;
-  }
-  else {
+  } else {
     if (BaseType->isObjCObjectPointerType() ||
         BaseType->isObjCObjectOrInterfaceType()) {
       contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess;
-    }
-    else {
+    } else {
       contextKind = CodeCompletionContext::CCC_DotMemberAccess;
     }
   }
 
   CodeCompletionContext CCContext(contextKind, BaseType);
-  ResultBuilder Results(*this, CodeCompleter->getAllocator(),
-                        CodeCompleter->getCodeCompletionTUInfo(),
-                        CCContext,
-                        &ResultBuilder::IsMember);
+  ResultBuilder Results(SemaRef, SemaRef.CodeCompleter->getAllocator(),
+                        SemaRef.CodeCompleter->getCodeCompletionTUInfo(),
+                        CCContext, &ResultBuilder::IsMember);
   Results.EnterNewScope();
   if (const RecordType *Record = BaseType->getAs<RecordType>()) {
-    AddRecordMembersCompletionResults(*this, Results, S, BaseType,
+    AddRecordMembersCompletionResults(SemaRef, Results, S, BaseType,
                                       Record->getDecl());
   } else if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) {
     TemplateName TN = TST->getTemplateName();
     if (const auto *TD =
             dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) {
       CXXRecordDecl *RD = TD->getTemplatedDecl();
-      AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
+      AddRecordMembersCompletionResults(SemaRef, Results, S, BaseType, RD);
     }
   } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) {
     if (auto *RD = ICNT->getDecl())
-      AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
+      AddRecordMembersCompletionResults(SemaRef, Results, S, BaseType, RD);
   } else if (!IsArrow && BaseType->isObjCObjectPointerType()) {
     // Objective-C property reference.
     AddedPropertiesSet AddedProperties;
@@ -4039,43 +4019,122 @@
       // Add property results based on our interface.
       assert(ObjCPtr && "Non-NULL pointer guaranteed above!");
       AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true,
-                        /*AllowNullaryMethods=*/true, CurContext,
+                        /*AllowNullaryMethods=*/true, SemaRef.CurContext,
                         AddedProperties, Results, IsBaseExprStatement);
     }
 
     // Add properties from the protocols in a qualified interface.
     for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals())
       AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true,
-                        CurContext, AddedProperties, Results,
+                        SemaRef.CurContext, AddedProperties, Results,
                         IsBaseExprStatement);
   } else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
              (!IsArrow && BaseType->isObjCObjectType())) {
     // Objective-C instance variable access.
     ObjCInterfaceDecl *Class = nullptr;
-    if (const ObjCObjectPointerType *ObjCPtr
-                                    = BaseType->getAs<ObjCObjectPointerType>())
+    if (const ObjCObjectPointerType *ObjCPtr =
+            BaseType->getAs<ObjCObjectPointerType>())
       Class = ObjCPtr->getInterfaceDecl();
     else
       Class = BaseType->getAs<ObjCObjectType>()->getInterface();
-    
+
     // Add all ivars from this class and its superclasses.
     if (Class) {
-      CodeCompletionDeclConsumer Consumer(Results, CurContext);
+      CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);
       Results.setFilter(&ResultBuilder::IsObjCIvar);
-      LookupVisibleDecls(
-          Class, LookupMemberName, Consumer, CodeCompleter->includeGlobals(),
-          /*IncludeDependentBases=*/false, CodeCompleter->loadExternal());
+      SemaRef.LookupVisibleDecls(
+          Class, SemaRef.LookupMemberName, Consumer,
+          SemaRef.CodeCompleter->includeGlobals(), /*IncludeDependentBases=*/false,
+          SemaRef.CodeCompleter->loadExternal());
     }
   }
-  
+
   // FIXME: How do we cope with isa?
-  
+
   Results.ExitScope();
+  return Results;
+}
 
+static void TryCompleteArrowInsteadOfDot(Sema &SemaRef, Scope *S, Expr *Base,
+                                         SourceLocation OpLoc,
+                                         bool IsBaseExprStatement,
+                                         ResultBuilder &ExistingResults) {
+  QualType BaseType = Base->getType();
+  if (BaseType->isPointerType()) {
+    BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+  } else {
+    const DeclarationName ArrowOpName =
+        SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
+    bool HasArrowOp = false;
+    for (CodeCompletionResult *result = ExistingResults.data();
+         result != ExistingResults.data() + ExistingResults.size(); ++result) {
+      if (result->Kind != CodeCompletionResult::RK_Declaration)
+        continue;
+      const NamedDecl *decl = result->getDeclaration();
+      if (decl && decl->getDeclName() == ArrowOpName) {
+        HasArrowOp = true;
+        break;
+      }
+    }
+    if (!HasArrowOp)
+      return;
+    ParsedType ObjectType;
+    bool MayBePseudoDestructor = false;
+    ExprResult LHS = SemaRef.ActOnStartCXXMemberReference(
+        S, Base, OpLoc, tok::arrow, ObjectType, MayBePseudoDestructor);
+    ExprResult ConvertedBase =
+        SemaRef.PerformMemberExprBaseConversion(LHS.get(), true);
+    if (ConvertedBase.isInvalid())
+      return;
+    Base = ConvertedBase.get();
+    BaseType = Base->getType();
+    if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+      BaseType = Ptr->getPointeeType();
+  }
+
+  ResultBuilder ArrowResults = GetCodeCompleteMemberReferenceResults(
+      SemaRef, S, BaseType, true, IsBaseExprStatement);
+  for (size_t i = 0; i < ArrowResults.size(); ++i)
+    ArrowResults.data()[i].RequiresDotToArrowCorrection = true;
+  HandleCodeCompleteResults(&SemaRef, SemaRef.CodeCompleter,
+                            ArrowResults.getCompletionContext(),
+                            ArrowResults.data(), ArrowResults.size());
+}
+
+void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
+                                           SourceLocation OpLoc, bool IsArrow,
+                                           bool IsBaseExprStatement) {
+  if (!Base || !CodeCompleter)
+    return;
+
+  ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow);
+  if (ConvertedBase.isInvalid())
+    return;
+  Base = ConvertedBase.get();
+
+  QualType BaseType = Base->getType();
+
+  if (IsArrow) {
+    if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+      BaseType = Ptr->getPointeeType();
+    else if (BaseType->isObjCObjectPointerType())
+      /*Do nothing*/;
+    else
+      return;
+  }
+
+  ResultBuilder Results = GetCodeCompleteMemberReferenceResults(
+      *this, S, BaseType, IsArrow, IsBaseExprStatement);
+
+  if (CodeCompleter->tryArrowInsteadOfDot() && !IsArrow &&
+      !BaseType->isObjCObjectPointerType() &&
+      !BaseType->isObjCObjectOrInterfaceType()) {
+    TryCompleteArrowInsteadOfDot(*this, S, Base, OpLoc, IsBaseExprStatement,
+                                 Results);
+  }
   // Hand off the results found for code completion.
-  HandleCodeCompleteResults(this, CodeCompleter, 
-                            Results.getCompletionContext(),
-                            Results.data(),Results.size());
+  HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+                            Results.data(), Results.size());
 }
 
 void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S,
Index: lib/Sema/CodeCompleteConsumer.cpp
===================================================================
--- lib/Sema/CodeCompleteConsumer.cpp
+++ lib/Sema/CodeCompleteConsumer.cpp
@@ -194,10 +194,12 @@
                                            const char **Annotations,
                                            unsigned NumAnnotations,
                                            StringRef ParentName,
-                                           const char *BriefComment)
+                                           const char *BriefComment,
+                                           bool RequiresDotToArrowCorrection)
   : NumChunks(NumChunks), NumAnnotations(NumAnnotations),
     Priority(Priority), Availability(Availability),
-    ParentName(ParentName), BriefComment(BriefComment)
+    ParentName(ParentName), BriefComment(BriefComment),
+    RequiresDotToArrowCorrection(RequiresDotToArrowCorrection)
 { 
   assert(NumChunks <= 0xffff);
   assert(NumAnnotations <= 0xffff);
@@ -335,7 +337,7 @@
     = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
                                      Priority, Availability,
                                      Annotations.data(), Annotations.size(),
-                                     ParentName, BriefComment);
+                                     ParentName, BriefComment, RequiresDotToArrowCorrection);
   Chunks.clear();
   return Result;
 }
Index: lib/Frontend/ASTUnit.cpp
===================================================================
--- lib/Frontend/ASTUnit.cpp
+++ lib/Frontend/ASTUnit.cpp
@@ -2069,6 +2069,7 @@
   CodeCompleteOpts.IncludeGlobals = CachedCompletionResults.empty();
   CodeCompleteOpts.IncludeBriefComments = IncludeBriefComments;
   CodeCompleteOpts.LoadExternal = Consumer.loadExternal();
+  CodeCompleteOpts.TryArrowInsteadOfDot = Consumer.tryArrowInsteadOfDot();
 
   assert(IncludeBriefComments == this->IncludeBriefCommentsInCodeCompletion);
 
Index: include/clang/Sema/CodeCompleteOptions.h
===================================================================
--- include/clang/Sema/CodeCompleteOptions.h
+++ include/clang/Sema/CodeCompleteOptions.h
@@ -39,10 +39,13 @@
   /// full results. If false, declarations from the preamble may be omitted.
   unsigned LoadExternal : 1;
 
+  /// Show also results after dot to arrow correction if arrow operator can be applied.
+  unsigned TryArrowInsteadOfDot : 1;
+
   CodeCompleteOptions()
       : IncludeMacros(0), IncludeCodePatterns(0), IncludeGlobals(1),
         IncludeNamespaceLevelDecls(1), IncludeBriefComments(0),
-        LoadExternal(1) {}
+        LoadExternal(1), TryArrowInsteadOfDot(0) {}
 };
 
 } // namespace clang
Index: include/clang/Sema/CodeCompleteConsumer.h
===================================================================
--- include/clang/Sema/CodeCompleteConsumer.h
+++ include/clang/Sema/CodeCompleteConsumer.h
@@ -472,22 +472,25 @@
 
   /// \brief The availability of this code-completion result.
   unsigned Availability : 2;
-  
+
   /// \brief The name of the parent context.
   StringRef ParentName;
 
   /// \brief A brief documentation comment attached to the declaration of
   /// entity being completed by this result.
   const char *BriefComment;
-  
+
+  /// \brief If this is the result of arrow completion when dot is present.
+  bool RequiresDotToArrowCorrection : 1;
+
   CodeCompletionString(const CodeCompletionString &) = delete;
   void operator=(const CodeCompletionString &) = delete;
 
   CodeCompletionString(const Chunk *Chunks, unsigned NumChunks,
                        unsigned Priority, CXAvailabilityKind Availability,
                        const char **Annotations, unsigned NumAnnotations,
-                       StringRef ParentName,
-                       const char *BriefComment);
+                       StringRef ParentName, const char *BriefComment,
+                       bool RequiresDotToArrowCorrection = false);
   ~CodeCompletionString() = default;
 
   friend class CodeCompletionBuilder;
@@ -514,6 +517,9 @@
   /// \brief Retrieve the availability of this code completion result.
   unsigned getAvailability() const { return Availability; }
 
+  /// \brief Check if this completion requires dot to arrow correction.
+  bool requiresDotToArrowCorrection() const { return RequiresDotToArrowCorrection; }
+
   /// \brief Retrieve the number of annotations for this code completion result.
   unsigned getAnnotationCount() const;
 
@@ -586,6 +592,7 @@
   CXAvailabilityKind Availability;
   StringRef ParentName;
   const char *BriefComment;
+  bool RequiresDotToArrowCorrection = false;
   
   /// \brief The chunks stored in this string.
   SmallVector<Chunk, 4> Chunks;
@@ -601,10 +608,12 @@
 
   CodeCompletionBuilder(CodeCompletionAllocator &Allocator,
                         CodeCompletionTUInfo &CCTUInfo,
-                        unsigned Priority, CXAvailabilityKind Availability)
+                        unsigned Priority, CXAvailabilityKind Availability,
+                        bool RequiresDotToArrowCorrection = false)
     : Allocator(Allocator), CCTUInfo(CCTUInfo),
       Priority(Priority), Availability(Availability),
-      BriefComment(nullptr) { }
+      BriefComment(nullptr),
+      RequiresDotToArrowCorrection(RequiresDotToArrowCorrection) { }
 
   /// \brief Retrieve the allocator into which the code completion
   /// strings should be allocated.
@@ -714,6 +723,9 @@
   /// rather than a use of that entity.
   bool DeclaringEntity : 1;
 
+  /// \brief If this is the result of arrow completion when dot is present.
+  bool RequiresDotToArrowCorrection : 1;
+
   /// \brief If the result should have a nested-name-specifier, this is it.
   /// When \c QualifierIsInformative, the nested-name-specifier is
   /// informative rather than required.
@@ -730,7 +742,8 @@
       Availability(CXAvailability_Available), Hidden(false),
       QualifierIsInformative(QualifierIsInformative),
       StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
-      DeclaringEntity(false), Qualifier(Qualifier) {
+      DeclaringEntity(false), RequiresDotToArrowCorrection(false),
+      Qualifier(Qualifier) {
     computeCursorKindAndAvailability(Accessible);
   }
 
@@ -741,7 +754,7 @@
       Availability(CXAvailability_Available), Hidden(false),
       QualifierIsInformative(0), StartsNestedNameSpecifier(false),
       AllParametersAreInformative(false), DeclaringEntity(false),
-      Qualifier(nullptr) {}
+      RequiresDotToArrowCorrection(false), Qualifier(nullptr) {}
 
   /// \brief Build a result that refers to a macro.
   CodeCompletionResult(const IdentifierInfo *Macro,
@@ -751,7 +764,7 @@
       Availability(CXAvailability_Available), Hidden(false),
       QualifierIsInformative(0), StartsNestedNameSpecifier(false),
       AllParametersAreInformative(false), DeclaringEntity(false),
-      Qualifier(nullptr) {}
+      RequiresDotToArrowCorrection(false), Qualifier(nullptr) {}
 
   /// \brief Build a result that refers to a pattern.
   CodeCompletionResult(CodeCompletionString *Pattern,
@@ -763,7 +776,8 @@
       Kind(RK_Pattern), CursorKind(CursorKind), Availability(Availability),
       Hidden(false), QualifierIsInformative(0),
       StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
-      DeclaringEntity(false), Qualifier(nullptr)
+      DeclaringEntity(false), RequiresDotToArrowCorrection(false),
+      Qualifier(nullptr)
   {
   }
 
@@ -775,7 +789,7 @@
       Kind(RK_Pattern), Availability(CXAvailability_Available), Hidden(false),
       QualifierIsInformative(false), StartsNestedNameSpecifier(false),
       AllParametersAreInformative(false), DeclaringEntity(false),
-      Qualifier(nullptr) {
+      RequiresDotToArrowCorrection(false), Qualifier(nullptr) {
     computeCursorKindAndAvailability();
   }  
   
@@ -950,6 +964,11 @@
     return CodeCompleteOpts.IncludeBriefComments;
   }
 
+  /// \brief Whether to try dot to arrow correction if arrow operator can be applied.
+  bool tryArrowInsteadOfDot() const {
+    return CodeCompleteOpts.TryArrowInsteadOfDot;
+  }
+
   /// \brief Hint whether to load data from the external AST in order to provide
   /// full results. If false, declarations from the preamble may be omitted.
   bool loadExternal() const {
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -32,7 +32,7 @@
  * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
  */
 #define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 47
+#define CINDEX_VERSION_MINOR 48
 
 #define CINDEX_VERSION_ENCODE(major, minor) ( \
       ((major) * 10000)                       \
@@ -5189,6 +5189,12 @@
 clang_getCompletionBriefComment(CXCompletionString completion_string);
 
 /**
+ * \brief Retrieve the necessity of dot to arrow correction for the given completion string.
+ */
+CINDEX_LINKAGE unsigned
+clang_getCompletionRequiresDotToArrowCorrection(CXCompletionString completion_string);
+
+/**
  * \brief Retrieve a completion string for an arbitrary declaration or macro
  * definition cursor.
  *
@@ -5251,7 +5257,12 @@
    * defined in the preamble. There's no guarantee any particular entity will
    * be omitted. This may be useful if the headers are indexed externally.
    */
-  CXCodeComplete_SkipPreamble = 0x08
+  CXCodeComplete_SkipPreamble = 0x08,
+
+  /**
+   * \brief Whether to try dot to arrow correction if arrow operator can be applied.
+   */
+  CXCodeComplete_TryArrowInsteadOfDot = 0x10
 };
 
 /**
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to