cpp11-migrate: Refactor NullptrActions

Several free functions related to macro arg testing are being moved into
CastSequenceVisitor to facilitate upcoming fix.

llvm-svn: 182013
This commit is contained in:
Edwin Vane 2013-05-16 14:54:24 +00:00
parent 7aa76b6a07
commit 1373c5cd6d
1 changed files with 179 additions and 181 deletions

View File

@ -77,149 +77,6 @@ llvm::StringRef GetOutermostMacroName(
return clang::Lexer::getImmediateMacroName(OutermostMacroLoc, SM, LO);
}
/// \brief Given the SourceLocation for a macro arg expansion, finds the
/// non-macro SourceLocation of the macro the arg was passed to and the
/// non-macro SourceLocation of the argument in the arg list to that macro.
/// These results are returned via \c MacroLoc and \c ArgLoc respectively.
/// These values are undefined if the return value is false.
///
/// \returns false if one of the returned SourceLocations would be a
/// SourceLocation pointing within the definition of another macro.
bool getMacroAndArgLocations(SourceLocation Loc, const SourceManager &SM,
SourceLocation &ArgLoc, SourceLocation &MacroLoc) {
assert(Loc.isMacroID() && "Only reasonble to call this on macros");
ArgLoc = Loc;
// Find the location of the immediate macro expansion.
while (1) {
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(ArgLoc);
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
ArgLoc = Expansion.getExpansionLocStart();
if (!Expansion.isMacroArgExpansion()) {
// TODO: Insert test for user-defined null macro here.
return MacroLoc.isFileID();
}
MacroLoc = SM.getImmediateExpansionRange(ArgLoc).first;
ArgLoc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
if (ArgLoc.isFileID())
return true;
// If spelling location resides in the same FileID as macro expansion
// location, it means there is no inner macro.
FileID MacroFID = SM.getFileID(MacroLoc);
if (SM.isInFileID(ArgLoc, MacroFID))
// Don't transform this case. If the characters that caused the
// null-conversion come from within a macro, they can't be changed.
return false;
}
llvm_unreachable("getMacroAndArgLocations");
}
/// \brief Tests if TestMacroLoc is found while recursively unravelling
/// expansions starting at TestLoc. TestMacroLoc.isFileID() must be true.
/// Implementation is very similar to getMacroAndArgLocations() except in this
/// case, it's not assumed that TestLoc is expanded from a macro argument.
/// While unravelling expansions macro arguments are handled as with
/// getMacroAndArgLocations() but in this function macro body expansions are
/// also handled.
///
/// False means either:
/// - TestLoc is not from a macro expansion
/// - TestLoc is from a different macro expansion
bool expandsFrom(SourceLocation TestLoc, SourceLocation TestMacroLoc,
const SourceManager &SM) {
if (TestLoc.isFileID()) {
return false;
}
SourceLocation Loc = TestLoc, MacroLoc;
while (1) {
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
Loc = Expansion.getExpansionLocStart();
if (!Expansion.isMacroArgExpansion()) {
if (Loc.isFileID()) {
if (Loc == TestMacroLoc)
// Match made.
return true;
return false;
}
// Since Loc is still a macro ID and it's not an argument expansion, we
// don't need to do the work of handling an argument expansion. Simply
// keep recursively expanding until we hit a FileID or a macro arg
// expansion or a macro arg expansion.
continue;
}
MacroLoc = SM.getImmediateExpansionRange(Loc).first;
if (MacroLoc.isFileID() && MacroLoc == TestMacroLoc)
// Match made.
return true;
Loc = Expansion.getSpellingLoc();
Loc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
if (Loc.isFileID())
// If we made it this far without finding a match, there is no match to
// be made.
return false;
}
llvm_unreachable("expandsFrom");
}
/// \brief Given a starting point \c Start in the AST, find an ancestor that
/// doesn't expand from the macro called at file location \c MacroLoc.
///
/// \pre MacroLoc.isFileID()
/// \returns true if such an ancestor was found, false otherwise.
bool findContainingAncestor(ast_type_traits::DynTypedNode Start,
SourceLocation MacroLoc,
ast_type_traits::DynTypedNode &Result,
ASTContext &Context) {
// Below we're only following the first parent back up the AST. This should
// be fine since for the statements we care about there should only be one
// parent as far up as we care. If this assumption doesn't hold, need to
// revisit what to do here.
assert(MacroLoc.isFileID());
do {
ASTContext::ParentVector Parents = Context.getParents(Start);
if (Parents.empty())
return false;
assert(Parents.size() == 1 &&
"Found an ancestor with more than one parent!");
ASTContext::ParentVector::const_iterator I = Parents.begin();
SourceLocation Loc;
if (const Decl *D = I->get<Decl>())
Loc = D->getLocStart();
else if (const Stmt *S = I->get<Stmt>())
Loc = S->getLocStart();
else
llvm_unreachable("Expected to find Decl or Stmt containing ancestor");
if (!expandsFrom(Loc, MacroLoc, Context.getSourceManager())) {
Result = *I;
return true;
}
Start = *I;
} while(1);
llvm_unreachable("findContainingAncestor");
}
/// \brief RecursiveASTVisitor for ensuring all nodes rooted at a given AST
/// subtree that have file-level source locations corresponding to a macro
/// argument have implicit NullTo(Member)Pointer nodes as ancestors.
@ -280,43 +137,6 @@ private:
bool InvalidFound;
};
/// \brief Tests that all expansions of a macro arg, one of which expands to
/// result in \p CE, yield NullTo(Member)Pointer casts.
bool allArgUsesValid(const CastExpr *CE, ASTContext &Context) {
SourceLocation CastLoc = CE->getLocStart();
const SourceManager &SM = Context.getSourceManager();
// Step 1: Get location of macro arg and location of the macro the arg was
// provided to.
SourceLocation ArgLoc, MacroLoc;
if (!getMacroAndArgLocations(CastLoc, SM, ArgLoc, MacroLoc))
return false;
// Step 2: Find the first ancestor that doesn't expand from this macro.
ast_type_traits::DynTypedNode ContainingAncestor;
if (!findContainingAncestor(ast_type_traits::DynTypedNode::create<Stmt>(*CE),
MacroLoc, ContainingAncestor, Context))
return false;
// Step 3:
// Visit children of this containing parent looking for the least-descended
// nodes of the containing parent which are macro arg expansions that expand
// from the given arg location.
// Visitor needs: arg loc
MacroArgUsageVisitor ArgUsageVisitor(SM.getFileLoc(CastLoc), SM);
if (const Decl *D = ContainingAncestor.get<Decl>())
ArgUsageVisitor.TraverseDecl(const_cast<Decl*>(D));
else if (const Stmt *S = ContainingAncestor.get<Stmt>())
ArgUsageVisitor.TraverseStmt(const_cast<Stmt*>(S));
else
llvm_unreachable("Unhandled ContainingAncestor node type");
if (ArgUsageVisitor.foundInvalid())
return false;
return true;
}
/// \brief Looks for implicit casts as well as sequences of 0 or more explicit
/// casts with an implicit null-to-pointer cast within.
///
@ -372,7 +192,7 @@ public:
SourceLocation FileLocStart = SM.getFileLoc(StartLoc),
FileLocEnd = SM.getFileLoc(EndLoc);
if (isReplaceableRange(FileLocStart, FileLocEnd, SM) &&
allArgUsesValid(C, Context)) {
allArgUsesValid(C)) {
ReplaceWithNullptr(Replace, SM, FileLocStart, FileLocEnd);
++AcceptedChanges;
}
@ -409,6 +229,184 @@ public:
private:
bool skipSubTree() { PruneSubtree = true; return true; }
/// \brief Tests that all expansions of a macro arg, one of which expands to
/// result in \p CE, yield NullTo(Member)Pointer casts.
bool allArgUsesValid(const CastExpr *CE) {
SourceLocation CastLoc = CE->getLocStart();
// Step 1: Get location of macro arg and location of the macro the arg was
// provided to.
SourceLocation ArgLoc, MacroLoc;
if (!getMacroAndArgLocations(CastLoc, ArgLoc, MacroLoc))
return false;
// Step 2: Find the first ancestor that doesn't expand from this macro.
ast_type_traits::DynTypedNode ContainingAncestor;
if (!findContainingAncestor(
ast_type_traits::DynTypedNode::create<Stmt>(*CE), MacroLoc,
ContainingAncestor))
return false;
// Step 3:
// Visit children of this containing parent looking for the least-descended
// nodes of the containing parent which are macro arg expansions that expand
// from the given arg location.
// Visitor needs: arg loc
MacroArgUsageVisitor ArgUsageVisitor(SM.getFileLoc(CastLoc), SM);
if (const Decl *D = ContainingAncestor.get<Decl>())
ArgUsageVisitor.TraverseDecl(const_cast<Decl *>(D));
else if (const Stmt *S = ContainingAncestor.get<Stmt>())
ArgUsageVisitor.TraverseStmt(const_cast<Stmt *>(S));
else
llvm_unreachable("Unhandled ContainingAncestor node type");
if (ArgUsageVisitor.foundInvalid())
return false;
return true;
}
/// \brief Given the SourceLocation for a macro arg expansion, finds the
/// non-macro SourceLocation of the macro the arg was passed to and the
/// non-macro SourceLocation of the argument in the arg list to that macro.
/// These results are returned via \c MacroLoc and \c ArgLoc respectively.
/// These values are undefined if the return value is false.
///
/// \returns false if one of the returned SourceLocations would be a
/// SourceLocation pointing within the definition of another macro.
bool getMacroAndArgLocations(SourceLocation Loc, SourceLocation &ArgLoc,
SourceLocation &MacroLoc) {
assert(Loc.isMacroID() && "Only reasonble to call this on macros");
ArgLoc = Loc;
// Find the location of the immediate macro expansion.
while (1) {
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(ArgLoc);
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
ArgLoc = Expansion.getExpansionLocStart();
if (!Expansion.isMacroArgExpansion()) {
// TODO: Insert test for user-defined null macro here.
return MacroLoc.isFileID();
}
MacroLoc = SM.getImmediateExpansionRange(ArgLoc).first;
ArgLoc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
if (ArgLoc.isFileID())
return true;
// If spelling location resides in the same FileID as macro expansion
// location, it means there is no inner macro.
FileID MacroFID = SM.getFileID(MacroLoc);
if (SM.isInFileID(ArgLoc, MacroFID))
// Don't transform this case. If the characters that caused the
// null-conversion come from within a macro, they can't be changed.
return false;
}
llvm_unreachable("getMacroAndArgLocations");
}
/// \brief Tests if TestMacroLoc is found while recursively unravelling
/// expansions starting at TestLoc. TestMacroLoc.isFileID() must be true.
/// Implementation is very similar to getMacroAndArgLocations() except in this
/// case, it's not assumed that TestLoc is expanded from a macro argument.
/// While unravelling expansions macro arguments are handled as with
/// getMacroAndArgLocations() but in this function macro body expansions are
/// also handled.
///
/// False means either:
/// - TestLoc is not from a macro expansion
/// - TestLoc is from a different macro expansion
bool expandsFrom(SourceLocation TestLoc, SourceLocation TestMacroLoc) {
if (TestLoc.isFileID()) {
return false;
}
SourceLocation Loc = TestLoc, MacroLoc;
while (1) {
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
Loc = Expansion.getExpansionLocStart();
if (!Expansion.isMacroArgExpansion()) {
if (Loc.isFileID()) {
if (Loc == TestMacroLoc)
// Match made.
return true;
return false;
}
// Since Loc is still a macro ID and it's not an argument expansion, we
// don't need to do the work of handling an argument expansion. Simply
// keep recursively expanding until we hit a FileID or a macro arg
// expansion or a macro arg expansion.
continue;
}
MacroLoc = SM.getImmediateExpansionRange(Loc).first;
if (MacroLoc.isFileID() && MacroLoc == TestMacroLoc)
// Match made.
return true;
Loc = Expansion.getSpellingLoc();
Loc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
if (Loc.isFileID())
// If we made it this far without finding a match, there is no match to
// be made.
return false;
}
llvm_unreachable("expandsFrom");
}
/// \brief Given a starting point \c Start in the AST, find an ancestor that
/// doesn't expand from the macro called at file location \c MacroLoc.
///
/// \pre MacroLoc.isFileID()
/// \returns true if such an ancestor was found, false otherwise.
bool findContainingAncestor(ast_type_traits::DynTypedNode Start,
SourceLocation MacroLoc,
ast_type_traits::DynTypedNode &Result) {
// Below we're only following the first parent back up the AST. This should
// be fine since for the statements we care about there should only be one
// parent as far up as we care. If this assumption doesn't hold, need to
// revisit what to do here.
assert(MacroLoc.isFileID());
do {
ASTContext::ParentVector Parents = Context.getParents(Start);
if (Parents.empty())
return false;
assert(Parents.size() == 1 &&
"Found an ancestor with more than one parent!");
ASTContext::ParentVector::const_iterator I = Parents.begin();
SourceLocation Loc;
if (const Decl *D = I->get<Decl>())
Loc = D->getLocStart();
else if (const Stmt *S = I->get<Stmt>())
Loc = S->getLocStart();
else
llvm_unreachable("Expected to find Decl or Stmt containing ancestor");
if (!expandsFrom(Loc, MacroLoc)) {
Result = *I;
return true;
}
Start = *I;
} while (1);
llvm_unreachable("findContainingAncestor");
}
private:
tooling::Replacements &Replace;
SourceManager &SM;