From 3e1ca15e69dfe80216440248eb8c851bccf5e158 Mon Sep 17 00:00:00 2001 From: grandizzy Date: Mon, 10 Nov 2025 21:01:27 +0200 Subject: [PATCH 1/2] Revert "Revert "fix(forge doc): use relative path instead of full path" (#12477)" This reverts commit ebcd59b575e1ff8a1fecda3f1411afa3dd0e57fb. --- crates/doc/src/builder.rs | 7 +-- .../src/preprocessor/contract_inheritance.rs | 2 +- crates/doc/src/writer/as_doc.rs | 16 +------ crates/forge/tests/cli/doc.rs | 48 +++++++++++++++++++ 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/crates/doc/src/builder.rs b/crates/doc/src/builder.rs index a4019db4a6a3a..3788df8e7edfa 100644 --- a/crates/doc/src/builder.rs +++ b/crates/doc/src/builder.rs @@ -124,6 +124,7 @@ impl DocBuilder { .collect::>(); let out_dir = self.out_dir()?; + let out_target_dir = out_dir.clone(); let documents = compiler.enter_mut(|compiler| -> eyre::Result>> { let gcx = compiler.gcx(); let documents = combined_sources @@ -197,7 +198,7 @@ impl DocBuilder { path.clone(), target_path, from_library, - self.config.out.clone(), + out_target_dir.clone(), ) .with_content(DocumentContent::Single(item), ident)) }) @@ -231,7 +232,7 @@ impl DocBuilder { path.clone(), target_path, from_library, - self.config.out.clone(), + out_target_dir.clone(), ) .with_content(DocumentContent::Constants(consts), identity), ) @@ -250,7 +251,7 @@ impl DocBuilder { path.clone(), target_path, from_library, - self.config.out.clone(), + out_target_dir.clone(), ) .with_content( DocumentContent::OverloadedFunctions(funcs), diff --git a/crates/doc/src/preprocessor/contract_inheritance.rs b/crates/doc/src/preprocessor/contract_inheritance.rs index 6d4195700bcc4..1c2159131b01a 100644 --- a/crates/doc/src/preprocessor/contract_inheritance.rs +++ b/crates/doc/src/preprocessor/contract_inheritance.rs @@ -62,7 +62,7 @@ impl ContractInheritance { && let ParseSource::Contract(ref contract) = item.source && base == contract.name.safe_unwrap().name { - return Some(candidate.target_path.clone()); + return Some(candidate.relative_output_path().to_path_buf()); } } None diff --git a/crates/doc/src/writer/as_doc.rs b/crates/doc/src/writer/as_doc.rs index ef6bf3875fcbb..b7d1490c1ccd2 100644 --- a/crates/doc/src/writer/as_doc.rs +++ b/crates/doc/src/writer/as_doc.rs @@ -9,7 +9,7 @@ use crate::{ }; use itertools::Itertools; use solang_parser::pt::{Base, FunctionDefinition}; -use std::path::{Path, PathBuf}; +use std::path::Path; /// The result of [`AsDoc::as_doc`]. pub type AsDocResult = Result; @@ -141,9 +141,6 @@ impl AsDoc for Document { if !contract.base.is_empty() { writer.write_bold("Inherits:")?; - // we need this to find the _relative_ paths - let src_target_dir = self.target_src_dir(); - let mut bases = vec![]; let linked = read_context!(self, CONTRACT_INHERITANCE_ID, ContractInheritance); @@ -155,11 +152,7 @@ impl AsDoc for Document { .as_ref() .and_then(|link| { link.get(base_ident).map(|path| { - let path = Path::new("/").join( - path.strip_prefix(&src_target_dir) - .ok() - .unwrap_or(path), - ); + let path = Path::new("/").join(path); Markdown::Link(&base_doc, &path.display().to_string()) .as_doc() }) @@ -287,11 +280,6 @@ impl AsDoc for Document { } impl Document { - /// Where all the source files are written to - fn target_src_dir(&self) -> PathBuf { - self.out_target_dir.join("src") - } - /// Writes a function to the buffer. fn write_function( &self, diff --git a/crates/forge/tests/cli/doc.rs b/crates/forge/tests/cli/doc.rs index fad1294b8fe09..97c829cade1d1 100644 --- a/crates/forge/tests/cli/doc.rs +++ b/crates/forge/tests/cli/doc.rs @@ -69,3 +69,51 @@ contract Example is IExample { assert!(content.contains("Process multiple addresses")); assert!(content.contains("Process an address with a value")); }); + +// Test that hyperlinks use relative paths, not absolute paths +// fixes +forgetest_init!(hyperlinks_use_relative_paths, |prj, cmd| { + prj.add_source( + "IBase.sol", + r#" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IBase { + function baseFunction() external; +} +"#, + ); + + prj.add_source( + "Derived.sol", + r#" +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IBase.sol"; + +/// @dev Inherits: {IBase} +contract Derived is IBase { + function baseFunction() external override {} +} +"#, + ); + + cmd.args(["doc", "--build"]).assert_success(); + + let doc_path = prj.root().join("docs/src/src/Derived.sol/contract.Derived.md"); + let content = std::fs::read_to_string(&doc_path).unwrap(); + + assert!( + content.contains("[IBase](/src/"), + "Hyperlink should use relative path starting with /src/, but found: {:?}", + content.lines().find(|line| line.contains("[IBase]")).unwrap_or("not found") + ); + assert!(!content.contains("/Users/"), "Hyperlink should not contain absolute path /Users/"); + assert!(!content.contains("/home/"), "Hyperlink should not contain absolute path /home/"); + assert!( + content.contains("IBase.sol/interface.IBase.md"), + "Hyperlink should point to IBase.sol/interface.IBase.md" + ); +}); From 4e85dce8b461beac5fb51fe835dd27040b52aa34 Mon Sep 17 00:00:00 2001 From: grandizzy Date: Mon, 10 Nov 2025 23:40:53 +0200 Subject: [PATCH 2/2] fix win and test --- crates/doc/src/writer/as_doc.rs | 6 +++++- crates/forge/tests/cli/doc.rs | 11 +++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/doc/src/writer/as_doc.rs b/crates/doc/src/writer/as_doc.rs index b7d1490c1ccd2..a215a95b581c7 100644 --- a/crates/doc/src/writer/as_doc.rs +++ b/crates/doc/src/writer/as_doc.rs @@ -152,7 +152,11 @@ impl AsDoc for Document { .as_ref() .and_then(|link| { link.get(base_ident).map(|path| { - let path = Path::new("/").join(path); + let path = if cfg!(windows) { + Path::new("\\").join(path) + } else { + Path::new("/").join(path) + }; Markdown::Link(&base_doc, &path.display().to_string()) .as_doc() }) diff --git a/crates/forge/tests/cli/doc.rs b/crates/forge/tests/cli/doc.rs index 97c829cade1d1..f1f6a8b2dec59 100644 --- a/crates/forge/tests/cli/doc.rs +++ b/crates/forge/tests/cli/doc.rs @@ -106,14 +106,9 @@ contract Derived is IBase { let content = std::fs::read_to_string(&doc_path).unwrap(); assert!( - content.contains("[IBase](/src/"), - "Hyperlink should use relative path starting with /src/, but found: {:?}", + content.contains("[IBase](/src/IBase.sol/interface.IBase.md") + || content.contains("[IBase](\\src\\IBase.sol\\interface.IBase.md"), + "Hyperlink should use relative path but found: {:?}", content.lines().find(|line| line.contains("[IBase]")).unwrap_or("not found") ); - assert!(!content.contains("/Users/"), "Hyperlink should not contain absolute path /Users/"); - assert!(!content.contains("/home/"), "Hyperlink should not contain absolute path /home/"); - assert!( - content.contains("IBase.sol/interface.IBase.md"), - "Hyperlink should point to IBase.sol/interface.IBase.md" - ); });