#include "clang/Analysis/Analyses/ThreadSafetyLogical.h"
using namespace llvm;
using namespace clang::threadSafety::lexpr;
static bool implies(const LExpr *LHS, bool LNeg, const LExpr *RHS, bool RNeg) {
const auto LeftAndOperator = [=](const BinOp *A) {
return implies(A->left(), LNeg, RHS, RNeg) &&
implies(A->right(), LNeg, RHS, RNeg);
};
const auto RightAndOperator = [=](const BinOp *A) {
return implies(LHS, LNeg, A->left(), RNeg) &&
implies(LHS, LNeg, A->right(), RNeg);
};
const auto LeftOrOperator = [=](const BinOp *A) {
return implies(A->left(), LNeg, RHS, RNeg) ||
implies(A->right(), LNeg, RHS, RNeg);
};
const auto RightOrOperator = [=](const BinOp *A) {
return implies(LHS, LNeg, A->left(), RNeg) ||
implies(LHS, LNeg, A->right(), RNeg);
};
switch (RHS->kind()) {
case LExpr::And:
return RNeg ? RightOrOperator(cast<And>(RHS))
: RightAndOperator(cast<And>(RHS));
case LExpr::Or:
return RNeg ? RightAndOperator(cast<Or>(RHS))
: RightOrOperator(cast<Or>(RHS));
case LExpr::Not:
return implies(LHS, LNeg, cast<Not>(RHS)->exp(), !RNeg);
case LExpr::Terminal:
break;
}
switch (LHS->kind()) {
case LExpr::And:
return LNeg ? LeftAndOperator(cast<And>(LHS))
: LeftOrOperator(cast<And>(LHS));
case LExpr::Or:
return LNeg ? LeftOrOperator(cast<Or>(LHS))
: LeftAndOperator(cast<Or>(LHS));
case LExpr::Not:
return implies(cast<Not>(LHS)->exp(), !LNeg, RHS, RNeg);
case LExpr::Terminal:
break;
}
if (LNeg != RNeg)
return false;
return cast<Terminal>(LHS)->expr() == cast<Terminal>(RHS)->expr();
}
namespace clang {
namespace threadSafety {
namespace lexpr {
bool implies(const LExpr *LHS, const LExpr *RHS) {
return ::implies(LHS, false, RHS, false);
}
}
}
}