def ObjCCocoaAPI : DiagGroup<"objc-cocoa-api", [
ObjCRedundantAPIUse
]>;
+
+def ObjCStringComparison : DiagGroup<"objc-string-compare">;
+def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [
+ ObjCStringComparison
+ ]>;
"%select{string|character|boolean|numeric}0 literal must be prefixed by '@' "
"in a collection">;
def warn_objc_literal_comparison : Warning<
- "direct comparison of %select{a string literal|an array literal|"
- "a dictionary literal|a numeric literal|a boxed expression|}0 has "
- "undefined behavior">, InGroup<DiagGroup<"objc-literal-compare">>;
+ "direct comparison of %select{an array literal|a dictionary literal|"
+ "a numeric literal|a boxed expression|}0 has undefined behavior">,
+ InGroup<ObjCLiteralComparison>;
+def warn_objc_string_literal_comparison : Warning<
+ "direct comparison of a string literal has undefined behavior">,
+ InGroup<ObjCStringComparison>;
def note_objc_literal_comparison_isequal : Note<
"use 'isEqual:' instead">;
-def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
- "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;
let CategoryName = "Cocoa API Issue" in {
def warn_objc_redundant_literal_use : Warning<
"using %0 with a literal is redundant">, InGroup<ObjCRedundantLiteralUse>;
}
+def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", "
+ "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">;
+
def err_only_annotate_after_access_spec : Error<
"access specifier can only have annotation attributes">;
BinaryOperator::Opcode Opc){
Expr *Literal = (isObjCObjectLiteral(LHS) ? LHS : RHS).get();
- unsigned LiteralKind;
+ // This should be kept in sync with warn_objc_literal_comparison.
+ // LK_String should always be last, since it has its own flag.
+ enum {
+ LK_Array,
+ LK_Dictionary,
+ LK_Numeric,
+ LK_Boxed,
+ LK_String
+ } LiteralKind;
+
switch (Literal->getStmtClass()) {
case Stmt::ObjCStringLiteralClass:
// "string literal"
- LiteralKind = 0;
+ LiteralKind = LK_String;
break;
case Stmt::ObjCArrayLiteralClass:
// "array literal"
- LiteralKind = 1;
+ LiteralKind = LK_Array;
break;
case Stmt::ObjCDictionaryLiteralClass:
// "dictionary literal"
- LiteralKind = 2;
+ LiteralKind = LK_Dictionary;
break;
case Stmt::ObjCBoxedExprClass: {
Expr *Inner = cast<ObjCBoxedExpr>(Literal)->getSubExpr();
case Stmt::ObjCBoolLiteralExprClass:
case Stmt::CXXBoolLiteralExprClass:
// "numeric literal"
- LiteralKind = 3;
+ LiteralKind = LK_Numeric;
break;
case Stmt::ImplicitCastExprClass: {
CastKind CK = cast<CastExpr>(Inner)->getCastKind();
// Boolean literals can be represented by implicit casts.
if (CK == CK_IntegralToBoolean || CK == CK_IntegralCast) {
- LiteralKind = 3;
+ LiteralKind = LK_Numeric;
break;
}
// FALLTHROUGH
}
default:
// "boxed expression"
- LiteralKind = 4;
+ LiteralKind = LK_Boxed;
break;
}
break;
llvm_unreachable("Unknown Objective-C object literal kind");
}
- S.Diag(Loc, diag::warn_objc_literal_comparison)
- << LiteralKind << Literal->getSourceRange();
+ if (LiteralKind == LK_String)
+ S.Diag(Loc, diag::warn_objc_string_literal_comparison)
+ << Literal->getSourceRange();
+ else
+ S.Diag(Loc, diag::warn_objc_literal_comparison)
+ << LiteralKind << Literal->getSourceRange();
if (BinaryOperator::isEqualityOp(Opc) &&
hasIsEqualMethod(S, LHS.get(), RHS.get())) {
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-everything -Wobjc-literal-compare -verify %s
+
+// (test the warning flag as well)
typedef unsigned char BOOL;
if (@"" >= @"") return; // expected-warning{{direct comparison of a string literal has undefined behavior}}
}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wobjc-string-compare"
+
+void testWarningFlags(id obj) {
+ if (obj == @"") return; // no-warning
+ if (@"" == obj) return; // no-warning
+
+ if (obj == @1) return; // expected-warning{{direct comparison of a numeric literal has undefined behavior}} expected-note{{use 'isEqual:' instead}}
+ if (@1 == obj) return; // expected-warning{{direct comparison of a numeric literal has undefined behavior}} expected-note{{use 'isEqual:' instead}}
+}
+
+#pragma clang diagnostic pop
+