11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
15 using namespace clang::ast_matchers;
25 void MakeUniqueCheck::registerMatchers(MatchFinder *
Finder) {
26 if (getLangOpts().CPlusPlus11) {
28 cxxBindTemporaryExpr(has(
30 hasType(qualType(hasDeclaration(classTemplateSpecializationDecl(
31 matchesName(
"::std::unique_ptr"),
32 templateArgumentCountIs(2),
33 hasTemplateArgument(0, templateArgument(refersToType(
36 1, templateArgument(refersToType(qualType(
37 hasDeclaration(classTemplateSpecializationDecl(
38 matchesName(
"::std::default_delete"),
39 templateArgumentCountIs(1),
41 0, templateArgument(refersToType(
42 qualType(equalsBoundNode(
46 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
54 void MakeUniqueCheck::check(
const MatchFinder::MatchResult &
Result) {
55 SourceManager &
SM = *Result.SourceManager;
56 const auto *Construct =
58 const auto *Type = Result.Nodes.getNodeAs<QualType>(
PointerType);
59 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(
NewExpression);
61 if (New->getNumPlacementArgs() != 0)
64 SourceLocation ConstructCallStart = Construct->getExprLoc();
67 StringRef ExprStr = Lexer::getSourceText(
68 CharSourceRange::getCharRange(
69 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
70 SM, LangOptions(), &Invalid);
74 auto Diag = diag(ConstructCallStart,
"use std::make_unique instead");
77 size_t LAngle = ExprStr.find(
"<");
78 SourceLocation ConstructCallEnd;
79 if (LAngle == StringRef::npos) {
82 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
83 Diag << FixItHint::CreateInsertion(
84 ConstructCallEnd,
"<" + Type->getAsString(getLangOpts()) +
">");
86 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
89 Diag << FixItHint::CreateReplacement(
90 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
95 if (Construct->isListInitialization()) {
96 SourceRange BraceRange = Construct->getParenOrBraceRange();
97 Diag << FixItHint::CreateReplacement(
98 CharSourceRange::getCharRange(
99 BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
101 Diag << FixItHint::CreateReplacement(
102 CharSourceRange::getCharRange(BraceRange.getEnd(),
103 BraceRange.getEnd().getLocWithOffset(1)),
107 SourceLocation NewStart = New->getSourceRange().getBegin();
108 SourceLocation NewEnd = New->getSourceRange().getEnd();
109 switch (New->getInitializationStyle()) {
110 case CXXNewExpr::NoInit: {
111 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
114 case CXXNewExpr::CallInit: {
115 SourceRange InitRange = New->getDirectInitRange();
116 Diag << FixItHint::CreateRemoval(
117 SourceRange(NewStart, InitRange.getBegin()));
118 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
121 case CXXNewExpr::ListInit: {
123 SourceRange InitRange;
124 if (
const auto *NewConstruct = New->getConstructExpr()) {
132 InitRange = SourceRange(
133 NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
134 NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
140 InitRange = SourceRange(
141 New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
142 New->getInitializer()->getSourceRange().getEnd());
144 Diag << FixItHint::CreateRemoval(
145 CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
146 Diag << FixItHint::CreateRemoval(
147 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
std::unique_ptr< ast_matchers::MatchFinder > Finder
static const char PointerType[]
static const char ConstructorCall[]
static const char NewExpression[]