summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp
blob: d0f2e0f071398810ea78aed85da47adc9942c9c3 (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
123
124
125
//===-- nullptr-convert/NullptrActions.cpp - Matcher callback -------------===//
//
//                     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 definition of the NullptrFixer class which is
///  used as an ASTMatcher callback. Also within this file is a helper AST
///  visitor class used to identify sequences of explicit casts.
///
//===----------------------------------------------------------------------===//

#include "NullptrActions.h"
#include "NullptrMatchers.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"

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

namespace {

/// \brief Replaces the provided range with the text "nullptr", but only if 
/// the start and end location are both in main file.
/// Returns true if and only if a replacement was made.
bool ReplaceWithNullptr(tooling::Replacements &Replace, SourceManager &SM,
                        SourceLocation StartLoc, SourceLocation EndLoc) {
  if (SM.isFromSameFile(StartLoc, EndLoc) && SM.isFromMainFile(StartLoc)) {
    CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
    Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
    return true;
  } else
    return false;
}

}

/// \brief Looks for a sequences of 0 or more explicit casts with an implicit
/// null-to-pointer cast within.
///
/// The matcher this visitor is used with will find a top-most explicit cast
/// (i.e. it has no explicit casts as an ancestor) where an implicit cast is
/// nested within. However, there is no guarantee that only explicit casts
/// exist between the found top-most explicit cast and the possibly more than
/// one nested implicit cast. This visitor finds all cast sequences with an
/// implicit cast to null within and creates a replacement.
class CastSequenceVisitor : public RecursiveASTVisitor<CastSequenceVisitor> {
public:
  CastSequenceVisitor(tooling::Replacements &R, SourceManager &SM,
                      unsigned &AcceptedChanges)
      : Replace(R), SM(SM), AcceptedChanges(AcceptedChanges), FirstCast(0) {}

  // Only VisitStmt is overridden as we shouldn't find other base AST types
  // within a cast expression.
  bool VisitStmt(Stmt *S) {
    CastExpr *C = dyn_cast<CastExpr>(S);

    if (!C) {
      ResetFirstCast();
      return true;
    } else if (!FirstCast) {
      FirstCast = C;
    }

    if (C->getCastKind() == CK_NullToPointer ||
        C->getCastKind() == CK_NullToMemberPointer) {
      SourceLocation StartLoc = FirstCast->getLocStart();
      SourceLocation EndLoc = FirstCast->getLocEnd();

      // If the start/end location is a macro, get the expansion location.
      StartLoc = SM.getFileLoc(StartLoc);
      EndLoc = SM.getFileLoc(EndLoc);

      AcceptedChanges +=
          ReplaceWithNullptr(Replace, SM, StartLoc, EndLoc) ? 1 : 0;

      ResetFirstCast();
    }

    return true;
  }

private:
  void ResetFirstCast() { FirstCast = 0; }

private:
  tooling::Replacements &Replace;
  SourceManager &SM;
  unsigned &AcceptedChanges;
  CastExpr *FirstCast;
};

void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) {
  SourceManager &SM = *Result.SourceManager;

  const CastExpr *NullCast = Result.Nodes.getNodeAs<CastExpr>(CastSequence);
  if (NullCast) {
    // Given an explicit cast with an implicit null-to-pointer cast within
    // use CastSequenceVisitor to identify sequences of explicit casts that can
    // be converted into 'nullptr'.
    CastSequenceVisitor Visitor(Replace, SM, AcceptedChanges);
    Visitor.TraverseStmt(const_cast<CastExpr *>(NullCast));
  }

  const CastExpr *Cast = Result.Nodes.getNodeAs<CastExpr>(ImplicitCastNode);
  if (Cast) {
    const Expr *E = Cast->IgnoreParenImpCasts();

    SourceLocation StartLoc = E->getLocStart();
    SourceLocation EndLoc = E->getLocEnd();

    // If the start/end location is a macro, get the expansion location.
    StartLoc = SM.getFileLoc(StartLoc);
    EndLoc = SM.getFileLoc(EndLoc);

    AcceptedChanges +=
        ReplaceWithNullptr(Replace, SM, StartLoc, EndLoc) ? 1 : 0;
  }
}
OpenPOWER on IntegriCloud