diff options
Diffstat (limited to '')
-rw-r--r-- | build/clang-plugin/StmtToBlockMap.h | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/build/clang-plugin/StmtToBlockMap.h b/build/clang-plugin/StmtToBlockMap.h new file mode 100644 index 0000000000..09b0cac415 --- /dev/null +++ b/build/clang-plugin/StmtToBlockMap.h @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef StmtToBlockMap_h__ +#define StmtToBlockMap_h__ + +#include "Utils.h" + +// This method is copied from clang-tidy's ExprSequence.cpp. +// +// Returns the Stmt nodes that are parents of 'S', skipping any potential +// intermediate non-Stmt nodes. +// +// In almost all cases, this function returns a single parent or no parents at +// all. +inline SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S, + ASTContext *Context) { + SmallVector<const Stmt *, 1> Result; + + auto Parents = Context->getParents(*S); + + SmallVector<clang::DynTypedNode, 1> NodesToProcess(Parents.begin(), + Parents.end()); + + while (!NodesToProcess.empty()) { + clang::DynTypedNode Node = NodesToProcess.back(); + NodesToProcess.pop_back(); + + if (const auto *S = Node.get<Stmt>()) { + Result.push_back(S); + } else { + Parents = Context->getParents(Node); + NodesToProcess.append(Parents.begin(), Parents.end()); + } + } + + return Result; +} + +// This class is a modified version of the class from clang-tidy's +// ExprSequence.cpp +// +// Maps `Stmt`s to the `CFGBlock` that contains them. Some `Stmt`s may be +// contained in more than one `CFGBlock`; in this case, they are mapped to the +// innermost block (i.e. the one that is furthest from the root of the tree). +// An optional outparameter provides the index into the block where the `Stmt` +// was found. +class StmtToBlockMap { +public: + // Initializes the map for the given `CFG`. + StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext) + : Context(TheContext) { + for (const auto *B : *TheCFG) { + for (size_t I = 0; I < B->size(); ++I) { + if (auto S = (*B)[I].getAs<CFGStmt>()) { + Map[S->getStmt()] = std::make_pair(B, I); + } + } + } + } + + // Returns the block that S is contained in. Some `Stmt`s may be contained + // in more than one `CFGBlock`; in this case, this function returns the + // innermost block (i.e. the one that is furthest from the root of the tree). + // + // The optional outparameter `Index` is set to the index into the block where + // the `Stmt` was found. + const CFGBlock *blockContainingStmt(const Stmt *S, + size_t *Index = nullptr) const { + while (!Map.count(S)) { + SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context); + if (Parents.empty()) + return nullptr; + S = Parents[0]; + } + + const auto &E = Map.lookup(S); + if (Index) + *Index = E.second; + return E.first; + } + +private: + ASTContext *Context; + + llvm::DenseMap<const Stmt *, std::pair<const CFGBlock *, size_t>> Map; +}; + +#endif // StmtToBlockMap_h__ |