Cleanup ObjCInterfaceDecl lookup for ObjC literals

llvm-svn: 243092
This commit is contained in:
Alex Denisov 2015-07-24 05:09:40 +00:00
parent 1e271df041
commit b7d8563973
7 changed files with 117 additions and 125 deletions

View File

@ -2101,25 +2101,18 @@ def err_field_with_address_space : Error<
"field may not be qualified with an address space">;
def err_attr_objc_ownership_redundant : Error<
"the type %0 is already explicitly ownership-qualified">;
def err_undeclared_nsnumber : Error<
"NSNumber must be available to use Objective-C literals">;
def err_undeclared_nsvalue : Error<
"NSValue must be available to use Objective-C boxed expressions">;
def err_invalid_nsnumber_type : Error<
"%0 is not a valid literal type for NSNumber">;
def err_undeclared_nsstring : Error<
"cannot box a string value because NSString has not been declared">;
def err_objc_illegal_boxed_expression_type : Error<
"illegal type %0 used in a boxed expression">;
def err_objc_non_trivially_copyable_boxed_expression_type : Error<
"non-trivially copyable type %0 cannot be used in a boxed expression">;
def err_objc_incomplete_boxed_expression_type : Error<
"incomplete type %0 used in a boxed expression">;
def err_undeclared_nsarray : Error<
"NSArray must be available to use Objective-C array literals">;
def err_undeclared_nsdictionary : Error<
"NSDictionary must be available to use Objective-C dictionary "
"literals">;
def err_undeclared_objc_literal_class : Error<
"definition of class %0 must be available to use Objective-C "
"%select{array literals|dictionary literals|numeric literals|boxed expressions|"
"string literals}1">;
def err_undeclared_boxing_method : Error<
"declaration of %0 is missing in %1 class">;
def err_objc_literal_method_sig : Error<

View File

@ -168,6 +168,76 @@ static bool validateBoxingMethod(Sema &S, SourceLocation Loc,
return true;
}
/// \brief Maps ObjCLiteralKind to NSClassIdKindKind
static NSAPI::NSClassIdKindKind ClassKindFromLiteralKind(
Sema::ObjCLiteralKind LiteralKind) {
switch (LiteralKind) {
case Sema::LK_Array:
return NSAPI::ClassId_NSArray;
case Sema::LK_Dictionary:
return NSAPI::ClassId_NSDictionary;
case Sema::LK_Numeric:
return NSAPI::ClassId_NSNumber;
case Sema::LK_String:
return NSAPI::ClassId_NSString;
case Sema::LK_Boxed:
return NSAPI::ClassId_NSValue;
// there is no corresponding matching
// between LK_None/LK_Block and NSClassIdKindKind
case Sema::LK_Block:
case Sema::LK_None:
llvm_unreachable("LiteralKind can't be converted into a ClassKind");
}
}
/// \brief Validates ObjCInterfaceDecl availability.
/// ObjCInterfaceDecl, used to create ObjC literals, should be defined
/// if clang not in a debugger mode.
static bool ValidateObjCLiteralInterfaceDecl(Sema &S, ObjCInterfaceDecl *Decl,
SourceLocation Loc,
Sema::ObjCLiteralKind LiteralKind) {
if (!Decl) {
NSAPI::NSClassIdKindKind Kind = ClassKindFromLiteralKind(LiteralKind);
IdentifierInfo *II = S.NSAPIObj->getNSClassId(Kind);
S.Diag(Loc, diag::err_undeclared_objc_literal_class)
<< II->getName() << LiteralKind;
return false;
} else if (!Decl->hasDefinition() && !S.getLangOpts().DebuggerObjCLiteral) {
S.Diag(Loc, diag::err_undeclared_objc_literal_class)
<< Decl->getName() << LiteralKind;
S.Diag(Decl->getLocation(), diag::note_forward_class);
return false;
}
return true;
}
/// \brief Looks up ObjCInterfaceDecl of a given NSClassIdKindKind.
/// Used to create ObjC literals, such as NSDictionary (@{}),
/// NSArray (@[]) and Boxed Expressions (@())
static ObjCInterfaceDecl *LookupObjCInterfaceDeclForLiteral(Sema &S,
SourceLocation Loc,
Sema::ObjCLiteralKind LiteralKind) {
NSAPI::NSClassIdKindKind ClassKind = ClassKindFromLiteralKind(LiteralKind);
IdentifierInfo *II = S.NSAPIObj->getNSClassId(ClassKind);
NamedDecl *IF = S.LookupSingleName(S.TUScope, II, Loc,
Sema::LookupOrdinaryName);
ObjCInterfaceDecl *ID = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
if (!ID && S.getLangOpts().DebuggerObjCLiteral) {
ASTContext &Context = S.Context;
TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
ID = ObjCInterfaceDecl::Create (Context, TU, SourceLocation(), II,
nullptr, nullptr, SourceLocation());
}
if (!ValidateObjCLiteralInterfaceDecl(S, ID, Loc, LiteralKind)) {
ID = nullptr;
}
return ID;
}
/// \brief Retrieve the NSNumber factory method that should be used to create
/// an Objective-C literal for the given type.
static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
@ -197,26 +267,9 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
// Look up the NSNumber class, if we haven't done so already. It's cached
// in the Sema instance.
if (!S.NSNumberDecl) {
IdentifierInfo *NSNumberId =
S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber);
NamedDecl *IF = S.LookupSingleName(S.TUScope, NSNumberId,
Loc, Sema::LookupOrdinaryName);
S.NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
S.NSNumberDecl = LookupObjCInterfaceDeclForLiteral(S, Loc,
Sema::LK_Numeric);
if (!S.NSNumberDecl) {
if (S.getLangOpts().DebuggerObjCLiteral) {
// Create a stub definition of NSNumber.
S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
CX.getTranslationUnitDecl(),
SourceLocation(), NSNumberId,
nullptr, nullptr,
SourceLocation());
} else {
// Otherwise, require a declaration of NSNumber.
S.Diag(Loc, diag::err_undeclared_nsnumber);
return nullptr;
}
} else if (!S.NSNumberDecl->hasDefinition()) {
S.Diag(Loc, diag::err_undeclared_nsnumber);
return nullptr;
}
}
@ -457,6 +510,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
if (RValue.isInvalid()) {
return ExprError();
}
SourceLocation Loc = SR.getBegin();
ValueExpr = RValue.get();
QualType ValueType(ValueExpr->getType());
if (const PointerType *PT = ValueType->getAs<PointerType>()) {
@ -464,29 +518,11 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) {
if (!NSStringDecl) {
IdentifierInfo *NSStringId =
NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
NamedDecl *Decl = LookupSingleName(TUScope, NSStringId,
SR.getBegin(), LookupOrdinaryName);
NSStringDecl = dyn_cast_or_null<ObjCInterfaceDecl>(Decl);
NSStringDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
Sema::LK_String);
if (!NSStringDecl) {
if (getLangOpts().DebuggerObjCLiteral) {
// Support boxed expressions in the debugger w/o NSString declaration.
DeclContext *TU = Context.getTranslationUnitDecl();
NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
SourceLocation(),
NSStringId,
nullptr, nullptr,
SourceLocation());
} else {
Diag(SR.getBegin(), diag::err_undeclared_nsstring);
return ExprError();
}
} else if (!NSStringDecl->hasDefinition()) {
Diag(SR.getBegin(), diag::err_undeclared_nsstring);
return ExprError();
}
assert(NSStringDecl && "NSStringDecl should not be NULL");
QualType NSStringObject = Context.getObjCInterfaceType(NSStringDecl);
NSStringPointer = Context.getObjCObjectPointerType(NSStringObject);
}
@ -520,7 +556,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
BoxingMethod = M;
}
if (!validateBoxingMethod(*this, SR.getBegin(), NSStringDecl,
if (!validateBoxingMethod(*this, Loc, NSStringDecl,
stringWithUTF8String, BoxingMethod))
return ExprError();
@ -563,16 +599,16 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
// FIXME: Do I need to do anything special with BoolTy expressions?
// Look for the appropriate method within NSNumber.
BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(), ValueType);
BoxingMethod = getNSNumberFactoryMethod(*this, Loc, ValueType);
BoxedType = NSNumberPointer;
} else if (const EnumType *ET = ValueType->getAs<EnumType>()) {
if (!ET->getDecl()->isComplete()) {
Diag(SR.getBegin(), diag::err_objc_incomplete_boxed_expression_type)
Diag(Loc, diag::err_objc_incomplete_boxed_expression_type)
<< ValueType << ValueExpr->getSourceRange();
return ExprError();
}
BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(),
BoxingMethod = getNSNumberFactoryMethod(*this, Loc,
ET->getDecl()->getIntegerType());
BoxedType = NSNumberPointer;
} else if (ValueType->isObjCBoxableRecordType()) {
@ -582,29 +618,12 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
// Look up the NSValue class, if we haven't done so already. It's cached
// in the Sema instance.
if (!NSValueDecl) {
IdentifierInfo *NSValueId =
NSAPIObj->getNSClassId(NSAPI::ClassId_NSValue);
NamedDecl *IF = LookupSingleName(TUScope, NSValueId,
SR.getBegin(), Sema::LookupOrdinaryName);
NSValueDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
NSValueDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
Sema::LK_Boxed);
if (!NSValueDecl) {
if (getLangOpts().DebuggerObjCLiteral) {
// Create a stub definition of NSValue.
DeclContext *TU = Context.getTranslationUnitDecl();
NSValueDecl = ObjCInterfaceDecl::Create(Context, TU,
SourceLocation(), NSValueId,
nullptr, nullptr,
SourceLocation());
} else {
// Otherwise, require a declaration of NSValue.
Diag(SR.getBegin(), diag::err_undeclared_nsvalue);
return ExprError();
}
} else if (!NSValueDecl->hasDefinition()) {
Diag(SR.getBegin(), diag::err_undeclared_nsvalue);
return ExprError();
}
// generate the pointer to NSValue type.
QualType NSValueObject = Context.getObjCInterfaceType(NSValueDecl);
NSValuePointer = Context.getObjCObjectPointerType(NSValueObject);
@ -663,7 +682,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
BoxingMethod = M;
}
if (!validateBoxingMethod(*this, SR.getBegin(), NSValueDecl,
if (!validateBoxingMethod(*this, Loc, NSValueDecl,
ValueWithBytesObjCType, BoxingMethod))
return ExprError();
@ -671,8 +690,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
}
if (!ValueType.isTriviallyCopyableType(Context)) {
Diag(SR.getBegin(),
diag::err_objc_non_trivially_copyable_boxed_expression_type)
Diag(Loc, diag::err_objc_non_trivially_copyable_boxed_expression_type)
<< ValueType << ValueExpr->getSourceRange();
return ExprError();
}
@ -682,12 +700,12 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
}
if (!BoxingMethod) {
Diag(SR.getBegin(), diag::err_objc_illegal_boxed_expression_type)
Diag(Loc, diag::err_objc_illegal_boxed_expression_type)
<< ValueType << ValueExpr->getSourceRange();
return ExprError();
}
DiagnoseUseOfDecl(BoxingMethod, SR.getBegin());
DiagnoseUseOfDecl(BoxingMethod, Loc);
ExprResult ConvertedValueExpr;
if (ValueType->isObjCBoxableRecordType()) {
@ -746,26 +764,16 @@ ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
}
ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
// Look up the NSArray class, if we haven't done so already.
if (!NSArrayDecl) {
NamedDecl *IF = LookupSingleName(TUScope,
NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
SR.getBegin(),
LookupOrdinaryName);
NSArrayDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
if (!NSArrayDecl && getLangOpts().DebuggerObjCLiteral)
NSArrayDecl = ObjCInterfaceDecl::Create (Context,
Context.getTranslationUnitDecl(),
SourceLocation(),
NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
nullptr, nullptr, SourceLocation());
SourceLocation Loc = SR.getBegin();
if (!NSArrayDecl) {
NSArrayDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
Sema::LK_Array);
if (!NSArrayDecl) {
Diag(SR.getBegin(), diag::err_undeclared_nsarray);
return ExprError();
}
}
// Find the arrayWithObjects:count: method, if we haven't done so already.
QualType IdT = Context.getObjCIdType();
if (!ArrayWithObjectsMethod) {
@ -801,7 +809,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Method->setMethodParams(Context, Params, None);
}
if (!validateBoxingMethod(*this, SR.getBegin(), NSArrayDecl, Sel, Method))
if (!validateBoxingMethod(*this, Loc, NSArrayDecl, Sel, Method))
return ExprError();
// Dig out the type that all elements should be converted to.
@ -862,25 +870,16 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
ObjCDictionaryElement *Elements,
unsigned NumElements) {
// Look up the NSDictionary class, if we haven't done so already.
if (!NSDictionaryDecl) {
NamedDecl *IF = LookupSingleName(TUScope,
NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
SR.getBegin(), LookupOrdinaryName);
NSDictionaryDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
if (!NSDictionaryDecl && getLangOpts().DebuggerObjCLiteral)
NSDictionaryDecl = ObjCInterfaceDecl::Create (Context,
Context.getTranslationUnitDecl(),
SourceLocation(),
NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
nullptr, nullptr, SourceLocation());
SourceLocation Loc = SR.getBegin();
if (!NSDictionaryDecl) {
NSDictionaryDecl = LookupObjCInterfaceDeclForLiteral(*this, Loc,
Sema::LK_Dictionary);
if (!NSDictionaryDecl) {
Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);
return ExprError();
return ExprError();
}
}
// Find the dictionaryWithObjects:forKeys:count: method, if we haven't done
// so already.
QualType IdT = Context.getObjCIdType();

View File

@ -11,14 +11,14 @@ typedef unsigned int NSUInteger;
void checkNSArrayUnavailableDiagnostic() {
id obj;
id arr = @[obj]; // expected-error {{NSArray must be available to use Objective-C array literals}}
id arr = @[obj]; // expected-error {{definition of class NSArray must be available to use Objective-C array literals}}
}
@class NSArray;
@class NSArray; // expected-note {{forward declaration of class here}}
void checkNSArrayFDDiagnostic() {
id obj;
id arr = @[obj]; // expected-error {{declaration of 'arrayWithObjects:count:' is missing in NSArray class}}
id arr = @[obj]; // expected-error {{definition of class NSArray must be available to use Objective-C array literals}}
}
@class NSString;

View File

@ -46,7 +46,7 @@ typedef union BOXABLE _BoxableUnion {
void checkNSValueDiagnostic() {
NSRect rect;
id value = @(rect); // expected-error{{NSValue must be available to use Objective-C boxed expressions}}
id value = @(rect); // expected-error{{definition of class NSValue must be available to use Objective-C boxed expressions}}
}
@interface NSValue

View File

@ -8,15 +8,15 @@
void checkNSDictionaryUnavailableDiagnostic() {
id key;
id value;
id dict = @{ key : value }; // expected-error {{NSDictionary must be available to use Objective-C dictionary literals}}
id dict = @{ key : value }; // expected-error {{definition of class NSDictionary must be available to use Objective-C dictionary literals}}
}
@class NSDictionary;
@class NSDictionary; // expected-note {{forward declaration of class here}}
void checkNSDictionaryFDDiagnostic() {
id key;
id value;
id dic = @{ key : value }; // expected-error {{declaration of 'dictionaryWithObjects:forKeys:count:' is missing in NSDictionary class}}
id dic = @{ key : value }; // expected-error {{definition of class NSDictionary must be available to use Objective-C dictionary literals}}
}
@interface NSNumber

View File

@ -10,20 +10,20 @@ typedef int NSInteger;
#endif
void checkNSNumberUnavailableDiagnostic() {
id num = @1000; // expected-error {{NSNumber must be available to use Objective-C literals}}
id num = @1000; // expected-error {{definition of class NSNumber must be available to use Objective-C numeric literals}}
int x = 1000;
id num1 = @(x); // expected-error {{NSNumber must be available to use Objective-C literals}}\
id num1 = @(x); // expected-error {{definition of class NSNumber must be available to use Objective-C numeric literals}}\
// expected-error {{illegal type 'int' used in a boxed expression}}
}
@class NSNumber;
@class NSNumber; // expected-note 2 {{forward declaration of class here}}
void checkNSNumberFDDiagnostic() {
id num = @1000; // expected-error {{NSNumber must be available to use Objective-C literals}}
id num = @1000; // expected-error {{definition of class NSNumber must be available to use Objective-C numeric literals}}
int x = 1000;
id num1 = @(x); // expected-error {{declaration of 'numberWithInt:' is missing in NSNumber class}}\
id num1 = @(x); // expected-error {{definition of class NSNumber must be available to use Objective-C numeric literals}}\
// expected-error {{illegal type 'int' used in a boxed expression}}
}
@ -71,10 +71,10 @@ int main() {
}
// Dictionary test
@class NSDictionary;
@class NSDictionary; // expected-note {{forward declaration of class here}}
NSDictionary *err() {
return @{@"name" : @"value"}; // expected-error {{declaration of 'dictionaryWithObjects:forKeys:count:' is missing in NSDictionary class}}
return @{@"name" : @"value"}; // expected-error {{definition of class NSDictionary must be available to use Objective-C dictionary literals}}
}
@interface NSDate : NSObject

View File

@ -48,7 +48,7 @@ struct BOXABLE NonTriviallyCopyable {
void checkNSValueDiagnostic() {
NSRect rect;
id value = @(rect); // expected-error{{NSValue must be available to use Objective-C boxed expressions}}
id value = @(rect); // expected-error{{definition of class NSValue must be available to use Objective-C boxed expressions}}
}
@interface NSValue