diff --git a/Cargo.lock b/Cargo.lock index fc646d201d66..a7cf3370ac1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,6 +409,7 @@ version = "0.1.0" dependencies = [ "anyhow", "argfile", + "chalk-ir", "chrono", "clap", "codeql-extractor", @@ -422,6 +423,7 @@ dependencies = [ "ra_ap_hir", "ra_ap_hir_def", "ra_ap_hir_expand", + "ra_ap_hir_ty", "ra_ap_ide_db", "ra_ap_intern", "ra_ap_load-cargo", diff --git a/MODULE.bazel b/MODULE.bazel index 8fecb2770b90..19bb0bb00224 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -73,6 +73,7 @@ use_repo( tree_sitter_extractors_deps, "vendor_ts__anyhow-1.0.96", "vendor_ts__argfile-0.2.1", + "vendor_ts__chalk-ir-0.99.0", "vendor_ts__chrono-0.4.39", "vendor_ts__clap-4.5.31", "vendor_ts__dunce-1.0.5", @@ -94,6 +95,7 @@ use_repo( "vendor_ts__ra_ap_hir-0.0.266", "vendor_ts__ra_ap_hir_def-0.0.266", "vendor_ts__ra_ap_hir_expand-0.0.266", + "vendor_ts__ra_ap_hir_ty-0.0.266", "vendor_ts__ra_ap_ide_db-0.0.266", "vendor_ts__ra_ap_intern-0.0.266", "vendor_ts__ra_ap_load-cargo-0.0.266", diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel index 3632f78bd5f4..186d05cc46fa 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel @@ -55,6 +55,18 @@ alias( tags = ["manual"], ) +alias( + name = "chalk-ir-0.99.0", + actual = "@vendor_ts__chalk-ir-0.98.0//:chalk_ir", + tags = ["manual"], +) + +alias( + name = "chalk-ir", + actual = "@vendor_ts__chalk-ir-0.99.0//:chalk_ir", + tags = ["manual"], +) + alias( name = "chrono-0.4.39", actual = "@vendor_ts__chrono-0.4.39//:chrono", @@ -307,6 +319,18 @@ alias( tags = ["manual"], ) +alias( + name = "ra_ap_hir_ty-0.0.266", + actual = "@vendor_ts__ra_ap_hir_ty-0.0.266//:ra_ap_hir_ty", + tags = ["manual"], +) + +alias( + name = "ra_ap_hir_ty", + actual = "@vendor_ts__ra_ap_hir_ty-0.0.266//:ra_ap_hir_ty", + tags = ["manual"], +) + alias( name = "ra_ap_ide_db-0.0.266", actual = "@vendor_ts__ra_ap_ide_db-0.0.266//:ra_ap_ide_db", diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl index ff89ab88d59e..817891809d2c 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl @@ -327,6 +327,7 @@ _NORMAL_DEPENDENCIES = { _COMMON_CONDITION: { "anyhow": Label("@vendor_ts__anyhow-1.0.96//:anyhow"), "argfile": Label("@vendor_ts__argfile-0.2.1//:argfile"), + "chalk-ir": Label("@vendor_ts__chalk-ir-0.99.0//:chalk_ir"), "chrono": Label("@vendor_ts__chrono-0.4.39//:chrono"), "clap": Label("@vendor_ts__clap-4.5.31//:clap"), "dunce": Label("@vendor_ts__dunce-1.0.5//:dunce"), @@ -339,6 +340,7 @@ _NORMAL_DEPENDENCIES = { "ra_ap_hir": Label("@vendor_ts__ra_ap_hir-0.0.266//:ra_ap_hir"), "ra_ap_hir_def": Label("@vendor_ts__ra_ap_hir_def-0.0.266//:ra_ap_hir_def"), "ra_ap_hir_expand": Label("@vendor_ts__ra_ap_hir_expand-0.0.266//:ra_ap_hir_expand"), + "ra_ap_hir_ty": Label("@vendor_ts__ra_ap_hir_ty-0.0.266//:ra_ap_hir_ty"), "ra_ap_ide_db": Label("@vendor_ts__ra_ap_ide_db-0.0.266//:ra_ap_ide_db"), "ra_ap_intern": Label("@vendor_ts__ra_ap_intern-0.0.266//:ra_ap_intern"), "ra_ap_load-cargo": Label("@vendor_ts__ra_ap_load-cargo-0.0.266//:ra_ap_load_cargo"), @@ -3476,6 +3478,7 @@ def crate_repositories(): return [ struct(repo = "vendor_ts__anyhow-1.0.96", is_dev_dep = False), struct(repo = "vendor_ts__argfile-0.2.1", is_dev_dep = False), + struct(repo = "vendor_ts__chalk-ir-0.99.0", is_dev_dep = False), struct(repo = "vendor_ts__chrono-0.4.39", is_dev_dep = False), struct(repo = "vendor_ts__clap-4.5.31", is_dev_dep = False), struct(repo = "vendor_ts__dunce-1.0.5", is_dev_dep = False), @@ -3497,6 +3500,7 @@ def crate_repositories(): struct(repo = "vendor_ts__ra_ap_hir-0.0.266", is_dev_dep = False), struct(repo = "vendor_ts__ra_ap_hir_def-0.0.266", is_dev_dep = False), struct(repo = "vendor_ts__ra_ap_hir_expand-0.0.266", is_dev_dep = False), + struct(repo = "vendor_ts__ra_ap_hir_ty-0.0.266", is_dev_dep = False), struct(repo = "vendor_ts__ra_ap_ide_db-0.0.266", is_dev_dep = False), struct(repo = "vendor_ts__ra_ap_intern-0.0.266", is_dev_dep = False), struct(repo = "vendor_ts__ra_ap_load-cargo-0.0.266", is_dev_dep = False), diff --git a/rust/extractor/Cargo.toml b/rust/extractor/Cargo.toml index cc7c67407964..186ac2b20e51 100644 --- a/rust/extractor/Cargo.toml +++ b/rust/extractor/Cargo.toml @@ -14,6 +14,7 @@ ra_ap_base_db = "0.0.266" ra_ap_hir = "0.0.266" ra_ap_hir_def = "0.0.266" ra_ap_ide_db = "0.0.266" +ra_ap_hir_ty = "0.0.266" ra_ap_hir_expand = "0.0.266" ra_ap_load-cargo = "0.0.266" ra_ap_paths = "0.0.266" @@ -39,3 +40,4 @@ toml = "0.8.20" tracing = "0.1.41" tracing-flame = "0.2.0" tracing-subscriber = "0.3.19" +chalk-ir = "0.99.0" diff --git a/rust/extractor/src/crate_graph.rs b/rust/extractor/src/crate_graph.rs new file mode 100644 index 000000000000..cc33982c13d8 --- /dev/null +++ b/rust/extractor/src/crate_graph.rs @@ -0,0 +1,1311 @@ +use crate::{ + generated::{self}, + trap::{self, TrapFile}, +}; +use chalk_ir::IntTy; +use chalk_ir::Scalar; +use chalk_ir::UintTy; +use chalk_ir::{FloatTy, Safety}; +use itertools::Itertools; +use ra_ap_base_db::CrateGraph; +use ra_ap_base_db::CrateId; +use ra_ap_base_db::SourceDatabase; +use ra_ap_cfg::CfgAtom; +use ra_ap_hir::{DefMap, ModuleDefId, db::HirDatabase}; +use ra_ap_hir::{VariantId, Visibility, db::DefDatabase}; +use ra_ap_hir_def::{AssocItemId, LocalModuleId, data::adt::VariantData, nameres::ModuleData}; +use ra_ap_hir_def::{HasModule, visibility::VisibilityExplicitness}; +use ra_ap_hir_def::{ModuleId, resolver::HasResolver}; +use ra_ap_hir_ty::TraitRefExt; +use ra_ap_hir_ty::Ty; +use ra_ap_hir_ty::TyExt; +use ra_ap_hir_ty::WhereClause; +use ra_ap_hir_ty::{Binders, FnPointer}; +use ra_ap_hir_ty::{Interner, ProjectionTy}; +use ra_ap_ide_db::RootDatabase; +use ra_ap_vfs::{Vfs, VfsPath}; +use std::hash::Hasher; +use std::{cmp::Ordering, collections::HashMap, path::PathBuf}; +use std::{hash::Hash, vec}; +use tracing::{debug, error}; + +pub fn extract_crate_graph(trap_provider: &trap::TrapFileProvider, db: &RootDatabase, vfs: &Vfs) { + let crate_graph = db.crate_graph(); + + // According to the documentation of `CrateGraph`: + // Each crate is defined by the `FileId` of its root module, the set of enabled + // `cfg` flags and the set of dependencies. + + // First compute a hash map with for each crate ID, the path to its root module and a hash of all + // its `cfg` flags and dependencies hashes. Iterate in topological order to ensure hashes of dependencies + // are present in the map. + let mut crate_id_map = HashMap::::new(); + for krate_id in crate_graph.crates_in_topological_order() { + let krate = &crate_graph[krate_id]; + let root_module_file: &VfsPath = vfs.file_path(krate.root_file_id); + if let Some(root_module_file) = root_module_file + .as_path() + .map(|p| std::fs::canonicalize(p).unwrap_or(p.into())) + { + let mut hasher = std::hash::DefaultHasher::new(); + krate + .cfg_options + .as_ref() + .into_iter() + .sorted_by(cmp_flag) + .for_each(|x| format!("{x}").hash(&mut hasher)); + + krate + .dependencies + .iter() + .flat_map(|d| crate_id_map.get(&d.crate_id)) + .sorted() + .for_each(|x| x.hash(&mut hasher)); + let hash = hasher.finish(); + crate_id_map.insert(krate_id, (root_module_file, hash)); + } + } + // Extract each crate + for krate_id in crate_graph.iter() { + if let Some((root_module_file, hash)) = crate_id_map.get(&krate_id) { + let path = root_module_file.join(format!("{hash:0>16x}")); + let mut trap = trap_provider.create("crates", path.as_path()); + // If the trap file already exists, then skip extraction because we have already extracted + // this crate with the same `cfg` flags and dependencies. + // FIXME: this may need to b improved in case the implemenation becomes multi-threaded + if trap.path.exists() { + continue; + } + let krate = &crate_graph[krate_id]; + let root_module = emit_module( + &crate_graph, + db, + db.crate_def_map(krate_id).as_ref(), + "crate", + DefMap::ROOT, + &mut trap, + ); + let file_label = trap.emit_file(root_module_file); + trap.emit_file_only_location(file_label, root_module); + + let element = generated::Crate { + id: trap::TrapId::Key(format!("{}:{hash}", root_module_file.display())), + name: krate + .display_name + .as_ref() + .map(|x| x.canonical_name().to_string()), + version: krate.version.to_owned(), + module: Some(root_module), + cfg_options: krate + .cfg_options + .as_ref() + .into_iter() + .map(|x| format!("{x}")) + .collect(), + dependencies: krate + .dependencies + .iter() + .flat_map(|x| crate_id_map.get(&x.crate_id)) + .map(|(module, hash)| trap.label(format!("{}:{hash}", module.display()).into())) + .collect(), + }; + trap.emit(element); + trap.commit().unwrap_or_else(|err| { + error!( + "Failed to write trap file for crate: {}: {}", + root_module_file.display(), + err.to_string() + ) + }); + } + } +} + +fn emit_module( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + map: &DefMap, + name: &str, + module: LocalModuleId, + trap: &mut TrapFile, +) -> trap::Label { + let module = &map.modules[module]; + let mut items = Vec::new(); + items.extend(emit_module_children(crate_graph, db, map, module, trap)); + items.extend(emit_module_items(crate_graph, db, module, trap)); + items.extend(emit_module_impls(crate_graph, db, module, trap)); + + let name = trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + }); + let item_list = trap.emit(generated::ItemList { + id: trap::TrapId::Star, + attrs: vec![], + items, + }); + let visibility = emit_visibility(crate_graph, db, trap, module.visibility); + trap.emit(generated::Module { + id: trap::TrapId::Star, + name: Some(name), + attrs: vec![], + item_list: Some(item_list), + visibility, + }) +} + +fn emit_module_children( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + map: &DefMap, + module: &ModuleData, + trap: &mut TrapFile, +) -> Vec> { + module + .children + .iter() + .sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) + .map(|(name, child)| emit_module(crate_graph, db, map, name.as_str(), *child, trap).into()) + .collect() +} + +fn emit_module_items( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + module: &ModuleData, + trap: &mut TrapFile, +) -> Vec> { + let mut items = Vec::new(); + let item_scope = &module.scope; + for (name, item) in item_scope.entries() { + let def = item.filter_visibility(|x| matches!(x, ra_ap_hir::Visibility::Public)); + if let Some(ra_ap_hir_def::per_ns::Item { + def: value, + vis, + import: _, + }) = def.values + { + match value { + ModuleDefId::FunctionId(function) => { + items.extend(emit_function( + crate_graph, + db, + name.as_str(), + trap, + function, + vis, + )); + } + ModuleDefId::ConstId(konst) => { + items.extend(emit_const(crate_graph, db, name.as_str(), trap, konst, vis)); + } + ModuleDefId::StaticId(statik) => { + items.extend(emit_static( + crate_graph, + db, + name.as_str(), + trap, + statik, + vis, + )); + } + ModuleDefId::EnumVariantId(variant_id) => { + items.extend(emit_enum_variant( + crate_graph, + db, + name.as_str(), + trap, + variant_id, + vis, + )); + } + _ => (), + } + } + if let Some(ra_ap_hir_def::per_ns::Item { + def: type_id, + vis, + import: _, + }) = def.types + { + match type_id { + ModuleDefId::AdtId(adt_id) => { + items.extend(emit_adt(crate_graph, db, name.as_str(), trap, adt_id, vis)); + } + ModuleDefId::TraitId(trait_id) => { + items.extend(emit_trait( + crate_graph, + db, + name.as_str(), + trap, + trait_id, + vis, + )); + } + _ => (), + } + } + } + items +} + +fn emit_function( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + name: &str, + trap: &mut TrapFile, + function: ra_ap_hir_def::FunctionId, + visibility: Visibility, +) -> Vec> { + let mut items = Vec::new(); + if let Some(type_) = db.value_ty(function.into()) { + items.push(const_or_function( + crate_graph, + db, + name, + trap, + type_, + visibility, + )); + } + items +} + +fn emit_const( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + name: &str, + trap: &mut TrapFile, + konst: ra_ap_hir_def::ConstId, + visibility: Visibility, +) -> Vec> { + let mut items = Vec::new(); + let type_ = db.value_ty(konst.into()); + let type_repr = + type_.and_then(|type_| emit_hir_ty(trap, crate_graph, db, type_.skip_binders())); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let konst = db.const_data(konst); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + items.push( + trap.emit(generated::Const { + id: trap::TrapId::Star, + name, + attrs: vec![], + body: None, + is_const: true, + is_default: konst.has_body, + type_repr, + visibility, + }) + .into(), + ); + items +} + +fn emit_static( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + name: &str, + trap: &mut TrapFile, + statik: ra_ap_hir_def::StaticId, + visibility: Visibility, +) -> Vec> { + let mut items = Vec::new(); + let type_ = db.value_ty(statik.into()); + let type_repr = + type_.and_then(|type_| emit_hir_ty(trap, crate_graph, db, type_.skip_binders())); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let statik = db.static_data(statik); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + items.push( + trap.emit(generated::Static { + id: trap::TrapId::Star, + name, + attrs: vec![], + body: None, + type_repr, + visibility, + is_mut: statik.mutable, + is_static: true, + is_unsafe: statik.has_unsafe_kw, + }) + .into(), + ); + items +} + +fn emit_enum_variant( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + name: &str, + trap: &mut TrapFile, + variant_id: ra_ap_hir_def::EnumVariantId, + visibility: Visibility, +) -> Vec> { + let mut items = Vec::new(); + if let Some(type_) = db.value_ty(variant_id.into()) { + items.push(const_or_function( + crate_graph, + db, + name, + trap, + type_, + visibility, + )); + } + items +} + +fn emit_adt( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + name: &str, + trap: &mut TrapFile, + adt_id: ra_ap_hir_def::AdtId, + visibility: Visibility, +) -> Vec> { + let mut items = Vec::new(); + match adt_id { + ra_ap_hir_def::AdtId::StructId(struct_id) => { + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let field_list = emit_variant_data(trap, crate_graph, db, struct_id.into()).into(); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + items.push( + trap.emit(generated::Struct { + id: trap::TrapId::Star, + name, + attrs: vec![], + field_list, + generic_param_list: None, + visibility, + where_clause: None, + }) + .into(), + ); + } + ra_ap_hir_def::AdtId::EnumId(enum_id) => { + let data = db.enum_data(enum_id); + let variants = data + .variants + .iter() + .map(|(enum_id, name)| { + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.as_str().to_owned()), + })); + let field_list = + emit_variant_data(trap, crate_graph, db, (*enum_id).into()).into(); + let visibility = None; + trap.emit(generated::Variant { + id: trap::TrapId::Star, + name, + field_list, + attrs: vec![], + expr: None, + visibility, + }) + }) + .collect(); + let variant_list = Some(trap.emit(generated::VariantList { + id: trap::TrapId::Star, + variants, + })); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + items.push( + trap.emit(generated::Enum { + id: trap::TrapId::Star, + name, + attrs: vec![], + generic_param_list: None, + variant_list, + visibility, + where_clause: None, + }) + .into(), + ); + } + ra_ap_hir_def::AdtId::UnionId(union_id) => { + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let record_field_list = + emit_variant_data(trap, crate_graph, db, union_id.into()).into(); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + items.push( + trap.emit(generated::Union { + id: trap::TrapId::Star, + name, + attrs: vec![], + record_field_list, + generic_param_list: None, + visibility, + where_clause: None, + }) + .into(), + ); + } + } + items +} + +fn emit_trait( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + name: &str, + trap: &mut TrapFile, + trait_id: ra_ap_hir_def::TraitId, + visibility: Visibility, +) -> Vec> { + let mut items = Vec::new(); + let data = db.trait_data(trait_id); + let assoc_items: Vec> = data + .items + .iter() + .flat_map(|(name, item)| { + if let AssocItemId::FunctionId(function) = item { + let sig = db.callable_item_signature((*function).into()); + let sig = sig.skip_binders(); + let params = sig + .params() + .iter() + .map(|p| { + let type_repr = emit_hir_ty(trap, crate_graph, db, p); + trap.emit(generated::Param { + id: trap::TrapId::Star, + attrs: vec![], + type_repr, + pat: None, + }) + }) + .collect(); + + let ret_type = emit_hir_ty(trap, crate_graph, db, sig.ret()); + let param_list = trap.emit(generated::ParamList { + id: trap::TrapId::Star, + params, + self_param: None, + }); + let ret_type = ret_type.map(|ret_type| { + trap.emit(generated::RetTypeRepr { + id: trap::TrapId::Star, + type_repr: Some(ret_type), + }) + }); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.as_str().to_owned()), + })); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + Some( + trap.emit(generated::Function { + id: trap::TrapId::Star, + name, + attrs: vec![], + body: None, + is_const: false, + is_default: false, + visibility, + abi: None, + is_async: false, + is_gen: false, + is_unsafe: matches!(sig.to_fn_ptr().sig.safety, Safety::Unsafe), + generic_param_list: None, //TODO + param_list: Some(param_list), + ret_type, + where_clause: None, + }) + .into(), + ) + } else { + None + } + }) + .collect(); + let assoc_item_list = Some(trap.emit(generated::AssocItemList { + id: trap::TrapId::Star, + assoc_items, + attrs: vec![], + })); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + items.push( + trap.emit(generated::Trait { + id: trap::TrapId::Star, + name, + assoc_item_list, + attrs: vec![], + generic_param_list: None, + is_auto: false, + is_unsafe: false, + type_bound_list: None, + visibility, + where_clause: None, + }) + .into(), + ); + items +} + +fn emit_module_impls( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + module: &ModuleData, + trap: &mut TrapFile, +) -> Vec> { + let mut items = Vec::new(); + module.scope.impls().for_each(|imp| { + let self_ty = db.impl_self_ty(imp); + let self_ty = emit_hir_ty(trap, crate_graph, db, self_ty.skip_binders()); + let imp = db.impl_data(imp); + let trait_ = imp + .target_trait + .as_ref() + .and_then(|t| make_qualified_path(trap, emit_hir_path(&imp.types_map[t.path]))); + let trait_ = trait_.map(|trait_| { + trap.emit(generated::PathTypeRepr { + id: trap::TrapId::Star, + path: Some(trait_), + }) + .into() + }); + let assoc_items = imp + .items + .iter() + .flat_map(|item| { + if let (name, AssocItemId::FunctionId(function)) = item { + let sig = db.callable_item_signature((*function).into()); + let sig = sig.skip_binders(); + let params = sig + .params() + .iter() + .map(|p| { + let type_repr = emit_hir_ty(trap, crate_graph, db, p); + trap.emit(generated::Param { + id: trap::TrapId::Star, + attrs: vec![], + type_repr, + pat: None, + }) + }) + .collect(); + + let ret_type = emit_hir_ty(trap, crate_graph, db, sig.ret()); + let param_list = trap.emit(generated::ParamList { + id: trap::TrapId::Star, + params, + self_param: None, + }); + let ret_type = ret_type.map(|ret_type| { + trap.emit(generated::RetTypeRepr { + id: trap::TrapId::Star, + type_repr: Some(ret_type), + }) + }); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.as_str().to_owned()), + })); + let data = db.function_data(*function); + let visibility = emit_visibility( + crate_graph, + db, + trap, + data.visibility + .resolve(db.upcast(), &function.resolver(db.upcast())), + ); + + Some( + trap.emit(generated::Function { + id: trap::TrapId::Star, + name, + attrs: vec![], + body: None, + is_const: false, + is_default: false, + visibility, + abi: None, + is_async: false, + is_gen: false, + is_unsafe: matches!(sig.to_fn_ptr().sig.safety, Safety::Unsafe), + generic_param_list: None, //TODO + param_list: Some(param_list), + ret_type, + where_clause: None, + }) + .into(), + ) + } else { + None + } + }) + .collect(); + let assoc_item_list = Some(trap.emit(generated::AssocItemList { + id: trap::TrapId::Star, + assoc_items, + attrs: vec![], + })); + items.push( + trap.emit(generated::Impl { + id: trap::TrapId::Star, + trait_, + self_ty, + assoc_item_list, + attrs: vec![], + generic_param_list: None, + is_const: false, + is_default: false, + is_unsafe: false, + visibility: None, + where_clause: None, + }) + .into(), + ); + }); + items +} + +fn emit_visibility( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + trap: &mut TrapFile, + visibility: Visibility, +) -> Option> { + let path = match visibility { + Visibility::Module(module_id, VisibilityExplicitness::Explicit) => { + Some(make_path_mod(crate_graph, db.upcast(), module_id)) + } + Visibility::Public => Some(vec![]), + Visibility::Module(_, VisibilityExplicitness::Implicit) => None, + }; + path.map(|path| { + let path = make_qualified_path(trap, path); + trap.emit(generated::Visibility { + id: trap::TrapId::Star, + path, + }) + }) +} +fn const_or_function( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + name: &str, + trap: &mut TrapFile, + type_: Binders, + visibility: Visibility, +) -> trap::Label { + let type_: &chalk_ir::Ty = type_.skip_binders(); + match type_.kind(ra_ap_hir_ty::Interner) { + chalk_ir::TyKind::FnDef(fn_def_id, parameters) => { + let data = db.fn_def_datum(*fn_def_id); + + let sig = ra_ap_hir_ty::CallableSig::from_def(db, *fn_def_id, parameters); + let params = sig + .params() + .iter() + .map(|p| { + let type_repr = emit_hir_ty(trap, crate_graph, db, p); + trap.emit(generated::Param { + id: trap::TrapId::Star, + attrs: vec![], + type_repr, + pat: None, + }) + }) + .collect(); + + let ret_type = emit_hir_ty(trap, crate_graph, db, sig.ret()); + let param_list = trap.emit(generated::ParamList { + id: trap::TrapId::Star, + params, + self_param: None, + }); + let ret_type = ret_type.map(|ret_type| { + trap.emit(generated::RetTypeRepr { + id: trap::TrapId::Star, + type_repr: Some(ret_type), + }) + }); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + trap.emit(generated::Function { + id: trap::TrapId::Star, + name, + attrs: vec![], + body: None, + is_const: false, + is_default: false, + visibility, + abi: None, + is_async: false, + is_gen: false, + is_unsafe: matches!(data.sig.safety, Safety::Unsafe), + generic_param_list: None, //TODO + param_list: Some(param_list), + ret_type, + where_clause: None, + }) + .into() + } + _ => { + let type_repr = emit_hir_ty(trap, crate_graph, db, type_); + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(name.to_owned()), + })); + let visibility = emit_visibility(crate_graph, db, trap, visibility); + trap.emit(generated::Const { + id: trap::TrapId::Star, + name, + attrs: vec![], + body: None, + is_const: false, + is_default: false, + type_repr, + visibility, + }) + .into() + } + } +} +fn emit_hir_type_bound( + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + trap: &mut TrapFile, + type_bound: &Binders>, +) -> Option> { + match type_bound.skip_binders() { + WhereClause::Implemented(trait_ref) => { + let mut path = make_path(crate_graph, db, trait_ref.hir_trait_id()); + path.push( + db.trait_data(trait_ref.hir_trait_id()) + .name + .as_str() + .to_owned(), + ); + let path = make_qualified_path(trap, path); + let type_repr = Some( + trap.emit(generated::PathTypeRepr { + id: trap::TrapId::Star, + path, + }) + .into(), + ); + Some(trap.emit(generated::TypeBound { + id: trap::TrapId::Star, + is_async: false, + is_const: false, + lifetime: None, + type_repr, + use_bound_generic_args: None, + })) + } + _ => None, + } +} + +fn emit_hir_path(path: &ra_ap_hir_def::path::Path) -> Vec { + path.segments() + .iter() + .map(|x| x.name.as_str().to_owned()) + .collect() +} + +fn emit_hir_fn_ptr( + trap: &mut TrapFile, + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + function: &FnPointer, +) -> trap::Label { + let parameters: Vec<_> = function.substitution.0.type_parameters(Interner).collect(); + + let (ret_type, params) = parameters.split_last().unwrap(); + + let ret_type = emit_hir_ty(trap, crate_graph, db, ret_type); + let ret_type = Some(trap.emit(generated::RetTypeRepr { + id: trap::TrapId::Star, + type_repr: ret_type, + })); + let params = params + .iter() + .map(|t| { + let type_repr = emit_hir_ty(trap, crate_graph, db, t); + trap.emit(generated::Param { + id: trap::TrapId::Star, + attrs: vec![], + type_repr, + pat: None, + }) + }) + .collect(); + let param_list = Some(trap.emit(generated::ParamList { + id: trap::TrapId::Star, + params, + self_param: None, + })); + let is_unsafe = matches!(function.sig.safety, ra_ap_hir::Safety::Unsafe); + trap.emit(generated::FnPtrTypeRepr { + id: trap::TrapId::Star, + abi: None, + is_async: false, + is_const: false, + is_unsafe, + ret_type, + param_list, + }) +} + +fn scalar_to_str(scalar: &Scalar) -> &'static str { + match scalar { + Scalar::Bool => "bool", + Scalar::Char => "char", + Scalar::Int(IntTy::I8) => "i8", + Scalar::Int(IntTy::I16) => "i16", + Scalar::Int(IntTy::I32) => "i32", + Scalar::Int(IntTy::I64) => "i64", + Scalar::Int(IntTy::I128) => "i128", + Scalar::Int(IntTy::Isize) => "isize", + Scalar::Uint(UintTy::U8) => "u8", + Scalar::Uint(UintTy::U16) => "u16", + Scalar::Uint(UintTy::U32) => "u32", + Scalar::Uint(UintTy::U64) => "u64", + Scalar::Uint(UintTy::U128) => "u128", + Scalar::Uint(UintTy::Usize) => "usize", + Scalar::Float(FloatTy::F16) => "f16", + Scalar::Float(FloatTy::F32) => "f32", + Scalar::Float(FloatTy::F64) => "f64", + Scalar::Float(FloatTy::F128) => "f128", + } +} + +fn make_path(crate_graph: &CrateGraph, db: &dyn HirDatabase, item: impl HasModule) -> Vec { + let db = db.upcast(); + let module = item.module(db); + make_path_mod(crate_graph, db, module) +} + +fn make_path_mod(crate_graph: &CrateGraph, db: &dyn DefDatabase, module: ModuleId) -> Vec { + let mut path = Vec::new(); + let mut module = module; + loop { + if module.is_block_module() { + path.push("".to_owned()); + } else if let Some(name) = module.name(db).map(|x| x.as_str().to_owned()).or_else(|| { + module.as_crate_root().and_then(|k| { + let krate = &crate_graph[k.krate()]; + krate + .display_name + .as_ref() + .map(|x| x.canonical_name().to_string()) + }) + }) { + path.push(name); + } else { + path.push("".to_owned()); + } + if let Some(parent) = module.containing_module(db) { + module = parent; + } else { + break; + } + } + path.reverse(); + path +} +fn make_qualified_path( + trap: &mut TrapFile, + path: Vec, +) -> Option> { + fn qualified_path( + trap: &mut TrapFile, + qualifier: Option>, + name: String, + ) -> trap::Label { + let name_ref = Some(trap.emit(generated::NameRef { + id: trap::TrapId::Star, + text: Some(name), + })); + let part = Some(trap.emit(generated::PathSegment { + id: trap::TrapId::Star, + generic_arg_list: None, + name_ref, + parenthesized_arg_list: None, + ret_type: None, + return_type_syntax: None, + })); + trap.emit(generated::Path { + id: trap::TrapId::Star, + qualifier, + part, + }) + } + path.into_iter() + .fold(None, |q, p| Some(qualified_path(trap, q, p))) +} +fn emit_hir_ty( + trap: &mut TrapFile, + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + ty: &Ty, +) -> Option> { + match ty.kind(ra_ap_hir_ty::Interner) { + chalk_ir::TyKind::Never => Some( + trap.emit(generated::NeverTypeRepr { + id: trap::TrapId::Star, + }) + .into(), + ), + + chalk_ir::TyKind::Placeholder(_index) => Some( + trap.emit(generated::InferTypeRepr { + id: trap::TrapId::Star, + }) + .into(), + ), + + chalk_ir::TyKind::Tuple(_size, substitution) => { + let fields = substitution.type_parameters(ra_ap_hir_ty::Interner); + let fields = fields + .flat_map(|field| emit_hir_ty(trap, crate_graph, db, &field)) + .collect(); + + Some( + trap.emit(generated::TupleTypeRepr { + id: trap::TrapId::Star, + fields, + }) + .into(), + ) + } + chalk_ir::TyKind::Raw(mutability, ty) => { + let type_repr = emit_hir_ty(trap, crate_graph, db, ty); + + Some( + trap.emit(generated::PtrTypeRepr { + id: trap::TrapId::Star, + is_mut: matches!(mutability, chalk_ir::Mutability::Mut), + is_const: false, + type_repr, + }) + .into(), + ) + } + chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => { + let type_repr = emit_hir_ty(trap, crate_graph, db, ty); + let lifetime = None; //TODO: ? + Some( + trap.emit(generated::RefTypeRepr { + id: trap::TrapId::Star, + is_mut: matches!(mutability, chalk_ir::Mutability::Mut), + lifetime, + type_repr, + }) + .into(), + ) + } + chalk_ir::TyKind::Array(ty, _konst) => { + let element_type_repr = emit_hir_ty(trap, crate_graph, db, ty); + // TODO: handle array size constant + Some( + trap.emit(generated::ArrayTypeRepr { + id: trap::TrapId::Star, + const_arg: None, + element_type_repr, + }) + .into(), + ) + } + chalk_ir::TyKind::Slice(ty) => { + let type_repr = emit_hir_ty(trap, crate_graph, db, ty); + Some( + trap.emit(generated::SliceTypeRepr { + id: trap::TrapId::Star, + type_repr, + }) + .into(), + ) + } + + chalk_ir::TyKind::Adt(adt_id, _substitution) => { + let mut path = make_path(crate_graph, db, adt_id.0); + let name = match adt_id.0 { + ra_ap_hir_def::AdtId::StructId(struct_id) => { + db.struct_data(struct_id).name.as_str().to_owned() + } + ra_ap_hir_def::AdtId::UnionId(union_id) => { + db.union_data(union_id).name.as_str().to_owned() + } + ra_ap_hir_def::AdtId::EnumId(enum_id) => { + db.enum_data(enum_id).name.as_str().to_owned() + } + }; + path.push(name); + let path = make_qualified_path(trap, path); + Some( + trap.emit(generated::PathTypeRepr { + id: trap::TrapId::Star, + path, + }) + .into(), + ) + } + chalk_ir::TyKind::Scalar(scalar) => { + let path = make_qualified_path(trap, vec![scalar_to_str(scalar).to_owned()]); + Some( + trap.emit(generated::PathTypeRepr { + id: trap::TrapId::Star, + path, + }) + .into(), + ) + } + chalk_ir::TyKind::Str => { + let path = make_qualified_path(trap, vec!["str".to_owned()]); + Some( + trap.emit(generated::PathTypeRepr { + id: trap::TrapId::Star, + path, + }) + .into(), + ) + } + chalk_ir::TyKind::Function(fn_pointer) => { + Some(emit_hir_fn_ptr(trap, crate_graph, db, fn_pointer).into()) + } + chalk_ir::TyKind::OpaqueType(_, _) + | chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(_)) => { + let bounds = ty + .impl_trait_bounds(db) + .iter() + .flatten() + .flat_map(|t| emit_hir_type_bound(crate_graph, db, trap, t)) + .collect(); + let type_bound_list = Some(trap.emit(generated::TypeBoundList { + id: trap::TrapId::Star, + bounds, + })); + Some( + trap.emit(generated::ImplTraitTypeRepr { + id: trap::TrapId::Star, + type_bound_list, + }) + .into(), + ) + } + chalk_ir::TyKind::Dyn(dyn_ty) => { + let bounds = dyn_ty + .bounds + .skip_binders() + .iter(ra_ap_hir_ty::Interner) + .flat_map(|t| emit_hir_type_bound(crate_graph, db, trap, t)) + .collect(); + let type_bound_list = Some(trap.emit(generated::TypeBoundList { + id: trap::TrapId::Star, + bounds, + })); + Some( + trap.emit(generated::DynTraitTypeRepr { + id: trap::TrapId::Star, + type_bound_list, + }) + .into(), + ) + } + chalk_ir::TyKind::FnDef(fn_def_id, parameters) => { + let sig = ra_ap_hir_ty::CallableSig::from_def(db, *fn_def_id, parameters); + Some(emit_hir_fn_ptr(trap, crate_graph, db, &sig.to_fn_ptr()).into()) + } + + chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy { + associated_ty_id, + substitution: _, + })) + | chalk_ir::TyKind::AssociatedType(associated_ty_id, _) => { + let assoc_ty_data = db.associated_ty_data(*associated_ty_id); + + let _name = db + .type_alias_data(assoc_ty_data.name) + .name + .as_str() + .to_owned(); + + let trait_ref = ra_ap_hir_ty::TraitRef { + trait_id: assoc_ty_data.trait_id, + substitution: assoc_ty_data.binders.identity_substitution(Interner), + }; + let mut trait_path = make_path(crate_graph, db, trait_ref.hir_trait_id()); + trait_path.push( + db.trait_data(trait_ref.hir_trait_id()) + .name + .as_str() + .to_owned(), + ); + //TODO + // trap.emit(generated::AssociatedType { + // id: trap::TrapId::Star, + // trait_path, + // name, + // }) + // .into() + None + } + chalk_ir::TyKind::BoundVar(var) => { + let var = format!("T_{}_{}", var.debruijn.depth(), var.index); + let path = make_qualified_path(trap, vec![var]); + Some( + trap.emit(generated::PathTypeRepr { + id: trap::TrapId::Star, + path, + }) + .into(), + ) + } + chalk_ir::TyKind::Foreign(_) + | chalk_ir::TyKind::Closure(_, _) + | chalk_ir::TyKind::Coroutine(_, _) + | chalk_ir::TyKind::CoroutineWitness(_, _) + | chalk_ir::TyKind::InferenceVar(_, _) + | chalk_ir::TyKind::Error => { + debug!("Unexpected type {:#?}", ty.kind(ra_ap_hir_ty::Interner)); + None + } + } +} + +enum Variant { + Unit, + Record(trap::Label), + Tuple(trap::Label), +} + +impl From for Option> { + fn from(val: Variant) -> Self { + match val { + Variant::Record(label) => Some(label), + _ => None, + } + } +} + +impl From for Option> { + fn from(val: Variant) -> Self { + match val { + Variant::Record(label) => Some(label.into()), + Variant::Tuple(label) => Some(label.into()), + Variant::Unit => None, + } + } +} + +fn emit_variant_data( + trap: &mut TrapFile, + crate_graph: &CrateGraph, + db: &dyn HirDatabase, + variant_id: VariantId, +) -> Variant { + let variant = variant_id.variant_data(db.upcast()); + match variant.as_ref() { + VariantData::Record { + fields: field_data, + types_map: _, + } => { + let field_types = db.field_types(variant_id); + let fields = field_types + .iter() + .map(|(field_id, ty)| { + let name = Some(trap.emit(generated::Name { + id: trap::TrapId::Star, + text: Some(field_data[field_id].name.as_str().to_owned()), + })); + let type_repr = emit_hir_ty(trap, crate_graph, db, ty.skip_binders()); + let visibility = emit_visibility( + crate_graph, + db, + trap, + field_data[field_id] + .visibility + .resolve(db.upcast(), &variant_id.resolver(db.upcast())), + ); + trap.emit(generated::RecordField { + id: trap::TrapId::Star, + attrs: vec![], + name, + type_repr, + visibility, + expr: None, + }) + }) + .collect(); + Variant::Record(trap.emit(generated::RecordFieldList { + id: trap::TrapId::Star, + fields, + })) + } + VariantData::Tuple { + fields: field_data, .. + } => { + let field_types = db.field_types(variant_id); + let fields = field_types + .iter() + .map(|(field_id, ty)| { + let type_repr = emit_hir_ty(trap, crate_graph, db, ty.skip_binders()); + let visibility = emit_visibility( + crate_graph, + db, + trap, + field_data[field_id] + .visibility + .resolve(db.upcast(), &variant_id.resolver(db.upcast())), + ); + + trap.emit(generated::TupleField { + id: trap::TrapId::Star, + attrs: vec![], + type_repr, + visibility, + }) + }) + .collect(); + Variant::Tuple(trap.emit(generated::TupleFieldList { + id: trap::TrapId::Star, + fields, + })) + } + VariantData::Unit => Variant::Unit, + } +} + +fn cmp_flag(a: &&CfgAtom, b: &&CfgAtom) -> Ordering { + match (a, b) { + (CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()), + (CfgAtom::Flag(a), CfgAtom::KeyValue { key: b, value: _ }) => { + a.as_str().cmp(b.as_str()).then(Ordering::Less) + } + (CfgAtom::KeyValue { key: a, value: _ }, CfgAtom::Flag(b)) => { + a.as_str().cmp(b.as_str()).then(Ordering::Greater) + } + (CfgAtom::KeyValue { key: a, value: av }, CfgAtom::KeyValue { key: b, value: bv }) => a + .as_str() + .cmp(b.as_str()) + .then(av.as_str().cmp(bv.as_str())), + } +} diff --git a/rust/extractor/src/diagnostics.rs b/rust/extractor/src/diagnostics.rs index a39706a0cf28..b0201e2aed75 100644 --- a/rust/extractor/src/diagnostics.rs +++ b/rust/extractor/src/diagnostics.rs @@ -83,6 +83,7 @@ pub enum ExtractionStepKind { LoadSource, Parse, Extract, + CrateGraph, } #[derive(Debug, Clone, Serialize)] @@ -128,6 +129,10 @@ impl ExtractionStep { ) } + pub fn crate_graph(start: Instant) -> Self { + Self::new(start, ExtractionStepKind::CrateGraph, None) + } + pub fn load_source(start: Instant, target: &Path) -> Self { Self::new( start, diff --git a/rust/extractor/src/generated/.generated.list b/rust/extractor/src/generated/.generated.list index 528da1d56714..e70681ab2aae 100644 --- a/rust/extractor/src/generated/.generated.list +++ b/rust/extractor/src/generated/.generated.list @@ -1,2 +1,2 @@ mod.rs 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 4bcb9def847469aae9d8649461546b7c21ec97cf6e63d3cf394e339915ce65d7 -top.rs da0f43b99d3a173520048275597e2b052a7351f6fcb2ad5fc912257976742bb7 da0f43b99d3a173520048275597e2b052a7351f6fcb2ad5fc912257976742bb7 +top.rs 4b7dee6ebdbb2f8bd2f387cbb71e0481475de0a94c0baaac4699f19551256d65 4b7dee6ebdbb2f8bd2f387cbb71e0481475de0a94c0baaac4699f19551256d65 diff --git a/rust/extractor/src/generated/top.rs b/rust/extractor/src/generated/top.rs index 2774193823aa..7df57c79bf6c 100644 --- a/rust/extractor/src/generated/top.rs +++ b/rust/extractor/src/generated/top.rs @@ -22,6 +22,54 @@ impl trap::TrapClass for Element { fn class_name() -> &'static str { "Element" } } +#[derive(Debug)] +pub struct Crate { + pub id: trap::TrapId, + pub name: Option, + pub version: Option, + pub module: Option>, + pub cfg_options: Vec, + pub dependencies: Vec>, +} + +impl trap::TrapEntry for Crate { + fn extract_id(&mut self) -> trap::TrapId { + std::mem::replace(&mut self.id, trap::TrapId::Star) + } + + fn emit(self, id: trap::Label, out: &mut trap::Writer) { + out.add_tuple("crates", vec![id.into()]); + if let Some(v) = self.name { + out.add_tuple("crate_names", vec![id.into(), v.into()]); + } + if let Some(v) = self.version { + out.add_tuple("crate_versions", vec![id.into(), v.into()]); + } + if let Some(v) = self.module { + out.add_tuple("crate_modules", vec![id.into(), v.into()]); + } + for (i, v) in self.cfg_options.into_iter().enumerate() { + out.add_tuple("crate_cfg_options", vec![id.into(), i.into(), v.into()]); + } + for (i, v) in self.dependencies.into_iter().enumerate() { + out.add_tuple("crate_dependencies", vec![id.into(), i.into(), v.into()]); + } + } +} + +impl trap::TrapClass for Crate { + fn class_name() -> &'static str { "Crate" } +} + +impl From> for trap::Label { + fn from(value: trap::Label) -> Self { + // SAFETY: this is safe because in the dbscheme Crate is a subclass of Element + unsafe { + Self::from_untyped(value.as_untyped()) + } + } +} + #[derive(Debug)] pub struct ExtractorStep { pub id: trap::TrapId, diff --git a/rust/extractor/src/main.rs b/rust/extractor/src/main.rs index 17bf43b91c6f..0abcc8c968fe 100644 --- a/rust/extractor/src/main.rs +++ b/rust/extractor/src/main.rs @@ -22,6 +22,7 @@ use tracing_subscriber::util::SubscriberInitExt; mod archive; mod config; +mod crate_graph; mod diagnostics; pub mod generated; mod qltest; @@ -243,6 +244,11 @@ fn main() -> anyhow::Result<()> { if let Some((ref db, ref vfs)) = extractor.load_manifest(manifest, &cargo_config, &load_cargo_config) { + let before_crate_graph = Instant::now(); + crate_graph::extract_crate_graph(extractor.traps, db, vfs); + extractor + .steps + .push(ExtractionStep::crate_graph(before_crate_graph)); let semantics = Semantics::new(db); for file in files { match extractor.load_source(file, &semantics, vfs) { diff --git a/rust/extractor/src/trap.rs b/rust/extractor/src/trap.rs index d118b04b7162..ce739e067f0a 100644 --- a/rust/extractor/src/trap.rs +++ b/rust/extractor/src/trap.rs @@ -74,7 +74,7 @@ macro_rules! trap_key { $( key.push_str(&$x.as_key_part()); )* - $crate::TrapId::Key(key) + trap::TrapId::Key(key) }}; } @@ -123,7 +123,7 @@ impl From> for trap::Arg { } pub struct TrapFile { - path: PathBuf, + pub path: PathBuf, pub writer: Writer, compression: Compression, } @@ -171,6 +171,26 @@ impl TrapFile { ); } + pub fn emit_file_only_location( + &mut self, + file_label: Label, + entity_label: Label, + ) { + let location_label = extractor::location_label( + &mut self.writer, + trap::Location { + file_label: file_label.as_untyped(), + start_line: 0, + start_column: 0, + end_line: 0, + end_column: 0, + }, + ); + self.writer.add_tuple( + "locatable_locations", + vec![entity_label.into(), location_label.into()], + ); + } pub fn emit_diagnostic( &mut self, severity: DiagnosticSeverity, diff --git a/rust/ql/.generated.list b/rust/ql/.generated.list index 6e7a2892a418..c3cff92c6955 100644 --- a/rust/ql/.generated.list +++ b/rust/ql/.generated.list @@ -43,6 +43,7 @@ lib/codeql/rust/elements/ConstArg.qll f37b34417503bbd2f3ce09b3211d8fa71f6a954970 lib/codeql/rust/elements/ConstBlockPat.qll a25f42b84dbeb33e10955735ef53b8bb7e3258522d6d1a9068f19adaf1af89d9 eeb816d2b54db77a1e7bb70e90b68d040a0cd44e9d44455a223311c3615c5e6e lib/codeql/rust/elements/ConstParam.qll 248db1e3abef6943326c42478a15f148f8cdaa25649ef5578064b15924c53351 28babba3aea28a65c3fe3b3db6cb9c86f70d7391e9d6ef9188eb2e4513072f9f lib/codeql/rust/elements/ContinueExpr.qll 9f27c5d5c819ad0ebc5bd10967ba8d33a9dc95b9aae278fcfb1fcf9216bda79c 0dc061445a6b89854fdce92aaf022fdc76b724511a50bb777496ce75c9ecb262 +lib/codeql/rust/elements/Crate.qll 67a3b953a04244e2fcebe7a18be13bc7fdb8781669819e473823a9168f3f5412 aef65281efbc8c7e7b3747693626718ca25b3d9a90aa42221de00998eca44efe lib/codeql/rust/elements/DynTraitTypeRepr.qll 5953263ec1e77613170c13b5259b22a71c206a7e08841d2fa1a0b373b4014483 d4380c6cc460687dcd8598df27cad954ef4f508f1117a82460d15d295a7b64ab lib/codeql/rust/elements/Element.qll 0b62d139fef54ed2cf2e2334806aa9bfbc036c9c2085d558f15a42cc3fa84c48 24b999b93df79383ef27ede46e38da752868c88a07fe35fcff5d526684ba7294 lib/codeql/rust/elements/Enum.qll 2f122b042519d55e221fceac72fce24b30d4caf1947b25e9b68ee4a2095deb11 83a47445145e4fda8c3631db602a42dbb7a431f259eddf5c09dccd86f6abdd0e @@ -254,6 +255,7 @@ lib/codeql/rust/elements/internal/ConstImpl.qll 7aac2b441a41f21b7d788e3eb042554f lib/codeql/rust/elements/internal/ConstParamConstructor.qll f6645f952aac87c7e00e5e9661275312a1df47172088b4de6b5a253d5c4ed048 eda737470a7b89cf6a02715c9147d074041d6d00fd50d5b2d70266add6e4b571 lib/codeql/rust/elements/internal/ConstParamImpl.qll 909d85d857dfb973cd8e148744d3a88506d113d193d35ab0243be745d004ad45 c9e18170c5b4e4d5fca9f175bb139a248055b608ceafdd90c7182d06d67c3cba lib/codeql/rust/elements/internal/ContinueExprConstructor.qll cd93f1b35ccdb031d7e8deba92f6a76187f6009c454f3ea07e89ba459de57ca6 6f658e7d580c4c9068b01d6dd6f72888b8800860668a6653f8c3b27dc9996935 +lib/codeql/rust/elements/internal/CrateConstructor.qll 2a3710ed6ff4ffdbc773ac16e2cf176415be8908e1d59fd0702bdeddbae096f4 f75a069b0ef71e54089001eb3a34b8a9e4ce8e4f65ffa71b669b38cf86e0af40 lib/codeql/rust/elements/internal/DynTraitTypeReprConstructor.qll 6964e6c80fb7f5e283c1d15562cef18ed097452b7fcbc04eff780c7646675c7a f03c4830bf1b958fdfb6563136fa21c911b2e41ce1d1caee14ec572c7232866d lib/codeql/rust/elements/internal/DynTraitTypeReprImpl.qll fa2dc41b441c2e8d663644ca8ae53f473ac54b3c977490b5173787cffe4a62b1 118945a547627b639574c5f8e58bf7dbf5f3882c6d74ebf363c28c8fb88799d3 lib/codeql/rust/elements/internal/EnumConstructor.qll eca1a13937faacb1db50e4cf69d175f992f2204a5aaed9144bb6f3cb63814ac5 1bafba78b2729fdb052a25a1ba3f4f70871564aa4df632b4a1d467858a437924 @@ -501,6 +503,7 @@ lib/codeql/rust/elements/internal/generated/ConstArg.qll e2451cac6ee464f5b64883d lib/codeql/rust/elements/internal/generated/ConstBlockPat.qll 7526d83ee9565d74776f42db58b1a2efff6fb324cfc7137f51f2206fee815d79 0ab3c22908ff790e7092e576a5df3837db33c32a7922a513a0f5e495729c1ac5 lib/codeql/rust/elements/internal/generated/ConstParam.qll 310342603959a4d521418caec45b585b97e3a5bf79368769c7150f52596a7266 a5dd92f0b24d7dbdaea2daedba3c8d5f700ec7d3ace81ca368600da2ad610082 lib/codeql/rust/elements/internal/generated/ContinueExpr.qll e2010feb14fb6edeb83a991d9357e50edb770172ddfde2e8670b0d3e68169f28 48d09d661e1443002f6d22b8710e22c9c36d9daa9cde09c6366a61e960d717cb +lib/codeql/rust/elements/internal/generated/Crate.qll 6d28f07d4ddaf077119590a007a8cfad0c86cf0efabbde689fb4092577b883df d43013163916aa83f281314a72d02d7566e1f505aa36cfd8060a760b06b02683 lib/codeql/rust/elements/internal/generated/DynTraitTypeRepr.qll a9d540717af1f00dbea1c683fd6b846cddfb2968c7f3e021863276f123337787 1972efb9bca7aae9a9708ca6dcf398e5e8c6d2416a07d525dba1649b80fbe4d1 lib/codeql/rust/elements/internal/generated/Element.qll fb483b636180c699181c8aff83bc471b2c416206694f7028c671015918547663 542d1b9ae80c997974c94db3655887186df3921a8fa3f565eaf292dcfdac3c4c lib/codeql/rust/elements/internal/generated/Enum.qll 4f4cbc9cd758c20d476bc767b916c62ba434d1750067d0ffb63e0821bb95ec86 3da735d54022add50cec0217bbf8ec4cf29b47f4851ee327628bcdd6454989d0 @@ -574,7 +577,7 @@ lib/codeql/rust/elements/internal/generated/ParamList.qll c808c9d84dd7800573832b lib/codeql/rust/elements/internal/generated/ParenExpr.qll bc0731505bfe88516205ec360582a4222d2681d11342c93e15258590ddee82f2 d4bd6e0c80cf1d63746c88d4bcb3a01d4c75732e5da09e3ebd9437ced227fb60 lib/codeql/rust/elements/internal/generated/ParenPat.qll 4f168ef5d5bb87a903251cc31b2e44a759b099ec69c90af31783fbb15778c940 0e34f94a45a13396fd57d94c245dc64d1adde2ab0e22b56946f7e94c04e297fc lib/codeql/rust/elements/internal/generated/ParenTypeRepr.qll 40ab5c592e7699c621787793743e33988de71ff42ca27599f5ab3ddb70e3f7d8 12c0a6eed2202ee3e892f61da3b3ce77ac3190854cdf3097e8d2be98aa3cb91d -lib/codeql/rust/elements/internal/generated/ParentChild.qll 2992505ffc3279d58f2d03e89ec0f7d23aedebb3c3baf990bfbda894a6cc10e8 2f6b721e8244b444b47d41c2303fea166debee208544389c4dd9f2be0d62fe43 +lib/codeql/rust/elements/internal/generated/ParentChild.qll 9858c29b5852292e87dedc9bc9105b17915f5eb8198b6a29a2d621e26b7440ef 17c1a3e7bb344c7f9584ee2f28de622eb0f17ca4d967231f6215aa36261eeec9 lib/codeql/rust/elements/internal/generated/ParenthesizedArgList.qll c5fa328ea60d3a3333d7c7bb3480969c1873166c7ac8ebb9d0afad7a8099d1a8 2dbbb6200d96f7db7dea4a55bdeab8d67b14d39a43e0bd54ada019f7e466f163 lib/codeql/rust/elements/internal/generated/Pat.qll 3605ac062be2f294ee73336e9669027b8b655f4ad55660e1eab35266275154ee 7f9400db2884d336dd1d21df2a8093759c2a110be9bf6482ce8e80ae0fd74ed4 lib/codeql/rust/elements/internal/generated/Path.qll 8e47e91aff3f8c60f1ee8cb3887b8e4936c38e4665d052f2c92a939a969aac29 2c28beb89cabd7c7c91a5bc65c874f414cb96bbefde37b25811b61089a8a0053 @@ -589,7 +592,7 @@ lib/codeql/rust/elements/internal/generated/PtrTypeRepr.qll 51d1e9e683fc79dddbff lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9 lib/codeql/rust/elements/internal/generated/RangePat.qll 80826a6a6868a803aa2372e31c52a03e1811a3f1f2abdb469f91ca0bfdd9ecb6 34ee1e208c1690cba505dff2c588837c0cd91e185e2a87d1fe673191962276a9 -lib/codeql/rust/elements/internal/generated/Raw.qll cfbf960b83fc7f659214a48ced60001366410322a116de255678dec9d765d8dd c0d1ee182ccb916dedf33a272fb37ac394e0fac95ef4fadb8a93c7db8d11feb5 +lib/codeql/rust/elements/internal/generated/Raw.qll 4b60a7c36b770156d3710d811247bc1607c851a926d1546271f166af5b68c01f f65ba77cb2135b4a0d37d8c3e19e49f368426b14c7e48730f3fb9e65f9d7b9c5 lib/codeql/rust/elements/internal/generated/RecordExpr.qll 2131b2cb336caa76170082e69776011bf02576bbfdd34ba68ca84af24209250a 39a2e3ec32352b594c43cc1295e0e8b3f9808173322d3d73cb7d48ef969d5565 lib/codeql/rust/elements/internal/generated/RecordExprField.qll 7e9f8663d3b74ebbc9603b10c9912f082febba6bd73d344b100bbd3edf837802 fbe6b578e7fd5d5a6f21bbb8c388957ab7210a6a249ec71510a50fb35b319ea1 lib/codeql/rust/elements/internal/generated/RecordExprFieldList.qll 179a97211fe7aa6265085d4d54115cdbc0e1cd7c9b2135591e8f36d6432f13d3 dd44bbbc1e83a1ed3a587afb729d7debf7aeb7b63245de181726af13090e50c0 @@ -615,8 +618,8 @@ lib/codeql/rust/elements/internal/generated/Static.qll 0b336767104d2b852b9acd234 lib/codeql/rust/elements/internal/generated/Stmt.qll 8473ff532dd5cc9d7decaddcd174b94d610f6ca0aec8e473cc051dad9f3db917 6ef7d2b5237c2dbdcacbf7d8b39109d4dc100229f2b28b5c9e3e4fbf673ba72b lib/codeql/rust/elements/internal/generated/StmtList.qll a667193e32341e17400867c6e359878c4e645ef9f5f4d97676afc0283a33a026 a320ed678ee359302e2fc1b70a9476705cd616fcfa44a499d32f0c7715627f73 lib/codeql/rust/elements/internal/generated/Struct.qll 4d57f0db12dc7ad3e31e750a24172ef1505406b4dab16386af0674bd18bf8f4b 1a73c83df926b996f629316f74c61ea775be04532ab61b56af904223354f033e -lib/codeql/rust/elements/internal/generated/Synth.qll a00cdbb2ba5213976055f2339ae8bb01a42fdae22c355f171aa2ddfbbd7ec200 f49fbdcc7ab69258e3a86039a95d17b069e64922cc6a32a872dc696067b65507 -lib/codeql/rust/elements/internal/generated/SynthConstructors.qll 0d7929ad8c03e683500c64d1cfff73da518be9836a5d32e44d2f311fb4ae1b96 0d7929ad8c03e683500c64d1cfff73da518be9836a5d32e44d2f311fb4ae1b96 +lib/codeql/rust/elements/internal/generated/Synth.qll 554d5979ddb7afa42aa4d373cafcffd086e017104130f4a661264ee1c7b54653 059fa863ddab905050e1bbb4669722a14721b40b193bb91f1642da9a36d09018 +lib/codeql/rust/elements/internal/generated/SynthConstructors.qll f6321ef2a74bb3c869cb3d3fc7753ec90d03bf2c620597f7f1fea636309a3575 f6321ef2a74bb3c869cb3d3fc7753ec90d03bf2c620597f7f1fea636309a3575 lib/codeql/rust/elements/internal/generated/Token.qll 77a91a25ca5669703cf3a4353b591cef4d72caa6b0b9db07bb9e005d69c848d1 2fdffc4882ed3a6ca9ac6d1fb5f1ac5a471ca703e2ffdc642885fa558d6e373b lib/codeql/rust/elements/internal/generated/TokenTree.qll 8577c2b097c1be2f0f7daa5acfcf146f78674a424d99563e08a84dd3e6d91b46 d2f30764e84dbfc0a6a5d3d8a5f935cd432413688cb32da9c94e420fbc10665c lib/codeql/rust/elements/internal/generated/Trait.qll 8fa41b50fa0f68333534f2b66bb4ec8e103ff09ac8fa5c2cc64bc04beafec205 ce1c9aa6d0e2f05d28aab8e1165c3b9fb8e24681ade0cf6a9df2e8617abeae7e @@ -652,7 +655,7 @@ lib/codeql/rust/elements/internal/generated/WhileExpr.qll 7edf1f23fbf953a2baabcd lib/codeql/rust/elements/internal/generated/WildcardPat.qll d74b70b57a0a66bfae017a329352a5b27a6b9e73dd5521d627f680e810c6c59e 4b913b548ba27ff3c82fcd32cf996ff329cb57d176d3bebd0fcef394486ea499 lib/codeql/rust/elements/internal/generated/YeetExpr.qll cac328200872a35337b4bcb15c851afb4743f82c080f9738d295571eb01d7392 94af734eea08129b587fed849b643e7572800e8330c0b57d727d41abda47930b lib/codeql/rust/elements/internal/generated/YieldExpr.qll 37e5f0c1e373a22bbc53d8b7f2c0e1f476e5be5080b8437c5e964f4e83fad79a 4a9a68643401637bf48e5c2b2f74a6bf0ddcb4ff76f6bffb61d436b685621e85 -lib/codeql/rust/elements.qll fd66034a77b69f4741ca1488e8d04879da800bfa8d55492747c2b49d71a8067b fd66034a77b69f4741ca1488e8d04879da800bfa8d55492747c2b49d71a8067b +lib/codeql/rust/elements.qll 041993d344a4c10b301ac607075254175f1a1f927328de4f40f4df0260d0dece 041993d344a4c10b301ac607075254175f1a1f927328de4f40f4df0260d0dece test/extractor-tests/generated/Abi/Abi.ql 7f6e7dc4af86eca3ebdc79b10373988cd0871bd78b51997d3cffd969105e5fdd 2f936b6ca005c6157c755121584410c03e4a3949c23bee302fbe05ee10ce118f test/extractor-tests/generated/Abi/Abi_getAbiString.ql a496762fcec5a0887b87023bbf93e9b650f02e20113e25c44d6e4281ae8f5335 14109c7ce11ba25e3cd6e7f1b3fcb4cb00622f2a4eac91bfe43145c5f366bc52 test/extractor-tests/generated/ArgList/ArgList.ql e412927756e72165d0e7c5c9bd3fca89d08197bbf760db8fb7683c64bb2229bc 043dba8506946fbb87753e22c387987d7eded6ddb963aa067f9e60ef9024d684 @@ -750,6 +753,7 @@ test/extractor-tests/generated/ConstParam/ConstParam_getTypeRepr.ql f25a4695e06a test/extractor-tests/generated/ContinueExpr/ContinueExpr.ql 971ccb238aec663855745fa2669d5f8973a4e6c76bacdf0deaf23522ec1cf80c 4e3ceb4c4cd833ad8311bb02e5cda18163082e341cd8a3def60734a53cca8929 test/extractor-tests/generated/ContinueExpr/ContinueExpr_getAttr.ql acb261869d3b3c65e364e7b6fbd7afdf5305806d4417b05044beed9a81e66ea4 af35ce0aee87ddc7a0cd34be4a480c619940d036d5cecce0e4e1fcd75b7c553e test/extractor-tests/generated/ContinueExpr/ContinueExpr_getLifetime.ql 39dae9872d92fa9b15343c93da545c2b0e15b4f27f2296c200fd4611b68858d5 52a209022e3b83260b4ef5513ffbcc1ca1f7c21bad2c721a0d3698793d2161d2 +test/extractor-tests/generated/Crate/MISSING_SOURCE.txt b6cf5771fdbbe981aeb3f443ec7a40517b6e99ffc9817fd8872c2e344240dae1 b6cf5771fdbbe981aeb3f443ec7a40517b6e99ffc9817fd8872c2e344240dae1 test/extractor-tests/generated/DynTraitTypeRepr/DynTraitTypeRepr.ql 513d64b564f359e1022ae6f3d6d4a8ad637f595f01f29a6c2a167d1c2e8f1f99 0c7a7af6ee1005126b9ab77b2a7732821f85f1d2d426312c98206cbbedc19bb2 test/extractor-tests/generated/DynTraitTypeRepr/DynTraitTypeRepr_getTypeBoundList.ql b20720ff0b147d55cea6f2de44d5bf297e79991eaf103938ccd7ab9d129e9656 eb8c9db2581cea00c29d7772de0b0a125be02c37092217a419f1a2b6a9711a6c test/extractor-tests/generated/Enum/Enum.ql ed518d828d8e2e4790849284de1d0d5e728dbc2fe5e9f187e8ebfa2d503efd5a 7092b963eb133371e1cbc09d45f8c2308d7093523140b351d67073a8d258643e diff --git a/rust/ql/.gitattributes b/rust/ql/.gitattributes index 05ac0fbbf272..4802a68f7a33 100644 --- a/rust/ql/.gitattributes +++ b/rust/ql/.gitattributes @@ -45,6 +45,7 @@ /lib/codeql/rust/elements/ConstBlockPat.qll linguist-generated /lib/codeql/rust/elements/ConstParam.qll linguist-generated /lib/codeql/rust/elements/ContinueExpr.qll linguist-generated +/lib/codeql/rust/elements/Crate.qll linguist-generated /lib/codeql/rust/elements/DynTraitTypeRepr.qll linguist-generated /lib/codeql/rust/elements/Element.qll linguist-generated /lib/codeql/rust/elements/Enum.qll linguist-generated @@ -256,6 +257,7 @@ /lib/codeql/rust/elements/internal/ConstParamConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/ConstParamImpl.qll linguist-generated /lib/codeql/rust/elements/internal/ContinueExprConstructor.qll linguist-generated +/lib/codeql/rust/elements/internal/CrateConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/DynTraitTypeReprConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/DynTraitTypeReprImpl.qll linguist-generated /lib/codeql/rust/elements/internal/EnumConstructor.qll linguist-generated @@ -503,6 +505,7 @@ /lib/codeql/rust/elements/internal/generated/ConstBlockPat.qll linguist-generated /lib/codeql/rust/elements/internal/generated/ConstParam.qll linguist-generated /lib/codeql/rust/elements/internal/generated/ContinueExpr.qll linguist-generated +/lib/codeql/rust/elements/internal/generated/Crate.qll linguist-generated /lib/codeql/rust/elements/internal/generated/DynTraitTypeRepr.qll linguist-generated /lib/codeql/rust/elements/internal/generated/Element.qll linguist-generated /lib/codeql/rust/elements/internal/generated/Enum.qll linguist-generated @@ -752,6 +755,7 @@ /test/extractor-tests/generated/ContinueExpr/ContinueExpr.ql linguist-generated /test/extractor-tests/generated/ContinueExpr/ContinueExpr_getAttr.ql linguist-generated /test/extractor-tests/generated/ContinueExpr/ContinueExpr_getLifetime.ql linguist-generated +/test/extractor-tests/generated/Crate/MISSING_SOURCE.txt linguist-generated /test/extractor-tests/generated/DynTraitTypeRepr/DynTraitTypeRepr.ql linguist-generated /test/extractor-tests/generated/DynTraitTypeRepr/DynTraitTypeRepr_getTypeBoundList.ql linguist-generated /test/extractor-tests/generated/Enum/Enum.ql linguist-generated diff --git a/rust/ql/integration-tests/hello-project/diagnostics.expected b/rust/ql/integration-tests/hello-project/diagnostics.expected index 5455d51f2797..146d8514488e 100644 --- a/rust/ql/integration-tests/hello-project/diagnostics.expected +++ b/rust/ql/integration-tests/hello-project/diagnostics.expected @@ -1,6 +1,10 @@ { "attributes": { "durations": { + "crateGraph": { + "ms": "__REDACTED__", + "pretty": "__REDACTED__" + }, "extract": { "ms": "__REDACTED__", "pretty": "__REDACTED__" diff --git a/rust/ql/integration-tests/hello-project/functions.ql b/rust/ql/integration-tests/hello-project/functions.ql index 8d9a3213dad7..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/hello-project/functions.ql +++ b/rust/ql/integration-tests/hello-project/functions.ql @@ -1,5 +1,5 @@ import rust from Function f -where exists(f.getLocation().getFile().getRelativePath()) +where f.fromSource() select f diff --git a/rust/ql/integration-tests/hello-project/steps.cargo.expected b/rust/ql/integration-tests/hello-project/steps.cargo.expected index 958079845eb5..4deec0653daf 100644 --- a/rust/ql/integration-tests/hello-project/steps.cargo.expected +++ b/rust/ql/integration-tests/hello-project/steps.cargo.expected @@ -1,4 +1,5 @@ | Cargo.toml:0:0:0:0 | LoadManifest(Cargo.toml) | +| file://:0:0:0:0 | CrateGraph | | file://:0:0:0:0 | FindManifests | | src/directory_module/mod.rs:0:0:0:0 | Extract(src/directory_module/mod.rs) | | src/directory_module/mod.rs:0:0:0:0 | LoadSource(src/directory_module/mod.rs) | diff --git a/rust/ql/integration-tests/hello-project/steps.rust-project.expected b/rust/ql/integration-tests/hello-project/steps.rust-project.expected index 3ebf60a82de0..fa790e6cd7fd 100644 --- a/rust/ql/integration-tests/hello-project/steps.rust-project.expected +++ b/rust/ql/integration-tests/hello-project/steps.rust-project.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | CrateGraph | | file://:0:0:0:0 | FindManifests | | rust-project.json:0:0:0:0 | LoadManifest(rust-project.json) | | src/directory_module/mod.rs:0:0:0:0 | Extract(src/directory_module/mod.rs) | diff --git a/rust/ql/integration-tests/hello-project/summary.expected b/rust/ql/integration-tests/hello-project/summary.expected index 2ffb1f4e34f7..78127d05b465 100644 --- a/rust/ql/integration-tests/hello-project/summary.expected +++ b/rust/ql/integration-tests/hello-project/summary.expected @@ -1,4 +1,4 @@ -| Elements extracted | 66 | +| Elements extracted | 67 | | Elements unextracted | 0 | | Extraction errors | 0 | | Extraction warnings | 1 | diff --git a/rust/ql/integration-tests/hello-workspace/diagnostics.cargo.expected b/rust/ql/integration-tests/hello-workspace/diagnostics.cargo.expected index af11fd2f2e8e..9429dada005e 100644 --- a/rust/ql/integration-tests/hello-workspace/diagnostics.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/diagnostics.cargo.expected @@ -1,6 +1,10 @@ { "attributes": { "durations": { + "crateGraph": { + "ms": "__REDACTED__", + "pretty": "__REDACTED__" + }, "extract": { "ms": "__REDACTED__", "pretty": "__REDACTED__" diff --git a/rust/ql/integration-tests/hello-workspace/diagnostics.rust-project.expected b/rust/ql/integration-tests/hello-workspace/diagnostics.rust-project.expected index af11fd2f2e8e..9429dada005e 100644 --- a/rust/ql/integration-tests/hello-workspace/diagnostics.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/diagnostics.rust-project.expected @@ -1,6 +1,10 @@ { "attributes": { "durations": { + "crateGraph": { + "ms": "__REDACTED__", + "pretty": "__REDACTED__" + }, "extract": { "ms": "__REDACTED__", "pretty": "__REDACTED__" diff --git a/rust/ql/integration-tests/hello-workspace/functions.ql b/rust/ql/integration-tests/hello-workspace/functions.ql index 8d9a3213dad7..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/hello-workspace/functions.ql +++ b/rust/ql/integration-tests/hello-workspace/functions.ql @@ -1,5 +1,5 @@ import rust from Function f -where exists(f.getLocation().getFile().getRelativePath()) +where f.fromSource() select f diff --git a/rust/ql/integration-tests/hello-workspace/steps.cargo.expected b/rust/ql/integration-tests/hello-workspace/steps.cargo.expected index a2f125948098..32a3b1110247 100644 --- a/rust/ql/integration-tests/hello-workspace/steps.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/steps.cargo.expected @@ -5,6 +5,7 @@ | exe/src/main.rs:0:0:0:0 | Extract(exe/src/main.rs) | | exe/src/main.rs:0:0:0:0 | LoadSource(exe/src/main.rs) | | exe/src/main.rs:0:0:0:0 | Parse(exe/src/main.rs) | +| file://:0:0:0:0 | CrateGraph | | file://:0:0:0:0 | FindManifests | | lib/src/a_module/mod.rs:0:0:0:0 | Extract(lib/src/a_module/mod.rs) | | lib/src/a_module/mod.rs:0:0:0:0 | LoadSource(lib/src/a_module/mod.rs) | diff --git a/rust/ql/integration-tests/hello-workspace/steps.rust-project.expected b/rust/ql/integration-tests/hello-workspace/steps.rust-project.expected index c0958b56523e..e9a65e0c7be5 100644 --- a/rust/ql/integration-tests/hello-workspace/steps.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/steps.rust-project.expected @@ -4,6 +4,7 @@ | exe/src/main.rs:0:0:0:0 | Extract(exe/src/main.rs) | | exe/src/main.rs:0:0:0:0 | LoadSource(exe/src/main.rs) | | exe/src/main.rs:0:0:0:0 | Parse(exe/src/main.rs) | +| file://:0:0:0:0 | CrateGraph | | file://:0:0:0:0 | FindManifests | | lib/src/a_module/mod.rs:0:0:0:0 | Extract(lib/src/a_module/mod.rs) | | lib/src/a_module/mod.rs:0:0:0:0 | LoadSource(lib/src/a_module/mod.rs) | diff --git a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected index d08ce1a41166..b17a2cd64f2f 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected @@ -1,4 +1,4 @@ -| Elements extracted | 86 | +| Elements extracted | 87 | | Elements unextracted | 0 | | Extraction errors | 0 | | Extraction warnings | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected index d08ce1a41166..b17a2cd64f2f 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected @@ -1,4 +1,4 @@ -| Elements extracted | 86 | +| Elements extracted | 87 | | Elements unextracted | 0 | | Extraction errors | 0 | | Extraction warnings | 0 | diff --git a/rust/ql/integration-tests/options/cfg/functions.ql b/rust/ql/integration-tests/options/cfg/functions.ql index c84e7a82ca53..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/options/cfg/functions.ql +++ b/rust/ql/integration-tests/options/cfg/functions.ql @@ -1,4 +1,5 @@ import rust from Function f +where f.fromSource() select f diff --git a/rust/ql/integration-tests/options/features/functions.ql b/rust/ql/integration-tests/options/features/functions.ql index c84e7a82ca53..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/options/features/functions.ql +++ b/rust/ql/integration-tests/options/features/functions.ql @@ -1,4 +1,5 @@ import rust from Function f +where f.fromSource() select f diff --git a/rust/ql/integration-tests/options/target/functions.ql b/rust/ql/integration-tests/options/target/functions.ql index c84e7a82ca53..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/options/target/functions.ql +++ b/rust/ql/integration-tests/options/target/functions.ql @@ -1,4 +1,5 @@ import rust from Function f +where f.fromSource() select f diff --git a/rust/ql/integration-tests/qltest/dependencies/functions.ql b/rust/ql/integration-tests/qltest/dependencies/functions.ql index 8d9a3213dad7..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/qltest/dependencies/functions.ql +++ b/rust/ql/integration-tests/qltest/dependencies/functions.ql @@ -1,5 +1,5 @@ import rust from Function f -where exists(f.getLocation().getFile().getRelativePath()) +where f.fromSource() select f diff --git a/rust/ql/integration-tests/qltest/failing_cargo_check/functions.ql b/rust/ql/integration-tests/qltest/failing_cargo_check/functions.ql index 8d9a3213dad7..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/qltest/failing_cargo_check/functions.ql +++ b/rust/ql/integration-tests/qltest/failing_cargo_check/functions.ql @@ -1,5 +1,5 @@ import rust from Function f -where exists(f.getLocation().getFile().getRelativePath()) +where f.fromSource() select f diff --git a/rust/ql/integration-tests/qltest/lib/functions.ql b/rust/ql/integration-tests/qltest/lib/functions.ql index 8d9a3213dad7..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/qltest/lib/functions.ql +++ b/rust/ql/integration-tests/qltest/lib/functions.ql @@ -1,5 +1,5 @@ import rust from Function f -where exists(f.getLocation().getFile().getRelativePath()) +where f.fromSource() select f diff --git a/rust/ql/integration-tests/qltest/main/functions.ql b/rust/ql/integration-tests/qltest/main/functions.ql index 8d9a3213dad7..f1c18ab4a6e2 100644 --- a/rust/ql/integration-tests/qltest/main/functions.ql +++ b/rust/ql/integration-tests/qltest/main/functions.ql @@ -1,5 +1,5 @@ import rust from Function f -where exists(f.getLocation().getFile().getRelativePath()) +where f.fromSource() select f diff --git a/rust/ql/integration-tests/workspace-with-glob/steps.expected b/rust/ql/integration-tests/workspace-with-glob/steps.expected index 26ac51d87bd1..4b0e6ed828b6 100644 --- a/rust/ql/integration-tests/workspace-with-glob/steps.expected +++ b/rust/ql/integration-tests/workspace-with-glob/steps.expected @@ -1,6 +1,7 @@ | Cargo.toml:0:0:0:0 | LoadManifest(Cargo.toml) | | exe/src/main.rs:0:0:0:0 | Extract(exe/src/main.rs) | | exe/src/main.rs:0:0:0:0 | Parse(exe/src/main.rs) | +| file://:0:0:0:0 | CrateGraph | | file://:0:0:0:0 | FindManifests | | lib/src/lib.rs:0:0:0:0 | Extract(lib/src/lib.rs) | | lib/src/lib.rs:0:0:0:0 | Parse(lib/src/lib.rs) | diff --git a/rust/ql/lib/codeql/files/FileSystem.qll b/rust/ql/lib/codeql/files/FileSystem.qll index b13793b36001..175f50c7c9ea 100644 --- a/rust/ql/lib/codeql/files/FileSystem.qll +++ b/rust/ql/lib/codeql/files/FileSystem.qll @@ -55,7 +55,8 @@ class File extends Container, Impl::File { | node.getFile() = this and line = [/*loc.getStartLine(), */ loc.getEndLine()] and // ignore start locations for now as we're getting them wrong for things with a comment attached - not loc instanceof EmptyLocation + not loc instanceof EmptyLocation and + line > 0 ) ) } diff --git a/rust/ql/lib/codeql/rust/elements.qll b/rust/ql/lib/codeql/rust/elements.qll index 3bcb8cafb067..89bc9087a14b 100644 --- a/rust/ql/lib/codeql/rust/elements.qll +++ b/rust/ql/lib/codeql/rust/elements.qll @@ -48,6 +48,7 @@ import codeql.rust.elements.ConstArg import codeql.rust.elements.ConstBlockPat import codeql.rust.elements.ConstParam import codeql.rust.elements.ContinueExpr +import codeql.rust.elements.Crate import codeql.rust.elements.DynTraitTypeRepr import codeql.rust.elements.Element import codeql.rust.elements.Enum diff --git a/rust/ql/lib/codeql/rust/elements/Crate.qll b/rust/ql/lib/codeql/rust/elements/Crate.qll new file mode 100644 index 000000000000..fc2f137c49ef --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/Crate.qll @@ -0,0 +1,10 @@ +// generated by codegen, do not edit +/** + * This module provides the public class `Crate`. + */ + +private import internal.CrateImpl +import codeql.rust.elements.Element +import codeql.rust.elements.Module + +final class Crate = Impl::Crate; diff --git a/rust/ql/lib/codeql/rust/elements/internal/CrateConstructor.qll b/rust/ql/lib/codeql/rust/elements/internal/CrateConstructor.qll new file mode 100644 index 000000000000..25a5c4ce8a47 --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/internal/CrateConstructor.qll @@ -0,0 +1,14 @@ +// generated by codegen, remove this comment if you wish to edit this file +/** + * This module defines the hook used internally to tweak the characteristic predicate of + * `Crate` synthesized instances. + * INTERNAL: Do not use. + */ + +private import codeql.rust.elements.internal.generated.Raw + +/** + * The characteristic predicate of `Crate` synthesized instances. + * INTERNAL: Do not use. + */ +predicate constructCrate(Raw::Crate id) { any() } diff --git a/rust/ql/lib/codeql/rust/elements/internal/CrateImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/CrateImpl.qll new file mode 100644 index 000000000000..d03aca69d338 --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/internal/CrateImpl.qll @@ -0,0 +1,29 @@ +/** + * This module provides a hand-modifiable wrapper around the generated class `Crate`. + * + * INTERNAL: Do not use. + */ + +private import codeql.rust.elements.internal.generated.Crate + +/** + * INTERNAL: This module contains the customizable definition of `Crate` and should not + * be referenced directly. + */ +module Impl { + class Crate extends Generated::Crate { + override string toString() { result = strictconcat(int i | | this.toStringPart(i) order by i) } + + private string toStringPart(int i) { + i = 0 and result = "Crate(" + or + i = 1 and result = this.getName() + or + i = 2 and result = "@" + or + i = 3 and result = this.getVersion() + or + i = 4 and result = ")" + } + } +} diff --git a/rust/ql/lib/codeql/rust/elements/internal/LocatableImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/LocatableImpl.qll index 605c0e0f8161..5aeec330a37d 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/LocatableImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/LocatableImpl.qll @@ -41,6 +41,9 @@ module Impl { * Gets the primary file where this element occurs. */ File getFile() { result = this.getLocation().getFile() } + + /** Holds if this element is from source code. */ + predicate fromSource() { exists(this.getFile().getRelativePath()) } } /** Gets the non-synthesized location of `l`, if any. */ diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/Crate.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/Crate.qll new file mode 100644 index 000000000000..0bac8d8380db --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/Crate.qll @@ -0,0 +1,94 @@ +// generated by codegen, do not edit +/** + * This module provides the generated definition of `Crate`. + * INTERNAL: Do not import directly. + */ + +private import codeql.rust.elements.internal.generated.Synth +private import codeql.rust.elements.internal.generated.Raw +import codeql.rust.elements.Crate +import codeql.rust.elements.internal.ElementImpl::Impl as ElementImpl +import codeql.rust.elements.Module + +private class CrateAlias = Crate; + +/** + * INTERNAL: This module contains the fully generated definition of `Crate` and should not + * be referenced directly. + */ +module Generated { + /** + * INTERNAL: Do not reference the `Generated::Crate` class directly. + * Use the subclass `Crate`, where the following predicates are available. + */ + class Crate extends Synth::TCrate, ElementImpl::Element { + override string getAPrimaryQlClass() { result = "Crate" } + + /** + * Gets the name of this crate, if it exists. + */ + string getName() { result = Synth::convertCrateToRaw(this).(Raw::Crate).getName() } + + /** + * Holds if `getName()` exists. + */ + final predicate hasName() { exists(this.getName()) } + + /** + * Gets the version of this crate, if it exists. + */ + string getVersion() { result = Synth::convertCrateToRaw(this).(Raw::Crate).getVersion() } + + /** + * Holds if `getVersion()` exists. + */ + final predicate hasVersion() { exists(this.getVersion()) } + + /** + * Gets the module of this crate, if it exists. + */ + Module getModule() { + result = Synth::convertModuleFromRaw(Synth::convertCrateToRaw(this).(Raw::Crate).getModule()) + } + + /** + * Holds if `getModule()` exists. + */ + final predicate hasModule() { exists(this.getModule()) } + + /** + * Gets the `index`th cfg option of this crate (0-based). + */ + string getCfgOption(int index) { + result = Synth::convertCrateToRaw(this).(Raw::Crate).getCfgOption(index) + } + + /** + * Gets any of the cfg options of this crate. + */ + final string getACfgOption() { result = this.getCfgOption(_) } + + /** + * Gets the number of cfg options of this crate. + */ + final int getNumberOfCfgOptions() { result = count(int i | exists(this.getCfgOption(i))) } + + /** + * Gets the `index`th dependency of this crate (0-based). + */ + CrateAlias getDependency(int index) { + result = + Synth::convertCrateFromRaw(Synth::convertCrateToRaw(this).(Raw::Crate).getDependency(index)) + } + + /** + * Gets any of the dependencies of this crate. + */ + final CrateAlias getADependency() { result = this.getDependency(_) } + + /** + * Gets the number of dependencies of this crate. + */ + final int getNumberOfDependencies() { result = count(int i | exists(this.getDependency(i))) } + } +} diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll index ee97d8a4c601..7cd819ab5379 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/ParentChild.qll @@ -12,6 +12,19 @@ private module Impl { none() } + private Element getImmediateChildOfCrate(Crate e, int index, string partialPredicateCall) { + exists(int b, int bElement, int n | + b = 0 and + bElement = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfElement(e, i, _)) | i) and + n = bElement and + ( + none() + or + result = getImmediateChildOfElement(e, index - b, partialPredicateCall) + ) + ) + } + private Element getImmediateChildOfExtractorStep( ExtractorStep e, int index, string partialPredicateCall ) { @@ -4050,6 +4063,8 @@ private module Impl { // * none() simplifies generation, as we can append `or ...` without a special case for the first item none() or + result = getImmediateChildOfCrate(e, index, partialAccessor) + or result = getImmediateChildOfExtractorStep(e, index, partialAccessor) or result = getImmediateChildOfFormat(e, index, partialAccessor) diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll index a858c89ce57c..96ef2a3701c9 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll @@ -12,6 +12,38 @@ module Raw { string toString() { none() } } + /** + * INTERNAL: Do not use. + */ + class Crate extends @crate, Element { + override string toString() { result = "Crate" } + + /** + * Gets the name of this crate, if it exists. + */ + string getName() { crate_names(this, result) } + + /** + * Gets the version of this crate, if it exists. + */ + string getVersion() { crate_versions(this, result) } + + /** + * Gets the module of this crate, if it exists. + */ + Module getModule() { crate_modules(this, result) } + + /** + * Gets the `index`th cfg option of this crate (0-based). + */ + string getCfgOption(int index) { crate_cfg_options(this, index, result) } + + /** + * Gets the `index`th dependency of this crate (0-based). + */ + Crate getDependency(int index) { crate_dependencies(this, index, result) } + } + /** * INTERNAL: Do not use. */ diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/Synth.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/Synth.qll index fff08a91d81b..d7a423aaf2e1 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/generated/Synth.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/Synth.qll @@ -162,6 +162,10 @@ module Synth { * INTERNAL: Do not use. */ TContinueExpr(Raw::ContinueExpr id) { constructContinueExpr(id) } or + /** + * INTERNAL: Do not use. + */ + TCrate(Raw::Crate id) { constructCrate(id) } or /** * INTERNAL: Do not use. */ @@ -1061,6 +1065,12 @@ module Synth { */ TContinueExpr convertContinueExprFromRaw(Raw::Element e) { result = TContinueExpr(e) } + /** + * INTERNAL: Do not use. + * Converts a raw element to a synthesized `TCrate`, if possible. + */ + TCrate convertCrateFromRaw(Raw::Element e) { result = TCrate(e) } + /** * INTERNAL: Do not use. * Converts a raw element to a synthesized `TDynTraitTypeRepr`, if possible. @@ -2050,6 +2060,8 @@ module Synth { * Converts a raw DB element to a synthesized `TElement`, if possible. */ TElement convertElementFromRaw(Raw::Element e) { + result = convertCrateFromRaw(e) + or result = convertExtractorStepFromRaw(e) or result = convertLocatableFromRaw(e) @@ -2633,6 +2645,12 @@ module Synth { */ Raw::Element convertContinueExprToRaw(TContinueExpr e) { e = TContinueExpr(result) } + /** + * INTERNAL: Do not use. + * Converts a synthesized `TCrate` to a raw DB element, if possible. + */ + Raw::Element convertCrateToRaw(TCrate e) { e = TCrate(result) } + /** * INTERNAL: Do not use. * Converts a synthesized `TDynTraitTypeRepr` to a raw DB element, if possible. @@ -3620,6 +3638,8 @@ module Synth { * Converts a synthesized `TElement` to a raw DB element, if possible. */ Raw::Element convertElementToRaw(TElement e) { + result = convertCrateToRaw(e) + or result = convertExtractorStepToRaw(e) or result = convertLocatableToRaw(e) diff --git a/rust/ql/lib/codeql/rust/elements/internal/generated/SynthConstructors.qll b/rust/ql/lib/codeql/rust/elements/internal/generated/SynthConstructors.qll index 7cfc9bda34f4..1cd8fac638c3 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/generated/SynthConstructors.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/generated/SynthConstructors.qll @@ -40,6 +40,7 @@ import codeql.rust.elements.internal.ConstArgConstructor import codeql.rust.elements.internal.ConstBlockPatConstructor import codeql.rust.elements.internal.ConstParamConstructor import codeql.rust.elements.internal.ContinueExprConstructor +import codeql.rust.elements.internal.CrateConstructor import codeql.rust.elements.internal.DynTraitTypeReprConstructor import codeql.rust.elements.internal.EnumConstructor import codeql.rust.elements.internal.ExprStmtConstructor diff --git a/rust/ql/lib/codeql/rust/internal/AstConsistency.qll b/rust/ql/lib/codeql/rust/internal/AstConsistency.qll index 4069a77f4b2b..f65617872cb2 100644 --- a/rust/ql/lib/codeql/rust/internal/AstConsistency.qll +++ b/rust/ql/lib/codeql/rust/internal/AstConsistency.qll @@ -24,7 +24,9 @@ query predicate multipleLocations(Locatable e) { strictcount(e.getLocation()) > /** * Holds if `e` does not have a `Location`. */ -query predicate noLocation(Locatable e) { not exists(e.getLocation()) } +query predicate noLocation(Locatable e) { + not exists(e.getLocation()) and not e.(AstNode).getParentNode*() = any(Crate c).getModule() +} private predicate multiplePrimaryQlClasses(Element e) { strictcount(string cls | cls = e.getAPrimaryQlClass() and cls != "VariableAccess") > 1 diff --git a/rust/ql/lib/rust.dbscheme b/rust/ql/lib/rust.dbscheme index 29a351d42ac6..2791dade0116 100644 --- a/rust/ql/lib/rust.dbscheme +++ b/rust/ql/lib/rust.dbscheme @@ -120,11 +120,48 @@ locatable_locations( // from schema @element = - @extractor_step + @crate +| @extractor_step | @locatable | @unextracted ; +crates( + unique int id: @crate +); + +#keyset[id] +crate_names( + int id: @crate ref, + string name: string ref +); + +#keyset[id] +crate_versions( + int id: @crate ref, + string version: string ref +); + +#keyset[id] +crate_modules( + int id: @crate ref, + int module: @module ref +); + +#keyset[id, index] +crate_cfg_options( + int id: @crate ref, + int index: int ref, + string cfg_option: string ref +); + +#keyset[id, index] +crate_dependencies( + int id: @crate ref, + int index: int ref, + int dependency: @crate ref +); + extractor_steps( unique int id: @extractor_step, string action: string ref, diff --git a/rust/ql/src/queries/summary/SummaryStats.ql b/rust/ql/src/queries/summary/SummaryStats.ql index 4e14045428f2..4795dee51063 100644 --- a/rust/ql/src/queries/summary/SummaryStats.ql +++ b/rust/ql/src/queries/summary/SummaryStats.ql @@ -14,9 +14,17 @@ import codeql.rust.Diagnostics import Stats import TaintReach +class CrateElement extends Element { + CrateElement() { + this instanceof Crate or + this.(AstNode).getParentNode*() = any(Crate c).getModule() + } +} + from string key, int value where - key = "Elements extracted" and value = count(Element e | not e instanceof Unextracted) + key = "Elements extracted" and + value = count(Element e | not e instanceof Unextracted and not e instanceof CrateElement) or key = "Elements unextracted" and value = count(Unextracted e) or diff --git a/rust/ql/test/TestUtils.qll b/rust/ql/test/TestUtils.qll index 214928691c05..dfd0d95141ea 100644 --- a/rust/ql/test/TestUtils.qll +++ b/rust/ql/test/TestUtils.qll @@ -1,3 +1,10 @@ private import rust -predicate toBeTested(Element e) { any() } +predicate toBeTested(Element e) { not e instanceof CrateElement } + +class CrateElement extends Element { + CrateElement() { + this instanceof Crate or + any(Crate c).getModule() = this.(AstNode).getParentNode*() + } +} diff --git a/rust/ql/test/extractor-tests/crate_graph/crates.expected b/rust/ql/test/extractor-tests/crate_graph/crates.expected new file mode 100644 index 000000000000..d3e9347973f7 --- /dev/null +++ b/rust/ql/test/extractor-tests/crate_graph/crates.expected @@ -0,0 +1,117 @@ +#-----| Crate(allocator_api2@0.2.21) + +#-----| Crate(core@0.0.0) +#-----| -> Crate(rand@0.8.5) +#-----| -> Crate(rand_xorshift@0.3.0) + +#-----| Crate(compiler_builtins@0.1.140) +#-----| -> Crate(core@0.0.0) + +#-----| Crate(cfg_if@1.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) + +#-----| Crate(std@0.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(cfg_if@1.0.0) +#-----| -> Crate(alloc@0.0.0) +#-----| -> Crate(hashbrown@0.15.2) +#-----| -> Crate(libc@0.2.169) +#-----| -> Crate(rand@0.8.5) +#-----| -> Crate(rand_xorshift@0.3.0) +#-----| -> Crate(rustc_demangle@0.1.24) +#-----| -> Crate(panic_abort@0.0.0) +#-----| -> Crate(unwind@0.0.0) +#-----| -> Crate(panic_unwind@0.0.0) +#-----| -> Crate(std_detect@0.1.5) + +#-----| Crate(unicode_width@0.1.14) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(std@0.0.0) + +#-----| Crate(getopts@0.2.21) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(std@0.0.0) +#-----| -> Crate(unicode_width@0.1.14) + +#-----| Crate(alloc@0.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(rand@0.8.5) +#-----| -> Crate(rand_xorshift@0.3.0) + +#-----| Crate(hashbrown@0.15.2) +#-----| -> Crate(allocator_api2@0.2.21) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(alloc@0.0.0) + +#-----| Crate(libc@0.2.169) +#-----| -> Crate(core@0.0.0) + +#-----| Crate(rand_core@0.6.4) + +#-----| Crate(rand@0.8.5) +#-----| -> Crate(rand_core@0.6.4) + +#-----| Crate(rand_xorshift@0.3.0) +#-----| -> Crate(rand_core@0.6.4) + +#-----| Crate(rustc_demangle@0.1.24) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) + +#-----| Crate(panic_abort@0.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(cfg_if@1.0.0) +#-----| -> Crate(alloc@0.0.0) +#-----| -> Crate(libc@0.2.169) + +#-----| Crate(unwind@0.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(cfg_if@1.0.0) +#-----| -> Crate(libc@0.2.169) + +#-----| Crate(panic_unwind@0.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(cfg_if@1.0.0) +#-----| -> Crate(alloc@0.0.0) +#-----| -> Crate(libc@0.2.169) +#-----| -> Crate(unwind@0.0.0) + +#-----| Crate(proc_macro@0.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(std@0.0.0) + +#-----| Crate(std_detect@0.1.5) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(compiler_builtins@0.1.140) +#-----| -> Crate(cfg_if@1.0.0) +#-----| -> Crate(alloc@0.0.0) +#-----| -> Crate(libc@0.2.169) + +#-----| Crate(test@0.0.0) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(std@0.0.0) +#-----| -> Crate(getopts@0.2.21) +#-----| -> Crate(libc@0.2.169) + +#-----| Crate(test@0.0.1) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(std@0.0.0) +#-----| -> Crate(alloc@0.0.0) +#-----| -> Crate(proc_macro@0.0.0) +#-----| -> Crate(test@0.0.0) + +#-----| Crate(main@0.0.1) +#-----| -> Crate(core@0.0.0) +#-----| -> Crate(std@0.0.0) +#-----| -> Crate(alloc@0.0.0) +#-----| -> Crate(proc_macro@0.0.0) +#-----| -> Crate(test@0.0.0) +#-----| -> Crate(test@0.0.1) diff --git a/rust/ql/test/extractor-tests/crate_graph/crates.ql b/rust/ql/test/extractor-tests/crate_graph/crates.ql new file mode 100644 index 000000000000..f5475c015e18 --- /dev/null +++ b/rust/ql/test/extractor-tests/crate_graph/crates.ql @@ -0,0 +1,11 @@ +/** + * @id crate-graph + * @name Crate Graph + * @kind graph + */ + +import rust + +query predicate nodes(Crate c) { any() } + +query predicate edges(Crate c1, Crate c2) { c1.getADependency() = c2 } diff --git a/rust/ql/test/extractor-tests/crate_graph/main.rs b/rust/ql/test/extractor-tests/crate_graph/main.rs new file mode 100644 index 000000000000..774cd476e3b6 --- /dev/null +++ b/rust/ql/test/extractor-tests/crate_graph/main.rs @@ -0,0 +1,3 @@ +fn main() { + println! {"Hello world"} +} diff --git a/rust/ql/test/extractor-tests/crate_graph/module.rs b/rust/ql/test/extractor-tests/crate_graph/module.rs new file mode 100644 index 000000000000..e163026e817c --- /dev/null +++ b/rust/ql/test/extractor-tests/crate_graph/module.rs @@ -0,0 +1,42 @@ +use std::fmt; + +pub enum X { + A, + B, +} + +pub struct X_List { + x: X, + tail: Option>, +} + +pub fn length(list: X_List) -> usize { + match list { + X_List { x: _, tail: None } => 1, + X_List { + x: _, + tail: Some(tail), + } => 1 + length(*tail), + } +} +pub trait AsString { + fn as_string(&self) -> &str; +} + +impl AsString for X { + fn as_string(&self) -> &str { + match self { + X::A => "a", + X::B => "b", + } + } +} + +impl fmt::Display for X { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_string()) + } +} + +pub const X_A: X = X::A; +pub static X_B: X = X::B; diff --git a/rust/ql/test/extractor-tests/crate_graph/modules.expected b/rust/ql/test/extractor-tests/crate_graph/modules.expected new file mode 100644 index 000000000000..0bf8f0858f81 --- /dev/null +++ b/rust/ql/test/extractor-tests/crate_graph/modules.expected @@ -0,0 +1,38 @@ +#-----| Const + +#-----| Static + +#-----| enum X + +#-----| fn as_string + +#-----| fn as_string + +#-----| fn fmt + +#-----| fn length + +#-----| impl ...::Display for ...::X { ... } +#-----| -> fn fmt + +#-----| impl AsString for ...::X { ... } +#-----| -> fn as_string + +lib.rs: +# 0| mod crate +#-----| -> mod module + +#-----| mod module +#-----| -> Const +#-----| -> Static +#-----| -> enum X +#-----| -> fn length +#-----| -> impl ...::Display for ...::X { ... } +#-----| -> impl AsString for ...::X { ... } +#-----| -> struct X_List +#-----| -> trait AsString + +#-----| struct X_List + +#-----| trait AsString +#-----| -> fn as_string diff --git a/rust/ql/test/extractor-tests/crate_graph/modules.ql b/rust/ql/test/extractor-tests/crate_graph/modules.ql new file mode 100644 index 000000000000..42b0e5c0fcbb --- /dev/null +++ b/rust/ql/test/extractor-tests/crate_graph/modules.ql @@ -0,0 +1,45 @@ +/** + * @id module-graph + * @name Module and Item Graph + * @kind graph + */ + +import rust + +predicate nodes(Item i) { i instanceof RelevantNode } + +class RelevantNode extends Item { + RelevantNode() { + this.getParentNode*() = + any(Crate m | m.getName() = "test" and m.getVersion() = "0.0.1").getModule() + } +} + +predicate edges(RelevantNode container, RelevantNode element) { + element = container.(Module).getItemList().getAnItem() or + element = container.(Impl).getAssocItemList().getAnAssocItem() or + element = container.(Trait).getAssocItemList().getAnAssocItem() +} + +query predicate nodes(RelevantNode node, string attr, string val) { + nodes(node) and + ( + attr = "semmle.label" and + val = node.toString() + or + attr = "semmle.order" and + val = + any(int i | node = rank[i](RelevantNode n | nodes(n) | n order by n.toString())).toString() + ) +} + +query predicate edges(RelevantNode pred, RelevantNode succ, string attr, string val) { + edges(pred, succ) and + ( + attr = "semmle.label" and + val = "" + or + attr = "semmle.order" and + val = any(int i | succ = rank[i](Item s | edges(pred, s) | s order by s.toString())).toString() + ) +} diff --git a/rust/ql/test/extractor-tests/generated/Crate/MISSING_SOURCE.txt b/rust/ql/test/extractor-tests/generated/Crate/MISSING_SOURCE.txt new file mode 100644 index 000000000000..7f96b17b1f3c --- /dev/null +++ b/rust/ql/test/extractor-tests/generated/Crate/MISSING_SOURCE.txt @@ -0,0 +1,4 @@ +// generated by codegen, do not edit + +After a source file is added in this directory and codegen is run again, test queries +will appear and this file will be deleted diff --git a/rust/ql/test/extractor-tests/utf8/ast.ql b/rust/ql/test/extractor-tests/utf8/ast.ql index 420f7e94eb9a..8e484aedad9b 100644 --- a/rust/ql/test/extractor-tests/utf8/ast.ql +++ b/rust/ql/test/extractor-tests/utf8/ast.ql @@ -1,3 +1,4 @@ import codeql.rust.elements +import TestUtils -select any(AstNode n) +select any(AstNode n | toBeTested(n)) diff --git a/rust/ql/test/library-tests/path-resolution/path-resolution.ql b/rust/ql/test/library-tests/path-resolution/path-resolution.ql index bce15517b570..f33e312af28a 100644 --- a/rust/ql/test/library-tests/path-resolution/path-resolution.ql +++ b/rust/ql/test/library-tests/path-resolution/path-resolution.ql @@ -1,10 +1,11 @@ import rust import codeql.rust.elements.internal.PathResolution import utils.test.InlineExpectationsTest +import TestUtils -query predicate mod(Module m) { any() } +query predicate mod(Module m) { toBeTested(m) } -query predicate resolvePath(Path p, ItemNode i) { i = resolvePath(p) } +query predicate resolvePath(Path p, ItemNode i) { toBeTested(p) and i = resolvePath(p) } module ResolveTest implements TestSig { string getARelevantTag() { result = "item" } diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index 5249eae29b1f..797e173c023a 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -1,4 +1,4 @@ -| Elements extracted | 405 | +| Elements extracted | 406 | | Elements unextracted | 0 | | Extraction errors | 0 | | Extraction warnings | 7 | diff --git a/rust/schema/prelude.py b/rust/schema/prelude.py index c0637826fa25..e332de1f5a7b 100644 --- a/rust/schema/prelude.py +++ b/rust/schema/prelude.py @@ -5,6 +5,7 @@ File = imported("File", "codeql.files.FileSystem") + @qltest.skip class Element: pass @@ -85,7 +86,8 @@ class Addressable(AstNode): or `{}::name` for addressable items defined in an anonymous block (and only addressable there-in). """) | rust.detach | ql.internal - crate_origin: optional[string] | desc("One of `rustc:`, `repo::` or `lang:`.") | rust.detach | ql.internal + crate_origin: optional[string] | desc( + "One of `rustc:`, `repo::` or `lang:`.") | rust.detach | ql.internal class Resolvable(AstNode): @@ -109,3 +111,11 @@ class ExtractorStep(Element): action: string file: optional[File] duration_ms: int + + +class Crate(Element): + name: optional[string] + version: optional[string] + module: optional["Module"] + cfg_options: list[string] + dependencies: list["Crate"]