Skip to content

Commit 868614b

Browse files
Merge pull request #261 from github/index-special-files
Ensure special files are also indexed
2 parents 095c2af + 43d6595 commit 868614b

File tree

7 files changed

+213
-95
lines changed

7 files changed

+213
-95
lines changed

tree-sitter-stack-graphs/src/cli/index.rs

Lines changed: 81 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
use clap::Args;
99
use clap::ValueHint;
10+
use stack_graphs::arena::Handle;
11+
use stack_graphs::graph::File;
1012
use stack_graphs::graph::StackGraph;
1113
use stack_graphs::partial::PartialPaths;
1214
use stack_graphs::storage::FileStatus;
@@ -18,6 +20,7 @@ use std::time::Duration;
1820
use thiserror::Error;
1921
use tree_sitter_graph::Variables;
2022

23+
use crate::loader::FileLanguageConfigurations;
2124
use crate::loader::FileReader;
2225
use crate::loader::Loader;
2326
use crate::BuildError;
@@ -29,6 +32,7 @@ use super::util::duration_from_seconds_str;
2932
use super::util::iter_files_and_directories;
3033
use super::util::sha1;
3134
use super::util::wait_for_input;
35+
use super::util::BuildErrorWithSource;
3236
use super::util::ConsoleLogger;
3337
use super::util::ExistingPathBufValueParser;
3438
use super::util::FileLogger;
@@ -219,23 +223,24 @@ impl<'a> Indexer<'a> {
219223
}
220224

