Prazek updated the summary for this revision.
Prazek updated this revision to Diff 53121.
Prazek marked 5 inline comments as done.
http://reviews.llvm.org/D18136
Files:
clang-tidy/boost/BoostTidyModule.cpp
clang-tidy/boost/CMakeLists.txt
clang-tidy/boost/UseToStringCheck.cpp
clang-tidy/boost/UseToStringCheck.h
docs/ReleaseNotes.rst
docs/clang-tidy/checks/boost-use-to-string.rst
docs/clang-tidy/checks/list.rst
test/clang-tidy/boost-use-to-string.cpp
Index: test/clang-tidy/boost-use-to-string.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/boost-use-to-string.cpp
@@ -0,0 +1,146 @@
+// RUN: %check_clang_tidy %s boost-use-to-string %t
+
+
+namespace std {
+
+template <typename T> class basic_string {};
+
+using string = basic_string<char>;
+using wstring = basic_string<wchar_t>;
+}
+
+namespace boost {
+template <typename T, typename V>
+T lexical_cast(const V&) {
+ return T();
+};
+}
+
+struct my_weird_type {};
+
+std::string fun(const std::string &) {}
+
+void test_to_string1() {
+
+ auto xa = boost::lexical_cast<std::string>(5);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::to_string instead of boost::lexical_cast<std::string> [boost-use-to-string]
+// CHECK-FIXES: auto xa = std::to_string(5);
+
+ auto z = boost::lexical_cast<std::string>(42LL);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use std::to_string {{..}}
+// CHECK-FIXES: auto z = std::to_string(42LL);
+
+ // this should not trigger
+ fun(boost::lexical_cast<std::string>(42.0));
+ auto non = boost::lexical_cast<my_weird_type>(42);
+ boost::lexical_cast<int>("12");
+}
+
+void test_to_string2() {
+ int a;
+ long b;
+ long long c;
+ unsigned d;
+ unsigned long e;
+ unsigned long long f;
+ float g;
+ double h;
+ long double i;
+ bool j;
+
+ fun(boost::lexical_cast<std::string>(a));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string {{..}}
+// CHECK-FIXES: fun(std::to_string(a));
+ fun(boost::lexical_cast<std::string>(b));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string {{..}}
+// CHECK-FIXES: fun(std::to_string(b));
+ fun(boost::lexical_cast<std::string>(c));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string {{..}}
+// CHECK-FIXES: fun(std::to_string(c));
+ fun(boost::lexical_cast<std::string>(d));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string {{..}}
+// CHECK-FIXES: fun(std::to_string(d));
+ fun(boost::lexical_cast<std::string>(e));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string {{..}}
+// CHECK-FIXES: fun(std::to_string(e));
+ fun(boost::lexical_cast<std::string>(f));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string {{..}}
+// CHECK-FIXES: fun(std::to_string(f));
+
+ // No change for floating numbers.
+ fun(boost::lexical_cast<std::string>(g));
+ fun(boost::lexical_cast<std::string>(h));
+ fun(boost::lexical_cast<std::string>(i));
+ // And bool.
+ fun(boost::lexical_cast<std::string>(j));
+}
+
+std::string fun(const std::wstring &) {}
+
+void test_to_wstring() {
+ int a;
+ long b;
+ long long c;
+ unsigned d;
+ unsigned long e;
+ unsigned long long f;
+ float g;
+ double h;
+ long double i;
+ bool j;
+
+ fun(boost::lexical_cast<std::wstring>(a));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring instead of boost::lexical_cast<std::wstring> [boost-use-to-string]
+// CHECK-FIXES: fun(std::to_wstring(a));
+ fun(boost::lexical_cast<std::wstring>(b));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring {{..}}
+// CHECK-FIXES: fun(std::to_wstring(b));
+ fun(boost::lexical_cast<std::wstring>(c));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring {{..}}
+// CHECK-FIXES: fun(std::to_wstring(c));
+ fun(boost::lexical_cast<std::wstring>(d));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring {{..}}
+// CHECK-FIXES: fun(std::to_wstring(d));
+ fun(boost::lexical_cast<std::wstring>(e));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring {{..}}
+// CHECK-FIXES: fun(std::to_wstring(e));
+ fun(boost::lexical_cast<std::wstring>(f));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring {{..}}
+// CHECK-FIXES: fun(std::to_wstring(f));
+
+ // No change for floating numbers
+ fun(boost::lexical_cast<std::wstring>(g));
+ fun(boost::lexical_cast<std::wstring>(h));
+ fun(boost::lexical_cast<std::wstring>(i));
+ // and bool.
+ fun(boost::lexical_cast<std::wstring>(j));
+}
+
+const auto glob = boost::lexical_cast<std::string>(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use std::to_string{{..}}
+// CHECK-FIXES: const auto glob = std::to_string(42);
+
+template <typename T>
+void string_as_T(T t = T()) {
+ boost::lexical_cast<std::string>(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use std::to_string{{..}}
+// CHECK-FIXES: std::to_string(42);
+
+ boost::lexical_cast<T>(42);
+ string_as_T(boost::lexical_cast<T>(42));
+ auto p = boost::lexical_cast<T>(42);
+ auto p2 = (T)boost::lexical_cast<T>(42);
+ auto p3 = static_cast<T>(boost::lexical_cast<T>(42));
+}
+
+
+void no_warnings() {
+ fun(boost::lexical_cast<std::string>("abc"));
+ fun(boost::lexical_cast<std::wstring>("abc"));
+ fun(boost::lexical_cast<std::string>(my_weird_type{}));
+ string_as_T<int>();
+ string_as_T<std::string>();
+}
+
+
+
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -3,7 +3,9 @@
Clang-Tidy Checks
=========================
-.. toctree::
+.. toctree::
+
+ boost-use-to-string
cert-dcl03-c (redirects to misc-static-assert) <cert-dcl03-c>
cert-dcl50-cpp
cert-dcl54-cpp (redirects to misc-new-delete-overloads) <cert-dcl54-cpp>
Index: docs/clang-tidy/checks/boost-use-to-string.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/boost-use-to-string.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - boost-use-to-string
+
+boost-use-to-string
+===================
+
+This check finds conversion from integer type like ``int`` to ``std::string`` or
+``std::wstring`` using ``boost::lexical_cast``, and replace it with calls to
+``std::to_string`` and ``std::to_wstring``.
+
+It doesn't replace conversion from floating points despite the ``to_string``
+overloads, because it would change the behaviour.
+
+
+ .. code-block:: c++
+
+ auto str = boost::lexical_cast<std::string>(42);
+ auto wstr = boost::lexical_cast<std::wstring>(2137LL);
+
+ // Will be changed to
+ auto str = std::to_string(42);
+ auto wstr = std::to_wstring(2137LL);
+
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -155,6 +155,11 @@
- New Boost module containing checks for issues with Boost library
+- New `boost-use-to-string
+ <http://clang.llvm.org/extra/clang-tidy/checks/boost-use-to-string.html>`_ check
+
+ Finds usages of boost::lexical_cast<std::string> and changes it to std::to_string.
+
Fixed bugs:
Crash when running on compile database with relative source files paths.
Index: clang-tidy/boost/UseToStringCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/boost/UseToStringCheck.h
@@ -0,0 +1,37 @@
+//===--- UseToStringCheck.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_BOOST_USE_TO_STRING_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace boost {
+
+/// Matches calls to boost::lexical_cast<std::string> and
+/// boost::lexical_cast<std::wstring> and replaces it with to_string and
+/// to_wstring calls.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/boost-use-to-string.html
+class UseToStringCheck : public ClangTidyCheck {
+public:
+ UseToStringCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace boost
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H
Index: clang-tidy/boost/UseToStringCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/boost/UseToStringCheck.cpp
@@ -0,0 +1,79 @@
+//===--- UseToStringCheck.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 "UseToStringCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace boost {
+
+AST_MATCHER(Type, isStrictlyInteger) {
+ return Node.isIntegerType() && !Node.isAnyCharacterType() &&
+ !Node.isBooleanType();
+}
+
+void UseToStringCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ callExpr(
+ hasDeclaration(functionDecl(
+ returns(hasDeclaration(classTemplateSpecializationDecl(
+ hasName("std::basic_string"),
+ hasTemplateArgument(0,
+ templateArgument().bind("char_type"))))),
+ hasName("boost::lexical_cast"),
+ hasParameter(0, hasType(qualType(has(substTemplateTypeParmType(
+ isStrictlyInteger()))))))),
+ // FIXME using isInTemplateInstantiation asserts when using
+ // on TemplateArgument, dunno why...
+ argumentCountIs(
+ 1)) //, unless(hasParent(isInTemplateInstantiation())))
+ .bind("to_string"),
+ this);
+}
+
+void UseToStringCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("to_string");
+ auto CharType =
+ Result.Nodes.getNodeAs<TemplateArgument>("char_type")->getAsType();
+
+ if (CharType.isNull())
+ return;
+
+ StringRef StringType;
+ if (CharType->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ CharType->isSpecificBuiltinType(BuiltinType::Char_U))
+ // Is CharType 'char'.
+ StringType = "string";
+ else if (CharType->isSpecificBuiltinType(BuiltinType::WChar_S) ||
+ CharType->isSpecificBuiltinType(BuiltinType::WChar_U))
+ // Is CharType 'wchar_t'.
+ StringType = "wstring";
+ else
+ return;
+
+ auto Loc = Call->getLocStart();
+ if (Loc.isMacroID())
+ return;
+
+ diag(Loc, "use std::to_%0 instead of boost::lexical_cast<std::%0>")
+ << StringType
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(Call->getLocStart(),
+ Call->getArg(0)->getExprLoc()),
+ (llvm::Twine("std::to_") + StringType).str());
+}
+
+} // namespace boost
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/boost/CMakeLists.txt
===================================================================
--- clang-tidy/boost/CMakeLists.txt
+++ clang-tidy/boost/CMakeLists.txt
@@ -2,6 +2,7 @@
add_clang_library(clangTidyBoostModule
BoostTidyModule.cpp
+ UseToStringCheck.cpp
LINK_LIBS
clangAST
Index: clang-tidy/boost/BoostTidyModule.cpp
===================================================================
--- clang-tidy/boost/BoostTidyModule.cpp
+++ clang-tidy/boost/BoostTidyModule.cpp
@@ -10,15 +10,18 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
+#include "UseToStringCheck.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace boost {
class BoostModule : public ClangTidyModule {
public:
- void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {}
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<UseToStringCheck>("boost-use-to-string");
+ }
ClangTidyOptions getModuleOptions() override {
ClangTidyOptions Options;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits