diff options
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 19 | ||||
-rw-r--r-- | test/Index/properties-class-extensions.m | 28 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 51 |
4 files changed, 94 insertions, 7 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 975516ff9a..432e9e701b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1597,7 +1597,8 @@ public: const bool isAssign, const bool isReadWrite, const unsigned Attributes, QualType T, - tok::ObjCKeywordKind MethodImplKind); + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = 0); /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 69a338224e..453ea25859 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -121,7 +121,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CCPrimary, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, - Attributes, T, MethodImplKind); + Attributes, T, MethodImplKind, DC); // A case of continuation class adding a new property in the class. This // is not what it was meant for. However, gcc supports it and so should we. @@ -191,7 +191,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, const bool isReadWrite, const unsigned Attributes, QualType T, - tok::ObjCKeywordKind MethodImplKind){ + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC){ IdentifierInfo *PropertyId = FD.D.getIdentifier(); @@ -222,8 +223,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, Diag(prevDecl->getLocation(), diag::note_property_declare); PDecl->setInvalidDecl(); } - else + else { DC->addDecl(PDecl); + if (lexicalDC) + PDecl->setLexicalDeclContext(lexicalDC); + } if (T->isArrayType() || T->isFunctionType()) { Diag(AtLoc, diag::err_property_type) << T; @@ -1064,6 +1068,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCMethodDecl::Optional : ObjCMethodDecl::Required); CD->addDecl(GetterMethod); + // FIXME: Eventually this shouldn't be needed, as the lexical context + // and the real context should be the same. + if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + GetterMethod->setLexicalDeclContext(lexicalDC); + } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -1097,6 +1106,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, 0); SetterMethod->setMethodParams(Context, &Argument, 1, 1); CD->addDecl(SetterMethod); + // FIXME: Eventually this shouldn't be needed, as the lexical context + // and the real context should be the same. + if (DeclContext *lexicalDC = property->getLexicalDeclContext()) + SetterMethod->setLexicalDeclContext(lexicalDC); } else // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation diff --git a/test/Index/properties-class-extensions.m b/test/Index/properties-class-extensions.m new file mode 100644 index 0000000000..8bca37e7c9 --- /dev/null +++ b/test/Index/properties-class-extensions.m @@ -0,0 +1,28 @@ +// Test that @properties within class extensions are visited by +// clang_visitChildren only in the class extension, not the original +// @interface (where we have a duplicate declaration - to be removed). +@interface Foo {} @end +@interface Foo (Cat) + @property int a; +@end +@interface Foo () + @property int b; + - (void) bar; +@end + +// RUN: c-index-test -test-load-source local %s | FileCheck %s +// CHECK: properties-class-extensions.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 4:23] +// CHECK: properties-class-extensions.m:5:12: ObjCCategoryDecl=Cat:5:12 Extent=[5:1 - 7:5] +// CHECK: properties-class-extensions.m:5:12: ObjCClassRef=Foo:4:12 Extent=[5:12 - 5:15] +// CHECK: properties-class-extensions.m:6:17: ObjCPropertyDecl=a:6:17 Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:6:17: ObjCInstanceMethodDecl=a:6:17 Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:6:17: ObjCInstanceMethodDecl=setA::6:17 Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:6:17: ParmDecl=a:6:17 (Definition) Extent=[6:17 - 6:18] +// CHECK: properties-class-extensions.m:8:12: ObjCCategoryDecl=:8:12 Extent=[8:1 - 11:5] +// CHECK: properties-class-extensions.m:8:12: ObjCClassRef=Foo:4:12 Extent=[8:12 - 8:15] +// CHECK: properties-class-extensions.m:9:17: ObjCPropertyDecl=b:9:17 Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:9:17: ObjCInstanceMethodDecl=b:9:17 Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:9:17: ObjCInstanceMethodDecl=setB::9:17 Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:9:17: ParmDecl=b:9:17 (Definition) Extent=[9:17 - 9:18] +// CHECK: properties-class-extensions.m:10:3: ObjCInstanceMethodDecl=bar:10:3 Extent=[10:3 - 10:16] + diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 9de7c0b06e..6ea1619c3d 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -297,6 +297,7 @@ public: bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); bool VisitObjCImplDecl(ObjCImplDecl *D); bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); @@ -528,7 +529,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { - CXCursor Cursor = MakeCXCursor(*I, TU); + Decl *D = *I; + if (D->getLexicalDeclContext() != DC) + continue; + + CXCursor Cursor = MakeCXCursor(D, TU); if (RegionOfInterest.isValid()) { SourceRange Range = @@ -666,6 +671,40 @@ bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { return VisitObjCContainerDecl(PID); } +bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { + // FIXME: This implements a workaround with @property declarations also being + // installed in the DeclContext for the @interface. Eventually this code + // should be removed. + ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(PD->getDeclContext()); + if (!CDecl || !CDecl->IsClassExtension()) + return false; + + ObjCInterfaceDecl *ID = CDecl->getClassInterface(); + if (!ID) + return false; + + IdentifierInfo *PropertyId = PD->getIdentifier(); + ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId); + + if (!prevDecl) + return false; + + // Visit synthesized methods since they will be skipped when visiting + // the @interface. + if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + return false; +} + bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Issue callbacks for super class. if (D->getSuperClass() && @@ -2480,8 +2519,14 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { // Adjust the annotated range based specific declarations. const enum CXCursorKind cursorK = clang_getCursorKind(cursor); if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) { - if (const DeclaratorDecl *DD = - dyn_cast<DeclaratorDecl>(cxcursor::getCursorDecl(cursor))) { + Decl *D = cxcursor::getCursorDecl(cursor); + // Don't visit synthesized ObjC methods, since they have no syntatic + // representation in the source. + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->isSynthesized()) + return CXChildVisit_Continue; + } + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) { TypeLoc TL = TI->getTypeLoc(); SourceLocation TLoc = TL.getFullSourceRange().getBegin(); |