|
13 | 13 | #include <cctype> |
14 | 14 | #include <filesystem> |
15 | 15 | #include <format> |
| 16 | +#include <ranges> |
16 | 17 | #include <unordered_set> |
17 | 18 |
|
18 | 19 | #include "converter/lex.h" |
@@ -643,6 +644,78 @@ clang::Expr *GetCallObject(clang::CallExpr *expr) { |
643 | 644 | return nullptr; |
644 | 645 | } |
645 | 646 |
|
| 647 | +static void GetAllVarsImpl(const clang::Stmt *stmt, |
| 648 | + std::unordered_set<const clang::ValueDecl *> &vars) { |
| 649 | + if (!stmt) { |
| 650 | + return; |
| 651 | + } |
| 652 | + |
| 653 | + if (auto *decl_ref = clang::dyn_cast<clang::DeclRefExpr>(stmt)) { |
| 654 | + vars.insert(decl_ref->getDecl()); |
| 655 | + } else if (auto *member = clang::dyn_cast<clang::MemberExpr>(stmt)) { |
| 656 | + vars.insert(member->getMemberDecl()); |
| 657 | + GetAllVarsImpl(member->getBase(), vars); |
| 658 | + } |
| 659 | + |
| 660 | + for (auto *child : stmt->children()) { |
| 661 | + GetAllVarsImpl(child, vars); |
| 662 | + } |
| 663 | +} |
| 664 | + |
| 665 | +std::unordered_set<const clang::ValueDecl *> |
| 666 | +GetAllVars(const clang::Stmt *stmt) { |
| 667 | + std::unordered_set<const clang::ValueDecl *> vars; |
| 668 | + GetAllVarsImpl(stmt, vars); |
| 669 | + return vars; |
| 670 | +} |
| 671 | + |
| 672 | +bool ReferencesThis(const clang::Stmt *stmt) { |
| 673 | + if (!stmt) { |
| 674 | + return false; |
| 675 | + } |
| 676 | + if (clang::isa<clang::CXXThisExpr>(stmt)) { |
| 677 | + return true; |
| 678 | + } |
| 679 | + for (auto *child : stmt->children()) { |
| 680 | + if (ReferencesThis(child)) { |
| 681 | + return true; |
| 682 | + } |
| 683 | + } |
| 684 | + return false; |
| 685 | +} |
| 686 | + |
| 687 | +bool MayCauseBorrowMutError(const clang::Expr *lhs, const clang::Expr *rhs) { |
| 688 | + auto lhs_vars = GetAllVars(lhs); |
| 689 | + auto rhs_vars = GetAllVars(rhs); |
| 690 | + |
| 691 | + auto predicate = [lhs](auto *var) { |
| 692 | + auto qual_type = var->getType(); |
| 693 | + return (qual_type->isPointerType() || qual_type->isReferenceType()) && |
| 694 | + qual_type->getPointeeType() |
| 695 | + .getCanonicalType() |
| 696 | + .getUnqualifiedType() == |
| 697 | + lhs->getType().getCanonicalType().getUnqualifiedType(); |
| 698 | + }; |
| 699 | + |
| 700 | + if (std::ranges::any_of(rhs_vars, predicate) || |
| 701 | + (std::ranges::any_of(lhs_vars, predicate) && !rhs_vars.empty())) { |
| 702 | + return true; |
| 703 | + } |
| 704 | + |
| 705 | + for (auto *lhs_var : lhs_vars) { |
| 706 | + if (rhs_vars.count(lhs_var)) |
| 707 | + return true; |
| 708 | + } |
| 709 | + return false; |
| 710 | +} |
| 711 | + |
| 712 | +bool ArgsMayAlias(const clang::Expr *a, const clang::Expr *b) { |
| 713 | + if (ReferencesThis(a) && ReferencesThis(b)) { |
| 714 | + return true; |
| 715 | + } |
| 716 | + return MayCauseBorrowMutError(a, b) || MayCauseBorrowMutError(b, a); |
| 717 | +} |
| 718 | + |
646 | 719 | std::vector<clang::Expr *> |
647 | 720 | BuildUnifiedArgs(clang::Expr *expr, clang::Expr **args, unsigned num_args) { |
648 | 721 | std::vector<clang::Expr *> all_args; |
|
0 commit comments