diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-05-19 17:38:06 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-05-19 17:38:06 +0000 |
commit | 857e918a8a40deb128840308a318bf623d68295f (patch) | |
tree | f983e536db0a65dd511df9747db40faf4ace043d | |
parent | 4469e8a97cdca3725b4f8f366916143113c029ac (diff) |
Add clang support for IBOutletCollection.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104135 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang-c/Index.h | 3 | ||||
-rw-r--r-- | include/clang/AST/Attr.h | 21 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Parse/AttributeList.h | 1 | ||||
-rw-r--r-- | lib/AST/AttrImpl.cpp | 4 | ||||
-rw-r--r-- | lib/Checker/CheckObjCDealloc.cpp | 3 | ||||
-rw-r--r-- | lib/Checker/ObjCUnusedIVarsChecker.cpp | 3 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderDecl.cpp | 7 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/AttributeList.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 24 | ||||
-rw-r--r-- | test/Index/c-index-api-loadTU-test.m | 22 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 2 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 1 |
14 files changed, 94 insertions, 7 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index fa35d058e5..75ad31a061 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -810,7 +810,8 @@ enum CXCursorKind { CXCursor_IBActionAttr = 401, CXCursor_IBOutletAttr = 402, - CXCursor_LastAttr = CXCursor_IBOutletAttr, + CXCursor_IBOutletCollectionAttr = 403, + CXCursor_LastAttr = CXCursor_IBOutletCollectionAttr, /* Preprocessing */ CXCursor_PreprocessingDirective = 500, diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 6bdb4a2fb6..f41fbf9bcf 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -23,9 +23,10 @@ using llvm::dyn_cast; namespace clang { class ASTContext; + class IdentifierInfo; + class ObjCInterfaceDecl; } - // Defined in ASTContext.h void *operator new(size_t Bytes, clang::ASTContext &C, size_t Alignment = 16) throw (); @@ -63,6 +64,7 @@ public: GNUInline, Hiding, IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro. + IBOutletCollectionKind, // Clang-specific. IBActionKind, // Clang-specific. Use "Kind" suffix to not conflict w/ macro. Malloc, NoDebug, @@ -318,6 +320,23 @@ public: static bool classof(const IBOutletAttr *A) { return true; } }; +class IBOutletCollectionAttr : public Attr { + const ObjCInterfaceDecl *D; +public: + IBOutletCollectionAttr(const ObjCInterfaceDecl *d = 0) + : Attr(IBOutletCollectionKind), D(d) {} + + const ObjCInterfaceDecl *getClass() const { return D; } + + virtual Attr *clone(ASTContext &C) const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() == IBOutletCollectionKind; + } + static bool classof(const IBOutletCollectionAttr *A) { return true; } +}; + class IBActionAttr : public Attr { public: IBActionAttr() : Attr(IBActionKind) {} diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2298f6a3e9..03c9c0e7e4 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -957,8 +957,7 @@ def err_attribute_regparm_invalid_number : Error< // Clang-Specific Attributes def err_attribute_iboutlet : Error< - "iboutlet attribute can only be applied to instance variables or " - "properties">; + "%0 attribute can only be applied to instance variables or properties">; def err_attribute_ibaction: Error< "ibaction attribute can only be applied to Objective-C instance methods">; def err_attribute_overloadable_not_function : Error< diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 68d6f22c9b..1e6d3ab976 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -55,6 +55,7 @@ public: enum Kind { // Please keep this list alphabetized. AT_IBAction, // Clang-specific. AT_IBOutlet, // Clang-specific. + AT_IBOutletCollection, // Clang-specific. AT_address_space, AT_alias, AT_aligned, diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index 0345226787..1f3510d7b5 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -143,6 +143,10 @@ Attr *IBOutletAttr::clone(ASTContext &C) const { return ::new (C) IBOutletAttr; } +Attr *IBOutletCollectionAttr::clone(ASTContext &C) const { + return ::new (C) IBOutletCollectionAttr(D); +} + Attr *IBActionAttr::clone(ASTContext &C) const { return ::new (C) IBActionAttr; } diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp index c23be873f4..11ddaca9d6 100644 --- a/lib/Checker/CheckObjCDealloc.cpp +++ b/lib/Checker/CheckObjCDealloc.cpp @@ -115,7 +115,8 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, QualType T = ID->getType(); if (!T->isObjCObjectPointerType() || - ID->getAttr<IBOutletAttr>()) // Skip IBOutlets. + ID->getAttr<IBOutletAttr>() || // Skip IBOutlets. + ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections. continue; containsPointerIvar = true; diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp index 0e47621d42..2523cff9d8 100644 --- a/lib/Checker/ObjCUnusedIVarsChecker.cpp +++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp @@ -114,7 +114,8 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, // (b) explicitly marked unused // (c) are iboutlets if (ID->getAccessControl() != ObjCIvarDecl::Private || - ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>()) + ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() || + ID->getAttr<IBOutletCollectionAttr>()) continue; M[ID] = Unused; diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 1e8bd2fe55..0aee70cedc 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -726,6 +726,13 @@ Attr *PCHReader::ReadAttributes() { New = ::new (*Context) IBOutletAttr(); break; + case Attr::IBOutletCollectionKind: { + ObjCInterfaceDecl *D = + cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); + New = ::new (*Context) IBOutletCollectionAttr(D); + break; + } + SIMPLE_ATTR(Malloc); SIMPLE_ATTR(NoDebug); SIMPLE_ATTR(NoInline); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 88d197271d..f8415cd052 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1917,6 +1917,12 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { case Attr::NoThrow: break; + case Attr::IBOutletCollectionKind: { + const IBOutletCollectionAttr *ICA = cast<IBOutletCollectionAttr>(Attr); + AddDeclRef(ICA->getClass(), Record); + break; + } + case Attr::NonNull: { const NonNullAttr *NonNull = cast<NonNullAttr>(Attr); Record.push_back(NonNull->size()); diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 53406280bb..1ebff22e44 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -84,6 +84,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("fastcall", AT_fastcall) .Case("ibaction", AT_IBAction) .Case("iboutlet", AT_IBOutlet) + .Case("iboutletcollection", AT_IBOutletCollection) .Case("noreturn", AT_noreturn) .Case("noinline", AT_noinline) .Case("override", AT_override) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 3ae681a17d..c6dcc3b97b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -259,6 +259,26 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); } +static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, + Sema &S) { + + // The iboutletcollection attribute can have zero or one arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // The IBOutletCollection attributes only apply to instance variables of + // Objective-C classes. + if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) { + S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); + return; + } + + // FIXME: Eventually accept the type argument. + d->addAttr(::new (S.Context) IBOutletCollectionAttr()); +} + static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // GCC ignores the nonnull attribute on K&R style function prototypes, so we // ignore it as well @@ -1884,7 +1904,9 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, return; switch (Attr.getKind()) { case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break; - case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; + case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; + case AttributeList::AT_IBOutletCollection: + HandleIBOutletCollection(D, Attr, S); break; case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: case AttributeList::AT_vector_size: diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m index d97f963a3a..22875dbfe8 100644 --- a/test/Index/c-index-api-loadTU-test.m +++ b/test/Index/c-index-api-loadTU-test.m @@ -54,6 +54,18 @@ int main (int argc, const char * argv[]) { main(someEnum, (const char **)bee); } +// Test attribute traversal. +#define IBOutlet __attribute__((iboutlet)) +#define IBOutletCollection(ClassName) __attribute__((iboutletcollection)) +#define IBAction void)__attribute__((ibaction) + +@interface TestAttributes { + IBOutlet char * anOutlet; + IBOutletCollection(id) id anOutletCollection; +} +- (IBAction) actionMethod:(id)arg; +@end + // CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5] // CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:32 - 6:40] // CHECK: <invalid loc>:0:0: attribute(iboutlet)= @@ -123,4 +135,14 @@ int main (int argc, const char * argv[]) { // CHECK: c-index-api-loadTU-test.m:54:8: DeclRefExpr=someEnum:43:3 Extent=[54:8 - 54:16] // CHECK: c-index-api-loadTU-test.m:54:18: UnexposedExpr=bee:47:8 Extent=[54:18 - 54:36] // CHECK: c-index-api-loadTU-test.m:54:33: DeclRefExpr=bee:47:8 Extent=[54:33 - 54:36] +// CHECK: c-index-api-loadTU-test.m:62:12: ObjCInterfaceDecl=TestAttributes:62:12 Extent=[62:1 - 67:5] +// CHECK: c-index-api-loadTU-test.m:63:19: ObjCIvarDecl=anOutlet:63:19 (Definition) Extent=[63:19 - 63:27] +// CHECK: <invalid loc>:0:0: attribute(iboutlet)= +// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[64:29 - 64:47] +// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)= +// CHECK: c-index-api-loadTU-test.m:64:26: TypeRef=id:0:0 Extent=[64:26 - 64:28] +// CHECK: c-index-api-loadTU-test.m:66:1: ObjCInstanceMethodDecl=actionMethod::66:1 Extent=[66:1 - 66:35] +// CHECK: <invalid loc>:0:0: attribute(ibaction)= +// CHECK: c-index-api-loadTU-test.m:66:31: ParmDecl=arg:66:31 (Definition) Extent=[66:28 - 66:34] +// CHECK: c-index-api-loadTU-test.m:66:28: TypeRef=id:0:0 Extent=[66:28 - 66:30] diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 85383d0be0..563dd6b027 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1726,6 +1726,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("attribute(ibaction)"); case CXCursor_IBOutletAttr: return createCXString("attribute(iboutlet)"); + case CXCursor_IBOutletCollectionAttr: + return createCXString("attribute(iboutletcollection)"); case CXCursor_PreprocessingDirective: return createCXString("preprocessing directive"); case CXCursor_MacroDefinition: diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index dea7b4d9d3..f7192dd7e2 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -80,6 +80,7 @@ static CXCursorKind GetCursorKind(const Attr *A) { default: break; case Attr::IBActionKind: return CXCursor_IBActionAttr; case Attr::IBOutletKind: return CXCursor_IBOutletAttr; + case Attr::IBOutletCollectionKind: return CXCursor_IBOutletCollectionAttr; } return CXCursor_UnexposedAttr; |