summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clang-tidy/misc/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.cpp85
-rw-r--r--clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.h34
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/list.rst1
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/misc-string-integer-assignment.rst31
-rw-r--r--clang-tools-extra/test/clang-tidy/misc-string-integer-assignment.cpp53
7 files changed, 208 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index 871be3de120..17ee66c7987 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -17,6 +17,7 @@ add_clang_library(clangTidyMiscModule
NonCopyableObjects.cpp
SizeofContainerCheck.cpp
StaticAssertCheck.cpp
+ StringIntegerAssignmentCheck.cpp
SwappedArgumentsCheck.cpp
ThrowByValueCatchByReferenceCheck.cpp
UndelegatedConstructor.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index 3d3e4866a6e..8d8de17724e 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -25,6 +25,7 @@
#include "NonCopyableObjects.h"
#include "SizeofContainerCheck.h"
#include "StaticAssertCheck.h"
+#include "StringIntegerAssignmentCheck.h"
#include "SwappedArgumentsCheck.h"
#include "ThrowByValueCatchByReferenceCheck.h"
#include "UndelegatedConstructor.h"
@@ -68,6 +69,8 @@ public:
CheckFactories.registerCheck<SizeofContainerCheck>("misc-sizeof-container");
CheckFactories.registerCheck<StaticAssertCheck>(
"misc-static-assert");
+ CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
+ "misc-string-integer-assignment");
CheckFactories.registerCheck<SwappedArgumentsCheck>(
"misc-swapped-arguments");
CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
diff --git a/clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.cpp b/clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.cpp
new file mode 100644
index 00000000000..c9ed466ccc3
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.cpp
@@ -0,0 +1,85 @@
+//===--- StringIntegerAssignmentCheck.cpp - clang-tidy---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringIntegerAssignmentCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ anyOf(hasOverloadedOperatorName("="),
+ hasOverloadedOperatorName("+=")),
+ callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
+ hasName("::std::basic_string"),
+ hasTemplateArgument(0, refersToType(qualType().bind("type"))))))),
+ hasArgument(1,
+ ignoringImpCasts(expr(hasType(isInteger()),
+ unless(hasType(isAnyCharacter())))
+ .bind("expr"))),
+ unless(isInTemplateInstantiation())),
+ this);
+}
+
+void StringIntegerAssignmentCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
+ SourceLocation Loc = Argument->getLocStart();
+
+ auto Diag =
+ diag(Loc, "an integer is interpreted as a character code when assigning "
+ "it to a string; if this is intended, cast the integer to the "
+ "appropriate character type; if you want a string "
+ "representation, use the appropriate conversion facility");
+
+ if (Loc.isMacroID())
+ return;
+
+ auto CharType = *Result.Nodes.getNodeAs<QualType>("type");
+ bool IsWideCharType = CharType->isWideCharType();
+ if (!CharType->isCharType() && !IsWideCharType)
+ return;
+ bool IsOneDigit = false;
+ bool IsLiteral = false;
+ if (const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
+ IsOneDigit = Literal->getValue().getLimitedValue() < 10;
+ IsLiteral = true;
+ }
+
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Argument->getLocEnd(), 0, *Result.SourceManager,
+ Result.Context->getLangOpts());
+ if (IsOneDigit) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L'" : "'")
+ << FixItHint::CreateInsertion(EndLoc, "'");
+ return;
+ }
+ if (IsLiteral) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L\"" : "\"")
+ << FixItHint::CreateInsertion(EndLoc, "\"");
+ return;
+ }
+
+ if (getLangOpts().CPlusPlus11) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "std::to_wstring("
+ : "std::to_string(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ }
+}
+
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.h b/clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.h
new file mode 100644
index 00000000000..072b96aa08e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/StringIntegerAssignmentCheck.h
@@ -0,0 +1,34 @@
+//===--- StringIntegerAssignmentCheck.h - clang-tidy-------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_INTEGER_ASSIGNMENT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_INTEGER_ASSIGNMENT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// Finds instances where an integer is assigned to a string.
+///
+/// For more details see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-assignment.html
+class StringIntegerAssignmentCheck : public ClangTidyCheck {
+public:
+ StringIntegerAssignmentCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_INTEGER_ASSIGNMENT_H
+
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 2f1686fa995..f8001440e73 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -48,6 +48,7 @@ List of clang-tidy Checks
misc-non-copyable-objects
misc-sizeof-container
misc-static-assert
+ misc-string-integer-assignment
misc-swapped-arguments
misc-throw-by-value-catch-by-reference
misc-undelegated-constructor
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc-string-integer-assignment.rst b/clang-tools-extra/docs/clang-tidy/checks/misc-string-integer-assignment.rst
new file mode 100644
index 00000000000..4e2aeef2183
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc-string-integer-assignment.rst
@@ -0,0 +1,31 @@
+misc-string-integer-assignment
+==============================
+
+The check finds assignments of an integer to ``std::basic_string<CharT>``
+(``std::string``, ``std::wstring``, etc.). The source of the problem is the
+following assignment operator of ``std::basic_string<CharT>``:
+
+.. code:: c++
+ basic_string& operator=( CharT ch );
+
+Numeric types can be implicity casted to character types.
+
+.. code:: c++
+ std::string s;
+ int x = 5965;
+ s = 6;
+ s = x;
+
+Use the appropriate conversion functions or character literals.
+
+.. code:: c++
+ std::string s;
+ int x = 5965;
+ s = '6';
+ s = std::to_string(x);
+
+In order to suppress false positives, use an explicit cast.
+
+.. code:: c++
+ std::string s;
+ s = static_cast<char>(6);
diff --git a/clang-tools-extra/test/clang-tidy/misc-string-integer-assignment.cpp b/clang-tools-extra/test/clang-tidy/misc-string-integer-assignment.cpp
new file mode 100644
index 00000000000..cb823410777
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/misc-string-integer-assignment.cpp
@@ -0,0 +1,53 @@
+// RUN: %check_clang_tidy %s misc-string-integer-assignment %t
+
+namespace std {
+template<typename T>
+struct basic_string {
+ basic_string& operator=(T);
+ basic_string& operator=(basic_string);
+ basic_string& operator+=(T);
+ basic_string& operator+=(basic_string);
+};
+
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+typedef int MyArcaneChar;
+
+int main() {
+ std::string s;
+ std::wstring ws;
+ int x = 5;
+
+ s = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [misc-string-integer-assignment]
+// CHECK-FIXES: {{^}} s = '6';{{$}}
+ s = 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = "66";{{$}}
+ s = x;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = std::to_string(x);{{$}}
+ s = 'c';
+ s = static_cast<char>(6);
+
+// +=
+ ws += 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L'6';{{$}}
+ ws += 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L"66";{{$}}
+ ws += x;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += std::to_wstring(x);{{$}}
+ ws += L'c';
+ ws += (wchar_t)6;
+
+ std::basic_string<MyArcaneChar> as;
+ as = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} as = 6;{{$}}
+
+}
OpenPOWER on IntegriCloud