From db5d8792d4fdb806acd128d619917538325d23c6 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 4 Dec 2013 20:32:50 +0000 Subject: [PATCH] ObjectiveC - Introducing objc_bridge_related attribute which specifies couple of (optional) method selectors for bridging a CFobject to or from an ObjectiveC object. This is wip. // rdsr://15499111 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196408 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 9 +++ include/clang/Basic/DiagnosticParseKinds.td | 7 ++ include/clang/Parse/Parser.h | 5 ++ include/clang/Sema/AttributeList.h | 48 +++++++++++ lib/Parse/ParseDecl.cpp | 90 +++++++++++++++++++++ lib/Sema/SemaDeclAttr.cpp | 21 +++++ test/Parser/objcbridge-related-attribute.m | 15 ++++ 7 files changed, 195 insertions(+) create mode 100644 test/Parser/objcbridge-related-attribute.m diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 2268fa6478..bf5e5d6726 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -615,6 +615,15 @@ def ObjCBridgeMutable : InheritableAttr { let Args = [IdentifierArgument<"BridgedType">]; } +def ObjCBridgeRelated : InheritableAttr { + let Spellings = [GNU<"objc_bridge_related">]; + let Subjects = SubjectList<[Record], ErrorDiag>; + let Args = [IdentifierArgument<"RelatedClass">, + IdentifierArgument<"ClassMethod">, + IdentifierArgument<"InstanceMethod">]; + let HasCustomParsing = 1; +} + def NSReturnsRetained : InheritableAttr { let Spellings = [GNU<"ns_returns_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 3415a0078c..22a9d64ca8 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -753,6 +753,13 @@ def err_zero_version : Error< "version number must have non-zero major, minor, or sub-minor version">; def err_availability_expected_platform : Error< "expected a platform name, e.g., 'macosx'">; + +// objc_bridge_related attribute +def err_objcbridge_related_expected_related_class : Error< + "expected a related ObjectiveC class name, e.g., 'NSColor'">; +def err_objcbridge_related_selector_name : Error< + "expected a class method selector with single argument, e.g., 'colorWithCGColor:'">; + def err_availability_expected_change : Error< "expected 'introduced', 'deprecated', or 'obsoleted'">; def err_availability_unknown_change : Error< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f23d4fb8a5..52d57a96ba 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2003,6 +2003,11 @@ private: SourceLocation AvailabilityLoc, ParsedAttributes &attrs, SourceLocation *endLoc); + + void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated, + SourceLocation ObjCBridgeRelatedLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc); bool IsThreadSafetyAttribute(StringRef AttrName); void ParseThreadSafetyAttribute(IdentifierInfo &AttrName, diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 96a9efee91..a0059b5e83 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -245,6 +245,26 @@ private: AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } + /// Constructor for objc_bridge_related attributes. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Parm1, + IdentifierLoc *Parm2, + IdentifierLoc *Parm3, + Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange), + ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(3), SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false), + NextInPosition(0), NextInPool(0) { + ArgsVector Args; + Args.push_back(Parm1); + Args.push_back(Parm2); + Args.push_back(Parm3); + memcpy(getArgsBuffer(), &Args[0], 3 * sizeof(ArgsUnion)); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + /// Constructor for type_tag_for_datatype attribute. AttributeList(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, @@ -609,6 +629,20 @@ public: syntax)); } + AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param1, + IdentifierLoc *Param2, + IdentifierLoc *Param3, + AttributeList::Syntax syntax) { + size_t size = sizeof(AttributeList) + 3 * sizeof(ArgsUnion); + void *memory = allocate(size); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + Param1, Param2, Param3, + syntax)); + } + AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, SourceLocation TokLoc, int Arg); @@ -769,6 +803,20 @@ public: return attr; } + /// Add objc_bridge_related attribute. + AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierLoc *Param1, + IdentifierLoc *Param2, + IdentifierLoc *Param3, + AttributeList::Syntax syntax) { + AttributeList *attr = + pool.create(attrName, attrRange, scopeName, scopeLoc, + Param1, Param2, Param3, syntax); + add(attr); + return attr; + } + /// Add type_tag_for_datatype attribute. AttributeList *addNewTypeTagForDatatype( IdentifierInfo *attrName, SourceRange attrRange, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 944942658a..2c93def4c2 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -259,6 +259,12 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } + + if (AttrKind == AttributeList::AT_ObjCBridgeRelated) { + ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } + // Thread safety attributes are parsed in an unevaluated context. // FIXME: Share the bulk of the parsing code here and just pull out // the unevaluated context. @@ -959,6 +965,90 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, AttributeList::AS_GNU); } +/// \brief Parse the contents of the "objc_bridge_related" attribute. +/// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')' +/// related_class: +/// Identifier +/// +/// opt-class_method: +/// Identifier: | +/// +/// opt-instance_method: +/// Identifier | +/// +void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated, + SourceLocation ObjCBridgeRelatedLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc) { + // Opening '('. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + Diag(Tok, diag::err_expected_lparen); + return; + } + + // Parse the related class name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_objcbridge_related_expected_related_class); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + IdentifierLoc *RelatedClass = ParseIdentifierLoc(); + if (Tok.isNot(tok::comma)) { + Diag(Tok, diag::err_expected_comma); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + ConsumeToken(); + + // Parse optional class method name. + IdentifierLoc *ClassMethod = 0; + if (Tok.is(tok::identifier)) { + ClassMethod = ParseIdentifierLoc(); + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_objcbridge_related_selector_name); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + ConsumeToken(); + } + if (Tok.isNot(tok::comma)) { + if (Tok.is(tok::colon)) + Diag(Tok, diag::err_objcbridge_related_selector_name); + else + Diag(Tok, diag::err_expected_comma); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + ConsumeToken(); + + // Parse optional instance method name. + IdentifierLoc *InstanceMethod = 0; + if (Tok.is(tok::identifier)) + InstanceMethod = ParseIdentifierLoc(); + else if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + + // Closing ')'. + if (T.consumeClose()) + return; + + if (endLoc) + *endLoc = T.getCloseLocation(); + + // Record this attribute + attrs.addNew(&ObjCBridgeRelated, + SourceRange(ObjCBridgeRelatedLoc, T.getCloseLocation()), + 0, ObjCBridgeRelatedLoc, + RelatedClass, + ClassMethod, + InstanceMethod, + AttributeList::AS_GNU); + +} // Late Parsed Attributes: // See other examples of late parsing in lib/Parse/ParseCXXInlineMethods diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index c587452aeb..5414453efc 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3713,6 +3713,24 @@ static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D, + const AttributeList &Attr) { + IdentifierInfo *RelatedClass = + Attr.isArgIdent(0) ? Attr.getArgAsIdent(0)->Ident : 0; + if (!RelatedClass) { + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + return; + } + IdentifierInfo *ClassMethod = + Attr.getArgAsIdent(1) ? Attr.getArgAsIdent(1)->Ident : 0; + IdentifierInfo *InstanceMethod = + Attr.getArgAsIdent(2) ? Attr.getArgAsIdent(2)->Ident : 0; + D->addAttr(::new (S.Context) + ObjCBridgeRelatedAttr(Attr.getRange(), S.Context, RelatedClass, + ClassMethod, InstanceMethod, + Attr.getAttributeSpellingListIndex())); +} + static void handleObjCDesignatedInitializer(Sema &S, Decl *D, const AttributeList &Attr) { SourceLocation Loc = Attr.getLoc(); @@ -3986,6 +4004,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ObjCBridgeMutable: handleObjCBridgeMutableAttr(S, scope, D, Attr); break; + + case AttributeList::AT_ObjCBridgeRelated: + handleObjCBridgeRelatedAttr(S, scope, D, Attr); break; case AttributeList::AT_ObjCDesignatedInitializer: handleObjCDesignatedInitializer(S, D, Attr); break; diff --git a/test/Parser/objcbridge-related-attribute.m b/test/Parser/objcbridge-related-attribute.m new file mode 100644 index 0000000000..209448bba8 --- /dev/null +++ b/test/Parser/objcbridge-related-attribute.m @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s +// rdar://15499111 + +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,CGColor))) CGColor *CGColorRefOk; +typedef struct __attribute__((objc_bridge_related(NSColor,,CGColor))) CGColor *CGColorRef1Ok; +typedef struct __attribute__((objc_bridge_related(NSColor,,))) CGColor *CGColorRef2Ok; +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,))) CGColor *CGColorRef3Ok; + +typedef struct __attribute__((objc_bridge_related(,colorWithCGColor:,CGColor))) CGColor *CGColorRef1NotOk; // expected-error {{expected a related ObjectiveC class name, e.g., 'NSColor'}} +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor,CGColor))) CGColor *CGColorRef2NotOk; // expected-error {{expected a class method selector with single argument, e.g., 'colorWithCGColor:'}} +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor::,CGColor))) CGColor *CGColorRef3NotOk; // expected-error {{expected a class method selector with single argument, e.g., 'colorWithCGColor:'}} +typedef struct __attribute__((objc_bridge_related(12,colorWithCGColor:,CGColor))) CGColor *CGColorRef4NotOk; // expected-error {{expected a related ObjectiveC class name, e.g., 'NSColor'}} +typedef struct __attribute__((objc_bridge_related(NSColor,+:,CGColor))) CGColor *CGColorRef5NotOk; // expected-error {{expected ','}} +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,+))) CGColor *CGColorRef6NotOk; // expected-error {{expected ')'}} + -- 2.40.0