blob: bdf5538a59c3bd21c1e28430f4a9095ab4367c81 [file] [log] [blame]
Angel Garcia Gomez26fd0e82015-09-29 09:36:41 +00001//===--- 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
15using namespace clang::ast_matchers;
16
17namespace clang {
18namespace tidy {
19namespace modernize {
20
21const char PointerType[] = "pointerType";
22const char ConstructorCall[] = "constructorCall";
23const char NewExpression[] = "newExpression";
24
25void 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"),
Angel Garcia Gomezb9f30592015-10-05 12:20:17 +000032 templateArgumentCountIs(2),
33 hasTemplateArgument(0, templateArgument(refersToType(
34 qualType().bind(PointerType)))),
Angel Garcia Gomez26fd0e82015-09-29 09:36:41 +000035 hasTemplateArgument(
Angel Garcia Gomezb9f30592015-10-05 12:20:17 +000036 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))))))))))))))),
Angel Garcia Gomez26fd0e82015-09-29 09:36:41 +000044 argumentCountIs(1),
45 hasArgument(0, cxxNewExpr(hasType(pointsTo(qualType(
46 equalsBoundNode(PointerType)))))
47 .bind(NewExpression)))
48 .bind(ConstructorCall))),
49 this);
50 }
51}
52
53void MakeUniqueCheck::check(const MatchFinder::MatchResult &Result) {
54 SourceManager &SM = *Result.SourceManager;
55 const auto *Construct =
56 Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
57 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
58 const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType);
59
60 SourceLocation ConstructCallStart = Construct->getExprLoc();
61
62 bool Invalid = false;
63 StringRef ExprStr = Lexer::getSourceText(
64 CharSourceRange::getCharRange(
65 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
66 SM, LangOptions(), &Invalid);
67 if (Invalid)
68 return;
69
70 auto Diag = diag(ConstructCallStart, "use std::make_unique instead");
71
72 // Find the location of the template's left angle.
73 size_t LAngle = ExprStr.find("<");
74 SourceLocation ConstructCallEnd;
75 if (LAngle == StringRef::npos) {
76 // If the template argument is missing (because it is part of the alias)
77 // we have to add it back.
78 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
79 Diag << FixItHint::CreateInsertion(ConstructCallEnd,
80 "<" + Type->getAsString() + ">");
81 } else {
82 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
83 }
84
85 Diag << FixItHint::CreateReplacement(
86 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
87 "std::make_unique");
88
89 SourceLocation NewStart = New->getSourceRange().getBegin();
90 SourceLocation NewEnd = New->getSourceRange().getEnd();
91 switch (New->getInitializationStyle()) {
92 case CXXNewExpr::NoInit: {
93 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
94 break;
95 }
96 case CXXNewExpr::CallInit: {
97 SourceRange InitRange = New->getDirectInitRange();
98 Diag << FixItHint::CreateRemoval(
99 SourceRange(NewStart, InitRange.getBegin()));
100 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
101 break;
102 }
103 case CXXNewExpr::ListInit: {
104 SourceRange InitRange = New->getInitializer()->getSourceRange();
105 Diag << FixItHint::CreateRemoval(
106 SourceRange(NewStart, InitRange.getBegin().getLocWithOffset(-1)));
107 Diag << FixItHint::CreateRemoval(
108 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
109 break;
110 }
111 }
112}
113
114} // namespace modernize
115} // namespace tidy
116} // namespace clang