Skip to content

Commit

Permalink
Hide docs for impls of hidden traits / traits with hidden generic arg…
Browse files Browse the repository at this point in the history
…s. (#1644)
  • Loading branch information
maciektr authored Oct 14, 2024
1 parent 4d91be7 commit 3cda92a
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 5 deletions.
2 changes: 1 addition & 1 deletion extensions/scarb-doc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ camino.workspace = true
clap.workspace = true
cairo-lang-compiler.workspace = true
cairo-lang-defs.workspace = true
cairo-lang-diagnostics.workspace = true
cairo-lang-doc.workspace = true
cairo-lang-filesystem.workspace = true
cairo-lang-parser.workspace = true
Expand All @@ -22,7 +23,6 @@ cairo-lang-starknet.workspace = true
cairo-lang-syntax.workspace = true
cairo-lang-utils.workspace = true
cairo-lang-lowering.workspace = true
cairo-lang-diagnostics.workspace = true
expect-test.workspace = true
indoc.workspace = true
itertools.workspace = true
Expand Down
62 changes: 58 additions & 4 deletions extensions/scarb-doc/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cairo_lang_semantic::items::us::SemanticUseEx;
use cairo_lang_semantic::items::visibility::{self, Visibility};
use cairo_lang_semantic::resolve::ResolvedGenericItem;
use cairo_lang_syntax::node::helpers::QueryAttrs;
use cairo_lang_utils::Upcast;
use cairo_lang_utils::{LookupIntern, Upcast};
use itertools::chain;
use serde::Serialize;

Expand All @@ -21,9 +21,11 @@ use cairo_lang_doc::db::DocGroup;
use cairo_lang_doc::documentable_item::DocumentableItemId;
use cairo_lang_filesystem::ids::CrateId;
use cairo_lang_semantic::db::SemanticGroup;
use cairo_lang_semantic::items::attribute::SemanticQueryAttrs;
use cairo_lang_semantic::{ConcreteTypeId, GenericArgumentId, TypeLongId};
use cairo_lang_syntax::node::{
ast::{self},
SyntaxNode,
SyntaxNode, TypedSyntaxNode,
};

use crate::db::ScarbDocDatabase;
Expand Down Expand Up @@ -257,8 +259,53 @@ impl Module {
)?;

let module_impls = db.module_impls(module_id)?;
let hide_impls_for_hidden_traits = |impl_def_id: &&ImplDefId| {
// Hide impls for hidden traits and hidden trait generic args.
// Example: `HiddenTrait<*>` or `NotHiddenTrait<HiddenStruct>` (e.g. Drop<HiddenStruct>).
// We still keep impls, if any trait generic argument is not hidden.
let Ok(trait_id) = db.impl_def_trait(**impl_def_id) else {
return true;
};
let Ok(item_trait) = db.module_trait_by_id(trait_id) else {
return true;
};
let all_generic_args_are_hidden = db
.impl_def_concrete_trait(**impl_def_id)
.ok()
.map(|concrete_trait_id| {
let args = concrete_trait_id.generic_args(db.upcast());
if args.is_empty() {
return false;
}
args.into_iter()
.filter_map(|arg_id| {
let GenericArgumentId::Type(type_id) = arg_id else {
return None;
};
let TypeLongId::Concrete(concrete_type_id) = type_id.lookup_intern(db)
else {
return None;
};
let concrete_id: &dyn SemanticQueryAttrs = match &concrete_type_id {
ConcreteTypeId::Struct(struct_id) => struct_id,
ConcreteTypeId::Enum(enum_id) => enum_id,
ConcreteTypeId::Extern(extern_type_id) => extern_type_id,
};
is_doc_hidden_attr_semantic(db, concrete_id).ok()
})
.all(|x| x)
})
.unwrap_or(false);

let trait_is_hidden = item_trait
.map(|item_trait| is_doc_hidden_attr(db, &item_trait.as_syntax_node()))
.unwrap_or(false);

!(all_generic_args_are_hidden || trait_is_hidden)
};
let impls = filter_map_item_id_to_item(
chain!(module_impls.keys(), module_pubuses.use_impl_defs.iter()),
chain!(module_impls.keys(), module_pubuses.use_impl_defs.iter())
.filter(hide_impls_for_hidden_traits),
should_include_item,
|id| Impl::new(db, *id),
)?;
Expand Down Expand Up @@ -367,7 +414,14 @@ fn is_doc_hidden_attr(db: &ScarbDocDatabase, syntax_node: &SyntaxNode) -> bool {
syntax_node.has_attr_with_arg(db, "doc", "hidden")
}

#[derive(Serialize, Clone)]
fn is_doc_hidden_attr_semantic(
db: &dyn SemanticGroup,
node: &dyn SemanticQueryAttrs,
) -> Maybe<bool> {
node.has_attr_with_arg(db, "doc", "hidden")
}

#[derive(Debug, Serialize, Clone)]
pub struct ItemData {
pub name: String,
pub doc: Option<String>,
Expand Down
88 changes: 88 additions & 0 deletions extensions/scarb-doc/tests/data/json_doc_hidden_impls.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"format_version": 1,
"packages_information": [
{
"crate_": {
"root_module": {
"item_data": {
"name": "hello_world",
"doc": null,
"signature": null,
"full_path": "hello_world"
},
"submodules": [],
"constants": [],
"free_functions": [],
"structs": [
{
"members": [],
"item_data": {
"name": "VisibleStruct",
"doc": null,
"signature": "struct VisibleStruct {}",
"full_path": "hello_world::VisibleStruct"
}
}
],
"enums": [],
"type_aliases": [],
"impl_aliases": [],
"traits": [
{
"trait_constants": [],
"trait_types": [],
"trait_functions": [],
"item_data": {
"name": "VisibleTrait",
"doc": null,
"signature": "trait VisibleTrait<T>",
"full_path": "hello_world::VisibleTrait"
}
},
{
"trait_constants": [],
"trait_types": [],
"trait_functions": [],
"item_data": {
"name": "SecondVisibleTrait",
"doc": null,
"signature": "trait SecondVisibleTrait<T, Y>",
"full_path": "hello_world::SecondVisibleTrait"
}
}
],
"impls": [
{
"impl_types": [],
"impl_constants": [],
"impl_functions": [],
"item_data": {
"name": "VisibleImpl",
"doc": null,
"signature": "impl VisibleImpl of VisibleTrait<VisibleStruct>",
"full_path": "hello_world::VisibleImpl"
}
},
{
"impl_types": [],
"impl_constants": [],
"impl_functions": [],
"item_data": {
"name": "SecondVisibleImpl",
"doc": null,
"signature": "impl SecondVisibleImpl of SecondVisibleTrait<HiddenStruct, VisibleStruct>",
"full_path": "hello_world::SecondVisibleImpl"
}
}
],
"extern_types": [],
"extern_functions": []
}
},
"metadata": {
"name": "hello_world",
"authors": null
}
}
]
}
45 changes: 45 additions & 0 deletions extensions/scarb-doc/tests/doc_hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,48 @@ fn test_doc_hidden() {
.expected("./data/json_doc_hidden.json")
.assert_files_match();
}

#[test]
fn hides_impls_of_private_traits() {
let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello_world")
.lib_cairo(indoc! {r#"
#[doc(hidden)
struct HiddenStuct {}
#[doc(hidden)]
trait HiddenTrait<T> {}
struct VisibleStruct {}
trait VisibleTrait<T> {}
impl VisibleImpl of VisibleTrait<VisibleStruct> {}
impl FirstHiddenImpl of HiddenTrait<HiddenStruct> {}
impl SecondHiddenImpl of HiddenTrait<VisibleStruct> {}
impl ThirdHiddenImpl of VisibleTrait<HiddenStruct> {}
#[doc(hidden)]
impl FourthHiddenImpl of VisibleTrait<VisibleStruct> {}
trait SecondVisibleTrait<T,Y> {}
impl SecondVisibleImpl of SecondVisibleTrait<HiddenStruct, VisibleStruct> {}
impl FifthHiddenImpl of SecondVisibleTrait<HiddenStruct, HiddenStruct> {}
"#})
.build(&t);

Scarb::quick_snapbox()
.arg("doc")
.args(["--document-private-items", "--output-format", "json"])
.current_dir(&t)
.assert()
.success();

JsonTargetChecker::default()
.actual(&t.path().join("target/doc/output.json"))
.expected("./data/json_doc_hidden_impls.json")
.assert_files_match();
}

0 comments on commit 3cda92a

Please sign in to comment.