diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ec4104fe6..636fe25dd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -23,6 +23,7 @@ updates: - "deno_task_shell" - "gix" - "semver" + - "salsa" - package-ecosystem: "github-actions" directory: "/" diff --git a/Cargo.lock b/Cargo.lock index 8a21ab3a9..28b29785c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4718,14 +4718,16 @@ dependencies = [ "assert_fs", "cairo-lang-compiler", "cairo-lang-defs", + "cairo-lang-doc", "cairo-lang-filesystem", + "cairo-lang-parser", "cairo-lang-semantic", + "cairo-lang-starknet", "cairo-lang-syntax", "cairo-lang-utils", - "camino", "clap", "indoc", - "itertools 0.12.1", + "salsa", "scarb-metadata 1.12.0", "scarb-test-support", "scarb-ui", diff --git a/Cargo.toml b/Cargo.toml index bf041f4a0..63a6313d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ cairo-lang-compiler = { git = "https://github.com/starkware-libs/cairo", rev = " cairo-lang-debug = { git = "https://github.com/starkware-libs/cairo", rev = "43cf361d9b6b26ec8cd5ee076dd15341bde7577c" } cairo-lang-defs = { git = "https://github.com/starkware-libs/cairo", rev = "43cf361d9b6b26ec8cd5ee076dd15341bde7577c" } cairo-lang-diagnostics = { git = "https://github.com/starkware-libs/cairo", rev = "43cf361d9b6b26ec8cd5ee076dd15341bde7577c" } +cairo-lang-doc = { git = "https://github.com/starkware-libs/cairo", rev = "43cf361d9b6b26ec8cd5ee076dd15341bde7577c" } cairo-lang-filesystem = { git = "https://github.com/starkware-libs/cairo", rev = "43cf361d9b6b26ec8cd5ee076dd15341bde7577c" } cairo-lang-formatter = { git = "https://github.com/starkware-libs/cairo", rev = "43cf361d9b6b26ec8cd5ee076dd15341bde7577c" } cairo-lang-language-server = { git = "https://github.com/starkware-libs/cairo", rev = "43cf361d9b6b26ec8cd5ee076dd15341bde7577c" } @@ -99,6 +100,7 @@ ra_ap_toolchain = "0.0.218" rayon = "1.10" redb = "2.1.1" reqwest = { version = "0.11", features = ["gzip", "brotli", "deflate", "json", "stream"], default-features = false } +salsa = "0.16.1" semver = { version = "1", features = ["serde"] } serde = { version = "1", features = ["serde_derive"] } serde-untagged = "0.1" diff --git a/extensions/scarb-doc/Cargo.toml b/extensions/scarb-doc/Cargo.toml index 204efb1e2..e20f526c7 100644 --- a/extensions/scarb-doc/Cargo.toml +++ b/extensions/scarb-doc/Cargo.toml @@ -10,21 +10,23 @@ repository.workspace = true [dependencies] anyhow.workspace = true -camino.workspace = true clap.workspace = true cairo-lang-compiler.workspace = true cairo-lang-defs.workspace = true +cairo-lang-doc.workspace = true +cairo-lang-filesystem.workspace = true +cairo-lang-parser.workspace = true cairo-lang-semantic.workspace = true +cairo-lang-starknet.workspace = true cairo-lang-syntax.workspace = true -cairo-lang-filesystem.workspace = true cairo-lang-utils.workspace = true scarb-metadata = { path = "../../scarb-metadata" } scarb-ui = { path = "../../utils/scarb-ui" } serde_json.workspace = true -itertools.workspace = true +salsa.workspace = true smol_str.workspace = true [dev-dependencies] -scarb-test-support = { path = "../../utils/scarb-test-support" } assert_fs.workspace = true indoc.workspace = true +scarb-test-support = { path = "../../utils/scarb-test-support" } diff --git a/extensions/scarb-doc/src/db.rs b/extensions/scarb-doc/src/db.rs new file mode 100644 index 000000000..0c23ce968 --- /dev/null +++ b/extensions/scarb-doc/src/db.rs @@ -0,0 +1,126 @@ +use cairo_lang_compiler::project::{ + update_crate_root, update_crate_roots_from_project_config, ProjectConfig, +}; +use cairo_lang_defs::db::{DefsDatabase, DefsGroup}; +use cairo_lang_doc::db::{DocDatabase, DocGroup}; +use cairo_lang_filesystem::cfg::{Cfg, CfgSet}; +use cairo_lang_filesystem::db::{ + init_files_group, AsFilesGroupMut, FilesDatabase, FilesGroup, CORELIB_CRATE_NAME, +}; +use cairo_lang_parser::db::{ParserDatabase, ParserGroup}; +use cairo_lang_semantic::db::{SemanticDatabase, SemanticGroup}; +use cairo_lang_semantic::inline_macros::get_default_plugin_suite; +use cairo_lang_semantic::plugin::PluginSuite; +use cairo_lang_starknet::starknet_plugin_suite; +use cairo_lang_syntax::node::db::{SyntaxDatabase, SyntaxGroup}; +use cairo_lang_utils::Upcast; + +use salsa; + +/// The Cairo compiler Salsa database tailored for scarb-doc usage. +#[salsa::database( + FilesDatabase, + ParserDatabase, + SyntaxDatabase, + DefsDatabase, + SemanticDatabase, + DocDatabase +)] +pub struct ScarbDocDatabase { + storage: salsa::Storage, +} + +impl ScarbDocDatabase { + pub fn new(project_config: Option) -> Self { + let mut db = Self { + storage: Default::default(), + }; + + init_files_group(&mut db); + + db.set_cfg_set(Self::initial_cfg_set().into()); + let plugin_suite = [get_default_plugin_suite(), starknet_plugin_suite()] + .into_iter() + .fold(PluginSuite::default(), |mut acc, suite| { + acc.add(suite); + acc + }); + + db.apply_plugin_suite(plugin_suite); + + if let Some(config) = project_config { + db.apply_project_config(config); + } + + db + } + + fn initial_cfg_set() -> CfgSet { + CfgSet::from_iter([Cfg::name("doc")]) + } + + fn apply_plugin_suite(&mut self, plugin_suite: PluginSuite) { + self.set_macro_plugins(plugin_suite.plugins); + self.set_inline_macro_plugins(plugin_suite.inline_macro_plugins.into()); + self.set_analyzer_plugins(plugin_suite.analyzer_plugins); + } + + fn apply_project_config(&mut self, config: ProjectConfig) { + update_crate_roots_from_project_config(self, &config); + if let Some(corelib) = &config.corelib { + update_crate_root(self, &config, CORELIB_CRATE_NAME.into(), corelib.clone()); + } + } +} + +impl salsa::Database for ScarbDocDatabase {} + +impl salsa::ParallelDatabase for ScarbDocDatabase { + fn snapshot(&self) -> salsa::Snapshot { + salsa::Snapshot::new(ScarbDocDatabase { + storage: self.storage.snapshot(), + }) + } +} + +impl AsFilesGroupMut for ScarbDocDatabase { + fn as_files_group_mut(&mut self) -> &mut (dyn FilesGroup + 'static) { + self + } +} + +impl Upcast for ScarbDocDatabase { + fn upcast(&self) -> &(dyn FilesGroup + 'static) { + self + } +} + +impl Upcast for ScarbDocDatabase { + fn upcast(&self) -> &(dyn ParserGroup + 'static) { + self + } +} + +impl Upcast for ScarbDocDatabase { + fn upcast(&self) -> &(dyn SyntaxGroup + 'static) { + self + } +} + +impl Upcast for ScarbDocDatabase { + fn upcast(&self) -> &(dyn DefsGroup + 'static) { + self + } +} + +impl Upcast for ScarbDocDatabase { + fn upcast(&self) -> &(dyn SemanticGroup + 'static) { + self + } +} + +impl Upcast for ScarbDocDatabase { + fn upcast(&self) -> &(dyn DocGroup + 'static) { + self + } +} diff --git a/extensions/scarb-doc/src/lib.rs b/extensions/scarb-doc/src/lib.rs new file mode 100644 index 000000000..0a24f7947 --- /dev/null +++ b/extensions/scarb-doc/src/lib.rs @@ -0,0 +1,3 @@ +pub mod compilation; +pub mod db; +pub mod types; diff --git a/extensions/scarb-doc/src/main.rs b/extensions/scarb-doc/src/main.rs index eb9f4abcd..be8d5011c 100644 --- a/extensions/scarb-doc/src/main.rs +++ b/extensions/scarb-doc/src/main.rs @@ -4,15 +4,13 @@ use clap::Parser; use scarb_metadata::MetadataCommand; use scarb_ui::args::PackagesFilter; -use cairo_lang_compiler::db::RootDatabase; use cairo_lang_filesystem::db::FilesGroup; use cairo_lang_filesystem::ids::CrateLongId; -use compilation::get_project_config; -use types::Crate; - -mod compilation; -mod types; +use scarb_doc::compilation::get_project_config; +use scarb_doc::db::ScarbDocDatabase; +use scarb_doc::types; +use scarb_doc::types::Crate; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -39,14 +37,10 @@ fn main() -> Result<()> { let project_config = get_project_config(&metadata, &package_metadata); - let db = &mut { - let mut b = RootDatabase::builder(); - b.with_project_config(project_config); - b.build()? - }; + let db = ScarbDocDatabase::new(Some(project_config)); let main_crate_id = db.intern_crate(CrateLongId::Real(package_metadata.name.clone().into())); - let crate_ = Crate::new(db, main_crate_id); + let crate_ = Crate::new(&db, main_crate_id); print_module(&crate_.root_module); diff --git a/extensions/scarb-doc/src/types.rs b/extensions/scarb-doc/src/types.rs index d02051621..143b9991d 100644 --- a/extensions/scarb-doc/src/types.rs +++ b/extensions/scarb-doc/src/types.rs @@ -4,8 +4,10 @@ use cairo_lang_defs::db::DefsGroup; use cairo_lang_defs::ids::{ ConstantId, EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, ImplAliasId, ImplDefId, - ModuleId, ModuleItemId, ModuleTypeAliasId, StructId, TraitId, UseId, + LookupItemId, ModuleId, ModuleItemId, ModuleTypeAliasId, NamedLanguageElementId, StructId, + TopLevelLanguageElementId, TraitId, UseId, }; +use cairo_lang_doc::db::DocGroup; use cairo_lang_filesystem::ids::CrateId; use cairo_lang_syntax::node::{ast, TypedSyntaxNode}; @@ -15,7 +17,7 @@ pub struct Crate { } impl Crate { - pub fn new(db: &dyn DefsGroup, crate_id: CrateId) -> Self { + pub fn new(db: &dyn DocGroup, crate_id: CrateId) -> Self { Self { root_module: Module::new(db, ModuleId::CrateRoot(crate_id)), } @@ -42,74 +44,75 @@ pub struct Module { } impl Module { - pub fn new(db: &dyn DefsGroup, module_id: ModuleId) -> Self { - let module_constants = db.module_constants(module_id).unwrap(); + pub fn new(db: &dyn DocGroup, module_id: ModuleId) -> Self { + let defs_db: &dyn DefsGroup = db.upcast(); + let module_constants = defs_db.module_constants(module_id).unwrap(); let constants = module_constants .iter() .map(|(id, node)| Constant::new(db, *id, node)) .collect(); - let module_uses = db.module_uses(module_id).unwrap(); + let module_uses = defs_db.module_uses(module_id).unwrap(); let uses = module_uses .iter() .map(|(id, node)| Use::new(db, *id, node)) .collect(); - let module_free_functions = db.module_free_functions(module_id).unwrap(); + let module_free_functions = defs_db.module_free_functions(module_id).unwrap(); let free_functions = module_free_functions .iter() .map(|(id, node)| FreeFunction::new(db, *id, node)) .collect(); - let module_structs = db.module_structs(module_id).unwrap(); + let module_structs = defs_db.module_structs(module_id).unwrap(); let structs = module_structs .iter() .map(|(id, node)| Struct::new(db, *id, node)) .collect(); - let module_enums = db.module_enums(module_id).unwrap(); + let module_enums = defs_db.module_enums(module_id).unwrap(); let enums = module_enums .iter() .map(|(id, node)| Enum::new(db, *id, node)) .collect(); - let module_type_aliases = db.module_type_aliases(module_id).unwrap(); + let module_type_aliases = defs_db.module_type_aliases(module_id).unwrap(); let type_aliases = module_type_aliases .iter() .map(|(id, node)| TypeAlias::new(db, *id, node)) .collect(); - let module_impl_aliases = db.module_impl_aliases(module_id).unwrap(); + let module_impl_aliases = defs_db.module_impl_aliases(module_id).unwrap(); let impl_aliases = module_impl_aliases .iter() .map(|(id, node)| ImplAlias::new(db, *id, node)) .collect(); - let module_traits = db.module_traits(module_id).unwrap(); + let module_traits = defs_db.module_traits(module_id).unwrap(); let traits = module_traits .iter() .map(|(id, node)| Trait::new(db, *id, node)) .collect(); - let module_impls = db.module_impls(module_id).unwrap(); + let module_impls = defs_db.module_impls(module_id).unwrap(); let impls = module_impls .iter() .map(|(id, node)| Impl::new(db, *id, node)) .collect(); - let module_extern_types = db.module_extern_types(module_id).unwrap(); + let module_extern_types = defs_db.module_extern_types(module_id).unwrap(); let extern_types = module_extern_types .iter() .map(|(id, node)| ExternType::new(db, *id, node)) .collect(); - let module_extern_functions = db.module_extern_functions(module_id).unwrap(); + let module_extern_functions = defs_db.module_extern_functions(module_id).unwrap(); let extern_functions = module_extern_functions .iter() .map(|(id, node)| ExternFunction::new(db, *id, node)) .collect(); - let module_submodules = db.module_submodules(module_id).unwrap(); + let module_submodules = defs_db.module_submodules(module_id).unwrap(); let submodules = module_submodules .iter() .map(|(id, _node)| Self::new(db, ModuleId::Submodule(*id))) @@ -117,7 +120,7 @@ impl Module { Self { module_id, - full_path: module_id.full_path(db), + full_path: module_id.full_path(defs_db), submodules, constants, uses, @@ -146,15 +149,15 @@ pub struct ItemData { } impl ItemData { - pub fn new(_db: &dyn DefsGroup, _id: ModuleItemId, _node: &impl TypedSyntaxNode) -> Self { - // Self { - // name: id.name(db).into(), - // full_path: id.full_path(db), - // doc: db.get_item_documentation(LookupItemId::ModuleItem(id)), - // definition: db.get_item_signature(LookupItemId::ModuleItem(id)), - // text: node.as_syntax_node().get_text_without_trivia(db.upcast()), - // } - todo!("TODO(piotmag769): fix") + pub fn new(db: &dyn DocGroup, id: ModuleItemId, node: &impl TypedSyntaxNode) -> Self { + let defs_db = db.upcast(); + Self { + name: id.name(defs_db).into(), + full_path: id.full_path(defs_db), + doc: db.get_item_documentation(LookupItemId::ModuleItem(id)), + definition: db.get_item_signature(LookupItemId::ModuleItem(id)), + text: node.as_syntax_node().get_text_without_trivia(db.upcast()), + } } } @@ -167,7 +170,7 @@ pub struct Constant { } impl Constant { - pub fn new(db: &dyn DefsGroup, id: ConstantId, node: &ast::ItemConstant) -> Self { + pub fn new(db: &dyn DocGroup, id: ConstantId, node: &ast::ItemConstant) -> Self { Self { id, node: node.stable_ptr(), @@ -185,7 +188,7 @@ pub struct Use { } impl Use { - pub fn new(db: &dyn DefsGroup, id: UseId, node: &ast::UsePathLeaf) -> Self { + pub fn new(db: &dyn DocGroup, id: UseId, node: &ast::UsePathLeaf) -> Self { Self { id, node: node.stable_ptr(), @@ -203,7 +206,7 @@ pub struct FreeFunction { } impl FreeFunction { - pub fn new(db: &dyn DefsGroup, id: FreeFunctionId, node: &ast::FunctionWithBody) -> Self { + pub fn new(db: &dyn DocGroup, id: FreeFunctionId, node: &ast::FunctionWithBody) -> Self { Self { id, node: node.stable_ptr(), @@ -221,7 +224,7 @@ pub struct Struct { } impl Struct { - pub fn new(db: &dyn DefsGroup, id: StructId, node: &ast::ItemStruct) -> Self { + pub fn new(db: &dyn DocGroup, id: StructId, node: &ast::ItemStruct) -> Self { Self { id, node: node.stable_ptr(), @@ -239,7 +242,7 @@ pub struct Enum { } impl Enum { - pub fn new(db: &dyn DefsGroup, id: EnumId, node: &ast::ItemEnum) -> Self { + pub fn new(db: &dyn DocGroup, id: EnumId, node: &ast::ItemEnum) -> Self { Self { id, node: node.stable_ptr(), @@ -257,7 +260,7 @@ pub struct TypeAlias { } impl TypeAlias { - pub fn new(db: &dyn DefsGroup, id: ModuleTypeAliasId, node: &ast::ItemTypeAlias) -> Self { + pub fn new(db: &dyn DocGroup, id: ModuleTypeAliasId, node: &ast::ItemTypeAlias) -> Self { Self { id, node: node.stable_ptr(), @@ -275,7 +278,7 @@ pub struct ImplAlias { } impl ImplAlias { - pub fn new(db: &dyn DefsGroup, id: ImplAliasId, node: &ast::ItemImplAlias) -> Self { + pub fn new(db: &dyn DocGroup, id: ImplAliasId, node: &ast::ItemImplAlias) -> Self { Self { id, node: node.stable_ptr(), @@ -293,7 +296,7 @@ pub struct Trait { } impl Trait { - pub fn new(db: &dyn DefsGroup, id: TraitId, node: &ast::ItemTrait) -> Self { + pub fn new(db: &dyn DocGroup, id: TraitId, node: &ast::ItemTrait) -> Self { Self { id, node: node.stable_ptr(), @@ -311,7 +314,7 @@ pub struct Impl { } impl Impl { - pub fn new(db: &dyn DefsGroup, id: ImplDefId, node: &ast::ItemImpl) -> Self { + pub fn new(db: &dyn DocGroup, id: ImplDefId, node: &ast::ItemImpl) -> Self { Self { id, node: node.stable_ptr(), @@ -329,7 +332,7 @@ pub struct ExternType { } impl ExternType { - pub fn new(db: &dyn DefsGroup, id: ExternTypeId, node: &ast::ItemExternType) -> Self { + pub fn new(db: &dyn DocGroup, id: ExternTypeId, node: &ast::ItemExternType) -> Self { Self { id, node: node.stable_ptr(), @@ -347,7 +350,7 @@ pub struct ExternFunction { } impl ExternFunction { - pub fn new(db: &dyn DefsGroup, id: ExternFunctionId, node: &ast::ItemExternFunction) -> Self { + pub fn new(db: &dyn DocGroup, id: ExternFunctionId, node: &ast::ItemExternFunction) -> Self { Self { id, node: node.stable_ptr(), diff --git a/extensions/scarb-doc/tests/test.rs b/extensions/scarb-doc/tests/test.rs index 4b255c45f..ae9cac65b 100644 --- a/extensions/scarb-doc/tests/test.rs +++ b/extensions/scarb-doc/tests/test.rs @@ -5,7 +5,6 @@ use scarb_test_support::{ }; #[test] -#[ignore = "TODO(piotmag769): fix"] fn test_main() { let t = TempDir::new().unwrap(); ProjectBuilder::start() @@ -127,7 +126,6 @@ fn test_main() { } #[test] -#[ignore = "TODO(piotmag769): fix"] fn test_workspace() { let t = TempDir::new().unwrap(); let hello = t.child("hello_world");