summaryrefslogtreecommitdiffstats
path: root/lib/Parse/ParseObjc.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2015-06-21 14:00:56 +0000
committerdim <dim@FreeBSD.org>2015-06-21 14:00:56 +0000
commit9dd834653b811ad20382e98a87dff824980c9916 (patch)
treea764184c2fc9486979b074250b013a0937ee64e5 /lib/Parse/ParseObjc.cpp
parentbb9760db9b86e93a638ed430d0a14785f7ff9064 (diff)
downloadFreeBSD-src-9dd834653b811ad20382e98a87dff824980c9916.zip
FreeBSD-src-9dd834653b811ad20382e98a87dff824980c9916.tar.gz
Vendor import of clang trunk r240225:
https://llvm.org/svn/llvm-project/cfe/trunk@240225
Diffstat (limited to 'lib/Parse/ParseObjc.cpp')
-rw-r--r--lib/Parse/ParseObjc.cpp169
1 files changed, 149 insertions, 20 deletions
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 691f53f..e4f7911 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -13,6 +13,7 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
@@ -307,6 +308,37 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
return ClsType;
}
+/// Add an attribute for a context-sensitive type nullability to the given
+/// declarator.
+static void addContextSensitiveTypeNullability(Parser &P,
+ Declarator &D,
+ NullabilityKind nullability,
+ SourceLocation nullabilityLoc,
+ bool &addedToDeclSpec) {
+ // Create the attribute.
+ auto getNullabilityAttr = [&]() -> AttributeList * {
+ return D.getAttributePool().create(
+ P.getNullabilityKeyword(nullability),
+ SourceRange(nullabilityLoc),
+ nullptr, SourceLocation(),
+ nullptr, 0,
+ AttributeList::AS_ContextSensitiveKeyword);
+ };
+
+ if (D.getNumTypeObjects() > 0) {
+ // Add the attribute to the declarator chunk nearest the declarator.
+ auto nullabilityAttr = getNullabilityAttr();
+ DeclaratorChunk &chunk = D.getTypeObject(0);
+ nullabilityAttr->setNext(chunk.getAttrListRef());
+ chunk.getAttrListRef() = nullabilityAttr;
+ } else if (!addedToDeclSpec) {
+ // Otherwise, just put it on the declaration specifiers (if one
+ // isn't there already).
+ D.getMutableDeclSpec().addAttributes(getNullabilityAttr());
+ addedToDeclSpec = true;
+ }
+}
+
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -330,7 +362,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
while (1) {
// If this is a method prototype, parse it.
- if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
+ if (Tok.isOneOf(tok::minus, tok::plus)) {
if (Decl *methodPrototype =
ParseObjCMethodPrototype(MethodImplKind, false))
allMethods.push_back(methodPrototype);
@@ -445,6 +477,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
ParseObjCPropertyAttribute(OCDS);
}
+ bool addedToDeclSpec = false;
auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
if (FD.D.getIdentifier() == nullptr) {
Diag(AtLoc, diag::err_objc_property_requires_field_name)
@@ -457,6 +490,13 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
return;
}
+ // Map a nullability property attribute to a context-sensitive keyword
+ // attribute.
+ if (OCDS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
+ OCDS.getNullabilityLoc(),
+ addedToDeclSpec);
+
// Install the property declarator into interfaceDecl.
IdentifierInfo *SelName =
OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
@@ -510,6 +550,24 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
}
+/// Diagnose redundant or conflicting nullability information.
+static void diagnoseRedundantPropertyNullability(Parser &P,
+ ObjCDeclSpec &DS,
+ NullabilityKind nullability,
+ SourceLocation nullabilityLoc){
+ if (DS.getNullability() == nullability) {
+ P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
+ << static_cast<unsigned>(nullability) << true
+ << SourceRange(DS.getNullabilityLoc());
+ return;
+ }
+
+ P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
+ << static_cast<unsigned>(nullability) << true
+ << static_cast<unsigned>(DS.getNullability()) << true
+ << SourceRange(DS.getNullabilityLoc());
+}
+
/// Parse property attribute declarations.
///
/// property-attr-decl: '(' property-attrlist ')'
@@ -529,6 +587,10 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
/// strong
/// weak
/// unsafe_unretained
+/// nonnull
+/// nullable
+/// null_unspecified
+/// null_resettable
///
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
assert(Tok.getKind() == tok::l_paren);
@@ -614,6 +676,37 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
DS.setGetterName(SelIdent);
}
+ } else if (II->isStr("nonnull")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::NonNull,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
+ } else if (II->isStr("nullable")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::Nullable,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
+ } else if (II->isStr("null_unspecified")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::Unspecified,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
+ } else if (II->isStr("null_resettable")) {
+ if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+ diagnoseRedundantPropertyNullability(*this, DS,
+ NullabilityKind::Unspecified,
+ Tok.getLocation());
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+ DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
+
+ // Also set the null_resettable bit.
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable);
} else {
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
SkipUntil(tok::r_paren, StopAtSemi);
@@ -641,7 +734,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
///
Decl *Parser::ParseObjCMethodPrototype(tok::ObjCKeywordKind MethodImplKind,
bool MethodDefinition) {
- assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
+ assert(Tok.isOneOf(tok::minus, tok::plus) && "expected +/-");
tok::TokenKind methodType = Tok.getKind();
SourceLocation mLoc = ConsumeToken();
@@ -779,6 +872,17 @@ bool Parser::isTokIdentifier_in() const {
/// objc-type-qualifier
/// objc-type-qualifiers objc-type-qualifier
///
+/// objc-type-qualifier:
+/// 'in'
+/// 'out'
+/// 'inout'
+/// 'oneway'
+/// 'bycopy'
+/// 'byref'
+/// 'nonnull'
+/// 'nullable'
+/// 'null_unspecified'
+///
void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
Declarator::TheContext Context) {
assert(Context == Declarator::ObjCParameterContext ||
@@ -796,10 +900,13 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
const IdentifierInfo *II = Tok.getIdentifierInfo();
for (unsigned i = 0; i != objc_NumQuals; ++i) {
- if (II != ObjCTypeQuals[i])
+ if (II != ObjCTypeQuals[i] ||
+ NextToken().is(tok::less) ||
+ NextToken().is(tok::coloncolon))
continue;
ObjCDeclSpec::ObjCDeclQualifier Qual;
+ NullabilityKind Nullability;
switch (i) {
default: llvm_unreachable("Unknown decl qualifier");
case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
@@ -808,8 +915,28 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
+
+ case objc_nonnull:
+ Qual = ObjCDeclSpec::DQ_CSNullability;
+ Nullability = NullabilityKind::NonNull;
+ break;
+
+ case objc_nullable:
+ Qual = ObjCDeclSpec::DQ_CSNullability;
+ Nullability = NullabilityKind::Nullable;
+ break;
+
+ case objc_null_unspecified:
+ Qual = ObjCDeclSpec::DQ_CSNullability;
+ Nullability = NullabilityKind::Unspecified;
+ break;
}
+
+ // FIXME: Diagnose redundant specifiers.
DS.setObjCDeclQualifier(Qual);
+ if (Qual == ObjCDeclSpec::DQ_CSNullability)
+ DS.setNullability(Tok.getLocation(), Nullability);
+
ConsumeToken();
II = nullptr;
break;
@@ -878,17 +1005,28 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
ParseObjCTypeQualifierList(DS, context);
ParsedType Ty;
- if (isTypeSpecifierQualifier()) {
+ if (isTypeSpecifierQualifier() || isObjCInstancetype()) {
// Parse an abstract declarator.
DeclSpec declSpec(AttrFactory);
declSpec.setObjCQualifiers(&DS);
- ParseSpecifierQualifierList(declSpec);
+ DeclSpecContext dsContext = DSC_normal;
+ if (context == Declarator::ObjCResultContext)
+ dsContext = DSC_objc_method_result;
+ ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
declSpec.SetRangeEnd(Tok.getLocation());
Declarator declarator(declSpec, context);
ParseDeclarator(declarator);
// If that's not invalid, extract a type.
if (!declarator.isInvalidType()) {
+ // Map a nullability specifier to a context-sensitive keyword attribute.
+ bool addedToDeclSpec = false;
+ if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
+ addContextSensitiveTypeNullability(*this, declarator,
+ DS.getNullability(),
+ DS.getNullabilityLoc(),
+ addedToDeclSpec);
+
TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
if (!type.isInvalid())
Ty = type.get();
@@ -898,15 +1036,6 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
if (context == Declarator::ObjCParameterContext)
takeDeclAttributes(*paramAttrs, declarator);
}
- } else if (context == Declarator::ObjCResultContext &&
- Tok.is(tok::identifier)) {
- if (!Ident_instancetype)
- Ident_instancetype = PP.getIdentifierInfo("instancetype");
-
- if (Tok.getIdentifierInfo() == Ident_instancetype) {
- Ty = Actions.ActOnObjCInstanceType(Tok.getLocation());
- ConsumeToken();
- }
}
if (Tok.is(tok::r_paren))
@@ -1309,6 +1438,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
// Install the declarator into the interface decl.
+ FD.D.setObjCIvar(true);
Decl *Field = Actions.ActOnIvar(
getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
FD.BitfieldSize, visibility);
@@ -2170,8 +2300,8 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
InMessageExpressionRAIIObject InMessage(*this, true);
- if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
- Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
+ if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_typename,
+ tok::annot_cxxscope))
TryAnnotateTypeOrScopeToken();
if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) {
@@ -2265,7 +2395,7 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() {
if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) {
const Token &AfterNext = GetLookAheadToken(2);
- if (AfterNext.is(tok::colon) || AfterNext.is(tok::r_square)) {
+ if (AfterNext.isOneOf(tok::colon, tok::r_square)) {
if (Tok.is(tok::identifier))
TryAnnotateTypeOrScopeToken();
@@ -2891,9 +3021,8 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
- assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
- Tok.is(tok::colon)) &&
- "Inline objective-c method not starting with '{' or 'try' or ':'");
+ assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
+ "Inline objective-c method not starting with '{' or 'try' or ':'");
// Enter a scope for the method or c-function body.
ParseScope BodyScope(this,
parseMethod
OpenPOWER on IntegriCloud