llvm-project/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp

119 lines
4.0 KiB
C++

//===-- 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;
/// \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);
if (SM.getFileID(StartLoc) == SM.getFileID(EndLoc) &&
SM.isFromMainFile(StartLoc) && SM.isFromMainFile(EndLoc)) {
CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
++AcceptedChanges;
}
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) {
SourceLocation StartLoc = Cast->getLocStart();
SourceLocation EndLoc = Cast->getLocEnd();
if (SM.getFileID(StartLoc) != SM.getFileID(EndLoc))
return;
// If the start/end location is a macro, get the expansion location.
StartLoc = SM.getFileLoc(StartLoc);
EndLoc = SM.getFileLoc(EndLoc);
if (!SM.isFromMainFile(StartLoc) || !SM.isFromMainFile(EndLoc))
return;
CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
++AcceptedChanges;
}
}