summaryrefslogtreecommitdiffstats
path: root/include/clang/Analysis/Visitors/CFGStmtVisitor.h
blob: f42bbde8f1489a2a14ef4aebabbd3466ec1e7155 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the CFGStmtVisitor interface, which extends 
//  StmtVisitor.  This interface is useful for visiting statements in a CFG
//  where some statements have implicit control-flow and thus should
//  be treated specially.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H

#include "clang/AST/StmtVisitor.h"
#include "clang/AST/CFG.h"

namespace clang {

#define DISPATCH_CASE(CLASS) \
case Stmt::CLASS ## Class: return \
static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));  

#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
{ return\
  static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\
  cast<Expr>(S)); }

template <typename ImplClass, typename RetTy=void>
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
  Stmt* CurrentBlkStmt;

  struct NullifyStmt {
    Stmt*& S;  
    
    NullifyStmt(Stmt*& s) : S(s) {}
    ~NullifyStmt() { S = NULL; }
  };
  
public:
  CFGStmtVisitor() : CurrentBlkStmt(NULL) {}  
  
  Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
  
  RetTy Visit(Stmt* S) {
    if (S == CurrentBlkStmt || 
        !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
      return StmtVisitor<ImplClass,RetTy>::Visit(S);
    else
      return RetTy();
  }
  
  /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in
  /// CFGBlocks.  Root statements are the statements that appear explicitly in 
  /// the list of statements in a CFGBlock.  For substatements, or when there
  /// is no implementation provided for a BlockStmt_XXX method, we default
  /// to using StmtVisitor's Visit method.
  RetTy BlockStmt_Visit(Stmt* S) {
    CurrentBlkStmt = S;
    NullifyStmt cleanup(CurrentBlkStmt);
    
    switch (S->getStmtClass()) {

      DISPATCH_CASE(StmtExpr)
      DISPATCH_CASE(ConditionalOperator)
      DISPATCH_CASE(ObjCForCollectionStmt)
        
      case Stmt::BinaryOperatorClass: {
        BinaryOperator* B = cast<BinaryOperator>(S);
        if (B->isLogicalOp())
          return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B);
        else if (B->getOpcode() == BinaryOperator::Comma)
          return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B);
        // Fall through.
      }
      
      default:
        if (isa<Expr>(S))
          return 
            static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S));
        else
          return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);                             
    }
  }

  DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
  DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
  
  RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
    return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
  }
  
  RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
    return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
  }
  
  RetTy BlockStmt_VisitExpr(Expr* E) {
    return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
  }
  
  RetTy BlockStmt_VisitStmt(Stmt* S) {
    return static_cast<ImplClass*>(this)->Visit(S);
  }

  RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) {
    return 
     static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
  }
  
  RetTy BlockStmt_VisitComma(BinaryOperator* B) {
    return
     static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
  }

  //===--------------------------------------------------------------------===//
  // Utility methods.  Not called by default (but subclasses may use them).
  //===--------------------------------------------------------------------===//
    
  /// VisitChildren: Call "Visit" on each child of S.
  void VisitChildren(Stmt* S) {
    
    switch (S->getStmtClass()) {
      default:
        break;
        
      case Stmt::StmtExprClass: {
        CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt();
        if (CS->body_empty()) return;
        static_cast<ImplClass*>(this)->Visit(CS->body_back());
        return;
      }
        
      case Stmt::BinaryOperatorClass: {
        BinaryOperator* B = cast<BinaryOperator>(S);
        if (B->getOpcode() != BinaryOperator::Comma) break;
        static_cast<ImplClass*>(this)->Visit(B->getRHS());
        return;
      }
    }
        
    for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
      if (*I) static_cast<ImplClass*>(this)->Visit(*I);    
  }
};  
      
#undef DEFAULT_BLOCKSTMT_VISIT
#undef DISPATCH_CASE

}  // end namespace clang

#endif
OpenPOWER on IntegriCloud