forked from OSchip/llvm-project
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:
parent
7aa76b6a07
commit
1373c5cd6d
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue