Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for stitcher configuration #321

Merged
merged 7 commits into from
Nov 21, 2023
Merged
2 changes: 0 additions & 2 deletions languages/tree-sitter-stack-graphs-java/rust/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use tree_sitter_stack_graphs::loader::FileAnalyzers;
use tree_sitter_stack_graphs::loader::LanguageConfiguration;
use tree_sitter_stack_graphs::loader::LoadError;
use tree_sitter_stack_graphs::CancellationFlag;
Expand Down Expand Up @@ -39,7 +38,6 @@ pub fn try_language_configuration(
STACK_GRAPHS_BUILTINS_SOURCE,
)),
Some(STACK_GRAPHS_BUILTINS_CONFIG),
FileAnalyzers::new(),
cancellation_flag,
)
}
9 changes: 5 additions & 4 deletions languages/tree-sitter-stack-graphs-javascript/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
// ------------------------------------------------------------------------------------------------

use tree_sitter_stack_graphs::loader::FileAnalyzers;
use tree_sitter_stack_graphs::loader::LanguageConfiguration;
use tree_sitter_stack_graphs::loader::LoadError;
use tree_sitter_stack_graphs::CancellationFlag;
Expand Down Expand Up @@ -38,7 +37,7 @@ pub fn language_configuration(cancellation_flag: &dyn CancellationFlag) -> Langu
pub fn try_language_configuration(
cancellation_flag: &dyn CancellationFlag,
) -> Result<LanguageConfiguration, LoadError> {
LanguageConfiguration::from_sources(
let mut lc = LanguageConfiguration::from_sources(
tree_sitter_javascript::language(),
Some(String::from("source.js")),
None,
Expand All @@ -50,7 +49,9 @@ pub fn try_language_configuration(
STACK_GRAPHS_BUILTINS_SOURCE,
)),
Some(STACK_GRAPHS_BUILTINS_CONFIG),
FileAnalyzers::new().add("package.json".to_string(), NpmPackageAnalyzer {}),
cancellation_flag,
)
)?;
lc.special_files
.add("package.json".to_string(), NpmPackageAnalyzer {});
Ok(lc)
}
13 changes: 7 additions & 6 deletions languages/tree-sitter-stack-graphs-typescript/rust/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
// ------------------------------------------------------------------------------------------------

use tree_sitter_stack_graphs::loader::FileAnalyzers;
use tree_sitter_stack_graphs::loader::LanguageConfiguration;
use tree_sitter_stack_graphs::loader::LoadError;
use tree_sitter_stack_graphs::CancellationFlag;
Expand Down Expand Up @@ -41,7 +40,7 @@ pub fn language_configuration(cancellation_flag: &dyn CancellationFlag) -> Langu
pub fn try_language_configuration(
cancellation_flag: &dyn CancellationFlag,
) -> Result<LanguageConfiguration, LoadError> {
LanguageConfiguration::from_sources(
let mut lc = LanguageConfiguration::from_sources(
tree_sitter_typescript::language_typescript(),
Some(String::from("source.ts")),
None,
Expand All @@ -53,9 +52,11 @@ pub fn try_language_configuration(
STACK_GRAPHS_BUILTINS_SOURCE,
)),
Some(STACK_GRAPHS_BUILTINS_CONFIG),
FileAnalyzers::new()
.add("tsconfig.json".to_string(), TsConfigAnalyzer {})
.add("package.json".to_string(), NpmPackageAnalyzer {}),
cancellation_flag,
)
)?;
lc.special_files
.add("tsconfig.json".to_string(), TsConfigAnalyzer {})
.add("package.json".to_string(), NpmPackageAnalyzer {});
lc.no_similar_paths_in_file = true;
Ok(lc)
}
7 changes: 7 additions & 0 deletions stack-graphs/include/stack-graphs.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ struct sg_partial_path {
struct sg_partial_path_edge_list edges;
};

struct sg_stitcher_config {
// Enables similar path detection during stiching.
bool detect_similar_paths;
};

// An array of all of the partial paths in a partial path database. Partial path handles are
// indices into this array. There will never be a valid partial path at index 0; a handle with
// the value 0 represents a missing partial path.
Expand Down Expand Up @@ -733,6 +738,7 @@ enum sg_result sg_partial_path_arena_find_partial_paths_in_file(const struct sg_
struct sg_partial_path_arena *partials,
sg_file_handle file,
struct sg_partial_path_list *partial_path_list,
const struct sg_stitcher_config *stitcher_config,
const size_t *cancellation_flag);

// Finds all complete paths reachable from a set of starting nodes, placing the result into the
Expand All @@ -748,6 +754,7 @@ enum sg_result sg_partial_path_arena_find_all_complete_paths(const struct sg_sta
size_t starting_node_count,
const sg_node_handle *starting_nodes,
struct sg_partial_path_list *path_list,
const struct sg_stitcher_config *stitcher_config,
const size_t *cancellation_flag);

// Returns a reference to the array of partial path data in this partial path database. The
Expand Down
16 changes: 13 additions & 3 deletions stack-graphs/src/assert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::partial::PartialPaths;
use crate::stitching::Database;
use crate::stitching::DatabaseCandidates;
use crate::stitching::ForwardPartialPathStitcher;
use crate::stitching::StitcherConfig;
use crate::CancellationError;
use crate::CancellationFlag;

Expand Down Expand Up @@ -149,12 +150,19 @@ impl Assertion {
graph: &StackGraph,
partials: &mut PartialPaths,
db: &mut Database,
stitcher_config: StitcherConfig,
cancellation_flag: &dyn CancellationFlag,
) -> Result<(), AssertionError> {
match self {
Self::Defined { source, targets } => {
self.run_defined(graph, partials, db, source, targets, cancellation_flag)
}
Self::Defined { source, targets } => self.run_defined(
graph,
partials,
db,
source,
targets,
stitcher_config,
cancellation_flag,
),
Self::Defines { source, symbols } => self.run_defines(graph, source, symbols),
Self::Refers { source, symbols } => self.run_refers(graph, source, symbols),
}
Expand All @@ -167,6 +175,7 @@ impl Assertion {
db: &mut Database,
source: &AssertionSource,
expected_targets: &Vec<AssertionTarget>,
stitcher_config: StitcherConfig,
cancellation_flag: &dyn CancellationFlag,
) -> Result<(), AssertionError> {
let references = source.iter_references(graph).collect::<Vec<_>>();
Expand All @@ -182,6 +191,7 @@ impl Assertion {
ForwardPartialPathStitcher::find_all_complete_partial_paths(
&mut DatabaseCandidates::new(graph, partials, db),
vec![*reference],
stitcher_config,
cancellation_flag,
|_, _, p| {
reference_paths.push(p.clone());
Expand Down
21 changes: 21 additions & 0 deletions stack-graphs/src/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use crate::stitching::Database;
use crate::stitching::DatabaseCandidates;
use crate::stitching::ForwardPartialPathStitcher;
use crate::stitching::GraphEdgeCandidates;
use crate::stitching::StitcherConfig;
use crate::CancellationError;
use crate::CancellationFlag;

Expand Down Expand Up @@ -1173,18 +1174,21 @@ pub extern "C" fn sg_partial_path_arena_find_partial_paths_in_file(
partials: *mut sg_partial_path_arena,
file: sg_file_handle,
partial_path_list: *mut sg_partial_path_list,
stitcher_config: *const sg_stitcher_config,
cancellation_flag: *const usize,
) -> sg_result {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let file = file.into();
let partial_path_list = unsafe { &mut *partial_path_list };
let stitcher_config = unsafe { *stitcher_config };
let cancellation_flag: Option<&AtomicUsize> =
unsafe { std::mem::transmute(cancellation_flag.as_ref()) };
ForwardPartialPathStitcher::find_minimal_partial_path_set_in_file(
graph,
partials,
file,
stitcher_config.into(),
&AtomicUsizeCancellationFlag(cancellation_flag),
|_graph, partials, path| {
let mut path = path.clone();
Expand All @@ -1210,17 +1214,20 @@ pub extern "C" fn sg_partial_path_arena_find_all_complete_paths(
starting_node_count: usize,
starting_nodes: *const sg_node_handle,
path_list: *mut sg_partial_path_list,
stitcher_config: *const sg_stitcher_config,
cancellation_flag: *const usize,
) -> sg_result {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let starting_nodes = unsafe { std::slice::from_raw_parts(starting_nodes, starting_node_count) };
let stitcher_config = unsafe { *stitcher_config };
let path_list = unsafe { &mut *path_list };
let cancellation_flag: Option<&AtomicUsize> =
unsafe { std::mem::transmute(cancellation_flag.as_ref()) };
ForwardPartialPathStitcher::find_all_complete_partial_paths(
&mut GraphEdgeCandidates::new(graph, partials, None),
starting_nodes.iter().copied().map(sg_node_handle::into),
stitcher_config.into(),
&AtomicUsizeCancellationFlag(cancellation_flag),
|graph, _partials, path| {
if path.is_complete(graph) {
Expand Down Expand Up @@ -1391,6 +1398,20 @@ pub struct sg_forward_partial_path_stitcher {
pub is_complete: bool,
}

// Configuration for partial path stitchers.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct sg_stitcher_config {
/// Enables similar path detection during stiching.
pub detect_similar_paths: bool,
}

impl Into<StitcherConfig> for sg_stitcher_config {
fn into(self) -> StitcherConfig {
StitcherConfig::default().with_detect_similar_paths(self.detect_similar_paths)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this is nice, it means we don't have to #[repr(C)] the Rust type

}
}

// This is the Rust equivalent of a common C trick, where you have two versions of a struct — a
// publicly visible one and a private one containing internal implementation details. In our case,
// `sg_forward_partial_path_stitcher` is the public struct, and
Expand Down
106 changes: 71 additions & 35 deletions stack-graphs/src/stitching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,7 @@ impl<H> ForwardPartialPathStitcher<H> {
initial_paths: next_iteration.0.len(),
next_iteration,
appended_paths,
// By default, all paths are checked for similarity
similar_path_detector: Some(SimilarPathDetector::new()),
// By default, all nodes are checked for cycles and (if enabled) similarity
check_only_join_nodes: false,
Expand All @@ -879,28 +880,6 @@ impl<H> ForwardPartialPathStitcher<H> {
phase_number: 1,
}
}
}

impl<H: Clone> ForwardPartialPathStitcher<H> {
/// Returns an iterator of all of the (possibly incomplete) partial paths that were encountered
/// during the most recent phase of the algorithm.
pub fn previous_phase_partial_paths(&self) -> impl Iterator<Item = &PartialPath> + '_ {
self.next_iteration.0.iter()
}

/// Returns a slice of all of the (possibly incomplete) partial paths that were encountered
/// during the most recent phase of the algorithm.
pub fn previous_phase_partial_paths_slice(&mut self) -> &[PartialPath] {
self.next_iteration.0.make_contiguous();
self.next_iteration.0.as_slices().0
}

/// Returns a mutable slice of all of the (possibly incomplete) partial paths that were
/// encountered during the most recent phase of the algorithm.
pub fn previous_phase_partial_paths_slice_mut(&mut self) -> &mut [PartialPath] {
self.next_iteration.0.make_contiguous();
self.next_iteration.0.as_mut_slices().0
}

/// Sets whether similar path detection should be enabled during path stitching. Paths are similar
/// if start and end node, and pre- and postconditions are the same. The presence of similar paths
Expand Down Expand Up @@ -930,6 +909,28 @@ impl<H: Clone> ForwardPartialPathStitcher<H> {
pub fn set_max_work_per_phase(&mut self, max_work_per_phase: usize) {
self.max_work_per_phase = max_work_per_phase;
}
}

impl<H: Clone> ForwardPartialPathStitcher<H> {
/// Returns an iterator of all of the (possibly incomplete) partial paths that were encountered
/// during the most recent phase of the algorithm.
pub fn previous_phase_partial_paths(&self) -> impl Iterator<Item = &PartialPath> + '_ {
self.next_iteration.0.iter()
}

/// Returns a slice of all of the (possibly incomplete) partial paths that were encountered
/// during the most recent phase of the algorithm.
pub fn previous_phase_partial_paths_slice(&mut self) -> &[PartialPath] {
self.next_iteration.0.make_contiguous();
self.next_iteration.0.as_slices().0
}

/// Returns a mutable slice of all of the (possibly incomplete) partial paths that were
/// encountered during the most recent phase of the algorithm.
pub fn previous_phase_partial_paths_slice_mut(&mut self) -> &mut [PartialPath] {
self.next_iteration.0.make_contiguous();
self.next_iteration.0.as_mut_slices().0
}

/// Attempts to extend one partial path as part of the algorithm. When calling this function,
/// you are responsible for ensuring that `db` already contains all of the possible appendables
Expand Down Expand Up @@ -1145,6 +1146,7 @@ impl ForwardPartialPathStitcher<Edge> {
graph: &StackGraph,
partials: &mut PartialPaths,
file: Handle<File>,
config: StitcherConfig,
cancellation_flag: &dyn CancellationFlag,
mut visit: F,
) -> Result<(), CancellationError>
Expand All @@ -1164,6 +1166,7 @@ impl ForwardPartialPathStitcher<Edge> {
.collect::<Vec<_>>();
let mut stitcher =
ForwardPartialPathStitcher::from_partial_paths(graph, partials, initial_paths);
config.apply(&mut stitcher);
stitcher.set_check_only_join_nodes(true);
while !stitcher.is_complete() {
cancellation_flag.check("finding complete partial paths")?;
Expand Down Expand Up @@ -1196,6 +1199,7 @@ impl<H: Clone> ForwardPartialPathStitcher<H> {
pub fn find_all_complete_partial_paths<I, F, A, Db, C, Err>(
candidates: &mut C,
starting_nodes: I,
config: StitcherConfig,
cancellation_flag: &dyn CancellationFlag,
mut visit: F,
) -> Result<(), Err>
Expand All @@ -1207,19 +1211,19 @@ impl<H: Clone> ForwardPartialPathStitcher<H> {
F: FnMut(&StackGraph, &mut PartialPaths, &PartialPath),
Err: std::convert::From<CancellationError>,
{
let mut stitcher = {
let (graph, partials, _) = candidates.get_graph_partials_and_db();
let initial_paths = starting_nodes
.into_iter()
.filter(|n| graph[*n].is_reference())
.map(|n| {
let mut p = PartialPath::from_node(graph, partials, n);
p.eliminate_precondition_stack_variables(partials);
p
})
.collect::<Vec<_>>();
ForwardPartialPathStitcher::from_partial_paths(graph, partials, initial_paths)
};
let (graph, partials, _) = candidates.get_graph_partials_and_db();
let initial_paths = starting_nodes
.into_iter()
.filter(|n| graph[*n].is_reference())
.map(|n| {
let mut p = PartialPath::from_node(graph, partials, n);
p.eliminate_precondition_stack_variables(partials);
p
})
.collect::<Vec<_>>();
let mut stitcher =
ForwardPartialPathStitcher::from_partial_paths(graph, partials, initial_paths);
config.apply(&mut stitcher);
stitcher.set_check_only_join_nodes(true);
while !stitcher.is_complete() {
cancellation_flag.check("finding complete partial paths")?;
Expand All @@ -1237,3 +1241,35 @@ impl<H: Clone> ForwardPartialPathStitcher<H> {
Ok(())
}
}

/// Configuration for partial path stitchers.
#[derive(Clone, Copy, Debug)]
pub struct StitcherConfig {
/// Enables similar path detection during path stitching.
detect_similar_paths: bool,
}

impl StitcherConfig {
pub fn detect_similar_paths(&self) -> bool {
self.detect_similar_paths
}

pub fn with_detect_similar_paths(mut self, detect_similar_paths: bool) -> Self {
self.detect_similar_paths = detect_similar_paths;
self
}
}

impl StitcherConfig {
fn apply<H>(&self, stitcher: &mut ForwardPartialPathStitcher<H>) {
stitcher.set_similar_path_detection(self.detect_similar_paths);
}
}

impl Default for StitcherConfig {
fn default() -> Self {
Self {
detect_similar_paths: true,
}
}
}
Loading