[cfe-commits] r104055 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaObjCProperty.cpp test/Index/properties-class-extensions.m tools/libclang/CIndex.cpp

Ted Kremenek kremenek at apple.com
Tue May 18 14:09:07 PDT 2010


Author: kremenek
Date: Tue May 18 16:09:07 2010
New Revision: 104055

URL: http://llvm.org/viewvc/llvm-project?rev=104055&view=rev
Log:
Teach CursorVisitor about duplicate ObjCPropertyDecls that can arise because of a current
design limitation in how we handle Objective-C class extensions.  This was causing the CursorVisitor
to essentially visit an @property twice (once in the @interface, the other in the class extension).
Fixes <rdar://problem/7410145>.

Added:
    cfe/trunk/test/Index/properties-class-extensions.m
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/tools/libclang/CIndex.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=104055&r1=104054&r2=104055&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue May 18 16:09:07 2010
@@ -1597,7 +1597,8 @@
                                        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

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=104055&r1=104054&r2=104055&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Tue May 18 16:09:07 2010
@@ -121,7 +121,7 @@
     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 @@
                                            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 @@
     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 @@
                              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 @@
                                                   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

Added: cfe/trunk/test/Index/properties-class-extensions.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/properties-class-extensions.m?rev=104055&view=auto
==============================================================================
--- cfe/trunk/test/Index/properties-class-extensions.m (added)
+++ cfe/trunk/test/Index/properties-class-extensions.m Tue May 18 16:09:07 2010
@@ -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).
+ at interface Foo {} @end
+ at interface Foo (Cat)
+  @property int a;
+ at end
+ at interface Foo ()
+  @property int b;
+  - (void) bar;
+ at 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]
+

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=104055&r1=104054&r2=104055&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Tue May 18 16:09:07 2010
@@ -297,6 +297,7 @@
   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 @@
   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 @@
   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 @@
   // 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();





More information about the cfe-commits mailing list