clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

MakeUniqueCheck.cpp
Go to the documentation of this file.
1 //===--- MakeUniqueCheck.cpp - clang-tidy----------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "MakeUniqueCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14
15 using namespace clang::ast_matchers;
16
17 namespace clang {
18 namespace tidy {
19 namespace modernize {
20
21 static const char PointerType[] = "pointerType";
22 static const char ConstructorCall[] = "constructorCall";
23 static const char NewExpression[] = "newExpression";
24
25 void MakeUniqueCheck::registerMatchers(MatchFinder *Finder) {
26 if (getLangOpts().CPlusPlus11) {
27 Finder->addMatcher(
28 cxxBindTemporaryExpr(has(
29 cxxConstructExpr(
30 hasType(qualType(hasDeclaration(classTemplateSpecializationDecl(
31 matchesName("::std::unique_ptr"),
32 templateArgumentCountIs(2),
33 hasTemplateArgument(0, templateArgument(refersToType(
34 qualType().bind(PointerType)))),
35 hasTemplateArgument(
36 1, templateArgument(refersToType(qualType(
37 hasDeclaration(classTemplateSpecializationDecl(
38 matchesName("::std::default_delete"),
39 templateArgumentCountIs(1),
40 hasTemplateArgument(
41 0, templateArgument(refersToType(
42 qualType(equalsBoundNode(
43 PointerType))))))))))))))),
44 argumentCountIs(1),
45 hasArgument(
46 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
47 equalsBoundNode(PointerType))))))
48 .bind(NewExpression)))
49 .bind(ConstructorCall))),
50 this);
51 }
52 }
53
54 void MakeUniqueCheck::check(const MatchFinder::MatchResult &Result) {
55 SourceManager &SM = *Result.SourceManager;
56 const auto *Construct =
57 Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
58 const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType);
59 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
60
61 if (New->getNumPlacementArgs() != 0)
62 return;
63
64 SourceLocation ConstructCallStart = Construct->getExprLoc();
65
66 bool Invalid = false;
67 StringRef ExprStr = Lexer::getSourceText(
68 CharSourceRange::getCharRange(
69 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
70 SM, LangOptions(), &Invalid);
71 if (Invalid)
72 return;
73
74 auto Diag = diag(ConstructCallStart, "use std::make_unique instead");
75
76 // Find the location of the template's left angle.
77 size_t LAngle = ExprStr.find("<");
78 SourceLocation ConstructCallEnd;
79 if (LAngle == StringRef::npos) {
80 // If the template argument is missing (because it is part of the alias)
81 // we have to add it back.
82 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
83 Diag << FixItHint::CreateInsertion(
84 ConstructCallEnd, "<" + Type->getAsString(getLangOpts()) + ">");
85 } else {
86 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
87 }
88
89 Diag << FixItHint::CreateReplacement(
90 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
91 "std::make_unique");
92
93 // If the unique_ptr is built with brace enclosed direct initialization, use
94 // parenthesis instead.
95 if (Construct->isListInitialization()) {
96 SourceRange BraceRange = Construct->getParenOrBraceRange();
97 Diag << FixItHint::CreateReplacement(
98 CharSourceRange::getCharRange(
99 BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
100 "(");
101 Diag << FixItHint::CreateReplacement(
102 CharSourceRange::getCharRange(BraceRange.getEnd(),
103 BraceRange.getEnd().getLocWithOffset(1)),
104 ")");
105 }
106
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));
112 break;
113 }
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));
119 break;
120 }
121 case CXXNewExpr::ListInit: {
122 // Range of the substring that we do not want to remove.
123 SourceRange InitRange;
124 if (const auto *NewConstruct = New->getConstructExpr()) {
125 // Direct initialization with initialization list.
126 // struct S { S(int x) {} };
127 // std::unique_ptr<S>(new S{5});
128 // The arguments in the initialization list are going to be forwarded to
129 // the constructor, so this has to be replaced with:
130 // struct S { S(int x) {} };
131 // std::make_unique<S>(5);
132 InitRange = SourceRange(
133 NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
134 NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
135 } else {
136 // Aggregate initialization.
137 // std::unique_ptr<Pair>(new Pair{first, second});
138 // Has to be replaced with:
139 // std::make_unique<Pair>(Pair{first, second});
140 InitRange = SourceRange(
141 New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
142 New->getInitializer()->getSourceRange().getEnd());
143 }
144 Diag << FixItHint::CreateRemoval(
145 CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
146 Diag << FixItHint::CreateRemoval(
147 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
148 break;
149 }
150 }
151 }
152
153 } // namespace modernize
154 } // namespace tidy
155 } // namespace clang
Finder
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
SM
SourceManager & SM
Definition: IncludeOrderCheck.cpp:44
clang::tidy::modernize::PointerType
static const char PointerType[]
Definition: MakeUniqueCheck.cpp:21
clang::tidy::modernize::ConstructorCall
static const char ConstructorCall[]
Definition: MakeUniqueCheck.cpp:22
clang::tidy::modernize::NewExpression
static const char NewExpression[]
Definition: MakeUniqueCheck.cpp:23
MakeUniqueCheck.h
Result
const NamedDecl * Result
Definition: USRFinder.cpp:121