diff --git a/rust/extractor/src/rust_analyzer.rs b/rust/extractor/src/rust_analyzer.rs index d79d20b4142f..ef4c638efbe6 100644 --- a/rust/extractor/src/rust_analyzer.rs +++ b/rust/extractor/src/rust_analyzer.rs @@ -1,5 +1,5 @@ use itertools::Itertools; -use ra_ap_base_db::{EditionedFileId, RootQueryDb, SourceDatabase}; +use ra_ap_base_db::{EditionedFileId, FileText, RootQueryDb, SourceDatabase}; use ra_ap_hir::Semantics; use ra_ap_ide_db::RootDatabase; use ra_ap_load_cargo::{LoadCargoConfig, load_workspace_at}; @@ -7,7 +7,6 @@ use ra_ap_paths::{AbsPath, Utf8PathBuf}; use ra_ap_project_model::ProjectManifest; use ra_ap_project_model::{CargoConfig, ManifestPath}; use ra_ap_span::Edition; -use ra_ap_span::EditionedFileId as SpanEditionedFileId; use ra_ap_span::TextRange; use ra_ap_span::TextSize; use ra_ap_syntax::SourceFile; @@ -54,7 +53,6 @@ impl<'a> RustAnalyzer<'a> { ) -> Option<(RootDatabase, Vfs)> { let progress = |t| (trace!("progress: {}", t)); let manifest = project.manifest_path(); - match load_workspace_at(manifest.as_ref(), config, load_config, &progress) { Ok((db, vfs, _macro_server)) => Some((db, vfs)), Err(err) => { @@ -66,67 +64,70 @@ impl<'a> RustAnalyzer<'a> { pub fn new(vfs: &'a Vfs, semantics: &'a Semantics<'a, RootDatabase>) -> Self { RustAnalyzer::WithSemantics { vfs, semantics } } - pub fn parse(&self, path: &Path) -> ParseResult { - let no_semantics_reason; + fn get_file_data( + &self, + path: &Path, + ) -> Result<(&Semantics, EditionedFileId, FileText), &str> { match self { + RustAnalyzer::WithoutSemantics { reason } => Err(reason), RustAnalyzer::WithSemantics { vfs, semantics } => { - if let Some(file_id) = path_to_file_id(path, vfs) { - if let Ok(input) = std::panic::catch_unwind(|| semantics.db.file_text(file_id)) - { - let file_id = EditionedFileId::new( - semantics.db, - SpanEditionedFileId::current_edition(file_id), - ); - let source_file = semantics.parse(file_id); - let errors = semantics - .db - .parse_errors(file_id) - .into_iter() - .flat_map(|x| x.to_vec()) - .collect(); - - return ParseResult { - ast: source_file, - text: input.text(semantics.db), - errors, - semantics_info: Ok(FileSemanticInformation { file_id, semantics }), - }; - } - debug!( - "No text available for file_id '{:?}', falling back to loading file '{}' from disk.", - file_id, - path.to_string_lossy() - ); - no_semantics_reason = "no text available for the file in the project"; - } else { - no_semantics_reason = "file not found in project"; - } - } - RustAnalyzer::WithoutSemantics { reason } => { - no_semantics_reason = reason; + 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")?; + Ok(( + semantics, + EditionedFileId::new(semantics.db, editioned_file_id), + input, + )) } } - let mut errors = Vec::new(); - let input = match std::fs::read(path) { - Ok(data) => data, - Err(e) => { - errors.push(SyntaxError::new( - format!("Could not read {}: {}", path.to_string_lossy(), e), - TextRange::empty(TextSize::default()), - )); - vec![] + } + + pub fn parse(&self, path: &Path) -> ParseResult { + match self.get_file_data(path) { + Ok((semantics, file_id, input)) => { + let source_file = semantics.parse(file_id); + let errors = semantics + .db + .parse_errors(file_id) + .into_iter() + .flat_map(|x| x.to_vec()) + .collect(); + + ParseResult { + ast: source_file, + text: input.text(semantics.db), + errors, + semantics_info: Ok(FileSemanticInformation { file_id, semantics }), + } } - }; - let (input, err) = from_utf8_lossy(&input); + Err(reason) => { + let mut errors = Vec::new(); + let input = match std::fs::read(path) { + Ok(data) => data, + Err(e) => { + errors.push(SyntaxError::new( + format!("Could not read {}: {}", path.to_string_lossy(), e), + TextRange::empty(TextSize::default()), + )); + vec![] + } + }; + let (input, err) = from_utf8_lossy(&input); - let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT); - errors.extend(parse.errors()); - errors.extend(err); - ParseResult { - ast: parse.tree(), - text: input.as_ref().into(), - errors, - semantics_info: Err(no_semantics_reason), + let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT); + errors.extend(parse.errors()); + errors.extend(err); + ParseResult { + ast: parse.tree(), + text: input.as_ref().into(), + errors, + semantics_info: Err(reason), + } + } } } } diff --git a/rust/ql/integration-tests/conftest.py b/rust/ql/integration-tests/conftest.py index a1fbcf4e18d2..578a81a849a9 100644 --- a/rust/ql/integration-tests/conftest.py +++ b/rust/ql/integration-tests/conftest.py @@ -2,13 +2,35 @@ import json import commands import pathlib +import tomllib + + +@pytest.fixture(params=[2018, 2021, 2024]) +def rust_edition(request): + return request.param @pytest.fixture -def cargo(cwd): - assert (cwd / "Cargo.toml").exists() +def cargo(cwd, rust_edition): + manifest_file = cwd / "Cargo.toml" + assert manifest_file.exists() (cwd / "rust-project.json").unlink(missing_ok=True) + def update(file): + contents = file.read_text() + m = tomllib.loads(contents) + if 'package' in m: + # tomllib does not support writing, and we don't want to use further dependencies + # so we just do a dumb search and replace + contents = contents.replace(f'edition = "{m["package"]["edition"]}"', f'edition = "{rust_edition}"') + file.write_text(contents) + if 'members' in m.get('workspace', ()): + for member in m['workspace']['members']: + update(file.parent / member / "Cargo.toml") + + update(manifest_file) + + @pytest.fixture(scope="session") def rust_sysroot_src() -> str: rust_sysroot = pathlib.Path(commands.run("rustc --print sysroot", _capture=True)) @@ -16,15 +38,19 @@ def rust_sysroot_src() -> str: assert ret.exists() return str(ret) + @pytest.fixture -def rust_project(cwd, rust_sysroot_src): +def rust_project(cwd, rust_sysroot_src, rust_edition): project_file = cwd / "rust-project.json" assert project_file.exists() project = json.loads(project_file.read_text()) project["sysroot_src"] = rust_sysroot_src + for c in project["crates"]: + c["edition"] = str(rust_edition) project_file.write_text(json.dumps(project, indent=4)) (cwd / "Cargo.toml").unlink(missing_ok=True) + @pytest.fixture def rust_check_diagnostics(check_diagnostics): check_diagnostics.redact += [ diff --git a/rust/ql/integration-tests/hello-project/Cargo.toml b/rust/ql/integration-tests/hello-project/Cargo.toml index 909b5b525ff3..7ad4f694f489 100644 --- a/rust/ql/integration-tests/hello-project/Cargo.toml +++ b/rust/ql/integration-tests/hello-project/Cargo.toml @@ -2,6 +2,6 @@ [package] name = "hello-cargo" version = "0.1.0" -edition = "2021" +edition = "2021" # replaced in test [dependencies] diff --git a/rust/ql/integration-tests/hello-[workspace]/Cargo.toml b/rust/ql/integration-tests/hello-workspace/Cargo.toml similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/Cargo.toml rename to rust/ql/integration-tests/hello-workspace/Cargo.toml diff --git a/rust/ql/integration-tests/hello-[workspace]/ExtractionErrors.expected b/rust/ql/integration-tests/hello-workspace/ExtractionErrors.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/ExtractionErrors.expected rename to rust/ql/integration-tests/hello-workspace/ExtractionErrors.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/ExtractionErrors.qlref b/rust/ql/integration-tests/hello-workspace/ExtractionErrors.qlref similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/ExtractionErrors.qlref rename to rust/ql/integration-tests/hello-workspace/ExtractionErrors.qlref diff --git a/rust/ql/integration-tests/hello-[workspace]/ExtractionWarnings.expected b/rust/ql/integration-tests/hello-workspace/ExtractionWarnings.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/ExtractionWarnings.expected rename to rust/ql/integration-tests/hello-workspace/ExtractionWarnings.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/ExtractionWarnings.qlref b/rust/ql/integration-tests/hello-workspace/ExtractionWarnings.qlref similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/ExtractionWarnings.qlref rename to rust/ql/integration-tests/hello-workspace/ExtractionWarnings.qlref diff --git a/rust/ql/integration-tests/hello-[workspace]/diagnostics.cargo.expected b/rust/ql/integration-tests/hello-workspace/diagnostics.cargo.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/diagnostics.cargo.expected rename to rust/ql/integration-tests/hello-workspace/diagnostics.cargo.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/diagnostics.rust-project.expected b/rust/ql/integration-tests/hello-workspace/diagnostics.rust-project.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/diagnostics.rust-project.expected rename to rust/ql/integration-tests/hello-workspace/diagnostics.rust-project.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/exe/Cargo.toml b/rust/ql/integration-tests/hello-workspace/exe/Cargo.toml similarity index 69% rename from rust/ql/integration-tests/hello-[workspace]/exe/Cargo.toml rename to rust/ql/integration-tests/hello-workspace/exe/Cargo.toml index b63ccfd5da54..4d9a0e543070 100644 --- a/rust/ql/integration-tests/hello-[workspace]/exe/Cargo.toml +++ b/rust/ql/integration-tests/hello-workspace/exe/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "exe" version = "0.1.0" -edition = "2021" +edition = "2021" # replaced in test [dependencies] lib = { path = "../lib" } diff --git a/rust/ql/integration-tests/hello-[workspace]/exe/src/a_module.rs b/rust/ql/integration-tests/hello-workspace/exe/src/a_module.rs similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/exe/src/a_module.rs rename to rust/ql/integration-tests/hello-workspace/exe/src/a_module.rs diff --git a/rust/ql/integration-tests/hello-[workspace]/exe/src/main.rs b/rust/ql/integration-tests/hello-workspace/exe/src/main.rs similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/exe/src/main.rs rename to rust/ql/integration-tests/hello-workspace/exe/src/main.rs diff --git a/rust/ql/integration-tests/hello-[workspace]/functions.expected b/rust/ql/integration-tests/hello-workspace/functions.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/functions.expected rename to rust/ql/integration-tests/hello-workspace/functions.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/functions.ql b/rust/ql/integration-tests/hello-workspace/functions.ql similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/functions.ql rename to rust/ql/integration-tests/hello-workspace/functions.ql diff --git a/rust/ql/integration-tests/hello-[workspace]/lib/Cargo.toml b/rust/ql/integration-tests/hello-workspace/lib/Cargo.toml similarity index 60% rename from rust/ql/integration-tests/hello-[workspace]/lib/Cargo.toml rename to rust/ql/integration-tests/hello-workspace/lib/Cargo.toml index e8fc5405b71f..9d59bf133d3c 100644 --- a/rust/ql/integration-tests/hello-[workspace]/lib/Cargo.toml +++ b/rust/ql/integration-tests/hello-workspace/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lib" version = "0.1.0" -edition = "2021" +edition = "2021" # replaced in test [dependencies] diff --git a/rust/ql/integration-tests/hello-[workspace]/lib/src/a_module/mod.rs b/rust/ql/integration-tests/hello-workspace/lib/src/a_module/mod.rs similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/lib/src/a_module/mod.rs rename to rust/ql/integration-tests/hello-workspace/lib/src/a_module/mod.rs diff --git a/rust/ql/integration-tests/hello-[workspace]/lib/src/lib.rs b/rust/ql/integration-tests/hello-workspace/lib/src/lib.rs similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/lib/src/lib.rs rename to rust/ql/integration-tests/hello-workspace/lib/src/lib.rs diff --git a/rust/ql/integration-tests/hello-[workspace]/path-resolution.expected b/rust/ql/integration-tests/hello-workspace/path-resolution.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/path-resolution.expected rename to rust/ql/integration-tests/hello-workspace/path-resolution.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/path-resolution.ql b/rust/ql/integration-tests/hello-workspace/path-resolution.ql similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/path-resolution.ql rename to rust/ql/integration-tests/hello-workspace/path-resolution.ql diff --git a/rust/ql/integration-tests/hello-[workspace]/rust-project.json b/rust/ql/integration-tests/hello-workspace/rust-project.json similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/rust-project.json rename to rust/ql/integration-tests/hello-workspace/rust-project.json diff --git a/rust/ql/integration-tests/hello-[workspace]/source_archive.expected b/rust/ql/integration-tests/hello-workspace/source_archive.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/source_archive.expected rename to rust/ql/integration-tests/hello-workspace/source_archive.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/steps.cargo.expected b/rust/ql/integration-tests/hello-workspace/steps.cargo.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/steps.cargo.expected rename to rust/ql/integration-tests/hello-workspace/steps.cargo.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/steps.ql b/rust/ql/integration-tests/hello-workspace/steps.ql similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/steps.ql rename to rust/ql/integration-tests/hello-workspace/steps.ql diff --git a/rust/ql/integration-tests/hello-[workspace]/steps.rust-project.expected b/rust/ql/integration-tests/hello-workspace/steps.rust-project.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/steps.rust-project.expected rename to rust/ql/integration-tests/hello-workspace/steps.rust-project.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/summary.cargo.expected b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/summary.cargo.expected rename to rust/ql/integration-tests/hello-workspace/summary.cargo.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/summary.qlref b/rust/ql/integration-tests/hello-workspace/summary.qlref similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/summary.qlref rename to rust/ql/integration-tests/hello-workspace/summary.qlref diff --git a/rust/ql/integration-tests/hello-[workspace]/summary.rust-project.expected b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected similarity index 100% rename from rust/ql/integration-tests/hello-[workspace]/summary.rust-project.expected rename to rust/ql/integration-tests/hello-workspace/summary.rust-project.expected diff --git a/rust/ql/integration-tests/hello-[workspace]/test_workspace.py b/rust/ql/integration-tests/hello-workspace/test_workspace.py similarity index 99% rename from rust/ql/integration-tests/hello-[workspace]/test_workspace.py rename to rust/ql/integration-tests/hello-workspace/test_workspace.py index fe8dbc69141c..acf46b70aa64 100644 --- a/rust/ql/integration-tests/hello-[workspace]/test_workspace.py +++ b/rust/ql/integration-tests/hello-workspace/test_workspace.py @@ -1,6 +1,5 @@ import pytest - @pytest.mark.ql_test("steps.ql", expected=".cargo.expected") @pytest.mark.ql_test("summary.qlref", expected=".cargo.expected") def test_cargo(codeql, rust, cargo, check_source_archive, rust_check_diagnostics):