|
24 | 24 |
|
25 | 25 | #include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
26 | 26 | #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
|
| 27 | +#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" |
27 | 28 | #include "clang/Analysis/AnalysisContext.h"
|
28 | 29 | #include "clang/Basic/OperatorKinds.h"
|
29 | 30 |
|
30 | 31 | #include <memory>
|
| 32 | +#include <ostream> |
| 33 | +#include <sstream> |
31 | 34 | #include <vector>
|
32 | 35 |
|
33 | 36 |
|
34 | 37 | namespace clang {
|
35 | 38 | namespace threadSafety {
|
36 | 39 |
|
| 40 | + |
| 41 | +// Various helper functions on til::SExpr |
| 42 | +namespace sx { |
| 43 | + |
| 44 | +inline bool equals(const til::SExpr *E1, const til::SExpr *E2) { |
| 45 | + return til::EqualsComparator::compareExprs(E1, E2); |
| 46 | +} |
| 47 | + |
| 48 | +inline bool matches(const til::SExpr *E1, const til::SExpr *E2) { |
| 49 | + // We treat a top-level wildcard as the "univsersal" lock. |
| 50 | + // It matches everything for the purpose of checking locks, but not |
| 51 | + // for unlocking them. |
| 52 | + if (isa<til::Wildcard>(E1)) |
| 53 | + return isa<til::Wildcard>(E2); |
| 54 | + if (isa<til::Wildcard>(E2)) |
| 55 | + return isa<til::Wildcard>(E1); |
| 56 | + |
| 57 | + return til::MatchComparator::compareExprs(E1, E2); |
| 58 | +} |
| 59 | + |
| 60 | +inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) { |
| 61 | + auto *PE1 = dyn_cast_or_null<til::Project>(E1); |
| 62 | + if (!PE1) |
| 63 | + return false; |
| 64 | + auto *PE2 = dyn_cast_or_null<til::Project>(E2); |
| 65 | + if (!PE2) |
| 66 | + return false; |
| 67 | + return PE1->clangDecl() == PE2->clangDecl(); |
| 68 | +} |
| 69 | + |
| 70 | +inline std::string toString(const til::SExpr *E) { |
| 71 | + std::stringstream ss; |
| 72 | + til::StdPrinter::print(E, ss); |
| 73 | + return ss.str(); |
| 74 | +} |
| 75 | + |
| 76 | +} // end namespace sx |
| 77 | + |
| 78 | + |
| 79 | + |
37 | 80 | // This class defines the interface of a clang CFG Visitor.
|
38 | 81 | // CFGWalker will invoke the following methods.
|
39 | 82 | // Note that methods are not virtual; the visitor is templatized.
|
@@ -206,6 +249,59 @@ class CFGWalker {
|
206 | 249 | };
|
207 | 250 |
|
208 | 251 |
|
| 252 | + |
| 253 | + |
| 254 | +class CapabilityExpr { |
| 255 | + // TODO: move this back into ThreadSafety.cpp |
| 256 | + // This is specific to thread safety. It is here because |
| 257 | + // translateAttrExpr needs it, but that should be moved too. |
| 258 | + |
| 259 | +private: |
| 260 | + const til::SExpr* CapExpr; //< The capability expression. |
| 261 | + bool Negated; //< True if this is a negative capability |
| 262 | + |
| 263 | +public: |
| 264 | + CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {} |
| 265 | + |
| 266 | + const til::SExpr* sexpr() const { return CapExpr; } |
| 267 | + bool negative() const { return Negated; } |
| 268 | + |
| 269 | + CapabilityExpr operator!() const { |
| 270 | + return CapabilityExpr(CapExpr, !Negated); |
| 271 | + } |
| 272 | + |
| 273 | + bool equals(const CapabilityExpr &other) const { |
| 274 | + return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr); |
| 275 | + } |
| 276 | + |
| 277 | + bool matches(const CapabilityExpr &other) const { |
| 278 | + return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr); |
| 279 | + } |
| 280 | + |
| 281 | + bool matchesUniv(const CapabilityExpr &CapE) const { |
| 282 | + return isUniversal() || matches(CapE); |
| 283 | + } |
| 284 | + |
| 285 | + bool partiallyMatches(const CapabilityExpr &other) const { |
| 286 | + return (Negated == other.Negated) && |
| 287 | + sx::partiallyMatches(CapExpr, other.CapExpr); |
| 288 | + } |
| 289 | + |
| 290 | + std::string toString() const { |
| 291 | + if (Negated) |
| 292 | + return "!" + sx::toString(CapExpr); |
| 293 | + return sx::toString(CapExpr); |
| 294 | + } |
| 295 | + |
| 296 | + bool shouldIgnore() const { return CapExpr == nullptr; } |
| 297 | + |
| 298 | + bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); } |
| 299 | + |
| 300 | + bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); } |
| 301 | +}; |
| 302 | + |
| 303 | + |
| 304 | + |
209 | 305 | // Translate clang::Expr to til::SExpr.
|
210 | 306 | class SExprBuilder {
|
211 | 307 | public:
|
@@ -242,10 +338,10 @@ class SExprBuilder {
|
242 | 338 |
|
243 | 339 | // Translate a clang expression in an attribute to a til::SExpr.
|
244 | 340 | // Constructs the context from D, DeclExp, and SelfDecl.
|
245 |
| - til::SExpr *translateAttrExpr(const Expr *AttrExp, const NamedDecl *D, |
246 |
| - const Expr *DeclExp, VarDecl *SelfDecl=nullptr); |
| 341 | + CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D, |
| 342 | + const Expr *DeclExp, VarDecl *SelfD=nullptr); |
247 | 343 |
|
248 |
| - til::SExpr *translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx); |
| 344 | + CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx); |
249 | 345 |
|
250 | 346 | // Translate a clang statement or expression to a TIL expression.
|
251 | 347 | // Also performs substitution of variables; Ctx provides the context.
|
|
0 commit comments