xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1 //===- ThreadSafetyTraverse.h -----------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a framework for doing generic traversals and rewriting
10 // operations over the Thread Safety TIL.
11 //
12 // UNDER CONSTRUCTION.  USE AT YOUR OWN RISK.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
17 #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
18 
19 #include "clang/AST/Decl.h"
20 #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
21 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
22 #include "clang/Basic/LLVM.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Support/Casting.h"
25 #include <cstdint>
26 #include <ostream>
27 
28 namespace clang {
29 namespace threadSafety {
30 namespace til {
31 
32 // Defines an interface used to traverse SExprs.  Traversals have been made as
33 // generic as possible, and are intended to handle any kind of pass over the
34 // AST, e.g. visitors, copying, non-destructive rewriting, destructive
35 // (in-place) rewriting, hashing, typing, etc.
36 //
37 // Traversals implement the functional notion of a "fold" operation on SExprs.
38 // Each SExpr class provides a traverse method, which does the following:
39 //   * e->traverse(v):
40 //       // compute a result r_i for each subexpression e_i
41 //       for (i = 1..n)  r_i = v.traverse(e_i);
42 //       // combine results into a result for e,  where X is the class of e
43 //       return v.reduceX(*e, r_1, .. r_n).
44 //
45 // A visitor can control the traversal by overriding the following methods:
46 //   * v.traverse(e):
47 //       return v.traverseByCase(e), which returns v.traverseX(e)
48 //   * v.traverseX(e):   (X is the class of e)
49 //       return e->traverse(v).
50 //   * v.reduceX(*e, r_1, .. r_n):
51 //       compute a result for a node of type X
52 //
53 // The reduceX methods control the kind of traversal (visitor, copy, etc.).
54 // They are defined in derived classes.
55 //
56 // Class R defines the basic interface types (R_SExpr).
57 template <class Self, class R>
58 class Traversal {
59 public:
self()60   Self *self() { return static_cast<Self *>(this); }
61 
62   // Traverse an expression -- returning a result of type R_SExpr.
63   // Override this method to do something for every expression, regardless
64   // of which kind it is.
65   // E is a reference, so this can be use for in-place updates.
66   // The type T must be a subclass of SExpr.
67   template <class T>
traverse(T * & E,typename R::R_Ctx Ctx)68   typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) {
69     return traverseSExpr(E, Ctx);
70   }
71 
72   // Override this method to do something for every expression.
73   // Does not allow in-place updates.
traverseSExpr(SExpr * E,typename R::R_Ctx Ctx)74   typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) {
75     return traverseByCase(E, Ctx);
76   }
77 
78   // Helper method to call traverseX(e) on the appropriate type.
traverseByCase(SExpr * E,typename R::R_Ctx Ctx)79   typename R::R_SExpr traverseByCase(SExpr *E, typename R::R_Ctx Ctx) {
80     switch (E->opcode()) {
81 #define TIL_OPCODE_DEF(X)                                                   \
82     case COP_##X:                                                           \
83       return self()->traverse##X(cast<X>(E), Ctx);
84 #include "ThreadSafetyOps.def"
85 #undef TIL_OPCODE_DEF
86     }
87     return self()->reduceNull();
88   }
89 
90 // Traverse e, by static dispatch on the type "X" of e.
91 // Override these methods to do something for a particular kind of term.
92 #define TIL_OPCODE_DEF(X)                                                   \
93   typename R::R_SExpr traverse##X(X *e, typename R::R_Ctx Ctx) {            \
94     return e->traverse(*self(), Ctx);                                       \
95   }
96 #include "ThreadSafetyOps.def"
97 #undef TIL_OPCODE_DEF
98 };
99 
100 // Base class for simple reducers that don't much care about the context.
101 class SimpleReducerBase {
102 public:
103   enum TraversalKind {
104     // Ordinary subexpressions.
105     TRV_Normal,
106 
107     // Declarations (e.g. function bodies).
108     TRV_Decl,
109 
110     // Expressions that require lazy evaluation.
111     TRV_Lazy,
112 
113     // Type expressions.
114     TRV_Type
115   };
116 
117   // R_Ctx defines a "context" for the traversal, which encodes information
118   // about where a term appears.  This can be used to encoding the
119   // "current continuation" for CPS transforms, or other information.
120   using R_Ctx = TraversalKind;
121 
122   // Create context for an ordinary subexpression.
subExprCtx(R_Ctx Ctx)123   R_Ctx subExprCtx(R_Ctx Ctx) { return TRV_Normal; }
124 
125   // Create context for a subexpression that occurs in a declaration position
126   // (e.g. function body).
declCtx(R_Ctx Ctx)127   R_Ctx declCtx(R_Ctx Ctx) { return TRV_Decl; }
128 
129   // Create context for a subexpression that occurs in a position that
130   // should be reduced lazily.  (e.g. code body).
lazyCtx(R_Ctx Ctx)131   R_Ctx lazyCtx(R_Ctx Ctx) { return TRV_Lazy; }
132 
133   // Create context for a subexpression that occurs in a type position.
typeCtx(R_Ctx Ctx)134   R_Ctx typeCtx(R_Ctx Ctx) { return TRV_Type; }
135 };
136 
137 // Base class for traversals that rewrite an SExpr to another SExpr.
138 class CopyReducerBase : public SimpleReducerBase {
139 public:
140   // R_SExpr is the result type for a traversal.
141   // A copy or non-destructive rewrite returns a newly allocated term.
142   using R_SExpr = SExpr *;
143   using R_BasicBlock = BasicBlock *;
144 
145   // Container is a minimal interface used to store results when traversing
146   // SExprs of variable arity, such as Phi, Goto, and SCFG.
147   template <class T> class Container {
148   public:
149     // Allocate a new container with a capacity for n elements.
Container(CopyReducerBase & S,unsigned N)150     Container(CopyReducerBase &S, unsigned N) : Elems(S.Arena, N) {}
151 
152     // Push a new element onto the container.
push_back(T E)153     void push_back(T E) { Elems.push_back(E); }
154 
155     SimpleArray<T> Elems;
156   };
157 
CopyReducerBase(MemRegionRef A)158   CopyReducerBase(MemRegionRef A) : Arena(A) {}
159 
160 protected:
161   MemRegionRef Arena;
162 };
163 
164 // Base class for visit traversals.
165 class VisitReducerBase : public SimpleReducerBase {
166 public:
167   // A visitor returns a bool, representing success or failure.
168   using R_SExpr = bool;
169   using R_BasicBlock = bool;
170 
171   // A visitor "container" is a single bool, which accumulates success.
172   template <class T> class Container {
173   public:
174     bool Success = true;
175 
Container(VisitReducerBase & S,unsigned N)176     Container(VisitReducerBase &S, unsigned N) {}
177 
push_back(bool E)178     void push_back(bool E) { Success = Success && E; }
179   };
180 };
181 
182 // Implements a traversal that visits each subexpression, and returns either
183 // true or false.
184 template <class Self>
185 class VisitReducer : public Traversal<Self, VisitReducerBase>,
186                      public VisitReducerBase {
187 public:
188   VisitReducer() = default;
189 
190 public:
reduceNull()191   R_SExpr reduceNull() { return true; }
reduceUndefined(Undefined & Orig)192   R_SExpr reduceUndefined(Undefined &Orig) { return true; }
reduceWildcard(Wildcard & Orig)193   R_SExpr reduceWildcard(Wildcard &Orig) { return true; }
194 
reduceLiteral(Literal & Orig)195   R_SExpr reduceLiteral(Literal &Orig) { return true; }
196   template<class T>
reduceLiteralT(LiteralT<T> & Orig)197   R_SExpr reduceLiteralT(LiteralT<T> &Orig) { return true; }
reduceLiteralPtr(Literal & Orig)198   R_SExpr reduceLiteralPtr(Literal &Orig) { return true; }
199 
reduceFunction(Function & Orig,Variable * Nvd,R_SExpr E0)200   R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) {
201     return Nvd && E0;
202   }
203 
reduceSFunction(SFunction & Orig,Variable * Nvd,R_SExpr E0)204   R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) {
205     return Nvd && E0;
206   }
207 
reduceCode(Code & Orig,R_SExpr E0,R_SExpr E1)208   R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
209     return E0 && E1;
210   }
211 
reduceField(Field & Orig,R_SExpr E0,R_SExpr E1)212   R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) {
213     return E0 && E1;
214   }
215 
reduceApply(Apply & Orig,R_SExpr E0,R_SExpr E1)216   R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
217     return E0 && E1;
218   }
219 
reduceSApply(SApply & Orig,R_SExpr E0,R_SExpr E1)220   R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) {
221     return E0 && E1;
222   }
223 
reduceProject(Project & Orig,R_SExpr E0)224   R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; }
reduceCall(Call & Orig,R_SExpr E0)225   R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; }
reduceAlloc(Alloc & Orig,R_SExpr E0)226   R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; }
reduceLoad(Load & Orig,R_SExpr E0)227   R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; }
reduceStore(Store & Orig,R_SExpr E0,R_SExpr E1)228   R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; }
229 
reduceArrayIndex(Store & Orig,R_SExpr E0,R_SExpr E1)230   R_SExpr reduceArrayIndex(Store &Orig, R_SExpr E0, R_SExpr E1) {
231     return E0 && E1;
232   }
233 
reduceArrayAdd(Store & Orig,R_SExpr E0,R_SExpr E1)234   R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1) {
235     return E0 && E1;
236   }
237 
reduceUnaryOp(UnaryOp & Orig,R_SExpr E0)238   R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; }
239 
reduceBinaryOp(BinaryOp & Orig,R_SExpr E0,R_SExpr E1)240   R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) {
241     return E0 && E1;
242   }
243 
reduceCast(Cast & Orig,R_SExpr E0)244   R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; }
245 
reduceSCFG(SCFG & Orig,Container<BasicBlock * > Bbs)246   R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) {
247     return Bbs.Success;
248   }
249 
reduceBasicBlock(BasicBlock & Orig,Container<R_SExpr> & As,Container<R_SExpr> & Is,R_SExpr T)250   R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<R_SExpr> &As,
251                                 Container<R_SExpr> &Is, R_SExpr T) {
252     return (As.Success && Is.Success && T);
253   }
254 
reducePhi(Phi & Orig,Container<R_SExpr> & As)255   R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
256     return As.Success;
257   }
258 
reduceGoto(Goto & Orig,BasicBlock * B)259   R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) {
260     return true;
261   }
262 
reduceBranch(Branch & O,R_SExpr C,BasicBlock * B0,BasicBlock * B1)263   R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
264     return C;
265   }
266 
reduceReturn(Return & O,R_SExpr E)267   R_SExpr reduceReturn(Return &O, R_SExpr E) {
268     return E;
269   }
270 
reduceIdentifier(Identifier & Orig)271   R_SExpr reduceIdentifier(Identifier &Orig) {
272     return true;
273   }
274 
reduceIfThenElse(IfThenElse & Orig,R_SExpr C,R_SExpr T,R_SExpr E)275   R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) {
276     return C && T && E;
277   }
278 
reduceLet(Let & Orig,Variable * Nvd,R_SExpr B)279   R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) {
280     return Nvd && B;
281   }
282 
enterScope(Variable & Orig,R_SExpr E0)283   Variable *enterScope(Variable &Orig, R_SExpr E0) { return &Orig; }
exitScope(const Variable & Orig)284   void exitScope(const Variable &Orig) {}
enterCFG(SCFG & Cfg)285   void enterCFG(SCFG &Cfg) {}
exitCFG(SCFG & Cfg)286   void exitCFG(SCFG &Cfg) {}
enterBasicBlock(BasicBlock & BB)287   void enterBasicBlock(BasicBlock &BB) {}
exitBasicBlock(BasicBlock & BB)288   void exitBasicBlock(BasicBlock &BB) {}
289 
reduceVariableRef(Variable * Ovd)290   Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
reduceBasicBlockRef(BasicBlock * Obb)291   BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; }
292 
293 public:
294   bool traverse(SExpr *E, TraversalKind K = TRV_Normal) {
295     Success = Success && this->traverseByCase(E);
296     return Success;
297   }
298 
visit(SExpr * E)299   static bool visit(SExpr *E) {
300     Self Visitor;
301     return Visitor.traverse(E, TRV_Normal);
302   }
303 
304 private:
305   bool Success;
306 };
307 
308 // Basic class for comparison operations over expressions.
309 template <typename Self>
310 class Comparator {
311 protected:
self()312   Self *self() { return reinterpret_cast<Self *>(this); }
313 
314 public:
compareByCase(const SExpr * E1,const SExpr * E2)315   bool compareByCase(const SExpr *E1, const SExpr* E2) {
316     switch (E1->opcode()) {
317 #define TIL_OPCODE_DEF(X)                                                     \
318     case COP_##X:                                                             \
319       return cast<X>(E1)->compare(cast<X>(E2), *self());
320 #include "ThreadSafetyOps.def"
321 #undef TIL_OPCODE_DEF
322     }
323     return false;
324   }
325 };
326 
327 class EqualsComparator : public Comparator<EqualsComparator> {
328 public:
329   // Result type for the comparison, e.g. bool for simple equality,
330   // or int for lexigraphic comparison (-1, 0, 1).  Must have one value which
331   // denotes "true".
332   using CType = bool;
333 
trueResult()334   CType trueResult() { return true; }
notTrue(CType ct)335   bool notTrue(CType ct) { return !ct; }
336 
compareIntegers(unsigned i,unsigned j)337   bool compareIntegers(unsigned i, unsigned j) { return i == j; }
compareStrings(StringRef s,StringRef r)338   bool compareStrings (StringRef s, StringRef r) { return s == r; }
comparePointers(const void * P,const void * Q)339   bool comparePointers(const void* P, const void* Q) { return P == Q; }
340 
compare(const SExpr * E1,const SExpr * E2)341   bool compare(const SExpr *E1, const SExpr* E2) {
342     if (E1->opcode() != E2->opcode())
343       return false;
344     return compareByCase(E1, E2);
345   }
346 
347   // TODO -- handle alpha-renaming of variables
enterScope(const Variable * V1,const Variable * V2)348   void enterScope(const Variable *V1, const Variable *V2) {}
leaveScope()349   void leaveScope() {}
350 
compareVariableRefs(const Variable * V1,const Variable * V2)351   bool compareVariableRefs(const Variable *V1, const Variable *V2) {
352     return V1 == V2;
353   }
354 
compareExprs(const SExpr * E1,const SExpr * E2)355   static bool compareExprs(const SExpr *E1, const SExpr* E2) {
356     EqualsComparator Eq;
357     return Eq.compare(E1, E2);
358   }
359 };
360 
361 class MatchComparator : public Comparator<MatchComparator> {
362 public:
363   // Result type for the comparison, e.g. bool for simple equality,
364   // or int for lexigraphic comparison (-1, 0, 1).  Must have one value which
365   // denotes "true".
366   using CType = bool;
367 
trueResult()368   CType trueResult() { return true; }
notTrue(CType ct)369   bool notTrue(CType ct) { return !ct; }
370 
compareIntegers(unsigned i,unsigned j)371   bool compareIntegers(unsigned i, unsigned j) { return i == j; }
compareStrings(StringRef s,StringRef r)372   bool compareStrings (StringRef s, StringRef r) { return s == r; }
comparePointers(const void * P,const void * Q)373   bool comparePointers(const void *P, const void *Q) { return P == Q; }
374 
compare(const SExpr * E1,const SExpr * E2)375   bool compare(const SExpr *E1, const SExpr *E2) {
376     // Wildcards match anything.
377     if (E1->opcode() == COP_Wildcard || E2->opcode() == COP_Wildcard)
378       return true;
379     // otherwise normal equality.
380     if (E1->opcode() != E2->opcode())
381       return false;
382     return compareByCase(E1, E2);
383   }
384 
385   // TODO -- handle alpha-renaming of variables
enterScope(const Variable * V1,const Variable * V2)386   void enterScope(const Variable* V1, const Variable* V2) {}
leaveScope()387   void leaveScope() {}
388 
compareVariableRefs(const Variable * V1,const Variable * V2)389   bool compareVariableRefs(const Variable* V1, const Variable* V2) {
390     return V1 == V2;
391   }
392 
compareExprs(const SExpr * E1,const SExpr * E2)393   static bool compareExprs(const SExpr *E1, const SExpr* E2) {
394     MatchComparator Matcher;
395     return Matcher.compare(E1, E2);
396   }
397 };
398 
399 // inline std::ostream& operator<<(std::ostream& SS, StringRef R) {
400 //   return SS.write(R.data(), R.size());
401 // }
402 
403 // Pretty printer for TIL expressions
404 template <typename Self, typename StreamType>
405 class PrettyPrinter {
406 private:
407   // Print out additional information.
408   bool Verbose;
409 
410   // Omit redundant decls.
411   bool Cleanup;
412 
413   // Print exprs in C-like syntax.
414   bool CStyle;
415 
416 public:
417   PrettyPrinter(bool V = false, bool C = true, bool CS = true)
Verbose(V)418       : Verbose(V), Cleanup(C), CStyle(CS) {}
419 
print(const SExpr * E,StreamType & SS)420   static void print(const SExpr *E, StreamType &SS) {
421     Self printer;
422     printer.printSExpr(E, SS, Prec_MAX);
423   }
424 
425 protected:
self()426   Self *self() { return reinterpret_cast<Self *>(this); }
427 
newline(StreamType & SS)428   void newline(StreamType &SS) {
429     SS << "\n";
430   }
431 
432   // TODO: further distinguish between binary operations.
433   static const unsigned Prec_Atom = 0;
434   static const unsigned Prec_Postfix = 1;
435   static const unsigned Prec_Unary = 2;
436   static const unsigned Prec_Binary = 3;
437   static const unsigned Prec_Other = 4;
438   static const unsigned Prec_Decl = 5;
439   static const unsigned Prec_MAX = 6;
440 
441   // Return the precedence of a given node, for use in pretty printing.
precedence(const SExpr * E)442   unsigned precedence(const SExpr *E) {
443     switch (E->opcode()) {
444       case COP_Future:     return Prec_Atom;
445       case COP_Undefined:  return Prec_Atom;
446       case COP_Wildcard:   return Prec_Atom;
447 
448       case COP_Literal:    return Prec_Atom;
449       case COP_LiteralPtr: return Prec_Atom;
450       case COP_Variable:   return Prec_Atom;
451       case COP_Function:   return Prec_Decl;
452       case COP_SFunction:  return Prec_Decl;
453       case COP_Code:       return Prec_Decl;
454       case COP_Field:      return Prec_Decl;
455 
456       case COP_Apply:      return Prec_Postfix;
457       case COP_SApply:     return Prec_Postfix;
458       case COP_Project:    return Prec_Postfix;
459 
460       case COP_Call:       return Prec_Postfix;
461       case COP_Alloc:      return Prec_Other;
462       case COP_Load:       return Prec_Postfix;
463       case COP_Store:      return Prec_Other;
464       case COP_ArrayIndex: return Prec_Postfix;
465       case COP_ArrayAdd:   return Prec_Postfix;
466 
467       case COP_UnaryOp:    return Prec_Unary;
468       case COP_BinaryOp:   return Prec_Binary;
469       case COP_Cast:       return Prec_Atom;
470 
471       case COP_SCFG:       return Prec_Decl;
472       case COP_BasicBlock: return Prec_MAX;
473       case COP_Phi:        return Prec_Atom;
474       case COP_Goto:       return Prec_Atom;
475       case COP_Branch:     return Prec_Atom;
476       case COP_Return:     return Prec_Other;
477 
478       case COP_Identifier: return Prec_Atom;
479       case COP_IfThenElse: return Prec_Other;
480       case COP_Let:        return Prec_Decl;
481     }
482     return Prec_MAX;
483   }
484 
printBlockLabel(StreamType & SS,const BasicBlock * BB,int index)485   void printBlockLabel(StreamType & SS, const BasicBlock *BB, int index) {
486     if (!BB) {
487       SS << "BB_null";
488       return;
489     }
490     SS << "BB_";
491     SS << BB->blockID();
492     if (index >= 0) {
493       SS << ":";
494       SS << index;
495     }
496   }
497 
498   void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true) {
499     if (!E) {
500       self()->printNull(SS);
501       return;
502     }
503     if (Sub && E->block() && E->opcode() != COP_Variable) {
504       SS << "_x" << E->id();
505       return;
506     }
507     if (self()->precedence(E) > P) {
508       // Wrap expr in () if necessary.
509       SS << "(";
510       self()->printSExpr(E, SS, Prec_MAX);
511       SS << ")";
512       return;
513     }
514 
515     switch (E->opcode()) {
516 #define TIL_OPCODE_DEF(X)                                                  \
517     case COP_##X:                                                          \
518       self()->print##X(cast<X>(E), SS);                                    \
519       return;
520 #include "ThreadSafetyOps.def"
521 #undef TIL_OPCODE_DEF
522     }
523   }
524 
printNull(StreamType & SS)525   void printNull(StreamType &SS) {
526     SS << "#null";
527   }
528 
printFuture(const Future * E,StreamType & SS)529   void printFuture(const Future *E, StreamType &SS) {
530     self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom);
531   }
532 
printUndefined(const Undefined * E,StreamType & SS)533   void printUndefined(const Undefined *E, StreamType &SS) {
534     SS << "#undefined";
535   }
536 
printWildcard(const Wildcard * E,StreamType & SS)537   void printWildcard(const Wildcard *E, StreamType &SS) {
538     SS << "*";
539   }
540 
541   template<class T>
printLiteralT(const LiteralT<T> * E,StreamType & SS)542   void printLiteralT(const LiteralT<T> *E, StreamType &SS) {
543     SS << E->value();
544   }
545 
printLiteralT(const LiteralT<uint8_t> * E,StreamType & SS)546   void printLiteralT(const LiteralT<uint8_t> *E, StreamType &SS) {
547     SS << "'" << E->value() << "'";
548   }
549 
printLiteral(const Literal * E,StreamType & SS)550   void printLiteral(const Literal *E, StreamType &SS) {
551     if (E->clangExpr()) {
552       SS << getSourceLiteralString(E->clangExpr());
553       return;
554     }
555     else {
556       ValueType VT = E->valueType();
557       switch (VT.Base) {
558       case ValueType::BT_Void:
559         SS << "void";
560         return;
561       case ValueType::BT_Bool:
562         if (E->as<bool>().value())
563           SS << "true";
564         else
565           SS << "false";
566         return;
567       case ValueType::BT_Int:
568         switch (VT.Size) {
569         case ValueType::ST_8:
570           if (VT.Signed)
571             printLiteralT(&E->as<int8_t>(), SS);
572           else
573             printLiteralT(&E->as<uint8_t>(), SS);
574           return;
575         case ValueType::ST_16:
576           if (VT.Signed)
577             printLiteralT(&E->as<int16_t>(), SS);
578           else
579             printLiteralT(&E->as<uint16_t>(), SS);
580           return;
581         case ValueType::ST_32:
582           if (VT.Signed)
583             printLiteralT(&E->as<int32_t>(), SS);
584           else
585             printLiteralT(&E->as<uint32_t>(), SS);
586           return;
587         case ValueType::ST_64:
588           if (VT.Signed)
589             printLiteralT(&E->as<int64_t>(), SS);
590           else
591             printLiteralT(&E->as<uint64_t>(), SS);
592           return;
593         default:
594           break;
595         }
596         break;
597       case ValueType::BT_Float:
598         switch (VT.Size) {
599         case ValueType::ST_32:
600           printLiteralT(&E->as<float>(), SS);
601           return;
602         case ValueType::ST_64:
603           printLiteralT(&E->as<double>(), SS);
604           return;
605         default:
606           break;
607         }
608         break;
609       case ValueType::BT_String:
610         SS << "\"";
611         printLiteralT(&E->as<StringRef>(), SS);
612         SS << "\"";
613         return;
614       case ValueType::BT_Pointer:
615         SS << "#ptr";
616         return;
617       case ValueType::BT_ValueRef:
618         SS << "#vref";
619         return;
620       }
621     }
622     SS << "#lit";
623   }
624 
printLiteralPtr(const LiteralPtr * E,StreamType & SS)625   void printLiteralPtr(const LiteralPtr *E, StreamType &SS) {
626     if (const NamedDecl *D = E->clangDecl())
627       SS << D->getNameAsString();
628     else
629       SS << "<temporary>";
630   }
631 
632   void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) {
633     if (CStyle && V->kind() == Variable::VK_SFun)
634       SS << "this";
635     else
636       SS << V->name() << V->id();
637   }
638 
639   void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) {
640     switch (sugared) {
641       default:
642         SS << "\\(";   // Lambda
643         break;
644       case 1:
645         SS << "(";     // Slot declarations
646         break;
647       case 2:
648         SS << ", ";    // Curried functions
649         break;
650     }
651     self()->printVariable(E->variableDecl(), SS, true);
652     SS << ": ";
653     self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX);
654 
655     const SExpr *B = E->body();
656     if (B && B->opcode() == COP_Function)
657       self()->printFunction(cast<Function>(B), SS, 2);
658     else {
659       SS << ")";
660       self()->printSExpr(B, SS, Prec_Decl);
661     }
662   }
663 
printSFunction(const SFunction * E,StreamType & SS)664   void printSFunction(const SFunction *E, StreamType &SS) {
665     SS << "@";
666     self()->printVariable(E->variableDecl(), SS, true);
667     SS << " ";
668     self()->printSExpr(E->body(), SS, Prec_Decl);
669   }
670 
printCode(const Code * E,StreamType & SS)671   void printCode(const Code *E, StreamType &SS) {
672     SS << ": ";
673     self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
674     SS << " -> ";
675     self()->printSExpr(E->body(), SS, Prec_Decl);
676   }
677 
printField(const Field * E,StreamType & SS)678   void printField(const Field *E, StreamType &SS) {
679     SS << ": ";
680     self()->printSExpr(E->range(), SS, Prec_Decl-1);
681     SS << " = ";
682     self()->printSExpr(E->body(), SS, Prec_Decl);
683   }
684 
685   void printApply(const Apply *E, StreamType &SS, bool sugared = false) {
686     const SExpr *F = E->fun();
687     if (F->opcode() == COP_Apply) {
688       printApply(cast<Apply>(F), SS, true);
689       SS << ", ";
690     } else {
691       self()->printSExpr(F, SS, Prec_Postfix);
692       SS << "(";
693     }
694     self()->printSExpr(E->arg(), SS, Prec_MAX);
695     if (!sugared)
696       SS << ")$";
697   }
698 
printSApply(const SApply * E,StreamType & SS)699   void printSApply(const SApply *E, StreamType &SS) {
700     self()->printSExpr(E->sfun(), SS, Prec_Postfix);
701     if (E->isDelegation()) {
702       SS << "@(";
703       self()->printSExpr(E->arg(), SS, Prec_MAX);
704       SS << ")";
705     }
706   }
707 
printProject(const Project * E,StreamType & SS)708   void printProject(const Project *E, StreamType &SS) {
709     if (CStyle) {
710       // Omit the  this->
711       if (const auto *SAP = dyn_cast<SApply>(E->record())) {
712         if (const auto *V = dyn_cast<Variable>(SAP->sfun())) {
713           if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) {
714             SS << E->slotName();
715             return;
716           }
717         }
718       }
719       if (isa<Wildcard>(E->record())) {
720         // handle existentials
721         SS << "&";
722         SS << E->clangDecl()->getQualifiedNameAsString();
723         return;
724       }
725     }
726     self()->printSExpr(E->record(), SS, Prec_Postfix);
727     if (CStyle && E->isArrow())
728       SS << "->";
729     else
730       SS << ".";
731     SS << E->slotName();
732   }
733 
printCall(const Call * E,StreamType & SS)734   void printCall(const Call *E, StreamType &SS) {
735     const SExpr *T = E->target();
736     if (T->opcode() == COP_Apply) {
737       self()->printApply(cast<Apply>(T), SS, true);
738       SS << ")";
739     }
740     else {
741       self()->printSExpr(T, SS, Prec_Postfix);
742       SS << "()";
743     }
744   }
745 
printAlloc(const Alloc * E,StreamType & SS)746   void printAlloc(const Alloc *E, StreamType &SS) {
747     SS << "new ";
748     self()->printSExpr(E->dataType(), SS, Prec_Other-1);
749   }
750 
printLoad(const Load * E,StreamType & SS)751   void printLoad(const Load *E, StreamType &SS) {
752     self()->printSExpr(E->pointer(), SS, Prec_Postfix);
753     if (!CStyle)
754       SS << "^";
755   }
756 
printStore(const Store * E,StreamType & SS)757   void printStore(const Store *E, StreamType &SS) {
758     self()->printSExpr(E->destination(), SS, Prec_Other-1);
759     SS << " := ";
760     self()->printSExpr(E->source(), SS, Prec_Other-1);
761   }
762 
printArrayIndex(const ArrayIndex * E,StreamType & SS)763   void printArrayIndex(const ArrayIndex *E, StreamType &SS) {
764     self()->printSExpr(E->array(), SS, Prec_Postfix);
765     SS << "[";
766     self()->printSExpr(E->index(), SS, Prec_MAX);
767     SS << "]";
768   }
769 
printArrayAdd(const ArrayAdd * E,StreamType & SS)770   void printArrayAdd(const ArrayAdd *E, StreamType &SS) {
771     self()->printSExpr(E->array(), SS, Prec_Postfix);
772     SS << " + ";
773     self()->printSExpr(E->index(), SS, Prec_Atom);
774   }
775 
printUnaryOp(const UnaryOp * E,StreamType & SS)776   void printUnaryOp(const UnaryOp *E, StreamType &SS) {
777     SS << getUnaryOpcodeString(E->unaryOpcode());
778     self()->printSExpr(E->expr(), SS, Prec_Unary);
779   }
780 
printBinaryOp(const BinaryOp * E,StreamType & SS)781   void printBinaryOp(const BinaryOp *E, StreamType &SS) {
782     self()->printSExpr(E->expr0(), SS, Prec_Binary-1);
783     SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " ";
784     self()->printSExpr(E->expr1(), SS, Prec_Binary-1);
785   }
786 
printCast(const Cast * E,StreamType & SS)787   void printCast(const Cast *E, StreamType &SS) {
788     if (!CStyle) {
789       SS << "cast[";
790       switch (E->castOpcode()) {
791       case CAST_none:
792         SS << "none";
793         break;
794       case CAST_extendNum:
795         SS << "extendNum";
796         break;
797       case CAST_truncNum:
798         SS << "truncNum";
799         break;
800       case CAST_toFloat:
801         SS << "toFloat";
802         break;
803       case CAST_toInt:
804         SS << "toInt";
805         break;
806       case CAST_objToPtr:
807         SS << "objToPtr";
808         break;
809       }
810       SS << "](";
811       self()->printSExpr(E->expr(), SS, Prec_Unary);
812       SS << ")";
813       return;
814     }
815     self()->printSExpr(E->expr(), SS, Prec_Unary);
816   }
817 
printSCFG(const SCFG * E,StreamType & SS)818   void printSCFG(const SCFG *E, StreamType &SS) {
819     SS << "CFG {\n";
820     for (const auto *BBI : *E)
821       printBasicBlock(BBI, SS);
822     SS << "}";
823     newline(SS);
824   }
825 
printBBInstr(const SExpr * E,StreamType & SS)826   void printBBInstr(const SExpr *E, StreamType &SS) {
827     bool Sub = false;
828     if (E->opcode() == COP_Variable) {
829       const auto *V = cast<Variable>(E);
830       SS << "let " << V->name() << V->id() << " = ";
831       E = V->definition();
832       Sub = true;
833     }
834     else if (E->opcode() != COP_Store) {
835       SS << "let _x" << E->id() << " = ";
836     }
837     self()->printSExpr(E, SS, Prec_MAX, Sub);
838     SS << ";";
839     newline(SS);
840   }
841 
printBasicBlock(const BasicBlock * E,StreamType & SS)842   void printBasicBlock(const BasicBlock *E, StreamType &SS) {
843     SS << "BB_" << E->blockID() << ":";
844     if (E->parent())
845       SS << " BB_" << E->parent()->blockID();
846     newline(SS);
847 
848     for (const auto *A : E->arguments())
849       printBBInstr(A, SS);
850 
851     for (const auto *I : E->instructions())
852       printBBInstr(I, SS);
853 
854     const SExpr *T = E->terminator();
855     if (T) {
856       self()->printSExpr(T, SS, Prec_MAX, false);
857       SS << ";";
858       newline(SS);
859     }
860     newline(SS);
861   }
862 
printPhi(const Phi * E,StreamType & SS)863   void printPhi(const Phi *E, StreamType &SS) {
864     SS << "phi(";
865     if (E->status() == Phi::PH_SingleVal)
866       self()->printSExpr(E->values()[0], SS, Prec_MAX);
867     else {
868       unsigned i = 0;
869       for (const auto *V : E->values()) {
870         if (i++ > 0)
871           SS << ", ";
872         self()->printSExpr(V, SS, Prec_MAX);
873       }
874     }
875     SS << ")";
876   }
877 
printGoto(const Goto * E,StreamType & SS)878   void printGoto(const Goto *E, StreamType &SS) {
879     SS << "goto ";
880     printBlockLabel(SS, E->targetBlock(), E->index());
881   }
882 
printBranch(const Branch * E,StreamType & SS)883   void printBranch(const Branch *E, StreamType &SS) {
884     SS << "branch (";
885     self()->printSExpr(E->condition(), SS, Prec_MAX);
886     SS << ") ";
887     printBlockLabel(SS, E->thenBlock(), -1);
888     SS << " ";
889     printBlockLabel(SS, E->elseBlock(), -1);
890   }
891 
printReturn(const Return * E,StreamType & SS)892   void printReturn(const Return *E, StreamType &SS) {
893     SS << "return ";
894     self()->printSExpr(E->returnValue(), SS, Prec_Other);
895   }
896 
printIdentifier(const Identifier * E,StreamType & SS)897   void printIdentifier(const Identifier *E, StreamType &SS) {
898     SS << E->name();
899   }
900 
printIfThenElse(const IfThenElse * E,StreamType & SS)901   void printIfThenElse(const IfThenElse *E, StreamType &SS) {
902     if (CStyle) {
903       printSExpr(E->condition(), SS, Prec_Unary);
904       SS << " ? ";
905       printSExpr(E->thenExpr(), SS, Prec_Unary);
906       SS << " : ";
907       printSExpr(E->elseExpr(), SS, Prec_Unary);
908       return;
909     }
910     SS << "if (";
911     printSExpr(E->condition(), SS, Prec_MAX);
912     SS << ") then ";
913     printSExpr(E->thenExpr(), SS, Prec_Other);
914     SS << " else ";
915     printSExpr(E->elseExpr(), SS, Prec_Other);
916   }
917 
printLet(const Let * E,StreamType & SS)918   void printLet(const Let *E, StreamType &SS) {
919     SS << "let ";
920     printVariable(E->variableDecl(), SS, true);
921     SS << " = ";
922     printSExpr(E->variableDecl()->definition(), SS, Prec_Decl-1);
923     SS << "; ";
924     printSExpr(E->body(), SS, Prec_Decl-1);
925   }
926 };
927 
928 class StdPrinter : public PrettyPrinter<StdPrinter, std::ostream> {};
929 
930 } // namespace til
931 } // namespace threadSafety
932 } // namespace clang
933 
934 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
935