diff options
author | Jordan Rose <jordan_rose@apple.com> | 2013-10-25 16:52:00 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2013-10-25 16:52:00 +0000 |
commit | 5565941effbe6e4d255f7a1b35c04ab5c106db41 (patch) | |
tree | 4f803cd0c642dddbaefe73f52018d0cc1e7d5f20 | |
parent | c0fdb3941cc631f17f7bf76d2742169bd1ca3831 (diff) | |
download | bcm5719-llvm-5565941effbe6e4d255f7a1b35c04ab5c106db41.tar.gz bcm5719-llvm-5565941effbe6e4d255f7a1b35c04ab5c106db41.zip |
Add -Wstring-plus-char, which warns when adding char literals to C strings.
Specifically, this warns when a character literal is added (using '+') to a
variable with type 'char *' (or any other pointer to character type). Like
-Wstring-plus-int, there is a fix-it to change "foo + 'a'" to "&foo['a']"
iff the character literal is on the right side of the string.
Patch by Anders Rönnholm!
llvm-svn: 193418
-rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 1 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 61 | ||||
-rw-r--r-- | clang/test/Sema/string-plus-char.c | 15 | ||||
-rw-r--r-- | clang/test/SemaCXX/string-plus-char.cpp | 32 |
5 files changed, 109 insertions, 5 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 57108058b54..7ca9aae6134 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -269,6 +269,7 @@ def GNUStaticFloatInit : DiagGroup<"gnu-static-float-init">; def StaticFloatInit : DiagGroup<"static-float-init", [GNUStaticFloatInit]>; def GNUStatementExpression : DiagGroup<"gnu-statement-expression">; def StringPlusInt : DiagGroup<"string-plus-int">; +def StringPlusChar : DiagGroup<"string-plus-char">; def StrncatSize : DiagGroup<"strncat-size">; def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">; def TautologicalCompare : DiagGroup<"tautological-compare", diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 441ad4ccace..94e7e9d62ae 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4292,7 +4292,10 @@ def warn_self_assignment : Warning< def warn_string_plus_int : Warning< "adding %0 to a string does not append to the string">, InGroup<StringPlusInt>; -def note_string_plus_int_silence : Note< +def warn_string_plus_char : Warning< + "adding %0 to a string pointer does not append to the string">, + InGroup<StringPlusChar>; +def note_string_plus_scalar_silence : Note< "use array indexing to silence this warning">; def warn_sizeof_array_param : Warning< diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 69f8f2e739a..139bf5b9729 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6963,12 +6963,63 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc, // Only print a fixit for "str" + int, not for int + "str". if (IndexExpr == RHSExpr) { SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd()); - Self.Diag(OpLoc, diag::note_string_plus_int_silence) + Self.Diag(OpLoc, diag::note_string_plus_scalar_silence) << FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&") << FixItHint::CreateReplacement(SourceRange(OpLoc), "[") << FixItHint::CreateInsertion(EndLoc, "]"); } else - Self.Diag(OpLoc, diag::note_string_plus_int_silence); + Self.Diag(OpLoc, diag::note_string_plus_scalar_silence); +} + +/// \brief Emit a warning when adding a char literal to a string. +static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc, + Expr *LHSExpr, Expr *RHSExpr) { + const DeclRefExpr *StringRefExpr = + dyn_cast<DeclRefExpr>(LHSExpr->IgnoreImpCasts()); + const CharacterLiteral *CharExpr = + dyn_cast<CharacterLiteral>(RHSExpr->IgnoreImpCasts()); + if (!StringRefExpr) { + StringRefExpr = dyn_cast<DeclRefExpr>(RHSExpr->IgnoreImpCasts()); + CharExpr = dyn_cast<CharacterLiteral>(LHSExpr->IgnoreImpCasts()); + } + + if (!CharExpr || !StringRefExpr) + return; + + const QualType StringType = StringRefExpr->getType(); + + // Return if not a PointerType. + if (!StringType->isAnyPointerType()) + return; + + // Return if not a CharacterType. + if (!StringType->getPointeeType()->isAnyCharacterType()) + return; + + ASTContext &Ctx = Self.getASTContext(); + SourceRange DiagRange(LHSExpr->getLocStart(), RHSExpr->getLocEnd()); + + const QualType CharType = CharExpr->getType(); + if (!CharType->isAnyCharacterType() && + CharType->isIntegerType() && + llvm::isUIntN(Ctx.getCharWidth(), CharExpr->getValue())) { + Self.Diag(OpLoc, diag::warn_string_plus_char) + << DiagRange << Ctx.CharTy; + } else { + Self.Diag(OpLoc, diag::warn_string_plus_char) + << DiagRange << CharExpr->getType(); + } + + // Only print a fixit for str + char, not for char + str. + if (isa<CharacterLiteral>(RHSExpr->IgnoreImpCasts())) { + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd()); + Self.Diag(OpLoc, diag::note_string_plus_scalar_silence) + << FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&") + << FixItHint::CreateReplacement(SourceRange(OpLoc), "[") + << FixItHint::CreateInsertion(EndLoc, "]"); + } else { + Self.Diag(OpLoc, diag::note_string_plus_scalar_silence); + } } /// \brief Emit error when two pointers are incompatible. @@ -6997,9 +7048,11 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - // Diagnose "string literal" '+' int. - if (Opc == BO_Add) + // Diagnose "string literal" '+' int and string '+' "char literal". + if (Opc == BO_Add) { diagnoseStringPlusInt(*this, Loc, LHS.get(), RHS.get()); + diagnoseStringPlusChar(*this, Loc, LHS.get(), RHS.get()); + } // handle the common case first (both operands are arithmetic). if (!compType.isNull() && compType->isArithmeticType()) { diff --git a/clang/test/Sema/string-plus-char.c b/clang/test/Sema/string-plus-char.c new file mode 100644 index 00000000000..322e8f5962b --- /dev/null +++ b/clang/test/Sema/string-plus-char.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +void f(const char *s) { + char *str = 0; + char *str2 = str + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + + const char *constStr = s + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + + str = 'c' + str;// expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + + // no-warning + char c = 'c'; + str = str + c; + str = c + str; +} diff --git a/clang/test/SemaCXX/string-plus-char.cpp b/clang/test/SemaCXX/string-plus-char.cpp new file mode 100644 index 00000000000..00a2c4550dc --- /dev/null +++ b/clang/test/SemaCXX/string-plus-char.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s + +class A { +public: + A(): str() { } + A(const char *p) { } + A(char *p) : str(p + 'a') { } // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + A& operator+(const char *p) { return *this; } + A& operator+(char ch) { return *this; } + char * str; +}; + +void f(const char *s) { + A a = s + 'a'; // // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + a = a + s + 'b'; // no-warning + + char *str = 0; + char *str2 = str + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + + const char *constStr = s + 'c'; // expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + + str = 'c' + str;// expected-warning {{adding 'char' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + + wchar_t *wstr; + wstr = wstr + L'c'; // expected-warning {{adding 'wchar_t' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + str2 = str + u'a'; // expected-warning {{adding 'char16_t' to a string pointer does not append to the string}} expected-note {{use array indexing to silence this warning}} + + // no-warning + char c = 'c'; + str = str + c; + str = c + str; +} |