use serde::{Deserialize, Serialize};
use super::fragment_types::is_false;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Candidate {
pub id: String,
pub file: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum HeuristicTier {
Ext,
Guess,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SemanticProvenance {
Semantic,
SemanticDiscovered,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind")]
pub enum Edge {
#[serde(rename = "inherits")]
Inherits {
from_file: String,
from_line: usize,
to: String,
to_file: String,
#[serde(default, skip_serializing_if = "is_false")]
heuristic: bool,
},
#[serde(rename = "uses-type")]
UsesType {
from_file: String,
from_line: usize,
to: String,
to_file: String,
#[serde(default, skip_serializing_if = "is_false")]
heuristic: bool,
},
#[serde(rename = "uses-member")]
UsesMember {
from_file: String,
from_line: usize,
to: String,
to_file: String,
#[serde(default, skip_serializing_if = "is_false")]
heuristic: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
tier: Option<HeuristicTier>,
#[serde(default, skip_serializing_if = "Option::is_none")]
member: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
source: Option<SemanticProvenance>,
#[serde(default, skip_serializing_if = "Option::is_none")]
overload_signature: Option<String>,
},
#[serde(rename = "imports")]
Imports {
from_file: String,
from_line: usize,
target: String,
},
#[serde(rename = "ambiguous")]
Ambiguous {
origin: String,
from_file: String,
from_line: usize,
raw: String,
candidates: Vec<Candidate>,
candidate_count: usize,
},
#[serde(rename = "ctor-di")]
CtorDi {
from_file: String,
from_line: usize,
iface: String,
resolution: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
args: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
to: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
candidates: Vec<Candidate>,
},
#[serde(rename = "import")]
Import {
from_file: String,
from_line: usize,
target: String,
to_file: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
via: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
bound_defs: Vec<String>,
},
#[serde(rename = "call")]
Call {
from_file: String,
from_line: usize,
to: String,
to_file: String,
},
#[serde(rename = "jsx-use")]
JsxUse {
from_file: String,
from_line: usize,
to: String,
to_file: String,
},
#[serde(rename = "dispatch")]
Dispatch {
from_file: String,
from_line: usize,
to: String,
to_file: String,
},
#[serde(rename = "implements")]
Implements {
from_file: String,
from_line: usize,
to: String,
to_file: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
member: Option<String>,
},
#[serde(rename = "overrides")]
Overrides {
from_file: String,
from_line: usize,
to: String,
to_file: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
member: Option<String>,
},
#[serde(rename = "bus-hop")]
BusHop {
from_file: String,
from_line: usize,
message: String,
to: String,
to_file: String,
evidence: String,
},
}
impl Edge {
pub fn tier(&self) -> Option<HeuristicTier> {
match self {
Edge::UsesMember { tier, .. } => *tier,
_ => None,
}
}
pub fn is_heuristic(&self) -> bool {
match self {
Edge::Inherits { heuristic, .. }
| Edge::UsesType { heuristic, .. }
| Edge::UsesMember { heuristic, .. } => *heuristic,
_ => false,
}
}
pub fn uses_member(
from_file: String,
from_line: usize,
to: String,
to_file: String,
member: Option<String>,
tier: Option<HeuristicTier>,
) -> Edge {
Edge::UsesMember {
from_file,
from_line,
to,
to_file,
heuristic: tier.is_some(),
tier,
member,
source: None,
overload_signature: None,
}
}
pub fn uses_member_semantic(
from_file: String,
from_line: usize,
to: String,
to_file: String,
member: Option<String>,
provenance: SemanticProvenance,
overload_signature: Option<String>,
) -> Edge {
Edge::UsesMember {
from_file,
from_line,
to,
to_file,
heuristic: false,
tier: None,
member,
source: Some(provenance),
overload_signature,
}
}
pub fn provenance(&self) -> Option<SemanticProvenance> {
match self {
Edge::UsesMember { source, .. } => *source,
_ => None,
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct EdgesByKind {
pub inherits: usize,
#[serde(rename = "uses-type")]
pub uses_type: usize,
pub imports: usize,
#[serde(rename = "uses-member")]
pub uses_member: usize,
#[serde(rename = "ctor-di")]
pub ctor_di: usize,
#[serde(default)]
pub implements: usize,
#[serde(default)]
pub overrides: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub import: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub call: Option<usize>,
#[serde(rename = "jsx-use", default, skip_serializing_if = "Option::is_none")]
pub jsx_use: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub dispatch: Option<usize>,
#[serde(rename = "bus-hop", default, skip_serializing_if = "Option::is_none")]
pub bus_hop: Option<usize>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
pub struct HeuristicByTier {
pub ext: usize,
pub guess: usize,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
pub struct SemanticStats {
pub confirmed: usize,
pub disagreements: usize,
pub discovered: usize,
}