Add boost-use-to-string

http://reviews.llvm.org/D18136

llvm-svn: 268079
This commit is contained in:
Piotr Padlewski 2016-04-29 17:58:29 +00:00
parent 46977b62aa
commit 5625f65667
13 changed files with 353 additions and 1 deletions

View File

@ -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)

View File

@ -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

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -8,6 +8,7 @@ add_clang_library(clangTidyPlugin
clangFrontend
clangSema
clangTidy
clangTidyBoostModule
clangTidyCERTModule
clangTidyCppCoreGuidelinesModule
clangTidyGoogleModule

View File

@ -10,6 +10,7 @@ target_link_libraries(clang-tidy
clangASTMatchers
clangBasic
clangTidy
clangTidyBoostModule
clangTidyCERTModule
clangTidyCppCoreGuidelinesModule
clangTidyGoogleModule

View File

@ -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 =

View File

@ -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.

View File

@ -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);

View File

@ -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>

View File

@ -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

View File

@ -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>();
}