source/Issue.cpp (126 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <boost/functional/hash.hpp>
#include <Show.h>
#include <mariana-trench/Issue.h>
#include <mariana-trench/JsonValidation.h>
namespace marianatrench {
bool Issue::leq(const Issue& other) const {
if (is_bottom()) {
return true;
} else if (other.is_bottom()) {
return false;
} else {
return rule_ == other.rule_ && position_ == other.position_ &&
sources_.leq(other.sources_) && sinks_.leq(other.sinks_);
}
}
bool Issue::equals(const Issue& other) const {
if (is_bottom()) {
return other.is_bottom();
} else if (other.is_bottom()) {
return false;
} else {
return rule_ == other.rule_ && position_ == other.position_ &&
sources_ == other.sources_ && sinks_ == other.sinks_;
}
}
void Issue::join_with(const Issue& other) {
mt_if_expensive_assert(auto previous = *this);
if (is_bottom()) {
*this = other;
} else if (other.is_bottom()) {
return;
} else {
mt_assert(rule_ == other.rule_);
mt_assert(position_ == other.position_);
sources_.join_with(other.sources_);
sinks_.join_with(other.sinks_);
}
mt_expensive_assert(previous.leq(*this) && other.leq(*this));
}
void Issue::widen_with(const Issue& other) {
mt_if_expensive_assert(auto previous = *this);
if (is_bottom()) {
*this = other;
} else if (other.is_bottom()) {
return;
} else {
mt_assert(rule_ == other.rule_);
mt_assert(position_ == other.position_);
sources_.widen_with(other.sources_);
sinks_.widen_with(other.sinks_);
}
mt_expensive_assert(previous.leq(*this) && other.leq(*this));
}
void Issue::meet_with(const Issue& other) {
if (is_bottom()) {
return;
} else if (other.is_bottom()) {
set_to_bottom();
} else {
mt_assert(rule_ == other.rule_);
mt_assert(position_ == other.position_);
sources_.meet_with(other.sources_);
sinks_.meet_with(other.sinks_);
}
}
void Issue::narrow_with(const Issue& other) {
if (is_bottom()) {
return;
} else if (other.is_bottom()) {
set_to_bottom();
} else {
mt_assert(rule_ == other.rule_);
mt_assert(position_ == other.position_);
sources_.narrow_with(other.sources_);
sinks_.narrow_with(other.sinks_);
}
}
bool Issue::GroupEqual::operator()(const Issue& left, const Issue& right)
const {
return left.rule_ == right.rule_ && left.position_ == right.position_;
}
std::size_t Issue::GroupHash::operator()(const Issue& issue) const {
std::size_t seed = 0;
boost::hash_combine(seed, issue.rule_);
boost::hash_combine(seed, issue.position_);
return seed;
}
void Issue::filter_sources(
const std::function<
bool(const Method* MT_NULLABLE, const AccessPath&, const Kind*)>&
predicate) {
sources_.filter_invalid_frames(predicate);
}
void Issue::filter_sinks(
const std::function<
bool(const Method* MT_NULLABLE, const AccessPath&, const Kind*)>&
predicate) {
sinks_.filter_invalid_frames(predicate);
}
FeatureMayAlwaysSet Issue::features() const {
auto source_features = sources_.features_joined();
auto sink_features = sinks_.features_joined();
source_features.add(sink_features);
return source_features;
}
Json::Value Issue::to_json() const {
mt_assert(!is_bottom());
auto value = Json::Value(Json::objectValue);
value["sources"] = sources_.to_json();
value["sinks"] = sinks_.to_json();
value["rule"] = Json::Value(rule_->code());
value["position"] = position_->to_json();
JsonValidation::update_object(value, features().to_json());
return value;
}
std::ostream& operator<<(std::ostream& out, const Issue& issue) {
out << "Issue(sources=" << issue.sources_ << ", sinks=" << issue.sinks_
<< ", rule=";
if (issue.rule_ != nullptr) {
out << issue.rule_->code();
} else {
out << "null";
}
return out << ", position=" << show(issue.position_) << ")";
}
} // namespace marianatrench