Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Adds generic trait impls to forc-doc #6850

Merged
merged 5 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions forc-plugins/forc-doc/src/doc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use crate::{
render::{
item::{components::*, context::DocImplTrait, documentable_type::DocumentableType},
link::DocLink,
util::format::docstring::{create_preview, DocStrings},
util::{
format::docstring::{create_preview, DocStrings},
strip_generic_suffix,
},
},
};
use anyhow::Result;
Expand Down Expand Up @@ -96,10 +99,12 @@ impl Documentation {
DocumentableType::Declared(TyDecl::StructDecl(_))
| DocumentableType::Declared(TyDecl::EnumDecl(_))
| DocumentableType::Primitive(_) => {
let item_name = doc.item_header.item_name.as_str().to_string();
let item_name = doc.item_header.item_name.clone();
for (impl_trait, _) in impl_traits.iter_mut() {
// Check if this implementation is for this struct/enum.
if item_name.as_str() == impl_trait.implementing_for.span.as_str() {
if item_name.as_str()
== strip_generic_suffix(impl_trait.implementing_for.span.as_str())
{
let module_info_override = if let Some(decl_module_info) =
trait_decls.get(&impl_trait.trait_name.suffix)
{
Expand Down
122 changes: 101 additions & 21 deletions forc-plugins/forc-doc/src/render/item/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use anyhow::Result;
use horrorshow::{box_html, Raw, RenderBox, Template};
use std::{collections::BTreeMap, fmt::Write};
use sway_core::language::ty::{
TyEnumVariant, TyImplSelfOrTrait, TyStorageField, TyStructField, TyTraitFn, TyTraitItem,
TyConstantDecl, TyEnumVariant, TyFunctionDecl, TyImplSelfOrTrait, TyStorageField,
TyStructField, TyTraitFn, TyTraitItem, TyTraitType,
};

/// The actual context of the item displayed by [ItemContext].
Expand Down Expand Up @@ -586,16 +587,29 @@ impl Renderable for DocImplTrait {
}
impl Renderable for TyTraitItem {
fn render(self, render_plan: RenderPlan) -> Result<Box<dyn RenderBox>> {
let item = match self {
TyTraitItem::Fn(item_fn) => item_fn,
TyTraitItem::Constant(_) => unimplemented!("Constant Trait items not yet implemented"),
TyTraitItem::Type(_) => unimplemented!("Type Trait items not yet implemented"),
};
let method = render_plan.engines.de().get_function(item.id());
let attributes = method.attributes.to_html_string();
match self {
TyTraitItem::Fn(decl_ref) => {
let decl = render_plan.engines.de().get_function(decl_ref.id());
<TyFunctionDecl as Clone>::clone(&decl).render(render_plan)
}
TyTraitItem::Constant(ref decl_ref) => {
let decl = render_plan.engines.de().get_constant(decl_ref.id());
<TyConstantDecl as Clone>::clone(&decl).render(render_plan)
}
TyTraitItem::Type(ref decl_ref) => {
let decl = render_plan.engines.de().get_type(decl_ref.id());
<TyTraitType as Clone>::clone(&decl).render(render_plan)
}
}
}
}

impl Renderable for TyFunctionDecl {
fn render(self, _render_plan: RenderPlan) -> Result<Box<dyn RenderBox>> {
let attributes = self.attributes.to_html_string();

let mut fn_sig = format!("fn {}(", method.name.as_str());
for param in &method.parameters {
let mut fn_sig = format!("fn {}(", self.name.as_str());
for param in &self.parameters {
let mut param_str = String::new();
if param.is_reference {
write!(param_str, "ref ")?;
Expand All @@ -614,22 +628,25 @@ impl Renderable for TyTraitItem {
)?;
}
}
write!(fn_sig, ") -> {}", method.return_type.span.as_str())?;
write!(fn_sig, ") -> {}", self.return_type.span.as_str())?;
let multiline = fn_sig.chars().count() >= 60;

let method_id = format!("method.{}", method.name.as_str());
let method_id = format!("method.{}", self.name.as_str());

let impl_list = box_html! {
div(id=format!("method.{}", item.name().as_str()), class="method trait-impl") {
a(href=format!("{IDENTITY}method.{}", item.name().as_str()), class="anchor");
div(id=format!("{method_id}"), class="method trait-impl") {
a(href=format!("{IDENTITY}{method_id}"), class="anchor");
h4(class="code-header") {
@ if self.visibility.is_public() {
: "pub ";
}
: "fn ";
a(class="fnname", href=format!("{IDENTITY}{method_id}")) {
: method.name.as_str();
: self.name.as_str();
}
: "(";
@ if multiline {
@ for param in &method.parameters {
@ for param in &self.parameters {
br;
: " ";
@ if param.is_reference {
Expand All @@ -650,7 +667,7 @@ impl Renderable for TyTraitItem {
br;
: ")";
} else {
@ for param in &method.parameters {
@ for param in &self.parameters {
@ if param.is_reference {
: "ref";
}
Expand All @@ -665,21 +682,22 @@ impl Renderable for TyTraitItem {
: param.type_argument.span.as_str();
}
@ if param.name.as_str()
!= method.parameters.last()
!= self.parameters.last()
.expect("no last element in trait method parameters list")
.name.as_str() {
: ", ";
}
}
: ")";
}
@ if method.span.as_str().contains("->") {
@ if self.span.as_str().contains("->") {
: " -> ";
: method.return_type.span.as_str();
: self.return_type.span.as_str();
}
}
}
}.into_string()?;
}
.into_string()?;

Ok(box_html! {
@ if !attributes.is_empty() {
Expand All @@ -698,6 +716,68 @@ impl Renderable for TyTraitItem {
}
}

impl Renderable for TyTraitType {
fn render(self, _render_plan: RenderPlan) -> Result<Box<dyn RenderBox>> {
let attributes = self.attributes.to_html_string();
let trait_type_id = format!("traittype.{}", self.name.as_str());
let contents = box_html! {
div(id=format!("{trait_type_id}"), class="type trait-impl") {
a(href=format!("{IDENTITY}{trait_type_id}"), class="anchor");
h4(class="code-header") {
: self.span.as_str();
}
}
}
.into_string()?;

Ok(box_html! {
@ if !attributes.is_empty() {
details(class="swaydoc-toggle method-toggle", open) {
summary {
: Raw(contents);
}
div(class="docblock") {
: Raw(attributes);
}
}
} else {
: Raw(contents);
}
})
}
}

impl Renderable for TyConstantDecl {
fn render(self, _render_plan: RenderPlan) -> Result<Box<dyn RenderBox>> {
let attributes = self.attributes.to_html_string();
let const_id = format!("const.{}", self.call_path.suffix.as_str());
let contents = box_html! {
div(id=format!("{const_id}"), class="const trait-impl") {
a(href=format!("{IDENTITY}{const_id}"), class="anchor");
h4(class="code-header") {
: self.span.as_str();
}
}
}
.into_string()?;

Ok(box_html! {
@ if !attributes.is_empty() {
details(class="swaydoc-toggle method-toggle", open) {
summary {
: Raw(contents);
}
div(class="docblock") {
: Raw(attributes);
}
}
} else {
: Raw(contents);
}
})
}
}

#[derive(Clone, Debug)]
/// Represents the type of [Context] for item declarations that have
/// fields, variants or methods, and acts as a wrapper for those values for rendering.
Expand Down
5 changes: 5 additions & 0 deletions forc-plugins/forc-doc/src/render/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
//! Utilities for managing edge cases in rendering types and their corresponding documentation.
pub mod format;

/// Strip the generic suffix from a type name. For example, `Foo<T>` would become `Foo`.
pub fn strip_generic_suffix(input: &str) -> &str {
input.split_once('<').map_or(input, |(head, _)| head)
}
4 changes: 0 additions & 4 deletions forc-plugins/forc-doc/src/static.files/ayu.css
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,6 @@ pre,
color: #39afd7;
}
.content span.type,
.content a.type {
color: #39afd7;
}
.content span.type,
.content a.type,
.block a.current.type {
color: #39afd7;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[[package]]
name = "core"
source = "path+from-root-09A5B00ACCB1BF9C"
source = "path+from-root-BD391496AC0FBC33"

[[package]]
name = "impl_traits_clone"
name = "impl_traits_generic"
source = "member"
dependencies = ["core"]
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
authors = ["Fuel Labs <[email protected]>"]
entry = "lib.sw"
license = "Apache-2.0"
name = "impl_traits_clone"
name = "impl_traits_generic"

[dependencies]
core = { path = "../../../../../../sway-lib-core" }
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,26 @@ library;
use ::foo::{Foo, Baz};
use core::ops::Add;

pub struct Bar {}
pub struct Bar<T> {}

impl Foo for Bar {
impl<T> Foo for Bar<T> {
/// something more about foo();
fn foo() {}
}
impl Baz for Bar {}
impl Bar {
impl<T> Baz for Bar<T> {}
impl<T> Bar<T> {
fn foo_bar() {
Self::foo()
}
}

// test dependency impls
impl Add for Bar {
impl<T> Add for Bar<T> {
fn add(self, other: Self) -> Self {
Bar {}
}
}
impl core::ops::Subtract for Bar {
impl<T> core::ops::Subtract for Bar<T> {
fn subtract(self, other: Self) -> Self {
Bar {}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
library;

mod foo;
pub mod foo;
mod bar;
Loading
Loading