Disabling rustdoc tests for module?

Hi! I have a module that include!s some code generated by an external library.

mod Foo {
  include!("code.gen.rs");
}

The generated code happens to have comments that contain words enclosed in consecutive backticks ``` so that running rustdoc on my project treats part of the comments as my rust tests and fails as a result since the library wasn't trying to include rust code.
Is there any way to get rustdoc to ignore doc tests for a module? I couldn't find any work around so far.

cfg(doctest) seems to be a thing, so you can try to add that cfg (negated) and see if it works :slightly_smiling_face::

#[cfg(not(doctest))]
mod Foo {
    include!("code.gen.rs");
}

I can't use that in this case unfortunately since it means the entire module won't be included which would break the rest of the codebase that relies on it

Did you test it? The idea is that the Rust codebase is "examined" through multiple passes; the #[cfg(not(doctest))] ought to disable your module for the doctest pass only, that is, it will be available to normal passes; it will even be present in the documentation!

asciicast

Yeah, that was my initial attempt to resolve the issue, to clarify, since the generated code contains modules etc I had to disable at the module level instead rather than any struct as in your example (since I can't change the included code) for example:

pub mod foo {
  #![cfg(not(doctest))]
  ///```
  /// Wops
  ///
  pub bar() {}
  pub mod submodule{}
  }

The breakage arises in my code elsewhere that e.g imports the generated modules (running cargo test --doc)

mod caller {
  use crate::foo::submodule; // compiler error since submodule doesn't exist because it wasn't included in the doctest.
}
1 Like

If all else fails you can write a proc-macro to remove or rewrite these doc comments, which is probably easiest using syn::visit_mut. Untested first draft:

struct RemoveDocs;

impl syn::VisitMut for RemoveDocs {
    fn visit_attribute_mut(&mut self, attr: &mut Attribute) {
        if attr.path.is_ident("doc") {
            *attr = parse_quote! { #[doc = ""] };
        }
    }
}

#[proc_macro]
pub fn remove_docs(input: TokenStream) -> TokenStream {
    let mut syntax_tree = syn::parse_macro_input!(input as syn::File);
    RemoveDocs.visit_file_mut(&mut syntax_tree);
    quote!(#syntax_tree).into()
}

used as

remove_docs!(include!("code.gen.rs"));

This will not work AFAIK (at least not without accessing the file directly), since remove_docs will be expanded before include.

Well, accessing the file directly would be bad since then you don't get the dependency tracking include! gives you. I think the "proper" solution then is having a macro_rules! macro that wraps remove_docs! & include! and expands the latter first. That's possible, right?

If you are able to modify the code that generates these comments, you can make it add the "ignore" attribute to tell rustdoc that it is not a doctest:

/// ```ignore
/// non-Rust code goes here
/// ```

Or if it contains code in some other language, you can tag it with that language:

/// ```c
/// int main(void) { }
/// ```
2 Likes