mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Rust: add flag to turn off extractor path resolution
This commit is contained in:
@@ -78,3 +78,7 @@ options:
|
|||||||
Collect flame graph data using the `tracing-flame` crate. To render a flame graph
|
Collect flame graph data using the `tracing-flame` crate. To render a flame graph
|
||||||
or chart, run the `inferno-flamegraph` command. See also: https://crates.io/crates/tracing-flame
|
or chart, run the `inferno-flamegraph` command. See also: https://crates.io/crates/tracing-flame
|
||||||
type: string
|
type: string
|
||||||
|
skip_path_resolution:
|
||||||
|
title: Skip path resolution
|
||||||
|
description: >
|
||||||
|
Skip path resolution. This is experimental, while we move path resolution from the extractor to the QL library.
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ pub struct Config {
|
|||||||
pub qltest: bool,
|
pub qltest: bool,
|
||||||
pub qltest_cargo_check: bool,
|
pub qltest_cargo_check: bool,
|
||||||
pub qltest_dependencies: Vec<String>,
|
pub qltest_dependencies: Vec<String>,
|
||||||
|
pub skip_path_resolution: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::diagnostics::{emit_extraction_diagnostics, ExtractionStep};
|
use crate::diagnostics::{emit_extraction_diagnostics, ExtractionStep};
|
||||||
use crate::rust_analyzer::path_to_file_id;
|
use crate::rust_analyzer::path_to_file_id;
|
||||||
|
use crate::translate::ResolvePaths;
|
||||||
use crate::trap::TrapId;
|
use crate::trap::TrapId;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use archive::Archiver;
|
use archive::Archiver;
|
||||||
@@ -43,7 +44,7 @@ impl<'a> Extractor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract(&mut self, rust_analyzer: &rust_analyzer::RustAnalyzer, file: &std::path::Path) {
|
fn extract(&mut self, rust_analyzer: &RustAnalyzer, file: &Path, resolve_paths: ResolvePaths) {
|
||||||
self.archiver.archive(file);
|
self.archiver.archive(file);
|
||||||
|
|
||||||
let before_parse = Instant::now();
|
let before_parse = Instant::now();
|
||||||
@@ -66,6 +67,7 @@ impl<'a> Extractor<'a> {
|
|||||||
label,
|
label,
|
||||||
line_index,
|
line_index,
|
||||||
semantics_info.as_ref().ok(),
|
semantics_info.as_ref().ok(),
|
||||||
|
resolve_paths,
|
||||||
);
|
);
|
||||||
|
|
||||||
for err in errors {
|
for err in errors {
|
||||||
@@ -102,12 +104,17 @@ impl<'a> Extractor<'a> {
|
|||||||
file: &Path,
|
file: &Path,
|
||||||
semantics: &Semantics<'_, RootDatabase>,
|
semantics: &Semantics<'_, RootDatabase>,
|
||||||
vfs: &Vfs,
|
vfs: &Vfs,
|
||||||
|
resolve_paths: ResolvePaths,
|
||||||
) {
|
) {
|
||||||
self.extract(&RustAnalyzer::new(vfs, semantics), file);
|
self.extract(&RustAnalyzer::new(vfs, semantics), file, resolve_paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_without_semantics(&mut self, file: &Path, reason: &str) {
|
pub fn extract_without_semantics(&mut self, file: &Path, reason: &str) {
|
||||||
self.extract(&RustAnalyzer::WithoutSemantics { reason }, file);
|
self.extract(
|
||||||
|
&RustAnalyzer::WithoutSemantics { reason },
|
||||||
|
file,
|
||||||
|
ResolvePaths::No,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_manifest(
|
pub fn load_manifest(
|
||||||
@@ -236,12 +243,19 @@ fn main() -> anyhow::Result<()> {
|
|||||||
extractor.extract_without_semantics(file, "no manifest found");
|
extractor.extract_without_semantics(file, "no manifest found");
|
||||||
}
|
}
|
||||||
let cargo_config = cfg.to_cargo_config(&cwd()?);
|
let cargo_config = cfg.to_cargo_config(&cwd()?);
|
||||||
|
let resolve_paths = if cfg.skip_path_resolution {
|
||||||
|
ResolvePaths::No
|
||||||
|
} else {
|
||||||
|
ResolvePaths::Yes
|
||||||
|
};
|
||||||
for (manifest, files) in map.values().filter(|(_, files)| !files.is_empty()) {
|
for (manifest, files) in map.values().filter(|(_, files)| !files.is_empty()) {
|
||||||
if let Some((ref db, ref vfs)) = extractor.load_manifest(manifest, &cargo_config) {
|
if let Some((ref db, ref vfs)) = extractor.load_manifest(manifest, &cargo_config) {
|
||||||
let semantics = Semantics::new(db);
|
let semantics = Semantics::new(db);
|
||||||
for file in files {
|
for file in files {
|
||||||
match extractor.load_source(file, &semantics, vfs) {
|
match extractor.load_source(file, &semantics, vfs) {
|
||||||
Ok(()) => extractor.extract_with_semantics(file, &semantics, vfs),
|
Ok(()) => {
|
||||||
|
extractor.extract_with_semantics(file, &semantics, vfs, resolve_paths)
|
||||||
|
}
|
||||||
Err(reason) => extractor.extract_without_semantics(file, &reason),
|
Err(reason) => extractor.extract_without_semantics(file, &reason),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ mod base;
|
|||||||
mod generated;
|
mod generated;
|
||||||
mod mappings;
|
mod mappings;
|
||||||
|
|
||||||
pub use base::Translator;
|
pub use base::{ResolvePaths, Translator};
|
||||||
|
|||||||
@@ -83,6 +83,12 @@ macro_rules! dispatch_to_tracing {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ResolvePaths {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Translator<'a> {
|
pub struct Translator<'a> {
|
||||||
pub trap: TrapFile,
|
pub trap: TrapFile,
|
||||||
path: &'a str,
|
path: &'a str,
|
||||||
@@ -90,6 +96,7 @@ pub struct Translator<'a> {
|
|||||||
line_index: LineIndex,
|
line_index: LineIndex,
|
||||||
file_id: Option<EditionedFileId>,
|
file_id: Option<EditionedFileId>,
|
||||||
pub semantics: Option<&'a Semantics<'a, RootDatabase>>,
|
pub semantics: Option<&'a Semantics<'a, RootDatabase>>,
|
||||||
|
resolve_paths: ResolvePaths,
|
||||||
}
|
}
|
||||||
|
|
||||||
const UNKNOWN_LOCATION: (LineCol, LineCol) =
|
const UNKNOWN_LOCATION: (LineCol, LineCol) =
|
||||||
@@ -102,6 +109,7 @@ impl<'a> Translator<'a> {
|
|||||||
label: Label<generated::File>,
|
label: Label<generated::File>,
|
||||||
line_index: LineIndex,
|
line_index: LineIndex,
|
||||||
semantic_info: Option<&FileSemanticInformation<'a>>,
|
semantic_info: Option<&FileSemanticInformation<'a>>,
|
||||||
|
resolve_paths: ResolvePaths,
|
||||||
) -> Translator<'a> {
|
) -> Translator<'a> {
|
||||||
Translator {
|
Translator {
|
||||||
trap,
|
trap,
|
||||||
@@ -110,6 +118,7 @@ impl<'a> Translator<'a> {
|
|||||||
line_index,
|
line_index,
|
||||||
file_id: semantic_info.map(|i| i.file_id),
|
file_id: semantic_info.map(|i| i.file_id),
|
||||||
semantics: semantic_info.map(|i| i.semantics),
|
semantics: semantic_info.map(|i| i.semantics),
|
||||||
|
resolve_paths,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn location(&self, range: TextRange) -> Option<(LineCol, LineCol)> {
|
fn location(&self, range: TextRange) -> Option<(LineCol, LineCol)> {
|
||||||
@@ -497,6 +506,9 @@ impl<'a> Translator<'a> {
|
|||||||
item: &T,
|
item: &T,
|
||||||
label: Label<generated::Addressable>,
|
label: Label<generated::Addressable>,
|
||||||
) {
|
) {
|
||||||
|
if self.resolve_paths == ResolvePaths::No {
|
||||||
|
return;
|
||||||
|
}
|
||||||
(|| {
|
(|| {
|
||||||
let sema = self.semantics.as_ref()?;
|
let sema = self.semantics.as_ref()?;
|
||||||
let def = T::Hir::try_from_source(item, sema)?;
|
let def = T::Hir::try_from_source(item, sema)?;
|
||||||
@@ -517,6 +529,9 @@ impl<'a> Translator<'a> {
|
|||||||
item: &ast::Variant,
|
item: &ast::Variant,
|
||||||
label: Label<generated::Variant>,
|
label: Label<generated::Variant>,
|
||||||
) {
|
) {
|
||||||
|
if self.resolve_paths == ResolvePaths::No {
|
||||||
|
return;
|
||||||
|
}
|
||||||
(|| {
|
(|| {
|
||||||
let sema = self.semantics.as_ref()?;
|
let sema = self.semantics.as_ref()?;
|
||||||
let def = sema.to_enum_variant_def(item)?;
|
let def = sema.to_enum_variant_def(item)?;
|
||||||
@@ -537,6 +552,9 @@ impl<'a> Translator<'a> {
|
|||||||
item: &impl PathAst,
|
item: &impl PathAst,
|
||||||
label: Label<generated::Resolvable>,
|
label: Label<generated::Resolvable>,
|
||||||
) {
|
) {
|
||||||
|
if self.resolve_paths == ResolvePaths::No {
|
||||||
|
return;
|
||||||
|
}
|
||||||
(|| {
|
(|| {
|
||||||
let path = item.path()?;
|
let path = item.path()?;
|
||||||
let sema = self.semantics.as_ref()?;
|
let sema = self.semantics.as_ref()?;
|
||||||
@@ -557,6 +575,9 @@ impl<'a> Translator<'a> {
|
|||||||
item: &ast::MethodCallExpr,
|
item: &ast::MethodCallExpr,
|
||||||
label: Label<generated::MethodCallExpr>,
|
label: Label<generated::MethodCallExpr>,
|
||||||
) {
|
) {
|
||||||
|
if self.resolve_paths == ResolvePaths::No {
|
||||||
|
return;
|
||||||
|
}
|
||||||
(|| {
|
(|| {
|
||||||
let sema = self.semantics.as_ref()?;
|
let sema = self.semantics.as_ref()?;
|
||||||
let resolved = sema.resolve_method_call_fallback(item)?;
|
let resolved = sema.resolve_method_call_fallback(item)?;
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// would prefer to write `include!("../anonymous.rs");`
|
||||||
|
// but it seems `include!` does not work in rust-analyzer/our extractor
|
||||||
|
|
||||||
|
use super::regular::Trait;
|
||||||
|
|
||||||
|
fn canonicals() {
|
||||||
|
struct OtherStruct;
|
||||||
|
|
||||||
|
trait OtherTrait {
|
||||||
|
fn g(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OtherTrait for OtherStruct {
|
||||||
|
fn g(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OtherTrait for crate::regular::Struct {
|
||||||
|
fn g(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::regular::Trait for OtherStruct {
|
||||||
|
fn f(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nested() {
|
||||||
|
struct OtherStruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage() {
|
||||||
|
let s = OtherStruct {};
|
||||||
|
s.f();
|
||||||
|
s.g();
|
||||||
|
nested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn other() {
|
||||||
|
struct OtherStruct;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
canonicalPaths
|
||||||
|
| anonymous.rs:4:1:4:26 | Use | None | None |
|
||||||
|
| anonymous.rs:6:1:35:1 | fn canonicals | None | None |
|
||||||
|
| anonymous.rs:7:5:7:23 | struct OtherStruct | None | None |
|
||||||
|
| anonymous.rs:9:5:11:5 | trait OtherTrait | None | None |
|
||||||
|
| anonymous.rs:10:9:10:20 | fn g | None | None |
|
||||||
|
| anonymous.rs:13:5:15:5 | impl OtherTrait for OtherStruct { ... } | None | None |
|
||||||
|
| anonymous.rs:14:9:14:22 | fn g | None | None |
|
||||||
|
| anonymous.rs:17:5:19:5 | impl OtherTrait for ...::Struct { ... } | None | None |
|
||||||
|
| anonymous.rs:18:9:18:22 | fn g | None | None |
|
||||||
|
| anonymous.rs:21:5:23:5 | impl ...::Trait for OtherStruct { ... } | None | None |
|
||||||
|
| anonymous.rs:22:9:22:22 | fn f | None | None |
|
||||||
|
| anonymous.rs:25:5:27:5 | fn nested | None | None |
|
||||||
|
| anonymous.rs:26:9:26:27 | struct OtherStruct | None | None |
|
||||||
|
| anonymous.rs:29:5:34:5 | fn usage | None | None |
|
||||||
|
| anonymous.rs:37:1:39:1 | fn other | None | None |
|
||||||
|
| anonymous.rs:38:5:38:23 | struct OtherStruct | None | None |
|
||||||
|
| lib.rs:1:1:1:14 | mod anonymous | None | None |
|
||||||
|
| lib.rs:2:1:2:12 | mod regular | None | None |
|
||||||
|
| regular.rs:4:1:5:18 | struct Struct | None | None |
|
||||||
|
| regular.rs:7:1:9:1 | trait Trait | None | None |
|
||||||
|
| regular.rs:8:5:8:16 | fn f | None | None |
|
||||||
|
| regular.rs:11:1:13:1 | impl Trait for Struct { ... } | None | None |
|
||||||
|
| regular.rs:12:5:12:18 | fn f | None | None |
|
||||||
|
| regular.rs:15:1:17:1 | impl Struct { ... } | None | None |
|
||||||
|
| regular.rs:16:5:16:18 | fn g | None | None |
|
||||||
|
| regular.rs:19:1:21:1 | trait TraitWithBlanketImpl | None | None |
|
||||||
|
| regular.rs:20:5:20:16 | fn h | None | None |
|
||||||
|
| regular.rs:23:1:25:1 | impl TraitWithBlanketImpl for T { ... } | None | None |
|
||||||
|
| regular.rs:24:5:24:18 | fn h | None | None |
|
||||||
|
| regular.rs:27:1:27:12 | fn free | None | None |
|
||||||
|
| regular.rs:29:1:35:1 | fn usage | None | None |
|
||||||
|
| regular.rs:37:1:41:1 | enum MyEnum | None | None |
|
||||||
|
| regular.rs:43:1:49:1 | fn enum_qualified_usage | None | None |
|
||||||
|
| regular.rs:51:1:58:1 | fn enum_unqualified_usage | None | None |
|
||||||
|
| regular.rs:54:5:54:18 | Use | None | None |
|
||||||
|
| regular.rs:60:1:66:1 | fn enum_match | None | None |
|
||||||
|
resolvedPaths
|
||||||
|
| anonymous.rs:30:17:30:30 | OtherStruct {...} | None | None |
|
||||||
|
| anonymous.rs:31:9:31:9 | s | None | None |
|
||||||
|
| anonymous.rs:31:9:31:13 | s.f(...) | None | None |
|
||||||
|
| anonymous.rs:32:9:32:9 | s | None | None |
|
||||||
|
| anonymous.rs:32:9:32:13 | s.g(...) | None | None |
|
||||||
|
| anonymous.rs:33:9:33:14 | nested | None | None |
|
||||||
|
| regular.rs:30:13:30:21 | Struct {...} | None | None |
|
||||||
|
| regular.rs:31:5:31:5 | s | None | None |
|
||||||
|
| regular.rs:31:5:31:9 | s.f(...) | None | None |
|
||||||
|
| regular.rs:32:5:32:5 | s | None | None |
|
||||||
|
| regular.rs:32:5:32:9 | s.g(...) | None | None |
|
||||||
|
| regular.rs:33:5:33:5 | s | None | None |
|
||||||
|
| regular.rs:33:5:33:9 | s.h(...) | None | None |
|
||||||
|
| regular.rs:34:5:34:8 | free | None | None |
|
||||||
|
| regular.rs:44:9:44:26 | ...::None::<...> | None | None |
|
||||||
|
| regular.rs:45:9:45:20 | ...::Some | None | None |
|
||||||
|
| regular.rs:46:9:46:24 | ...::Variant1 | None | None |
|
||||||
|
| regular.rs:47:9:47:24 | ...::Variant2 | None | None |
|
||||||
|
| regular.rs:48:9:48:33 | ...::Variant3 {...} | None | None |
|
||||||
|
| regular.rs:52:9:52:18 | None::<...> | None | None |
|
||||||
|
| regular.rs:53:9:53:12 | Some | None | None |
|
||||||
|
| regular.rs:55:9:55:16 | Variant1 | None | None |
|
||||||
|
| regular.rs:56:9:56:16 | Variant2 | None | None |
|
||||||
|
| regular.rs:57:9:57:25 | Variant3 {...} | None | None |
|
||||||
|
| regular.rs:61:11:61:11 | e | None | None |
|
||||||
|
| regular.rs:62:9:62:24 | ...::Variant1 | None | None |
|
||||||
|
| regular.rs:63:9:63:27 | ...::Variant2(...) | None | None |
|
||||||
|
| regular.rs:64:9:64:31 | ...::Variant3 {...} | None | None |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
extractor-tests/canonical_path/canonical_paths.ql
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
skip_path_resolution: true
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// would prefer to write `include!("../regular.rs");`
|
||||||
|
// but it seems `include!` does not work in rust-analyzer/our extractor
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub struct Struct;
|
||||||
|
|
||||||
|
pub trait Trait {
|
||||||
|
fn f(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for Struct {
|
||||||
|
fn f(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Struct {
|
||||||
|
fn g(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TraitWithBlanketImpl {
|
||||||
|
fn h(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq> TraitWithBlanketImpl for T {
|
||||||
|
fn h(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free() {}
|
||||||
|
|
||||||
|
fn usage() {
|
||||||
|
let s = Struct {};
|
||||||
|
s.f();
|
||||||
|
s.g();
|
||||||
|
s.h();
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MyEnum {
|
||||||
|
Variant1,
|
||||||
|
Variant2(usize),
|
||||||
|
Variant3 { x: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enum_qualified_usage() {
|
||||||
|
_ = Option::None::<()>;
|
||||||
|
_ = Option::Some(0);
|
||||||
|
_ = MyEnum::Variant1;
|
||||||
|
_ = MyEnum::Variant2(0);
|
||||||
|
_ = MyEnum::Variant3 { x: 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enum_unqualified_usage() {
|
||||||
|
_ = None::<()>;
|
||||||
|
_ = Some(0);
|
||||||
|
use MyEnum::*;
|
||||||
|
_ = Variant1;
|
||||||
|
_ = Variant2(0);
|
||||||
|
_ = Variant3 { x: 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enum_match(e: MyEnum) {
|
||||||
|
match e {
|
||||||
|
MyEnum::Variant1 => {}
|
||||||
|
MyEnum::Variant2(_) => {}
|
||||||
|
MyEnum::Variant3 { .. } => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user