When code-completing a potential call to a C++ non-static member
function, take into account the qualifiers on the object argument
(e.g., what will become "this"), filtering around uncallable member
functions and giving a slight priority boost to those with
exactly-matching qualifiers.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112193 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index b75a7d0..3921526 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -136,11 +136,19 @@
/// different levels of, e.g., the inheritance hierarchy.
std::list<ShadowMap> ShadowMaps;
+ /// \brief If we're potentially referring to a C++ member function, the set
+ /// of qualifiers applied to the object type.
+ Qualifiers ObjectTypeQualifiers;
+
+ /// \brief Whether the \p ObjectTypeQualifiers field is active.
+ bool HasObjectTypeQualifiers;
+
void AdjustResultPriorityForPreferredType(Result &R);
public:
explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
- : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { }
+ : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false),
+ HasObjectTypeQualifiers(false) { }
/// \brief Whether we should include code patterns in the completion
/// results.
@@ -167,6 +175,18 @@
PreferredType = SemaRef.Context.getCanonicalType(T);
}
+ /// \brief Set the cv-qualifiers on the object type, for us in filtering
+ /// calls to member functions.
+ ///
+ /// When there are qualifiers in this set, they will be used to filter
+ /// out member functions that aren't available (because there will be a
+ /// cv-qualifier mismatch) or prefer functions with an exact qualifier
+ /// match.
+ void setObjectTypeQualifiers(Qualifiers Quals) {
+ ObjectTypeQualifiers = Quals;
+ HasObjectTypeQualifiers = true;
+ }
+
/// \brief Specify whether nested-name-specifiers are allowed.
void allowNestedNameSpecifiers(bool Allow = true) {
AllowNestedNameSpecifiers = Allow;
@@ -770,6 +790,20 @@
if (!PreferredType.isNull())
AdjustResultPriorityForPreferredType(R);
+ if (HasObjectTypeQualifiers)
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
+ if (Method->isInstance()) {
+ Qualifiers MethodQuals
+ = Qualifiers::fromCVRMask(Method->getTypeQualifiers());
+ if (ObjectTypeQualifiers == MethodQuals)
+ R.Priority += CCD_ObjectQualifierMatch;
+ else if (ObjectTypeQualifiers - MethodQuals) {
+ // The method cannot be invoked, because doing so would drop
+ // qualifiers.
+ return;
+ }
+ }
+
// Insert this result into the set of results.
Results.push_back(R);
}
@@ -2364,6 +2398,13 @@
break;
}
+ // If we are in a C++ non-static member function, check the qualifiers on
+ // the member function to filter/prioritize the results list.
+ if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext))
+ if (CurMethod->isInstance())
+ Results.setObjectTypeQualifiers(
+ Qualifiers::fromCVRMask(CurMethod->getTypeQualifiers()));
+
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
CodeCompleter->includeGlobals());
@@ -2566,7 +2607,7 @@
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
BaseType = Ptr->getPointeeType();
else if (BaseType->isObjCObjectPointerType())
- /*Do nothing*/ ;
+ /*Do nothing*/ ;
else
return;
}
@@ -2574,6 +2615,10 @@
ResultBuilder Results(*this, &ResultBuilder::IsMember);
Results.EnterNewScope();
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
+ // Indicate that we are performing a member access, and the cv-qualifiers
+ // for the base object type.
+ Results.setObjectTypeQualifiers(BaseType.getQualifiers());
+
// Access to a C/C++ class, struct, or union.
Results.allowNestedNameSpecifiers();
CodeCompletionDeclConsumer Consumer(Results, CurContext);