summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp
blob: 27d8acc6f7696b8366a1d4d1f85f0c943b10d20c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//===-- UseAuto/UseAutoActions.cpp - Matcher callback impl ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
///  \file
///  \brief This file contains the implementation of callbacks for the UseAuto
///  transform.
///
//===----------------------------------------------------------------------===//
#include "UseAutoActions.h"
#include "UseAutoMatchers.h"
#include "clang/AST/ASTContext.h"

using namespace clang::ast_matchers;
using namespace clang::tooling;
using namespace clang;


void IteratorReplacer::run(const MatchFinder::MatchResult &Result) {
  const DeclStmt *D = Result.Nodes.getNodeAs<DeclStmt>(IteratorDeclStmtId);
  assert(D && "Bad Callback. No node provided");

  SourceManager &SM = *Result.SourceManager;
  if (!SM.isFromMainFile(D->getLocStart()))
    return;

  for (clang::DeclStmt::const_decl_iterator I  = D->decl_begin(),
        E = D->decl_end(); I != E; ++I) {
    const VarDecl *V = cast<VarDecl>(*I);

    const Expr *ExprInit = V->getInit();

    // Skip expressions with cleanups from the initializer expression.
    if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(ExprInit))
      ExprInit = E->getSubExpr();

    const CXXConstructExpr *Construct = cast<CXXConstructExpr>(ExprInit);

    assert(Construct->getNumArgs() == 1u &&
           "Expected constructor with single argument");

    // Drill down to the as-written initializer.
    const Expr *E = Construct->arg_begin()->IgnoreParenImpCasts();
    if (E != E->IgnoreConversionOperator())
      // We hit a conversion operator. Early-out now as they imply an implicit
      // conversion from a different type. Could also mean an explicit conversion
      // from the same type but that's pretty rare.
      return;

    if (const CXXConstructExpr *NestedConstruct = dyn_cast<CXXConstructExpr>(E))
      // If we ran into an implicit conversion constructor, can't convert.
      //
      // FIXME: The following only checks if the constructor can be used
      // implicitly, not if it actually was. Cases where the converting constructor
      // was used explicitly won't get converted.
      if (NestedConstruct->getConstructor()->isConvertingConstructor(false))
        return;
    if (!Result.Context->hasSameType(V->getType(), E->getType()))
      return;
  }
  // Get the type location using the first declartion.
  const VarDecl *V = cast<VarDecl>(*D->decl_begin());
  TypeLoc TL = V->getTypeSourceInfo()->getTypeLoc();

  // WARNING: TypeLoc::getSourceRange() will include the identifier for things
  // like function pointers. Not a concern since this action only works with
  // iterators but something to keep in mind in the future.

  CharSourceRange Range(TL.getSourceRange(), true);
  Replace.insert(tooling::Replacement(SM, Range, "auto"));
  ++AcceptedChanges;
}

void NewReplacer::run(const MatchFinder::MatchResult &Result) {
  const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>(DeclWithNewId);
  assert(D && "Bad Callback. No node provided");

  SourceManager &SM = *Result.SourceManager;
  if (!SM.isFromMainFile(D->getLocStart()))
    return;

  const CXXNewExpr *NewExpr = Result.Nodes.getNodeAs<CXXNewExpr>(NewExprId);
  assert(NewExpr && "Bad Callback. No CXXNewExpr bound");

  // If declaration and initializer have exactly the same type, just replace
  // with 'auto'.
  if (Result.Context->hasSameType(D->getType(), NewExpr->getType())) {
    TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
    CharSourceRange Range(TL.getSourceRange(), /*IsTokenRange=*/ true);
    // Space after 'auto' to handle cases where the '*' in the pointer type
    // is next to the identifier. This avoids changing 'int *p' into 'autop'.
    Replace.insert(tooling::Replacement(SM, Range, "auto "));
    ++AcceptedChanges;
    return;
  }

  // If the CV qualifiers for the pointer differ then we still use auto, just
  // need to leave the qualifier behind.
  if (Result.Context->hasSameUnqualifiedType(D->getType(),
                                             NewExpr->getType())) {
    TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
    CharSourceRange Range(TL.getSourceRange(), /*IsTokenRange=*/ true);
    // Space after 'auto' to handle cases where the '*' in the pointer type
    // is next to the identifier. This avoids changing 'int *p' into 'autop'.
    Replace.insert(tooling::Replacement(SM, Range, "auto "));
    ++AcceptedChanges;
    return;
  }

  // The VarDecl and Initializer have mismatching types.
  return;

  // FIXME: There is, however, one case we can address: when the VarDecl
  // pointee is the same as the initializer, just more CV-qualified. However,
  // TypeLoc information is not reliable where CV qualifiers are concerned so
  // we can't do anything about this case for now.
}
OpenPOWER on IntegriCloud