clang-tools  3.9.0
MakeSmartPtrCheck.cpp
Go to the documentation of this file.
1 //===--- MakeSmartPtrCheck.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 "MakeSharedCheck.h"
11 #include "clang/Lex/Lexer.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace modernize {
18 
19 const char MakeSmartPtrCheck::PointerType[] = "pointerType";
20 const char MakeSmartPtrCheck::ConstructorCall[] = "constructorCall";
21 const char MakeSmartPtrCheck::NewExpression[] = "newExpression";
22 
23 MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
24  std::string makeSmartPtrFunctionName)
25  : ClangTidyCheck(Name, Context),
26  makeSmartPtrFunctionName(std::move(makeSmartPtrFunctionName)) {}
27 
28 void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
29  if (!getLangOpts().CPlusPlus11)
30  return;
31 
32  Finder->addMatcher(
33  cxxBindTemporaryExpr(has(ignoringParenImpCasts(
34  cxxConstructExpr(
35  hasType(getSmartPointerTypeMatcher()), argumentCountIs(1),
36  hasArgument(0,
37  cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
38  equalsBoundNode(PointerType))))))
39  .bind(NewExpression)))
40  .bind(ConstructorCall)))),
41  this);
42 }
43 
44 void MakeSmartPtrCheck::check(const MatchFinder::MatchResult &Result) {
45  // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
46  // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
47  // 'std::make_unique' or other function that creates smart_ptr.
48 
49  SourceManager &SM = *Result.SourceManager;
50  const auto *Construct =
51  Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
52  const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType);
53  const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
54 
55  if (New->getNumPlacementArgs() != 0)
56  return;
57 
58  SourceLocation ConstructCallStart = Construct->getExprLoc();
59 
60  bool Invalid = false;
61  StringRef ExprStr = Lexer::getSourceText(
62  CharSourceRange::getCharRange(
63  ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
64  SM, LangOptions(), &Invalid);
65  if (Invalid)
66  return;
67 
68  auto Diag = diag(ConstructCallStart, "use %0 instead")
69  << makeSmartPtrFunctionName;
70 
71  // Find the location of the template's left angle.
72  size_t LAngle = ExprStr.find("<");
73  SourceLocation ConstructCallEnd;
74  if (LAngle == StringRef::npos) {
75  // If the template argument is missing (because it is part of the alias)
76  // we have to add it back.
77  ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
78  Diag << FixItHint::CreateInsertion(
79  ConstructCallEnd, "<" + Type->getAsString(getLangOpts()) + ">");
80  } else {
81  ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
82  }
83 
84  Diag << FixItHint::CreateReplacement(
85  CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
86  makeSmartPtrFunctionName);
87 
88  // If the smart_ptr is built with brace enclosed direct initialization, use
89  // parenthesis instead.
90  if (Construct->isListInitialization()) {
91  SourceRange BraceRange = Construct->getParenOrBraceRange();
92  Diag << FixItHint::CreateReplacement(
93  CharSourceRange::getCharRange(
94  BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
95  "(");
96  Diag << FixItHint::CreateReplacement(
97  CharSourceRange::getCharRange(BraceRange.getEnd(),
98  BraceRange.getEnd().getLocWithOffset(1)),
99  ")");
100  }
101 
102  SourceLocation NewStart = New->getSourceRange().getBegin();
103  SourceLocation NewEnd = New->getSourceRange().getEnd();
104  switch (New->getInitializationStyle()) {
105  case CXXNewExpr::NoInit: {
106  Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
107  break;
108  }
109  case CXXNewExpr::CallInit: {
110  SourceRange InitRange = New->getDirectInitRange();
111  Diag << FixItHint::CreateRemoval(
112  SourceRange(NewStart, InitRange.getBegin()));
113  Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
114  break;
115  }
116  case CXXNewExpr::ListInit: {
117  // Range of the substring that we do not want to remove.
118  SourceRange InitRange;
119  if (const auto *NewConstruct = New->getConstructExpr()) {
120  // Direct initialization with initialization list.
121  // struct S { S(int x) {} };
122  // smart_ptr<S>(new S{5});
123  // The arguments in the initialization list are going to be forwarded to
124  // the constructor, so this has to be replaced with:
125  // struct S { S(int x) {} };
126  // std::make_smart_ptr<S>(5);
127  InitRange = SourceRange(
128  NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
129  NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
130  } else {
131  // Aggregate initialization.
132  // smart_ptr<Pair>(new Pair{first, second});
133  // Has to be replaced with:
134  // smart_ptr<Pair>(Pair{first, second});
135  InitRange = SourceRange(
136  New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
137  New->getInitializer()->getSourceRange().getEnd());
138  }
139  Diag << FixItHint::CreateRemoval(
140  CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
141  Diag << FixItHint::CreateRemoval(
142  SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
143  break;
144  }
145  }
146 }
147 
148 } // namespace modernize
149 } // namespace tidy
150 } // namespace clang
const std::string Name
Definition: USRFinder.cpp:140
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:170
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:210
void registerMatchers(ast_matchers::MatchFinder *Finder) final
Override this to register AST matchers with Finder.
Base class for all clang-tidy checks.
Definition: ClangTidy.h:110
virtual SmartPtrTypeMatcher getSmartPointerTypeMatcher() const =0
Returns matcher that match with different smart pointer types.
SourceManager & SM
void check(const ast_matchers::MatchFinder::MatchResult &Result) final
ClangTidyChecks that register ASTMatchers should do the actual work in here.
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidy.cpp:352
const NamedDecl * Result
Definition: USRFinder.cpp:137