From bdb2d5056fd675c27307b34efd371bbba6839e92 Mon Sep 17 00:00:00 2001 From: Douglas Gregor <dgregor@apple.com> Date: Tue, 21 Dec 2010 17:34:17 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122347 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 3 +-- include/clang/Sema/Sema.h | 8 ++---- lib/Parse/ParseObjc.cpp | 13 +++------ lib/Sema/SemaCodeComplete.cpp | 34 ++--------------------- lib/Sema/SemaDeclObjC.cpp | 13 ++++----- test/Index/annotate-tokens.m | 51 +++++++++++++++++++++++++++-------- test/Index/usrs.m | 4 +-- 7 files changed, 56 insertions(+), 70 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 6063237323a..3b6aceb5cd4 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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(); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ad96c675e2f..4eba0e5c3cc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index f1c48a6a3a1..cd1321ed832 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -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(); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 76452a45168..b33f3fcb7c1 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -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); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 5d9a924ed8c..d19991138ee 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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. diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m index f499cf82415..a271c51a30c 100644 --- a/test/Index/annotate-tokens.m +++ b/test/Index/annotate-tokens.m @@ -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 diff --git a/test/Index/usrs.m b/test/Index/usrs.m index 2d41c47f9c2..f34cc1e87bf 100644 --- a/test/Index/usrs.m +++ b/test/Index/usrs.m @@ -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] -- GitLab