221225
let mut file_reader = FileReader::new();
222-
let lc = match self
226+
let lcs = match self
223227
.loader
224228
.load_for_file(source_path, &mut file_reader, &NoCancellation)
225229
{
226-
Ok(Some(sgl)) => sgl,
227-
Ok(None) => {
230+
Ok(lcs) if !lcs.has_some() => {
228231
if missing_is_error {
229232
file_status.failure("not supported", None);
230233
}
231234
return Ok(());
232235
}
236+
Ok(lcs) => lcs,
233237
Err(crate::loader::LoadError::Cancelled(_)) => {
234238
file_status.warning("language loading timed out", None);
235239
return Ok(());
236240
}
237241
Err(e) => return Err(IndexError::LoadError(e)),
238242
};
243+
239244
let source = file_reader.get(source_path)?;
240245
let tag = sha1(source);
241246

@@ -264,64 +269,39 @@ impl<'a> Indexer<'a> {
264269
let mut graph = StackGraph::new();
265270
let file = graph
266271
.add_file(&source_path.to_string_lossy())
267-
.expect("file not present in emtpy graph");
272+
.expect("file not present in empty graph");
268273

269-
let relative_source_path = source_path.strip_prefix(source_root).unwrap();
270-
let result = if let Some(fa) = source_path
271-
.file_name()
272-
.and_then(|f| lc.special_files.get(&f.to_string_lossy()))
273-
{
274-
fa.build_stack_graph_into(
275-
&mut graph,
276-
file,
277-
&relative_source_path,
278-
&source,
279-
&mut std::iter::empty(),
280-
&HashMap::new(),
281-
&cancellation_flag,
282-
)
283-
} else {
284-
let globals = Variables::new();
285-
lc.sgl
286-
.build_stack_graph_into(&mut graph, file, &source, &globals, &cancellation_flag)
287-
};
288-
match result {
289-
Err(BuildError::Cancelled(_)) => {
290-
file_status.warning("parsing timed out", None);
291-
self.db
292-
.store_error_for_file(source_path, &tag, "parsing timed out")?;
293-
return Ok(());
294-
}
295-
Err(err @ BuildError::ParseErrors(_)) => {
296-
file_status.failure(
297-
"parsing failed",
298-
Some(&err.display_pretty(
299-
source_path,
300-
source,
301-
lc.sgl.tsg_path(),
302-
lc.sgl.tsg_source(),
303-
)),
304-
);
305-
self.db.store_error_for_file(
306-
source_path,
307-
&tag,
308-
&format!("parsing failed: {}", err),
309-
)?;
310-
return Ok(());
311-
}
312-
Err(err) => {
313-
file_status.failure(
314-
"failed to build stack graph",
315-
Some(&err.display_pretty(
274+
let result = Self::build_stack_graph(
275+
&mut graph,
276+
file,
277+
source_root,
278+
source_path,
279+
&source,
280+
lcs,
281+
&cancellation_flag,
282+
);
283+
if let Err(err) = result {
284+
match err.inner {
285+
BuildError::Cancelled(_) => {
286+
file_status.warning("parsing timed out", None);
287+
self.db
288+
.store_error_for_file(source_path, &tag, "parsing timed out")?;
289+
return Ok(());
290+
}
291+
BuildError::ParseErrors { .. } => {
292+
file_status.failure("parsing failed", Some(&err.display_pretty()));
293+
self.db.store_error_for_file(
316294
source_path,
317-
source,
318-
lc.sgl.tsg_path(),
319-
lc.sgl.tsg_source(),
320-
)),
321-
);
322-
return Err(IndexError::StackGraph);
295+
&tag,
296+
&format!("parsing failed: {}", err.inner),
297+
)?;
298+
return Ok(());
299+
}
300+
_ => {
301+
file_status.failure("failed to build stack graph", Some(&err.display_pretty()));
302+
return Err(IndexError::StackGraph);
303+
}
323304
}
324-
Ok(_) => true,
325305
};
326306

327307
let mut partials = PartialPaths::new();
@@ -354,6 +334,49 @@ impl<'a> Indexer<'a> {
354334
Ok(())
355335
}
356336

337+
fn build_stack_graph<'b>(
338+
graph: &mut StackGraph,
339+
file: Handle<File>,
340+
source_root: &Path,
341+
source_path: &Path,
342+
source: &'b str,
343+
lcs: FileLanguageConfigurations<'b>,
344+
cancellation_flag: &dyn CancellationFlag,
345+
) -> std::result::Result<(), BuildErrorWithSource<'b>> {
346+
let relative_source_path = source_path.strip_prefix(source_root).unwrap();
347+
if let Some(lc) = lcs.primary {
348+
let globals = Variables::new();
349+
lc.sgl
350+
.build_stack_graph_into(graph, file, source, &globals, cancellation_flag)
351+
.map_err(|inner| BuildErrorWithSource {
352+
inner,
353+
source_path: source_path.to_path_buf(),
354+
source_str: source,
355+
tsg_path: lc.sgl.tsg_path().to_path_buf(),
356+
tsg_str: &lc.sgl.tsg_source(),
357+
})?;
358+
}
359+
for (_, fa) in lcs.secondary {
360+
fa.build_stack_graph_into(
361+
graph,
362+
file,
363+
&relative_source_path,
364+
&source,
365+
&mut std::iter::empty(),
366+
&HashMap::new(),
367+
cancellation_flag,
368+
)
369+
.map_err(|inner| BuildErrorWithSource {
370+
inner,
371+
source_path: source_path.to_path_buf(),
372+
source_str: &source,
373+
tsg_path: PathBuf::new(),
374+
tsg_str: "",
375+
})?;
376+
}
377+
Ok(())
378+
}
379+
357380
/// Determines if a path should be skipped because we have not seen the
358381
/// continue_from mark yet. If the mark is seen, it is cleared, after which
359382
/// all paths are accepted.

tree-sitter-stack-graphs/src/cli/match.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ pub struct MatchArgs {
4141
impl MatchArgs {
4242
pub fn run(self, mut loader: Loader) -> anyhow::Result<()> {
4343
let mut file_reader = FileReader::new();
44-
let lc = match loader.load_for_file(&self.source_path, &mut file_reader, &NoCancellation)? {
44+
let lc = match loader
45+
.load_for_file(&self.source_path, &mut file_reader, &NoCancellation)?
46+
.primary
47+
{
4548
Some(lc) => lc,
4649
None => return Err(anyhow!("No stack graph language found")),
4750
};

tree-sitter-stack-graphs/src/cli/test.rs

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::CancellationFlag;
3333
use crate::NoCancellation;
3434

3535
use super::util::iter_files_and_directories;
36+
use super::util::BuildErrorWithSource;
3637
use super::util::ConsoleFileLogger;
3738
use super::util::FileLogger;
3839

@@ -206,8 +207,11 @@ impl TestArgs {
206207
test_path.to_path_buf()
207208
};
208209
let mut file_reader = MappingFileReader::new(&load_path, test_path);
209-
let lc = match loader.load_for_file(&load_path, &mut file_reader, cancellation_flag)? {
210-
Some(sgl) => sgl,
210+
let lc = match loader
211+
.load_for_file(&load_path, &mut file_reader, cancellation_flag)?
212+
.primary
213+
{
214+
Some(lc) => lc,
211215
None => return Ok(TestResult::new()),
212216
};
213217

@@ -236,7 +240,7 @@ impl TestArgs {
236240
let result = if let Some(fa) = test_fragment
237241
.path
238242
.file_name()
239-
.and_then(|f| lc.special_files.get(&f.to_string_lossy()))
243+
.and_then(|file_name| lc.special_files.get(&file_name.to_string_lossy()))
240244
{
241245
let mut all_paths = test.fragments.iter().map(|f| f.path.as_path());
242246
fa.build_stack_graph_into(
@@ -248,19 +252,34 @@ impl TestArgs {
248252
&test_fragment.globals,
249253
cancellation_flag,
250254
)
255+
.map_err(|inner| BuildErrorWithSource {
256+
inner,
257+
source_path: test_path.to_path_buf(),
258+
source_str: &test_fragment.source,
259+
tsg_path: PathBuf::new(),
260+
tsg_str: "",
261+
})
251262
} else if lc.matches_file(
252263
&test_fragment.path,
253264
&mut Some(test_fragment.source.as_ref()),
254265
)? {
255266
globals.clear();
256267
test_fragment.add_globals_to(&mut globals);
257-
lc.sgl.build_stack_graph_into(
258-
&mut test.graph,
259-
test_fragment.file,
260-
&test_fragment.source,
261-
&globals,
262-
cancellation_flag,
263-
)
268+
lc.sgl
269+
.build_stack_graph_into(
270+
&mut test.graph,
271+
test_fragment.file,
272+
&test_fragment.source,
273+
&globals,
274+
cancellation_flag,
275+
)
276+
.map_err(|inner| BuildErrorWithSource {
277+
inner,
278+
source_path: test_path.to_path_buf(),
279+
source_str: &test_fragment.source,
280+
tsg_path: lc.sgl.tsg_path().to_path_buf(),
281+
tsg_str: &lc.sgl.tsg_source(),
282+
})
264283
} else {
265284
return Err(anyhow!(
266285
"Test fragment {} not supported by language of test file {}",
@@ -270,15 +289,7 @@ impl TestArgs {
270289
};
271290
match result {
272291
Err(err) => {
273-
file_status.failure(
274-
"failed to build stack graph",
275-
Some(&err.display_pretty(
276-
test_path,
277-
source,
278-
lc.sgl.tsg_path(),
279-
lc.sgl.tsg_source(),
280-
)),
281-
);
292+
file_status.failure("failed to build stack graph", Some(&err.display_pretty()));
282293
return Err(anyhow!("Failed to build graph for {}", test_path.display()));
283294
}
284295
Ok(_) => {}

tree-sitter-stack-graphs/src/cli/util.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,3 +546,35 @@ pub fn wait_for_input() -> anyhow::Result<()> {
546546
std::io::stdin().read_line(&mut input)?;
547547
Ok(())
548548
}
549+
550+
/// Wraps a build error with the relevant sources
551+
pub struct BuildErrorWithSource<'a> {
552+
pub inner: crate::BuildError,
553+
pub source_path: PathBuf,
554+
pub source_str: &'a str,
555+
pub tsg_path: PathBuf,
556+
pub tsg_str: &'a str,
557+
}
558+
559+
impl<'a> BuildErrorWithSource<'a> {
560+
pub fn display_pretty(&'a self) -> impl std::fmt::Display + 'a {
561+
DisplayBuildErrorPretty(self)
562+
}
563+
}
564+
565+
struct DisplayBuildErrorPretty<'a>(&'a BuildErrorWithSource<'a>);
566+
567+
impl std::fmt::Display for DisplayBuildErrorPretty<'_> {
568+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
569+
write!(
570+
f,
571+
"{}",
572+
self.0.inner.display_pretty(
573+
&self.0.source_path,
574+
self.0.source_str,
575+
&self.0.tsg_path,
576+
self.0.tsg_str,
577+
)
578+
)
579+
}
580+
}

tree-sitter-stack-graphs/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,9 @@ impl<'a> Builder<'a> {
11801180
}
11811181

11821182
pub trait FileAnalyzer {
1183+
/// Construct stack graph for the given file. Implementations must assume that nodes
1184+
/// for the given file may already exist, and make sure to prevent node id conflicts,
1185+
/// for example by using `StackGraph::new_node_id`.
11831186
fn build_stack_graph_into<'a>(
11841187
&self,
11851188
stack_graph: &mut StackGraph,

0 commit comments

Comments
 (0)