diff options
Diffstat (limited to 'clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp')
| -rw-r--r-- | clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp | 360 |
1 files changed, 179 insertions, 181 deletions
diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp index 5595c663aa1..ac4b8e493b2 100644 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp +++ b/clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp @@ -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; |

