mirror of https://github.com/microsoft/clang.git
Enables support for custom subject lists for attributes. As a testbed, uses the custom subject for the ibaction attribute.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@195960 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e7b368b885
commit
1361a6ffcc
|
@ -37,6 +37,9 @@ def NormalVar : SubsetSubject<Var,
|
|||
def NonBitField : SubsetSubject<Field,
|
||||
[{!S->isBitField()}]>;
|
||||
|
||||
def ObjCInstanceMethod : SubsetSubject<ObjCMethod,
|
||||
[{S->isInstanceMethod()}]>;
|
||||
|
||||
// A single argument to an attribute
|
||||
class Argument<string name, bit optional> {
|
||||
string Name = name;
|
||||
|
@ -451,7 +454,8 @@ def Hot : InheritableAttr {
|
|||
|
||||
def IBAction : InheritableAttr {
|
||||
let Spellings = [GNU<"ibaction">];
|
||||
// let Subjects = [ObjCMethod];
|
||||
let Subjects = SubjectList<[ObjCInstanceMethod], WarnDiag,
|
||||
"ExpectedObjCInstanceMethod">;
|
||||
}
|
||||
|
||||
def IBOutlet : InheritableAttr {
|
||||
|
|
|
@ -2036,7 +2036,8 @@ def warn_attribute_wrong_decl_type : Warning<
|
|||
"variables, functions and tag types|thread-local variables|"
|
||||
"variables and fields|variables, data members and tag types|"
|
||||
"types and namespaces|Objective-C interfaces|methods and properties|"
|
||||
"struct or union|struct, union or class|types}1">,
|
||||
"struct or union|struct, union or class|types|"
|
||||
"Objective-C instance methods}1">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_attribute_wrong_decl_type : Error<
|
||||
"%0 attribute only applies to %select{functions|unions|"
|
||||
|
@ -2047,7 +2048,8 @@ def err_attribute_wrong_decl_type : Error<
|
|||
"variables, functions and tag types|thread-local variables|"
|
||||
"variables and fields|variables, data members and tag types|"
|
||||
"types and namespaces|Objective-C interfaces|methods and properties|"
|
||||
"struct or union|struct, union or class|types}1">;
|
||||
"struct or union|struct, union or class|types|"
|
||||
"Objective-C instance methods}1">;
|
||||
def warn_type_attribute_wrong_type : Warning<
|
||||
"'%0' only applies to %select{function|pointer|"
|
||||
"Objective-C object or block pointer}1 types; type here is %2">,
|
||||
|
@ -2393,9 +2395,6 @@ def err_attribute_not_supported_in_lang : Error<
|
|||
def warn_attribute_iboutlet : Warning<
|
||||
"%0 attribute can only be applied to instance variables or properties">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_attribute_ibaction: Warning<
|
||||
"ibaction attribute can only be applied to Objective-C instance methods">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_iboutletcollection_type : Error<
|
||||
"invalid type %0 as argument of iboutletcollection attribute">;
|
||||
def err_iboutletcollection_builtintype : Error<
|
||||
|
|
|
@ -858,7 +858,8 @@ enum AttributeDeclKind {
|
|||
ExpectedMethodOrProperty,
|
||||
ExpectedStructOrUnion,
|
||||
ExpectedStructOrUnionOrClass,
|
||||
ExpectedType
|
||||
ExpectedType,
|
||||
ExpectedObjCInstanceMethod
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -1119,16 +1119,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
}
|
||||
|
||||
static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
// The IBAction attributes only apply to instance methods.
|
||||
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
|
||||
if (MD->isInstanceMethod()) {
|
||||
D->addAttr(::new (S.Context)
|
||||
IBActionAttr(Attr.getRange(), S.Context,
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
return;
|
||||
}
|
||||
|
||||
S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName();
|
||||
D->addAttr(::new (S.Context) IBActionAttr(Attr.getRange(), S.Context,
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
{
|
||||
__attribute__((iboutlet)) id myoutlet;
|
||||
}
|
||||
+ (void) __attribute__((ibaction)) myClassMethod:(id)msg; // expected-warning{{ibaction attribute can only be applied to Objective-C instance methods}}
|
||||
+ (void) __attribute__((ibaction)) myClassMethod:(id)msg; // expected-warning{{'ibaction' attribute only applies to Objective-C instance methods}}
|
||||
- (void) __attribute__((ibaction)) myMessage:(id)msg;
|
||||
@end
|
||||
|
||||
@implementation Foo
|
||||
+ (void) __attribute__((ibaction)) myClassMethod:(id)msg {} // expected-warning{{ibaction attribute can only be applied to Objective-C instance methods}}
|
||||
+ (void) __attribute__((ibaction)) myClassMethod:(id)msg {} // expected-warning{{'ibaction' attribute only applies to Objective-C instance methods}}
|
||||
// Normally attributes should not be attached to method definitions, but
|
||||
// we allow 'ibaction' to be attached because it can be expanded from
|
||||
// the IBAction macro.
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
@ -1729,7 +1730,19 @@ static std::string CalculateDiagnostic(const Record &S) {
|
|||
std::vector<Record *> Subjects = S.getValueAsListOfDefs("Subjects");
|
||||
for (std::vector<Record *>::const_iterator I = Subjects.begin(),
|
||||
E = Subjects.end(); I != E; ++I) {
|
||||
uint32_t V = StringSwitch<uint32_t>((*I)->getName())
|
||||
const Record &R = (**I);
|
||||
std::string Name;
|
||||
|
||||
if (R.isSubClassOf("SubsetSubject")) {
|
||||
PrintError(R.getLoc(), "SubsetSubjects should use a custom diagnostic");
|
||||
// As a fallback, look through the SubsetSubject to see what its base
|
||||
// type is, and use that. This needs to be updated if SubsetSubjects
|
||||
// are allowed within other SubsetSubjects.
|
||||
Name = R.getValueAsDef("Base")->getName();
|
||||
} else
|
||||
Name = R.getName();
|
||||
|
||||
uint32_t V = StringSwitch<uint32_t>(Name)
|
||||
.Case("Function", Func)
|
||||
.Case("Var", Var)
|
||||
.Case("ObjCMethod", ObjCMethod)
|
||||
|
@ -1794,6 +1807,35 @@ static std::string CalculateDiagnostic(const Record &S) {
|
|||
return "";
|
||||
}
|
||||
|
||||
static std::string GenerateCustomAppertainsTo(const Record &Subject,
|
||||
raw_ostream &OS) {
|
||||
// If this code has already been generated, simply return the previous
|
||||
// instance of it.
|
||||
static std::set<std::string> CustomSubjectSet;
|
||||
std::set<std::string>::iterator I = CustomSubjectSet.find(Subject.getName());
|
||||
if (I != CustomSubjectSet.end())
|
||||
return *I;
|
||||
|
||||
Record *Base = Subject.getValueAsDef("Base");
|
||||
|
||||
// Not currently support custom subjects within custom subjects.
|
||||
if (Base->isSubClassOf("SubsetSubject")) {
|
||||
PrintFatalError(Subject.getLoc(),
|
||||
"SubsetSubjects within SubsetSubjects is not supported");
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string FnName = "is" + Subject.getName();
|
||||
OS << "static bool " << FnName << "(const Decl *D) {\n";
|
||||
OS << " const " << Base->getName() << "Decl *S = cast<" << Base->getName();
|
||||
OS << "Decl>(D);\n";
|
||||
OS << " return " << Subject.getValueAsString("CheckCode") << ";\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
CustomSubjectSet.insert(FnName);
|
||||
return FnName;
|
||||
}
|
||||
|
||||
static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
||||
// If the attribute does not contain a Subjects definition, then use the
|
||||
// default appertainsTo logic.
|
||||
|
@ -1808,9 +1850,6 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
|||
if (Subjects.empty())
|
||||
return "DefaultAppertainsTo";
|
||||
|
||||
// If any of the subjects are a SubsetSubject derivative, bail out for now
|
||||
// as though it was using custom parsing.
|
||||
bool HasSubsetSubject = false;
|
||||
bool Warn = SubjectObj->getValueAsDef("Diag")->getValueAsBit("Warn");
|
||||
|
||||
// Otherwise, generate an appertainsTo check specific to this attribute which
|
||||
|
@ -1823,10 +1862,17 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
|||
SS << " if (";
|
||||
for (std::vector<Record *>::const_iterator I = Subjects.begin(),
|
||||
E = Subjects.end(); I != E; ++I) {
|
||||
if ((*I)->isSubClassOf("SubsetSubject"))
|
||||
HasSubsetSubject = true;
|
||||
// If the subject has custom code associated with it, generate a function
|
||||
// for it. The function cannot be inlined into this check (yet) because it
|
||||
// requires the subject to be of a specific type, and were that information
|
||||
// inlined here, it would not support an attribute with multiple custom
|
||||
// subjects.
|
||||
if ((*I)->isSubClassOf("SubsetSubject")) {
|
||||
SS << "!" << GenerateCustomAppertainsTo(**I, OS) << "(D)";
|
||||
} else {
|
||||
SS << "!isa<" << (*I)->getName() << "Decl>(D)";
|
||||
}
|
||||
|
||||
SS << "!isa<" << (*I)->getName() << "Decl>(D)";
|
||||
if (I + 1 != E)
|
||||
SS << " && ";
|
||||
}
|
||||
|
@ -1842,9 +1888,6 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
|||
SS << " return true;\n";
|
||||
SS << "}\n\n";
|
||||
|
||||
if (HasSubsetSubject)
|
||||
return "DefaultAppertainsTo";
|
||||
|
||||
OS << SS.str();
|
||||
return FnName;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue