forked from OSchip/llvm-project
[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
This commit is contained in:
parent
45c7b3ecb5
commit
ce18ade406
|
@ -4,6 +4,8 @@ add_clang_library(clangTidyModernizeModule
|
|||
DeprecatedHeadersCheck.cpp
|
||||
LoopConvertCheck.cpp
|
||||
LoopConvertUtils.cpp
|
||||
MakeSmartPtrCheck.cpp
|
||||
MakeSharedCheck.cpp
|
||||
MakeUniqueCheck.cpp
|
||||
ModernizeTidyModule.cpp
|
||||
PassByValueCheck.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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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";
|
||||
MakeUniqueCheck::MakeUniqueCheck(StringRef Name,
|
||||
clang::tidy::ClangTidyContext *Context)
|
||||
: MakeSmartPtrCheck(Name, Context, "std::make_unique") {}
|
||||
|
||||
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::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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -180,6 +180,11 @@ identified. The improvements since the 3.8 release include:
|
|||
|
||||
Replaces C standard library headers with their C++ alternatives.
|
||||
|
||||
- New `modernize-make-shared
|
||||
<http://clang.llvm.org/extra/clang-tidy/checks/modernize-make-shared.html>`_ check
|
||||
|
||||
Replaces creation of ``std::shared_ptr`` from new expression with call to ``std::make_shared``.
|
||||
|
||||
- New `modernize-raw-string-literal
|
||||
<http://clang.llvm.org/extra/clang-tidy/checks/modernize-raw-string-literal.html>`_ check
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ Clang-Tidy Checks
|
|||
misc-virtual-near-miss
|
||||
modernize-deprecated-headers
|
||||
modernize-loop-convert
|
||||
modernize-make-shared
|
||||
modernize-make-unique
|
||||
modernize-pass-by-value
|
||||
modernize-raw-string-literal
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
.. title:: clang-tidy - modernize-make-shared
|
||||
|
||||
modernize-make-shared
|
||||
=====================
|
||||
|
||||
This check finds the creation of ``std::shared_ptr`` objects by explicitly
|
||||
calling the constructor and a ``new`` expression, and replaces it with a call
|
||||
to ``std::make_shared``.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
auto my_ptr = std::shared_ptr<MyPair>(new MyPair(1, 2));
|
||||
|
||||
// becomes
|
||||
|
||||
auto my_ptr = std::make_shared<MyPair>(1, 2);
|
|
@ -0,0 +1,200 @@
|
|||
// RUN: %check_clang_tidy %s modernize-make-shared %t
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename type>
|
||||
class shared_ptr {
|
||||
public:
|
||||
shared_ptr(type *ptr);
|
||||
shared_ptr(const shared_ptr<type> &t) {}
|
||||
shared_ptr(shared_ptr<type> &&t) {}
|
||||
~shared_ptr();
|
||||
type &operator*() { return *ptr; }
|
||||
type *operator->() { return ptr; }
|
||||
type *release();
|
||||
void reset();
|
||||
void reset(type *pt);
|
||||
|
||||
private:
|
||||
type *ptr;
|
||||
};
|
||||
}
|
||||
|
||||
struct Base {
|
||||
Base();
|
||||
Base(int, int);
|
||||
};
|
||||
|
||||
struct Derived : public Base {
|
||||
Derived();
|
||||
Derived(int, int);
|
||||
};
|
||||
|
||||
struct APair {
|
||||
int a, b;
|
||||
};
|
||||
|
||||
struct DPair {
|
||||
DPair() : a(0), b(0) {}
|
||||
DPair(int x, int y) : a(y), b(x) {}
|
||||
int a, b;
|
||||
};
|
||||
|
||||
struct Empty {};
|
||||
|
||||
template <class T>
|
||||
using shared_ptr_ = std::shared_ptr<T>;
|
||||
|
||||
void *operator new(__SIZE_TYPE__ Count, void *Ptr);
|
||||
|
||||
int g(std::shared_ptr<int> P);
|
||||
|
||||
std::shared_ptr<Base> getPointer() {
|
||||
return std::shared_ptr<Base>(new Base);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: return std::make_shared<Base>();
|
||||
}
|
||||
|
||||
void basic() {
|
||||
std::shared_ptr<int> P1 = std::shared_ptr<int>(new int());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared]
|
||||
// CHECK-FIXES: std::shared_ptr<int> P1 = std::make_shared<int>();
|
||||
|
||||
// Without parenthesis.
|
||||
std::shared_ptr<int> P2 = std::shared_ptr<int>(new int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared]
|
||||
// CHECK-FIXES: std::shared_ptr<int> P2 = std::make_shared<int>();
|
||||
|
||||
// With auto.
|
||||
auto P3 = std::shared_ptr<int>(new int());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: auto P3 = std::make_shared<int>();
|
||||
|
||||
{
|
||||
// No std.
|
||||
using namespace std;
|
||||
shared_ptr<int> Q = shared_ptr<int>(new int());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: shared_ptr<int> Q = std::make_shared<int>();
|
||||
}
|
||||
|
||||
std::shared_ptr<int> R(new int());
|
||||
|
||||
// Create the shared_ptr as a parameter to a function.
|
||||
int T = g(std::shared_ptr<int>(new int()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: int T = g(std::make_shared<int>());
|
||||
|
||||
// Only replace if the type in the template is the same than the type returned
|
||||
// by the new operator.
|
||||
auto Pderived = std::shared_ptr<Base>(new Derived());
|
||||
|
||||
// The pointer is returned by the function, nothing to do.
|
||||
std::shared_ptr<Base> RetPtr = getPointer();
|
||||
|
||||
// This emulates std::move.
|
||||
std::shared_ptr<int> Move = static_cast<std::shared_ptr<int> &&>(P1);
|
||||
|
||||
// Placemenet arguments should not be removed.
|
||||
int *PInt = new int;
|
||||
std::shared_ptr<int> Placement = std::shared_ptr<int>(new (PInt) int{3});
|
||||
}
|
||||
|
||||
void initialization(int T, Base b) {
|
||||
// Test different kinds of initialization of the pointee.
|
||||
|
||||
// Direct initialization with parenthesis.
|
||||
std::shared_ptr<DPair> PDir1 = std::shared_ptr<DPair>(new DPair(1, T));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<DPair> PDir1 = std::make_shared<DPair>(1, T);
|
||||
|
||||
// Direct initialization with braces.
|
||||
std::shared_ptr<DPair> PDir2 = std::shared_ptr<DPair>(new DPair{2, T});
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<DPair> PDir2 = std::make_shared<DPair>(2, T);
|
||||
|
||||
// Aggregate initialization.
|
||||
std::shared_ptr<APair> PAggr = std::shared_ptr<APair>(new APair{T, 1});
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<APair> PAggr = std::make_shared<APair>(APair{T, 1});
|
||||
|
||||
// Test different kinds of initialization of the pointee, when the shared_ptr
|
||||
// is initialized with braces.
|
||||
|
||||
// Direct initialization with parenthesis.
|
||||
std::shared_ptr<DPair> PDir3 = std::shared_ptr<DPair>{new DPair(3, T)};
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<DPair> PDir3 = std::make_shared<DPair>(3, T);
|
||||
|
||||
// Direct initialization with braces.
|
||||
std::shared_ptr<DPair> PDir4 = std::shared_ptr<DPair>{new DPair{4, T}};
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<DPair> PDir4 = std::make_shared<DPair>(4, T);
|
||||
|
||||
// Aggregate initialization.
|
||||
std::shared_ptr<APair> PAggr2 = std::shared_ptr<APair>{new APair{T, 2}};
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<APair> PAggr2 = std::make_shared<APair>(APair{T, 2});
|
||||
|
||||
// Direct initialization with parenthesis, without arguments.
|
||||
std::shared_ptr<DPair> PDir5 = std::shared_ptr<DPair>(new DPair());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<DPair> PDir5 = std::make_shared<DPair>();
|
||||
|
||||
// Direct initialization with braces, without arguments.
|
||||
std::shared_ptr<DPair> PDir6 = std::shared_ptr<DPair>(new DPair{});
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<DPair> PDir6 = std::make_shared<DPair>();
|
||||
|
||||
// Aggregate initialization without arguments.
|
||||
std::shared_ptr<Empty> PEmpty = std::shared_ptr<Empty>(new Empty{});
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<Empty> PEmpty = std::make_shared<Empty>(Empty{});
|
||||
}
|
||||
|
||||
void aliases() {
|
||||
typedef std::shared_ptr<int> IntPtr;
|
||||
IntPtr Typedef = IntPtr(new int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: IntPtr Typedef = std::make_shared<int>();
|
||||
|
||||
// We use 'bool' instead of '_Bool'.
|
||||
typedef std::shared_ptr<bool> BoolPtr;
|
||||
BoolPtr BoolType = BoolPtr(new bool);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: BoolPtr BoolType = std::make_shared<bool>();
|
||||
|
||||
// We use 'Base' instead of 'struct Base'.
|
||||
typedef std::shared_ptr<Base> BasePtr;
|
||||
BasePtr StructType = BasePtr(new Base);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: BasePtr StructType = std::make_shared<Base>();
|
||||
|
||||
#define PTR shared_ptr<int>
|
||||
std::shared_ptr<int> Macro = std::PTR(new int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<int> Macro = std::make_shared<int>();
|
||||
#undef PTR
|
||||
|
||||
std::shared_ptr<int> Using = shared_ptr_<int>(new int);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: std::shared_ptr<int> Using = std::make_shared<int>();
|
||||
}
|
||||
|
||||
void whitespaces() {
|
||||
// clang-format off
|
||||
auto Space = std::shared_ptr <int>(new int());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: auto Space = std::make_shared<int>();
|
||||
|
||||
auto Spaces = std :: shared_ptr <int>(new int());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: auto Spaces = std::make_shared<int>();
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void nesting() {
|
||||
auto Nest = std::shared_ptr<std::shared_ptr<int>>(new std::shared_ptr<int>(new int));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use std::make_shared instead
|
||||
// CHECK-FIXES: auto Nest = std::make_shared<std::shared_ptr<int>>(new int);
|
||||
}
|
Loading…
Reference in New Issue