blob: 77c684984de8110cd20630a3347ee61499919d93 [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"),
32 templateArgumentCountIs(1),
33 hasTemplateArgument(
34 0, templateArgument(
35 refersToType(qualType().bind(PointerType)))))))),
36 argumentCountIs(1),
37 hasArgument(0, cxxNewExpr(hasType(pointsTo(qualType(
38 equalsBoundNode(PointerType)))))
39 .bind(NewExpression)))
40 .bind(ConstructorCall))),
41 this);
42 }
43}
44
45void MakeUniqueCheck::check(const MatchFinder::MatchResult &Result) {
46 SourceManager &SM = *Result.SourceManager;
47 const auto *Construct =
48 Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
49 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
50 const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType);
51
52 SourceLocation ConstructCallStart = Construct->getExprLoc();
53
54 bool Invalid = false;
55 StringRef ExprStr = Lexer::getSourceText(
56 CharSourceRange::getCharRange(
57 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
58 SM, LangOptions(), &Invalid);
59 if (Invalid)
60 return;
61
62 auto Diag = diag(ConstructCallStart, "use std::make_unique instead");
63
64 // Find the location of the template's left angle.
65 size_t LAngle = ExprStr.find("<");
66 SourceLocation ConstructCallEnd;
67 if (LAngle == StringRef::npos) {
68 // If the template argument is missing (because it is part of the alias)
69 // we have to add it back.
70 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
71 Diag << FixItHint::CreateInsertion(ConstructCallEnd,
72 "<" + Type->getAsString() + ">");
73 } else {
74 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
75 }
76
77 Diag << FixItHint::CreateReplacement(
78 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
79 "std::make_unique");
80
81 SourceLocation NewStart = New->getSourceRange().getBegin();
82 SourceLocation NewEnd = New->getSourceRange().getEnd();
83 switch (New->getInitializationStyle()) {
84 case CXXNewExpr::NoInit: {
85 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
86 break;
87 }
88 case CXXNewExpr::CallInit: {
89 SourceRange InitRange = New->getDirectInitRange();
90 Diag << FixItHint::CreateRemoval(
91 SourceRange(NewStart, InitRange.getBegin()));
92 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
93 break;
94 }
95 case CXXNewExpr::ListInit: {
96 SourceRange InitRange = New->getInitializer()->getSourceRange();
97 Diag << FixItHint::CreateRemoval(
98 SourceRange(NewStart, InitRange.getBegin().getLocWithOffset(-1)));
99 Diag << FixItHint::CreateRemoval(
100 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
101 break;
102 }
103 }
104}
105
106} // namespace modernize
107} // namespace tidy
108} // namespace clang