Prazek updated the summary for this revision.
Prazek updated this revision to Diff 53891.
Prazek added a comment.

Small tests update. Ping me when your patch will be in trunk


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,154 @@
+// 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));
+}
+
+#define my_to_string boost::lexical_cast<std::string>
+
+void no_fixup_inside_macro() {
+  my_to_string(12);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use std::to_string{{..}}
+
+}
+
+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,78 @@
+//===--- 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()))))))),
+          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();
+  auto Diag =
+      diag(Loc, "use std::to_%0 instead of boost::lexical_cast<std::%0>")
+      << StringType;
+
+  if (Loc.isMacroID())
+    return;
+
+  Diag << FixItHint::CreateReplacement(
+      CharSourceRange::getCharRange(Call->getLocStart(),
+                                    Call->getArg(0)->getExprLoc()),
+      (llvm::Twine("std::to_") + StringType + llvm::Twine("(")).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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to