Fix a major inconsistency in the representation of Objective-C

classes, categories, protocols, and class extensions, where the
methods and properties of these entities would be inserted into the
DeclContext in an ordering that doesn't necessarily reflect source
order. The culprits were Sema::ActOnMethodDeclaration(), which did not
perform the insertion of the just-created method declaration into
the DeclContext for these Objective-C entities, and
Sema::ActOnAtEnd(), which inserted all method declarations at the
*end* of the DeclContext. 

With this fix in hand, clean up the code-completion actions for
property setters/getters that worked around this brokenness in the AST.

Fixes <rdar://problem/8062781>, where this problem manifested as poor
token-annotation information, but this would have struck again in many
other places.

llvm-svn: 122347
This commit is contained in:
Douglas Gregor 2010-12-21 17:34:17 +00:00
parent be57ab185f
commit 87e927520d
7 changed files with 56 additions and 70 deletions

View File

@ -983,8 +983,7 @@ private:
Decl *ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType,
Decl *classDecl,
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
void ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl,
Decl **Methods, unsigned NumMethods);
void ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl);
Decl *ParseObjCMethodDefinition();

View File

@ -4645,12 +4645,8 @@ public:
void CodeCompleteObjCAtStatement(Scope *S);
void CodeCompleteObjCAtExpression(Scope *S);
void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS);
void CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl,
Decl **Methods,
unsigned NumMethods);
void CodeCompleteObjCPropertySetter(Scope *S, Decl *ClassDecl,
Decl **Methods,
unsigned NumMethods);
void CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl);
void CodeCompleteObjCPropertySetter(Scope *S, Decl *ClassDecl);
void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS);
void CodeCompleteObjCMessageReceiver(Scope *S);
void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,

View File

@ -426,8 +426,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
ObjCDeclSpec OCDS;
// Parse property attribute list, if any.
if (Tok.is(tok::l_paren))
ParseObjCPropertyAttribute(OCDS, interfaceDecl,
allMethods.data(), allMethods.size());
ParseObjCPropertyAttribute(OCDS, interfaceDecl);
ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties,
OCDS, AtLoc, MethodImplKind);
@ -476,9 +475,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
/// copy
/// nonatomic
///
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl,
Decl **Methods,
unsigned NumMethods) {
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
assert(Tok.getKind() == tok::l_paren);
SourceLocation LHSLoc = ConsumeParen(); // consume '('
@ -523,11 +520,9 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl,
if (Tok.is(tok::code_completion)) {
if (IsSetter)
Actions.CodeCompleteObjCPropertySetter(getCurScope(), ClassDecl,
Methods, NumMethods);
Actions.CodeCompleteObjCPropertySetter(getCurScope(), ClassDecl);
else
Actions.CodeCompleteObjCPropertyGetter(getCurScope(), ClassDecl,
Methods, NumMethods);
Actions.CodeCompleteObjCPropertyGetter(getCurScope(), ClassDecl);
ConsumeCodeCompletionToken();
}

View File

@ -4171,9 +4171,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
}
void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl,
Decl **Methods,
unsigned NumMethods) {
void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) {
typedef CodeCompletionResult Result;
// Try to find the interface where getters might live.
@ -4191,19 +4189,6 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl,
ResultBuilder Results(*this, CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
// FIXME: We need to do this because Objective-C methods don't get
// pushed into DeclContexts early enough. Argh!
for (unsigned I = 0; I != NumMethods; ++I) {
if (ObjCMethodDecl *Method
= dyn_cast_or_null<ObjCMethodDecl>(Methods[I]))
if (Method->isInstanceMethod() &&
isAcceptableObjCMethod(Method, MK_ZeroArgSelector, 0, 0)) {
Result R = Result(Method, 0);
R.AllParametersAreInformative = true;
Results.MaybeAddResult(R, CurContext);
}
}
VisitedSelectorSet Selectors;
AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Selectors,
/*AllowSameLength=*/true, Results);
@ -4213,9 +4198,7 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl,
Results.data(),Results.size());
}
void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl,
Decl **Methods,
unsigned NumMethods) {
void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl) {
typedef CodeCompletionResult Result;
// Try to find the interface where setters might live.
@ -4234,19 +4217,6 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl,
ResultBuilder Results(*this, CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
// FIXME: We need to do this because Objective-C methods don't get
// pushed into DeclContexts early enough. Argh!
for (unsigned I = 0; I != NumMethods; ++I) {
if (ObjCMethodDecl *Method
= dyn_cast_or_null<ObjCMethodDecl>(Methods[I]))
if (Method->isInstanceMethod() &&
isAcceptableObjCMethod(Method, MK_OneArgSelector, 0, 0)) {
Result R = Result(Method, 0);
R.AllParametersAreInformative = true;
Results.MaybeAddResult(R, CurContext);
}
}
VisitedSelectorSet Selectors;
AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext,
Selectors, /*AllowSameLength=*/true, Results);

View File

@ -1475,8 +1475,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(L, diag::warn_missing_atend);
}
DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
// FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
@ -1496,8 +1494,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(Method->getLocation(), diag::err_duplicate_method_decl)
<< Method->getDeclName();
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
Method->setInvalidDecl();
} else {
DC->addDecl(Method);
InsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "id".
AddInstanceMethodToGlobalPool(Method);
@ -1515,8 +1513,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Diag(Method->getLocation(), diag::err_duplicate_method_decl)
<< Method->getDeclName();
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
Method->setInvalidDecl();
} else {
DC->addDecl(Method);
ClsMap[Method->getSelector()] = Method;
/// The following allows us to typecheck messages to "Class".
AddFactoryMethodToGlobalPool(Method);
@ -1773,10 +1771,7 @@ Decl *Sema::ActOnMethodDeclaration(
const ObjCMethodDecl *InterfaceMD = 0;
// For implementations (which can be very "coarse grain"), we add the
// method now. This allows the AST to implement lookup methods that work
// incrementally (without waiting until we parse the @end). It also allows
// us to flag multiple declaration errors as they occur.
// Add the method now.
if (ObjCImplementationDecl *ImpDecl =
dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
if (MethodType == tok::minus) {
@ -1803,6 +1798,8 @@ Decl *Sema::ActOnMethodDeclaration(
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
Diag(EndLoc, diag::warn_attribute_method_def);
} else {
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
}
if (PrevMethod) {
// You can never have two method definitions with the same name.

View File

@ -131,6 +131,11 @@ static Rdar8595462_A * Rdar8595462_staticVar;
}
@end
@interface Rdar8062781
+ (Foo*)getB;
@property (readonly, nonatomic) Foo *blah;
@end
// RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=Foo:1:12
@ -305,17 +310,17 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "anOutlet" [53:21 - 53:29] ObjCIvarDecl=anOutlet:53:21 (Definition)
// CHECK: Punctuation: ";" [53:29 - 53:30] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: "}" [54:1 - 54:2] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: "-" [55:1 - 55:2] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: "(" [55:3 - 55:4] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Identifier: "IBAction" [55:4 - 55:12] macro instantiation=IBAction
// CHECK: Punctuation: ")" [55:12 - 55:13] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Identifier: "actionMethod" [55:14 - 55:26] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: ":" [55:26 - 55:27] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: "(" [55:27 - 55:28] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Identifier: "id" [55:28 - 55:30] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: ")" [55:30 - 55:31] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Identifier: "arg" [55:31 - 55:34] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: ";" [55:34 - 55:35] ObjCInterfaceDecl=IBOutletTests:51:12
// CHECK: Punctuation: "-" [55:1 - 55:2] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Punctuation: "(" [55:3 - 55:4] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Identifier: "IBAction" [55:4 - 55:12] macro instantiation=IBAction:146:9
// CHECK: Punctuation: ")" [55:12 - 55:13] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Identifier: "actionMethod" [55:14 - 55:26] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Punctuation: ":" [55:26 - 55:27] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Punctuation: "(" [55:27 - 55:28] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Identifier: "id" [55:28 - 55:30] TypeRef=id:0:0
// CHECK: Punctuation: ")" [55:30 - 55:31] ParmDecl=arg:55:31 (Definition)
// CHECK: Identifier: "arg" [55:31 - 55:34] ParmDecl=arg:55:31 (Definition)
// CHECK: Punctuation: ";" [55:34 - 55:35] ObjCInstanceMethodDecl=actionMethod::55:1
// CHECK: Punctuation: "@" [56:1 - 56:2] ObjCPropertyDecl=aPropOutlet:56:26
// CHECK: Keyword: "property" [56:2 - 56:10] ObjCPropertyDecl=aPropOutlet:56:26
// CHECK: Identifier: "IBOutlet" [56:11 - 56:19] macro instantiation=IBOutlet
@ -519,3 +524,27 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK-INSIDE_BLOCK: Identifier: "a" [128:18 - 128:19] VarDecl=a:128:18 (Definition)
// CHECK-INSIDE_BLOCK: Punctuation: "=" [128:20 - 128:21] VarDecl=a:128:18 (Definition)
// CHECK-INSIDE_BLOCK: Identifier: "self" [128:22 - 128:26] DeclRefExpr=self:0:0
// RUN: c-index-test -test-annotate-tokens=%s:134:1:137:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck -check-prefix=CHECK-PROP-AFTER-METHOD %s
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [134:1 - 134:2] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Keyword: "interface" [134:2 - 134:11] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Identifier: "Rdar8062781" [134:12 - 134:23] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Punctuation: "+" [135:1 - 135:2] ObjCClassMethodDecl=getB:135:1
// CHECK-PROP-AFTER-METHOD: Punctuation: "(" [135:3 - 135:4] ObjCClassMethodDecl=getB:135:1
// CHECK-PROP-AFTER-METHOD: Identifier: "Foo" [135:4 - 135:7] ObjCClassRef=Foo:1:12
// CHECK-PROP-AFTER-METHOD: Punctuation: "*" [135:7 - 135:8] ObjCClassMethodDecl=getB:135:1
// CHECK-PROP-AFTER-METHOD: Punctuation: ")" [135:8 - 135:9] ObjCClassMethodDecl=getB:135:1
// CHECK-PROP-AFTER-METHOD: Identifier: "getB" [135:9 - 135:13] ObjCClassMethodDecl=getB:135:1
// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [135:13 - 135:14] ObjCClassMethodDecl=getB:135:1
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [136:1 - 136:2] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Keyword: "property" [136:2 - 136:10] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: "(" [136:11 - 136:12] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Identifier: "readonly" [136:12 - 136:20] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: "," [136:20 - 136:21] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Identifier: "nonatomic" [136:22 - 136:31] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: ")" [136:31 - 136:32] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Identifier: "Foo" [136:33 - 136:36] ObjCClassRef=Foo:1:12
// CHECK-PROP-AFTER-METHOD: Punctuation: "*" [136:37 - 136:38] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Identifier: "blah" [136:38 - 136:42] ObjCPropertyDecl=blah:136:38
// CHECK-PROP-AFTER-METHOD: Punctuation: ";" [136:42 - 136:43] ObjCInterfaceDecl=Rdar8062781:134:12
// CHECK-PROP-AFTER-METHOD: Punctuation: "@" [137:1 - 137:2] ObjCInterfaceDecl=Rdar8062781:134:12

View File

@ -95,9 +95,9 @@ int test_multi_declaration(void) {
// CHECK: usrs.m c:objc(cs)Foo Extent=[25:1 - 32:5]
// CHECK: usrs.m c:objc(cs)Foo@x Extent=[26:6 - 26:7]
// CHECK: usrs.m c:objc(cs)Foo@y Extent=[27:6 - 27:7]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[31:1 - 31:17]
// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[29:1 - 29:17]
// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[30:1 - 30:17]
// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[31:1 - 31:17]
// CHECK: usrs.m c:objc(cs)Foo(im)d1 Extent=[31:15 - 31:17]
// CHECK: usrs.m c:objc(cs)Foo(im)setD1: Extent=[31:15 - 31:17]
// CHECK: usrs.m c:usrs.m@352objc(cs)Foo(im)setD1:@d1 Extent=[31:15 - 31:17]
@ -160,11 +160,11 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:26:3: TypeRef=id:0:0 Extent=[26:3 - 26:5]
// CHECK-source: usrs.m:27:6: ObjCIvarDecl=y:27:6 (Definition) Extent=[27:6 - 27:7]
// CHECK-source: usrs.m:27:3: TypeRef=id:0:0 Extent=[27:3 - 27:5]
// CHECK-source: usrs.m:31:15: ObjCPropertyDecl=d1:31:15 Extent=[31:1 - 31:17]
// CHECK-source: usrs.m:29:1: ObjCInstanceMethodDecl=godzilla:29:1 Extent=[29:1 - 29:17]
// CHECK-source: usrs.m:29:4: TypeRef=id:0:0 Extent=[29:4 - 29:6]
// CHECK-source: usrs.m:30:1: ObjCClassMethodDecl=kingkong:30:1 Extent=[30:1 - 30:17]
// CHECK-source: usrs.m:30:4: TypeRef=id:0:0 Extent=[30:4 - 30:6]
// CHECK-source: usrs.m:31:15: ObjCPropertyDecl=d1:31:15 Extent=[31:1 - 31:17]
// CHECK-source: usrs.m:31:15: ObjCInstanceMethodDecl=d1:31:15 Extent=[31:15 - 31:17]
// CHECK-source: usrs.m:31:15: ObjCInstanceMethodDecl=setD1::31:15 Extent=[31:15 - 31:17]
// CHECK-source: usrs.m:31:15: ParmDecl=d1:31:15 (Definition) Extent=[31:15 - 31:17]