diff options
13 files changed, 353 insertions, 1 deletions
diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt b/clang-tools-extra/clang-tidy/CMakeLists.txt index 7838527a4ff..8ac61248bf4 100644 --- a/clang-tools-extra/clang-tidy/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangTidy  add_subdirectory(tool)  add_subdirectory(plugin) +add_subdirectory(boost)  add_subdirectory(cert)  add_subdirectory(llvm)  add_subdirectory(cppcoreguidelines) diff --git a/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp b/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp new file mode 100644 index 00000000000..28eb1d656b0 --- /dev/null +++ b/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp @@ -0,0 +1,38 @@ +//===------- BoostTidyModule.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 "../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 { +    CheckFactories.registerCheck<UseToStringCheck>("boost-use-to-string"); +  } +}; + +// Register the BoostModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add<BoostModule> X("boost-module", +                                                   "Add boost checks."); + +} // namespace boost + +// This anchor is used to force the linker to link in the generated object file +// and thus register the BoostModule. +volatile int BoostModuleAnchorSource = 0; + +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/boost/CMakeLists.txt b/clang-tools-extra/clang-tidy/boost/CMakeLists.txt new file mode 100644 index 00000000000..059f6e91eca --- /dev/null +++ b/clang-tools-extra/clang-tidy/boost/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangTidyBoostModule +  BoostTidyModule.cpp +  UseToStringCheck.cpp + +  LINK_LIBS +  clangAST +  clangASTMatchers +  clangBasic +  clangLex +  clangTidy +  clangTidyUtils +  ) diff --git a/clang-tools-extra/clang-tidy/boost/UseToStringCheck.cpp b/clang-tools-extra/clang-tidy/boost/UseToStringCheck.cpp new file mode 100644 index 00000000000..8982c8e459d --- /dev/null +++ b/clang-tools-extra/clang-tidy/boost/UseToStringCheck.cpp @@ -0,0 +1,73 @@ +//===--- 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(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(); + +  StringRef StringType; +  if (CharType->isSpecificBuiltinType(BuiltinType::Char_S) || +      CharType->isSpecificBuiltinType(BuiltinType::Char_U)) +    StringType = "string"; +  else if (CharType->isSpecificBuiltinType(BuiltinType::WChar_S) || +           CharType->isSpecificBuiltinType(BuiltinType::WChar_U)) +    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 + "(").str()); +} + +} // namespace boost +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/boost/UseToStringCheck.h b/clang-tools-extra/clang-tidy/boost/UseToStringCheck.h new file mode 100644 index 00000000000..76e7823bf87 --- /dev/null +++ b/clang-tools-extra/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 { + +/// Finds calls to ``boost::lexical_cast<std::string>`` and +/// ``boost::lexical_cast<std::wstring>`` and replaces them with +/// ``std::to_string`` and ``std::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 diff --git a/clang-tools-extra/clang-tidy/plugin/CMakeLists.txt b/clang-tools-extra/clang-tidy/plugin/CMakeLists.txt index 27d2c9af46f..212c7aa57de 100644 --- a/clang-tools-extra/clang-tidy/plugin/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/plugin/CMakeLists.txt @@ -8,6 +8,7 @@ add_clang_library(clangTidyPlugin    clangFrontend    clangSema    clangTidy +  clangTidyBoostModule    clangTidyCERTModule    clangTidyCppCoreGuidelinesModule    clangTidyGoogleModule diff --git a/clang-tools-extra/clang-tidy/tool/CMakeLists.txt b/clang-tools-extra/clang-tidy/tool/CMakeLists.txt index d66aa9ce9f2..766da71d776 100644 --- a/clang-tools-extra/clang-tidy/tool/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/tool/CMakeLists.txt @@ -10,6 +10,7 @@ target_link_libraries(clang-tidy    clangASTMatchers    clangBasic    clangTidy +  clangTidyBoostModule    clangTidyCERTModule    clangTidyCppCoreGuidelinesModule    clangTidyGoogleModule diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index f6bcf32c0ac..2662241024a 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -418,6 +418,11 @@ extern volatile int CERTModuleAnchorSource;  static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =      CERTModuleAnchorSource; +// This anchor is used to force the linker to link the BoostModule. +extern volatile int BoostModuleAnchorSource; +static int LLVM_ATTRIBUTE_UNUSED BoostModuleAnchorDestination = +    BoostModuleAnchorSource; +  // This anchor is used to force the linker to link the LLVMModule.  extern volatile int LLVMModuleAnchorSource;  static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination = diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index fe40386c720..a97aeb949b1 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -217,6 +217,13 @@ identified.  The improvements since the 3.8 release include:    Finds static function and variable definitions in anonymous namespace. +  - 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. diff --git a/clang-tools-extra/docs/clang-tidy/checks/boost-use-to-string.rst b/clang-tools-extra/docs/clang-tidy/checks/boost-use-to-string.rst new file mode 100644 index 00000000000..ebeb82916c8 --- /dev/null +++ b/clang-tools-extra/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); + diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index c85d7e73b72..267eb314017 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/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> diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst index d7e076cab6a..3fc0d35ed9b 100644 --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -67,6 +67,8 @@ There are currently the following groups of checks:  * Clang static analyzer checks are named starting with ``clang-analyzer-``. +* Checks related to Boost library starts with ``boost-``.  +    Clang diagnostics are treated in a similar way as check diagnostics. Clang  diagnostics are displayed by clang-tidy and can be filtered out using  ``-checks=`` option. However, the ``-checks=`` option does not affect diff --git a/clang-tools-extra/test/clang-tidy/boost-use-to-string.cpp b/clang-tools-extra/test/clang-tidy/boost-use-to-string.cpp new file mode 100644 index 00000000000..fe7a3a01285 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/boost-use-to-string.cpp @@ -0,0 +1,149 @@ +// 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]]:12: 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>(); +}  | 

