Frame Frame::from_json()

in source/Frame.cpp [248:391]


Frame Frame::from_json(const Json::Value& value, Context& context) {
  JsonValidation::validate_object(value);

  const Kind* kind = Kind::from_json(value, context);

  auto callee_port = AccessPath(Root(Root::Kind::Leaf));
  if (value.isMember("callee_port")) {
    JsonValidation::string(value, /* field */ "callee_port");
    callee_port = AccessPath::from_json(value["callee_port"]);
  }

  const Method* callee = nullptr;
  if (value.isMember("callee")) {
    callee = Method::from_json(
        JsonValidation::object_or_string(value, /* field */ "callee"), context);
  }

  const Position* call_position = nullptr;
  if (value.isMember("call_position")) {
    call_position = Position::from_json(
        JsonValidation::object(value, /* field */ "call_position"), context);
  }

  int distance = 0;
  if (value.isMember("distance")) {
    distance = JsonValidation::integer(value, /* field */ "distance");
  }

  JsonValidation::null_or_array(value, /* field */ "origins");
  auto origins = MethodSet::from_json(value["origins"], context);

  JsonValidation::null_or_array(value, /* field */ "field_origins");
  auto field_origins = FieldSet::from_json(value["field_origins"], context);

  // Inferred may_features and always_features. Technically, user-specified
  // features should go under "user_features", but this gives a way to override
  // that behavior and specify "may/always" features. Note that local inferred
  // features cannot be user-specified.
  auto inferred_features = FeatureMayAlwaysSet::from_json(value, context);

  // User specified always-features.
  FeatureSet user_features;
  if (value.isMember("features")) {
    JsonValidation::null_or_array(value, /* field */ "features");
    user_features = FeatureSet::from_json(value["features"], context);
  }

  RootSetAbstractDomain via_type_of_ports;
  if (value.isMember("via_type_of")) {
    for (const auto& root :
         JsonValidation::null_or_array(value, /* field */ "via_type_of")) {
      via_type_of_ports.add(Root::from_json(root));
    }
  }

  RootSetAbstractDomain via_value_of_ports;
  if (value.isMember("via_value_of")) {
    for (const auto& root :
         JsonValidation::null_or_array(value, /* field */ "via_value_of")) {
      via_value_of_ports.add(Root::from_json(root));
    }
  }

  LocalPositionSet local_positions;
  if (value.isMember("local_positions")) {
    JsonValidation::null_or_array(value, /* field */ "local_positions");
    local_positions =
        LocalPositionSet::from_json(value["local_positions"], context);
  }

  CanonicalNameSetAbstractDomain canonical_names;
  if (value.isMember("canonical_names")) {
    for (const auto& canonical_name :
         JsonValidation::nonempty_array(value, /* field */ "canonical_names")) {
      canonical_names.add(CanonicalName::from_json(canonical_name));
    }
  }

  if (canonical_names.is_value() && !canonical_names.elements().empty()) {
    callee_port = validate_and_infer_crtex_callee_port(
        value, callee_port, canonical_names, via_type_of_ports);
  } else if (
      callee_port.root().is_anchor() || callee_port.root().is_producer()) {
    throw JsonValidationError(
        value,
        /* field */ std::nullopt,
        "canonical_names to be specified with `Anchor` or `Producer` callee_port.");
  }

  // Sanity checks.
  if (callee == nullptr) {
    if (!callee_port.root().is_leaf_port()) {
      throw JsonValidationError(
          value,
          /* field */ "callee_port",
          /* expected */ "`Leaf`, `Anchor` or `Producer`");
    } else if (call_position != nullptr) {
      throw JsonValidationError(
          value,
          /* field */ "call_position",
          /* expected */ "unspecified position for leaf taint");
    } else if (distance != 0) {
      throw JsonValidationError(
          value,
          /* field */ "distance",
          /* expected */ "a value of 0");
    }
  } else {
    if (callee_port.root().is_leaf_port()) {
      throw JsonValidationError(
          value,
          /* field */ "callee_port",
          /* expected */ "`Argument(x)` or `Return`");
    } else if (call_position == nullptr) {
      throw JsonValidationError(
          value,
          /* field */ "call_position",
          /* expected */ "non-null position");
    } else if (distance == 0) {
      throw JsonValidationError(
          value,
          /* field */ "distance",
          /* expected */ "non-zero distance");
    }
  }

  return Frame(
      kind,
      std::move(callee_port),
      callee,
      /* field_callee */ nullptr, // A field callee can never be set from a json
                                  // model generator
      call_position,
      distance,
      std::move(origins),
      std::move(field_origins),
      std::move(inferred_features),
      /* locally_inferred_features */ FeatureMayAlwaysSet::bottom(),
      std::move(user_features),
      std::move(via_type_of_ports),
      std::move(via_value_of_ports),
      std::move(local_positions),
      std::move(canonical_names));
}