summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/cpp11-migrate/UseAuto/UseAutoActions.cpp
blob: 14986d8dca94f4db46ab6417ecbee74e17514d51 (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
//===-- 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 the UseAutoFixer class.
///
//===----------------------------------------------------------------------===//
#include "UseAutoActions.h"
#include "UseAutoMatchers.h"
#include "clang/AST/ASTContext.h"

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

void UseAutoFixer::run(const MatchFinder::MatchResult &Result) {
  const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>(DeclNodeId);

  assert(D && "Bad Callback. No node provided");

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

  const Expr *ExprInit = D->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(D->getType(), E->getType())) {
    TypeLoc TL = D->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;
  }
}
OpenPOWER on IntegriCloud