Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:24

0001 //===- ThreadSafetyTraverse.h -----------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file defines a framework for doing generic traversals and rewriting
0010 // operations over the Thread Safety TIL.
0011 //
0012 // UNDER CONSTRUCTION.  USE AT YOUR OWN RISK.
0013 //
0014 //===----------------------------------------------------------------------===//
0015 
0016 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
0017 #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
0018 
0019 #include "clang/AST/Decl.h"
0020 #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
0021 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
0022 #include "clang/Basic/LLVM.h"
0023 #include "llvm/ADT/StringRef.h"
0024 #include "llvm/Support/Casting.h"
0025 #include <cstdint>
0026 #include <ostream>
0027 
0028 namespace clang {
0029 namespace threadSafety {
0030 namespace til {
0031 
0032 // Defines an interface used to traverse SExprs.  Traversals have been made as
0033 // generic as possible, and are intended to handle any kind of pass over the
0034 // AST, e.g. visitors, copying, non-destructive rewriting, destructive
0035 // (in-place) rewriting, hashing, typing, etc.
0036 //
0037 // Traversals implement the functional notion of a "fold" operation on SExprs.
0038 // Each SExpr class provides a traverse method, which does the following:
0039 //   * e->traverse(v):
0040 //       // compute a result r_i for each subexpression e_i
0041 //       for (i = 1..n)  r_i = v.traverse(e_i);
0042 //       // combine results into a result for e,  where X is the class of e
0043 //       return v.reduceX(*e, r_1, .. r_n).
0044 //
0045 // A visitor can control the traversal by overriding the following methods:
0046 //   * v.traverse(e):
0047 //       return v.traverseByCase(e), which returns v.traverseX(e)
0048 //   * v.traverseX(e):   (X is the class of e)
0049 //       return e->traverse(v).
0050 //   * v.reduceX(*e, r_1, .. r_n):
0051 //       compute a result for a node of type X
0052 //
0053 // The reduceX methods control the kind of traversal (visitor, copy, etc.).
0054 // They are defined in derived classes.
0055 //
0056 // Class R defines the basic interface types (R_SExpr).
0057 template <class Self, class R>
0058 class Traversal {
0059 public:
0060   Self *self() { return static_cast<Self *>(this); }
0061 
0062   // Traverse an expression -- returning a result of type R_SExpr.
0063   // Override this method to do something for every expression, regardless
0064   // of which kind it is.
0065   // E is a reference, so this can be use for in-place updates.
0066   // The type T must be a subclass of SExpr.
0067   template <class T>
0068   typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) {
0069     return traverseSExpr(E, Ctx);
0070   }
0071 
0072   // Override this method to do something for every expression.
0073   // Does not allow in-place updates.
0074   typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) {
0075     return traverseByCase(E, Ctx);
0076   }
0077 
0078   // Helper method to call traverseX(e) on the appropriate type.
0079   typename R::R_SExpr traverseByCase(SExpr *E, typename R::R_Ctx Ctx) {
0080     switch (E->opcode()) {
0081 #define TIL_OPCODE_DEF(X)                                                   \
0082     case COP_##X:                                                           \
0083       return self()->traverse##X(cast<X>(E), Ctx);
0084 #include "ThreadSafetyOps.def"
0085 #undef TIL_OPCODE_DEF
0086     }
0087     return self()->reduceNull();
0088   }
0089 
0090 // Traverse e, by static dispatch on the type "X" of e.
0091 // Override these methods to do something for a particular kind of term.
0092 #define TIL_OPCODE_DEF(X)                                                   \
0093   typename R::R_SExpr traverse##X(X *e, typename R::R_Ctx Ctx) {            \
0094     return e->traverse(*self(), Ctx);                                       \
0095   }
0096 #include "ThreadSafetyOps.def"
0097 #undef TIL_OPCODE_DEF
0098 };
0099 
0100 // Base class for simple reducers that don't much care about the context.
0101 class SimpleReducerBase {
0102 public:
0103   enum TraversalKind {
0104     // Ordinary subexpressions.
0105     TRV_Normal,
0106 
0107     // Declarations (e.g. function bodies).
0108     TRV_Decl,
0109 
0110     // Expressions that require lazy evaluation.
0111     TRV_Lazy,
0112 
0113     // Type expressions.
0114     TRV_Type
0115   };
0116 
0117   // R_Ctx defines a "context" for the traversal, which encodes information
0118   // about where a term appears.  This can be used to encoding the
0119   // "current continuation" for CPS transforms, or other information.
0120   using R_Ctx = TraversalKind;
0121 
0122   // Create context for an ordinary subexpression.
0123   R_Ctx subExprCtx(R_Ctx Ctx) { return TRV_Normal; }
0124 
0125   // Create context for a subexpression that occurs in a declaration position
0126   // (e.g. function body).
0127   R_Ctx declCtx(R_Ctx Ctx) { return TRV_Decl; }
0128 
0129   // Create context for a subexpression that occurs in a position that
0130   // should be reduced lazily.  (e.g. code body).
0131   R_Ctx lazyCtx(R_Ctx Ctx) { return TRV_Lazy; }
0132 
0133   // Create context for a subexpression that occurs in a type position.
0134   R_Ctx typeCtx(R_Ctx Ctx) { return TRV_Type; }
0135 };
0136 
0137 // Base class for traversals that rewrite an SExpr to another SExpr.
0138 class CopyReducerBase : public SimpleReducerBase {
0139 public:
0140   // R_SExpr is the result type for a traversal.
0141   // A copy or non-destructive rewrite returns a newly allocated term.
0142   using R_SExpr = SExpr *;
0143   using R_BasicBlock = BasicBlock *;
0144 
0145   // Container is a minimal interface used to store results when traversing
0146   // SExprs of variable arity, such as Phi, Goto, and SCFG.
0147   template <class T> class Container {
0148   public:
0149     // Allocate a new container with a capacity for n elements.
0150     Container(CopyReducerBase &S, unsigned N) : Elems(S.Arena, N) {}
0151 
0152     // Push a new element onto the container.
0153     void push_back(T E) { Elems.push_back(E); }
0154 
0155     SimpleArray<T> Elems;
0156   };
0157 
0158   CopyReducerBase(MemRegionRef A) : Arena(A) {}
0159 
0160 protected:
0161   MemRegionRef Arena;
0162 };
0163 
0164 // Base class for visit traversals.
0165 class VisitReducerBase : public SimpleReducerBase {
0166 public:
0167   // A visitor returns a bool, representing success or failure.
0168   using R_SExpr = bool;
0169   using R_BasicBlock = bool;
0170 
0171   // A visitor "container" is a single bool, which accumulates success.
0172   template <class T> class Container {
0173   public:
0174     bool Success = true;
0175 
0176     Container(VisitReducerBase &S, unsigned N) {}
0177 
0178     void push_back(bool E) { Success = Success && E; }
0179   };
0180 };
0181 
0182 // Implements a traversal that visits each subexpression, and returns either
0183 // true or false.
0184 template <class Self>
0185 class VisitReducer : public Traversal<Self, VisitReducerBase>,
0186                      public VisitReducerBase {
0187 public:
0188   VisitReducer() = default;
0189 
0190 public:
0191   R_SExpr reduceNull() { return true; }
0192   R_SExpr reduceUndefined(Undefined &Orig) { return true; }
0193   R_SExpr reduceWildcard(Wildcard &Orig) { return true; }
0194 
0195   R_SExpr reduceLiteral(Literal &Orig) { return true; }
0196   template<class T>
0197   R_SExpr reduceLiteralT(LiteralT<T> &Orig) { return true; }
0198   R_SExpr reduceLiteralPtr(Literal &Orig) { return true; }
0199 
0200   R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) {
0201     return Nvd && E0;
0202   }
0203 
0204   R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) {
0205     return Nvd && E0;
0206   }
0207 
0208   R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
0209     return E0 && E1;
0210   }
0211 
0212   R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) {
0213     return E0 && E1;
0214   }
0215 
0216   R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
0217     return E0 && E1;
0218   }
0219 
0220   R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) {
0221     return E0 && E1;
0222   }
0223 
0224   R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; }
0225   R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; }
0226   R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; }
0227   R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; }
0228   R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; }
0229 
0230   R_SExpr reduceArrayIndex(Store &Orig, R_SExpr E0, R_SExpr E1) {
0231     return E0 && E1;
0232   }
0233 
0234   R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1) {
0235     return E0 && E1;
0236   }
0237 
0238   R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; }
0239 
0240   R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) {
0241     return E0 && E1;
0242   }
0243 
0244   R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; }
0245 
0246   R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) {
0247     return Bbs.Success;
0248   }
0249 
0250   R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<R_SExpr> &As,
0251                                 Container<R_SExpr> &Is, R_SExpr T) {
0252     return (As.Success && Is.Success && T);
0253   }
0254 
0255   R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
0256     return As.Success;
0257   }
0258 
0259   R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) {
0260     return true;
0261   }
0262 
0263   R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
0264     return C;
0265   }
0266 
0267   R_SExpr reduceReturn(Return &O, R_SExpr E) {
0268     return E;
0269   }
0270 
0271   R_SExpr reduceIdentifier(Identifier &Orig) {
0272     return true;
0273   }
0274 
0275   R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) {
0276     return C && T && E;
0277   }
0278 
0279   R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) {
0280     return Nvd && B;
0281   }
0282 
0283   Variable *enterScope(Variable &Orig, R_SExpr E0) { return &Orig; }
0284   void exitScope(const Variable &Orig) {}
0285   void enterCFG(SCFG &Cfg) {}
0286   void exitCFG(SCFG &Cfg) {}
0287   void enterBasicBlock(BasicBlock &BB) {}
0288   void exitBasicBlock(BasicBlock &BB) {}
0289 
0290   Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
0291   BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; }
0292 
0293 public:
0294   bool traverse(SExpr *E, TraversalKind K = TRV_Normal) {
0295     Success = Success && this->traverseByCase(E);
0296     return Success;
0297   }
0298 
0299   static bool visit(SExpr *E) {
0300     Self Visitor;
0301     return Visitor.traverse(E, TRV_Normal);
0302   }
0303 
0304 private:
0305   bool Success;
0306 };
0307 
0308 // Basic class for comparison operations over expressions.
0309 template <typename Self>
0310 class Comparator {
0311 protected:
0312   Self *self() { return reinterpret_cast<Self *>(this); }
0313 
0314 public:
0315   bool compareByCase(const SExpr *E1, const SExpr* E2) {
0316     switch (E1->opcode()) {
0317 #define TIL_OPCODE_DEF(X)                                                     \
0318     case COP_##X:                                                             \
0319       return cast<X>(E1)->compare(cast<X>(E2), *self());
0320 #include "ThreadSafetyOps.def"
0321 #undef TIL_OPCODE_DEF
0322     }
0323     return false;
0324   }
0325 };
0326 
0327 class EqualsComparator : public Comparator<EqualsComparator> {
0328 public:
0329   // Result type for the comparison, e.g. bool for simple equality,
0330   // or int for lexigraphic comparison (-1, 0, 1).  Must have one value which
0331   // denotes "true".
0332   using CType = bool;
0333 
0334   CType trueResult() { return true; }
0335   bool notTrue(CType ct) { return !ct; }
0336 
0337   bool compareIntegers(unsigned i, unsigned j) { return i == j; }
0338   bool compareStrings (StringRef s, StringRef r) { return s == r; }
0339   bool comparePointers(const void* P, const void* Q) { return P == Q; }
0340 
0341   bool compare(const SExpr *E1, const SExpr* E2) {
0342     if (E1->opcode() != E2->opcode())
0343       return false;
0344     return compareByCase(E1, E2);
0345   }
0346 
0347   // TODO -- handle alpha-renaming of variables
0348   void enterScope(const Variable *V1, const Variable *V2) {}
0349   void leaveScope() {}
0350 
0351   bool compareVariableRefs(const Variable *V1, const Variable *V2) {
0352     return V1 == V2;
0353   }
0354 
0355   static bool compareExprs(const SExpr *E1, const SExpr* E2) {
0356     EqualsComparator Eq;
0357     return Eq.compare(E1, E2);
0358   }
0359 };
0360 
0361 class MatchComparator : public Comparator<MatchComparator> {
0362 public:
0363   // Result type for the comparison, e.g. bool for simple equality,
0364   // or int for lexigraphic comparison (-1, 0, 1).  Must have one value which
0365   // denotes "true".
0366   using CType = bool;
0367 
0368   CType trueResult() { return true; }
0369   bool notTrue(CType ct) { return !ct; }
0370 
0371   bool compareIntegers(unsigned i, unsigned j) { return i == j; }
0372   bool compareStrings (StringRef s, StringRef r) { return s == r; }
0373   bool comparePointers(const void *P, const void *Q) { return P == Q; }
0374 
0375   bool compare(const SExpr *E1, const SExpr *E2) {
0376     // Wildcards match anything.
0377     if (E1->opcode() == COP_Wildcard || E2->opcode() == COP_Wildcard)
0378       return true;
0379     // otherwise normal equality.
0380     if (E1->opcode() != E2->opcode())
0381       return false;
0382     return compareByCase(E1, E2);
0383   }
0384 
0385   // TODO -- handle alpha-renaming of variables
0386   void enterScope(const Variable* V1, const Variable* V2) {}
0387   void leaveScope() {}
0388 
0389   bool compareVariableRefs(const Variable* V1, const Variable* V2) {
0390     return V1 == V2;
0391   }
0392 
0393   static bool compareExprs(const SExpr *E1, const SExpr* E2) {
0394     MatchComparator Matcher;
0395     return Matcher.compare(E1, E2);
0396   }
0397 };
0398 
0399 // inline std::ostream& operator<<(std::ostream& SS, StringRef R) {
0400 //   return SS.write(R.data(), R.size());
0401 // }
0402 
0403 // Pretty printer for TIL expressions
0404 template <typename Self, typename StreamType>
0405 class PrettyPrinter {
0406 private:
0407   // Print out additional information.
0408   bool Verbose;
0409 
0410   // Omit redundant decls.
0411   bool Cleanup;
0412 
0413   // Print exprs in C-like syntax.
0414   bool CStyle;
0415 
0416 public:
0417   PrettyPrinter(bool V = false, bool C = true, bool CS = true)
0418       : Verbose(V), Cleanup(C), CStyle(CS) {}
0419 
0420   static void print(const SExpr *E, StreamType &SS) {
0421     Self printer;
0422     printer.printSExpr(E, SS, Prec_MAX);
0423   }
0424 
0425 protected:
0426   Self *self() { return reinterpret_cast<Self *>(this); }
0427 
0428   void newline(StreamType &SS) {
0429     SS << "\n";
0430   }
0431 
0432   // TODO: further distinguish between binary operations.
0433   static const unsigned Prec_Atom = 0;
0434   static const unsigned Prec_Postfix = 1;
0435   static const unsigned Prec_Unary = 2;
0436   static const unsigned Prec_Binary = 3;
0437   static const unsigned Prec_Other = 4;
0438   static const unsigned Prec_Decl = 5;
0439   static const unsigned Prec_MAX = 6;
0440 
0441   // Return the precedence of a given node, for use in pretty printing.
0442   unsigned precedence(const SExpr *E) {
0443     switch (E->opcode()) {
0444       case COP_Future:     return Prec_Atom;
0445       case COP_Undefined:  return Prec_Atom;
0446       case COP_Wildcard:   return Prec_Atom;
0447 
0448       case COP_Literal:    return Prec_Atom;
0449       case COP_LiteralPtr: return Prec_Atom;
0450       case COP_Variable:   return Prec_Atom;
0451       case COP_Function:   return Prec_Decl;
0452       case COP_SFunction:  return Prec_Decl;
0453       case COP_Code:       return Prec_Decl;
0454       case COP_Field:      return Prec_Decl;
0455 
0456       case COP_Apply:      return Prec_Postfix;
0457       case COP_SApply:     return Prec_Postfix;
0458       case COP_Project:    return Prec_Postfix;
0459 
0460       case COP_Call:       return Prec_Postfix;
0461       case COP_Alloc:      return Prec_Other;
0462       case COP_Load:       return Prec_Postfix;
0463       case COP_Store:      return Prec_Other;
0464       case COP_ArrayIndex: return Prec_Postfix;
0465       case COP_ArrayAdd:   return Prec_Postfix;
0466 
0467       case COP_UnaryOp:    return Prec_Unary;
0468       case COP_BinaryOp:   return Prec_Binary;
0469       case COP_Cast:       return Prec_Atom;
0470 
0471       case COP_SCFG:       return Prec_Decl;
0472       case COP_BasicBlock: return Prec_MAX;
0473       case COP_Phi:        return Prec_Atom;
0474       case COP_Goto:       return Prec_Atom;
0475       case COP_Branch:     return Prec_Atom;
0476       case COP_Return:     return Prec_Other;
0477 
0478       case COP_Identifier: return Prec_Atom;
0479       case COP_IfThenElse: return Prec_Other;
0480       case COP_Let:        return Prec_Decl;
0481     }
0482     return Prec_MAX;
0483   }
0484 
0485   void printBlockLabel(StreamType & SS, const BasicBlock *BB, int index) {
0486     if (!BB) {
0487       SS << "BB_null";
0488       return;
0489     }
0490     SS << "BB_";
0491     SS << BB->blockID();
0492     if (index >= 0) {
0493       SS << ":";
0494       SS << index;
0495     }
0496   }
0497 
0498   void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true) {
0499     if (!E) {
0500       self()->printNull(SS);
0501       return;
0502     }
0503     if (Sub && E->block() && E->opcode() != COP_Variable) {
0504       SS << "_x" << E->id();
0505       return;
0506     }
0507     if (self()->precedence(E) > P) {
0508       // Wrap expr in () if necessary.
0509       SS << "(";
0510       self()->printSExpr(E, SS, Prec_MAX);
0511       SS << ")";
0512       return;
0513     }
0514 
0515     switch (E->opcode()) {
0516 #define TIL_OPCODE_DEF(X)                                                  \
0517     case COP_##X:                                                          \
0518       self()->print##X(cast<X>(E), SS);                                    \
0519       return;
0520 #include "ThreadSafetyOps.def"
0521 #undef TIL_OPCODE_DEF
0522     }
0523   }
0524 
0525   void printNull(StreamType &SS) {
0526     SS << "#null";
0527   }
0528 
0529   void printFuture(const Future *E, StreamType &SS) {
0530     self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom);
0531   }
0532 
0533   void printUndefined(const Undefined *E, StreamType &SS) {
0534     SS << "#undefined";
0535   }
0536 
0537   void printWildcard(const Wildcard *E, StreamType &SS) {
0538     SS << "*";
0539   }
0540 
0541   template<class T>
0542   void printLiteralT(const LiteralT<T> *E, StreamType &SS) {
0543     SS << E->value();
0544   }
0545 
0546   void printLiteralT(const LiteralT<uint8_t> *E, StreamType &SS) {
0547     SS << "'" << E->value() << "'";
0548   }
0549 
0550   void printLiteral(const Literal *E, StreamType &SS) {
0551     if (E->clangExpr()) {
0552       SS << getSourceLiteralString(E->clangExpr());
0553       return;
0554     }
0555     else {
0556       ValueType VT = E->valueType();
0557       switch (VT.Base) {
0558       case ValueType::BT_Void:
0559         SS << "void";
0560         return;
0561       case ValueType::BT_Bool:
0562         if (E->as<bool>().value())
0563           SS << "true";
0564         else
0565           SS << "false";
0566         return;
0567       case ValueType::BT_Int:
0568         switch (VT.Size) {
0569         case ValueType::ST_8:
0570           if (VT.Signed)
0571             printLiteralT(&E->as<int8_t>(), SS);
0572           else
0573             printLiteralT(&E->as<uint8_t>(), SS);
0574           return;
0575         case ValueType::ST_16:
0576           if (VT.Signed)
0577             printLiteralT(&E->as<int16_t>(), SS);
0578           else
0579             printLiteralT(&E->as<uint16_t>(), SS);
0580           return;
0581         case ValueType::ST_32:
0582           if (VT.Signed)
0583             printLiteralT(&E->as<int32_t>(), SS);
0584           else
0585             printLiteralT(&E->as<uint32_t>(), SS);
0586           return;
0587         case ValueType::ST_64:
0588           if (VT.Signed)
0589             printLiteralT(&E->as<int64_t>(), SS);
0590           else
0591             printLiteralT(&E->as<uint64_t>(), SS);
0592           return;
0593         default:
0594           break;
0595         }
0596         break;
0597       case ValueType::BT_Float:
0598         switch (VT.Size) {
0599         case ValueType::ST_32:
0600           printLiteralT(&E->as<float>(), SS);
0601           return;
0602         case ValueType::ST_64:
0603           printLiteralT(&E->as<double>(), SS);
0604           return;
0605         default:
0606           break;
0607         }
0608         break;
0609       case ValueType::BT_String:
0610         SS << "\"";
0611         printLiteralT(&E->as<StringRef>(), SS);
0612         SS << "\"";
0613         return;
0614       case ValueType::BT_Pointer:
0615         SS << "#ptr";
0616         return;
0617       case ValueType::BT_ValueRef:
0618         SS << "#vref";
0619         return;
0620       }
0621     }
0622     SS << "#lit";
0623   }
0624 
0625   void printLiteralPtr(const LiteralPtr *E, StreamType &SS) {
0626     if (const NamedDecl *D = E->clangDecl())
0627       SS << D->getNameAsString();
0628     else
0629       SS << "<temporary>";
0630   }
0631 
0632   void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) {
0633     if (CStyle && V->kind() == Variable::VK_SFun)
0634       SS << "this";
0635     else
0636       SS << V->name() << V->id();
0637   }
0638 
0639   void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) {
0640     switch (sugared) {
0641       default:
0642         SS << "\\(";   // Lambda
0643         break;
0644       case 1:
0645         SS << "(";     // Slot declarations
0646         break;
0647       case 2:
0648         SS << ", ";    // Curried functions
0649         break;
0650     }
0651     self()->printVariable(E->variableDecl(), SS, true);
0652     SS << ": ";
0653     self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX);
0654 
0655     const SExpr *B = E->body();
0656     if (B && B->opcode() == COP_Function)
0657       self()->printFunction(cast<Function>(B), SS, 2);
0658     else {
0659       SS << ")";
0660       self()->printSExpr(B, SS, Prec_Decl);
0661     }
0662   }
0663 
0664   void printSFunction(const SFunction *E, StreamType &SS) {
0665     SS << "@";
0666     self()->printVariable(E->variableDecl(), SS, true);
0667     SS << " ";
0668     self()->printSExpr(E->body(), SS, Prec_Decl);
0669   }
0670 
0671   void printCode(const Code *E, StreamType &SS) {
0672     SS << ": ";
0673     self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
0674     SS << " -> ";
0675     self()->printSExpr(E->body(), SS, Prec_Decl);
0676   }
0677 
0678   void printField(const Field *E, StreamType &SS) {
0679     SS << ": ";
0680     self()->printSExpr(E->range(), SS, Prec_Decl-1);
0681     SS << " = ";
0682     self()->printSExpr(E->body(), SS, Prec_Decl);
0683   }
0684 
0685   void printApply(const Apply *E, StreamType &SS, bool sugared = false) {
0686     const SExpr *F = E->fun();
0687     if (F->opcode() == COP_Apply) {
0688       printApply(cast<Apply>(F), SS, true);
0689       SS << ", ";
0690     } else {
0691       self()->printSExpr(F, SS, Prec_Postfix);
0692       SS << "(";
0693     }
0694     self()->printSExpr(E->arg(), SS, Prec_MAX);
0695     if (!sugared)
0696       SS << ")$";
0697   }
0698 
0699   void printSApply(const SApply *E, StreamType &SS) {
0700     self()->printSExpr(E->sfun(), SS, Prec_Postfix);
0701     if (E->isDelegation()) {
0702       SS << "@(";
0703       self()->printSExpr(E->arg(), SS, Prec_MAX);
0704       SS << ")";
0705     }
0706   }
0707 
0708   void printProject(const Project *E, StreamType &SS) {
0709     if (CStyle) {
0710       // Omit the  this->
0711       if (const auto *SAP = dyn_cast<SApply>(E->record())) {
0712         if (const auto *V = dyn_cast<Variable>(SAP->sfun())) {
0713           if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) {
0714             SS << E->slotName();
0715             return;
0716           }
0717         }
0718       }
0719       if (isa<Wildcard>(E->record())) {
0720         // handle existentials
0721         SS << "&";
0722         SS << E->clangDecl()->getQualifiedNameAsString();
0723         return;
0724       }
0725     }
0726     self()->printSExpr(E->record(), SS, Prec_Postfix);
0727     if (CStyle && E->isArrow())
0728       SS << "->";
0729     else
0730       SS << ".";
0731     SS << E->slotName();
0732   }
0733 
0734   void printCall(const Call *E, StreamType &SS) {
0735     const SExpr *T = E->target();
0736     if (T->opcode() == COP_Apply) {
0737       self()->printApply(cast<Apply>(T), SS, true);
0738       SS << ")";
0739     }
0740     else {
0741       self()->printSExpr(T, SS, Prec_Postfix);
0742       SS << "()";
0743     }
0744   }
0745 
0746   void printAlloc(const Alloc *E, StreamType &SS) {
0747     SS << "new ";
0748     self()->printSExpr(E->dataType(), SS, Prec_Other-1);
0749   }
0750 
0751   void printLoad(const Load *E, StreamType &SS) {
0752     self()->printSExpr(E->pointer(), SS, Prec_Postfix);
0753     if (!CStyle)
0754       SS << "^";
0755   }
0756 
0757   void printStore(const Store *E, StreamType &SS) {
0758     self()->printSExpr(E->destination(), SS, Prec_Other-1);
0759     SS << " := ";
0760     self()->printSExpr(E->source(), SS, Prec_Other-1);
0761   }
0762 
0763   void printArrayIndex(const ArrayIndex *E, StreamType &SS) {
0764     self()->printSExpr(E->array(), SS, Prec_Postfix);
0765     SS << "[";
0766     self()->printSExpr(E->index(), SS, Prec_MAX);
0767     SS << "]";
0768   }
0769 
0770   void printArrayAdd(const ArrayAdd *E, StreamType &SS) {
0771     self()->printSExpr(E->array(), SS, Prec_Postfix);
0772     SS << " + ";
0773     self()->printSExpr(E->index(), SS, Prec_Atom);
0774   }
0775 
0776   void printUnaryOp(const UnaryOp *E, StreamType &SS) {
0777     SS << getUnaryOpcodeString(E->unaryOpcode());
0778     self()->printSExpr(E->expr(), SS, Prec_Unary);
0779   }
0780 
0781   void printBinaryOp(const BinaryOp *E, StreamType &SS) {
0782     self()->printSExpr(E->expr0(), SS, Prec_Binary-1);
0783     SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " ";
0784     self()->printSExpr(E->expr1(), SS, Prec_Binary-1);
0785   }
0786 
0787   void printCast(const Cast *E, StreamType &SS) {
0788     if (!CStyle) {
0789       SS << "cast[";
0790       switch (E->castOpcode()) {
0791       case CAST_none:
0792         SS << "none";
0793         break;
0794       case CAST_extendNum:
0795         SS << "extendNum";
0796         break;
0797       case CAST_truncNum:
0798         SS << "truncNum";
0799         break;
0800       case CAST_toFloat:
0801         SS << "toFloat";
0802         break;
0803       case CAST_toInt:
0804         SS << "toInt";
0805         break;
0806       case CAST_objToPtr:
0807         SS << "objToPtr";
0808         break;
0809       }
0810       SS << "](";
0811       self()->printSExpr(E->expr(), SS, Prec_Unary);
0812       SS << ")";
0813       return;
0814     }
0815     self()->printSExpr(E->expr(), SS, Prec_Unary);
0816   }
0817 
0818   void printSCFG(const SCFG *E, StreamType &SS) {
0819     SS << "CFG {\n";
0820     for (const auto *BBI : *E)
0821       printBasicBlock(BBI, SS);
0822     SS << "}";
0823     newline(SS);
0824   }
0825 
0826   void printBBInstr(const SExpr *E, StreamType &SS) {
0827     bool Sub = false;
0828     if (E->opcode() == COP_Variable) {
0829       const auto *V = cast<Variable>(E);
0830       SS << "let " << V->name() << V->id() << " = ";
0831       E = V->definition();
0832       Sub = true;
0833     }
0834     else if (E->opcode() != COP_Store) {
0835       SS << "let _x" << E->id() << " = ";
0836     }
0837     self()->printSExpr(E, SS, Prec_MAX, Sub);
0838     SS << ";";
0839     newline(SS);
0840   }
0841 
0842   void printBasicBlock(const BasicBlock *E, StreamType &SS) {
0843     SS << "BB_" << E->blockID() << ":";
0844     if (E->parent())
0845       SS << " BB_" << E->parent()->blockID();
0846     newline(SS);
0847 
0848     for (const auto *A : E->arguments())
0849       printBBInstr(A, SS);
0850 
0851     for (const auto *I : E->instructions())
0852       printBBInstr(I, SS);
0853 
0854     const SExpr *T = E->terminator();
0855     if (T) {
0856       self()->printSExpr(T, SS, Prec_MAX, false);
0857       SS << ";";
0858       newline(SS);
0859     }
0860     newline(SS);
0861   }
0862 
0863   void printPhi(const Phi *E, StreamType &SS) {
0864     SS << "phi(";
0865     if (E->status() == Phi::PH_SingleVal)
0866       self()->printSExpr(E->values()[0], SS, Prec_MAX);
0867     else {
0868       unsigned i = 0;
0869       for (const auto *V : E->values()) {
0870         if (i++ > 0)
0871           SS << ", ";
0872         self()->printSExpr(V, SS, Prec_MAX);
0873       }
0874     }
0875     SS << ")";
0876   }
0877 
0878   void printGoto(const Goto *E, StreamType &SS) {
0879     SS << "goto ";
0880     printBlockLabel(SS, E->targetBlock(), E->index());
0881   }
0882 
0883   void printBranch(const Branch *E, StreamType &SS) {
0884     SS << "branch (";
0885     self()->printSExpr(E->condition(), SS, Prec_MAX);
0886     SS << ") ";
0887     printBlockLabel(SS, E->thenBlock(), -1);
0888     SS << " ";
0889     printBlockLabel(SS, E->elseBlock(), -1);
0890   }
0891 
0892   void printReturn(const Return *E, StreamType &SS) {
0893     SS << "return ";
0894     self()->printSExpr(E->returnValue(), SS, Prec_Other);
0895   }
0896 
0897   void printIdentifier(const Identifier *E, StreamType &SS) {
0898     SS << E->name();
0899   }
0900 
0901   void printIfThenElse(const IfThenElse *E, StreamType &SS) {
0902     if (CStyle) {
0903       printSExpr(E->condition(), SS, Prec_Unary);
0904       SS << " ? ";
0905       printSExpr(E->thenExpr(), SS, Prec_Unary);
0906       SS << " : ";
0907       printSExpr(E->elseExpr(), SS, Prec_Unary);
0908       return;
0909     }
0910     SS << "if (";
0911     printSExpr(E->condition(), SS, Prec_MAX);
0912     SS << ") then ";
0913     printSExpr(E->thenExpr(), SS, Prec_Other);
0914     SS << " else ";
0915     printSExpr(E->elseExpr(), SS, Prec_Other);
0916   }
0917 
0918   void printLet(const Let *E, StreamType &SS) {
0919     SS << "let ";
0920     printVariable(E->variableDecl(), SS, true);
0921     SS << " = ";
0922     printSExpr(E->variableDecl()->definition(), SS, Prec_Decl-1);
0923     SS << "; ";
0924     printSExpr(E->body(), SS, Prec_Decl-1);
0925   }
0926 };
0927 
0928 class StdPrinter : public PrettyPrinter<StdPrinter, std::ostream> {};
0929 
0930 } // namespace til
0931 } // namespace threadSafety
0932 } // namespace clang
0933 
0934 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H