Index: clang-tidy/CMakeLists.txt =================================================================== --- clang-tidy/CMakeLists.txt +++ clang-tidy/CMakeLists.txt @@ -26,6 +26,7 @@ ) add_subdirectory(tool) +add_subdirectory(boost) add_subdirectory(cert) add_subdirectory(llvm) add_subdirectory(cppcoreguidelines) Index: clang-tidy/boost/BoostTidyModule.cpp =================================================================== --- /dev/null +++ clang-tidy/boost/BoostTidyModule.cpp @@ -0,0 +1,44 @@ +//===------- 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 "LexicalCastRedundantTypeCheck.h" +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace boost { + +class ModernizeModule : public ClangTidyModule { +public: + void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "boost-lexical-cast-redundant-type"); + } + + ClangTidyOptions getModuleOptions() override { + ClangTidyOptions Options; + return Options; + } +}; + +// Register the ModernizeTidyModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add 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 Index: clang-tidy/boost/CMakeLists.txt =================================================================== --- /dev/null +++ clang-tidy/boost/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangTidyBoostModule + BoostTidyModule.cpp + LexicalCastRedundantTypeCheck.cpp + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangLex + clangTidy + clangTidyUtils + ) Index: clang-tidy/boost/LexicalCastRedundantTypeCheck.h =================================================================== --- /dev/null +++ clang-tidy/boost/LexicalCastRedundantTypeCheck.h @@ -0,0 +1,45 @@ +//===--- LexicalcastredundanttypeCheck.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_LEXICALCASTREDUNDANTTYPE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_LEXICALCASTREDUNDANTTYPE_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace boost { + +/// Checks for reduntand, or different type using boost::lexical_cast +/// +/// Given: +/// \code +/// int a = boost::lexical_cast("42"); +/// => +/// auto a = boost::lexical_cast("42"); +/// \code +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/boost-LexicalCastRedundantType.html +class LexicalCastRedundantTypeCheck : public ClangTidyCheck { +public: + LexicalCastRedundantTypeCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void apply(const DeclStmt *D, const std::string &warning); +}; + +} // namespace boost +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_LEXICALCASTREDUNDANTTYPE_H Index: clang-tidy/boost/LexicalCastRedundantTypeCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/boost/LexicalCastRedundantTypeCheck.cpp @@ -0,0 +1,72 @@ +//===--- LexicalcastredundanttypeCheck.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 "LexicalCastRedundantTypeCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace boost { + +static const std::string LEXICAL_CAST_NAME = "boost::lexical_cast"; +void LexicalCastRedundantTypeCheck::registerMatchers(MatchFinder *Finder) { + + if (!getLangOpts().CPlusPlus) + return; + + Finder->addMatcher( + declStmt(has(varDecl(hasInitializer(callExpr(callee( + functionDecl(hasName(LEXICAL_CAST_NAME))))), + unless(hasType(autoType()))))) + .bind("same_type"), + this); + + Finder->addMatcher( + declStmt(has(varDecl(hasInitializer(implicitCastExpr(has(callExpr( + callee(functionDecl(hasName(LEXICAL_CAST_NAME)))))))))) + .bind("different_type"), + this); +} + +void LexicalCastRedundantTypeCheck::apply(const DeclStmt *D, + const std::string &warning) { + const auto *Matched = dyn_cast(*D->decl_begin()); + if (!Matched) + return; + + Matched->getType().dump(); + SourceRange Range( + Matched->getTypeSourceInfo()->getTypeLoc().getSourceRange()); + // FIXIT: this replace doesnt work + diag(Range.getBegin(), warning) + << FixItHint::CreateReplacement(Range, "auto "); +} + +void LexicalCastRedundantTypeCheck::check( + const MatchFinder::MatchResult &Result) { + + const auto *MatchedSameType = Result.Nodes.getNodeAs("same_type"); + const auto *MatchedDifferentType = + Result.Nodes.getNodeAs("different_type"); + + if (MatchedSameType) { + apply(MatchedSameType, "redundant type for lexical_cast. Use auto instead"); + } + if (MatchedDifferentType) { + apply(MatchedDifferentType, + "different types for lexical_cast. Use auto instead"); + } +} + +} // namespace boost +} // namespace tidy +} // namespace clang Index: clang-tidy/tool/CMakeLists.txt =================================================================== --- clang-tidy/tool/CMakeLists.txt +++ clang-tidy/tool/CMakeLists.txt @@ -10,6 +10,7 @@ clangASTMatchers clangBasic clangTidy + clangTidyBoostModule clangTidyCERTModule clangTidyCppCoreGuidelinesModule clangTidyGoogleModule Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -393,6 +393,11 @@ 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 = Index: docs/clang-tidy/checks/boost-LexicalCastRedundantType.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/boost-LexicalCastRedundantType.rst @@ -0,0 +1,6 @@ +.. title:: clang-tidy - boost-LexicalCastRedundantType + +boost-LexicalCastRedundantType +============================== + +FIXME: Describe what patterns does the check detect and why. Give examples. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -4,6 +4,7 @@ ========================= .. toctree:: + boost-LexicalCastRedundantType cert-dcl03-c (redirects to misc-static-assert) cert-dcl50-cpp cert-dcl54-cpp (redirects to misc-new-delete-overloads) Index: test/clang-tidy/boost-LexicalCastRedundantType.cpp =================================================================== --- /dev/null +++ test/clang-tidy/boost-LexicalCastRedundantType.cpp @@ -0,0 +1,88 @@ +// RUN: %check_clang_tidy %s boost-lexical-cast-redundant-type %t + +namespace boost { +template +T lexical_cast(const U &) { return T(); } +} + +void same_type() { + // FIXME: Add something that triggers the check here. + int a1 = boost::lexical_cast("42"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: redundant type for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a1 = boost::lexical_cast("42"); + + long long a2 = boost::lexical_cast("42"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: redundant type for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a2 = boost::lexical_cast("42"); + + using MyType = unsigned long long; + MyType a3 = boost::lexical_cast("42"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: redundant type for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: MyType a3 = boost::lexical_cast("42"); + + unsigned long long a4 = boost::lexical_cast("2137"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: redundant type for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a4 = boost::lexical_cast("2137"); + + // multiple decls + int a9 = boost::lexical_cast("42"), a10 = boost::lexical_cast("24"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: redundant type for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: a9 = boost::lexical_cast("42"), a10 = boost::lexical_cast("24"); + + + MyType a11 = boost::lexical_cast("42"), a12 = boost::lexical_cast("24"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: redundant type for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a11 = boost::lexical_cast("42"), a12 = boost::lexical_cast("24"); + + unsigned long long a13 = boost::lexical_cast("42"), a14 = boost::lexical_cast("24"); + // CHECK-FIXES: auto a13 = boost::lexical_cast("42"), a14 = boost::lexical_cast("24"); + + a13 = boost::lexical_cast("42"); + + int a15 = boost::lexical_cast("42"), a16 = 15; + // CHECK-FIXES: auto a13 = boost::lexical_cast("42"), a14 = boost::lexical_cast("24"); + + long long *p = boost::lexical_cast("fdas"); + +} + +void different_type() { + int a5 = boost::lexical_cast("1488"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: different types for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a5 = boost::lexical_cast("1488"); + + long long a6 = boost::lexical_cast("2137"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: different types for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a6 = boost::lexical_cast("2137"); + + using MyType = unsigned long long; + long long a7 = boost::lexical_cast("42"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: different types for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a7 = boost::lexical_cast("42"); + + MyType a8 = boost::lexical_cast("42"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: different types for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + // CHECK-FIXES: auto a8 = boost::lexical_cast("42"); + + // multiple decls with different types - no fixit + int a9 = boost::lexical_cast("42"), a10 = boost::lexical_cast("24"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: different types for lexical_cast. Use auto instead [boost-lexical-cast-redundant-type] + +} + +// This should not generate any warnings. +void no_warnings(int x) { + + auto a4 = boost::lexical_cast("-42"); + auto a5 = boost::lexical_cast(x); + auto a6 = boost::lexical_cast("42"), a7 = boost::lexical_cast("24"); + + boost::lexical_cast("32"); + no_warnings(boost::lexical_cast(32)); +} + +// FIXME: Verify the applied fix. +// * Make the CHECK patterns specific enough and try to make verified lines +// unique to avoid incorrect matches. + +// FIXME: Add something that doesn't trigger the check here.