[clang-tools-extra] r290489 - [clang-tidy] refactor ExprSequence out of use-after-move check
Marek Sokolowski via cfe-commits
cfe-commits at lists.llvm.org
Sat Dec 24 04:45:09 PST 2016
Author: mnbvmar
Date: Sat Dec 24 06:45:07 2016
New Revision: 290489
URL: http://llvm.org/viewvc/llvm-project?rev=290489&view=rev
Log:
[clang-tidy] refactor ExprSequence out of use-after-move check
Differential Revision: https://reviews.llvm.org/D27700
Added:
clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp
clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h
Modified:
clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt
Modified: clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp?rev=290489&r1=290488&r2=290489&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/UseAfterMoveCheck.cpp Sat Dec 24 06:45:07 2016
@@ -11,13 +11,12 @@
#include "clang/Analysis/CFG.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include <algorithm>
+#include "../utils/ExprSequence.h"
using namespace clang::ast_matchers;
+using namespace clang::tidy::utils;
+
namespace clang {
namespace tidy {
@@ -25,101 +24,6 @@ namespace misc {
namespace {
-/// Provides information about the evaluation order of (sub-)expressions within
-/// a `CFGBlock`.
-///
-/// While a `CFGBlock` does contain individual `CFGElement`s for some
-/// sub-expressions, the order in which those `CFGElement`s appear reflects
-/// only one possible order in which the sub-expressions may be evaluated.
-/// However, we want to warn if any of the potential evaluation orders can lead
-/// to a use-after-move, not just the one contained in the `CFGBlock`.
-///
-/// This class implements only a simplified version of the C++ sequencing rules
-/// that is, however, sufficient for the purposes of this check. The main
-/// limitation is that we do not distinguish between value computation and side
-/// effect -- see the "Implementation" section for more details.
-///
-/// Note: `SequenceChecker` from SemaChecking.cpp does a similar job (and much
-/// more thoroughly), but using it would require
-/// - Pulling `SequenceChecker` out into a header file (i.e. making it part of
-/// the API),
-/// - Removing the dependency of `SequenceChecker` on `Sema`, and
-/// - (Probably) modifying `SequenceChecker` to make it suitable to be used in
-/// this context.
-/// For the moment, it seems preferable to re-implement our own version of
-/// sequence checking that is special-cased to what we need here.
-///
-/// Implementation
-/// --------------
-///
-/// `ExprSequence` uses two types of sequencing edges between nodes in the AST:
-///
-/// - Every `Stmt` is assumed to be sequenced after its children. This is
-/// overly optimistic because the standard only states that value computations
-/// of operands are sequenced before the value computation of the operator,
-/// making no guarantees about side effects (in general).
-///
-/// For our purposes, this rule is sufficient, however, because this check is
-/// interested in operations on objects, which are generally performed through
-/// function calls (whether explicit and implicit). Function calls guarantee
-/// that the value computations and side effects for all function arguments
-/// are sequenced before the execution fo the function.
-///
-/// - In addition, some `Stmt`s are known to be sequenced before or after
-/// their siblings. For example, the `Stmt`s that make up a `CompoundStmt`are
-/// all sequenced relative to each other. The function
-/// `getSequenceSuccessor()` implements these sequencing rules.
-class ExprSequence {
-public:
- /// Initializes this `ExprSequence` with sequence information for the given
- /// `CFG`.
- ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
-
- /// Returns whether \p Before is sequenced before \p After.
- bool inSequence(const Stmt *Before, const Stmt *After) const;
-
- /// Returns whether \p After can potentially be evaluated after \p Before.
- /// This is exactly equivalent to `!inSequence(After, Before)` but makes some
- /// conditions read more naturally.
- bool potentiallyAfter(const Stmt *After, const Stmt *Before) const;
-
-private:
- // Returns the sibling of \p S (if any) that is directly sequenced after \p S,
- // or nullptr if no such sibling exists. For example, if \p S is the child of
- // a `CompoundStmt`, this would return the Stmt that directly follows \p S in
- // the `CompoundStmt`.
- //
- // As the sequencing of many constructs that change control flow is already
- // encoded in the `CFG`, this function only implements the sequencing rules
- // for those constructs where sequencing cannot be inferred from the `CFG`.
- const Stmt *getSequenceSuccessor(const Stmt *S) const;
-
- const Stmt *resolveSyntheticStmt(const Stmt *S) const;
-
- ASTContext *Context;
-
- llvm::DenseMap<const Stmt *, const Stmt *> SyntheticStmtSourceMap;
-};
-
-/// 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).
-class StmtToBlockMap {
-public:
- /// Initializes the map for the given `CFG`.
- StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext);
-
- /// Returns the block that \p 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).
- const CFGBlock *blockContainingStmt(const Stmt *S) const;
-
-private:
- ASTContext *Context;
-
- llvm::DenseMap<const Stmt *, const CFGBlock *> Map;
-};
-
/// Contains information about a use-after-move.
struct UseAfterMove {
// The DeclRefExpr that constituted the use of the object.
@@ -163,168 +67,6 @@ private:
} // namespace
-// 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.
-//
-// The case that a Stmt has multiple parents is rare but does actually occur in
-// the parts of the AST that we're interested in. Specifically, InitListExpr
-// nodes cause ASTContext::getParent() to return multiple parents for certain
-// nodes in their subtree because RecursiveASTVisitor visits both the syntactic
-// and semantic forms of InitListExpr, and the parent-child relationships are
-// different between the two forms.
-static SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
- ASTContext *Context) {
- SmallVector<const Stmt *, 1> Result;
-
- ASTContext::DynTypedNodeList Parents = Context->getParents(*S);
-
- SmallVector<ast_type_traits::DynTypedNode, 1> NodesToProcess(Parents.begin(),
- Parents.end());
-
- while (!NodesToProcess.empty()) {
- ast_type_traits::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;
-}
-
-bool isDescendantOrEqual(const Stmt *Descendant, const Stmt *Ancestor,
- ASTContext *Context) {
- if (Descendant == Ancestor)
- return true;
- for (const Stmt *Parent : getParentStmts(Descendant, Context)) {
- if (isDescendantOrEqual(Parent, Ancestor, Context))
- return true;
- }
-
- return false;
-}
-
-ExprSequence::ExprSequence(const CFG *TheCFG, ASTContext *TheContext)
- : Context(TheContext) {
- for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) {
- SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second;
- }
-}
-
-bool ExprSequence::inSequence(const Stmt *Before, const Stmt *After) const {
- Before = resolveSyntheticStmt(Before);
- After = resolveSyntheticStmt(After);
-
- // If 'After' is in the subtree of the siblings that follow 'Before' in the
- // chain of successors, we know that 'After' is sequenced after 'Before'.
- for (const Stmt *Successor = getSequenceSuccessor(Before); Successor;
- Successor = getSequenceSuccessor(Successor)) {
- if (isDescendantOrEqual(After, Successor, Context))
- return true;
- }
-
- // If 'After' is a parent of 'Before' or is sequenced after one of these
- // parents, we know that it is sequenced after 'Before'.
- for (const Stmt *Parent : getParentStmts(Before, Context)) {
- if (Parent == After || inSequence(Parent, After))
- return true;
- }
-
- return false;
-}
-
-bool ExprSequence::potentiallyAfter(const Stmt *After,
- const Stmt *Before) const {
- return !inSequence(After, Before);
-}
-
-const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const {
- for (const Stmt *Parent : getParentStmts(S, Context)) {
- if (const auto *BO = dyn_cast<BinaryOperator>(Parent)) {
- // Comma operator: Right-hand side is sequenced after the left-hand side.
- if (BO->getLHS() == S && BO->getOpcode() == BO_Comma)
- return BO->getRHS();
- } else if (const auto *InitList = dyn_cast<InitListExpr>(Parent)) {
- // Initializer list: Each initializer clause is sequenced after the
- // clauses that precede it.
- for (unsigned I = 1; I < InitList->getNumInits(); ++I) {
- if (InitList->getInit(I - 1) == S)
- return InitList->getInit(I);
- }
- } else if (const auto *Compound = dyn_cast<CompoundStmt>(Parent)) {
- // Compound statement: Each sub-statement is sequenced after the
- // statements that precede it.
- const Stmt *Previous = nullptr;
- for (const auto *Child : Compound->body()) {
- if (Previous == S)
- return Child;
- Previous = Child;
- }
- } else if (const auto *TheDeclStmt = dyn_cast<DeclStmt>(Parent)) {
- // Declaration: Every initializer expression is sequenced after the
- // initializer expressions that precede it.
- const Expr *PreviousInit = nullptr;
- for (const Decl *TheDecl : TheDeclStmt->decls()) {
- if (const auto *TheVarDecl = dyn_cast<VarDecl>(TheDecl)) {
- if (const Expr *Init = TheVarDecl->getInit()) {
- if (PreviousInit == S)
- return Init;
- PreviousInit = Init;
- }
- }
- }
- } else if (const auto *ForRange = dyn_cast<CXXForRangeStmt>(Parent)) {
- // Range-based for: Loop variable declaration is sequenced before the
- // body. (We need this rule because these get placed in the same
- // CFGBlock.)
- if (S == ForRange->getLoopVarStmt())
- return ForRange->getBody();
- } else if (const auto *TheIfStmt = dyn_cast<IfStmt>(Parent)) {
- // If statement: If a variable is declared inside the condition, the
- // expression used to initialize the variable is sequenced before the
- // evaluation of the condition.
- if (S == TheIfStmt->getConditionVariableDeclStmt())
- return TheIfStmt->getCond();
- }
- }
-
- return nullptr;
-}
-
-const Stmt *ExprSequence::resolveSyntheticStmt(const Stmt *S) const {
- if (SyntheticStmtSourceMap.count(S))
- return SyntheticStmtSourceMap.lookup(S);
- else
- return S;
-}
-
-StmtToBlockMap::StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext)
- : Context(TheContext) {
- for (const auto *B : *TheCFG) {
- for (const auto &Elem : *B) {
- if (Optional<CFGStmt> S = Elem.getAs<CFGStmt>())
- Map[S->getStmt()] = B;
- }
- }
-}
-
-const CFGBlock *StmtToBlockMap::blockContainingStmt(const Stmt *S) const {
- while (!Map.count(S)) {
- SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context);
- if (Parents.empty())
- return nullptr;
- S = Parents[0];
- }
-
- return Map.lookup(S);
-}
// Matches nodes that are
// - Part of a decltype argument or class template argument (we check this by
Modified: clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt?rev=290489&r1=290488&r2=290489&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt Sat Dec 24 06:45:07 2016
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyUtils
ASTUtils.cpp
DeclRefExprUtils.cpp
+ ExprSequence.cpp
FixItHintUtils.cpp
HeaderFileExtensionsUtils.cpp
HeaderGuard.cpp
Added: clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp?rev=290489&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.cpp Sat Dec 24 06:45:07 2016
@@ -0,0 +1,182 @@
+//===---------- ExprSequence.cpp - clang-tidy -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprSequence.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+// 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.
+//
+// The case that a Stmt has multiple parents is rare but does actually occur in
+// the parts of the AST that we're interested in. Specifically, InitListExpr
+// nodes cause ASTContext::getParent() to return multiple parents for certain
+// nodes in their subtree because RecursiveASTVisitor visits both the syntactic
+// and semantic forms of InitListExpr, and the parent-child relationships are
+// different between the two forms.
+static SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
+ ASTContext *Context) {
+ SmallVector<const Stmt *, 1> Result;
+
+ ASTContext::DynTypedNodeList Parents = Context->getParents(*S);
+
+ SmallVector<ast_type_traits::DynTypedNode, 1> NodesToProcess(Parents.begin(),
+ Parents.end());
+
+ while (!NodesToProcess.empty()) {
+ ast_type_traits::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;
+}
+
+namespace {
+bool isDescendantOrEqual(const Stmt *Descendant, const Stmt *Ancestor,
+ ASTContext *Context) {
+ if (Descendant == Ancestor)
+ return true;
+ for (const Stmt *Parent : getParentStmts(Descendant, Context)) {
+ if (isDescendantOrEqual(Parent, Ancestor, Context))
+ return true;
+ }
+
+ return false;
+}
+}
+
+ExprSequence::ExprSequence(const CFG *TheCFG, ASTContext *TheContext)
+ : Context(TheContext) {
+ for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) {
+ SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second;
+ }
+}
+
+bool ExprSequence::inSequence(const Stmt *Before, const Stmt *After) const {
+ Before = resolveSyntheticStmt(Before);
+ After = resolveSyntheticStmt(After);
+
+ // If 'After' is in the subtree of the siblings that follow 'Before' in the
+ // chain of successors, we know that 'After' is sequenced after 'Before'.
+ for (const Stmt *Successor = getSequenceSuccessor(Before); Successor;
+ Successor = getSequenceSuccessor(Successor)) {
+ if (isDescendantOrEqual(After, Successor, Context))
+ return true;
+ }
+
+ // If 'After' is a parent of 'Before' or is sequenced after one of these
+ // parents, we know that it is sequenced after 'Before'.
+ for (const Stmt *Parent : getParentStmts(Before, Context)) {
+ if (Parent == After || inSequence(Parent, After))
+ return true;
+ }
+
+ return false;
+}
+
+bool ExprSequence::potentiallyAfter(const Stmt *After,
+ const Stmt *Before) const {
+ return !inSequence(After, Before);
+}
+
+const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const {
+ for (const Stmt *Parent : getParentStmts(S, Context)) {
+ if (const auto *BO = dyn_cast<BinaryOperator>(Parent)) {
+ // Comma operator: Right-hand side is sequenced after the left-hand side.
+ if (BO->getLHS() == S && BO->getOpcode() == BO_Comma)
+ return BO->getRHS();
+ } else if (const auto *InitList = dyn_cast<InitListExpr>(Parent)) {
+ // Initializer list: Each initializer clause is sequenced after the
+ // clauses that precede it.
+ for (unsigned I = 1; I < InitList->getNumInits(); ++I) {
+ if (InitList->getInit(I - 1) == S)
+ return InitList->getInit(I);
+ }
+ } else if (const auto *Compound = dyn_cast<CompoundStmt>(Parent)) {
+ // Compound statement: Each sub-statement is sequenced after the
+ // statements that precede it.
+ const Stmt *Previous = nullptr;
+ for (const auto *Child : Compound->body()) {
+ if (Previous == S)
+ return Child;
+ Previous = Child;
+ }
+ } else if (const auto *TheDeclStmt = dyn_cast<DeclStmt>(Parent)) {
+ // Declaration: Every initializer expression is sequenced after the
+ // initializer expressions that precede it.
+ const Expr *PreviousInit = nullptr;
+ for (const Decl *TheDecl : TheDeclStmt->decls()) {
+ if (const auto *TheVarDecl = dyn_cast<VarDecl>(TheDecl)) {
+ if (const Expr *Init = TheVarDecl->getInit()) {
+ if (PreviousInit == S)
+ return Init;
+ PreviousInit = Init;
+ }
+ }
+ }
+ } else if (const auto *ForRange = dyn_cast<CXXForRangeStmt>(Parent)) {
+ // Range-based for: Loop variable declaration is sequenced before the
+ // body. (We need this rule because these get placed in the same
+ // CFGBlock.)
+ if (S == ForRange->getLoopVarStmt())
+ return ForRange->getBody();
+ } else if (const auto *TheIfStmt = dyn_cast<IfStmt>(Parent)) {
+ // If statement: If a variable is declared inside the condition, the
+ // expression used to initialize the variable is sequenced before the
+ // evaluation of the condition.
+ if (S == TheIfStmt->getConditionVariableDeclStmt())
+ return TheIfStmt->getCond();
+ }
+ }
+
+ return nullptr;
+}
+
+const Stmt *ExprSequence::resolveSyntheticStmt(const Stmt *S) const {
+ if (SyntheticStmtSourceMap.count(S))
+ return SyntheticStmtSourceMap.lookup(S);
+ return S;
+}
+
+StmtToBlockMap::StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext)
+ : Context(TheContext) {
+ for (const auto *B : *TheCFG) {
+ for (const auto &Elem : *B) {
+ if (Optional<CFGStmt> S = Elem.getAs<CFGStmt>())
+ Map[S->getStmt()] = B;
+ }
+ }
+}
+
+const CFGBlock *StmtToBlockMap::blockContainingStmt(const Stmt *S) const {
+ while (!Map.count(S)) {
+ SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context);
+ if (Parents.empty())
+ return nullptr;
+ S = Parents[0];
+ }
+
+ return Map.lookup(S);
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
Added: clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h?rev=290489&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h (added)
+++ clang-tools-extra/trunk/clang-tidy/utils/ExprSequence.h Sat Dec 24 06:45:07 2016
@@ -0,0 +1,124 @@
+//===------------- ExprSequence.h - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRSEQUENCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRSEQUENCE_H
+
+#include "clang/Analysis/CFG.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+/// Provides information about the evaluation order of (sub-)expressions within
+/// a `CFGBlock`.
+///
+/// While a `CFGBlock` does contain individual `CFGElement`s for some
+/// sub-expressions, the order in which those `CFGElement`s appear reflects
+/// only one possible order in which the sub-expressions may be evaluated.
+/// However, we want to warn if any of the potential evaluation orders can lead
+/// to a use-after-move, not just the one contained in the `CFGBlock`.
+///
+/// This class implements only a simplified version of the C++ sequencing
+/// rules. The main limitation is that we do not distinguish between value
+/// computation and side effect -- see the "Implementation" section for more
+/// details.
+///
+/// Note: `SequenceChecker` from SemaChecking.cpp does a similar job (and much
+/// more thoroughly), but using it would require
+/// - Pulling `SequenceChecker` out into a header file (i.e. making it part of
+/// the API),
+/// - Removing the dependency of `SequenceChecker` on `Sema`, and
+/// - (Probably) modifying `SequenceChecker` to make it suitable to be used in
+/// this context.
+/// For the moment, it seems preferable to re-implement our own version of
+/// sequence checking that is special-cased to what we need here.
+///
+/// Implementation
+/// --------------
+///
+/// `ExprSequence` uses two types of sequencing edges between nodes in the AST:
+///
+/// - Every `Stmt` is assumed to be sequenced after its children. This is
+/// overly optimistic because the standard only states that value computations
+/// of operands are sequenced before the value computation of the operator,
+/// making no guarantees about side effects (in general).
+///
+/// For our purposes, this rule is sufficient, however, because this check is
+/// interested in operations on objects, which are generally performed through
+/// function calls (whether explicit and implicit). Function calls guarantee
+/// that the value computations and side effects for all function arguments
+/// are sequenced before the execution of the function.
+///
+/// - In addition, some `Stmt`s are known to be sequenced before or after
+/// their siblings. For example, the `Stmt`s that make up a `CompoundStmt`are
+/// all sequenced relative to each other. The function
+/// `getSequenceSuccessor()` implements these sequencing rules.
+class ExprSequence {
+public:
+ /// Initializes this `ExprSequence` with sequence information for the given
+ /// `CFG`.
+ ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
+
+ /// Returns whether \p Before is sequenced before \p After.
+ bool inSequence(const Stmt *Before, const Stmt *After) const;
+
+ /// Returns whether \p After can potentially be evaluated after \p Before.
+ /// This is exactly equivalent to `!inSequence(After, Before)` but makes some
+ /// conditions read more naturally.
+ bool potentiallyAfter(const Stmt *After, const Stmt *Before) const;
+
+private:
+ // Returns the sibling of \p S (if any) that is directly sequenced after \p S,
+ // or nullptr if no such sibling exists. For example, if \p S is the child of
+ // a `CompoundStmt`, this would return the Stmt that directly follows \p S in
+ // the `CompoundStmt`.
+ //
+ // As the sequencing of many constructs that change control flow is already
+ // encoded in the `CFG`, this function only implements the sequencing rules
+ // for those constructs where sequencing cannot be inferred from the `CFG`.
+ const Stmt *getSequenceSuccessor(const Stmt *S) const;
+
+ const Stmt *resolveSyntheticStmt(const Stmt *S) const;
+
+ ASTContext *Context;
+
+ llvm::DenseMap<const Stmt *, const Stmt *> SyntheticStmtSourceMap;
+};
+
+/// 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).
+class StmtToBlockMap {
+public:
+ /// Initializes the map for the given `CFG`.
+ StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext);
+
+ /// Returns the block that \p 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).
+ const CFGBlock *blockContainingStmt(const Stmt *S) const;
+
+private:
+ ASTContext *Context;
+
+ llvm::DenseMap<const Stmt *, const CFGBlock *> Map;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRSEQUENCE_H
More information about the cfe-commits
mailing list