CheckFinalizerVisitor.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "CheckFinalizerVisitor.h"
  5. using namespace clang;
  6. namespace {
  7. // Simple visitor to determine if the content of a field might be collected
  8. // during finalization.
  9. class MightBeCollectedVisitor : public EdgeVisitor {
  10. public:
  11. bool might_be_collected() const;
  12. void VisitMember(Member* edge) override;
  13. void VisitCollection(Collection* edge) override;
  14. private:
  15. bool might_be_collected_ = false;
  16. };
  17. bool MightBeCollectedVisitor::might_be_collected() const {
  18. return might_be_collected_;
  19. }
  20. void MightBeCollectedVisitor::VisitMember(Member* edge) {
  21. might_be_collected_ = true;
  22. }
  23. void MightBeCollectedVisitor::VisitCollection(Collection* edge) {
  24. if (edge->on_heap()) {
  25. might_be_collected_ = true;
  26. } else {
  27. edge->AcceptMembers(this);
  28. }
  29. }
  30. } // namespace
  31. CheckFinalizerVisitor::CheckFinalizerVisitor(RecordCache* cache)
  32. : blacklist_context_(false),
  33. cache_(cache) {
  34. }
  35. CheckFinalizerVisitor::Errors& CheckFinalizerVisitor::finalized_fields() {
  36. return finalized_fields_;
  37. }
  38. bool CheckFinalizerVisitor::WalkUpFromCXXOperatorCallExpr(
  39. CXXOperatorCallExpr* expr) {
  40. // Only continue the walk-up if the operator is a blacklisted one.
  41. switch (expr->getOperator()) {
  42. case OO_Arrow:
  43. case OO_Subscript:
  44. this->WalkUpFromCallExpr(expr);
  45. return true;
  46. default:
  47. return true;
  48. }
  49. }
  50. bool CheckFinalizerVisitor::WalkUpFromCallExpr(CallExpr* expr) {
  51. // We consider all non-operator calls to be blacklisted contexts.
  52. bool prev_blacklist_context = blacklist_context_;
  53. blacklist_context_ = true;
  54. for (size_t i = 0; i < expr->getNumArgs(); ++i)
  55. this->TraverseStmt(expr->getArg(i));
  56. blacklist_context_ = prev_blacklist_context;
  57. return true;
  58. }
  59. bool CheckFinalizerVisitor::VisitMemberExpr(MemberExpr* member) {
  60. FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl());
  61. if (!field)
  62. return true;
  63. RecordInfo* info = cache_->Lookup(field->getParent());
  64. if (!info)
  65. return true;
  66. RecordInfo::Fields::iterator it = info->GetFields().find(field);
  67. if (it == info->GetFields().end())
  68. return true;
  69. if (seen_members_.find(member) != seen_members_.end())
  70. return true;
  71. if (blacklist_context_ &&
  72. MightBeCollected(&it->second)) {
  73. finalized_fields_.push_back(
  74. Error(member, &it->second));
  75. seen_members_.insert(member);
  76. }
  77. return true;
  78. }
  79. bool CheckFinalizerVisitor::MightBeCollected(FieldPoint* point) {
  80. MightBeCollectedVisitor visitor;
  81. point->edge()->Accept(&visitor);
  82. return visitor.might_be_collected();
  83. }