use cpg_rs::{
ContainedRefs, Cpg, Edge, EdgeProperty, EdgePropertyName, EdgeType, Node, NodeProperty,
NodePropertyName, NodeType, PropertyValue, PropertyValueEnum, StringList,
};
use std::fs::File;
use std::io::{BufReader, BufWriter};
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cpg = create_sample_cpg();
save_cpg(&cpg, "sample_cpg.json")?;
println!("Created and saved a sample CPG to sample_cpg.json");
let mut cpg = load_cpg("sample_cpg.json")?;
modify_cpg(&mut cpg);
save_cpg(&cpg, "modified_cpg.json")?;
println!("Modified the CPG and saved it to modified_cpg.json");
Ok(())
}
fn create_sample_cpg() -> Cpg {
let file_node = Node {
key: 1,
r#type: NodeType::File,
property: vec![
NodeProperty {
name: NodePropertyName::Name,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("example.java".to_string())),
}),
},
NodeProperty {
name: NodePropertyName::Filename,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("example.java".to_string())),
}),
},
],
};
let method_node = Node {
key: 2,
r#type: NodeType::Method,
property: vec![
NodeProperty {
name: NodePropertyName::Name,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("main".to_string())),
}),
},
NodeProperty {
name: NodePropertyName::FullName,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue(
"com.example.Main.main".to_string(),
)),
}),
},
NodeProperty {
name: NodePropertyName::Signature,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue(
"void main(String[] args)".to_string(),
)),
}),
},
NodeProperty {
name: NodePropertyName::LineNumber,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::IntValue(10)),
}),
},
],
};
let return_node = Node {
key: 3,
r#type: NodeType::MethodReturn,
property: vec![
NodeProperty {
name: NodePropertyName::TypeFullName,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("void".to_string())),
}),
},
NodeProperty {
name: NodePropertyName::Code,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("RET".to_string())),
}),
},
],
};
let file_to_method_edge = Edge {
src: 1, dst: 2, r#type: EdgeType::Contains,
property: vec![],
};
let method_to_return_edge = Edge {
src: 2, dst: 3, r#type: EdgeType::Ast,
property: vec![],
};
Cpg {
node: vec![file_node, method_node, return_node],
edge: vec![file_to_method_edge, method_to_return_edge],
}
}
fn load_cpg<P: AsRef<Path>>(path: P) -> Result<Cpg, Box<dyn std::error::Error>> {
let file = File::open(path)?;
let reader = BufReader::new(file);
let cpg = serde_json::from_reader(reader)?;
Ok(cpg)
}
fn save_cpg<P: AsRef<Path>>(cpg: &Cpg, path: P) -> Result<(), Box<dyn std::error::Error>> {
let file = File::create(path)?;
let writer = BufWriter::new(file);
serde_json::to_writer_pretty(writer, cpg)?;
Ok(())
}
fn modify_cpg(cpg: &mut Cpg) {
let param_node = Node {
key: 4,
r#type: NodeType::MethodParameterIn,
property: vec![
NodeProperty {
name: NodePropertyName::Name,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("args".to_string())),
}),
},
NodeProperty {
name: NodePropertyName::TypeFullName,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue(
"java.lang.String[]".to_string(),
)),
}),
},
NodeProperty {
name: NodePropertyName::EvaluationStrategy,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("BY_VALUE".to_string())),
}),
},
],
};
let local_node = Node {
key: 5,
r#type: NodeType::Local,
property: vec![
NodeProperty {
name: NodePropertyName::Name,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("message".to_string())),
}),
},
NodeProperty {
name: NodePropertyName::TypeFullName,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue(
"java.lang.String".to_string(),
)),
}),
},
NodeProperty {
name: NodePropertyName::Code,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("String message".to_string())),
}),
},
],
};
let literal_node = Node {
key: 6,
r#type: NodeType::Literal,
property: vec![
NodeProperty {
name: NodePropertyName::TypeFullName,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue(
"java.lang.String".to_string(),
)),
}),
},
NodeProperty {
name: NodePropertyName::Code,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("Hello, World!".to_string())),
}),
},
],
};
let call_node = Node {
key: 7,
r#type: NodeType::Call,
property: vec![
NodeProperty {
name: NodePropertyName::Name,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("println".to_string())),
}),
},
NodeProperty {
name: NodePropertyName::MethodFullName,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue(
"java.io.PrintStream.println".to_string(),
)),
}),
},
NodeProperty {
name: NodePropertyName::TypeFullName,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("void".to_string())),
}),
},
NodeProperty {
name: NodePropertyName::Code,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue(
"System.out.println(message)".to_string(),
)),
}),
},
],
};
let method_to_param_edge = Edge {
src: 2, dst: 4, r#type: EdgeType::Ast,
property: vec![EdgeProperty {
name: EdgePropertyName::Variable,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringValue("args".to_string())),
}),
}],
};
let method_to_local_edge = Edge {
src: 2, dst: 5, r#type: EdgeType::Ast,
property: vec![],
};
let local_to_literal_edge = Edge {
src: 5, dst: 6, r#type: EdgeType::Ast,
property: vec![],
};
let method_to_call_edge = Edge {
src: 2, dst: 7, r#type: EdgeType::Ast,
property: vec![],
};
if let Some(method_node) = cpg.node.iter_mut().find(|n| n.key == 2) {
if let Some(line_prop) = method_node
.property
.iter_mut()
.find(|p| p.name == NodePropertyName::LineNumber)
{
line_prop.value = Some(PropertyValue {
value: Some(PropertyValueEnum::IntValue(12)), });
}
}
if let Some(method_node) = cpg.node.iter_mut().find(|n| n.key == 2) {
method_node.property.push(NodeProperty {
name: NodePropertyName::PossibleTypes,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::StringList(StringList {
values: vec![
"java.lang.Object".to_string(),
"com.example.Main".to_string(),
],
})),
}),
});
}
if let Some(file_node) = cpg.node.iter_mut().find(|n| n.key == 1) {
file_node.property.push(NodeProperty {
name: NodePropertyName::ContainedRef,
value: Some(PropertyValue {
value: Some(PropertyValueEnum::ContainedRefs(ContainedRefs {
local_name: "methods".to_string(),
refs: vec![2], })),
}),
});
}
cpg.node.push(param_node);
cpg.node.push(local_node);
cpg.node.push(literal_node);
cpg.node.push(call_node);
cpg.edge.push(method_to_param_edge);
cpg.edge.push(method_to_local_edge);
cpg.edge.push(local_to_literal_edge);
cpg.edge.push(method_to_call_edge);
}
fn print_cpg_summary(cpg: &Cpg) {
println!("CPG Summary:");
println!(" Nodes: {}", cpg.node.len());
println!(" Edges: {}", cpg.edge.len());
let mut node_type_counts = std::collections::HashMap::new();
for node in &cpg.node {
*node_type_counts
.entry(format!("{:?}", node.r#type))
.or_insert(0) += 1;
}
println!(" Node types:");
for (node_type, count) in node_type_counts {
println!(" {}: {}", node_type, count);
}
let mut edge_type_counts = std::collections::HashMap::new();
for edge in &cpg.edge {
*edge_type_counts
.entry(format!("{:?}", edge.r#type))
.or_insert(0) += 1;
}
println!(" Edge types:");
for (edge_type, count) in edge_type_counts {
println!(" {}: {}", edge_type, count);
}
}