Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -17,6 +17,7 @@ NonCopyableObjects.cpp SizeofContainerCheck.cpp StaticAssertCheck.cpp + StringAssignmentCheck.cpp SwappedArgumentsCheck.cpp ThrowByValueCatchByReferenceCheck.cpp UndelegatedConstructor.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -25,6 +25,7 @@ #include "NonCopyableObjects.h" #include "SizeofContainerCheck.h" #include "StaticAssertCheck.h" +#include "StringAssignmentCheck.h" #include "SwappedArgumentsCheck.h" #include "ThrowByValueCatchByReferenceCheck.h" #include "UndelegatedConstructor.h" @@ -68,6 +69,8 @@ CheckFactories.registerCheck("misc-sizeof-container"); CheckFactories.registerCheck( "misc-static-assert"); + CheckFactories.registerCheck( + "misc-string-assignment"); CheckFactories.registerCheck( "misc-swapped-arguments"); CheckFactories.registerCheck( Index: clang-tidy/misc/StringAssignmentCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/StringAssignmentCheck.h @@ -0,0 +1,34 @@ +//===--- StringAssignmentCheck.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_ASSIGNMENT_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_ASSIGNMENT_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { + +/// Finds instances where integer is assigned to a string. +/// +/// For more details see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-assignment.html +class StringAssignmentCheck : public ClangTidyCheck { +public: + StringAssignmentCheck(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_ASSIGNMENT_H + Index: clang-tidy/misc/StringAssignmentCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/StringAssignmentCheck.cpp @@ -0,0 +1,50 @@ +//===--- StringAssignmentCheck.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 "StringAssignmentCheck.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 StringAssignmentCheck::registerMatchers(MatchFinder *Finder) { + auto Matcher = cxxOperatorCallExpr( + anyOf(hasOverloadedOperatorName("="), hasOverloadedOperatorName("+=")), + callee(cxxMethodDecl(ofClass(hasName("::std::basic_string")))), + hasArgument(1, ignoringImpCasts(expr().bind("expr"))), + unless(isInTemplateInstantiation())); + Finder->addMatcher(Matcher, this); +} + +void StringAssignmentCheck::check(const MatchFinder::MatchResult &Result) { + auto Argument = Result.Nodes.getNodeAs("expr"); + QualType ArgType = Argument->getType(); + + if (!ArgType->isIntegerType() || ArgType->isAnyCharacterType()) + return; + SourceLocation Loc = Argument->getLocStart(); + SmallVector Hints; + if (!Loc.isMacroID()) { + Hints.push_back(FixItHint::CreateInsertion(Loc, "std::to_string(")); + Hints.push_back(FixItHint::CreateInsertion( + Lexer::getLocForEndOfToken(Argument->getLocEnd(), 0, + *Result.SourceManager, + Result.Context->getLangOpts()), + ")")); + } + + diag(Loc, "probably missing to_string operation") << Hints; +} + +} // namespace tidy +} // namespace clang Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -47,6 +47,7 @@ misc-non-copyable-objects misc-sizeof-container misc-static-assert + misc-string-assignment misc-swapped-arguments misc-throw-by-value-catch-by-reference misc-undelegated-constructor Index: docs/clang-tidy/checks/misc-string-assignment.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-string-assignment.rst @@ -0,0 +1,30 @@ +misc-string-assignment +====================== + +The ``std::basic_string`` has an assignment operator with the following signature: + +.. code:: c++ + basic_string& operator=( CharT ch ); + +The source of the problem is that, the numeric types can be implicity casted to most of the +character types. It possible to assign integers to ``basic_string``. + +.. 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(6); Index: test/clang-tidy/misc-string-assignment.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-string-assignment.cpp @@ -0,0 +1,39 @@ +// RUN: %check_clang_tidy %s misc-string-assignment %t + +namespace std { +template +struct basic_string { + basic_string(const T*) {} + basic_string& operator=(T) { + return *this; + } + basic_string& operator=(basic_string) { + return *this; + } + basic_string& operator+=(T) { + return *this; + } + basic_string& operator+=(basic_string) { + return *this; + } +}; + +typedef basic_string string; +} + +int main() { + std::string s("foobar"); + + s = 6; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: probably missing to_string operation [misc-string-assignment] +// CHECK-FIXES: {{^}} s = std::to_string(6);{{$}} + s = 'c'; + s = (char)6; + +// += + s += 6; +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: probably missing to_string operation [misc-string-assignment] +// CHECK-FIXES: {{^}} s += std::to_string(6);{{$}} + s += 'c'; + s += (char)6; +}