diff options
| author | Piotr Padlewski <piotr.padlewski@gmail.com> | 2016-05-02 16:56:39 +0000 |
|---|---|---|
| committer | Piotr Padlewski <piotr.padlewski@gmail.com> | 2016-05-02 16:56:39 +0000 |
| commit | ce18ade406a58aac9cfdea74479a6412f30d920f (patch) | |
| tree | 8ebc5fe184c2fee2c287e9a356b3b9d2437d21b6 /clang-tools-extra/clang-tidy | |
| parent | 45c7b3ecb574c84a559b6d00983dd19ec5041bc3 (diff) | |
| download | bcm5719-llvm-ce18ade406a58aac9cfdea74479a6412f30d920f.tar.gz bcm5719-llvm-ce18ade406a58aac9cfdea74479a6412f30d920f.zip | |
[clang-tidy] Add modernize-make-shared check
Because modernize-make-shared do almost the same job as
modernize-make-unique, I refactored common code to MakeSmartPtrCheck.
http://reviews.llvm.org/D19183
llvm-svn: 268253
Diffstat (limited to 'clang-tools-extra/clang-tidy')
8 files changed, 302 insertions, 139 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index b43b2a9e4d8..3c8add4741e 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -4,6 +4,8 @@ add_clang_library(clangTidyModernizeModule DeprecatedHeadersCheck.cpp LoopConvertCheck.cpp LoopConvertUtils.cpp + MakeSmartPtrCheck.cpp + MakeSharedCheck.cpp MakeUniqueCheck.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp new file mode 100644 index 00000000000..8d3020c6d35 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp @@ -0,0 +1,31 @@ +//===--- MakeSharedCheck.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 "MakeSharedCheck.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context) + : MakeSmartPtrCheck(Name, Context, "std::make_shared") {} + +MakeSharedCheck::SmartPtrTypeMatcher +MakeSharedCheck::getSmartPointerTypeMatcher() const { + return qualType(hasDeclaration(classTemplateSpecializationDecl( + matchesName("::std::shared_ptr"), templateArgumentCountIs(1), + hasTemplateArgument( + 0, templateArgument(refersToType(qualType().bind(PointerType))))))); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h new file mode 100644 index 00000000000..cf01446250c --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h @@ -0,0 +1,43 @@ +//===--- MakeSharedCheck.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_MODERNIZE_MAKE_SHARED_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H + +#include "MakeSmartPtrCheck.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// Replace the pattern: +/// \code +/// std::shared_ptr<type>(new type(args...)) +/// \endcode +/// +/// With the safer version: +/// \code +/// std::make_shared<type>(args...) +/// \endcode +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-make-shared.html +class MakeSharedCheck : public MakeSmartPtrCheck { +public: + MakeSharedCheck(StringRef Name, ClangTidyContext *Context); + +protected: + SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp new file mode 100644 index 00000000000..d1a561201f8 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -0,0 +1,150 @@ +//===--- MakeSmartPtrCheck.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 "MakeSharedCheck.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +const char MakeSmartPtrCheck::PointerType[] = "pointerType"; +const char MakeSmartPtrCheck::ConstructorCall[] = "constructorCall"; +const char MakeSmartPtrCheck::NewExpression[] = "newExpression"; + +MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context, + std::string makeSmartPtrFunctionName) + : ClangTidyCheck(Name, Context), + makeSmartPtrFunctionName(std::move(makeSmartPtrFunctionName)) {} + +void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) + return; + + Finder->addMatcher( + cxxBindTemporaryExpr( + has(cxxConstructExpr( + hasType(getSmartPointerTypeMatcher()), argumentCountIs(1), + hasArgument( + 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( + equalsBoundNode(PointerType)))))) + .bind(NewExpression))) + .bind(ConstructorCall))), + this); +} + +void MakeSmartPtrCheck::check(const MatchFinder::MatchResult &Result) { + // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other + // pointer, 'make_smart_ptr' refers to 'std::make_shared' or + // 'std::make_unique' or other function that creates smart_ptr. + + SourceManager &SM = *Result.SourceManager; + const auto *Construct = + Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall); + const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType); + const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression); + + if (New->getNumPlacementArgs() != 0) + return; + + SourceLocation ConstructCallStart = Construct->getExprLoc(); + + bool Invalid = false; + StringRef ExprStr = Lexer::getSourceText( + CharSourceRange::getCharRange( + ConstructCallStart, Construct->getParenOrBraceRange().getBegin()), + SM, LangOptions(), &Invalid); + if (Invalid) + return; + + auto Diag = diag(ConstructCallStart, "use %0 instead") + << makeSmartPtrFunctionName; + + // Find the location of the template's left angle. + size_t LAngle = ExprStr.find("<"); + SourceLocation ConstructCallEnd; + if (LAngle == StringRef::npos) { + // If the template argument is missing (because it is part of the alias) + // we have to add it back. + ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size()); + Diag << FixItHint::CreateInsertion( + ConstructCallEnd, "<" + Type->getAsString(getLangOpts()) + ">"); + } else { + ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle); + } + + Diag << FixItHint::CreateReplacement( + CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd), + makeSmartPtrFunctionName); + + // If the smart_ptr is built with brace enclosed direct initialization, use + // parenthesis instead. + if (Construct->isListInitialization()) { + SourceRange BraceRange = Construct->getParenOrBraceRange(); + Diag << FixItHint::CreateReplacement( + CharSourceRange::getCharRange( + BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)), + "("); + Diag << FixItHint::CreateReplacement( + CharSourceRange::getCharRange(BraceRange.getEnd(), + BraceRange.getEnd().getLocWithOffset(1)), + ")"); + } + + SourceLocation NewStart = New->getSourceRange().getBegin(); + SourceLocation NewEnd = New->getSourceRange().getEnd(); + switch (New->getInitializationStyle()) { + case CXXNewExpr::NoInit: { + Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd)); + break; + } + case CXXNewExpr::CallInit: { + SourceRange InitRange = New->getDirectInitRange(); + Diag << FixItHint::CreateRemoval( + SourceRange(NewStart, InitRange.getBegin())); + Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd)); + break; + } + case CXXNewExpr::ListInit: { + // Range of the substring that we do not want to remove. + SourceRange InitRange; + if (const auto *NewConstruct = New->getConstructExpr()) { + // Direct initialization with initialization list. + // struct S { S(int x) {} }; + // smart_ptr<S>(new S{5}); + // The arguments in the initialization list are going to be forwarded to + // the constructor, so this has to be replaced with: + // struct S { S(int x) {} }; + // std::make_smart_ptr<S>(5); + InitRange = SourceRange( + NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1), + NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1)); + } else { + // Aggregate initialization. + // smart_ptr<Pair>(new Pair{first, second}); + // Has to be replaced with: + // smart_ptr<Pair>(Pair{first, second}); + InitRange = SourceRange( + New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(), + New->getInitializer()->getSourceRange().getEnd()); + } + Diag << FixItHint::CreateRemoval( + CharSourceRange::getCharRange(NewStart, InitRange.getBegin())); + Diag << FixItHint::CreateRemoval( + SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd)); + break; + } + } +} + +} // namespace modernize +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h new file mode 100644 index 00000000000..38a8b18e04b --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h @@ -0,0 +1,50 @@ +//===--- MakeSmartPtrCheck.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_MODERNIZE_MAKE_SMART_PTR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H + +#include "../ClangTidy.h" +#include <string> + +namespace clang { +namespace tidy { +namespace modernize { + +/// Base class for MakeSharedCheck and MakeUniqueCheck. +class MakeSmartPtrCheck : public ClangTidyCheck { +public: + MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context, + std::string makeSmartPtrFunctionName); + void registerMatchers(ast_matchers::MatchFinder *Finder) override final; + void + check(const ast_matchers::MatchFinder::MatchResult &Result) override final; + +protected: + using SmartPtrTypeMatcher = ast_matchers::internal::BindableMatcher<QualType>; + + /// Returns matcher that match with different smart pointer types. + /// + /// Requires to bind pointer type (qualType) with PointerType string declared + /// in this class. + virtual SmartPtrTypeMatcher getSmartPointerTypeMatcher() const = 0; + + static const char PointerType[]; + static const char ConstructorCall[]; + static const char NewExpression[]; + +private: + std::string makeSmartPtrFunctionName; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H diff --git a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp index a585fe3e813..cef8e9d9a5e 100644 --- a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp @@ -8,9 +8,6 @@ //===----------------------------------------------------------------------===// #include "MakeUniqueCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; @@ -18,136 +15,24 @@ namespace clang { namespace tidy { namespace modernize { -static const char PointerType[] = "pointerType"; -static const char ConstructorCall[] = "constructorCall"; -static const char NewExpression[] = "newExpression"; - -void MakeUniqueCheck::registerMatchers(MatchFinder *Finder) { - if (getLangOpts().CPlusPlus11) { - Finder->addMatcher( - cxxBindTemporaryExpr(has( - cxxConstructExpr( - hasType(qualType(hasDeclaration(classTemplateSpecializationDecl( - matchesName("::std::unique_ptr"), - templateArgumentCountIs(2), - hasTemplateArgument(0, templateArgument(refersToType( - qualType().bind(PointerType)))), - hasTemplateArgument( - 1, templateArgument(refersToType(qualType( - hasDeclaration(classTemplateSpecializationDecl( - matchesName("::std::default_delete"), - templateArgumentCountIs(1), - hasTemplateArgument( - 0, templateArgument(refersToType( - qualType(equalsBoundNode( - PointerType))))))))))))))), - argumentCountIs(1), - hasArgument( - 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( - equalsBoundNode(PointerType)))))) - .bind(NewExpression))) - .bind(ConstructorCall))), - this); - } -} - -void MakeUniqueCheck::check(const MatchFinder::MatchResult &Result) { - SourceManager &SM = *Result.SourceManager; - const auto *Construct = - Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall); - const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType); - const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression); - - if (New->getNumPlacementArgs() != 0) - return; - - SourceLocation ConstructCallStart = Construct->getExprLoc(); - - bool Invalid = false; - StringRef ExprStr = Lexer::getSourceText( - CharSourceRange::getCharRange( - ConstructCallStart, Construct->getParenOrBraceRange().getBegin()), - SM, LangOptions(), &Invalid); - if (Invalid) - return; - - auto Diag = diag(ConstructCallStart, "use std::make_unique instead"); - - // Find the location of the template's left angle. - size_t LAngle = ExprStr.find("<"); - SourceLocation ConstructCallEnd; - if (LAngle == StringRef::npos) { - // If the template argument is missing (because it is part of the alias) - // we have to add it back. - ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size()); - Diag << FixItHint::CreateInsertion( - ConstructCallEnd, "<" + Type->getAsString(getLangOpts()) + ">"); - } else { - ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle); - } - - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd), - "std::make_unique"); - - // If the unique_ptr is built with brace enclosed direct initialization, use - // parenthesis instead. - if (Construct->isListInitialization()) { - SourceRange BraceRange = Construct->getParenOrBraceRange(); - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange( - BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)), - "("); - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange(BraceRange.getEnd(), - BraceRange.getEnd().getLocWithOffset(1)), - ")"); - } - - SourceLocation NewStart = New->getSourceRange().getBegin(); - SourceLocation NewEnd = New->getSourceRange().getEnd(); - switch (New->getInitializationStyle()) { - case CXXNewExpr::NoInit: { - Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd)); - break; - } - case CXXNewExpr::CallInit: { - SourceRange InitRange = New->getDirectInitRange(); - Diag << FixItHint::CreateRemoval( - SourceRange(NewStart, InitRange.getBegin())); - Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd)); - break; - } - case CXXNewExpr::ListInit: { - // Range of the substring that we do not want to remove. - SourceRange InitRange; - if (const auto *NewConstruct = New->getConstructExpr()) { - // Direct initialization with initialization list. - // struct S { S(int x) {} }; - // std::unique_ptr<S>(new S{5}); - // The arguments in the initialization list are going to be forwarded to - // the constructor, so this has to be replaced with: - // struct S { S(int x) {} }; - // std::make_unique<S>(5); - InitRange = SourceRange( - NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1), - NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1)); - } else { - // Aggregate initialization. - // std::unique_ptr<Pair>(new Pair{first, second}); - // Has to be replaced with: - // std::make_unique<Pair>(Pair{first, second}); - InitRange = SourceRange( - New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(), - New->getInitializer()->getSourceRange().getEnd()); - } - Diag << FixItHint::CreateRemoval( - CharSourceRange::getCharRange(NewStart, InitRange.getBegin())); - Diag << FixItHint::CreateRemoval( - SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd)); - break; - } - } +MakeUniqueCheck::MakeUniqueCheck(StringRef Name, + clang::tidy::ClangTidyContext *Context) + : MakeSmartPtrCheck(Name, Context, "std::make_unique") {} + +MakeUniqueCheck::SmartPtrTypeMatcher +MakeUniqueCheck::getSmartPointerTypeMatcher() const { + return qualType(hasDeclaration(classTemplateSpecializationDecl( + matchesName("::std::unique_ptr"), templateArgumentCountIs(2), + hasTemplateArgument( + 0, templateArgument(refersToType(qualType().bind(PointerType)))), + hasTemplateArgument( + 1, templateArgument(refersToType( + qualType(hasDeclaration(classTemplateSpecializationDecl( + matchesName("::std::default_delete"), + templateArgumentCountIs(1), + hasTemplateArgument( + 0, templateArgument(refersToType(qualType( + equalsBoundNode(PointerType)))))))))))))); } } // namespace modernize diff --git a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.h index 824204e2162..b939633d0d4 100644 --- a/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.h @@ -10,7 +10,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_UNIQUE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_UNIQUE_H -#include "../ClangTidy.h" +#include "MakeSmartPtrCheck.h" namespace clang { namespace tidy { @@ -25,12 +25,12 @@ namespace modernize { /// \code /// std::make_unique<type>(args...) /// \endcode -class MakeUniqueCheck : public ClangTidyCheck { +class MakeUniqueCheck : public MakeSmartPtrCheck { public: - MakeUniqueCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + MakeUniqueCheck(StringRef Name, ClangTidyContext *Context); + +protected: + SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override; }; } // namespace modernize diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index d7bda45351a..93866ba8dab 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "DeprecatedHeadersCheck.h" #include "LoopConvertCheck.h" +#include "MakeSharedCheck.h" #include "MakeUniqueCheck.h" #include "PassByValueCheck.h" #include "RawStringLiteralCheck.h" @@ -35,6 +36,7 @@ public: CheckFactories.registerCheck<DeprecatedHeadersCheck>( "modernize-deprecated-headers"); CheckFactories.registerCheck<LoopConvertCheck>("modernize-loop-convert"); + CheckFactories.registerCheck<MakeSharedCheck>("modernize-make-shared"); CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique"); CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value"); CheckFactories.registerCheck<RawStringLiteralCheck>( |

