CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402,
- CXCursor_LastAttr = CXCursor_IBOutletAttr,
+ CXCursor_IBOutletCollectionAttr = 403,
+ CXCursor_LastAttr = CXCursor_IBOutletCollectionAttr,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
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 ();
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,
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) {}
// 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<
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,
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;
}
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;
// (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;
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);
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());
.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)
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
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:
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)=
// 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]
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:
default: break;
case Attr::IBActionKind: return CXCursor_IBActionAttr;
case Attr::IBOutletKind: return CXCursor_IBOutletAttr;
+ case Attr::IBOutletCollectionKind: return CXCursor_IBOutletCollectionAttr;
}
return CXCursor_UnexposedAttr;