Teach code completion to provide property results when the property
can be used to automatically synthesize an ivar.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118052 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index b07ae39..c245e38 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -147,9 +147,13 @@
/// \brief The selector that we prefer.
Selector PreferredSelector;
- /// \brief The completion context in which
+ /// \brief The completion context in which we are gathering results.
CodeCompletionContext CompletionContext;
+ /// \brief If we are in an instance method definition, the @implementation
+ /// object.
+ ObjCImplementationDecl *ObjCImplementation;
+
void AdjustResultPriorityForDecl(Result &R);
void MaybeAddConstructorResults(Result R);
@@ -160,7 +164,27 @@
LookupFilter Filter = 0)
: SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false),
HasObjectTypeQualifiers(false),
- CompletionContext(CompletionContext) { }
+ CompletionContext(CompletionContext),
+ ObjCImplementation(0)
+ {
+ // If this is an Objective-C instance method definition, dig out the
+ // corresponding implementation.
+ switch (CompletionContext.getKind()) {
+ case CodeCompletionContext::CCC_Expression:
+ case CodeCompletionContext::CCC_ObjCMessageReceiver:
+ case CodeCompletionContext::CCC_ParenthesizedExpression:
+ case CodeCompletionContext::CCC_Statement:
+ case CodeCompletionContext::CCC_Recovery:
+ if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
+ if (Method->isInstanceMethod())
+ if (ObjCInterfaceDecl *Interface = Method->getClassInterface())
+ ObjCImplementation = Interface->getImplementation();
+ break;
+
+ default:
+ break;
+ }
+ }
/// \brief Whether we should include code patterns in the completion
/// results.
@@ -203,7 +227,7 @@
void setPreferredSelector(Selector Sel) {
PreferredSelector = Sel;
}
-
+
/// \brief Retrieve the code-completion context for which results are
/// being collected.
const CodeCompletionContext &getCompletionContext() const {
@@ -919,9 +943,14 @@
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
- else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND))
- return true;
-
+ else if (SemaRef.getLangOptions().ObjC1) {
+ if (isa<ObjCIvarDecl>(ND))
+ return true;
+ if (isa<ObjCPropertyDecl>(ND) &&
+ SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND)))
+ return true;
+ }
+
return ND->getIdentifierNamespace() & IDNS;
}
@@ -935,9 +964,14 @@
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
- else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND))
- return true;
-
+ else if (SemaRef.getLangOptions().ObjC1) {
+ if (isa<ObjCIvarDecl>(ND))
+ return true;
+ if (isa<ObjCPropertyDecl>(ND) &&
+ SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND)))
+ return true;
+ }
+
return ND->getIdentifierNamespace() & IDNS;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9e28172..fdc4828 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1027,25 +1027,41 @@
return true;
}
-static ObjCPropertyDecl *OkToSynthesizeProvisionalIvar(Sema &SemaRef,
- IdentifierInfo *II,
- SourceLocation NameLoc) {
- ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl();
+ObjCPropertyDecl *Sema::canSynthesizeProvisionalIvar(IdentifierInfo *II) {
+ ObjCMethodDecl *CurMeth = getCurMethodDecl();
ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface();
if (!IDecl)
return 0;
ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation();
if (!ClassImpDecl)
return 0;
- ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II);
+ ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II);
if (!property)
return 0;
if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II))
- if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic ||
+ PIDecl->getPropertyIvarDecl())
return 0;
return property;
}
+bool Sema::canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property) {
+ ObjCMethodDecl *CurMeth = getCurMethodDecl();
+ ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface();
+ if (!IDecl)
+ return false;
+ ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation();
+ if (!ClassImpDecl)
+ return false;
+ if (ObjCPropertyImplDecl *PIDecl
+ = ClassImpDecl->FindPropertyImplDecl(Property->getIdentifier()))
+ if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic ||
+ PIDecl->getPropertyIvarDecl())
+ return false;
+
+ return true;
+}
+
static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef,
LookupResult &Lookup,
IdentifierInfo *II,
@@ -1228,8 +1244,7 @@
if (getLangOptions().ObjCNonFragileABI && IvarLookupFollowUp &&
!getLangOptions().ObjCNonFragileABI2 &&
Var->isFileVarDecl()) {
- ObjCPropertyDecl *Property =
- OkToSynthesizeProvisionalIvar(*this, II, NameLoc);
+ ObjCPropertyDecl *Property = canSynthesizeProvisionalIvar(II);
if (Property) {
Diag(NameLoc, diag::warn_ivar_variable_conflict) << Var->getDeclName();
Diag(Property->getLocation(), diag::note_property_declare);
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index acc5b35..f0c21f4 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -2630,9 +2630,27 @@
// For instance methods, look for ivars in the method's interface.
LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
Result.getNameLoc(), Sema::LookupMemberName);
- if (ObjCInterfaceDecl *IFace = Method->getClassInterface())
+ if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
/*InBaseClass=*/false, Consumer, Visited);
+
+ // Look for properties from which we can synthesize ivars, if
+ // permitted.
+ if (Result.getSema().getLangOptions().ObjCNonFragileABI2 &&
+ IFace->getImplementation() &&
+ Result.getLookupKind() == Sema::LookupOrdinaryName) {
+ for (ObjCInterfaceDecl::prop_iterator
+ P = IFace->prop_begin(),
+ PEnd = IFace->prop_end();
+ P != PEnd; ++P) {
+ if (Result.getSema().canSynthesizeProvisionalIvar(*P) &&
+ !IFace->lookupInstanceVariable((*P)->getIdentifier())) {
+ Consumer.FoundDecl(*P, Visited.checkHidden(*P), false);
+ Visited.add(*P);
+ }
+ }
+ }
+ }
}
// We've already performed all of the name lookup that we need