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:
Aaron Ballman 2013-11-29 14:57:58 +00:00
parent e7b368b885
commit 1361a6ffcc
6 changed files with 68 additions and 29 deletions

View File

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

View File

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

View File

@ -858,7 +858,8 @@ enum AttributeDeclKind {
ExpectedMethodOrProperty,
ExpectedStructOrUnion,
ExpectedStructOrUnionOrClass,
ExpectedType
ExpectedType,
ExpectedObjCInstanceMethod
};
} // end namespace clang

View File

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

View File

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

View File

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