forked from OSchip/llvm-project
Teach code completion to provide property results when the property
can be used to automatically synthesize an ivar. llvm-svn: 118052
This commit is contained in:
parent
2c3991acf3
commit
05fcf84d14
|
@ -1377,6 +1377,14 @@ public:
|
|||
ObjCIvarDecl **Fields, unsigned nIvars,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// \brief Determine whether we can synthesize a provisional ivar for the
|
||||
/// given name.
|
||||
ObjCPropertyDecl *canSynthesizeProvisionalIvar(IdentifierInfo *II);
|
||||
|
||||
/// \brief Determine whether we can synthesize a provisional ivar for the
|
||||
/// given property.
|
||||
bool canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property);
|
||||
|
||||
/// ImplMethodsVsClassMethods - This is main routine to warn if any method
|
||||
/// remains unimplemented in the class or category @implementation.
|
||||
void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
|
||||
|
|
|
@ -147,9 +147,13 @@ namespace {
|
|||
/// \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 @@ namespace {
|
|||
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 @@ namespace {
|
|||
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 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
|
|||
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 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1027,25 +1027,41 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
|
|||
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 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
|
|||
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);
|
||||
|
|
|
@ -2630,9 +2630,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
|
|||
// 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
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// Note: this test is line- and column-sensitive. Test commands are at
|
||||
// the end.
|
||||
|
||||
|
||||
@interface A
|
||||
@property int prop1;
|
||||
@end
|
||||
|
||||
@interface B : A {
|
||||
float _prop2;
|
||||
}
|
||||
@property float prop2;
|
||||
@property short prop3;
|
||||
@end
|
||||
|
||||
@interface B ()
|
||||
@property double prop4;
|
||||
@end
|
||||
|
||||
@implementation B
|
||||
@synthesize prop2 = _prop2;
|
||||
|
||||
- (int)method {
|
||||
return _prop2;
|
||||
}
|
||||
|
||||
@dynamic prop3;
|
||||
|
||||
- (short)method2 {
|
||||
return prop4;
|
||||
}
|
||||
|
||||
- (short)method3 {
|
||||
return prop3;
|
||||
}
|
||||
@end
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:24:1 -Xclang -fobjc-nonfragile-abi2 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: NotImplemented:{TypedText _Bool} (50)
|
||||
// CHECK-CC1: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
|
||||
// CHECK-CC1-NOT: prop2
|
||||
// CHECK-CC1: ObjCPropertyDecl:{ResultType short}{TypedText prop3} (35)
|
||||
// CHECK-CC1: ObjCPropertyDecl:{ResultType double}{TypedText prop4} (35)
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:30:2 -Xclang -fobjc-nonfragile-abi2 %s | FileCheck -check-prefix=CHECK-CC2 %s
|
||||
// CHECK-CC2: NotImplemented:{TypedText _Bool} (50)
|
||||
// CHECK-CC2: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
|
||||
// CHECK-CC2-NOT: prop3
|
||||
// CHECK-CC2: ObjCPropertyDecl:{ResultType double}{TypedText prop4} (35)
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:34:2 -Xclang -fobjc-nonfragile-abi2 %s | FileCheck -check-prefix=CHECK-CC3 %s
|
||||
// CHECK-CC3: NotImplemented:{TypedText _Bool} (50)
|
||||
// CHECK-CC3: ObjCIvarDecl:{ResultType float}{TypedText _prop2} (35)
|
||||
// CHECK-CC3: ObjCIvarDecl:{ResultType double}{TypedText prop4}
|
||||
// CHECK-CC3-NOT: ObjCPropertyDecl:{ResultType double}{TypedText prop4} (35)
|
||||
// CHECK-CC1: restrict
|
Loading…
Reference in New Issue