Add clang support for IBOutletCollection.

llvm-svn: 104135
This commit is contained in:
Ted Kremenek 2010-05-19 17:38:06 +00:00
parent 52e37becf6
commit 26bde774df
14 changed files with 94 additions and 7 deletions

View File

@ -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,

View File

@ -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) {}

View File

@ -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<

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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());

View File

@ -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)

View File

@ -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:

View File

@ -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]

View File

@ -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:

View File

@ -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;