summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Parse/ParseObjc.cpp11
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp63
2 files changed, 71 insertions, 3 deletions
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 3dbecd09008..0f90b684685 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -319,7 +319,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
// Type arguments for the superclass or protocol conformances.
if (Tok.is(tok::less)) {
- parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+ parseObjCTypeArgsOrProtocolQualifiers(ParsedType(),
+ typeArgsLAngleLoc,
typeArgs,
typeArgsRAngleLoc,
LAngleLoc,
@@ -1589,6 +1590,7 @@ TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
///
void Parser::parseObjCTypeArgsOrProtocolQualifiers(
+ ParsedType baseType,
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
@@ -1648,6 +1650,7 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers(
// Let Sema figure out what we parsed.
Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
+ baseType,
lAngleLoc,
identifiers,
identifierLocs,
@@ -1723,6 +1726,7 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers(
}
void Parser::parseObjCTypeArgsAndProtocolQualifiers(
+ ParsedType baseType,
SourceLocation &typeArgsLAngleLoc,
SmallVectorImpl<ParsedType> &typeArgs,
SourceLocation &typeArgsRAngleLoc,
@@ -1734,7 +1738,8 @@ void Parser::parseObjCTypeArgsAndProtocolQualifiers(
assert(Tok.is(tok::less));
// Parse the first angle-bracket-delimited clause.
- parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+ parseObjCTypeArgsOrProtocolQualifiers(baseType,
+ typeArgsLAngleLoc,
typeArgs,
typeArgsRAngleLoc,
protocolLAngleLoc,
@@ -1786,7 +1791,7 @@ TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
SourceLocation protocolRAngleLoc;
// Parse type arguments and protocol qualifiers.
- parseObjCTypeArgsAndProtocolQualifiers(typeArgsLAngleLoc, typeArgs,
+ parseObjCTypeArgsAndProtocolQualifiers(type, typeArgsLAngleLoc, typeArgs,
typeArgsRAngleLoc, protocolLAngleLoc,
protocols, protocolLocs,
protocolRAngleLoc, consumeLastToken);
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 48aa2467d24..74fbec23545 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -1220,6 +1220,7 @@ class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback {
void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
Scope *S,
+ ParsedType baseType,
SourceLocation lAngleLoc,
ArrayRef<IdentifierInfo *> identifiers,
ArrayRef<SourceLocation> identifierLocs,
@@ -1237,6 +1238,27 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
auto resolvedAsProtocols = [&] {
assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols");
+ // Determine whether the base type is a parameterized class, in
+ // which case we want to warn about typos such as
+ // "NSArray<NSObject>" (that should be NSArray<NSObject *>).
+ ObjCInterfaceDecl *baseClass = nullptr;
+ QualType base = GetTypeFromParser(baseType, nullptr);
+ bool allAreTypeNames = false;
+ SourceLocation firstClassNameLoc;
+ if (!base.isNull()) {
+ if (const auto *objcObjectType = base->getAs<ObjCObjectType>()) {
+ baseClass = objcObjectType->getInterface();
+ if (baseClass) {
+ if (auto typeParams = baseClass->getTypeParamList()) {
+ if (typeParams->size() == numProtocolsResolved) {
+ // Note that we should be looking for type names, too.
+ allAreTypeNames = true;
+ }
+ }
+ }
+ }
+ }
+
for (unsigned i = 0, n = protocols.size(); i != n; ++i) {
ObjCProtocolDecl *&proto
= reinterpret_cast<ObjCProtocolDecl *&>(protocols[i]);
@@ -1261,6 +1283,47 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined)
<< forwardDecl;
}
+
+ // If everything this far has been a type name (and we care
+ // about such things), check whether this name refers to a type
+ // as well.
+ if (allAreTypeNames) {
+ if (auto *decl = LookupSingleName(S, identifiers[i], identifierLocs[i],
+ LookupOrdinaryName)) {
+ if (isa<ObjCInterfaceDecl>(decl)) {
+ if (firstClassNameLoc.isInvalid())
+ firstClassNameLoc = identifierLocs[i];
+ } else if (!isa<TypeDecl>(decl)) {
+ // Not a type.
+ allAreTypeNames = false;
+ }
+ } else {
+ allAreTypeNames = false;
+ }
+ }
+ }
+
+ // All of the protocols listed also have type names, and at least
+ // one is an Objective-C class name. Check whether all of the
+ // protocol conformances are declared by the base class itself, in
+ // which case we warn.
+ if (allAreTypeNames && firstClassNameLoc.isValid()) {
+ llvm::SmallPtrSet<ObjCProtocolDecl*, 8> knownProtocols;
+ Context.CollectInheritedProtocols(baseClass, knownProtocols);
+ bool allProtocolsDeclared = true;
+ for (auto proto : protocols) {
+ if (knownProtocols.count(static_cast<ObjCProtocolDecl *>(proto)) == 0) {
+ allProtocolsDeclared = false;
+ break;
+ }
+ }
+
+ if (allProtocolsDeclared) {
+ Diag(firstClassNameLoc, diag::warn_objc_redundant_qualified_class_type)
+ << baseClass->getDeclName() << SourceRange(lAngleLoc, rAngleLoc)
+ << FixItHint::CreateInsertion(
+ PP.getLocForEndOfToken(firstClassNameLoc), " *");
+ }
}
protocolLAngleLoc = lAngleLoc;
OpenPOWER on IntegriCloud