Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions rust/extractor/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::diagnostics::{ExtractionStep, emit_extraction_diagnostics};
use crate::rust_analyzer::path_to_file_id;
use crate::rust_analyzer::{RustAnalyzerNoSemantics, path_to_file_id};
use crate::translate::{ResolvePaths, SourceKind};
use crate::trap::TrapId;
use anyhow::Context;
Expand Down Expand Up @@ -87,14 +87,12 @@ impl<'a> Extractor<'a> {
translator.emit_parse_error(&ast, &err);
}
let no_location = (LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 });
if let Err(reason) = semantics_info {
if let Err(RustAnalyzerNoSemantics { severity, reason }) = semantics_info {
if !reason.is_empty() {
let message = format!("semantic analyzer unavailable ({reason})");
let full_message = format!(
"{message}: macro expansion, call graph, and type inference will be skipped."
);
let full_message = format!("{message}: macro expansion will be skipped.");
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

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

[nitpick] The message should be consistent with standard punctuation. Consider removing the period at the end for consistency with other diagnostic messages, or ensure all diagnostic messages follow the same punctuation pattern.

Suggested change
let full_message = format!("{message}: macro expansion will be skipped.");
let full_message = format!("{message}: macro expansion will be skipped");

Copilot uses AI. Check for mistakes.
translator.emit_diagnostic(
trap::DiagnosticSeverity::Warning,
severity,
"semantics".to_owned(),
message,
full_message,
Expand Down Expand Up @@ -135,10 +133,10 @@ impl<'a> Extractor<'a> {
&mut self,
file: &Path,
source_kind: SourceKind,
reason: &str,
err: RustAnalyzerNoSemantics,
) {
self.extract(
&RustAnalyzer::WithoutSemantics { reason },
&RustAnalyzer::from(err),
file,
ResolvePaths::No,
source_kind,
Expand All @@ -163,21 +161,25 @@ impl<'a> Extractor<'a> {
file: &Path,
semantics: &Semantics<'_, RootDatabase>,
vfs: &Vfs,
) -> Result<(), String> {
) -> Result<(), RustAnalyzerNoSemantics> {
let before = Instant::now();
let Some(id) = path_to_file_id(file, vfs) else {
return Err("not included in files loaded from manifest".to_string());
return Err(RustAnalyzerNoSemantics::warning(
"not included in files loaded from manifest",
));
};
match semantics.file_to_module_def(id) {
None => return Err("not included as a module".to_string()),
None => {
return Err(RustAnalyzerNoSemantics::info("not included as a module"));
Copy link
Contributor

Choose a reason for hiding this comment

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

So if I'm understanding correctly, this (and the one immediately below) are the bits of this change that affect results - downgrading these warnings to info so that they're no longer output by rust/diagnostics/extraction-warnings (and thus, we believe, won't appear on the status page).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

indeed

}
Some(module)
if module
.as_source_file_id(semantics.db)
.is_none_or(|mod_file_id| mod_file_id.file_id(semantics.db) != id) =>
{
return Err(
"not loaded as its own module, probably included by `!include`".to_string(),
);
return Err(RustAnalyzerNoSemantics::info(
"not loaded as its own module, probably included by `!include`",
));
}
_ => {}
};
Expand Down Expand Up @@ -279,7 +281,11 @@ fn main() -> anyhow::Result<()> {
continue 'outer;
}
}
extractor.extract_without_semantics(file, SourceKind::Source, "no manifest found");
extractor.extract_without_semantics(
file,
SourceKind::Source,
RustAnalyzerNoSemantics::warning("no manifest found"),
);
}
let cwd = cwd()?;
let (cargo_config, load_cargo_config) = cfg.to_cargo_config(&cwd);
Expand Down Expand Up @@ -319,7 +325,7 @@ fn main() -> anyhow::Result<()> {
source_resolve_paths,
source_mode,
),
Err(reason) => extractor.extract_without_semantics(file, source_mode, &reason),
Err(e) => extractor.extract_without_semantics(file, source_mode, e),
};
}
for (file_id, file) in vfs.iter() {
Expand Down Expand Up @@ -347,7 +353,7 @@ fn main() -> anyhow::Result<()> {
extractor.extract_without_semantics(
file,
SourceKind::Source,
"unable to load manifest",
RustAnalyzerNoSemantics::warning("unable to load manifest"),
);
}
}
Expand All @@ -359,7 +365,7 @@ fn main() -> anyhow::Result<()> {
let entry = entry.context("failed to read builtins directory")?;
let path = entry.path();
if path.extension().is_some_and(|ext| ext == "rs") {
extractor.extract_without_semantics(&path, SourceKind::Library, "");
extractor.extract_without_semantics(&path, SourceKind::Library, Default::default());
}
}

Expand Down
63 changes: 52 additions & 11 deletions rust/extractor/src/rust_analyzer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::trap;
use itertools::Itertools;
use ra_ap_base_db::{EditionedFileId, FileText, RootQueryDb, SourceDatabase};
use ra_ap_hir::Semantics;
Expand All @@ -23,16 +24,47 @@ use std::rc::Rc;
use tracing::{debug, error, info, trace, warn};
use triomphe::Arc;

#[derive(Clone, Default)]
pub struct RustAnalyzerNoSemantics {
pub severity: trap::DiagnosticSeverity,
pub reason: &'static str,
}

impl RustAnalyzerNoSemantics {
pub fn warning(reason: &'static str) -> Self {
RustAnalyzerNoSemantics {
severity: trap::DiagnosticSeverity::Warning,
reason,
}
}
pub fn info(reason: &'static str) -> Self {
RustAnalyzerNoSemantics {
severity: trap::DiagnosticSeverity::Info,
reason,
}
}
}

pub enum RustAnalyzer<'a> {
WithSemantics {
vfs: &'a Vfs,
semantics: &'a Semantics<'a, RootDatabase>,
},
WithoutSemantics {
reason: &'a str,
severity: trap::DiagnosticSeverity,
reason: &'static str,
},
}

impl From<RustAnalyzerNoSemantics> for RustAnalyzer<'static> {
fn from(value: RustAnalyzerNoSemantics) -> Self {
RustAnalyzer::WithoutSemantics {
severity: value.severity,
reason: value.reason,
}
}
}

pub struct FileSemanticInformation<'a> {
pub file_id: EditionedFileId,
pub semantics: &'a Semantics<'a, RootDatabase>,
Expand All @@ -42,7 +74,7 @@ pub struct ParseResult<'a> {
pub ast: SourceFile,
pub text: Arc<str>,
pub errors: Vec<SyntaxError>,
pub semantics_info: Result<FileSemanticInformation<'a>, &'a str>,
pub semantics_info: Result<FileSemanticInformation<'a>, RustAnalyzerNoSemantics>,
}

impl<'a> RustAnalyzer<'a> {
Expand All @@ -52,7 +84,7 @@ impl<'a> RustAnalyzer<'a> {
load_config: &LoadCargoConfig,
) -> Option<(RootDatabase, Vfs)> {
let progress = |t| trace!("progress: {t}");
let manifest = project.manifest_path();
let manifest: &ManifestPath = project.manifest_path();
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

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

[nitpick] This explicit type annotation is unnecessary since the type can be inferred from context. Consider removing it to reduce code noise.

Suggested change
let manifest: &ManifestPath = project.manifest_path();
let manifest = project.manifest_path();

Copilot uses AI. Check for mistakes.
match load_workspace_at(manifest.as_ref(), config, load_config, &progress) {
Ok((db, vfs, _macro_server)) => Some((db, vfs)),
Err(err) => {
Expand All @@ -67,16 +99,25 @@ impl<'a> RustAnalyzer<'a> {
fn get_file_data(
&self,
path: &Path,
) -> Result<(&Semantics<'_, RootDatabase>, EditionedFileId, FileText), &str> {
) -> Result<(&Semantics<'_, RootDatabase>, EditionedFileId, FileText), RustAnalyzerNoSemantics>
{
match self {
RustAnalyzer::WithoutSemantics { reason } => Err(reason),
RustAnalyzer::WithoutSemantics { severity, reason } => Err(RustAnalyzerNoSemantics {
severity: *severity,
reason,
}),
RustAnalyzer::WithSemantics { vfs, semantics } => {
let file_id = path_to_file_id(path, vfs).ok_or("file not found in project")?;
let input = std::panic::catch_unwind(|| semantics.db.file_text(file_id))
.or(Err("no text available for the file in the project"))?;
let editioned_file_id = semantics
.attach_first_edition(file_id)
.ok_or("failed to determine rust edition")?;
let file_id = path_to_file_id(path, vfs).ok_or(
RustAnalyzerNoSemantics::warning("file not found in project"),
)?;
let input = std::panic::catch_unwind(|| semantics.db.file_text(file_id)).or(
Err(RustAnalyzerNoSemantics::warning(
"no text available for the file in the project",
)),
)?;
let editioned_file_id = semantics.attach_first_edition(file_id).ok_or(
RustAnalyzerNoSemantics::warning("failed to determine rust edition"),
)?;
Ok((semantics, editioned_file_id, input))
}
}
Expand Down
2 changes: 1 addition & 1 deletion rust/extractor/src/translate/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ impl<'a> Translator<'a> {
mcall,
&SyntaxError::new(
format!(
"macro expansion failed: could not resolve macro '{}'",
"macro expansion failed for '{}'",
mcall.path().map(|p| p.to_string()).unwrap_or_default()
),
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),
Expand Down
3 changes: 2 additions & 1 deletion rust/extractor/src/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,10 @@ pub struct TrapFile {
compression: Compression,
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum DiagnosticSeverity {
Debug = 10,
#[default]
Info = 20,
Warning = 30,
Error = 40,
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
| src/directory_module/not_loaded.rs:1:1:1:1 | semantic analyzer unavailable (not included as a module) | Extraction warning in src/directory_module/not_loaded.rs with message semantic analyzer unavailable (not included as a module) | 1 |
8 changes: 4 additions & 4 deletions rust/ql/integration-tests/hello-project/summary.expected
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
| Extraction errors | 0 |
| Extraction warnings | 1 |
| Extraction warnings | 0 |
| Files extracted - total | 5 |
| Files extracted - with errors | 1 |
| Files extracted - without errors | 4 |
| Files extracted - without errors % | 80 |
| Files extracted - with errors | 0 |
| Files extracted - without errors | 5 |
| Files extracted - without errors % | 100 |
| Inconsistencies - AST | 0 |
| Inconsistencies - CFG | 0 |
| Inconsistencies - Path resolution | 0 |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
extractionWarning
| included/included.rs:1:1:1:1 | semantic analyzer unavailable (not loaded as its own module, probably included by `!include`) |
| macro_expansion.rs:56:9:56:31 | macro expansion failed: could not resolve macro 'concat' |
| macro_expansion.rs:56:9:56:31 | macro expansion failed for 'concat' |
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,4 @@ unexpanded_macro_calls
| macro_expansion.rs:56:9:56:31 | concat!... |
| macro_expansion.rs:63:9:63:32 | include_str!... |
warnings
| included/included.rs:1:1:1:1 | semantic analyzer unavailable (not loaded as its own module, probably included by `!include`) |
| macro_expansion.rs:56:9:56:31 | macro expansion failed: could not resolve macro 'concat' |
| macro_expansion.rs:56:9:56:31 | macro expansion failed for 'concat' |

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ extractionWarning
| does_not_compile.rs:2:21:2:20 | expected SEMICOLON |
| does_not_compile.rs:2:26:2:25 | expected SEMICOLON |
| error.rs:2:5:2:17 | An error! |
| my_macro.rs:17:9:17:27 | macro expansion failed: could not resolve macro 'myUndefinedMacro' |
| my_macro.rs:17:9:17:27 | macro expansion failed for 'myUndefinedMacro' |
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
| does_not_compile.rs:2:21:2:20 | expected SEMICOLON | Extraction warning in does_not_compile.rs with message expected SEMICOLON | 1 |
| does_not_compile.rs:2:26:2:25 | expected SEMICOLON | Extraction warning in does_not_compile.rs with message expected SEMICOLON | 1 |
| error.rs:2:5:2:17 | An error! | Extraction warning in error.rs with message An error! | 1 |
| my_macro.rs:17:9:17:27 | macro expansion failed: could not resolve macro 'myUndefinedMacro' | Extraction warning in my_macro.rs with message macro expansion failed: could not resolve macro 'myUndefinedMacro' | 1 |
| my_macro.rs:17:9:17:27 | macro expansion failed for 'myUndefinedMacro' | Extraction warning in my_macro.rs with message macro expansion failed for 'myUndefinedMacro' | 1 |

This file was deleted.