diff options
Diffstat (limited to '')
1285 files changed, 29698 insertions, 0 deletions
diff --git a/src/test/rustdoc-gui/README.md b/src/test/rustdoc-gui/README.md new file mode 100644 index 000000000..d9854e2e7 --- /dev/null +++ b/src/test/rustdoc-gui/README.md @@ -0,0 +1,34 @@ +The tests present here are used to test the generated HTML from rustdoc. The +goal is to prevent unsound/unexpected GUI changes. + +This is using the [browser-ui-test] framework to do so. It works as follows: + +It wraps [puppeteer] to send commands to a web browser in order to navigate and +test what's being currently displayed in the web page. + +You can find more information and its documentation in its [repository][browser-ui-test]. + +If you need to have more information on the tests run, you can use `--test-args`: + +```bash +$ ./x.py test src/test/rustdoc-gui --stage 1 --test-args --debug +``` + +If you don't want to run in headless mode (helpful to debug sometimes), you can use +`--no-headless`: + +```bash +$ ./x.py test src/test/rustdoc-gui --stage 1 --test-args --no-headless +``` + +To see the supported options, use `--help`. + +Important to be noted: if the chromium instance crashes when you run it, you might need to +use `--no-sandbox` to make it work: + +```bash +$ ./x.py test src/test/rustdoc-gui --stage 1 --test-args --no-sandbox +``` + +[browser-ui-test]: https://github.com/GuillaumeGomez/browser-UI-test/ +[puppeteer]: https://pptr.dev/ diff --git a/src/test/rustdoc-gui/anchor-navigable.goml b/src/test/rustdoc-gui/anchor-navigable.goml new file mode 100644 index 000000000..424c31223 --- /dev/null +++ b/src/test/rustdoc-gui/anchor-navigable.goml @@ -0,0 +1,11 @@ +// The `impl Foo` heading underneath `Implementations` has a § +// anchor to its left (used for linking to that heading). The anchor only shows +// up when hovering the `impl Foo`. This test ensures there's no gap between the +// anchor and the `impl Foo`. If there were a gap, this would cause an annoying +// problem: you hover `impl Foo` to see the anchor, then when you move your +// mouse to the left, the anchor disappears before you reach it. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +// We check that ".item-info" is bigger than its content. +move-cursor-to: ".impl" +assert-property: (".impl > a.anchor", {"offsetWidth": "9"}) +assert-css: (".impl > a.anchor", {"left": "-8px"}) diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml new file mode 100644 index 000000000..84b8bbd1b --- /dev/null +++ b/src/test/rustdoc-gui/anchors.goml @@ -0,0 +1,34 @@ +// This test is to ensure that the anchors (`§`) have the expected color and position. +goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html +show-text: true + +// This is needed to ensure that the text color is computed. +show-text: true + +// Set the theme to light. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"}) +assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"}) +assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 55, 138)"}) +assert-css: (".srclink", {"color": "rgb(56, 115, 173)"}) + +move-cursor-to: ".main-heading .srclink" +assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)"}) + +assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"}) + +assert-css: (".sidebar a", {"color": "rgb(53, 109, 164)"}) +assert-css: (".in-band a", {"color": "rgb(0, 0, 0)"}) + +// We move the cursor over the "Implementations" title so the anchor is displayed. +move-cursor-to: "h2#implementations" +assert-css: ("h2#implementations a.anchor", {"color": "rgb(0, 0, 0)"}) + +// Same thing with the impl block title. +move-cursor-to: "#impl-HeavilyDocumentedStruct" +assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(0, 0, 0)"}) + +assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"}) diff --git a/src/test/rustdoc-gui/auto-hide-trait-implementations.goml b/src/test/rustdoc-gui/auto-hide-trait-implementations.goml new file mode 100644 index 000000000..7b1358fed --- /dev/null +++ b/src/test/rustdoc-gui/auto-hide-trait-implementations.goml @@ -0,0 +1,13 @@ +// Checks that the setting "auto hide trait implementations" is working as expected. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html + +// By default, the trait implementations are not collapsed. +assert-attribute: ("#trait-implementations-list > details", {"open": ""}, ALL) + +// We now set the setting to auto hide all trait implementations. +local-storage: {"rustdoc-auto-hide-trait-implementations": "true" } +// We reload to ensure the trait implementations are collapsed as expected. +reload: + +// We now check that all matching elements don't have the open attributes. +assert-attribute-false: ("#trait-implementations-list > details", {"open": ""}, ALL) diff --git a/src/test/rustdoc-gui/basic-code.goml b/src/test/rustdoc-gui/basic-code.goml new file mode 100644 index 000000000..27deb2c98 --- /dev/null +++ b/src/test/rustdoc-gui/basic-code.goml @@ -0,0 +1,3 @@ +goto: file://|DOC_PATH|/test_docs/index.html +click: ".srclink" +assert-count: (".line-numbers", 1) diff --git a/src/test/rustdoc-gui/basic.goml b/src/test/rustdoc-gui/basic.goml new file mode 100644 index 000000000..239e51a91 --- /dev/null +++ b/src/test/rustdoc-gui/basic.goml @@ -0,0 +1,4 @@ +goto: file://|DOC_PATH|/test_docs/index.html +assert: ("#functions") +goto: ./struct.Foo.html +assert: ("div.item-decl") diff --git a/src/test/rustdoc-gui/check-code-blocks-margin.goml b/src/test/rustdoc-gui/check-code-blocks-margin.goml new file mode 100644 index 000000000..f6266eba7 --- /dev/null +++ b/src/test/rustdoc-gui/check-code-blocks-margin.goml @@ -0,0 +1,6 @@ +// This test ensures that the docblock elements have the appropriate left margin. +goto: file://|DOC_PATH|/test_docs/fn.foo.html +// The top docblock elements shouldn't have left margin... +assert-css: ("#main-content .docblock.item-decl", {"margin-left": "0px"}) +// ... but all the others should! +assert-css: ("#main-content .docblock:not(.item-decl)", {"margin-left": "24px"}) diff --git a/src/test/rustdoc-gui/check_info_sign_position.goml b/src/test/rustdoc-gui/check_info_sign_position.goml new file mode 100644 index 000000000..3bed7a0a0 --- /dev/null +++ b/src/test/rustdoc-gui/check_info_sign_position.goml @@ -0,0 +1,11 @@ +// This test checks the position of the information on the code blocks (like +// `compile_fail` or `ignore`). +goto: file://|DOC_PATH|/test_docs/index.html +goto: ./fn.check_list_code_block.html +// If the codeblock is the first element of the docblock, the information tooltip must have +// have some top margin to avoid going over the toggle (the "[+]"). +assert-css: (".docblock > .information > .compile_fail", { "margin-top": "16px" }) +// Checks that the other codeblocks don't have this top margin. +assert-css: ("ol > li > .information > .compile_fail", { "margin-top": "0px" }) +assert-css: ("ol > li > .information > .ignore", { "margin-top": "0px" }) +assert-css: (".docblock > .information > .ignore", { "margin-top": "0px" }) diff --git a/src/test/rustdoc-gui/code-blocks-overflow.goml b/src/test/rustdoc-gui/code-blocks-overflow.goml new file mode 100644 index 000000000..f93f3f0ae --- /dev/null +++ b/src/test/rustdoc-gui/code-blocks-overflow.goml @@ -0,0 +1,8 @@ +// This test ensures that codeblocks content don't overflow. +goto: file://|DOC_PATH|/lib2/sub_mod/struct.Foo.html +size: (1080, 600) +// There should be two codeblocks: a rust one and a non-rust one. +assert-count: (".docblock > .example-wrap", 2) +assert: ".docblock > .example-wrap > .language-txt" +assert: ".docblock > .example-wrap > .rust-example-rendered" +assert-css: (".docblock > .example-wrap > pre", {"width": "785.25px", "overflow-x": "auto"}, ALL) diff --git a/src/test/rustdoc-gui/code-color.goml b/src/test/rustdoc-gui/code-color.goml new file mode 100644 index 000000000..2f95bfb6b --- /dev/null +++ b/src/test/rustdoc-gui/code-color.goml @@ -0,0 +1,30 @@ +// The ayu theme has a different color for the "<code>" tags in the doc blocks. We need to +// check that the rule isn't applied on other "<code>" elements. +// +// While we're at it, we also check it for the other themes. +goto: file://|DOC_PATH|/test_docs/fn.foo.html +// If the text isn't displayed, the browser doesn't compute color style correctly... +show-text: true +// Set the theme to dark. +local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: (".docblock pre > code", {"color": "rgb(221, 221, 221)"}, ALL) +assert-css: (".docblock > p > code", {"color": "rgb(221, 221, 221)"}, ALL) + +// Set the theme to ayu. +local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: (".docblock pre > code", {"color": "rgb(230, 225, 207)"}, ALL) +assert-css: (".docblock > p > code", {"color": "rgb(255, 180, 84)"}, ALL) + +// Set the theme to light. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: (".docblock pre > code", {"color": "rgb(0, 0, 0)"}, ALL) +assert-css: (".docblock > p > code", {"color": "rgb(0, 0, 0)"}, ALL) diff --git a/src/test/rustdoc-gui/code-sidebar-toggle.goml b/src/test/rustdoc-gui/code-sidebar-toggle.goml new file mode 100644 index 000000000..867db0569 --- /dev/null +++ b/src/test/rustdoc-gui/code-sidebar-toggle.goml @@ -0,0 +1,7 @@ +// This test checks that the source code pages sidebar toggle is working as expected. +goto: file://|DOC_PATH|/test_docs/index.html +click: ".srclink" +wait-for: "#sidebar-toggle" +click: "#sidebar-toggle" +fail: true +assert-css: ("#source-sidebar", { "left": "-300px" }) diff --git a/src/test/rustdoc-gui/code-tags.goml b/src/test/rustdoc-gui/code-tags.goml new file mode 100644 index 000000000..200569a28 --- /dev/null +++ b/src/test/rustdoc-gui/code-tags.goml @@ -0,0 +1,20 @@ +// This test ensures that items and documentation code blocks are wrapped in <pre><code> +goto: file://|DOC_PATH|/test_docs/fn.foo.html +size: (1080, 600) +// There should be three doc codeblocks +// Check that their content is inside <pre><code> +assert-count: (".example-wrap pre > code", 3) +// Check that function signature is inside <pre><code> +assert: "pre.rust.fn > code" + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +assert: "pre.rust.struct > code" + +goto: file://|DOC_PATH|/test_docs/enum.AnEnum.html +assert: "pre.rust.enum > code" + +goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html +assert: "pre.rust.trait > code" + +goto: file://|DOC_PATH|/test_docs/type.SomeType.html +assert: "pre.rust.typedef > code" diff --git a/src/test/rustdoc-gui/default-settings.goml b/src/test/rustdoc-gui/default-settings.goml new file mode 100644 index 000000000..90f0b087a --- /dev/null +++ b/src/test/rustdoc-gui/default-settings.goml @@ -0,0 +1,8 @@ +// This test ensures that the default settings are correctly applied. +// +// The "settings" crate uses "ayu" as default setting, which is what we will +// check. +goto: file://|DOC_PATH|/settings/index.html +// Wait a bit to be sure the default theme is applied. +// If the theme isn't applied, the command will time out. +wait-for-css: ("body", {"background-color": "rgb(15, 20, 25)"}) diff --git a/src/test/rustdoc-gui/docblock-big-code-mobile.goml b/src/test/rustdoc-gui/docblock-big-code-mobile.goml new file mode 100644 index 000000000..02f79f1fc --- /dev/null +++ b/src/test/rustdoc-gui/docblock-big-code-mobile.goml @@ -0,0 +1,9 @@ +// If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning +// that it'll be on two lines. +emulate: "iPhone 8" // it has the following size: (375, 667) +goto: file://|DOC_PATH|/test_docs/long_code_block/index.html +// We now check that the block is on two lines: +show-text: true // We need to enable text draw to be able to have the "real" size +// Little explanations for this test: if the text wasn't displayed on two lines, it would take +// around 20px (which is the font size). +assert-property: (".docblock p > code", {"offsetHeight": "44"}) diff --git a/src/test/rustdoc-gui/docblock-code-block-line-number.goml b/src/test/rustdoc-gui/docblock-code-block-line-number.goml new file mode 100644 index 000000000..baf9651c4 --- /dev/null +++ b/src/test/rustdoc-gui/docblock-code-block-line-number.goml @@ -0,0 +1,22 @@ +// Checks that the setting "line numbers" is working as expected. +goto: file://|DOC_PATH|/test_docs/fn.foo.html + +// We check that without this setting, there is no line number displayed. +assert-false: "pre.line-number" + +// We now set the setting to show the line numbers on code examples. +local-storage: {"rustdoc-line-numbers": "true" } +// We reload to make the line numbers appear. +reload: + +// We wait for them to be added into the DOM by the JS... +wait-for: "pre.line-number" +// If the test didn't fail, it means that it was found! +// Let's now check some CSS properties... +assert-css: ("pre.line-number", { + "margin": "0px", + "padding": "13px 8px", + "text-align": "right", +}) +// The first code block has two lines so let's check its `<pre>` elements lists both of them. +assert-text: ("pre.line-number", "1\n2") diff --git a/src/test/rustdoc-gui/docblock-details.goml b/src/test/rustdoc-gui/docblock-details.goml new file mode 100644 index 000000000..f6287ade2 --- /dev/null +++ b/src/test/rustdoc-gui/docblock-details.goml @@ -0,0 +1,23 @@ +// This ensures that the `<details>`/`<summary>` elements are displayed as expected. +goto: file://|DOC_PATH|/test_docs/details/struct.Details.html +show-text: true +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +reload: + +// We first check that the headers in the `.top-doc` doc block still have their +// bottom border. +assert-text: (".top-doc .docblock > h3", "Hello") +assert-css: ( + ".top-doc .docblock > h3", + {"border-bottom": "1px solid rgb(210, 210, 210)"}, +) +// We now check that the `<summary>` doesn't have a bottom border and has the correct display. +assert-css: ( + ".top-doc .docblock summary h4", + {"border-bottom": "0px none rgb(210, 210, 210)"}, +) +// This allows to ensure that summary is on one line only! +assert-property: (".top-doc .docblock summary h4", {"offsetHeight": "33"}) +assert-css: (".top-doc .docblock summary h4", {"margin-top": "15px", "margin-bottom": "5px"}) +// So `33 + 15 + 5` == `53` +assert-property: (".top-doc .docblock summary", {"offsetHeight": "53"}) diff --git a/src/test/rustdoc-gui/docblock-table-overflow.goml b/src/test/rustdoc-gui/docblock-table-overflow.goml new file mode 100644 index 000000000..af76d2ea4 --- /dev/null +++ b/src/test/rustdoc-gui/docblock-table-overflow.goml @@ -0,0 +1,21 @@ +// This test ensures that the type declaration content overflow is handled inside the <pre> directly. +goto: file://|DOC_PATH|/lib2/long_table/struct.Foo.html +// We set a fixed size so there is no chance of "random" resize. +size: (1100, 800) +// Logically, the ".docblock" and the "<p>" should have the same scroll width. +compare-elements-property: (".top-doc .docblock", ".top-doc .docblock > p", ["scrollWidth"]) +assert-property: (".top-doc .docblock", {"scrollWidth": "801"}) +// However, since there is overflow in the <table>, its scroll width is bigger. +assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"}) + +// Checking it works on other doc blocks as well... + +// Logically, the ".docblock" and the "<p>" should have the same scroll width. +compare-elements-property: ( + "#implementations-list > details .docblock", + "#implementations-list > details .docblock > p", + ["scrollWidth"], +) +assert-property: ("#implementations-list > details .docblock", {"scrollWidth": "801"}) +// However, since there is overflow in the <table>, its scroll width is bigger. +assert-property: ("#implementations-list > details .docblock table", {"scrollWidth": "1573"}) diff --git a/src/test/rustdoc-gui/duplicate-macro-reexport.goml b/src/test/rustdoc-gui/duplicate-macro-reexport.goml new file mode 100644 index 000000000..9ea599062 --- /dev/null +++ b/src/test/rustdoc-gui/duplicate-macro-reexport.goml @@ -0,0 +1,14 @@ +// This test ensures that there is no macro duplicates in the sidebar. +goto: file://|DOC_PATH|/test_docs/macro.a.html +// Waiting for the elements in the sidebar to be rendered. +wait-for: ".sidebar-elems .macro" +// Check there is only one macro named "a" listed in the sidebar. +assert-count: ( + "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[text()='a']", + 1, +) +// Check there is only one macro named "b" listed in the sidebar. +assert-count: ( + "//*[@class='sidebar-elems']//*[@class='block macro']//li/a[text()='b']", + 1, +) diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml new file mode 100644 index 000000000..a5afb037d --- /dev/null +++ b/src/test/rustdoc-gui/escape-key.goml @@ -0,0 +1,35 @@ +// This test ensures that the "Escape" shortcut is handled correctly based on the +// current content displayed. +goto: file://|DOC_PATH|/test_docs/index.html +// First, we check that the search results are hidden when the Escape key is pressed. +write: (".search-input", "test") +// To be SURE that the search will be run. +press-key: 'Enter' +wait-for: "#search h1" // The search element is empty before the first search +// Check that the currently displayed element is search. +wait-for: "#alternative-display #search" +assert-attribute: ("#main-content", {"class": "content hidden"}) +assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH) +press-key: "Escape" +// Checks that search is no longer in the displayed content. +wait-for: "#not-displayed #search" +assert-false: "#alternative-display #search" +assert-attribute: ("#main-content", {"class": "content"}) +assert-document-property: ({"URL": "index.html"}, [ENDS_WITH]) + +// Check that focusing the search input brings back the search results +focus: ".search-input" +wait-for: "#alternative-display #search" +assert-attribute: ("#main-content", {"class": "content hidden"}) +assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH) + +// Check that Escape hides the search results when a search result is focused. +focus: ".search-input" +assert: ".search-input:focus" +press-key: "ArrowDown" +assert-false: ".search-input:focus" +assert: "#results a:focus" +press-key: "Escape" +wait-for: "#not-displayed #search" +assert-false: "#alternative-display #search" +assert-attribute: ("#main-content", {"class": "content"}) diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml new file mode 100644 index 000000000..5f29fde66 --- /dev/null +++ b/src/test/rustdoc-gui/font-weight.goml @@ -0,0 +1,44 @@ +// This test checks that the font weight is correctly applied. +goto: file://|DOC_PATH|/lib2/struct.Foo.html +assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"}) +assert-css: ( + "//*[@class='structfield small-section-header']//a[text()='Alias']", + {"font-weight": "400"}, +) +assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"}) +assert-css: ("#associatedtype\.X > .code-header", {"font-weight": "600"}) +assert-css: ("#associatedconstant\.Y > .code-header", {"font-weight": "600"}) + +goto: file://|DOC_PATH|/test_docs/type.SomeType.html +assert-css: (".top-doc .docblock p", {"font-weight": "400"}, ALL) + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +assert-css: (".impl-items .method", {"font-weight": "600"}, ALL) + +goto: file://|DOC_PATH|/lib2/trait.Trait.html + +// This is a complex selector, so here's how it works: +// +// * //*[@class='docblock item-decl'] — selects element of any tag with classes docblock and item-decl +// * /pre[@class='rust trait'] — selects immediate child with tag pre and classes rust and trait +// * /code — selects immediate child with tag code +// * /a[@class='constant'] — selects immediate child with tag a and class constant +// * //text() — selects child that is text node +// * /parent::* — selects immediate parent of the text node (the * means it can be any tag) +// +// This uses '/parent::*' as a proxy for the style of the text node. +// We can't just select the '<a>' because intermediate tags could be added. +assert-count: ( + "//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", + 1, +) +assert-css: ( + "//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", + {"font-weight": "400"}, +) + +assert-count: (".methods .associatedtype", 1) +assert-css: (".methods .associatedtype", {"font-weight": "600"}) +assert-count: (".methods .constant", 1) +assert-css: (".methods .constant", {"font-weight": "600"}) +assert-css: (".methods .method", {"font-weight": "600"}) diff --git a/src/test/rustdoc-gui/hash-item-expansion.goml b/src/test/rustdoc-gui/hash-item-expansion.goml new file mode 100644 index 000000000..861f69283 --- /dev/null +++ b/src/test/rustdoc-gui/hash-item-expansion.goml @@ -0,0 +1,11 @@ +// This test ensures that the element corresponding to the hash is displayed. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.borrow +// In the blanket implementations list, "Borrow" is the second one, hence the ":nth(2)". +assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""}) +// We first check that the impl block is open by default. +assert-attribute: ("#implementations-list details", {"open": ""}) +// To ensure that we will click on the currently hidden method. +assert-text: (".sidebar-elems section .block li > a", "must_use") +click: ".sidebar-elems section .block li > a" +// We check that the impl block was opened as expected so that we can see the method. +assert-attribute: ("#implementations-list > details", {"open": ""}) diff --git a/src/test/rustdoc-gui/headers-color.goml b/src/test/rustdoc-gui/headers-color.goml new file mode 100644 index 000000000..a47a9c8a1 --- /dev/null +++ b/src/test/rustdoc-gui/headers-color.goml @@ -0,0 +1,117 @@ +// This test check for headers text and background colors for the different themes. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html + +// This is needed so that the text color is computed. +show-text: true + +// Ayu theme +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-preferred-dark-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +assert-css: ( + ".impl", + {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"}, + ALL, +) +assert-css: ( + ".impl .code-header", + {"color": "rgb(230, 225, 207)", "background-color": "rgb(15, 20, 25)"}, + ALL, +) + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo +assert-css: ( + "#impl-Foo", + {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"}, +) + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use +assert-css: ( + "#method\.must_use", + {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"}, + ALL, +) + +goto: file://|DOC_PATH|/test_docs/index.html +assert-css: (".small-section-header a", {"color": "rgb(197, 197, 197)"}, ALL) + +goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html +// We select headings (h2, h3, h...). +assert-css: (".docblock > :not(p) > a", {"color": "rgb(57, 175, 215)"}, ALL) + +// Dark theme +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-preferred-dark-theme": "dark", + "rustdoc-use-system-theme": "false", +} +goto: file://|DOC_PATH|/test_docs/struct.Foo.html + +assert-css: ( + ".impl", + {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, + ALL, +) +assert-css: ( + ".impl .code-header", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(53, 53, 53)"}, + ALL, +) + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo +assert-css: ( + "#impl-Foo", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"}, +) + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use +assert-css: ( + "#method\.must_use", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"}, + ALL, +) + +goto: file://|DOC_PATH|/test_docs/index.html +assert-css: (".small-section-header a", {"color": "rgb(221, 221, 221)"}, ALL) + +goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html +// We select headings (h2, h3, h...). +assert-css: (".docblock > :not(p) > a", {"color": "rgb(210, 153, 29)"}, ALL) + +// Light theme +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +reload: + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html + +assert-css: ( + ".impl", + {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, + ALL, +) +assert-css: ( + ".impl .code-header", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"}, + ALL, +) + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo +assert-css: ("#impl-Foo", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"}) + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use +assert-css: ( + "#method\.must_use", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"}, + ALL, +) + +goto: file://|DOC_PATH|/test_docs/index.html +assert-css: (".small-section-header a", {"color": "rgb(0, 0, 0)"}, ALL) + +goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html +// We select headings (h2, h3, h...). +assert-css: (".docblock > :not(p) > a", {"color": "rgb(56, 115, 173)"}, ALL) diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml new file mode 100644 index 000000000..8c2c3df15 --- /dev/null +++ b/src/test/rustdoc-gui/headings.goml @@ -0,0 +1,258 @@ +// This test checks that headers (a) have the correct heading level, (b) are the right size, +// and (c) have the correct underlining (or absence of underlining). +// The sizes may change as design changes, but try to make sure a lower header is never bigger than +// its parent headers. Also make sure lower headers don't have underlines when their parents lack +// an underline. +// Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our +// default 16px font size: +// 24px 1.5em +// 22px 1.375rem +// 20px 1.25rem +// 18px 1.125em +// 16px 1rem +// 14px 0.875rem +goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"}) +assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"}) +assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "18px"}) +assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"}) + +assert-css: ("h2#fields", {"font-size": "22px"}) +assert-css: ("h2#fields", {"border-bottom-width": "1px"}) +assert-css: ("h3#title-for-field", {"font-size": "20px"}) +assert-css: ("h3#title-for-field", {"border-bottom-width": "0px"}) +assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"}) +assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"}) + +assert-css: ("h2#implementations", {"font-size": "22px"}) +assert-css: ("h2#implementations", {"border-bottom-width": "1px"}) + +assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"font-size": "18px"}) +assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"border-bottom-width": "0px"}) +assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"}) +assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"}) + +assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"}) +assert-css: ("h4#title-for-struct-impl-doc", {"border-bottom-width": "0px"}) +assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"}) +assert-css: ("h5#sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"}) +assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "14px"}) +assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"}) + +assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"}) +assert-css: ("h5#title-for-struct-impl-item-doc", {"border-bottom-width": "0px"}) +assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "14px"}) +assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"}) +assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "14px"}) + +goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"}) +assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"}) +assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "18px"}) +assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"}) + +assert-css: ("h2#variants", {"font-size": "22px"}) +assert-css: ("h2#variants", {"border-bottom-width": "1px"}) + +assert-css: ("h4#none-prose-title", {"font-size": "16px"}) +assert-css: ("h4#none-prose-title", {"border-bottom-width": "0px"}) +assert-css: ("h5#none-prose-sub-heading", {"font-size": "16px"}) +assert-css: ("h5#none-prose-sub-heading", {"border-bottom-width": "0px"}) + +assert-css: ("h4#wrapped-prose-title", {"font-size": "16px"}) +assert-css: ("h4#wrapped-prose-title", {"border-bottom-width": "0px"}) +assert-css: ("h5#wrapped-prose-sub-heading", {"font-size": "16px"}) +assert-css: ("h5#wrapped-prose-sub-heading", {"border-bottom-width": "0px"}) + +assert-css: ("h5#wrapped0-prose-title", {"font-size": "16px"}) +assert-css: ("h5#wrapped0-prose-title", {"border-bottom-width": "0px"}) +assert-css: ("h6#wrapped0-prose-sub-heading", {"font-size": "14px"}) +assert-css: ("h6#wrapped0-prose-sub-heading", {"border-bottom-width": "0px"}) + +assert-css: ("h5#structy-prose-title", {"font-size": "16px"}) +assert-css: ("h5#structy-prose-title", {"border-bottom-width": "0px"}) +assert-css: ("h6#structy-prose-sub-heading", {"font-size": "14px"}) +assert-css: ("h6#structy-prose-sub-heading", {"border-bottom-width": "0px"}) + +assert-css: ("h2#implementations", {"font-size": "22px"}) +assert-css: ("h2#implementations", {"border-bottom-width": "1px"}) + +assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"font-size": "18px"}) +assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"border-bottom-width": "0px"}) +assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"}) +assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"}) + +assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"}) +assert-css: ("h4#title-for-enum-impl-doc", {"border-bottom-width": "0px"}) +assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"}) +assert-css: ("h5#sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"}) +assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "14px"}) +assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"}) + +assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"}) +assert-css: ("h5#title-for-enum-impl-item-doc", {"border-bottom-width": "0px"}) +assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "14px"}) +assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"}) +assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "14px"}) +assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"}) + +assert-text: (".sidebar .mod h3", "Modules") +assert-css: (".sidebar .mod h3", {"border-bottom-width": "0px"}, ALL) + +goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"}) +assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"}) + +assert-css: ("h2#fields", {"font-size": "22px"}) +assert-css: ("h2#fields", {"border-bottom-width": "1px"}) + +assert-css: ("h3#title-for-union-variant", {"font-size": "20px"}) +assert-css: ("h3#title-for-union-variant", {"border-bottom-width": "0px"}) +assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"}) +assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"}) + +assert-css: ("h2#implementations", {"font-size": "22px"}) +assert-css: ("h2#implementations", {"border-bottom-width": "1px"}) + +assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"font-size": "18px"}) +assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"border-bottom-width": "0px"}) +assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"}) +assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"}) +assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"}) +assert-css: ("h5#sub-heading-for-union-impl-doc", {"border-bottom-width": "0px"}) + +assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"}) +assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"}) +assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "14px"}) +assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"}) + +goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html + +assert-css: ("h1.fqn", {"font-size": "24px"}) + +assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"}) +assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"}) +assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"}) + +// Checking colors now. +show-text: true +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html +assert-css: ( + ".top-doc .docblock h2", + {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"}, +) +assert-css: ( + ".top-doc .docblock h3", + {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"}, +) +assert-css: ( + ".top-doc .docblock h4", + {"color": "rgb(0, 0, 0)", "border-bottom": "1px solid rgb(221, 221, 221)"}, +) +assert-css: ( + ".top-doc .docblock h5", + {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, +) +assert-css: ( + "#implementations-list .docblock h4", + {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, +) +assert-css: ( + "#implementations-list .docblock h5", + {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, +) +assert-css: ( + "#implementations-list .docblock h6", + {"color": "rgb(0, 0, 0)", "border-bottom": "0px none rgb(221, 221, 221)"}, +) + +local-storage: {"rustdoc-theme": "dark"} +reload: +assert-css: ( + ".top-doc .docblock h2", + {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"}, +) +assert-css: ( + ".top-doc .docblock h3", + {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"}, +) +assert-css: ( + ".top-doc .docblock h4", + {"color": "rgb(221, 221, 221)", "border-bottom": "1px solid rgb(210, 210, 210)"}, +) +assert-css: ( + ".top-doc .docblock h5", + {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, +) +assert-css: ( + "#implementations-list .docblock h4", + {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, +) +assert-css: ( + "#implementations-list .docblock h5", + {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, +) +assert-css: ( + "#implementations-list .docblock h6", + {"color": "rgb(221, 221, 221)", "border-bottom": "0px none rgb(210, 210, 210)"}, +) + +local-storage: {"rustdoc-theme": "ayu"} +reload: +assert-css: ( + ".top-doc .docblock h2", + {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"}, +) +assert-css: ( + ".top-doc .docblock h2", + {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"}, +) +assert-css: ( + ".top-doc .docblock h4", + {"color": "rgb(255, 255, 255)", "border-bottom": "1px solid rgb(92, 103, 115)"}, +) +assert-css: ( + ".top-doc .docblock h5", + {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"}, +) +assert-css: ( + "#implementations-list .docblock h4", + {"color": "rgb(255, 255, 255)", "border-bottom": "0px none rgb(92, 103, 115)"}, +) +assert-css: ( + "#implementations-list .docblock h5", + {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"}, +) +assert-css: ( + "#implementations-list .docblock h6", + {"color": "rgb(197, 197, 197)", "border-bottom": "0px none rgb(92, 103, 115)"}, +) + +local-storage: {"rustdoc-theme": "light"} +goto: file://|DOC_PATH|/staged_api/struct.Foo.html +assert-css: (".since", {"color": "rgb(128, 128, 128)"}) + +local-storage: {"rustdoc-theme": "dark"} +reload: +assert-css: (".since", {"color": "rgb(128, 128, 128)"}) + +local-storage: {"rustdoc-theme": "ayu"} +reload: +assert-css: (".since", {"color": "rgb(128, 128, 128)"}) diff --git a/src/test/rustdoc-gui/huge-collection-of-constants.goml b/src/test/rustdoc-gui/huge-collection-of-constants.goml new file mode 100644 index 000000000..4f75b5841 --- /dev/null +++ b/src/test/rustdoc-gui/huge-collection-of-constants.goml @@ -0,0 +1,9 @@ +// Make sure that the last two entries are more than 12 pixels apart and not stacked on each other. + +goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html + +compare-elements-position-near-false: ( + "//*[@class='item-table']//div[last()-1]", + "//*[@class='item-table']//div[last()-3]", + {"y": 12}, +) diff --git a/src/test/rustdoc-gui/impl-default-expansion.goml b/src/test/rustdoc-gui/impl-default-expansion.goml new file mode 100644 index 000000000..6df2661e6 --- /dev/null +++ b/src/test/rustdoc-gui/impl-default-expansion.goml @@ -0,0 +1,3 @@ +// This test ensures that the impl blocks are open by default. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +assert-attribute: ("#implementations-list details.implementors-toggle", {"open": ""}) diff --git a/src/test/rustdoc-gui/implementors.goml b/src/test/rustdoc-gui/implementors.goml new file mode 100644 index 000000000..666a6e125 --- /dev/null +++ b/src/test/rustdoc-gui/implementors.goml @@ -0,0 +1,35 @@ +// The goal of this test is to check that the external trait implementors, generated with JS, +// have the same display than the "local" ones. +goto: file://|DOC_PATH|/implementors/trait.Whatever.html +assert: "#implementors-list" +// There are supposed to be two implementors listed. +assert-count: ("#implementors-list .impl", 2) +// Now we check that both implementors have an anchor, an ID and a similar DOM. +assert: ("#implementors-list .impl:nth-child(1) > a.anchor") +assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever-for-Struct"}) +assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever-for-Struct"}) +assert: "#implementors-list .impl:nth-child(1) > .code-header.in-band" + +assert: ("#implementors-list .impl:nth-child(2) > a.anchor") +assert-attribute: ("#implementors-list .impl:nth-child(2)", {"id": "impl-Whatever-1"}) +assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"}) +assert: "#implementors-list .impl:nth-child(2) > .code-header.in-band" + +goto: file://|DOC_PATH|/test_docs/struct.HasEmptyTraits.html +compare-elements-position-near-false: ( + "#impl-EmptyTrait1-for-HasEmptyTraits", + "#impl-EmptyTrait2-for-HasEmptyTraits", + {"y": 30}, +) +compare-elements-position-near: ( + "#impl-EmptyTrait3-for-HasEmptyTraits h3", + "#impl-EmptyTrait3-for-HasEmptyTraits .item-info", + {"y": 30}, +) + +// Now check that re-exports work correctly. +// There should be exactly one impl shown on both of these pages. +goto: file://|DOC_PATH|/lib2/trait.TraitToReexport.html +assert-count: ("#implementors-list .impl", 1) +goto: file://|DOC_PATH|/implementors/trait.TraitToReexport.html +assert-count: ("#implementors-list .impl", 1) diff --git a/src/test/rustdoc-gui/item-info-overflow.goml b/src/test/rustdoc-gui/item-info-overflow.goml new file mode 100644 index 000000000..b7095a3c5 --- /dev/null +++ b/src/test/rustdoc-gui/item-info-overflow.goml @@ -0,0 +1,31 @@ +// This test ensures that the "item-info" elements don't overflow. +goto: file://|DOC_PATH|/lib2/struct.LongItemInfo.html +// We set a fixed size so there is no chance of "random" resize. +size: (1200, 870) +// Logically, the "item-decl" and the "item-info" should have the same scroll width. +compare-elements-property: (".docblock.item-decl", ".item-info", ["scrollWidth"]) +assert-property: (".item-info", {"scrollWidth": "890"}) +// Just to be sure we're comparing the correct "item-info": +assert-text: ( + ".item-info", + "Available on Android or Linux or Emscripten or DragonFly BSD", + STARTS_WITH, +) + +// Checking the "item-info" on an impl block as well: +goto: file://|DOC_PATH|/lib2/struct.LongItemInfo2.html +compare-elements-property: ( + "#impl-SimpleTrait-for-LongItemInfo2 .item-info", + "#impl-SimpleTrait-for-LongItemInfo2 + .docblock", + ["scrollWidth"], +) +assert-property: ( + "#impl-SimpleTrait-for-LongItemInfo2 .item-info", + {"scrollWidth": "866"}, +) +// Just to be sure we're comparing the correct "item-info": +assert-text: ( + "#impl-SimpleTrait-for-LongItemInfo2 .item-info", + "Available on Android or Linux or Emscripten or DragonFly BSD", + STARTS_WITH, +) diff --git a/src/test/rustdoc-gui/item-info.goml b/src/test/rustdoc-gui/item-info.goml new file mode 100644 index 000000000..50c45b76b --- /dev/null +++ b/src/test/rustdoc-gui/item-info.goml @@ -0,0 +1,32 @@ +// This test ensures a few things for item info elements. +goto: file://|DOC_PATH|/lib2/struct.Foo.html +// Ensuring that the item information don't take 100% of the width if unnecessary. +// We set a fixed size so there is no chance of "random" resize. +size: (1100, 800) +// We check that ".item-info" is bigger than its content. +assert-css: (".item-info", {"width": "790px"}) +assert-css: (".item-info .stab", {"width": "289px"}) +assert-position: (".item-info .stab", {"x": 295}) + +// Now we ensure that they're not rendered on the same line. +goto: file://|DOC_PATH|/lib2/trait.Trait.html +// We first ensure that there are two item info on the trait. +assert-count: ("#main-content > .item-info .stab", 2) +// They should not have the same `y` position! +compare-elements-position-false: ( + "#main-content > .item-info .stab:nth-of-type(1)", + "#main-content > .item-info .stab:nth-of-type(2)", + ("y"), +) +// But they should have the same `x` position. +compare-elements-position: ( + "#main-content > .item-info .stab:nth-of-type(1)", + "#main-content > .item-info .stab:nth-of-type(2)", + ("x"), +) +// They are supposed to have the same height too. +compare-elements-css: ( + "#main-content > .item-info .stab:nth-of-type(1)", + "#main-content > .item-info .stab:nth-of-type(2)", + ["height"], +) diff --git a/src/test/rustdoc-gui/item-summary-table.goml b/src/test/rustdoc-gui/item-summary-table.goml new file mode 100644 index 000000000..6bf4e288c --- /dev/null +++ b/src/test/rustdoc-gui/item-summary-table.goml @@ -0,0 +1,6 @@ +// This test ensures that <table> elements aren't display in items summary. +goto: file://|DOC_PATH|/lib2/summary_table/index.html +// We check that we picked the right item first. +assert-text: (".item-table .item-left", "Foo") +// Then we check that its summary is empty. +assert-text: (".item-table .item-right", "") diff --git a/src/test/rustdoc-gui/javascript-disabled.goml b/src/test/rustdoc-gui/javascript-disabled.goml new file mode 100644 index 000000000..1693f7b64 --- /dev/null +++ b/src/test/rustdoc-gui/javascript-disabled.goml @@ -0,0 +1,6 @@ +// When JavaScript is disabled, we hide the search bar, because it +// can't be used without JS. +javascript: false + +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +assert-css: (".sub", {"display": "none"}) diff --git a/src/test/rustdoc-gui/jump-to-def-background.goml b/src/test/rustdoc-gui/jump-to-def-background.goml new file mode 100644 index 000000000..d17400f5b --- /dev/null +++ b/src/test/rustdoc-gui/jump-to-def-background.goml @@ -0,0 +1,43 @@ +// We check the background color on the jump to definition links in the source code page. +goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html + +// Set the theme to dark. +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-preferred-dark-theme": "dark", + "rustdoc-use-system-theme": "false", +} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ( + "body.source .example-wrap pre.rust a", + {"background-color": "rgb(51, 51, 51)"}, + ALL, +) + +// Set the theme to ayu. +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-preferred-dark-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ( + "body.source .example-wrap pre.rust a", + {"background-color": "rgb(51, 51, 51)"}, + ALL, +) + +// Set the theme to light. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + +assert-css: ( + "body.source .example-wrap pre.rust a", + {"background-color": "rgb(238, 238, 238)"}, + ALL, +) diff --git a/src/test/rustdoc-gui/label-next-to-symbol.goml b/src/test/rustdoc-gui/label-next-to-symbol.goml new file mode 100644 index 000000000..ca3994a08 --- /dev/null +++ b/src/test/rustdoc-gui/label-next-to-symbol.goml @@ -0,0 +1,78 @@ +// These tests verify that labels like "UNIX" and "Deprecated" stay on the same line as their symbol. +// It also verifies the staggered layout on mobile. +goto: file://|DOC_PATH|/test_docs/index.html + +// Desktop view +size: (1080, 600) +assert: (".stab.deprecated") +assert: (".stab.portability") + +// make sure that deprecated and portability are different colours +assert-css: ( + ".item-table .item-left .stab.deprecated", + { "background-color": "rgb(255, 196, 196)" }, +) +assert-css: ( + ".item-table .item-left .stab.portability", + { "background-color": "rgb(243, 223, 255)" }, +) + +// table like view +assert-css: (".item-right.docblock-short", { "padding-left": "0px" }) +compare-elements-position-near: ( + "//*[@class='item-left module-item']//a[text()='replaced_function']", + ".item-left .stab.deprecated", + {"y": 2}, +) +compare-elements-position: ( + ".item-left .stab.deprecated", + ".item-left .stab.portability", + ("y"), +) + +// Ensure no wrap +compare-elements-position-near: ( + "//*[@class='item-left module-item']//a[text()='replaced_function']", + "//*[@class='item-right docblock-short']//p[text()='a thing with a label']", + {"y": 2}, +) +// compare parent elements +compare-elements-position: ( + "//*[@class='item-left module-item']//a[text()='replaced_function']/..", + "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..", + ("y"), +) + + +// Mobile view +size: (600, 600) +// staggered layout with 2em spacing +assert-css: (".item-right.docblock-short", { "padding-left": "32px" }) +compare-elements-position-near: ( + "//*[@class='item-left module-item']//a[text()='replaced_function']", + ".item-left .stab.deprecated", + {"y": 1}, +) +compare-elements-position: ( + ".item-left .stab.deprecated", + ".item-left .stab.portability", + ("y"), +) + +// Ensure wrap +compare-elements-position-near-false: ( + "//*[@class='item-left module-item']//a[text()='replaced_function']", + "//*[@class='item-right docblock-short']//p[text()='a thing with a label']", + {"y": 12}, +) +// compare parent elements +compare-elements-position-false: ( + "//*[@class='item-left module-item']//a[text()='replaced_function']/..", + "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..", + ("y"), +) +compare-elements-position-false: ( + ".item-left .stab.deprecated", + "//*[@class='item-right docblock-short']//p[text()='a thing with a label']", + ("y"), +) diff --git a/src/test/rustdoc-gui/list_code_block.goml b/src/test/rustdoc-gui/list_code_block.goml new file mode 100644 index 000000000..eba1a662b --- /dev/null +++ b/src/test/rustdoc-gui/list_code_block.goml @@ -0,0 +1,4 @@ +// This test checks that code blocks in list are supported. +goto: file://|DOC_PATH|/test_docs/index.html +goto: ./fn.check_list_code_block.html +assert: ("pre.rust.fn") diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml new file mode 100644 index 000000000..13b9b563d --- /dev/null +++ b/src/test/rustdoc-gui/mobile.goml @@ -0,0 +1,30 @@ +// Test various properties of the mobile UI +goto: file://|DOC_PATH|/staged_api/struct.Foo.html +size: (400, 600) + +font-size: 18 +wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account. + +// The out-of-band info (source, stable version, collapse) should be below the +// h1 when the screen gets narrow enough. +assert-css: (".main-heading", { + "display": "flex", + "flex-direction": "column" +}) + +assert-property: (".mobile-topbar h2.location", {"offsetHeight": 36}) + +// Note: We can't use assert-text here because the 'Since' is set by CSS and +// is therefore not part of the DOM. +assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" }) + +size: (1000, 1000) +wait-for: 100 // wait a bit for the resize to be fully taken into account. +assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" }) + +// On the settings page, the theme buttons should not line-wrap. Instead, they should +// all be placed as a group on a line below the setting name "Theme." +goto: file://|DOC_PATH|/settings.html +size: (400, 600) +// Ignored for now https://github.com/rust-lang/rust/issues/93784. +// compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16}) diff --git a/src/test/rustdoc-gui/module-items-font.goml b/src/test/rustdoc-gui/module-items-font.goml new file mode 100644 index 000000000..758ee391a --- /dev/null +++ b/src/test/rustdoc-gui/module-items-font.goml @@ -0,0 +1,67 @@ +// This test checks that the correct font is used on module items (in index.html pages). +goto: file://|DOC_PATH|/test_docs/index.html +assert-css: ( + ".item-table .module-item a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, + ALL, +) +assert-css: ( + ".item-table .docblock-short", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, + ALL, +) + +// modules +assert-css: ( + "#modules + .item-table .item-left a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#modules + .item-table .item-right.docblock-short", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) +// structs +assert-css: ( + "#structs + .item-table .item-left a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#structs + .item-table .item-right.docblock-short", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) +// enums +assert-css: ( + "#enums + .item-table .item-left a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#enums + .item-table .item-right.docblock-short", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) +// traits +assert-css: ( + "#traits + .item-table .item-left a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#traits + .item-table .item-right.docblock-short", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) +// functions +assert-css: ( + "#functions + .item-table .item-left a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#functions + .item-table .item-right.docblock-short", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) +// keywords +assert-css: ( + "#keywords + .item-table .item-left a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#keywords + .item-table .item-right.docblock-short", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) diff --git a/src/test/rustdoc-gui/overflow-tooltip-information.goml b/src/test/rustdoc-gui/overflow-tooltip-information.goml new file mode 100644 index 000000000..7ef85a4c4 --- /dev/null +++ b/src/test/rustdoc-gui/overflow-tooltip-information.goml @@ -0,0 +1,8 @@ +// The goal of this test is to ensure that the tooltip `.information` class doesn't +// have overflow and max-width CSS rules set because they create a bug in firefox on +// mac. For more information: https://github.com/rust-lang/rust/issues/89185 +goto: file://|DOC_PATH|/test_docs/fn.foo.html +assert-css: (".docblock > .information", { + "overflow-x": "visible", + "max-width": "none" +}, ALL) diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml new file mode 100644 index 000000000..54f3790a7 --- /dev/null +++ b/src/test/rustdoc-gui/pocket-menu.goml @@ -0,0 +1,77 @@ +// This test ensures that the "pocket menus" are working as expected. +goto: file://|DOC_PATH|/test_docs/index.html +// First we check that the help menu doesn't exist yet. +assert-false: "#help-button .popover" +// Then we display the help menu. +click: "#help-button" +assert: "#help-button .popover" +assert-css: ("#help-button .popover", {"display": "block"}) + +// Now we click somewhere else on the page to ensure it is handling the blur event +// correctly. +click: ".sidebar" +assert-css: ("#help-button .popover", {"display": "none"}) + +// Now we will check that we cannot have two "pocket menus" displayed at the same time. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "block"}) +click: "#settings-menu" +assert-css: ("#help-button .popover", {"display": "none"}) +assert-css: ("#settings-menu .popover", {"display": "block"}) + +// Now the other way. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "block"}) +assert-css: ("#settings-menu .popover", {"display": "none"}) + +// Now verify that clicking the help menu again closes it. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "none"}) +assert-css: ("#settings-menu .popover", {"display": "none"}) + +// We check the borders color now: + +// Ayu theme +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(92, 103, 115)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) + +// Dark theme +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(210, 210, 210)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) + +// Light theme +local-storage: { + "rustdoc-theme": "light", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(221, 221, 221)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) diff --git a/src/test/rustdoc-gui/run-on-hover.goml b/src/test/rustdoc-gui/run-on-hover.goml new file mode 100644 index 000000000..b8efa8e30 --- /dev/null +++ b/src/test/rustdoc-gui/run-on-hover.goml @@ -0,0 +1,7 @@ +// Example code blocks sometimes have a "Run" button to run them on the +// Playground. That button is hidden until the user hovers over the code block. +// This test checks that it is hidden, and that it shows on hover. +goto: file://|DOC_PATH|/test_docs/fn.foo.html +assert-css: (".test-arrow", {"visibility": "hidden"}) +move-cursor-to: ".example-wrap" +assert-css: (".test-arrow", {"visibility": "visible"}) diff --git a/src/test/rustdoc-gui/rust-logo.goml b/src/test/rustdoc-gui/rust-logo.goml new file mode 100644 index 000000000..4a9dcf735 --- /dev/null +++ b/src/test/rustdoc-gui/rust-logo.goml @@ -0,0 +1,78 @@ +// This test ensures that the correct style is applied to the rust logo in the sidebar. +goto: file://|DOC_PATH|/test_docs/index.html + +// First we start with the dark theme. +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-preferred-dark-theme": "dark", + "rustdoc-use-system-theme": "false", +} +reload: + +assert-css: ( + ".rust-logo", + {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"}, +) + +// In the source view page now. +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html + +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-preferred-dark-theme": "dark", + "rustdoc-use-system-theme": "false", +} +reload: + +assert-css: ( + ".rust-logo", + {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"}, +) + +// Then with the ayu theme. +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-preferred-dark-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +assert-css: ( + ".rust-logo", + {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"}, +) + +// In the source view page now. +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html + +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-preferred-dark-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +assert-css: ( + ".rust-logo", + {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"}, +) + +// And finally with the light theme. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +reload: + +assert-css: ( + ".rust-logo", + {"filter": "none"}, +) + +// In the source view page now. +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html + +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +reload: + +assert-css: ( + ".rust-logo", + {"filter": "none"}, +) diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml new file mode 100644 index 000000000..d645e2370 --- /dev/null +++ b/src/test/rustdoc-gui/search-filter.goml @@ -0,0 +1,83 @@ +// Checks that the crate search filtering is handled correctly and changes the results. +goto: file://|DOC_PATH|/test_docs/index.html +show-text: true +write: (".search-input", "test") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +assert-text: ("#results .externcrate", "test_docs") + +wait-for: "#crate-search" +// We now want to change the crate filter. +click: "#crate-search" +// We select "lib2" option then press enter to change the filter. +press-key: "ArrowDown" +press-key: "ArrowDown" +press-key: "Enter" +// Waiting for the search results to appear... +wait-for: "#titles" +assert-document-property: ({"URL": "&filter-crate="}, CONTAINS) +// We check that there is no more "test_docs" appearing. +assert-false: "#results .externcrate" +// We also check that "lib2" is the filter crate. +assert-property: ("#crate-search", {"value": "lib2"}) + +// Now we check that leaving the search results and putting them back keeps the +// crate filtering. +press-key: "Escape" +wait-for-css: ("#main-content", {"display": "block"}) +focus: ".search-input" +wait-for-css: ("#main-content", {"display": "none"}) +// We check that there is no more "test_docs" appearing. +assert-false: "#results .externcrate" +assert-property: ("#crate-search", {"value": "lib2"}) + +// Selecting back "All crates" +click: "#crate-search" +press-key: "ArrowUp" +press-key: "ArrowUp" +press-key: "Enter" +// Waiting for the search results to appear... +wait-for: "#titles" +assert-property: ("#crate-search", {"value": "All crates"}) + +// Checking that the URL parameter is taken into account for crate filtering. +goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2 +wait-for: "#crate-search" +assert-property: ("#crate-search", {"value": "lib2"}) +assert-false: "#results .externcrate" + +// Checking that the text for the "title" is correct (the "All" comes from the "<select>"). +assert-text: ("#search-settings", "Results for test in All", STARTS_WITH) + +// Checking the display of the crate filter. +// We start with the light theme. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +reload: + +timeout: 2000 +wait-for: "#crate-search" +assert-css: ("#crate-search", { + "border": "1px solid rgb(224, 224, 224)", + "color": "rgb(0, 0, 0)", + "background-color": "rgb(255, 255, 255)", +}) + +// We now check the dark theme. +click: "#settings-menu" +wait-for: "#settings" +click: "#theme-dark" +wait-for-css: ("#crate-search", { + "border": "1px solid rgb(240, 240, 240)", + "color": "rgb(17, 17, 17)", + "background-color": "rgb(240, 240, 240)", +}) + +// And finally we check the ayu theme. +click: "#theme-ayu" +wait-for-css: ("#crate-search", { + "border": "1px solid rgb(66, 76, 87)", + "color": "rgb(197, 197, 197)", + "background-color": "rgb(20, 25, 32)", +}) diff --git a/src/test/rustdoc-gui/search-input-mobile.goml b/src/test/rustdoc-gui/search-input-mobile.goml new file mode 100644 index 000000000..5c95db70a --- /dev/null +++ b/src/test/rustdoc-gui/search-input-mobile.goml @@ -0,0 +1,11 @@ +// Test to ensure that you can click on the search input, whatever the width. +// The PR which fixed it is: https://github.com/rust-lang/rust/pull/81592 +goto: file://|DOC_PATH|/test_docs/index.html +size: (463, 700) +// We first check that the search input isn't already focused. +assert-false: ("input.search-input:focus") +click: "input.search-input" +reload: +size: (750, 700) +click: "input.search-input" +assert: ("input.search-input:focus") diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml new file mode 100644 index 000000000..44123b702 --- /dev/null +++ b/src/test/rustdoc-gui/search-input.goml @@ -0,0 +1,23 @@ +// Ensures that the search input border color changes on focus. +goto: file://|DOC_PATH|/test_docs/index.html +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} +reload: + +assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) +click: ".search-input" +focus: ".search-input" +assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"}) + +local-storage: {"rustdoc-theme": "light"} +reload: + +assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) +click: ".search-input" +assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"}) + +local-storage: {"rustdoc-theme": "ayu"} +reload: + +assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"}) +click: ".search-input" +assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"}) diff --git a/src/test/rustdoc-gui/search-reexport.goml b/src/test/rustdoc-gui/search-reexport.goml new file mode 100644 index 000000000..5ef890d47 --- /dev/null +++ b/src/test/rustdoc-gui/search-reexport.goml @@ -0,0 +1,33 @@ +// Checks that the reexports are present in the search index, can have +// doc aliases and are highligted when their ID is the hash of the page. +goto: file://|DOC_PATH|/test_docs/index.html +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +reload: +// First we check that the reexport has the correct ID and no background color. +assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;") +assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"}) +write: (".search-input", "TheStdReexport") +// To be SURE that the search will be run. +press-key: 'Enter' +wait-for: "//a[@class='result-import']" +assert-attribute: ( + "//a[@class='result-import']", + {"href": "../test_docs/index.html#reexport.TheStdReexport"}, +) +assert-text: ("//a[@class='result-import']", "test_docs::TheStdReexport") +click: "//a[@class='result-import']" +// We check that it has the background modified thanks to the focus. +wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgb(73, 74, 61)"}) + +// We now check that the alias is working as well on the reexport. +// To be SURE that the search will be run. +press-key: 'Enter' +write: (".search-input", "AliasForTheStdReexport") +wait-for: "//a[@class='result-import']" +assert-text: ( + "//a[@class='result-import']", + "AliasForTheStdReexport - see test_docs::TheStdReexport", +) +// Same thing again, we click on it to ensure the background is once again set as expected. +click: "//a[@class='result-import']" +wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgb(73, 74, 61)"}) diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml new file mode 100644 index 000000000..9a49ae2c6 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-color.goml @@ -0,0 +1,98 @@ +// The goal of this test is to ensure the color of the text is the one expected. +goto: file://|DOC_PATH|/test_docs/index.html?search=coo + +// This is needed so that the text color is computed. +show-text: true + +// Ayu theme +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-preferred-dark-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +// Waiting for the search results to appear... +wait-for: "#titles" +assert-css: ( + "//*[@class='desc']//*[text()='Just a normal struct.']", + {"color": "rgb(197, 197, 197)"}, +) +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']", + {"color": "rgb(0, 150, 207)"}, +) + +// Checking the color for "keyword". +assert-css: ( + "//*[@class='result-name']//*[text()='(keyword)']", + {"color": "rgb(120, 135, 151)"}, +) + +// Dark theme +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-preferred-dark-theme": "dark", + "rustdoc-use-system-theme": "false", +} +reload: + +// Waiting for the search results to appear... +wait-for: "#titles" +assert-css: ( + "//*[@class='desc']//*[text()='Just a normal struct.']", + {"color": "rgb(221, 221, 221)"}, +) +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']", + {"color": "rgb(221, 221, 221)"}, +) + +// Checking the color for "keyword". +assert-css: ( + "//*[@class='result-name']//*[text()='(keyword)']", + {"color": "rgb(221, 221, 221)"}, +) + +// Light theme +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +reload: + +// Waiting for the search results to appear... +wait-for: "#titles" +assert-css: ( + "//*[@class='desc']//*[text()='Just a normal struct.']", + {"color": "rgb(0, 0, 0)"}, +) +assert-css: ( + "//*[@class='result-name']/*[text()='test_docs::']", + {"color": "rgb(0, 0, 0)"}, +) + +// Checking the color for "keyword". +assert-css: ( + "//*[@class='result-name']//*[text()='(keyword)']", + {"color": "rgb(0, 0, 0)"}, +) + +// Check the alias more specifically in the dark theme. +goto: file://|DOC_PATH|/test_docs/index.html +// We set the theme so we're sure that the correct values will be used, whatever the computer +// this test is running on. +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-preferred-dark-theme": "dark", + "rustdoc-use-system-theme": "false", +} +// If the text isn't displayed, the browser doesn't compute color style correctly... +show-text: true +// We reload the page so the local storage settings are being used. +reload: +write: (".search-input", "thisisanalias") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +// Checking that the colors for the alias element are the ones expected. +assert-css: (".result-name > .alias", {"color": "rgb(255, 255, 255)"}) +assert-css: (".result-name > .alias > .grey", {"color": "rgb(204, 204, 204)"}) diff --git a/src/test/rustdoc-gui/search-result-description.goml b/src/test/rustdoc-gui/search-result-description.goml new file mode 100644 index 000000000..d8cb6ee57 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-description.goml @@ -0,0 +1,5 @@ +// This test is to ensure that the codeblocks are correctly rendered in the search results. +goto: file://|DOC_PATH|/test_docs/index.html?search=some_more_function +// Waiting for the search results to appear... +wait-for: "#titles" +assert-text: (".search-results .desc code", "format!") diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml new file mode 100644 index 000000000..8464ba7c2 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -0,0 +1,42 @@ +// Checks that the search results have the expected width. +goto: file://|DOC_PATH|/test_docs/index.html +size: (900, 1000) +write: (".search-input", "test") +// To be SURE that the search will be run. +press-key: 'Enter' +wait-for: "#search-settings" +// The width is returned by "getComputedStyle" which returns the exact number instead of the +// CSS rule which is "50%"... +assert-css: (".search-results div.desc", {"width": "295px"}) +size: (600, 100) +// As counter-intuitive as it may seem, in this width, the width is "100%", which is why +// when computed it's larger. +assert-css: (".search-results div.desc", {"width": "570px"}) + +// Check that the crate filter `<select>` is correctly handled when it goes to next line. +// To do so we need to update the length of one of its `<option>`. +size: (900, 900) + +// First we check the current width and position. +assert-css: ("#crate-search", {"width": "218px"}) +compare-elements-position-near: ( + "#crate-search", + "#search-settings .search-results-title", + {"y": 5}, +) + +// Then we update the text of one of the `<option>`. +text: ( + "#crate-search option", + "sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa", +) + +// Then we compare again. +assert-css: ("#crate-search", {"width": "640px"}) +compare-elements-position-near-false: ( + "#crate-search", + "#search-settings .search-results-title", + {"y": 5}, +) +// And we check that the `<select>` isn't bigger than its container. +assert-css: ("#search", {"width": "640px"}) diff --git a/src/test/rustdoc-gui/search-result-go-to-first.goml b/src/test/rustdoc-gui/search-result-go-to-first.goml new file mode 100644 index 000000000..255470a3e --- /dev/null +++ b/src/test/rustdoc-gui/search-result-go-to-first.goml @@ -0,0 +1,19 @@ +// This test ensures that the "go_to_first" feature is working as expected. + +// First, we check that the first page doesn't have the string we're looking for to ensure +// that the feature is changing page as expected. +goto: file://|DOC_PATH|/test_docs/index.html +assert-text-false: (".fqn .in-band", "Struct test_docs::Foo") + +// We now check that we land on the search result page if "go_to_first" isn't set. +goto: file://|DOC_PATH|/test_docs/index.html?search=struct%3AFoo +// Waiting for the search results to appear... +wait-for: "#titles" +assert-text-false: (".fqn .in-band", "Struct test_docs::Foo") +// Ensure that the search results are displayed, not the "normal" content. +assert-css: ("#main-content", {"display": "none"}) + +// Now we can check that the feature is working as expected! +goto: file://|DOC_PATH|/test_docs/index.html?search=struct%3AFoo&go_to_first=true +// Waiting for the page to load... +wait-for-text: (".fqn .in-band", "Struct test_docs::Foo") diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml new file mode 100644 index 000000000..16ae10431 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-keyword.goml @@ -0,0 +1,13 @@ +// Checks that the "keyword" results have the expected text alongside them. +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "CookieMonster") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +// Note: The two next assert commands could be merged as one but readability would be +// less good. +// +// Checking that the CSS is displaying " (keyword)" in italic. +assert-text: (".result-name span.keyword > i", "(keyword)") +assert-text: (".result-name span.keyword", "CookieMonster (keyword)") diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml new file mode 100644 index 000000000..9d506c151 --- /dev/null +++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml @@ -0,0 +1,74 @@ +// Checks that the search tab results work correctly with function signature syntax +// First, try a search-by-name +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "Foo") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Names", STARTS_WITH) +assert: "input.search-input:focus" +// Use left-right keys +press-key: "ArrowDown" +assert: "#results > .search-results.active > a:nth-of-type(1):focus" +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(2)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowLeft" +wait-for-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"}) + +// Now try search-by-return +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "-> String") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH) +assert: "input.search-input:focus" +// Use left-right keys +press-key: "ArrowDown" +assert: "#results > .search-results.active > a:nth-of-type(1):focus" +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowLeft" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) + +// Try with a search-by-return with no results +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "-> Something") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH) + +// Try with a search-by-parameter +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "usize pattern") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Parameters", STARTS_WITH) + +// Try with a search-by-parameter-and-return +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "pattern -> str") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signatures", STARTS_WITH) diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml new file mode 100644 index 000000000..d9cf5ee66 --- /dev/null +++ b/src/test/rustdoc-gui/settings.goml @@ -0,0 +1,158 @@ +// This test ensures that the settings menu display is working as expected. +goto: file://|DOC_PATH|/test_docs/index.html +show-text: true // needed when we check for colors below. +// First, we check that the settings page doesn't exist. +assert-false: "#settings" +// We now click on the settings button. +click: "#settings-menu" +wait-for: "#settings" +assert-css: ("#settings", {"display": "block"}) +// Let's close it by clicking on the same button. +click: "#settings-menu" +wait-for-css: ("#settings", {"display": "none"}) + +// Let's check that pressing "ESCAPE" is closing it. +click: "#settings-menu" +wait-for-css: ("#settings", {"display": "block"}) +press-key: "Escape" +wait-for-css: ("#settings", {"display": "none"}) + +// Let's click on it when the search results are displayed. +focus: ".search-input" +write: "test" +// To be SURE that the search will be run. +press-key: 'Enter' +wait-for: "#alternative-display #search" +click: "#settings-menu" +wait-for-css: ("#settings", {"display": "block"}) +// Ensure that the search is still displayed. +wait-for: "#alternative-display #search" +assert: "#main-content.hidden" + +// Now let's check the content of the settings menu. +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +reload: +click: "#settings-menu" +wait-for: "#settings" + +// We check that the "Use system theme" is disabled. +assert-property: ("#use-system-theme", {"checked": "false"}) +assert: "//*[@class='setting-line']//span[text()='Use system theme']" +// Meaning that only the "theme" menu is showing up. +assert: ".setting-line:not(.hidden) #theme" +assert: ".setting-line.hidden #preferred-dark-theme" +assert: ".setting-line.hidden #preferred-light-theme" + +// We check that the correct theme is selected. +assert-property: ("#theme .choices #theme-dark", {"checked": "true"}) + +// Some style checks... +// First we check the "default" display. +assert-css: ( + "#theme-dark", + { + "border-color": "rgb(221, 221, 221)", + "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset", + }, +) +assert-css: ("#theme-light", {"border-color": "rgb(221, 221, 221)", "box-shadow": "none"}) +// Let's start with the hover. +move-cursor-to: "#theme-dark" +assert-css: ( + "#theme-dark", + { + "border-color": "rgb(33, 150, 243)", + "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset", + }, +) +move-cursor-to: "#theme-light" +assert-css: ("#theme-light", {"border-color": "rgb(33, 150, 243)", "box-shadow": "none"}) +move-cursor-to: "#theme-ayu" +// Let's now check with the focus. +focus: "#theme-dark" +assert-css: ( + "#theme-dark", + { + "border-color": "rgb(221, 221, 221)", + "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px", + }, +) +focus: "#theme-light" +assert-css: ( + "#theme-light", + { + "border-color": "rgb(221, 221, 221)", + "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + }, +) +// Now we check we both focus and hover. +move-cursor-to: "#theme-dark" +focus: "#theme-dark" +assert-css: ( + "#theme-dark", + { + "border-color": "rgb(33, 150, 243)", + "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px", + }, +) +move-cursor-to: "#theme-light" +focus: "#theme-light" +assert-css: ( + "#theme-light", + { + "border-color": "rgb(33, 150, 243)", + "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px", + }, +) + +// We now switch the display. +click: "#use-system-theme" +// Wait for the hidden element to show up. +wait-for: ".setting-line:not(.hidden) #preferred-dark-theme" +assert: ".setting-line:not(.hidden) #preferred-light-theme" +// Check that the theme picking is hidden. +assert: ".setting-line.hidden #theme" + +// We check their text as well. +assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme") +assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme") + +// We now check that clicking on the "sliders"' text is like clicking on the slider. +// To test it, we use the "Disable keyboard shortcuts". +local-storage: {"rustdoc-disable-shortcuts": "false"} +click: ".setting-line:last-child .toggle .label" +assert-local-storage: {"rustdoc-disable-shortcuts": "true"} + +// Make sure that "Disable keyboard shortcuts" actually took effect. +press-key: "Escape" +press-key: "?" +assert-false: "#help-button .popover" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) + +// Now turn keyboard shortcuts back on, and see if they work. +click: ".setting-line:last-child .toggle .label" +assert-local-storage: {"rustdoc-disable-shortcuts": "false"} +press-key: "Escape" +press-key: "?" +wait-for-css: ("#help-button .popover", {"display": "block"}) +assert-css: ("#settings-menu .popover", {"display": "none"}) + +// Now we go to the settings page to check that the CSS is loaded as expected. +goto: file://|DOC_PATH|/settings.html +wait-for: "#settings" +assert-css: (".setting-line .toggle .slider", {"width": "45px", "margin-right": "20px"}) + +// We now check the display with JS disabled. +assert-false: "noscript section" +javascript: false +reload: +assert-css: ("noscript section", {"display": "block"}) +javascript: true + +// Check for the display on small screen +show-text: true +reload: +size: (300, 1000) +click: "#settings-menu" +wait-for: "#settings" +assert-css: ("#settings .slider", {"width": "45px"}, ALL) diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml new file mode 100644 index 000000000..1f20a0eaa --- /dev/null +++ b/src/test/rustdoc-gui/shortcuts.goml @@ -0,0 +1,13 @@ +// Check that the various shortcuts are working. +goto: file://|DOC_PATH|/test_docs/index.html +// We first check that the search input isn't already focused. +assert-false: "input.search-input:focus" +press-key: "s" +assert: "input.search-input:focus" +press-key: "Escape" +assert-false: "input.search-input:focus" +// We now check for the help popup. +press-key: "?" +assert-css: ("#help-button .popover", {"display": "block"}) +press-key: "Escape" +assert-css: ("#help-button .popover", {"display": "none"}) diff --git a/src/test/rustdoc-gui/sidebar-macro-reexport.goml b/src/test/rustdoc-gui/sidebar-macro-reexport.goml new file mode 100644 index 000000000..a3a62fe54 --- /dev/null +++ b/src/test/rustdoc-gui/sidebar-macro-reexport.goml @@ -0,0 +1,5 @@ +// This test ensures that the reexport of a macro doesn't make the original macro +// displayed twice in the sidebar. +goto: file://|DOC_PATH|/test_docs/macro.repro.html +wait-for: ".sidebar-elems .macro .macro" +assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1) diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml new file mode 100644 index 000000000..033c65783 --- /dev/null +++ b/src/test/rustdoc-gui/sidebar-mobile.goml @@ -0,0 +1,64 @@ +// This test ensure that the sidebar isn't "hidden" on mobile but instead moved out of the viewport. +// This is especially important for devices for "text-first" content (like for users with +// sight issues). +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +// Switching to "mobile view" by reducing the width to 600px. +size: (600, 600) +assert-css: (".sidebar", {"display": "block", "left": "-1000px"}) +// Opening the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"display": "block", "left": "0px"}) +// Closing the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"display": "block", "left": "-1000px"}) +// Force the sidebar open by focusing a link inside it. +// This makes it easier for keyboard users to get to it. +focus: ".sidebar-title a" +assert-css: (".sidebar", {"display": "block", "left": "0px"}) +// When we tab out of the sidebar, close it. +focus: ".search-input" +assert-css: (".sidebar", {"display": "block", "left": "-1000px"}) + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"left": "0px"}) + +// Click elsewhere. +click: "body" +assert-css: (".sidebar", {"display": "block", "left": "-1000px"}) + +// Check that the topbar is visible +assert-property: (".mobile-topbar", {"clientHeight": "45"}) + +// Check that clicking an element from the sidebar scrolls to the right place +// so the target is not obscured by the topbar. +click: ".sidebar-menu-toggle" +click: ".sidebar-elems section .block li > a" +assert-position: ("#method\.must_use", {"y": 45}) + +// Check that the bottom-most item on the sidebar menu can be scrolled fully into view. +click: ".sidebar-menu-toggle" +scroll-to: ".block.keyword li:nth-child(1)" +compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543}) + +// Now checking the background color of the sidebar. +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} +reload: + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)"}) + +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"} +reload: + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)"}) + +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"} +reload: + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)"}) diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml new file mode 100644 index 000000000..fa322574f --- /dev/null +++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml @@ -0,0 +1,254 @@ +// This test ensures that the elements in the sidebar are displayed correctly. +javascript: false +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +// Since the javascript is disabled, there shouldn't be a toggle. +assert-false: "#sidebar-toggle" +// For some reason, we need to wait a bit here because it seems like the transition on opacity +// is being applied whereas it can't be reproduced in a browser... +wait-for-css: (".sidebar > *", {"visibility": "hidden", "opacity": 0}) + +// Let's retry with javascript enabled. +javascript: true +reload: +wait-for: "#sidebar-toggle" +assert-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +assert-css: (".sidebar > *:not(#sidebar-toggle)", {"visibility": "hidden", "opacity": 0}) +// Let's expand the sidebar now. +click: "#sidebar-toggle" +// Because of the transition CSS, we check by using `wait-for-css` instead of `assert-css`. +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) + +// We now check that opening the sidebar and clicking a link will leave it open. +// The behavior here on desktop is different than the behavior on mobile, +// but since the sidebar doesn't fill the entire screen here, it makes sense to have the +// sidebar stay resident. +wait-for-css: (".sidebar", {"width": "300px"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} +click: ".sidebar a.selected" +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +wait-for-css: (".sidebar", {"width": "300px"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} + +// Now we check the display of the sidebar items. +show-text: true + +// First we start with the light theme. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +assert-css: ( + "#source-sidebar details[open] > .files a.selected", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"}, +) +// Without hover or focus. +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"}) +// With focus. +focus: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"}) +focus: ".search-input" +// With hover. +move-cursor-to: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"}) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .files a:not(.selected)" +wait-for-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)" +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .folders > details > summary" +wait-for-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .folders > details > summary" +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) + +// Now with the dark theme. +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +assert-css: ( + "#source-sidebar details[open] > .files > a.selected", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(51, 51, 51)"}, +) +// Without hover or focus. +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"}) +// With focus. +focus: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"}) +focus: ".search-input" +// With hover. +move-cursor-to: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"}) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .files > a:not(.selected)", + {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .files a:not(.selected)" +wait-for-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)" +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .folders > details > summary" +wait-for-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .folders > details > summary" +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) + +// And finally with the ayu theme. +local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"} +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +assert-css: ( + "#source-sidebar details[open] > .files a.selected", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +// Without hover or focus. +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"}) +// With focus. +focus: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"}) +focus: ".search-input" +// With hover. +move-cursor-to: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"}) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .files a:not(.selected)" +wait-for-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)" +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .folders > details > summary" +wait-for-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .folders > details > summary" +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) + +// Now checking on mobile devices. +size: (500, 700) +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) + +// We now check it takes the full size of the display. +assert-property: ("body", {"clientWidth": "500", "clientHeight": "700"}) +assert-property: (".sidebar", {"clientWidth": "500", "clientHeight": "700"}) + +// We now check the display of the toggle once the sidebar is expanded. +assert-property: ("#sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"}) +assert-css: ( + "#sidebar-toggle", + { + "border-top-width": "0px", + "border-right-width": "0px", + "border-left-width": "0px", + "border-bottom-width": "1px", + }, +) + +// We now check that the scroll position is kept when opening the sidebar. +click: "#sidebar-toggle" +wait-for-css: (".sidebar", {"width": "0px"}) +// We scroll to line 117 to change the scroll position. +scroll-to: '//*[@id="117"]' +assert-window-property: {"pageYOffset": "2519"} +// Expanding the sidebar... +click: "#sidebar-toggle" +wait-for-css: (".sidebar", {"width": "500px"}) +click: "#sidebar-toggle" +wait-for-css: (".sidebar", {"width": "0px"}) +// The "scrollTop" property should be the same. +assert-window-property: {"pageYOffset": "2519"} + +// We now check that opening the sidebar and clicking a link will close it. +// The behavior here on mobile is different than the behavior on desktop, +// but common sense dictates that if you have a list of files that fills the entire screen, and +// you click one of them, you probably want to actually see the file's contents, and not just +// make it the current selection. +click: "#sidebar-toggle" +wait-for-css: ("#source-sidebar", {"visibility": "visible"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} +click: ".sidebar a.selected" +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "false"} +// Resize back to desktop size, to check that the sidebar doesn't spontaneously open. +size: (1000, 1000) +wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "false"} +click: "#sidebar-toggle" +wait-for-css: ("#source-sidebar", {"visibility": "visible"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} diff --git a/src/test/rustdoc-gui/sidebar-source-code.goml b/src/test/rustdoc-gui/sidebar-source-code.goml new file mode 100644 index 000000000..e882080c7 --- /dev/null +++ b/src/test/rustdoc-gui/sidebar-source-code.goml @@ -0,0 +1,45 @@ +// The goal of this test is to ensure that the sidebar is working as expected in the source +// code pages. +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +// First: desktop mode. +size: (1100, 800) +// We check that the sidebar isn't expanded and has the expected width. +assert-css: ("nav.sidebar", {"width": "50px"}) +// We now click on the button to expand the sidebar. +click: (10, 10) +// We wait for the sidebar to be expanded. +wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "300px"}) +assert-css: (".source-sidebar-expanded nav.sidebar a", {"font-size": "14px"}) +// We collapse the sidebar. +click: (10, 10) +// We ensure that the class has been removed. +wait-for: "html:not(.expanded)" +assert: "nav.sidebar" + +// Checking that only the path to the current file is "open". +goto: file://|DOC_PATH|/src/lib2/another_folder/sub_mod/mod.rs.html +// First we expand the sidebar again. +click: (10, 10) +// We wait for the sidebar to be expanded. +wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "300px"}) +assert: "//*[@class='dir-entry' and @open]/*[text()='lib2']" +assert: "//*[@class='dir-entry' and @open]/*[text()='another_folder']" +assert: "//*[@class='dir-entry' and @open]/*[text()='sub_mod']" +// Only "another_folder" should be "open" in "lib2". +assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']" +// All other trees should be collapsed. +assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 5) + +// We now switch to mobile mode. +size: (600, 600) +wait-for-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"}) +// We collapse the sidebar. +click: (10, 10) +// We check that the sidebar has the expected width (0). +assert-css: ("nav.sidebar", {"width": "0px"}) +// We ensure that the class has been removed. +assert-false: ".source-sidebar-expanded" +assert: "nav.sidebar" + +// Check that the topbar is not visible +assert-property: (".mobile-topbar", {"offsetParent": "null"}) diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml new file mode 100644 index 000000000..32fe3334f --- /dev/null +++ b/src/test/rustdoc-gui/sidebar.goml @@ -0,0 +1,88 @@ +// Checks multiple things on the sidebar display (width of its elements, colors, etc). +goto: file://|DOC_PATH|/test_docs/index.html +show-text: true +local-storage: {"rustdoc-theme": "light"} +// We reload the page so the local storage settings are being used. +reload: + +assert-text: (".sidebar > .location", "Crate test_docs") +// In modules, we only have one "location" element. +assert-count: (".sidebar .location", 1) +assert-text: ("#all-types", "All Items") +assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"}) +// We check that we have the crates list and that the "current" on is "test_docs". +assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs") +// And we're also supposed to have the list of items in the current module. +assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Re-exports") +assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Modules") +assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Macros") +assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Structs") +assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Enums") +assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Traits") +assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Functions") +assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Type Definitions") +assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Unions") +assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Keywords") +assert-text: ("#structs + .item-table .item-left > a", "Foo") +click: "#structs + .item-table .item-left > a" + +// PAGE: struct.Foo.html +assert-count: (".sidebar .location", 2) +// We check that there is no crate listed outside of the top level. +assert-false: ".sidebar-elems > .crate" + +click: ".sidebar-elems section .block li > a" +assert-property-false: ("html", {"scrollTop": "0"}) + +click: ".sidebar h2.location a" +assert-property: ("html", {"scrollTop": "0"}) + +// We now go back to the crate page to click on the "lib2" crate link. +goto: file://|DOC_PATH|/test_docs/index.html +assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(53, 109, 164)"}) +click: ".sidebar-elems .crate > ul > li:first-child > a" + +// PAGE: lib2/index.html +goto: file://|DOC_PATH|/lib2/index.html +assert-text: (".sidebar > .location", "Crate lib2") +// We check that we have the crates list and that the "current" on is now "lib2". +assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2") +// We now go to the "foobar" function page. +assert-text: (".sidebar-elems > section .block ul > li:nth-child(1)", "Modules") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(2)", "Structs") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(3)", "Traits") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(4)", "Functions") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(5)", "Type Definitions") +assert-text: ("#functions + .item-table .item-left > a", "foobar") +click: "#functions + .item-table .item-left > a" + +// PAGE: fn.foobar.html +// In items containing no items (like functions or constants) and in modules, we have one +// "location" elements. +assert-count: (".sidebar .location", 1) +assert-text: (".sidebar .sidebar-elems .location", "In lib2") +// We check that we don't have the crate list. +assert-false: ".sidebar-elems > .crate" + +goto: ./module/index.html +assert-text: (".sidebar > .location", "Module module") +// We check that we don't have the crate list. +assert-false: ".sidebar-elems > .crate" + +goto: ./sub_module/sub_sub_module/index.html +assert-text: (".sidebar > .location", "Module sub_sub_module") +// We check that we don't have the crate list. +assert-false: ".sidebar-elems .crate" +assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions") +assert-text: ("#functions + .item-table .item-left > a", "foo") + +// Links to trait implementations in the sidebar should not wrap even if they are long. +goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html +assert-property: (".sidebar-elems section .block li > a", {"offsetHeight": 29}) + +// Test that clicking on of the "In <module>" headings in the sidebar links to the +// appropriate anchor in index.html. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +click: ".block.mod h3 a" +// PAGE: index.html +assert-css: ("#modules", {"background-color": "rgb(253, 255, 211)"}) diff --git a/src/test/rustdoc-gui/source-anchor-scroll.goml b/src/test/rustdoc-gui/source-anchor-scroll.goml new file mode 100644 index 000000000..4e51c8dca --- /dev/null +++ b/src/test/rustdoc-gui/source-anchor-scroll.goml @@ -0,0 +1,20 @@ +// We check that when the anchor changes and is output of the displayed content, +// the page is scrolled to it. +goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html + +// We reduce the window size to make it easier to make an element "out of the page". +size: (600, 800) +// We check that the scroll is at the top first. +assert-property: ("html", {"scrollTop": "0"}) + +click: '//a[text() = "barbar"]' +assert-property: ("html", {"scrollTop": "125"}) +click: '//a[text() = "bar"]' +assert-property: ("html", {"scrollTop": "166"}) +click: '//a[text() = "sub_fn"]' +assert-property: ("html", {"scrollTop": "53"}) + +// We now check that clicking on lines doesn't change the scroll +// Extra information: the "sub_fn" function header is on line 1. +click: '//*[@id="6"]' +assert-property: ("html", {"scrollTop": "53"}) diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml new file mode 100644 index 000000000..581f826a3 --- /dev/null +++ b/src/test/rustdoc-gui/source-code-page.goml @@ -0,0 +1,49 @@ +// Checks that the interactions with the source code pages are working as expected. +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +// Check that we can click on the line number. +click: ".line-numbers > span:nth-child(4)" // This is the span for line 4. +// Ensure that the page URL was updated. +assert-document-property: ({"URL": "lib.rs.html#4"}, ENDS_WITH) +assert-attribute: ("//*[@id='4']", {"class": "line-highlighted"}) +// We now check that the good spans are highlighted +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html#4-6 +assert-attribute-false: (".line-numbers > span:nth-child(3)", {"class": "line-highlighted"}) +assert-attribute: (".line-numbers > span:nth-child(4)", {"class": "line-highlighted"}) +assert-attribute: (".line-numbers > span:nth-child(5)", {"class": "line-highlighted"}) +assert-attribute: (".line-numbers > span:nth-child(6)", {"class": "line-highlighted"}) +assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"}) +// This is to ensure that the content is correctly align with the line numbers. +compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y")) + +// Assert that the line numbers text is aligned to the right. +assert-css: (".line-numbers", {"text-align": "right"}) + +// Now let's check that clicking on something else than the line number doesn't +// do anything (and certainly not add a `#NaN` to the URL!). +show-text: true +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +// We use this assert-position to know where we will click. +assert-position: ("//*[@id='1']", {"x": 104, "y": 103}) +// We click on the left of the "1" span but still in the "line-number" `<pre>`. +click: (103, 103) +assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH) + +// Checking the source code sidebar. + +// First we "open" it. +click: "#sidebar-toggle" +assert: ".source-sidebar-expanded" + +// We check that the first entry of the sidebar is collapsed +assert-property: ("#source-sidebar details:first-of-type", {"open": "false"}) +assert-text: ("#source-sidebar details:first-of-type > summary", "implementors") +// We now click on it. +click: "#source-sidebar details:first-of-type > summary" +assert-property: ("#source-sidebar details:first-of-type", {"open": "true"}) + +// And now we collapse it again. +click: "#source-sidebar details:first-of-type > summary" +assert-property: ("#source-sidebar details:first-of-type", {"open": "false"}) + +// Check the spacing. +assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"}) diff --git a/src/test/rustdoc-gui/src-font-size.goml b/src/test/rustdoc-gui/src-font-size.goml new file mode 100644 index 000000000..0c01e2545 --- /dev/null +++ b/src/test/rustdoc-gui/src-font-size.goml @@ -0,0 +1,11 @@ +// This test ensures that the "[src]" have the same font size as their headers +// to avoid having some weird height difference in the background when the element +// is selected. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +show-text: true +// Check the impl headers. +assert-css: (".impl.has-srclink .srclink", {"font-size": "16px"}, ALL) +assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "18px"}, ALL) +// Check the impl items. +assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL) +assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL) diff --git a/src/test/rustdoc-gui/src/lib2/Cargo.lock b/src/test/rustdoc-gui/src/lib2/Cargo.lock new file mode 100644 index 000000000..a5873ceb3 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "implementors" +version = "0.1.0" + +[[package]] +name = "lib2" +version = "0.1.0" +dependencies = [ + "implementors", +] diff --git a/src/test/rustdoc-gui/src/lib2/Cargo.toml b/src/test/rustdoc-gui/src/lib2/Cargo.toml new file mode 100644 index 000000000..2e37f3f66 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "lib2" +version = "0.1.0" +edition = "2018" + +[lib] +path = "lib.rs" + +[dependencies] +implementors = { path = "./implementors" } diff --git a/src/test/rustdoc-gui/src/lib2/another_folder/mod.rs b/src/test/rustdoc-gui/src/lib2/another_folder/mod.rs new file mode 100644 index 000000000..ec9a20859 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/another_folder/mod.rs @@ -0,0 +1,3 @@ +pub fn another_fn() {} + +pub mod sub_mod; diff --git a/src/test/rustdoc-gui/src/lib2/another_folder/sub_mod/mod.rs b/src/test/rustdoc-gui/src/lib2/another_folder/sub_mod/mod.rs new file mode 100644 index 000000000..f16722cf3 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/another_folder/sub_mod/mod.rs @@ -0,0 +1 @@ +pub fn subsubsub() {} diff --git a/src/test/rustdoc-gui/src/lib2/another_mod/mod.rs b/src/test/rustdoc-gui/src/lib2/another_mod/mod.rs new file mode 100644 index 000000000..9a4f007a2 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/another_mod/mod.rs @@ -0,0 +1 @@ +pub fn tadam() {} diff --git a/src/test/rustdoc-gui/src/lib2/implementors/Cargo.lock b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.lock new file mode 100644 index 000000000..cad99a991 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "implementors" +version = "0.1.0" diff --git a/src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml new file mode 100644 index 000000000..7ef1052c4 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/implementors/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "implementors" +version = "0.1.0" +edition = "2018" + +[lib] +path = "lib.rs" diff --git a/src/test/rustdoc-gui/src/lib2/implementors/lib.rs b/src/test/rustdoc-gui/src/lib2/implementors/lib.rs new file mode 100644 index 000000000..1620e8422 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/implementors/lib.rs @@ -0,0 +1,20 @@ +pub trait Whatever { + type Foo; + + fn method() {} +} + +pub struct Struct; + +impl Whatever for Struct { + type Foo = u8; +} + +mod traits { + pub trait TraitToReexport { + fn method() {} + } +} + +#[doc(inline)] +pub use traits::TraitToReexport; diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs new file mode 100644 index 000000000..87f91be3a --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -0,0 +1,145 @@ +// ignore-tidy-linelength + +#![feature(doc_cfg)] + +pub mod another_folder; +pub mod another_mod; + +pub mod module { + pub mod sub_module { + pub mod sub_sub_module { + pub fn foo() {} + } + pub fn bar() {} + } + pub fn whatever() {} +} + +pub fn foobar() {} + +pub type Alias = u32; + +#[doc(cfg(feature = "foo-method"))] +pub struct Foo { + pub x: Alias, +} + +impl Foo { + /// Some documentation + /// # A Heading + pub fn a_method(&self) {} +} + +#[doc(cfg(feature = "foo-method"))] +#[deprecated = "Whatever [`Foo::a_method`](#method.a_method)"] +pub trait Trait { + type X; + const Y: u32; + + #[deprecated = "Whatever [`Foo`](#tadam)"] + fn foo() {} +} + +impl Trait for Foo { + type X = u32; + const Y: u32 = 0; +} + +impl implementors::Whatever for Foo { + type Foo = u32; +} + +#[doc(inline)] +pub use implementors::TraitToReexport; + +pub struct StructToImplOnReexport; + +impl TraitToReexport for StructToImplOnReexport {} + +pub mod sub_mod { + /// ```txt + /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// ``` + /// + /// ``` + /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + /// ``` + pub struct Foo; +} + +pub mod long_trait { + use std::ops::DerefMut; + + pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem: + DerefMut<Target = u32> + From<u128> + Send + Sync + AsRef<str> + 'static + { + } +} + +pub mod long_table { + /// | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | + /// | ----------- | ----------- | ----------- | ----------- | + /// | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | + /// + /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq + pub struct Foo; + + /// | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | + /// | ----------- | ----------- | ----------- | ----------- | + /// | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | + /// + /// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq + impl Foo { + pub fn foo(&self) {} + } +} + +pub mod summary_table { + /// | header 1 | header 2 | + /// | -------- | -------- | + /// | content | content | + pub struct Foo; +} + +pub mod too_long { + pub type ReallyLongTypeNameLongLongLong = + Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>; + + pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0; + + /// This also has a really long doccomment. Lorem ipsum dolor sit amet, + /// consectetur adipiscing elit. Suspendisse id nibh malesuada, hendrerit + /// massa vel, tincidunt est. Nulla interdum, sem ac efficitur ornare, arcu + /// nunc dignissim nibh, at rutrum diam augue ac mauris. Fusce tincidunt et + /// ligula sed viverra. Aenean sed facilisis dui, non volutpat felis. In + /// vitae est dui. Donec felis nibh, blandit at nibh eu, tempor suscipit + /// nisl. Vestibulum ornare porta libero, eu faucibus purus iaculis ut. Ut + /// quis tincidunt nunc, in mollis purus. Nulla sed interdum quam. Nunc + /// vitae cursus ex. + pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { + pub a: u32, + } + + impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { + /// ``` + /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 }; + /// ``` + pub fn foo(&self) {} + } +} + +pub struct HasALongTraitWithParams {} + +pub trait LongTraitWithParamsBananaBananaBanana<T> {} + +impl LongTraitWithParamsBananaBananaBanana<usize> for HasALongTraitWithParams {} + +#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] +pub struct LongItemInfo; + +pub trait SimpleTrait {} +pub struct LongItemInfo2; + +/// Some docs. +#[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] +impl SimpleTrait for LongItemInfo2 {} diff --git a/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock b/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock new file mode 100644 index 000000000..e4b4e52d0 --- /dev/null +++ b/src/test/rustdoc-gui/src/link_to_definition/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "link_to_definition" +version = "0.1.0" diff --git a/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml b/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml new file mode 100644 index 000000000..cdd294d74 --- /dev/null +++ b/src/test/rustdoc-gui/src/link_to_definition/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "link_to_definition" +version = "0.1.0" +edition = "2018" + +[lib] +path = "lib.rs" diff --git a/src/test/rustdoc-gui/src/link_to_definition/lib.rs b/src/test/rustdoc-gui/src/link_to_definition/lib.rs new file mode 100644 index 000000000..419a9ccee --- /dev/null +++ b/src/test/rustdoc-gui/src/link_to_definition/lib.rs @@ -0,0 +1,35 @@ +pub fn sub_fn() { + barbar(); +} +fn barbar() { + bar(vec![], vec![], vec![], vec![], Bar { a: "a".into(), b: 0 }); +} + +pub struct Bar { + pub a: String, + pub b: u32, +} + +pub fn foo(_b: &Bar) {} + +// The goal now is to add +// a lot of lines so +// that the next content +// will be out of the screen +// to allow us to test that +// if the anchor changes to +// something outside of the +// current view, it'll +// scroll to it as expected. + +// More filling content. + +pub fn bar( + _a: Vec<String>, + _b: Vec<String>, + _c: Vec<String>, + _d: Vec<String>, + _e: Bar, +) { + sub_fn(); +} diff --git a/src/test/rustdoc-gui/src/settings/.cargo/config.toml b/src/test/rustdoc-gui/src/settings/.cargo/config.toml new file mode 100644 index 000000000..bbb8d11a2 --- /dev/null +++ b/src/test/rustdoc-gui/src/settings/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustdocflags = ["--default-theme", "ayu"] diff --git a/src/test/rustdoc-gui/src/settings/Cargo.lock b/src/test/rustdoc-gui/src/settings/Cargo.lock new file mode 100644 index 000000000..6f0de1ac1 --- /dev/null +++ b/src/test/rustdoc-gui/src/settings/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "settings" +version = "0.1.0" diff --git a/src/test/rustdoc-gui/src/settings/Cargo.toml b/src/test/rustdoc-gui/src/settings/Cargo.toml new file mode 100644 index 000000000..c8a211a47 --- /dev/null +++ b/src/test/rustdoc-gui/src/settings/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "settings" +version = "0.1.0" +edition = "2018" + +[lib] +path = "lib.rs" diff --git a/src/test/rustdoc-gui/src/settings/lib.rs b/src/test/rustdoc-gui/src/settings/lib.rs new file mode 100644 index 000000000..b76b4321d --- /dev/null +++ b/src/test/rustdoc-gui/src/settings/lib.rs @@ -0,0 +1 @@ +pub fn foo() {} diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.lock b/src/test/rustdoc-gui/src/staged_api/Cargo.lock new file mode 100644 index 000000000..6e8eba56c --- /dev/null +++ b/src/test/rustdoc-gui/src/staged_api/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "staged_api" +version = "0.1.0" diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.toml b/src/test/rustdoc-gui/src/staged_api/Cargo.toml new file mode 100644 index 000000000..117c4134e --- /dev/null +++ b/src/test/rustdoc-gui/src/staged_api/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "staged_api" +version = "0.1.0" +edition = "2021" + +[lib] +path = "lib.rs" + +[features] +default = ["some_feature"] +some_feature = [] diff --git a/src/test/rustdoc-gui/src/staged_api/lib.rs b/src/test/rustdoc-gui/src/staged_api/lib.rs new file mode 100644 index 000000000..0cb460f03 --- /dev/null +++ b/src/test/rustdoc-gui/src/staged_api/lib.rs @@ -0,0 +1,10 @@ +#![feature(staged_api)] +#![stable(feature = "some_feature", since = "1.3.5")] + +#[stable(feature = "some_feature", since = "1.3.5")] +pub struct Foo {} + +impl Foo { + #[stable(feature = "some_feature", since = "1.3.5")] + pub fn bar() {} +} diff --git a/src/test/rustdoc-gui/src/test_docs/Cargo.lock b/src/test/rustdoc-gui/src/test_docs/Cargo.lock new file mode 100644 index 000000000..6b80f6e88 --- /dev/null +++ b/src/test/rustdoc-gui/src/test_docs/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "test_docs" +version = "0.1.0" diff --git a/src/test/rustdoc-gui/src/test_docs/Cargo.toml b/src/test/rustdoc-gui/src/test_docs/Cargo.toml new file mode 100644 index 000000000..8be819b76 --- /dev/null +++ b/src/test/rustdoc-gui/src/test_docs/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "test_docs" +version = "0.1.0" +edition = "2018" + +build = "build.rs" + +[lib] +path = "lib.rs" + +[features] +default = ["some-feature"] +some-feature = [] diff --git a/src/test/rustdoc-gui/src/test_docs/build.rs b/src/test/rustdoc-gui/src/test_docs/build.rs new file mode 100644 index 000000000..16c96ded9 --- /dev/null +++ b/src/test/rustdoc-gui/src/test_docs/build.rs @@ -0,0 +1,15 @@ +//! generate 2000 constants for testing + +use std::{fs::write, path::PathBuf}; + +fn main() -> std::io::Result<()> { + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is not defined"); + + let mut output = String::new(); + for i in 0..2000 { + let line = format!("/// Some const A{0}\npub const A{0}: isize = 0;\n", i); + output.push_str(&*line); + }; + + write(&[&*out_dir, "huge_amount_of_consts.rs"].iter().collect::<PathBuf>(), output) +} diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs new file mode 100644 index 000000000..1b26aaecb --- /dev/null +++ b/src/test/rustdoc-gui/src/test_docs/lib.rs @@ -0,0 +1,295 @@ +//! The point of this crate is to be able to have enough different "kinds" of +//! documentation generated so we can test each different features. +#![doc(html_playground_url="https://play.rust-lang.org/")] + +#![crate_name = "test_docs"] +#![feature(rustdoc_internals)] +#![feature(doc_cfg)] + +use std::convert::AsRef; +use std::fmt; + +/// Basic function with some code examples: +/// +/// ``` +/// println!("nothing fancy"); +/// println!("but with two lines!"); +/// ``` +/// +/// A failing to compile one: +/// +/// ```compile_fail +/// println!("where did my argument {} go? :'("); +/// ``` +/// +/// An ignored one: +/// +/// ```ignore (it's a test) +/// Let's say I'm just some text will ya? +/// ``` +/// +/// An inlined `code`! +pub fn foo() {} + +/// Just a normal struct. +pub struct Foo; + +impl Foo { + #[must_use] + pub fn must_use(&self) -> bool { + true + } +} + +impl AsRef<str> for Foo { + fn as_ref(&self) -> &str { + "hello" + } +} + +/// Just a normal enum. +/// +/// # title! +#[doc(alias = "ThisIsAnAlias")] +pub enum WhoLetTheDogOut { + /// Woof! + Woof, + /// Meoooooooow... + Meow, +} + +/// Who doesn't love to wrap a `format!` call? +pub fn some_more_function<T: fmt::Debug>(t: &T) -> String { + format!("{:?}", t) +} + +/// Woohoo! A trait! +pub trait AnotherOne { + /// Some func 3. + fn func3(); + + /// Some func 1. + fn func1(); + + fn another(); + fn why_not(); + + /// Some func 2. + fn func2(); + + fn hello(); +} + +/// ```compile_fail +/// whatever +/// ``` +/// +/// Check for "i" signs in lists! +/// +/// 1. elem 1 +/// 2. test 1 +/// ```compile_fail +/// fn foo() {} +/// ``` +/// 3. elem 3 +/// 4. ```ignore (it's a test) +/// fn foo() {} +/// ``` +/// 5. elem 5 +/// +/// Final one: +/// +/// ```ignore (still a test) +/// let x = 12; +/// ``` +pub fn check_list_code_block() {} + +/// a thing with a label +#[deprecated(since = "1.0.0", note = "text why this deprecated")] +#[doc(cfg(unix))] +pub fn replaced_function() {} + +/// Some doc with `code`! +pub enum AnEnum { + WithVariants { and: usize, sub: usize, variants: usize }, +} + +#[doc(keyword = "CookieMonster")] +/// Some keyword. +pub mod keyword {} + +/// Just some type alias. +pub type SomeType = u32; + +pub mod huge_amount_of_consts { + include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs")); +} + +/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`. +pub mod long_code_block {} + +#[macro_export] +macro_rules! repro { + () => {}; +} + +pub use crate::repro as repro2; + +/// # Top-doc Prose title +/// +/// Text below title. +/// +/// ## Top-doc Prose sub-heading +/// +/// Text below sub-heading. +/// +/// ### Top-doc Prose sub-sub-heading +/// +/// Text below sub-sub-heading +/// +/// #### You know the drill. +/// +/// More text. +pub struct HeavilyDocumentedStruct { + /// # Title for field + /// ## Sub-heading for field + pub nothing: (), +} + +/// # Title for struct impl doc +/// +/// Text below heading. +/// +/// ## Sub-heading for struct impl doc +/// +/// Text below sub-heading. +/// +/// ### Sub-sub-heading for struct impl doc +/// +/// Text below sub-sub-heading. +/// +impl HeavilyDocumentedStruct { + /// # Title for struct impl-item doc + /// Text below title. + /// ## Sub-heading for struct impl-item doc + /// Text below sub-heading. + /// ### Sub-sub-heading for struct impl-item doc + /// Text below sub-sub-heading. + pub fn do_nothing() {} +} + +/// # Top-doc Prose title +/// +/// Text below title. +/// +/// ## Top-doc Prose sub-heading +/// +/// Text below sub-heading. +/// +/// ### Top-doc Prose sub-sub-heading +/// +/// Text below sub-sub-heading +pub enum HeavilyDocumentedEnum { + /// # None prose title + /// ## None prose sub-heading + None, + /// # Wrapped prose title + /// ## Wrapped prose sub-heading + Wrapped( + /// # Wrapped.0 prose title + /// ## Wrapped.0 prose sub-heading + String, + String, + ), + Structy { + /// # Structy prose title + /// ## Structy prose sub-heading + alpha: String, + beta: String, + }, +} + +/// # Title for enum impl doc +/// +/// Text below heading. +/// +/// ## Sub-heading for enum impl doc +/// +/// Text below sub-heading. +/// +/// ### Sub-sub-heading for enum impl doc +/// +/// Text below sub-sub-heading. +/// +impl HeavilyDocumentedEnum { + /// # Title for enum impl-item doc + /// Text below title. + /// ## Sub-heading for enum impl-item doc + /// Text below sub-heading. + /// ### Sub-sub-heading for enum impl-item doc + /// Text below sub-sub-heading. + pub fn do_nothing() {} +} + +/// # Top-doc prose title +/// +/// Text below heading. +/// +/// ## Top-doc prose sub-heading +/// +/// Text below heading. +pub union HeavilyDocumentedUnion { + /// # Title for union variant + /// ## Sub-heading for union variant + pub nothing: (), + pub something: f32, +} + +/// # Title for union impl doc +/// ## Sub-heading for union impl doc +impl HeavilyDocumentedUnion { + /// # Title for union impl-item doc + /// ## Sub-heading for union impl-item doc + pub fn do_nothing() {} +} + +/// # Top-doc prose title +/// +/// Text below heading. +/// +/// ## Top-doc prose sub-heading +/// +/// Text below heading. +#[macro_export] +macro_rules! heavily_documented_macro { + () => {}; +} + +pub trait EmptyTrait1 {} +pub trait EmptyTrait2 {} +pub trait EmptyTrait3 {} + +pub struct HasEmptyTraits{} + +impl EmptyTrait1 for HasEmptyTraits {} +impl EmptyTrait2 for HasEmptyTraits {} +#[doc(cfg(feature = "some-feature"))] +impl EmptyTrait3 for HasEmptyTraits {} + +mod macros; +pub use macros::*; + +#[doc(alias = "AliasForTheStdReexport")] +pub use ::std as TheStdReexport; + +pub mod details { + /// We check the appearance of the `<details>`/`<summary>` in here. + /// + /// ## Hello + /// + /// <details> + /// <summary><h4>I'm a summary</h4></summary> + /// <div>I'm the content of the details!</div> + /// </details> + pub struct Details; +} diff --git a/src/test/rustdoc-gui/src/test_docs/macros.rs b/src/test/rustdoc-gui/src/test_docs/macros.rs new file mode 100644 index 000000000..07b2b9792 --- /dev/null +++ b/src/test/rustdoc-gui/src/test_docs/macros.rs @@ -0,0 +1,4 @@ +#[macro_export] +macro_rules! a{ () => {}} +#[macro_export] +macro_rules! b{ () => {}} diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml new file mode 100644 index 000000000..fb1c37ae6 --- /dev/null +++ b/src/test/rustdoc-gui/theme-change.goml @@ -0,0 +1,32 @@ +// Ensures that the theme change is working as expected. +goto: file://|DOC_PATH|/test_docs/index.html +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} +reload: +click: "#settings-menu" +wait-for: "#theme-ayu" +click: "#theme-ayu" +// should be the ayu theme so let's check the color. +wait-for-css: ("body", { "background-color": "rgb(15, 20, 25)" }) +assert-local-storage: { "rustdoc-theme": "ayu" } +click: "#theme-light" +// should be the light theme so let's check the color. +wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } +click: "#theme-dark" +// Should be the dark theme so let's check the color. +wait-for-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } + +goto: file://|DOC_PATH|/settings.html +wait-for: "#settings" +click: "#theme-light" +wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } + +click: "#theme-dark" +wait-for-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } + +click: "#theme-ayu" +wait-for-css: ("body", { "background-color": "rgb(15, 20, 25)" }) +assert-local-storage: { "rustdoc-theme": "ayu" } diff --git a/src/test/rustdoc-gui/theme-in-history.goml b/src/test/rustdoc-gui/theme-in-history.goml new file mode 100644 index 000000000..f576ced1c --- /dev/null +++ b/src/test/rustdoc-gui/theme-in-history.goml @@ -0,0 +1,28 @@ +// Ensures that the theme is working when going back in history. +goto: file://|DOC_PATH|/test_docs/index.html +// Set the theme to dark. +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-preferred-dark-theme": "dark", + "rustdoc-use-system-theme": "false", +} +// We reload the page so the local storage settings are being used. +reload: +assert-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } + +// Now we go to the settings page. +goto: file://|DOC_PATH|/settings.html +wait-for: "#settings" +// We change the theme to "light". +click: "#theme-light" +wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } + +// We go back in history. +history-go-back: +// Confirm that we're not on the settings page. +assert-false: "#settings" +// Check that the current theme is still "light". +assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } diff --git a/src/test/rustdoc-gui/toggle-click-deadspace.goml b/src/test/rustdoc-gui/toggle-click-deadspace.goml new file mode 100644 index 000000000..4a328c9f9 --- /dev/null +++ b/src/test/rustdoc-gui/toggle-click-deadspace.goml @@ -0,0 +1,12 @@ +// This test ensures that clicking on a method summary, but not on the "[-]", +// doesn't toggle the <details>. +goto: file://|DOC_PATH|/lib2/struct.Foo.html +assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""}) +click: "h4.code-header" // This is the position of "pub" in "pub fn a_method" +assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""}) +click: ".impl-items .rustdoc-toggle summary::before" // This is the position of "[-]" next to that pub fn. +assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""}) + +// Click the "Trait" part of "impl Trait" and verify it navigates. +click: "#impl-Trait-for-Foo h3 a:first-of-type" +assert-text: (".fqn .in-band", "Trait lib2::Trait") diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml new file mode 100644 index 000000000..ee6bc3cf7 --- /dev/null +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -0,0 +1,33 @@ +// Checks that the documentation toggles on mobile have the correct position, style and work +// as expected. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +size: (433, 600) +assert-attribute: (".top-doc", {"open": ""}) +click: (4, 270) // This is the position of the top doc comment toggle +assert-attribute-false: (".top-doc", {"open": ""}) +click: (4, 270) +assert-attribute: (".top-doc", {"open": ""}) +// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. +click: (3, 270) +assert-attribute: (".top-doc", {"open": ""}) + +// Assert the position of the toggle on the top doc block. +assert-position: (".top-doc summary::before", {"x": 4}) +// Assert the position of the toggle on the impl block. +assert-position: ("#implementations-list > details > summary::before", {"x": 4}) +// Assert the position of the toggle on a method. +assert-position: ( + "#trait-implementations-list .impl-items .method-toggle > summary::before", + {"x": 4}, +) + +// Now we do the same but with a little bigger width +size: (600, 600) +assert-attribute: (".top-doc", {"open": ""}) +click: (4, 270) // New Y position since all search elements are back on one line. +assert-attribute-false: (".top-doc", {"open": ""}) +click: (4, 270) +assert-attribute: (".top-doc", {"open": ""}) +// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. +click: (3, 270) +assert-attribute: (".top-doc", {"open": ""}) diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml new file mode 100644 index 000000000..63962b576 --- /dev/null +++ b/src/test/rustdoc-gui/toggle-docs.goml @@ -0,0 +1,42 @@ +// Checks that the documentation toggles have the correct position, style and work as expected. +goto: file://|DOC_PATH|/test_docs/index.html +assert-attribute: ("#main-content > details.top-doc", {"open": ""}) +assert-text: ("#toggle-all-docs", "[−]") +click: "#toggle-all-docs" +wait-for: 50 +// This is now collapsed so there shouldn't be the "open" attribute on details. +assert-attribute-false: ("#main-content > details.top-doc", {"open": ""}) +assert-text: ("#toggle-all-docs", "[+]") +click: "#toggle-all-docs" +// Not collapsed anymore so the "open" attribute should be back. +wait-for-attribute: ("#main-content > details.top-doc", {"open": ""}) +assert-text: ("#toggle-all-docs", "[−]") + +// Check that it works on non-module pages as well. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +// We first check that everything is visible. +assert-text: ("#toggle-all-docs", "[−]") +assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL) +assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL) +assert-attribute-false: ( + "#blanket-implementations-list > details.rustdoc-toggle", + {"open": ""}, + ALL, +) + +// We collapse them all. +click: "#toggle-all-docs" +wait-for-text: ("#toggle-all-docs", "[+]") +// We check that all <details> are collapsed (except for the impl block ones). +assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL) +assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""}) +// We now check that the other impl blocks are collapsed. +assert-attribute-false: ( + "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle", + {"open": ""}, + ALL, +) +// We open them all again. +click: "#toggle-all-docs" +wait-for-text: ("#toggle-all-docs", "[−]") +assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL) diff --git a/src/test/rustdoc-gui/toggle-implementors.goml b/src/test/rustdoc-gui/toggle-implementors.goml new file mode 100644 index 000000000..15521ff0f --- /dev/null +++ b/src/test/rustdoc-gui/toggle-implementors.goml @@ -0,0 +1,4 @@ +// This test ensures that the implementors toggle are not open by default. +goto: file://|DOC_PATH|/implementors/trait.Whatever.html + +assert-attribute-false: ("#implementors-list > details", {"open": ""}, ALL) diff --git a/src/test/rustdoc-gui/toggled-open-implementations.goml b/src/test/rustdoc-gui/toggled-open-implementations.goml new file mode 100644 index 000000000..bc97b38c8 --- /dev/null +++ b/src/test/rustdoc-gui/toggled-open-implementations.goml @@ -0,0 +1,5 @@ +// This tests that the "implementations" section on struct/enum pages +// has all the implementations toggled open by default, so users can +// find method names in those implementations with Ctrl-F. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +assert-attribute: (".rustdoc-toggle.implementors-toggle", {"open": ""}) diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml new file mode 100644 index 000000000..d77d1dca4 --- /dev/null +++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml @@ -0,0 +1,8 @@ +// Checks that the elements in the sidebar are alphabetically sorted. +goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html +assert-text: (".sidebar-elems section .block li:nth-of-type(1) > a", "another") +assert-text: (".sidebar-elems section .block li:nth-of-type(2) > a", "func1") +assert-text: (".sidebar-elems section .block li:nth-of-type(3) > a", "func2") +assert-text: (".sidebar-elems section .block li:nth-of-type(4) > a", "func3") +assert-text: (".sidebar-elems section .block li:nth-of-type(5) > a", "hello") +assert-text: (".sidebar-elems section .block li:nth-of-type(6) > a", "why_not") diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml new file mode 100644 index 000000000..22212a317 --- /dev/null +++ b/src/test/rustdoc-gui/type-declation-overflow.goml @@ -0,0 +1,37 @@ +// This test ensures that the items declaration content overflow is handled inside the <pre> directly. +goto: file://|DOC_PATH|/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html +// We set a fixed size so there is no chance of "random" resize. +size: (1100, 800) +// Logically, the <body> scroll width should be the width of the window. +assert-property: ("body", {"scrollWidth": "1100"}) +// However, since there is overflow in the type declaration, its scroll width is bigger. +assert-property: (".item-decl pre", {"scrollWidth": "1324"}) + +// In the table-ish view on the module index, the name should not be wrapped more than necessary. +goto: file://|DOC_PATH|/lib2/too_long/index.html +assert-property: (".item-table .struct", {"offsetWidth": "684"}) + +// We now make the same check on type declaration... +goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html +assert-property: ("body", {"scrollWidth": "1100"}) +// We now check that the section width hasn't grown because of it. +assert-property: ("#main-content", {"scrollWidth": "825"}) +// And now checking that it has scrollable content. +assert-property: (".item-decl pre", {"scrollWidth": "1103"}) + +// ... and constant. +// On a sidenote, it also checks that the (very) long title isn't changing the docblock width. +goto: file://|DOC_PATH|/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html +assert-property: ("body", {"scrollWidth": "1100"}) +// We now check that the section width hasn't grown because of it. +assert-property: ("#main-content", {"scrollWidth": "825"}) +// And now checking that it has scrollable content. +assert-property: (".item-decl pre", {"scrollWidth": "950"}) + +// On mobile: +size: (600, 600) +goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html +// It shouldn't have an overflow in the topbar either. +assert-property: (".mobile-topbar .location", {"scrollWidth": "492"}) +assert-property: (".mobile-topbar .location", {"clientWidth": "492"}) +assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"}) diff --git a/src/test/rustdoc-js-std/alias-1.js b/src/test/rustdoc-js-std/alias-1.js new file mode 100644 index 000000000..7c6327fcd --- /dev/null +++ b/src/test/rustdoc-js-std/alias-1.js @@ -0,0 +1,7 @@ +const QUERY = '&'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'reference' }, + ], +}; diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js new file mode 100644 index 000000000..798fa29ef --- /dev/null +++ b/src/test/rustdoc-js-std/alias-2.js @@ -0,0 +1,10 @@ +const QUERY = '+'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::ops', 'name': 'AddAssign' }, + { 'path': 'std::ops', 'name': 'Add' }, + { 'path': 'core::ops', 'name': 'AddAssign' }, + { 'path': 'core::ops', 'name': 'Add' }, + ], +}; diff --git a/src/test/rustdoc-js-std/alias-3.js b/src/test/rustdoc-js-std/alias-3.js new file mode 100644 index 000000000..392b1e818 --- /dev/null +++ b/src/test/rustdoc-js-std/alias-3.js @@ -0,0 +1,7 @@ +const QUERY = '!'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'never' }, + ], +}; diff --git a/src/test/rustdoc-js-std/alias-4.js b/src/test/rustdoc-js-std/alias-4.js new file mode 100644 index 000000000..bf2bb4d29 --- /dev/null +++ b/src/test/rustdoc-js-std/alias-4.js @@ -0,0 +1,7 @@ +const QUERY = '<'; + +const EXPECTED = { + 'others': [ + { 'name': 'Ord' }, + ], +}; diff --git a/src/test/rustdoc-js-std/alias.js b/src/test/rustdoc-js-std/alias.js new file mode 100644 index 000000000..2b709c991 --- /dev/null +++ b/src/test/rustdoc-js-std/alias.js @@ -0,0 +1,11 @@ +// ignore-order + +const QUERY = '['; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'slice' }, + { 'path': 'std::ops', 'name': 'IndexMut' }, + { 'path': 'std::ops', 'name': 'Index' }, + ], +}; diff --git a/src/test/rustdoc-js-std/asrawfd.js b/src/test/rustdoc-js-std/asrawfd.js new file mode 100644 index 000000000..fd228a590 --- /dev/null +++ b/src/test/rustdoc-js-std/asrawfd.js @@ -0,0 +1,14 @@ +// ignore-order + +const QUERY = 'RawFd::as_raw_fd'; + +const EXPECTED = { + 'others': [ + // Reproduction test for https://github.com/rust-lang/rust/issues/78724 + // Validate that type alias methods get the correct path. + { 'path': 'std::os::unix::io::AsRawFd', 'name': 'as_raw_fd' }, + { 'path': 'std::os::wasi::io::AsRawFd', 'name': 'as_raw_fd' }, + { 'path': 'std::os::linux::process::PidFd', 'name': 'as_raw_fd' }, + { 'path': 'std::os::unix::io::RawFd', 'name': 'as_raw_fd' }, + ], +}; diff --git a/src/test/rustdoc-js-std/basic.js b/src/test/rustdoc-js-std/basic.js new file mode 100644 index 000000000..824cac710 --- /dev/null +++ b/src/test/rustdoc-js-std/basic.js @@ -0,0 +1,15 @@ +const QUERY = 'String'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::string', 'name': 'String' }, + { 'path': 'std::ffi', 'name': 'CString' }, + { 'path': 'std::ffi', 'name': 'OsString' }, + ], + 'in_args': [ + { 'path': 'std::str', 'name': 'eq' }, + ], + 'returned': [ + { 'path': 'std::string::String', 'name': 'add' }, + ], +}; diff --git a/src/test/rustdoc-js-std/deduplication.js b/src/test/rustdoc-js-std/deduplication.js new file mode 100644 index 000000000..f02f6cf55 --- /dev/null +++ b/src/test/rustdoc-js-std/deduplication.js @@ -0,0 +1,11 @@ +// ignore-order + +const QUERY = 'is_nan'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::f32', 'name': 'is_nan' }, + { 'path': 'std::f64', 'name': 'is_nan' }, + { 'path': 'std::option::Option', 'name': 'is_none' }, + ], +}; diff --git a/src/test/rustdoc-js-std/enum-option.js b/src/test/rustdoc-js-std/enum-option.js new file mode 100644 index 000000000..902e09069 --- /dev/null +++ b/src/test/rustdoc-js-std/enum-option.js @@ -0,0 +1,7 @@ +const QUERY = 'enum:Option'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::option', 'name': 'Option' }, + ], +}; diff --git a/src/test/rustdoc-js-std/filter-crate.js b/src/test/rustdoc-js-std/filter-crate.js new file mode 100644 index 000000000..b47a1fefa --- /dev/null +++ b/src/test/rustdoc-js-std/filter-crate.js @@ -0,0 +1,9 @@ +// exact-check + +const QUERY = '"hashmap"'; +const FILTER_CRATE = 'core'; + +const EXPECTED = { + 'others': [ + ], +}; diff --git a/src/test/rustdoc-js-std/fn-forget.js b/src/test/rustdoc-js-std/fn-forget.js new file mode 100644 index 000000000..66a5fcaa7 --- /dev/null +++ b/src/test/rustdoc-js-std/fn-forget.js @@ -0,0 +1,8 @@ +const QUERY = 'fn:forget'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::mem', 'name': 'forget' }, + { 'path': 'std::fmt', 'name': 'format' }, + ], +}; diff --git a/src/test/rustdoc-js-std/from_u.js b/src/test/rustdoc-js-std/from_u.js new file mode 100644 index 000000000..e3f3cd436 --- /dev/null +++ b/src/test/rustdoc-js-std/from_u.js @@ -0,0 +1,9 @@ +const QUERY = 'from_u'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::char', 'name': 'from_u32' }, + { 'path': 'std::str', 'name': 'from_utf8' }, + { 'path': 'std::string::String', 'name': 'from_utf8' }, + ], +}; diff --git a/src/test/rustdoc-js-std/keyword.js b/src/test/rustdoc-js-std/keyword.js new file mode 100644 index 000000000..868ddd7b6 --- /dev/null +++ b/src/test/rustdoc-js-std/keyword.js @@ -0,0 +1,10 @@ +// ignore-order + +const QUERY = 'fn'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'fn', ty: 15 }, // 15 is for primitive types + { 'path': 'std', 'name': 'fn', ty: 21 }, // 21 is for keywords + ], +}; diff --git a/src/test/rustdoc-js-std/macro-check.js b/src/test/rustdoc-js-std/macro-check.js new file mode 100644 index 000000000..242e0cbf5 --- /dev/null +++ b/src/test/rustdoc-js-std/macro-check.js @@ -0,0 +1,10 @@ +// ignore-order + +const QUERY = 'panic'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'panic', ty: 14 }, // 15 is for macros + { 'path': 'std', 'name': 'panic', ty: 0 }, // 0 is for modules + ], +}; diff --git a/src/test/rustdoc-js-std/macro-print.js b/src/test/rustdoc-js-std/macro-print.js new file mode 100644 index 000000000..858046e72 --- /dev/null +++ b/src/test/rustdoc-js-std/macro-print.js @@ -0,0 +1,10 @@ +const QUERY = 'macro:print'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'print' }, + { 'path': 'std', 'name': 'eprint' }, + { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprintln' }, + ], +}; diff --git a/src/test/rustdoc-js-std/never.js b/src/test/rustdoc-js-std/never.js new file mode 100644 index 000000000..392b1e818 --- /dev/null +++ b/src/test/rustdoc-js-std/never.js @@ -0,0 +1,7 @@ +const QUERY = '!'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'never' }, + ], +}; diff --git a/src/test/rustdoc-js-std/parser-errors.js b/src/test/rustdoc-js-std/parser-errors.js new file mode 100644 index 000000000..dc42031e0 --- /dev/null +++ b/src/test/rustdoc-js-std/parser-errors.js @@ -0,0 +1,385 @@ +const QUERY = [ + '<P>', + '-> <P>', + 'a<"P">', + '"P" "P"', + 'P "P"', + '"p" p', + '"const": p', + "a<:a>", + "a<::a>", + "((a))", + "(p -> p", + "::a::b", + "a::::b", + "a::b::", + ":a", + "a b:", + "a (b:", + "_:", + "a-bb", + "a>bb", + "ab'", + "a->", + '"p" <a>', + '"p" a<a>', + "a,<", + "aaaaa<>b", + "fn:aaaaa<>b", + "->a<>b", + "a<->", + "a:: a", + "a ::a", + "a<a>:", + "a<>:", + "a,:", + " a<> :", + "mod : :", + "a!a", + "a!!", +]; + +const PARSED = [ + { + elems: [], + foundElems: 0, + original: "<P>", + returned: [], + typeFilter: -1, + userQuery: "<p>", + error: "Found generics without a path", + }, + { + elems: [], + foundElems: 0, + original: "-> <P>", + returned: [], + typeFilter: -1, + userQuery: "-> <p>", + error: "Found generics without a path", + }, + { + elems: [], + foundElems: 0, + original: "a<\"P\">", + returned: [], + typeFilter: -1, + userQuery: "a<\"p\">", + error: "`\"` cannot be used in generics", + }, + { + elems: [], + foundElems: 0, + original: "\"P\" \"P\"", + returned: [], + typeFilter: -1, + userQuery: "\"p\" \"p\"", + error: "Cannot have more than one literal search element", + }, + { + elems: [], + foundElems: 0, + original: "P \"P\"", + returned: [], + typeFilter: -1, + userQuery: "p \"p\"", + error: "Cannot use literal search when there is more than one element", + }, + { + elems: [], + foundElems: 0, + original: "\"p\" p", + returned: [], + typeFilter: -1, + userQuery: "\"p\" p", + error: "You cannot have more than one element if you use quotes", + }, + { + elems: [], + foundElems: 0, + original: "\"const\": p", + returned: [], + typeFilter: -1, + userQuery: "\"const\": p", + error: "You cannot use quotes on type filter", + }, + { + elems: [], + foundElems: 0, + original: "a<:a>", + returned: [], + typeFilter: -1, + userQuery: "a<:a>", + error: "Unexpected `:` after `<`", + }, + { + elems: [], + foundElems: 0, + original: "a<::a>", + returned: [], + typeFilter: -1, + userQuery: "a<::a>", + error: "Unexpected `::`: paths cannot start with `::`", + }, + { + elems: [], + foundElems: 0, + original: "((a))", + returned: [], + typeFilter: -1, + userQuery: "((a))", + error: "Unexpected `(`", + }, + { + elems: [], + foundElems: 0, + original: "(p -> p", + returned: [], + typeFilter: -1, + userQuery: "(p -> p", + error: "Unexpected `(`", + }, + { + elems: [], + foundElems: 0, + original: "::a::b", + returned: [], + typeFilter: -1, + userQuery: "::a::b", + error: "Paths cannot start with `::`", + }, + { + elems: [], + foundElems: 0, + original: "a::::b", + returned: [], + typeFilter: -1, + userQuery: "a::::b", + error: "Unexpected `::::`", + }, + { + elems: [], + foundElems: 0, + original: "a::b::", + returned: [], + typeFilter: -1, + userQuery: "a::b::", + error: "Paths cannot end with `::`", + }, + { + elems: [], + foundElems: 0, + original: ":a", + returned: [], + typeFilter: -1, + userQuery: ":a", + error: "Expected type filter before `:`", + }, + { + elems: [], + foundElems: 0, + original: "a b:", + returned: [], + typeFilter: -1, + userQuery: "a b:", + error: "Unexpected `:`", + }, + { + elems: [], + foundElems: 0, + original: "a (b:", + returned: [], + typeFilter: -1, + userQuery: "a (b:", + error: "Unexpected `(`", + }, + { + elems: [], + foundElems: 0, + original: "_:", + returned: [], + typeFilter: -1, + userQuery: "_:", + error: "Unknown type filter `_`", + }, + { + elems: [], + foundElems: 0, + original: "a-bb", + returned: [], + typeFilter: -1, + userQuery: "a-bb", + error: "Unexpected `-` (did you mean `->`?)", + }, + { + elems: [], + foundElems: 0, + original: "a>bb", + returned: [], + typeFilter: -1, + userQuery: "a>bb", + error: "Unexpected `>` (did you mean `->`?)", + }, + { + elems: [], + foundElems: 0, + original: "ab'", + returned: [], + typeFilter: -1, + userQuery: "ab'", + error: "Unexpected `'`", + }, + { + elems: [], + foundElems: 0, + original: "a->", + returned: [], + typeFilter: -1, + userQuery: "a->", + error: "Expected at least one item after `->`", + }, + { + elems: [], + foundElems: 0, + original: '"p" <a>', + returned: [], + typeFilter: -1, + userQuery: '"p" <a>', + error: "Found generics without a path", + }, + { + elems: [], + foundElems: 0, + original: '"p" a<a>', + returned: [], + typeFilter: -1, + userQuery: '"p" a<a>', + error: "You cannot have more than one element if you use quotes", + }, + { + elems: [], + foundElems: 0, + original: 'a,<', + returned: [], + typeFilter: -1, + userQuery: 'a,<', + error: 'Found generics without a path', + }, + { + elems: [], + foundElems: 0, + original: 'aaaaa<>b', + returned: [], + typeFilter: -1, + userQuery: 'aaaaa<>b', + error: 'Expected `,`, ` `, `:` or `->`, found `b`', + }, + { + elems: [], + foundElems: 0, + original: 'fn:aaaaa<>b', + returned: [], + typeFilter: -1, + userQuery: 'fn:aaaaa<>b', + error: 'Expected `,`, ` ` or `->`, found `b`', + }, + { + elems: [], + foundElems: 0, + original: '->a<>b', + returned: [], + typeFilter: -1, + userQuery: '->a<>b', + error: 'Expected `,` or ` `, found `b`', + }, + { + elems: [], + foundElems: 0, + original: 'a<->', + returned: [], + typeFilter: -1, + userQuery: 'a<->', + error: 'Unexpected `-` after `<`', + }, + { + elems: [], + foundElems: 0, + original: 'a:: a', + returned: [], + typeFilter: -1, + userQuery: 'a:: a', + error: 'Paths cannot end with `::`', + }, + { + elems: [], + foundElems: 0, + original: 'a ::a', + returned: [], + typeFilter: -1, + userQuery: 'a ::a', + error: 'Paths cannot start with `::`', + }, + { + elems: [], + foundElems: 0, + original: "a<a>:", + returned: [], + typeFilter: -1, + userQuery: "a<a>:", + error: 'Unexpected `:`', + }, + { + elems: [], + foundElems: 0, + original: "a<>:", + returned: [], + typeFilter: -1, + userQuery: "a<>:", + error: 'Unexpected `<` in type filter', + }, + { + elems: [], + foundElems: 0, + original: "a,:", + returned: [], + typeFilter: -1, + userQuery: "a,:", + error: 'Unexpected `,` in type filter', + }, + { + elems: [], + foundElems: 0, + original: "a<> :", + returned: [], + typeFilter: -1, + userQuery: "a<> :", + error: 'Unexpected `<` in type filter', + }, + { + elems: [], + foundElems: 0, + original: "mod : :", + returned: [], + typeFilter: -1, + userQuery: "mod : :", + error: 'Unexpected `:`', + }, + { + elems: [], + foundElems: 0, + original: "a!a", + returned: [], + typeFilter: -1, + userQuery: "a!a", + error: '`!` can only be at the end of an ident', + }, + { + elems: [], + foundElems: 0, + original: "a!!", + returned: [], + typeFilter: -1, + userQuery: "a!!", + error: 'Cannot have more than one `!` in an ident', + }, +]; diff --git a/src/test/rustdoc-js-std/parser-filter.js b/src/test/rustdoc-js-std/parser-filter.js new file mode 100644 index 000000000..e5a87a415 --- /dev/null +++ b/src/test/rustdoc-js-std/parser-filter.js @@ -0,0 +1,43 @@ +const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo']; + +const PARSED = [ + { + elems: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [], + }], + foundElems: 1, + original: "fn:foo", + returned: [], + typeFilter: 5, + userQuery: "fn:foo", + error: null, + }, + { + elems: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [], + }], + foundElems: 1, + original: "enum : foo", + returned: [], + typeFilter: 4, + userQuery: "enum : foo", + error: null, + }, + { + elems: [], + foundElems: 0, + original: "macro<f>:foo", + returned: [], + typeFilter: -1, + userQuery: "macro<f>:foo", + error: "Unexpected `:`", + }, +]; diff --git a/src/test/rustdoc-js-std/parser-generics.js b/src/test/rustdoc-js-std/parser-generics.js new file mode 100644 index 000000000..0cf7f5019 --- /dev/null +++ b/src/test/rustdoc-js-std/parser-generics.js @@ -0,0 +1,62 @@ +const QUERY = ['A<B<C<D>, E>', 'p<> u8', '"p"<a>']; + +const PARSED = [ + { + elems: [], + foundElems: 0, + original: 'A<B<C<D>, E>', + returned: [], + typeFilter: -1, + userQuery: 'a<b<c<d>, e>', + error: 'Unexpected `<` after `<`', + }, + { + elems: [ + { + name: "p", + fullPath: ["p"], + pathWithoutLast: [], + pathLast: "p", + generics: [], + }, + { + name: "u8", + fullPath: ["u8"], + pathWithoutLast: [], + pathLast: "u8", + generics: [], + }, + ], + foundElems: 2, + original: "p<> u8", + returned: [], + typeFilter: -1, + userQuery: "p<> u8", + error: null, + }, + { + elems: [ + { + name: "p", + fullPath: ["p"], + pathWithoutLast: [], + pathLast: "p", + generics: [ + { + name: "a", + fullPath: ["a"], + pathWithoutLast: [], + pathLast: "a", + generics: [], + }, + ], + }, + ], + foundElems: 1, + original: '"p"<a>', + returned: [], + typeFilter: -1, + userQuery: '"p"<a>', + error: null, + }, +]; diff --git a/src/test/rustdoc-js-std/parser-ident.js b/src/test/rustdoc-js-std/parser-ident.js new file mode 100644 index 000000000..4b5ab01ac --- /dev/null +++ b/src/test/rustdoc-js-std/parser-ident.js @@ -0,0 +1,93 @@ +const QUERY = [ + "R<!>", + "!", + "a!", + "a!::b", + "a!::b!", +]; + +const PARSED = [ + { + elems: [{ + name: "r", + fullPath: ["r"], + pathWithoutLast: [], + pathLast: "r", + generics: [ + { + name: "!", + fullPath: ["!"], + pathWithoutLast: [], + pathLast: "!", + generics: [], + }, + ], + }], + foundElems: 1, + original: "R<!>", + returned: [], + typeFilter: -1, + userQuery: "r<!>", + error: null, + }, + { + elems: [{ + name: "!", + fullPath: ["!"], + pathWithoutLast: [], + pathLast: "!", + generics: [], + }], + foundElems: 1, + original: "!", + returned: [], + typeFilter: -1, + userQuery: "!", + error: null, + }, + { + elems: [{ + name: "a!", + fullPath: ["a!"], + pathWithoutLast: [], + pathLast: "a!", + generics: [], + }], + foundElems: 1, + original: "a!", + returned: [], + typeFilter: -1, + userQuery: "a!", + error: null, + }, + { + elems: [{ + name: "a!::b", + fullPath: ["a!", "b"], + pathWithoutLast: ["a!"], + pathLast: "b", + generics: [], + }], + foundElems: 1, + original: "a!::b", + returned: [], + typeFilter: -1, + userQuery: "a!::b", + error: null, + }, + { + elems: [{ + name: "a!::b!", + fullPath: ["a!", "b!"], + pathWithoutLast: ["a!"], + pathLast: "b!", + generics: [], + }], + foundElems: 1, + original: "a!::b!", + returned: [], + typeFilter: -1, + userQuery: "a!::b!", + error: null, + }, +]; diff --git a/src/test/rustdoc-js-std/parser-literal.js b/src/test/rustdoc-js-std/parser-literal.js new file mode 100644 index 000000000..87b3baff1 --- /dev/null +++ b/src/test/rustdoc-js-std/parser-literal.js @@ -0,0 +1,27 @@ +const QUERY = ['R<P>']; + +const PARSED = [ + { + elems: [{ + name: "r", + fullPath: ["r"], + pathWithoutLast: [], + pathLast: "r", + generics: [ + { + name: "p", + fullPath: ["p"], + pathWithoutLast: [], + pathLast: "p", + generics: [], + }, + ], + }], + foundElems: 1, + original: "R<P>", + returned: [], + typeFilter: -1, + userQuery: "r<p>", + error: null, + } +]; diff --git a/src/test/rustdoc-js-std/parser-paths.js b/src/test/rustdoc-js-std/parser-paths.js new file mode 100644 index 000000000..9f823f933 --- /dev/null +++ b/src/test/rustdoc-js-std/parser-paths.js @@ -0,0 +1,90 @@ +const QUERY = ['A::B', 'A::B,C', 'A::B<f>,C', 'mod::a']; + +const PARSED = [ + { + elems: [{ + name: "a::b", + fullPath: ["a", "b"], + pathWithoutLast: ["a"], + pathLast: "b", + generics: [], + }], + foundElems: 1, + original: "A::B", + returned: [], + typeFilter: -1, + userQuery: "a::b", + error: null, + }, + { + elems: [ + { + name: "a::b", + fullPath: ["a", "b"], + pathWithoutLast: ["a"], + pathLast: "b", + generics: [], + }, + { + name: "c", + fullPath: ["c"], + pathWithoutLast: [], + pathLast: "c", + generics: [], + }, + ], + foundElems: 2, + original: 'A::B,C', + returned: [], + typeFilter: -1, + userQuery: 'a::b,c', + error: null, + }, + { + elems: [ + { + name: "a::b", + fullPath: ["a", "b"], + pathWithoutLast: ["a"], + pathLast: "b", + generics: [ + { + name: "f", + fullPath: ["f"], + pathWithoutLast: [], + pathLast: "f", + generics: [], + }, + ], + }, + { + name: "c", + fullPath: ["c"], + pathWithoutLast: [], + pathLast: "c", + generics: [], + }, + ], + foundElems: 2, + original: 'A::B<f>,C', + returned: [], + typeFilter: -1, + userQuery: 'a::b<f>,c', + error: null, + }, + { + elems: [{ + name: "mod::a", + fullPath: ["mod", "a"], + pathWithoutLast: ["mod"], + pathLast: "a", + generics: [], + }], + foundElems: 1, + original: "mod::a", + returned: [], + typeFilter: -1, + userQuery: "mod::a", + error: null, + }, +]; diff --git a/src/test/rustdoc-js-std/parser-quote.js b/src/test/rustdoc-js-std/parser-quote.js new file mode 100644 index 000000000..1e16c90de --- /dev/null +++ b/src/test/rustdoc-js-std/parser-quote.js @@ -0,0 +1,87 @@ +const QUERY = [ + '-> "p"', + '"p",', + '"p" -> a', + '"a" -> "p"', + '->"-"', + '"a', + '""', +]; + +const PARSED = [ + { + elems: [], + foundElems: 1, + original: '-> "p"', + returned: [{ + name: "p", + fullPath: ["p"], + pathWithoutLast: [], + pathLast: "p", + generics: [], + }], + typeFilter: -1, + userQuery: '-> "p"', + error: null, + }, + { + elems: [{ + name: "p", + fullPath: ["p"], + pathWithoutLast: [], + pathLast: "p", + generics: [], + }], + foundElems: 1, + original: '"p",', + returned: [], + typeFilter: -1, + userQuery: '"p",', + error: null, + }, + { + elems: [], + foundElems: 0, + original: '"p" -> a', + returned: [], + typeFilter: -1, + userQuery: '"p" -> a', + error: "You cannot have more than one element if you use quotes", + }, + { + elems: [], + foundElems: 0, + original: '"a" -> "p"', + returned: [], + typeFilter: -1, + userQuery: '"a" -> "p"', + error: "Cannot have more than one literal search element", + }, + { + elems: [], + foundElems: 0, + original: '->"-"', + returned: [], + typeFilter: -1, + userQuery: '->"-"', + error: 'Unexpected `-` in a string element', + }, + { + elems: [], + foundElems: 0, + original: '"a', + returned: [], + typeFilter: -1, + userQuery: '"a', + error: 'Unclosed `"`', + }, + { + elems: [], + foundElems: 0, + original: '""', + returned: [], + typeFilter: -1, + userQuery: '""', + error: 'Cannot have empty string element', + }, +]; diff --git a/src/test/rustdoc-js-std/parser-returned.js b/src/test/rustdoc-js-std/parser-returned.js new file mode 100644 index 000000000..6fce17dca --- /dev/null +++ b/src/test/rustdoc-js-std/parser-returned.js @@ -0,0 +1,99 @@ +const QUERY = [ + "-> F<P>", + "-> P", + "->,a", + "aaaaa->a", + "-> !", +]; + +const PARSED = [ + { + elems: [], + foundElems: 1, + original: "-> F<P>", + returned: [{ + name: "f", + fullPath: ["f"], + pathWithoutLast: [], + pathLast: "f", + generics: [ + { + name: "p", + fullPath: ["p"], + pathWithoutLast: [], + pathLast: "p", + generics: [], + }, + ], + }], + typeFilter: -1, + userQuery: "-> f<p>", + error: null, + }, + { + elems: [], + foundElems: 1, + original: "-> P", + returned: [{ + name: "p", + fullPath: ["p"], + pathWithoutLast: [], + pathLast: "p", + generics: [], + }], + typeFilter: -1, + userQuery: "-> p", + error: null, + }, + { + elems: [], + foundElems: 1, + original: "->,a", + returned: [{ + name: "a", + fullPath: ["a"], + pathWithoutLast: [], + pathLast: "a", + generics: [], + }], + typeFilter: -1, + userQuery: "->,a", + error: null, + }, + { + elems: [{ + name: "aaaaa", + fullPath: ["aaaaa"], + pathWithoutLast: [], + pathLast: "aaaaa", + generics: [], + }], + foundElems: 2, + original: "aaaaa->a", + returned: [{ + name: "a", + fullPath: ["a"], + pathWithoutLast: [], + pathLast: "a", + generics: [], + }], + typeFilter: -1, + userQuery: "aaaaa->a", + error: null, + }, + { + elems: [], + foundElems: 1, + original: "-> !", + returned: [{ + name: "!", + fullPath: ["!"], + pathWithoutLast: [], + pathLast: "!", + generics: [], + }], + typeFilter: -1, + userQuery: "-> !", + error: null, + }, +]; diff --git a/src/test/rustdoc-js-std/parser-separators.js b/src/test/rustdoc-js-std/parser-separators.js new file mode 100644 index 000000000..5b7abdfa8 --- /dev/null +++ b/src/test/rustdoc-js-std/parser-separators.js @@ -0,0 +1,206 @@ +// ignore-tidy-tab + +const QUERY = [ + 'aaaaaa b', + 'a b', + 'a,b', + 'a\tb', + 'a<b c>', + 'a<b,c>', + 'a<b\tc>', +]; + +const PARSED = [ + { + elems: [ + { + name: 'aaaaaa', + fullPath: ['aaaaaa'], + pathWithoutLast: [], + pathLast: 'aaaaaa', + generics: [], + }, + { + name: 'b', + fullPath: ['b'], + pathWithoutLast: [], + pathLast: 'b', + generics: [], + }, + ], + foundElems: 2, + original: "aaaaaa b", + returned: [], + typeFilter: -1, + userQuery: "aaaaaa b", + error: null, + }, + { + elems: [ + { + name: 'a', + fullPath: ['a'], + pathWithoutLast: [], + pathLast: 'a', + generics: [], + }, + { + name: 'b', + fullPath: ['b'], + pathWithoutLast: [], + pathLast: 'b', + generics: [], + }, + ], + foundElems: 2, + original: "a b", + returned: [], + typeFilter: -1, + userQuery: "a b", + error: null, + }, + { + elems: [ + { + name: 'a', + fullPath: ['a'], + pathWithoutLast: [], + pathLast: 'a', + generics: [], + }, + { + name: 'b', + fullPath: ['b'], + pathWithoutLast: [], + pathLast: 'b', + generics: [], + }, + ], + foundElems: 2, + original: "a,b", + returned: [], + typeFilter: -1, + userQuery: "a,b", + error: null, + }, + { + elems: [ + { + name: 'a', + fullPath: ['a'], + pathWithoutLast: [], + pathLast: 'a', + generics: [], + }, + { + name: 'b', + fullPath: ['b'], + pathWithoutLast: [], + pathLast: 'b', + generics: [], + }, + ], + foundElems: 2, + original: "a\tb", + returned: [], + typeFilter: -1, + userQuery: "a\tb", + error: null, + }, + { + elems: [ + { + name: 'a', + fullPath: ['a'], + pathWithoutLast: [], + pathLast: 'a', + generics: [ + { + name: 'b', + fullPath: ['b'], + pathWithoutLast: [], + pathLast: 'b', + generics: [], + }, + { + name: 'c', + fullPath: ['c'], + pathWithoutLast: [], + pathLast: 'c', + generics: [], + }, + ], + }, + ], + foundElems: 1, + original: "a<b c>", + returned: [], + typeFilter: -1, + userQuery: "a<b c>", + error: null, + }, + { + elems: [ + { + name: 'a', + fullPath: ['a'], + pathWithoutLast: [], + pathLast: 'a', + generics: [ + { + name: 'b', + fullPath: ['b'], + pathWithoutLast: [], + pathLast: 'b', + generics: [], + }, + { + name: 'c', + fullPath: ['c'], + pathWithoutLast: [], + pathLast: 'c', + generics: [], + }, + ], + }, + ], + foundElems: 1, + original: "a<b,c>", + returned: [], + typeFilter: -1, + userQuery: "a<b,c>", + error: null, + }, + { + elems: [ + { + name: 'a', + fullPath: ['a'], + pathWithoutLast: [], + pathLast: 'a', + generics: [ + { + name: 'b', + fullPath: ['b'], + pathWithoutLast: [], + pathLast: 'b', + generics: [], + }, + { + name: 'c', + fullPath: ['c'], + pathWithoutLast: [], + pathLast: 'c', + generics: [], + }, + ], + }, + ], + foundElems: 1, + original: "a<b\tc>", + returned: [], + typeFilter: -1, + userQuery: "a<b\tc>", + error: null, + }, +]; diff --git a/src/test/rustdoc-js-std/parser-weird-queries.js b/src/test/rustdoc-js-std/parser-weird-queries.js new file mode 100644 index 000000000..a3d85aeca --- /dev/null +++ b/src/test/rustdoc-js-std/parser-weird-queries.js @@ -0,0 +1,123 @@ +// This test is mostly to check that the parser still kinda outputs something +// (and doesn't enter an infinite loop!) even though the query is completely +// invalid. +const QUERY = [ + 'a b', + 'a b', + 'a,b(c)', + 'aaa,a', + ',,,,', + 'mod :', + 'mod\t:', +]; + +const PARSED = [ + { + elems: [ + { + name: "a", + fullPath: ["a"], + pathWithoutLast: [], + pathLast: "a", + generics: [], + }, + { + name: "b", + fullPath: ["b"], + pathWithoutLast: [], + pathLast: "b", + generics: [], + }, + ], + foundElems: 2, + original: "a b", + returned: [], + typeFilter: -1, + userQuery: "a b", + error: null, + }, + { + elems: [ + { + name: "a", + fullPath: ["a"], + pathWithoutLast: [], + pathLast: "a", + generics: [], + }, + { + name: "b", + fullPath: ["b"], + pathWithoutLast: [], + pathLast: "b", + generics: [], + }, + ], + foundElems: 2, + original: "a b", + returned: [], + typeFilter: -1, + userQuery: "a b", + error: null, + }, + { + elems: [], + foundElems: 0, + original: "a,b(c)", + returned: [], + typeFilter: -1, + userQuery: "a,b(c)", + error: "Unexpected `(`", + }, + { + elems: [ + { + name: "aaa", + fullPath: ["aaa"], + pathWithoutLast: [], + pathLast: "aaa", + generics: [], + }, + { + name: "a", + fullPath: ["a"], + pathWithoutLast: [], + pathLast: "a", + generics: [], + }, + ], + foundElems: 2, + original: "aaa,a", + returned: [], + typeFilter: -1, + userQuery: "aaa,a", + error: null, + }, + { + elems: [], + foundElems: 0, + original: ",,,,", + returned: [], + typeFilter: -1, + userQuery: ",,,,", + error: null, + }, + { + elems: [], + foundElems: 0, + original: 'mod :', + returned: [], + typeFilter: 0, + userQuery: 'mod :', + error: null, + }, + { + elems: [], + foundElems: 0, + original: 'mod\t:', + returned: [], + typeFilter: 0, + userQuery: 'mod\t:', + error: null, + }, +]; diff --git a/src/test/rustdoc-js-std/path-ordering.js b/src/test/rustdoc-js-std/path-ordering.js new file mode 100644 index 000000000..7dcdd4023 --- /dev/null +++ b/src/test/rustdoc-js-std/path-ordering.js @@ -0,0 +1,12 @@ +const QUERY = 'hashset::insert'; + +const EXPECTED = { + 'others': [ + // ensure hashset::insert comes first + { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' }, + { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' }, + { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' }, + { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' }, + { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' }, + ], +}; diff --git a/src/test/rustdoc-js-std/primitive.js b/src/test/rustdoc-js-std/primitive.js new file mode 100644 index 000000000..e5690383e --- /dev/null +++ b/src/test/rustdoc-js-std/primitive.js @@ -0,0 +1,75 @@ +const QUERY = [ + 'i8', + 'u32', + 'str', + 'char', + 'unit', + 'tuple', + 'fn', +]; + +const EXPECTED = [ + { + 'others': [ + { + 'path': 'std', + 'name': 'i8', + 'href': '../std/primitive.i8.html', + }, + ] + }, + { + 'others': [ + { + 'path': 'std', + 'name': 'u32', + 'href': '../std/primitive.u32.html', + }, + ] + }, + { + 'others': [ + { + 'path': 'std', + 'name': 'str', + 'href': '../std/primitive.str.html', + }, + ] + }, + { + 'others': [ + { + 'path': 'std', + 'name': 'char', + 'href': '../std/primitive.char.html', + }, + ] + }, + { + 'others': [ + { + 'path': 'std', + 'name': 'unit', + 'href': '../std/primitive.unit.html', + }, + ] + }, + { + 'others': [ + { + 'path': 'std', + 'name': 'tuple', + 'href': '../std/primitive.tuple.html', + }, + ] + }, + { + 'others': [ + { + 'path': 'std', + 'name': 'fn', + 'href': '../std/primitive.fn.html', + }, + ] + }, +]; diff --git a/src/test/rustdoc-js-std/quoted.js b/src/test/rustdoc-js-std/quoted.js new file mode 100644 index 000000000..aec8484a4 --- /dev/null +++ b/src/test/rustdoc-js-std/quoted.js @@ -0,0 +1,21 @@ +// ignore-order + +const QUERY = '"error"'; +const FILTER_CRATE = 'std'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'error' }, + { 'path': 'std::fmt', 'name': 'Error' }, + { 'path': 'std::io', 'name': 'Error' }, + ], + 'in_args': [ + { 'path': 'std::fmt::Error', 'name': 'eq' }, + { 'path': 'std::fmt::Error', 'name': 'cmp' }, + { 'path': 'std::fmt::Error', 'name': 'partial_cmp' }, + + ], + 'returned': [ + { 'path': 'std::fmt::LowerExp', 'name': 'fmt' }, + ], +}; diff --git a/src/test/rustdoc-js-std/return-specific-literal.js b/src/test/rustdoc-js-std/return-specific-literal.js new file mode 100644 index 000000000..c7c347240 --- /dev/null +++ b/src/test/rustdoc-js-std/return-specific-literal.js @@ -0,0 +1,10 @@ +const QUERY = 'struct:"string"'; + +const EXPECTED = { + 'in_args': [ + { 'path': 'std::string::String', 'name': 'ne' }, + ], + 'returned': [ + { 'path': 'std::string::String', 'name': 'add' }, + ], +}; diff --git a/src/test/rustdoc-js-std/return-specific.js b/src/test/rustdoc-js-std/return-specific.js new file mode 100644 index 000000000..d9a910553 --- /dev/null +++ b/src/test/rustdoc-js-std/return-specific.js @@ -0,0 +1,10 @@ +const QUERY = 'struct:string'; + +const EXPECTED = { + 'in_args': [ + { 'path': 'std::string::String', 'name': 'ne' }, + ], + 'returned': [ + { 'path': 'std::string::String', 'name': 'add' }, + ], +}; diff --git a/src/test/rustdoc-js-std/should-fail.js b/src/test/rustdoc-js-std/should-fail.js new file mode 100644 index 000000000..b85a47dc0 --- /dev/null +++ b/src/test/rustdoc-js-std/should-fail.js @@ -0,0 +1,9 @@ +// should-fail + +const QUERY = 'fn'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'fn', ty: 14 }, + ], +}; diff --git a/src/test/rustdoc-js-std/string-from_ut.js b/src/test/rustdoc-js-std/string-from_ut.js new file mode 100644 index 000000000..f9edf4408 --- /dev/null +++ b/src/test/rustdoc-js-std/string-from_ut.js @@ -0,0 +1,11 @@ +const QUERY = 'String::from_ut'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::string::String', 'name': 'from_utf8' }, + { 'path': 'std::string::String', 'name': 'from_utf8' }, + { 'path': 'std::string::String', 'name': 'from_utf8_lossy' }, + { 'path': 'std::string::String', 'name': 'from_utf16_lossy' }, + { 'path': 'std::string::String', 'name': 'from_utf8_unchecked' }, + ], +}; diff --git a/src/test/rustdoc-js-std/struct-vec.js b/src/test/rustdoc-js-std/struct-vec.js new file mode 100644 index 000000000..29609904b --- /dev/null +++ b/src/test/rustdoc-js-std/struct-vec.js @@ -0,0 +1,8 @@ +const QUERY = 'struct:VecD'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::collections', 'name': 'VecDeque' }, + { 'path': 'std::vec', 'name': 'Vec' }, + ], +}; diff --git a/src/test/rustdoc-js-std/typed-query.js b/src/test/rustdoc-js-std/typed-query.js new file mode 100644 index 000000000..25efbad26 --- /dev/null +++ b/src/test/rustdoc-js-std/typed-query.js @@ -0,0 +1,17 @@ +// exact-check + +const QUERY = 'macro:print'; +const FILTER_CRATE = 'std'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'print' }, + { 'path': 'std', 'name': 'eprint' }, + { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprintln' }, + { 'path': 'std::pin', 'name': 'pin' }, + { 'path': 'std::future', 'name': 'join' }, + { 'path': 'std', 'name': 'line' }, + { 'path': 'std', 'name': 'write' }, + ], +}; diff --git a/src/test/rustdoc-js-std/vec-new.js b/src/test/rustdoc-js-std/vec-new.js new file mode 100644 index 000000000..cd0e8e7b4 --- /dev/null +++ b/src/test/rustdoc-js-std/vec-new.js @@ -0,0 +1,9 @@ +const QUERY = 'Vec::new'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::vec::Vec', 'name': 'new' }, + { 'path': 'std::vec::Vec', 'name': 'ne' }, + { 'path': 'alloc::vec::Vec', 'name': 'ne' }, + ], +}; diff --git a/src/test/rustdoc-js/basic.js b/src/test/rustdoc-js/basic.js new file mode 100644 index 000000000..d99b23468 --- /dev/null +++ b/src/test/rustdoc-js/basic.js @@ -0,0 +1,7 @@ +const QUERY = 'Fo'; + +const EXPECTED = { + 'others': [ + { 'path': 'basic', 'name': 'Foo' }, + ], +}; diff --git a/src/test/rustdoc-js/basic.rs b/src/test/rustdoc-js/basic.rs new file mode 100644 index 000000000..da946a58b --- /dev/null +++ b/src/test/rustdoc-js/basic.rs @@ -0,0 +1,2 @@ +/// Docs for Foo +pub struct Foo; diff --git a/src/test/rustdoc-js/doc-alias-filter-out.js b/src/test/rustdoc-js/doc-alias-filter-out.js new file mode 100644 index 000000000..46a089d06 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-filter-out.js @@ -0,0 +1,9 @@ +// exact-check + +const QUERY = 'true'; + +const FILTER_CRATE = 'some_other_crate'; + +const EXPECTED = { + 'others': [], +}; diff --git a/src/test/rustdoc-js/doc-alias-filter-out.rs b/src/test/rustdoc-js/doc-alias-filter-out.rs new file mode 100644 index 000000000..3f0c09479 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-filter-out.rs @@ -0,0 +1,2 @@ +#[doc(alias = "true")] +pub struct Foo; diff --git a/src/test/rustdoc-js/doc-alias-filter.js b/src/test/rustdoc-js/doc-alias-filter.js new file mode 100644 index 000000000..e06047ba7 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-filter.js @@ -0,0 +1,17 @@ +// exact-check + +const QUERY = '"true"'; + +const FILTER_CRATE = 'doc_alias_filter'; + +const EXPECTED = { + 'others': [ + { + 'path': 'doc_alias_filter', + 'name': 'Foo', + 'alias': 'true', + 'href': '../doc_alias_filter/struct.Foo.html', + 'is_alias': true + }, + ], +}; diff --git a/src/test/rustdoc-js/doc-alias-filter.rs b/src/test/rustdoc-js/doc-alias-filter.rs new file mode 100644 index 000000000..d5227814c --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-filter.rs @@ -0,0 +1,5 @@ +#[doc(alias = "true")] +pub struct Foo; + +#[doc(alias = "false")] +pub struct Bar; diff --git a/src/test/rustdoc-js/doc-alias-whitespace.js b/src/test/rustdoc-js/doc-alias-whitespace.js new file mode 100644 index 000000000..c9fc0c431 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-whitespace.js @@ -0,0 +1,19 @@ +// exact-check + +const QUERY = [ + 'Demon Lord', +]; + +const EXPECTED = [ + { + 'others': [ + { + 'path': 'doc_alias_whitespace', + 'name': 'Struct', + 'alias': 'Demon Lord', + 'href': '../doc_alias_whitespace/struct.Struct.html', + 'is_alias': true + }, + ], + }, +]; diff --git a/src/test/rustdoc-js/doc-alias-whitespace.rs b/src/test/rustdoc-js/doc-alias-whitespace.rs new file mode 100644 index 000000000..16c022c74 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-whitespace.rs @@ -0,0 +1,2 @@ +#[doc(alias = "Demon Lord")] +pub struct Struct; diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js new file mode 100644 index 000000000..7bb0cbe38 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias.js @@ -0,0 +1,295 @@ +// exact-check + +const QUERY = [ + 'StructItem', + 'StructFieldItem', + 'StructMethodItem', + 'ImplTraitItem', + 'StructImplConstItem', + 'ImplTraitFunction', + 'EnumItem', + 'VariantItem', + 'EnumMethodItem', + 'TypedefItem', + 'TraitItem', + 'TraitTypeItem', + 'AssociatedConstItem', + 'TraitFunctionItem', + 'FunctionItem', + 'ModuleItem', + 'ConstItem', + 'StaticItem', + 'UnionItem', + 'UnionFieldItem', + 'UnionMethodItem', + 'MacroItem', +]; + +const EXPECTED = [ + { + // StructItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Struct', + 'alias': 'StructItem', + 'href': '../doc_alias/struct.Struct.html', + 'is_alias': true + }, + ], + }, + { + // StructFieldItem + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'field', + 'alias': 'StructFieldItem', + 'href': '../doc_alias/struct.Struct.html#structfield.field', + 'is_alias': true + }, + ], + }, + { + // StructMethodItem + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'method', + 'alias': 'StructMethodItem', + 'href': '../doc_alias/struct.Struct.html#method.method', + 'is_alias': true + }, + ], + }, + { + // ImplTraitItem + 'others': [], + }, + { + // StructImplConstItem + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'ImplConstItem', + 'alias': 'StructImplConstItem', + 'href': '../doc_alias/struct.Struct.html#associatedconstant.ImplConstItem', + 'is_alias': true + }, + ], + }, + { + // ImplTraitFunction + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'function', + 'alias': 'ImplTraitFunction', + 'href': '../doc_alias/struct.Struct.html#method.function', + 'is_alias': true + }, + ], + }, + { + // EnumItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Enum', + 'alias': 'EnumItem', + 'href': '../doc_alias/enum.Enum.html', + 'is_alias': true + }, + ], + }, + { + // VariantItem + 'others': [ + { + 'path': 'doc_alias::Enum', + 'name': 'Variant', + 'alias': 'VariantItem', + 'href': '../doc_alias/enum.Enum.html#variant.Variant', + 'is_alias': true + }, + ], + }, + { + // EnumMethodItem + 'others': [ + { + 'path': 'doc_alias::Enum', + 'name': 'method', + 'alias': 'EnumMethodItem', + 'href': '../doc_alias/enum.Enum.html#method.method', + 'is_alias': true + }, + ], + }, + { + // TypedefItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Typedef', + 'alias': 'TypedefItem', + 'href': '../doc_alias/type.Typedef.html', + 'is_alias': true + }, + ], + }, + { + // TraitItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Trait', + 'alias': 'TraitItem', + 'href': '../doc_alias/trait.Trait.html', + 'is_alias': true + }, + ], + }, + { + // TraitTypeItem + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'Target', + 'alias': 'TraitTypeItem', + 'href': '../doc_alias/trait.Trait.html#associatedtype.Target', + 'is_alias': true + }, + ], + }, + { + // AssociatedConstItem + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'AssociatedConst', + 'alias': 'AssociatedConstItem', + 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst', + 'is_alias': true + }, + ], + }, + { + // TraitFunctionItem + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'function', + 'alias': 'TraitFunctionItem', + 'href': '../doc_alias/trait.Trait.html#tymethod.function', + 'is_alias': true + }, + ], + }, + { + // FunctionItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'function', + 'alias': 'FunctionItem', + 'href': '../doc_alias/fn.function.html', + 'is_alias': true + }, + ], + }, + { + // ModuleItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Module', + 'alias': 'ModuleItem', + 'href': '../doc_alias/Module/index.html', + 'is_alias': true + }, + ], + }, + { + // ConstItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Const', + 'alias': 'ConstItem', + 'href': '../doc_alias/constant.Const.html', + 'is_alias': true + }, + { + 'path': 'doc_alias::Struct', + 'name': 'ImplConstItem', + }, + ], + }, + { + // StaticItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Static', + 'alias': 'StaticItem', + 'href': '../doc_alias/static.Static.html', + 'is_alias': true + }, + ], + }, + { + // UnionItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Union', + 'alias': 'UnionItem', + 'href': '../doc_alias/union.Union.html', + 'is_alias': true + }, + // Not an alias! + { + 'path': 'doc_alias::Union', + 'name': 'union_item', + 'href': '../doc_alias/union.Union.html#structfield.union_item' + }, + ], + }, + { + // UnionFieldItem + 'others': [ + { + 'path': 'doc_alias::Union', + 'name': 'union_item', + 'alias': 'UnionFieldItem', + 'href': '../doc_alias/union.Union.html#structfield.union_item', + 'is_alias': true + }, + ], + }, + { + // UnionMethodItem + 'others': [ + { + 'path': 'doc_alias::Union', + 'name': 'method', + 'alias': 'UnionMethodItem', + 'href': '../doc_alias/union.Union.html#method.method', + 'is_alias': true + }, + ], + }, + { + // MacroItem + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Macro', + 'alias': 'MacroItem', + 'href': '../doc_alias/macro.Macro.html', + 'is_alias': true + }, + ], + }, +]; diff --git a/src/test/rustdoc-js/doc-alias.rs b/src/test/rustdoc-js/doc-alias.rs new file mode 100644 index 000000000..750b7b757 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias.rs @@ -0,0 +1,75 @@ +#[doc(alias = "StructItem")] +pub struct Struct { + #[doc(alias = "StructFieldItem")] + pub field: u32, +} + +impl Struct { + #[doc(alias = "StructImplConstItem")] + pub const ImplConstItem: i32 = 0; + #[doc(alias = "StructMethodItem")] + pub fn method(&self) {} +} + +impl Trait for Struct { + type Target = u32; + const AssociatedConst: i32 = 12; + + #[doc(alias = "ImplTraitFunction")] + fn function() -> Self::Target { 0 } +} + +#[doc(alias = "EnumItem")] +pub enum Enum { + #[doc(alias = "VariantItem")] + Variant, +} + +impl Enum { + #[doc(alias = "EnumMethodItem")] + pub fn method(&self) {} +} + +#[doc(alias = "TypedefItem")] +pub type Typedef = i32; + +#[doc(alias = "TraitItem")] +pub trait Trait { + #[doc(alias = "TraitTypeItem")] + type Target; + #[doc(alias = "AssociatedConstItem")] + const AssociatedConst: i32; + + #[doc(alias = "TraitFunctionItem")] + fn function() -> Self::Target; +} + +#[doc(alias = "FunctionItem")] +pub fn function() {} + +#[doc(alias = "ModuleItem")] +pub mod Module {} + +#[doc(alias = "ConstItem")] +pub const Const: u32 = 0; + +#[doc(alias = "StaticItem")] +pub static Static: u32 = 0; + +#[doc(alias = "UnionItem")] +pub union Union { + #[doc(alias = "UnionFieldItem")] + pub union_item: u32, + pub y: f32, +} + +impl Union { + #[doc(alias = "UnionMethodItem")] + pub fn method(&self) {} +} + +#[doc(alias = "MacroItem")] +#[macro_export] +macro_rules! Macro { + () => {} +} diff --git a/src/test/rustdoc-js/exact-match.js b/src/test/rustdoc-js/exact-match.js new file mode 100644 index 000000000..b0a411bee --- /dev/null +++ b/src/test/rustdoc-js/exact-match.js @@ -0,0 +1,9 @@ +const QUERY = 'si::pc'; + +const EXPECTED = { + 'others': [ + { 'path': 'exact_match::Si', 'name': 'pc' }, + { 'path': 'exact_match::Psi', 'name': 'pc' }, + { 'path': 'exact_match::Si', 'name': 'pa' }, + ], +}; diff --git a/src/test/rustdoc-js/exact-match.rs b/src/test/rustdoc-js/exact-match.rs new file mode 100644 index 000000000..2eacc0a35 --- /dev/null +++ b/src/test/rustdoc-js/exact-match.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/foreign-type-path.js b/src/test/rustdoc-js/foreign-type-path.js new file mode 100644 index 000000000..334761bad --- /dev/null +++ b/src/test/rustdoc-js/foreign-type-path.js @@ -0,0 +1,9 @@ +const QUERY = 'MyForeignType::my_method'; + +const EXPECTED = { + 'others': [ + // Test case for https://github.com/rust-lang/rust/pull/96887#pullrequestreview-967154358 + // Validates that the parent path for a foreign type method is correct. + { 'path': 'foreign_type_path::aaaaaaa::MyForeignType', 'name': 'my_method' }, + ], +}; diff --git a/src/test/rustdoc-js/foreign-type-path.rs b/src/test/rustdoc-js/foreign-type-path.rs new file mode 100644 index 000000000..83400104e --- /dev/null +++ b/src/test/rustdoc-js/foreign-type-path.rs @@ -0,0 +1,13 @@ +#![feature(extern_types)] + +pub mod aaaaaaa { + + extern { + pub type MyForeignType; + } + + impl MyForeignType { + pub fn my_method() {} + } + +} diff --git a/src/test/rustdoc-js/generics-impl.js b/src/test/rustdoc-js/generics-impl.js new file mode 100644 index 000000000..bb6e0041d --- /dev/null +++ b/src/test/rustdoc-js/generics-impl.js @@ -0,0 +1,57 @@ +// exact-check + +const QUERY = [ + 'Aaaaaaa -> u32', + 'Aaaaaaa -> bool', + 'Aaaaaaa -> usize', + 'Read -> u64', + 'bool -> u64', + 'Ddddddd -> u64', + '-> Ddddddd' +]; + +const EXPECTED = [ + { + // Aaaaaaa -> u32 + 'others': [ + { 'path': 'generics_impl::Aaaaaaa', 'name': 'bbbbbbb' }, + ], + }, + { + // Aaaaaaa -> bool + 'others': [ + { 'path': 'generics_impl::Aaaaaaa', 'name': 'ccccccc' }, + ], + }, + { + // Aaaaaaa -> usize + 'others': [ + { 'path': 'generics_impl::Aaaaaaa', 'name': 'read' }, + ], + }, + { + // Read -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' }, + { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, + ], + }, + { + // bool -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' }, + ], + }, + { + // Ddddddd -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, + ], + }, + { + // -> Ddddddd + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'hhhhhhh' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/generics-impl.rs b/src/test/rustdoc-js/generics-impl.rs new file mode 100644 index 000000000..696218021 --- /dev/null +++ b/src/test/rustdoc-js/generics-impl.rs @@ -0,0 +1,35 @@ +use std::io::{Result as IoResult, Read}; + +pub struct Aaaaaaa; + +impl Aaaaaaa { + pub fn bbbbbbb(self) -> u32 { + 1 + } + pub fn ccccccc(&self) -> bool { + true + } +} + +impl Read for Aaaaaaa { + fn read(&mut self, out: &mut [u8]) -> IoResult<usize> { + Ok(out.len()) + } +} + +pub struct Ddddddd<T>(T); + +impl<T: Read> Ddddddd<T> { + pub fn eeeeeee(_: T) -> u64 { + 1 + } + pub fn fffffff(_: bool) -> u64 { + 1 + } + pub fn ggggggg(self) -> u64 { + 1 + } + pub fn hhhhhhh() -> Self where T: Default { + Ddddddd(T::default()) + } +} diff --git a/src/test/rustdoc-js/generics-multi-trait.js b/src/test/rustdoc-js/generics-multi-trait.js new file mode 100644 index 000000000..e7fcea876 --- /dev/null +++ b/src/test/rustdoc-js/generics-multi-trait.js @@ -0,0 +1,32 @@ +// exact-check + +const QUERY = [ + 'Result<SomeTrait>', + 'Zzzzzzzzzzzzzzzzzz', + 'Nonononononononono', +]; + +const EXPECTED = [ + // check one of the generic items + { + 'in_args': [ + { 'path': 'generics_multi_trait', 'name': 'beta' }, + ], + 'returned': [ + { 'path': 'generics_multi_trait', 'name': 'bet' }, + ], + }, + { + 'in_args': [ + { 'path': 'generics_multi_trait', 'name': 'beta' }, + ], + 'returned': [ + { 'path': 'generics_multi_trait', 'name': 'bet' }, + ], + }, + // ignore the name of the generic itself + { + 'in_args': [], + 'returned': [], + }, +]; diff --git a/src/test/rustdoc-js/generics-multi-trait.rs b/src/test/rustdoc-js/generics-multi-trait.rs new file mode 100644 index 000000000..e6fd06d25 --- /dev/null +++ b/src/test/rustdoc-js/generics-multi-trait.rs @@ -0,0 +1,12 @@ +pub trait SomeTrait {} +pub trait Zzzzzzzzzzzzzzzzzz {} + +pub fn bet<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>() -> Result<Nonononononononono, ()> { + loop {} +} + +pub fn beta<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>( + _param: Result<Nonononononononono, ()>, +) { + loop {} +} diff --git a/src/test/rustdoc-js/generics-trait.js b/src/test/rustdoc-js/generics-trait.js new file mode 100644 index 000000000..787662243 --- /dev/null +++ b/src/test/rustdoc-js/generics-trait.js @@ -0,0 +1,23 @@ +const QUERY = [ + 'Result<SomeTrait>', + 'OtherThingxxxxxxxx', +]; + +const EXPECTED = [ + { + 'in_args': [ + { 'path': 'generics_trait', 'name': 'beta' }, + ], + 'returned': [ + { 'path': 'generics_trait', 'name': 'bet' }, + ], + }, + { + 'in_args': [ + { 'path': 'generics_trait', 'name': 'alpha' }, + ], + 'returned': [ + { 'path': 'generics_trait', 'name': 'alef' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/generics-trait.rs b/src/test/rustdoc-js/generics-trait.rs new file mode 100644 index 000000000..20db117cc --- /dev/null +++ b/src/test/rustdoc-js/generics-trait.rs @@ -0,0 +1,8 @@ +pub trait SomeTrait {} +pub trait OtherThingxxxxxxxx {} + +pub fn alef<T: OtherThingxxxxxxxx>() -> Result<T, ()> { loop {} } +pub fn bet<T: SomeTrait>() -> Result<T, ()> { loop {} } + +pub fn alpha<T: OtherThingxxxxxxxx>(_param: Result<T, ()>) { loop {} } +pub fn beta<T: SomeTrait>(_param: Result<T, ()>) { loop {} } diff --git a/src/test/rustdoc-js/generics.js b/src/test/rustdoc-js/generics.js new file mode 100644 index 000000000..5e5ba7cd9 --- /dev/null +++ b/src/test/rustdoc-js/generics.js @@ -0,0 +1,73 @@ +// exact-check + +const QUERY = [ + 'R<P>', + '"P"', + 'P', + 'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>', + 'TraitCat', + 'TraitDog', + 'Result<String>', +]; + +const EXPECTED = [ + { + // R<P> + 'returned': [ + { 'path': 'generics', 'name': 'alef' }, + ], + 'in_args': [ + { 'path': 'generics', 'name': 'alpha' }, + ], + }, + { + // "P" + 'others': [ + { 'path': 'generics', 'name': 'P' }, + ], + 'returned': [ + { 'path': 'generics', 'name': 'alef' }, + ], + 'in_args': [ + { 'path': 'generics', 'name': 'alpha' }, + ], + }, + { + // P + 'returned': [ + { 'path': 'generics', 'name': 'alef' }, + ], + 'in_args': [ + { 'path': 'generics', 'name': 'alpha' }, + ], + }, + { + // "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti> + 'in_args': [ + { 'path': 'generics', 'name': 'extracreditlabhomework' }, + ], + 'returned': [], + }, + { + // TraitCat + 'in_args': [ + { 'path': 'generics', 'name': 'gamma' }, + ], + }, + { + // TraitDog + 'in_args': [ + { 'path': 'generics', 'name': 'gamma' }, + ], + }, + { + // Result<String> + 'others': [], + 'returned': [ + { 'path': 'generics', 'name': 'super_soup' }, + ], + 'in_args': [ + { 'path': 'generics', 'name': 'super_soup' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/generics.rs b/src/test/rustdoc-js/generics.rs new file mode 100644 index 000000000..055c51c7e --- /dev/null +++ b/src/test/rustdoc-js/generics.rs @@ -0,0 +1,28 @@ +pub struct P; +pub struct Q; +pub struct R<T>(T); + +// returns test +pub fn alef() -> R<P> { loop {} } +pub fn bet() -> R<Q> { loop {} } + +// in_args test +pub fn alpha(_x: R<P>) { loop {} } +pub fn beta(_x: R<Q>) { loop {} } + +// test case with multiple appearances of the same type +pub struct ExtraCreditStructMulti<T, U> { t: T, u: U } +pub struct ExtraCreditInnerMulti {} +pub fn extracreditlabhomework( + _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti> +) { loop {} } +pub fn redherringmatchforextracredit( + _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()> +) { loop {} } + +pub trait TraitCat {} +pub trait TraitDog {} + +pub fn gamma<T: TraitCat + TraitDog>(t: T) {} + +pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s } diff --git a/src/test/rustdoc-js/impl-trait.js b/src/test/rustdoc-js/impl-trait.js new file mode 100644 index 000000000..8d594bf8a --- /dev/null +++ b/src/test/rustdoc-js/impl-trait.js @@ -0,0 +1,51 @@ +// ignore-order + +const QUERY = [ + 'Aaaaaaa -> i32', + 'Aaaaaaa -> Aaaaaaa', + 'Aaaaaaa -> usize', + '-> Aaaaaaa', + 'Aaaaaaa', +]; + +const EXPECTED = [ + { + // Aaaaaaa -> i32 + 'others': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' }, + ], + }, + { + // Aaaaaaa -> Aaaaaaa + 'others': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + ], + }, + { + // Aaaaaaa -> usize + 'others': [], + }, + { + // -> Aaaaaaa + 'others': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'impl_trait', 'name': 'bbbbbbb' }, + ], + }, + { + // Aaaaaaa + 'others': [ + { 'path': 'impl_trait', 'name': 'Aaaaaaa' }, + ], + 'in_args': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' }, + ], + 'returned': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'impl_trait', 'name': 'bbbbbbb' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/impl-trait.rs b/src/test/rustdoc-js/impl-trait.rs new file mode 100644 index 000000000..fb8869b46 --- /dev/null +++ b/src/test/rustdoc-js/impl-trait.rs @@ -0,0 +1,21 @@ +pub trait Aaaaaaa {} + +impl Aaaaaaa for () {} + +pub fn bbbbbbb() -> impl Aaaaaaa { + () +} + +pub struct Ccccccc {} + +impl Ccccccc { + pub fn ddddddd(&self) -> impl Aaaaaaa { + () + } + pub fn eeeeeee(&self, _x: impl Aaaaaaa) -> i32 { + 0 + } + pub fn fffffff(&self, x: impl Aaaaaaa) -> impl Aaaaaaa { + x + } +} diff --git a/src/test/rustdoc-js/module-substring.js b/src/test/rustdoc-js/module-substring.js new file mode 100644 index 000000000..a446c39eb --- /dev/null +++ b/src/test/rustdoc-js/module-substring.js @@ -0,0 +1,9 @@ +const QUERY = 'ig::pc'; + +const EXPECTED = { + 'others': [ + { 'path': 'module_substring::Sig', 'name': 'pc' }, + { 'path': 'module_substring::Si', 'name': 'pc' }, + { 'path': 'module_substring::Si', 'name': 'pa' }, + ], +}; diff --git a/src/test/rustdoc-js/module-substring.rs b/src/test/rustdoc-js/module-substring.rs new file mode 100644 index 000000000..2eacc0a35 --- /dev/null +++ b/src/test/rustdoc-js/module-substring.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/path-ordering.js b/src/test/rustdoc-js/path-ordering.js new file mode 100644 index 000000000..4aee569b0 --- /dev/null +++ b/src/test/rustdoc-js/path-ordering.js @@ -0,0 +1,14 @@ +// exact-check + +const QUERY = 'b::ccccccc'; + +const EXPECTED = { + 'others': [ + // `ccccccc` is an exact match for all three of these. + // However `b` is a closer match for `bb` than for any + // of the others, so it ought to go first. + { 'path': 'path_ordering::bb', 'name': 'Ccccccc' }, + { 'path': 'path_ordering::aa', 'name': 'Ccccccc' }, + { 'path': 'path_ordering::dd', 'name': 'Ccccccc' }, + ], +}; diff --git a/src/test/rustdoc-js/path-ordering.rs b/src/test/rustdoc-js/path-ordering.rs new file mode 100644 index 000000000..7843cf7f9 --- /dev/null +++ b/src/test/rustdoc-js/path-ordering.rs @@ -0,0 +1,9 @@ +pub mod dd { + pub struct Ccccccc; +} +pub mod aa { + pub struct Ccccccc; +} +pub mod bb { + pub struct Ccccccc; +} diff --git a/src/test/rustdoc-js/primitive.js b/src/test/rustdoc-js/primitive.js new file mode 100644 index 000000000..918f70999 --- /dev/null +++ b/src/test/rustdoc-js/primitive.js @@ -0,0 +1,25 @@ +// exact-check + +const QUERY = [ + "i32", + "str", + "TotoIsSomewhere", +]; + +const EXPECTED = [ + { + 'in_args': [ + { 'path': 'primitive', 'name': 'foo' }, + ], + }, + { + 'returned': [ + { 'path': 'primitive', 'name': 'foo' }, + ], + }, + { + 'others': [], + 'in_args': [], + 'returned': [], + }, +]; diff --git a/src/test/rustdoc-js/primitive.rs b/src/test/rustdoc-js/primitive.rs new file mode 100644 index 000000000..2b30ccf15 --- /dev/null +++ b/src/test/rustdoc-js/primitive.rs @@ -0,0 +1,5 @@ +pub fn foo(i: i32) -> &'static str { + "hello" +} + +pub fn foo2<TotoIsSomewhere>(i: &TotoIsSomewhere, j: TotoIsSomewhere) {} diff --git a/src/test/rustdoc-js/prototype.js b/src/test/rustdoc-js/prototype.js new file mode 100644 index 000000000..2f1d841c3 --- /dev/null +++ b/src/test/rustdoc-js/prototype.js @@ -0,0 +1,16 @@ +// exact-check + +const QUERY = ['constructor', '__proto__']; + +const EXPECTED = [ + { + 'others': [], + 'returned': [], + 'in_args': [], + }, + { + 'others': [], + 'returned': [], + 'in_args': [], + }, +]; diff --git a/src/test/rustdoc-js/prototype.rs b/src/test/rustdoc-js/prototype.rs new file mode 100644 index 000000000..5f6d73cc1 --- /dev/null +++ b/src/test/rustdoc-js/prototype.rs @@ -0,0 +1,4 @@ +// The alias needed to be there to reproduce the bug +// that used to be here. +#[doc(alias="other_alias")] +pub fn something_else() {} diff --git a/src/test/rustdoc-js/raw-pointer.js b/src/test/rustdoc-js/raw-pointer.js new file mode 100644 index 000000000..140b955ea --- /dev/null +++ b/src/test/rustdoc-js/raw-pointer.js @@ -0,0 +1,55 @@ +// ignore-order + +const QUERY = [ + 'Aaaaaaa -> i32', + 'Aaaaaaa -> Aaaaaaa', + 'Aaaaaaa -> usize', + '-> Aaaaaaa', + 'Aaaaaaa', +]; + +const EXPECTED = [ + { + // Aaaaaaa -> i32 + 'others': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' }, + ], + }, + { + // Aaaaaaa -> Aaaaaaa + 'others': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + ], + }, + { + // Aaaaaaa -> usize + 'others': [], + }, + { + // -> Aaaaaaa + 'others': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'raw_pointer', 'name': 'bbbbbbb' }, + ], + }, + { + // Aaaaaaa + 'others': [ + { 'path': 'raw_pointer', 'name': 'Aaaaaaa' }, + ], + 'in_args': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' }, + ], + 'returned': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'raw_pointer', 'name': 'bbbbbbb' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/raw-pointer.rs b/src/test/rustdoc-js/raw-pointer.rs new file mode 100644 index 000000000..b8ace2e0b --- /dev/null +++ b/src/test/rustdoc-js/raw-pointer.rs @@ -0,0 +1,24 @@ +use std::ptr; + +pub struct Aaaaaaa {} + +pub fn bbbbbbb() -> *const Aaaaaaa { + ptr::null() +} + +pub struct Ccccccc {} + +impl Ccccccc { + pub fn ddddddd(&self) -> *const Aaaaaaa { + ptr::null() + } + pub fn eeeeeee(&self, _x: *const Aaaaaaa) -> i32 { + 0 + } + pub fn fffffff(&self, x: *const Aaaaaaa) -> *const Aaaaaaa { + x + } + pub fn ggggggg(&self, x: *mut Aaaaaaa) -> *mut Aaaaaaa { + x + } +} diff --git a/src/test/rustdoc-js/search-short-types.js b/src/test/rustdoc-js/search-short-types.js new file mode 100644 index 000000000..d14672af7 --- /dev/null +++ b/src/test/rustdoc-js/search-short-types.js @@ -0,0 +1,10 @@ +const QUERY = 'P'; + +const EXPECTED = { + 'others': [ + { 'path': 'search_short_types', 'name': 'P' }, + { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' }, + { 'path': 'search_short_types', 'name': 'Ap' }, + { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' }, + ], +}; diff --git a/src/test/rustdoc-js/search-short-types.rs b/src/test/rustdoc-js/search-short-types.rs new file mode 100644 index 000000000..a4083f9a7 --- /dev/null +++ b/src/test/rustdoc-js/search-short-types.rs @@ -0,0 +1,74 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; + +pub struct VeryLongTypeName; +impl VeryLongTypeName { + pub fn p() {} + pub fn ap() {} +} diff --git a/src/test/rustdoc-js/struct-like-variant.js b/src/test/rustdoc-js/struct-like-variant.js new file mode 100644 index 000000000..f6deea51e --- /dev/null +++ b/src/test/rustdoc-js/struct-like-variant.js @@ -0,0 +1,7 @@ +const QUERY = 'name'; + +const EXPECTED = { + 'others': [ + { 'path': 'struct_like_variant::Enum::Bar', 'name': 'name', 'desc': 'This is a name.' }, + ], +}; diff --git a/src/test/rustdoc-js/struct-like-variant.rs b/src/test/rustdoc-js/struct-like-variant.rs new file mode 100644 index 000000000..2f52a319a --- /dev/null +++ b/src/test/rustdoc-js/struct-like-variant.rs @@ -0,0 +1,8 @@ +#![crate_name = "struct_like_variant"] + +pub enum Enum { + Bar { + /// This is a name. + name: String + } +} diff --git a/src/test/rustdoc-js/substring.js b/src/test/rustdoc-js/substring.js new file mode 100644 index 000000000..af05cd1ad --- /dev/null +++ b/src/test/rustdoc-js/substring.js @@ -0,0 +1,8 @@ +const QUERY = 'waker_from'; + +const EXPECTED = { + 'others': [ + { 'path': 'substring::SuperWaker', 'name': 'local_waker_from_nonlocal' }, + { 'path': 'substring::SuperWakerTask', 'name': 'local_waker_from_nonlocal' }, + ], +}; diff --git a/src/test/rustdoc-js/substring.rs b/src/test/rustdoc-js/substring.rs new file mode 100644 index 000000000..e729c722c --- /dev/null +++ b/src/test/rustdoc-js/substring.rs @@ -0,0 +1,21 @@ +pub struct SuperWaker; + +impl SuperWaker { + pub fn local_waker_from_nonlocal() {} + pub fn local_waker_frm_nonlocal() {} + pub fn some_method() {} + pub fn some_other_method() {} + pub fn waker_non_local() {} + pub fn from_non_local() {} +} + +pub struct SuperWakerTask; + +impl SuperWakerTask { + pub fn local_waker_from_nonlocal() {} + pub fn local_waker_frm_nonlocal() {} + pub fn some_method() {} + pub fn some_other_method() {} + pub fn waker_non_local() {} + pub fn from_non_local() {} +} diff --git a/src/test/rustdoc-js/summaries.js b/src/test/rustdoc-js/summaries.js new file mode 100644 index 000000000..dfb11e804 --- /dev/null +++ b/src/test/rustdoc-js/summaries.js @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +const QUERY = ['summaries', 'summaries::Sidebar', 'summaries::Sidebar2']; + +const EXPECTED = [ + { + 'others': [ + { 'path': '', 'name': 'summaries', 'desc': 'This <em>summary</em> has a link, [<code>code</code>], and <code>Sidebar2</code> intra-doc.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar', 'desc': 'This <code>code</code> will be rendered in a code tag.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar2', 'desc': '' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/summaries.rs b/src/test/rustdoc-js/summaries.rs new file mode 100644 index 000000000..1ee1c34aa --- /dev/null +++ b/src/test/rustdoc-js/summaries.rs @@ -0,0 +1,22 @@ +#![crate_type = "lib"] +#![crate_name = "summaries"] + +#![allow(rustdoc::broken_intra_doc_links)] + +//! This *summary* has a [link], [`code`], and [`Sidebar2`] intra-doc. +//! +//! This is the second paragraph. It should not be rendered. +//! To test that intra-doc links are resolved properly, [`code`] should render +//! the square brackets, and [`Sidebar2`] should not. +//! +//! [link]: https://example.com + +/// This `code` will be rendered in a code tag. +/// +/// This text should not be rendered. +pub struct Sidebar; + +/// ```text +/// this block should not be rendered +/// ``` +pub struct Sidebar2; diff --git a/src/test/rustdoc-json/assoc_items.rs b/src/test/rustdoc-json/assoc_items.rs new file mode 100644 index 000000000..2ee64c9f6 --- /dev/null +++ b/src/test/rustdoc-json/assoc_items.rs @@ -0,0 +1,29 @@ +#![no_std] + +// @has assoc_items.json + +pub struct Simple; + +impl Simple { + // @has - "$.index[*][?(@.name=='CONSTANT')].kind" \"assoc_const\" + pub const CONSTANT: usize = 0; +} + +pub trait EasyToImpl { + // @has - "$.index[*][?(@.name=='ToDeclare')].kind" \"assoc_type\" + // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default" null + type ToDeclare; + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].kind" \"assoc_const\" + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" null + const AN_ATTRIBUTE: usize; +} + +impl EasyToImpl for Simple { + // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default.kind" \"primitive\" + // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default.inner" \"usize\" + type ToDeclare = usize; + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.kind" \"primitive\" + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.inner" \"usize\" + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" \"12\" + const AN_ATTRIBUTE: usize = 12; +} diff --git a/src/test/rustdoc-json/assoc_type.rs b/src/test/rustdoc-json/assoc_type.rs new file mode 100644 index 000000000..716bb3d28 --- /dev/null +++ b/src/test/rustdoc-json/assoc_type.rs @@ -0,0 +1,22 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98547>. + +// @has assoc_type.json +// @has - "$.index[*][?(@.name=='Trait')]" +// @has - "$.index[*][?(@.name=='AssocType')]" +// @has - "$.index[*][?(@.name=='S')]" +// @has - "$.index[*][?(@.name=='S2')]" + +pub trait Trait { + type AssocType; +} + +impl<T> Trait for T { + type AssocType = Self; +} + +pub struct S; + +/// Not needed for the #98547 ICE to occur, but added to maximize the chance of +/// getting an ICE in the future. See +/// <https://github.com/rust-lang/rust/pull/98548#discussion_r908219164> +pub struct S2; diff --git a/src/test/rustdoc-json/blanket_impls.rs b/src/test/rustdoc-json/blanket_impls.rs new file mode 100644 index 000000000..edf1a9fe2 --- /dev/null +++ b/src/test/rustdoc-json/blanket_impls.rs @@ -0,0 +1,9 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98658> + +#![no_std] + +// @has blanket_impls.json +// @has - "$.index[*][?(@.name=='Error')].kind" \"assoc_type\" +// @has - "$.index[*][?(@.name=='Error')].inner.default.kind" \"resolved_path\" +// @has - "$.index[*][?(@.name=='Error')].inner.default.inner.name" \"Infallible\" +pub struct ForBlanketTryFromImpl; diff --git a/src/test/rustdoc-json/doc_hidden_failure.rs b/src/test/rustdoc-json/doc_hidden_failure.rs new file mode 100644 index 000000000..5c4ccf996 --- /dev/null +++ b/src/test/rustdoc-json/doc_hidden_failure.rs @@ -0,0 +1,22 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98007>. + +#![feature(no_core)] +#![no_core] + +mod auto { + mod action_row { + pub struct ActionRowBuilder; + } + + #[doc(hidden)] + pub mod builders { + pub use super::action_row::ActionRowBuilder; + } +} + +// @count doc_hidden_failure.json "$.index[*][?(@.name=='builders')]" 2 +pub use auto::*; + +pub mod builders { + pub use crate::auto::builders::*; +} diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs new file mode 100644 index 000000000..fcd92887c --- /dev/null +++ b/src/test/rustdoc-json/enums/variant_struct.rs @@ -0,0 +1,11 @@ +// @has variant_struct.json "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\" +pub enum EnumStruct { + // @has - "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\" + // @has - "$.index[*][?(@.name=='x')].kind" \"struct_field\" + // @has - "$.index[*][?(@.name=='y')].kind" \"struct_field\" + VariantS { + x: u32, + y: String, + }, +} diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs new file mode 100644 index 000000000..ac3e72e29 --- /dev/null +++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs @@ -0,0 +1,8 @@ +// @has variant_tuple_struct.json "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\" +pub enum EnumTupleStruct { + // @has - "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\" + // @has - "$.index[*][?(@.name=='0')].kind" \"struct_field\" + // @has - "$.index[*][?(@.name=='1')].kind" \"struct_field\" + VariantA(u32, String), +} diff --git a/src/test/rustdoc-json/fn_pointer/abi.rs b/src/test/rustdoc-json/fn_pointer/abi.rs new file mode 100644 index 000000000..eef20e60a --- /dev/null +++ b/src/test/rustdoc-json/fn_pointer/abi.rs @@ -0,0 +1,25 @@ +// ignore-tidy-linelength + +#![feature(abi_vectorcall)] +#![feature(c_unwind)] + +// @is abi.json "$.index[*][?(@.name=='AbiRust')].inner.type.inner.header.abi" \"Rust\" +pub type AbiRust = fn(); + +// @is - "$.index[*][?(@.name=='AbiC')].inner.type.inner.header.abi" '{"C": {"unwind": false}}' +pub type AbiC = extern "C" fn(); + +// @is - "$.index[*][?(@.name=='AbiSystem')].inner.type.inner.header.abi" '{"System": {"unwind": false}}' +pub type AbiSystem = extern "system" fn(); + +// @is - "$.index[*][?(@.name=='AbiCUnwind')].inner.type.inner.header.abi" '{"C": {"unwind": true}}' +pub type AbiCUnwind = extern "C-unwind" fn(); + +// @is - "$.index[*][?(@.name=='AbiSystemUnwind')].inner.type.inner.header.abi" '{"System": {"unwind": true}}' +pub type AbiSystemUnwind = extern "system-unwind" fn(); + +// @is - "$.index[*][?(@.name=='AbiVecorcall')].inner.type.inner.header.abi.Other" '"\"vectorcall\""' +pub type AbiVecorcall = extern "vectorcall" fn(); + +// @is - "$.index[*][?(@.name=='AbiVecorcallUnwind')].inner.type.inner.header.abi.Other" '"\"vectorcall-unwind\""' +pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn(); diff --git a/src/test/rustdoc-json/fn_pointer/generics.rs b/src/test/rustdoc-json/fn_pointer/generics.rs new file mode 100644 index 000000000..646f720e6 --- /dev/null +++ b/src/test/rustdoc-json/fn_pointer/generics.rs @@ -0,0 +1,14 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +// @count generics.json "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][0]" '"val"' +// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].inner.lifetime" \"\'c\" +// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.output" '{ "kind": "primitive", "inner": "i32" }' +// @count - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[*]" 1 +// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].name" \"\'c\" +// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +pub type WithHigherRankTraitBounds = for<'c> fn(val: &'c i32) -> i32; diff --git a/src/test/rustdoc-json/fn_pointer/qualifiers.rs b/src/test/rustdoc-json/fn_pointer/qualifiers.rs new file mode 100644 index 000000000..381922085 --- /dev/null +++ b/src/test/rustdoc-json/fn_pointer/qualifiers.rs @@ -0,0 +1,9 @@ +// @is qualifiers.json "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.unsafe" false +// @is - "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.const" false +// @is - "$.index[*][?(@.name=='FnPointer')].inner.type.inner.header.async" false +pub type FnPointer = fn(); + +// @is - "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.unsafe" true +// @is - "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.const" false +// @is - "$.index[*][?(@.name=='UnsafePointer')].inner.type.inner.header.async" false +pub type UnsafePointer = unsafe fn(); diff --git a/src/test/rustdoc-json/fns/abi.rs b/src/test/rustdoc-json/fns/abi.rs new file mode 100644 index 000000000..16b579130 --- /dev/null +++ b/src/test/rustdoc-json/fns/abi.rs @@ -0,0 +1,25 @@ +// ignore-tidy-linelength + +#![feature(abi_vectorcall)] +#![feature(c_unwind)] + +// @is abi.json "$.index[*][?(@.name=='abi_rust')].inner.header.abi" \"Rust\" +pub fn abi_rust() {} + +// @is - "$.index[*][?(@.name=='abi_c')].inner.header.abi" '{"C": {"unwind": false}}' +pub extern "C" fn abi_c() {} + +// @is - "$.index[*][?(@.name=='abi_system')].inner.header.abi" '{"System": {"unwind": false}}' +pub extern "system" fn abi_system() {} + +// @is - "$.index[*][?(@.name=='abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}' +pub extern "C-unwind" fn abi_c_unwind() {} + +// @is - "$.index[*][?(@.name=='abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}' +pub extern "system-unwind" fn abi_system_unwind() {} + +// @is - "$.index[*][?(@.name=='abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""' +pub extern "vectorcall" fn abi_vectorcall() {} + +// @is - "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""' +pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} diff --git a/src/test/rustdoc-json/fns/generic_args.rs b/src/test/rustdoc-json/fns/generic_args.rs new file mode 100644 index 000000000..69150443c --- /dev/null +++ b/src/test/rustdoc-json/fns/generic_args.rs @@ -0,0 +1,71 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +// @set foo = generic_args.json "$.index[*][?(@.name=='Foo')].id" +pub trait Foo {} + +// @set generic_foo = generic_args.json "$.index[*][?(@.name=='GenericFoo')].id" +pub trait GenericFoo<'a> {} + +// @is - "$.index[*][?(@.name=='generics')].inner.generics.where_predicates" "[]" +// @count - "$.index[*][?(@.name=='generics')].inner.generics.params[*]" 1 +// @is - "$.index[*][?(@.name=='generics')].inner.generics.params[0].name" '"F"' +// @is - "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.default" 'null' +// @count - "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.bounds[*]" 1 +// @is - "$.index[*][?(@.name=='generics')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" '$foo' +// @count - "$.index[*][?(@.name=='generics')].inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][0]" '"f"' +// @is - "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][1].kind" '"generic"' +// @is - "$.index[*][?(@.name=='generics')].inner.decl.inputs[0][1].inner" '"F"' +pub fn generics<F: Foo>(f: F) {} + +// @is - "$.index[*][?(@.name=='impl_trait')].inner.generics.where_predicates" "[]" +// @count - "$.index[*][?(@.name=='impl_trait')].inner.generics.params[*]" 1 +// @is - "$.index[*][?(@.name=='impl_trait')].inner.generics.params[0].name" '"impl Foo"' +// @is - "$.index[*][?(@.name=='impl_trait')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $foo +// @count - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][0]" '"f"' +// @is - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].kind" '"impl_trait"' +// @count - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].inner[*]" 1 +// @is - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.inner.id" $foo +pub fn impl_trait(f: impl Foo) {} + +// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.params[*]" 3 +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].name" '"F"' +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}' +// @count - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[*]" 3 +// @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][0]" '"f"' +// @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].kind" '"generic"' +// @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].inner" '"F"' +// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[*]" 3 + +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F", "kind": "generic"}' +// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[*]" 1 +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.inner.id" $foo + +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.type" '{"inner": "G", "kind": "generic"}' +// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[*]" 1 +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.inner.id" $generic_foo +// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1 +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\" +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.generic_params" "[]" + +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.lifetime" \"\'b\" +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.type" '{"inner": "H", "kind": "generic"}' +// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[*]" 1 +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.inner.id" $foo +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]" +// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[*]" 1 +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\" +// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +pub fn where_clase<F, G, H>(f: F, g: G, h: H) +where + F: Foo, + G: for<'a> GenericFoo<'a>, + for<'b> &'b H: Foo, +{ +} diff --git a/src/test/rustdoc-json/fns/generic_returns.rs b/src/test/rustdoc-json/fns/generic_returns.rs new file mode 100644 index 000000000..1a0f33fe3 --- /dev/null +++ b/src/test/rustdoc-json/fns/generic_returns.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +// @count generic_returns.json "$.index[*][?(@.name=='generic_returns')].inner.items[*]" 2 + +// @set foo = - "$.index[*][?(@.name=='Foo')].id" +pub trait Foo {} + +// @is - "$.index[*][?(@.name=='get_foo')].inner.decl.inputs" [] +// @is - "$.index[*][?(@.name=='get_foo')].inner.decl.output.kind" '"impl_trait"' +// @count - "$.index[*][?(@.name=='get_foo')].inner.decl.output.inner[*]" 1 +// @is - "$.index[*][?(@.name=='get_foo')].inner.decl.output.inner[0].trait_bound.trait.inner.id" $foo +pub fn get_foo() -> impl Foo { + Fooer {} +} + +struct Fooer {} + +impl Foo for Fooer {} diff --git a/src/test/rustdoc-json/fns/generics.rs b/src/test/rustdoc-json/fns/generics.rs new file mode 100644 index 000000000..e777fabaa --- /dev/null +++ b/src/test/rustdoc-json/fns/generics.rs @@ -0,0 +1,26 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +// @set wham_id = generics.json "$.index[*][?(@.name=='Wham')].id" +pub trait Wham {} + +// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.where_predicates" [] +// @count - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[*]" 1 +// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].name" '"T"' +// @has - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" false +// @has - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id +// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.decl.inputs" '[["w", {"inner": "T", "kind": "generic"}]]' +pub fn one_generic_param_fn<T: Wham>(w: T) {} + +// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.where_predicates" [] +// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[*]" 1 +// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].name" '"impl Wham"' +// @has - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" true +// @has - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id +// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][0]" '"w"' +// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].kind" '"impl_trait"' +// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.inner.id" $wham_id +pub fn one_synthetic_generic_param_fn(w: impl Wham) {} diff --git a/src/test/rustdoc-json/fns/qualifiers.rs b/src/test/rustdoc-json/fns/qualifiers.rs new file mode 100644 index 000000000..5cb3b43e6 --- /dev/null +++ b/src/test/rustdoc-json/fns/qualifiers.rs @@ -0,0 +1,33 @@ +// edition:2018 + +// @is qualifiers.json "$.index[*][?(@.name=='nothing_fn')].inner.header.async" false +// @is - "$.index[*][?(@.name=='nothing_fn')].inner.header.const" false +// @is - "$.index[*][?(@.name=='nothing_fn')].inner.header.unsafe" false +pub fn nothing_fn() {} + +// @is - "$.index[*][?(@.name=='unsafe_fn')].inner.header.async" false +// @is - "$.index[*][?(@.name=='unsafe_fn')].inner.header.const" false +// @is - "$.index[*][?(@.name=='unsafe_fn')].inner.header.unsafe" true +pub unsafe fn unsafe_fn() {} + +// @is - "$.index[*][?(@.name=='const_fn')].inner.header.async" false +// @is - "$.index[*][?(@.name=='const_fn')].inner.header.const" true +// @is - "$.index[*][?(@.name=='const_fn')].inner.header.unsafe" false +pub const fn const_fn() {} + +// @is - "$.index[*][?(@.name=='async_fn')].inner.header.async" true +// @is - "$.index[*][?(@.name=='async_fn')].inner.header.const" false +// @is - "$.index[*][?(@.name=='async_fn')].inner.header.unsafe" false +pub async fn async_fn() {} + +// @is - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.async" true +// @is - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.const" false +// @is - "$.index[*][?(@.name=='async_unsafe_fn')].inner.header.unsafe" true +pub async unsafe fn async_unsafe_fn() {} + +// @is - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.async" false +// @is - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.const" true +// @is - "$.index[*][?(@.name=='const_unsafe_fn')].inner.header.unsafe" true +pub const unsafe fn const_unsafe_fn() {} + +// It's impossible for a function to be both const and async, so no test for that diff --git a/src/test/rustdoc-json/generic-associated-types/gats.rs b/src/test/rustdoc-json/generic-associated-types/gats.rs new file mode 100644 index 000000000..368ff8d8d --- /dev/null +++ b/src/test/rustdoc-json/generic-associated-types/gats.rs @@ -0,0 +1,44 @@ +// ignore-tidy-linelength + +#![no_core] +#![feature(generic_associated_types, lang_items, no_core)] + +#[lang = "sized"] +pub trait Sized {} + +pub trait Display {} + +// @has gats.json +pub trait LendingIterator { + // @count - "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*]" 1 + // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*].name" \"\'a\" + // @count - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*]" 1 + // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.type.inner" \"Self\" + // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\" + // @count - "$.index[*][?(@.name=='LendingItem')].inner.bounds[*]" 1 + type LendingItem<'a>: Display + where + Self: 'a; + + // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.kind" \"qualified_path\" + // @count - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 1 + // @count - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0 + // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.self_type.inner" \"Self\" + // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.name" \"LendingItem\" + fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>; +} + +// @has gats.json +pub trait Iterator { + // @count - "$.index[*][?(@.name=='Item')].inner.generics.params[*]" 0 + // @count - "$.index[*][?(@.name=='Item')].inner.generics.where_predicates[*]" 0 + // @count - "$.index[*][?(@.name=='Item')].inner.bounds[*]" 1 + type Item: Display; + + // @is - "$.index[*][?(@.name=='next')].inner.decl.output.kind" \"qualified_path\" + // @count - "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 0 + // @count - "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0 + // @is - "$.index[*][?(@.name=='next')].inner.decl.output.inner.self_type.inner" \"Self\" + // @is - "$.index[*][?(@.name=='next')].inner.decl.output.inner.name" \"Item\" + fn next<'a>(&'a self) -> Self::Item; +} diff --git a/src/test/rustdoc-json/generic_impl.rs b/src/test/rustdoc-json/generic_impl.rs new file mode 100644 index 000000000..ac68ba578 --- /dev/null +++ b/src/test/rustdoc-json/generic_impl.rs @@ -0,0 +1,24 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/97986>. + +// @has generic_impl.json +// @has - "$.index[*][?(@.name=='f')]" +// @has - "$.index[*][?(@.name=='AssocTy')]" +// @has - "$.index[*][?(@.name=='AssocConst')]" + +pub mod m { + pub struct S; +} + +pub trait F { + type AssocTy; + const AssocConst: usize; + fn f() -> m::S; +} + +impl<T> F for T { + type AssocTy = u32; + const AssocConst: usize = 0; + fn f() -> m::S { + m::S + } +} diff --git a/src/test/rustdoc-json/glob_import.rs b/src/test/rustdoc-json/glob_import.rs new file mode 100644 index 000000000..d7ac952d1 --- /dev/null +++ b/src/test/rustdoc-json/glob_import.rs @@ -0,0 +1,24 @@ +// This is a regression test for <https://github.com/rust-lang/rust/issues/98003>. + +#![feature(no_core)] +#![no_std] +#![no_core] + +// @has glob_import.json +// @has - "$.index[*][?(@.name=='glob')]" +// @has - "$.index[*][?(@.kind=='import')].inner.name" \"*\" + + +mod m1 { + pub fn f() {} +} +mod m2 { + pub fn f(_: u8) {} +} + +pub use m1::*; +pub use m2::*; + +pub mod glob { + pub use *; +} diff --git a/src/test/rustdoc-json/impls/blanket_with_local.rs b/src/test/rustdoc-json/impls/blanket_with_local.rs new file mode 100644 index 000000000..a3d55b35f --- /dev/null +++ b/src/test/rustdoc-json/impls/blanket_with_local.rs @@ -0,0 +1,18 @@ +// Test for the ICE in rust/83718 +// A blanket impl plus a local type together shouldn't result in mismatched ID issues + +// @has blanket_with_local.json "$.index[*][?(@.name=='Load')]" +pub trait Load { + // @has - "$.index[*][?(@.name=='load')]" + fn load() {} + // @has - "$.index[*][?(@.name=='write')]" + fn write(self) {} +} + +impl<P> Load for P { + fn load() {} + fn write(self) {} +} + +// @has - "$.index[*][?(@.name=='Wrapper')]" +pub struct Wrapper {} diff --git a/src/test/rustdoc-json/keyword.rs b/src/test/rustdoc-json/keyword.rs new file mode 100644 index 000000000..78a843aca --- /dev/null +++ b/src/test/rustdoc-json/keyword.rs @@ -0,0 +1,21 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98002>. + +// Keywords should not be generated in rustdoc JSON output and this test +// ensures it. + +#![feature(rustdoc_internals)] +#![no_std] + +// @has keyword.json +// @!has - "$.index[*][?(@.name=='match')]" +// @has - "$.index[*][?(@.name=='foo')]" + +#[doc(keyword = "match")] +/// this is a test! +pub mod foo {} + +// @!has - "$.index[*][?(@.name=='hello')]" +// @!has - "$.index[*][?(@.name=='bar')]" +#[doc(keyword = "hello")] +/// hello +mod bar {} diff --git a/src/test/rustdoc-json/lifetime/longest.rs b/src/test/rustdoc-json/lifetime/longest.rs new file mode 100644 index 000000000..95b99599e --- /dev/null +++ b/src/test/rustdoc-json/lifetime/longest.rs @@ -0,0 +1,33 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +// @is longest.json "$.index[*][?(@.name=='longest')].inner.generics.params[0].name" \"\'a\" +// @is - "$.index[*][?(@.name=='longest')].inner.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +// @is - "$.index[*][?(@.name=='longest')].inner.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +// @count - "$.index[*][?(@.name=='longest')].inner.generics.params[*]" 1 +// @is - "$.index[*][?(@.name=='longest')].inner.generics.where_predicates" [] + +// @count - "$.index[*][?(@.name=='longest')].inner.decl.inputs[*]" 2 +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][0]" '"l"' +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][0]" '"r"' + +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.mutable" false +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[0][1].inner.type" '{"inner": "str", "kind": "primitive"}' + +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.mutable" false +// @is - "$.index[*][?(@.name=='longest')].inner.decl.inputs[1][1].inner.type" '{"inner": "str", "kind": "primitive"}' + +// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.inner.mutable" false +// @is - "$.index[*][?(@.name=='longest')].inner.decl.output.inner.type" '{"inner": "str", "kind": "primitive"}' + +pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str { + if l.len() > r.len() { l } else { r } +} diff --git a/src/test/rustdoc-json/lifetime/outlives.rs b/src/test/rustdoc-json/lifetime/outlives.rs new file mode 100644 index 000000000..096dd7f7a --- /dev/null +++ b/src/test/rustdoc-json/lifetime/outlives.rs @@ -0,0 +1,23 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +// @count outlives.json "$.index[*][?(@.name=='foo')].inner.generics.params[*]" 3 +// @is - "$.index[*][?(@.name=='foo')].inner.generics.where_predicates" [] +// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[0].name" \"\'a\" +// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[1].name" \"\'b\" +// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[2].name" '"T"' +// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[0].kind.lifetime.outlives" [] +// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[1].kind.lifetime.outlives" [\"\'a\"] +// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.default" null +// @count - "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.bounds[*]" 1 +// @is - "$.index[*][?(@.name=='foo')].inner.generics.params[2].kind.type.bounds[0].outlives" \"\'b\" +// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.mutable" false +// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.lifetime" \"\'b\" +// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.mutable" false +// @is - "$.index[*][?(@.name=='foo')].inner.decl.inputs[0][1].inner.type.inner.type" '{"inner": "T", "kind": "generic"}' +pub fn foo<'a, 'b: 'a, T: 'b>(_: &'a &'b T) {} diff --git a/src/test/rustdoc-json/methods/abi.rs b/src/test/rustdoc-json/methods/abi.rs new file mode 100644 index 000000000..07b01d03b --- /dev/null +++ b/src/test/rustdoc-json/methods/abi.rs @@ -0,0 +1,55 @@ +// ignore-tidy-linelength + +#![feature(abi_vectorcall)] +#![feature(c_unwind)] +#![feature(no_core)] +#![no_core] + +// @has abi.json "$.index[*][?(@.name=='Foo')]" +pub struct Foo; + +impl Foo { + // @is - "$.index[*][?(@.name=='abi_rust')].inner.header.abi" \"Rust\" + pub fn abi_rust() {} + + // @is - "$.index[*][?(@.name=='abi_c')].inner.header.abi" '{"C": {"unwind": false}}' + pub extern "C" fn abi_c() {} + + // @is - "$.index[*][?(@.name=='abi_system')].inner.header.abi" '{"System": {"unwind": false}}' + pub extern "system" fn abi_system() {} + + // @is - "$.index[*][?(@.name=='abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}' + pub extern "C-unwind" fn abi_c_unwind() {} + + // @is - "$.index[*][?(@.name=='abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}' + pub extern "system-unwind" fn abi_system_unwind() {} + + // @is - "$.index[*][?(@.name=='abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""' + pub extern "vectorcall" fn abi_vectorcall() {} + + // @is - "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""' + pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} +} + +pub trait Bar { + // @is - "$.index[*][?(@.name=='trait_abi_rust')].inner.header.abi" \"Rust\" + fn trait_abi_rust() {} + + // @is - "$.index[*][?(@.name=='trait_abi_c')].inner.header.abi" '{"C": {"unwind": false}}' + extern "C" fn trait_abi_c() {} + + // @is - "$.index[*][?(@.name=='trait_abi_system')].inner.header.abi" '{"System": {"unwind": false}}' + extern "system" fn trait_abi_system() {} + + // @is - "$.index[*][?(@.name=='trait_abi_c_unwind')].inner.header.abi" '{"C": {"unwind": true}}' + extern "C-unwind" fn trait_abi_c_unwind() {} + + // @is - "$.index[*][?(@.name=='trait_abi_system_unwind')].inner.header.abi" '{"System": {"unwind": true}}' + extern "system-unwind" fn trait_abi_system_unwind() {} + + // @is - "$.index[*][?(@.name=='trait_abi_vectorcall')].inner.header.abi.Other" '"\"vectorcall\""' + extern "vectorcall" fn trait_abi_vectorcall() {} + + // @is - "$.index[*][?(@.name=='trait_abi_vectorcall_unwind')].inner.header.abi.Other" '"\"vectorcall-unwind\""' + extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} +} diff --git a/src/test/rustdoc-json/methods/qualifiers.rs b/src/test/rustdoc-json/methods/qualifiers.rs new file mode 100644 index 000000000..af36d36b6 --- /dev/null +++ b/src/test/rustdoc-json/methods/qualifiers.rs @@ -0,0 +1,37 @@ +// edition:2018 + +pub struct Foo; + +impl Foo { + // @is qualifiers.json "$.index[*][?(@.name=='const_meth')].inner.header.async" false + // @is - "$.index[*][?(@.name=='const_meth')].inner.header.const" true + // @is - "$.index[*][?(@.name=='const_meth')].inner.header.unsafe" false + pub const fn const_meth() {} + + // @is - "$.index[*][?(@.name=='nothing_meth')].inner.header.async" false + // @is - "$.index[*][?(@.name=='nothing_meth')].inner.header.const" false + // @is - "$.index[*][?(@.name=='nothing_meth')].inner.header.unsafe" false + pub fn nothing_meth() {} + + // @is - "$.index[*][?(@.name=='unsafe_meth')].inner.header.async" false + // @is - "$.index[*][?(@.name=='unsafe_meth')].inner.header.const" false + // @is - "$.index[*][?(@.name=='unsafe_meth')].inner.header.unsafe" true + pub unsafe fn unsafe_meth() {} + + // @is - "$.index[*][?(@.name=='async_meth')].inner.header.async" true + // @is - "$.index[*][?(@.name=='async_meth')].inner.header.const" false + // @is - "$.index[*][?(@.name=='async_meth')].inner.header.unsafe" false + pub async fn async_meth() {} + + // @is - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.async" true + // @is - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.const" false + // @is - "$.index[*][?(@.name=='async_unsafe_meth')].inner.header.unsafe" true + pub async unsafe fn async_unsafe_meth() {} + + // @is - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.async" false + // @is - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.const" true + // @is - "$.index[*][?(@.name=='const_unsafe_meth')].inner.header.unsafe" true + pub const unsafe fn const_unsafe_meth() {} + + // It's impossible for a method to be both const and async, so no test for that +} diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs new file mode 100644 index 000000000..b0e717d8a --- /dev/null +++ b/src/test/rustdoc-json/nested.rs @@ -0,0 +1,30 @@ +// edition:2018 +// compile-flags: --crate-version 1.0.0 + +// @is nested.json "$.crate_version" \"1.0.0\" +// @is - "$.index[*][?(@.name=='nested')].kind" \"module\" +// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true +// @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1 + +// @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\" +// @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false +// @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2 +pub mod l1 { + + // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\" + // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false + // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1 + // @set l3_id = - "$.index[*][?(@.name=='l3')].id" + // @has - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id + pub mod l3 { + + // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\" + // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" + // @set l4_id = - "$.index[*][?(@.name=='L4')].id" + // @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id + pub struct L4; + } + // @is nested.json "$.index[*][?(@.inner.source=='l3::L4')].kind" \"import\" + // @is - "$.index[*][?(@.inner.source=='l3::L4')].inner.glob" false + pub use l3::L4; +} diff --git a/src/test/rustdoc-json/output_generics.rs b/src/test/rustdoc-json/output_generics.rs new file mode 100644 index 000000000..d80656c7f --- /dev/null +++ b/src/test/rustdoc-json/output_generics.rs @@ -0,0 +1,38 @@ +// compile-flags: --document-private-items --document-hidden-items + +// This is a regression test for #98009. + +// @has output_generics.json +// @has - "$.index[*][?(@.name=='this_compiles')]" +// @has - "$.index[*][?(@.name=='this_does_not')]" +// @has - "$.index[*][?(@.name=='Events')]" +// @has - "$.index[*][?(@.name=='Other')]" +// @has - "$.index[*][?(@.name=='Trait')]" + +struct Events<R>(R); + +struct Other; + +pub trait Trait<T> { + fn handle(value: T) -> Self; +} + +impl<T, U> Trait<U> for T where T: From<U> { + fn handle(_: U) -> Self { unimplemented!() } +} + +impl<'a, R> Trait<&'a mut Events<R>> for Other { + fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() } +} + +fn this_compiles<'a, R>(value: &'a mut Events<R>) { + for _ in 0..3 { + Other::handle(&mut *value); + } +} + +fn this_does_not<'a, R>(value: &'a mut Events<R>) { + for _ in 0..3 { + Other::handle(value); + } +} diff --git a/src/test/rustdoc-json/primitive.rs b/src/test/rustdoc-json/primitive.rs new file mode 100644 index 000000000..b84c2f7c6 --- /dev/null +++ b/src/test/rustdoc-json/primitive.rs @@ -0,0 +1,14 @@ +// edition:2018 + +#![feature(rustdoc_internals)] + +#[doc(primitive = "usize")] +mod usize {} + +// @set local_crate_id = primitive.json "$.index[*][?(@.name=='primitive')].crate_id" + +// @has - "$.index[*][?(@.name=='log10')]" +// @!is - "$.index[*][?(@.name=='log10')].crate_id" $local_crate_id +// @has - "$.index[*][?(@.name=='checked_add')]" +// @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id +// @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]" diff --git a/src/test/rustdoc-json/primitive_overloading.rs b/src/test/rustdoc-json/primitive_overloading.rs new file mode 100644 index 000000000..a10d5a837 --- /dev/null +++ b/src/test/rustdoc-json/primitive_overloading.rs @@ -0,0 +1,17 @@ +// compile-flags: --document-private-items + +// Regression test for <https://github.com/rust-lang/rust/issues/98006>. + +#![feature(rustdoc_internals)] +#![feature(no_core)] + +#![no_core] + +// @has primitive_overloading.json +// @has - "$.index[*][?(@.name=='usize')]" +// @has - "$.index[*][?(@.name=='prim')]" + +#[doc(primitive = "usize")] +/// This is the built-in type `usize`. +mod prim { +} diff --git a/src/test/rustdoc-json/primitives.rs b/src/test/rustdoc-json/primitives.rs new file mode 100644 index 000000000..fd04f04da --- /dev/null +++ b/src/test/rustdoc-json/primitives.rs @@ -0,0 +1,22 @@ +#![feature(never_type)] + +// @has primitives.json "$.index[*][?(@.name=='PrimNever')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='PrimNever')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimNever')].inner.type.inner" \"never\" +pub type PrimNever = !; + +// @has - "$.index[*][?(@.name=='PrimStr')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimStr')].inner.type.inner" \"str\" +pub type PrimStr = str; + +// @has - "$.index[*][?(@.name=='PrimBool')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimBool')].inner.type.inner" \"bool\" +pub type PrimBool = bool; + +// @has - "$.index[*][?(@.name=='PrimChar')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimChar')].inner.type.inner" \"char\" +pub type PrimChar = char; + +// @has - "$.index[*][?(@.name=='PrimU8')].inner.type.kind" \"primitive\" +// @has - "$.index[*][?(@.name=='PrimU8')].inner.type.inner" \"u8\" +pub type PrimU8 = u8; diff --git a/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs b/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs new file mode 100644 index 000000000..4a835673a --- /dev/null +++ b/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/src/test/rustdoc-json/reexport/glob_extern.rs b/src/test/rustdoc-json/reexport/glob_extern.rs new file mode 100644 index 000000000..ba1cfd8a0 --- /dev/null +++ b/src/test/rustdoc-json/reexport/glob_extern.rs @@ -0,0 +1,18 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] + +// @is glob_extern.json "$.index[*][?(@.name=='mod1')].kind" \"module\" +// @is glob_extern.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true" +mod mod1 { + extern "C" { + // @has - "$.index[*][?(@.name=='public_fn')].id" + pub fn public_fn(); + // @!has - "$.index[*][?(@.name=='private_fn')]" + fn private_fn(); + } +} + +// @is - "$.index[*][?(@.kind=='import')].inner.glob" true +pub use mod1::*; diff --git a/src/test/rustdoc-json/reexport/glob_private.rs b/src/test/rustdoc-json/reexport/glob_private.rs new file mode 100644 index 000000000..e6a44748c --- /dev/null +++ b/src/test/rustdoc-json/reexport/glob_private.rs @@ -0,0 +1,32 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] + +// @is glob_private.json "$.index[*][?(@.name=='mod1')].kind" \"module\" +// @is glob_private.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true" +mod mod1 { + // @is - "$.index[*][?(@.name=='mod2')].kind" \"module\" + // @is - "$.index[*][?(@.name=='mod2')].inner.is_stripped" "true" + mod mod2 { + // @set m2pub_id = - "$.index[*][?(@.name=='Mod2Public')].id" + pub struct Mod2Public; + + // @!has - "$.index[*][?(@.name=='Mod2Private')]" + struct Mod2Private; + } + + // @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')]" + pub use self::mod2::*; + + // @set m1pub_id = - "$.index[*][?(@.name=='Mod1Public')].id" + pub struct Mod1Public; + // @!has - "$.index[*][?(@.name=='Mod1Private')]" + struct Mod1Private; +} + +// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')]" +pub use mod1::*; + +// @has - "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id +// @has - "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod.rs b/src/test/rustdoc-json/reexport/in_root_and_mod.rs new file mode 100644 index 000000000..7bf10a986 --- /dev/null +++ b/src/test/rustdoc-json/reexport/in_root_and_mod.rs @@ -0,0 +1,17 @@ +#![feature(no_core)] +#![no_core] + +// @is in_root_and_mod.json "$.index[*][?(@.name=='foo')].kind" \"module\" +// @is in_root_and_mod.json "$.index[*][?(@.name=='foo')].inner.is_stripped" "true" +mod foo { + // @has - "$.index[*][?(@.name=='Foo')]" + pub struct Foo; +} + +// @has - "$.index[*][?(@.kind=='import' && @.inner.source=='foo::Foo')]" +pub use foo::Foo; + +pub mod bar { + // @has - "$.index[*][?(@.kind=='import' && @.inner.source=='crate::foo::Foo')]" + pub use crate::foo::Foo; +} diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs new file mode 100644 index 000000000..2daadf762 --- /dev/null +++ b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs @@ -0,0 +1,20 @@ +#![feature(no_core)] +#![no_core] + +pub mod foo { + // @set bar_id = in_root_and_mod_pub.json "$.index[*][?(@.name=='Bar')].id" + // @has - "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id + pub struct Bar; +} + +// @set root_import_id = - "$.index[*][?(@.inner.source=='foo::Bar')].id" +// @is - "$.index[*][?(@.inner.source=='foo::Bar')].inner.id" $bar_id +// @has - "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.items[*]" $root_import_id +pub use foo::Bar; + +pub mod baz { + // @set baz_import_id = - "$.index[*][?(@.inner.source=='crate::foo::Bar')].id" + // @is - "$.index[*][?(@.inner.source=='crate::foo::Bar')].inner.id" $bar_id + // @has - "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id + pub use crate::foo::Bar; +} diff --git a/src/test/rustdoc-json/reexport/macro.rs b/src/test/rustdoc-json/reexport/macro.rs new file mode 100644 index 000000000..b86614ffb --- /dev/null +++ b/src/test/rustdoc-json/reexport/macro.rs @@ -0,0 +1,17 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] + +// @count macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" 2 + +// @set repro_id = macro.json "$.index[*][?(@.name=='repro')].id" +// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id +#[macro_export] +macro_rules! repro { + () => {}; +} + +// @set repro2_id = macro.json "$.index[*][?(@.inner.name=='repro2')].id" +// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro2_id +pub use crate::repro as repro2; diff --git a/src/test/rustdoc-json/reexport/private_twice_one_inline.rs b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs new file mode 100644 index 000000000..327b0f45f --- /dev/null +++ b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs @@ -0,0 +1,18 @@ +// aux-build:pub-struct.rs + +// Test for the ICE in rust/83057 +// Am external type re-exported with different attributes shouldn't cause an error + +#![no_core] +#![feature(no_core)] + +extern crate pub_struct as foo; + +#[doc(inline)] +pub use foo::Foo; + +pub mod bar { + pub use foo::Foo; +} + +// @count private_twice_one_inline.json "$.index[*][?(@.kind=='import')]" 2 diff --git a/src/test/rustdoc-json/reexport/private_two_names.rs b/src/test/rustdoc-json/reexport/private_two_names.rs new file mode 100644 index 000000000..36d6a50d3 --- /dev/null +++ b/src/test/rustdoc-json/reexport/private_two_names.rs @@ -0,0 +1,17 @@ +// Test for the ICE in rust/83720 +// A pub-in-private type re-exported under two different names shouldn't cause an error + +#![no_core] +#![feature(no_core)] + +// @is private_two_names.json "$.index[*][?(@.name=='style')].kind" \"module\" +// @is private_two_names.json "$.index[*][?(@.name=='style')].inner.is_stripped" "true" +mod style { + // @has - "$.index[*](?(@.name=='Color'))" + pub struct Color; +} + +// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')]" +pub use style::Color; +// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')]" +pub use style::Color as Colour; diff --git a/src/test/rustdoc-json/reexport/rename_private.rs b/src/test/rustdoc-json/reexport/rename_private.rs new file mode 100644 index 000000000..2476399bd --- /dev/null +++ b/src/test/rustdoc-json/reexport/rename_private.rs @@ -0,0 +1,14 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] + +// @is rename_private.json "$.index[*][?(@.name=='inner')].kind" \"module\" +// @is rename_private.json "$.index[*][?(@.name=='inner')].inner.is_stripped" "true" +mod inner { + // @has - "$.index[*][?(@.name=='Public')]" + pub struct Public; +} + +// @is - "$.index[*][?(@.kind=='import')].inner.name" \"NewName\" +pub use inner::Public as NewName; diff --git a/src/test/rustdoc-json/reexport/rename_public.rs b/src/test/rustdoc-json/reexport/rename_public.rs new file mode 100644 index 000000000..2dd438d22 --- /dev/null +++ b/src/test/rustdoc-json/reexport/rename_public.rs @@ -0,0 +1,17 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] + +// @set inner_id = rename_public.json "$.index[*][?(@.name=='inner')].id" +// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $inner_id +pub mod inner { + // @set public_id = - "$.index[*][?(@.name=='Public')].id" + // @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id + pub struct Public; +} +// @set import_id = - "$.index[*][?(@.inner.name=='NewName')].id" +// @!has - "$.index[*][?(@.inner.name=='Public')]" +// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $import_id +// @is - "$.index[*][?(@.inner.name=='NewName')].inner.source" \"inner::Public\" +pub use inner::Public as NewName; diff --git a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs new file mode 100644 index 000000000..eedddd6a7 --- /dev/null +++ b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs @@ -0,0 +1,15 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/97432>. + +#![feature(no_core)] +#![no_std] +#![no_core] + +// @has same_type_reexported_more_than_once.json +// @has - "$.index[*][?(@.name=='Trait')]" +pub use inner::Trait; +// @has - "$.index[*].inner[?(@.name=='Reexport')].id" +pub use inner::Trait as Reexport; + +mod inner { + pub trait Trait {} +} diff --git a/src/test/rustdoc-json/reexport/simple_private.rs b/src/test/rustdoc-json/reexport/simple_private.rs new file mode 100644 index 000000000..5ec13e403 --- /dev/null +++ b/src/test/rustdoc-json/reexport/simple_private.rs @@ -0,0 +1,15 @@ +// edition:2018 +#![no_core] +#![feature(no_core)] + +// @is simple_private.json "$.index[*][?(@.name=='inner')].kind" \"module\" +// @is simple_private.json "$.index[*][?(@.name=='inner')].inner.is_stripped" "true" +mod inner { + // @set pub_id = - "$.index[*][?(@.name=='Public')].id" + pub struct Public; +} + +// @is - "$.index[*][?(@.kind=='import')].inner.name" \"Public\" +pub use inner::Public; + +// @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id diff --git a/src/test/rustdoc-json/reexport/simple_public.rs b/src/test/rustdoc-json/reexport/simple_public.rs new file mode 100644 index 000000000..2e4de301f --- /dev/null +++ b/src/test/rustdoc-json/reexport/simple_public.rs @@ -0,0 +1,18 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] + +// @set inner_id = simple_public.json "$.index[*][?(@.name=='inner')].id" +// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $inner_id +pub mod inner { + + // @set public_id = - "$.index[*][?(@.name=='Public')].id" + // @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id + pub struct Public; +} + +// @set import_id = - "$.index[*][?(@.inner.name=='Public')].id" +// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $import_id +// @is - "$.index[*][?(@.inner.name=='Public')].inner.source" \"inner::Public\" +pub use inner::Public; diff --git a/src/test/rustdoc-json/return_private.rs b/src/test/rustdoc-json/return_private.rs new file mode 100644 index 000000000..6b324d009 --- /dev/null +++ b/src/test/rustdoc-json/return_private.rs @@ -0,0 +1,15 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/96161>. +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +mod secret { + pub struct Secret; +} + +// @is return_private.json "$.index[*][?(@.name=='get_secret')].kind" \"function\" +// @is return_private.json "$.index[*][?(@.name=='get_secret')].inner.decl.output.inner.name" \"secret::Secret\" +pub fn get_secret() -> secret::Secret { + secret::Secret +} diff --git a/src/test/rustdoc-json/stripped_modules.rs b/src/test/rustdoc-json/stripped_modules.rs new file mode 100644 index 000000000..91f9f02ad --- /dev/null +++ b/src/test/rustdoc-json/stripped_modules.rs @@ -0,0 +1,21 @@ +#![no_core] +#![feature(no_core)] + +// @!has stripped_modules.json "$.index[*][?(@.name=='no_pub_inner')]" +mod no_pub_inner { + fn priv_inner() {} +} + +// @!has - "$.index[*][?(@.name=='pub_inner_unreachable')]" +mod pub_inner_unreachable { + // @!has - "$.index[*][?(@.name=='pub_inner_1')]" + pub fn pub_inner_1() {} +} + +// @has - "$.index[*][?(@.name=='pub_inner_reachable')]" +mod pub_inner_reachable { + // @has - "$.index[*][?(@.name=='pub_inner_2')]" + pub fn pub_inner_2() {} +} + +pub use pub_inner_reachable::pub_inner_2; diff --git a/src/test/rustdoc-json/structs/plain_empty.rs b/src/test/rustdoc-json/structs/plain_empty.rs new file mode 100644 index 000000000..a251caf4b --- /dev/null +++ b/src/test/rustdoc-json/structs/plain_empty.rs @@ -0,0 +1,6 @@ +// @has plain_empty.json "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\" +// @has - "$.index[*][?(@.name=='PlainEmpty')].inner.struct_type" \"plain\" +// @has - "$.index[*][?(@.name=='PlainEmpty')].inner.fields_stripped" false +// @has - "$.index[*][?(@.name=='PlainEmpty')].inner.fields" [] +pub struct PlainEmpty {} diff --git a/src/test/rustdoc-json/structs/tuple.rs b/src/test/rustdoc-json/structs/tuple.rs new file mode 100644 index 000000000..4e510b398 --- /dev/null +++ b/src/test/rustdoc-json/structs/tuple.rs @@ -0,0 +1,5 @@ +// @has tuple.json "$.index[*][?(@.name=='Tuple')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Tuple')].kind" \"struct\" +// @has - "$.index[*][?(@.name=='Tuple')].inner.struct_type" \"tuple\" +// @has - "$.index[*][?(@.name=='Tuple')].inner.fields_stripped" true +pub struct Tuple(u32, String); diff --git a/src/test/rustdoc-json/structs/unit.rs b/src/test/rustdoc-json/structs/unit.rs new file mode 100644 index 000000000..559d3068d --- /dev/null +++ b/src/test/rustdoc-json/structs/unit.rs @@ -0,0 +1,5 @@ +// @has unit.json "$.index[*][?(@.name=='Unit')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Unit')].kind" \"struct\" +// @has - "$.index[*][?(@.name=='Unit')].inner.struct_type" \"unit\" +// @has - "$.index[*][?(@.name=='Unit')].inner.fields" [] +pub struct Unit; diff --git a/src/test/rustdoc-json/structs/with_generics.rs b/src/test/rustdoc-json/structs/with_generics.rs new file mode 100644 index 000000000..65cfe7eff --- /dev/null +++ b/src/test/rustdoc-json/structs/with_generics.rs @@ -0,0 +1,14 @@ +use std::collections::HashMap; + +// @has with_generics.json "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\" +// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\" +// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type" +// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\" +// @has - "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type" +// @has - "$.index[*][?(@.name=='WithGenerics')].inner.struct_type" \"plain\" +// @has - "$.index[*][?(@.name=='WithGenerics')].inner.fields_stripped" true +pub struct WithGenerics<T, U> { + stuff: Vec<T>, + things: HashMap<U, U>, +} diff --git a/src/test/rustdoc-json/structs/with_primitives.rs b/src/test/rustdoc-json/structs/with_primitives.rs new file mode 100644 index 000000000..9e64317ec --- /dev/null +++ b/src/test/rustdoc-json/structs/with_primitives.rs @@ -0,0 +1,10 @@ +// @has with_primitives.json "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\" +// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\" +// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" [] +// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\" +// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true +pub struct WithPrimitives<'a> { + num: u32, + s: &'a str, +} diff --git a/src/test/rustdoc-json/traits/has_body.rs b/src/test/rustdoc-json/traits/has_body.rs new file mode 100644 index 000000000..44dacb1ee --- /dev/null +++ b/src/test/rustdoc-json/traits/has_body.rs @@ -0,0 +1,21 @@ +// @has has_body.json "$.index[*][?(@.name=='Foo')]" +pub trait Foo { + // @has - "$.index[*][?(@.name=='no_self')].inner.has_body" false + fn no_self(); + // @has - "$.index[*][?(@.name=='move_self')].inner.has_body" false + fn move_self(self); + // @has - "$.index[*][?(@.name=='ref_self')].inner.has_body" false + fn ref_self(&self); + + // @has - "$.index[*][?(@.name=='no_self_def')].inner.has_body" true + fn no_self_def() {} + // @has - "$.index[*][?(@.name=='move_self_def')].inner.has_body" true + fn move_self_def(self) {} + // @has - "$.index[*][?(@.name=='ref_self_def')].inner.has_body" true + fn ref_self_def(&self) {} +} + +pub trait Bar: Clone { + // @has - "$.index[*][?(@.name=='method')].inner.has_body" false + fn method(&self, param: usize); +} diff --git a/src/test/rustdoc-json/traits/implementors.rs b/src/test/rustdoc-json/traits/implementors.rs new file mode 100644 index 000000000..f7f03d987 --- /dev/null +++ b/src/test/rustdoc-json/traits/implementors.rs @@ -0,0 +1,19 @@ +#![feature(no_core)] +#![no_core] + +// @set wham = implementors.json "$.index[*][?(@.name=='Wham')].id" +// @count - "$.index[*][?(@.name=='Wham')].inner.implementations[*]" 1 +// @set gmWham = - "$.index[*][?(@.name=='Wham')].inner.implementations[0]" +pub trait Wham {} + +// @count - "$.index[*][?(@.name=='GeorgeMichael')].inner.impls[*]" 1 +// @is - "$.index[*][?(@.name=='GeorgeMichael')].inner.impls[0]" $gmWham +// @set gm = - "$.index[*][?(@.name=='Wham')].id" + +// jsonpath_lib isnt expressive enough (for now) to get the "impl" item, so we +// just check it isn't pointing to the type, but when you port to jsondocck-ng +// check what the impl item is +// @!is - "$.index[*][?(@.name=='Wham')].inner.implementations[0]" $gm +pub struct GeorgeMichael {} + +impl Wham for GeorgeMichael {} diff --git a/src/test/rustdoc-json/traits/supertrait.rs b/src/test/rustdoc-json/traits/supertrait.rs new file mode 100644 index 000000000..486a8e713 --- /dev/null +++ b/src/test/rustdoc-json/traits/supertrait.rs @@ -0,0 +1,26 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![feature(lang_items)] +#![no_core] + +// @set loud_id = supertrait.json "$.index[*][?(@.name=='Loud')].id" +pub trait Loud {} + +// @set very_loud_id = - "$.index[*][?(@.name=='VeryLoud')].id" +// @count - "$.index[*][?(@.name=='VeryLoud')].inner.bounds[*]" 1 +// @is - "$.index[*][?(@.name=='VeryLoud')].inner.bounds[0].trait_bound.trait.inner.id" $loud_id +pub trait VeryLoud: Loud {} + +// @set sounds_good_id = - "$.index[*][?(@.name=='SoundsGood')].id" +pub trait SoundsGood {} + +// @count - "$.index[*][?(@.name=='MetalBand')].inner.bounds[*]" 2 +// @is - "$.index[*][?(@.name=='MetalBand')].inner.bounds[0].trait_bound.trait.inner.id" $very_loud_id +// @is - "$.index[*][?(@.name=='MetalBand')].inner.bounds[1].trait_bound.trait.inner.id" $sounds_good_id +pub trait MetalBand: VeryLoud + SoundsGood {} + +// @count - "$.index[*][?(@.name=='DnabLatem')].inner.bounds[*]" 2 +// @is - "$.index[*][?(@.name=='DnabLatem')].inner.bounds[1].trait_bound.trait.inner.id" $very_loud_id +// @is - "$.index[*][?(@.name=='DnabLatem')].inner.bounds[0].trait_bound.trait.inner.id" $sounds_good_id +pub trait DnabLatem: SoundsGood + VeryLoud {} diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs new file mode 100644 index 000000000..f53dc03f4 --- /dev/null +++ b/src/test/rustdoc-json/type/dyn.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1 +// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id" +// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen + +// @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" [] +// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1 +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\" +// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3 +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' +pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>; diff --git a/src/test/rustdoc-json/type/fn_lifetime.rs b/src/test/rustdoc-json/type/fn_lifetime.rs new file mode 100644 index 000000000..e0d1e9649 --- /dev/null +++ b/src/test/rustdoc-json/type/fn_lifetime.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength + +// @is fn_lifetime.json "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\" + +// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*]" 1 +// @is - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\" +// @has - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime" +// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0 +// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0 +// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.kind" \"function_pointer\" +// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.generic_params[*]" 0 +// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.output.inner.lifetime" \"\'a\" + +pub type GenericFn<'a> = fn(&'a i32) -> &'a i32; + +// @is fn_lifetime.json "$.index[*][?(@.name=='ForAll')].kind" \"typedef\" +// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.params[*]" 0 +// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.where_predicates[*]" 0 +// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*]" 1 +// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].name" \"\'a\" +// @has - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime" +// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime.outlives[*]" 0 +// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*]" 1 +// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\" +// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.output.inner.lifetime" \"\'a\" +pub type ForAll = for<'a> fn(&'a i32) -> &'a i32; diff --git a/src/test/rustdoc-json/type/generic_default.rs b/src/test/rustdoc-json/type/generic_default.rs new file mode 100644 index 000000000..b6bb6dcc5 --- /dev/null +++ b/src/test/rustdoc-json/type/generic_default.rs @@ -0,0 +1,33 @@ +// ignore-tidy-linelength + +// @set result = generic_default.json "$.index[*][?(@.name=='Result')].id" +pub enum Result<T, E> { + Ok(T), + Err(E), +} + +// @set my_error = - "$.index[*][?(@.name=='MyError')].id" +pub struct MyError {} + +// @is - "$.index[*][?(@.name=='MyResult')].kind" \"typedef\" +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.where_predicates[*]" 0 +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[*]" 2 +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].name" \"T\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].name" \"E\" +// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type" +// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type" +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.bounds[*]" 0 +// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.bounds[*]" 0 +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.default" null +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.id" $my_error +// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.name" \"MyError\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.kind" \"resolved_path\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.id" $result +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.name" \"Result\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.bindings" [] +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"generic\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.kind" \"generic\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.inner" \"T\" +// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.inner" \"E\" +pub type MyResult<T, E = MyError> = Result<T, E>; diff --git a/src/test/rustdoc-json/unions/impl.rs b/src/test/rustdoc-json/unions/impl.rs new file mode 100644 index 000000000..0388b4a8c --- /dev/null +++ b/src/test/rustdoc-json/unions/impl.rs @@ -0,0 +1,15 @@ +#![no_std] + +// @has impl.json "$.index[*][?(@.name=='Ux')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Ux')].kind" \"union\" +pub union Ux { + a: u32, + b: u64 +} + +// @has - "$.index[*][?(@.name=='Num')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Num')].kind" \"trait\" +pub trait Num {} + +// @count - "$.index[*][?(@.name=='Ux')].inner.impls" 1 +impl Num for Ux {} diff --git a/src/test/rustdoc-json/unions/union.rs b/src/test/rustdoc-json/unions/union.rs new file mode 100644 index 000000000..ac2eb7977 --- /dev/null +++ b/src/test/rustdoc-json/unions/union.rs @@ -0,0 +1,7 @@ +// @has union.json "$.index[*][?(@.name=='Union')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Union')].kind" \"union\" +// @!has - "$.index[*][?(@.name=='Union')].inner.struct_type" +pub union Union { + int: i32, + float: f32, +} diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs new file mode 100644 index 000000000..e58bba640 --- /dev/null +++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs @@ -0,0 +1,16 @@ +// This test ensures that rustdoc does not panic on inherented associated types +// that are referred to without fully-qualified syntax. + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +pub struct Struct; + +impl Struct { + pub type AssocTy = usize; + pub const AssocConst: Self::AssocTy = 42; + //~^ ERROR ambiguous associated type + //~| HELP use fully-qualified syntax + //~| ERROR ambiguous associated type + //~| HELP use fully-qualified syntax +} diff --git a/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr new file mode 100644 index 000000000..b963b722f --- /dev/null +++ b/src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr @@ -0,0 +1,15 @@ +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27 + | +LL | pub const AssocConst: Self::AssocTy = 42; + | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy` + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27 + | +LL | pub const AssocConst: Self::AssocTy = 42; + | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.rs b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs new file mode 100644 index 000000000..0976515f4 --- /dev/null +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs @@ -0,0 +1,22 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +#[derive(Debug)] +/// Link to [`S::fmt`] +//~^ ERROR unresolved link +pub struct S; + +pub mod inner { + use std::fmt::Debug; + use super::S; + + /// Link to [`S::fmt`] + pub fn f() {} +} + +pub mod ambiguous { + use std::fmt::{Display, Debug}; + use super::S; + + /// Link to [`S::fmt`] + pub fn f() {} +} diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr new file mode 100644 index 000000000..04594ad41 --- /dev/null +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -0,0 +1,14 @@ +error: unresolved link to `S::fmt` + --> $DIR/assoc-item-not-in-scope.rs:4:15 + | +LL | /// Link to [`S::fmt`] + | ^^^^^^ the struct `S` has no field or associated item named `fmt` + | +note: the lint level is defined here + --> $DIR/assoc-item-not-in-scope.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/auxiliary/empty-fn.rs b/src/test/rustdoc-ui/auxiliary/empty-fn.rs new file mode 100644 index 000000000..877810f15 --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/empty-fn.rs @@ -0,0 +1,3 @@ +// no-prefer-dynamic +#![crate_type = "lib"] +pub fn empty() {} diff --git a/src/test/rustdoc-ui/auxiliary/extern_macros.rs b/src/test/rustdoc-ui/auxiliary/extern_macros.rs new file mode 100644 index 000000000..ee1fec4c5 --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/extern_macros.rs @@ -0,0 +1,7 @@ +#[macro_export] +macro_rules! attrs_on_struct { + ( $( #[$attr:meta] )* ) => { + $( #[$attr] )* + pub struct ExpandedStruct; + } +} diff --git a/src/test/rustdoc-ui/auxiliary/issue-61592.rs b/src/test/rustdoc-ui/auxiliary/issue-61592.rs new file mode 100644 index 000000000..57a365b3f --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/issue-61592.rs @@ -0,0 +1,3 @@ +#![crate_name = "foo"] + +pub trait Foo {} diff --git a/src/test/rustdoc-ui/auxiliary/module_macro_doc.rs b/src/test/rustdoc-ui/auxiliary/module_macro_doc.rs new file mode 100644 index 000000000..9d6b52b95 --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/module_macro_doc.rs @@ -0,0 +1 @@ +//! [`long_cat`] is really long diff --git a/src/test/rustdoc-ui/auxiliary/overflow.rs b/src/test/rustdoc-ui/auxiliary/overflow.rs new file mode 100644 index 000000000..ff65936be --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/overflow.rs @@ -0,0 +1,20 @@ +pub struct B0; +pub struct B1; +use std::ops::Shl; +use std::ops::Sub; +pub type Shleft<A, B> = <A as Shl<B>>::Output; +pub type Sub1<A> = <A as Sub<B1>>::Output; +pub struct UInt<U, B> { + pub(crate) msb: U, + pub(crate) lsb: B, +} +impl<U, B, Ur, Br> Shl<UInt<Ur, Br>> for UInt<U, B> +where + UInt<Ur, Br>: Sub<B1>, + UInt<UInt<U, B>, B0>: Shl<Sub1<UInt<Ur, Br>>>, +{ + type Output = Shleft<UInt<UInt<U, B>, B0>, Sub1<UInt<Ur, Br>>>; + fn shl(self, rhs: UInt<Ur, Br>) -> Self::Output { + unimplemented!() + } +} diff --git a/src/test/rustdoc-ui/auxiliary/panic-item.rs b/src/test/rustdoc-ui/auxiliary/panic-item.rs new file mode 100644 index 000000000..17b26850d --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/panic-item.rs @@ -0,0 +1,17 @@ +// no-prefer-dynamic +#![crate_type = "lib"] +#![no_std] +#![feature(lang_items)] + +use core::panic::PanicInfo; +use core::sync::atomic::{self, Ordering}; + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop { + atomic::compiler_fence(Ordering::SeqCst); + } +} + +#[lang = "eh_personality"] +fn foo() {} diff --git a/src/test/rustdoc-ui/bare-urls.fixed b/src/test/rustdoc-ui/bare-urls.fixed new file mode 100644 index 000000000..23aa5c44c --- /dev/null +++ b/src/test/rustdoc-ui/bare-urls.fixed @@ -0,0 +1,60 @@ +// run-rustfix + +#![deny(rustdoc::bare_urls)] + +/// <https://somewhere.com> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a> +//~^ ERROR this URL is not a hyperlink +/// <https://www.somewhere.com> +//~^ ERROR this URL is not a hyperlink +/// <https://www.somewhere.com/a> +//~^ ERROR this URL is not a hyperlink +/// <https://subdomain.example.com> +//~^ ERROR not a hyperlink +/// <https://somewhere.com?> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a?> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com?hello=12> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a?hello=12> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com?hello=12#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com/a?hello=12#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com/a#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com?hello=12&bye=11> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a?hello=12&bye=11> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com?hello=12&bye=11#xyz> +//~^ ERROR this URL is not a hyperlink +/// hey! <https://somewhere.com/a?hello=12&bye=11#xyz> +//~^ ERROR this URL is not a hyperlink +pub fn c() {} + +/// <https://somewhere.com> +/// [a](http://a.com) +/// [b] +/// +/// [b]: http://b.com +/// +/// ``` +/// This link should not be linted: http://example.com +/// +/// Nor this one: <http://example.com> or this one: [x](http://example.com) +/// ``` +/// +/// [should_not.lint](should_not.lint) +pub fn everything_is_fine_here() {} + +#[allow(rustdoc::bare_urls)] +pub mod foo { + /// https://somewhere.com/a?hello=12&bye=11#xyz + pub fn bar() {} +} diff --git a/src/test/rustdoc-ui/bare-urls.rs b/src/test/rustdoc-ui/bare-urls.rs new file mode 100644 index 000000000..592f57343 --- /dev/null +++ b/src/test/rustdoc-ui/bare-urls.rs @@ -0,0 +1,60 @@ +// run-rustfix + +#![deny(rustdoc::bare_urls)] + +/// https://somewhere.com +//~^ ERROR this URL is not a hyperlink +/// https://somewhere.com/a +//~^ ERROR this URL is not a hyperlink +/// https://www.somewhere.com +//~^ ERROR this URL is not a hyperlink +/// https://www.somewhere.com/a +//~^ ERROR this URL is not a hyperlink +/// https://subdomain.example.com +//~^ ERROR not a hyperlink +/// https://somewhere.com? +//~^ ERROR this URL is not a hyperlink +/// https://somewhere.com/a? +//~^ ERROR this URL is not a hyperlink +/// https://somewhere.com?hello=12 +//~^ ERROR this URL is not a hyperlink +/// https://somewhere.com/a?hello=12 +//~^ ERROR this URL is not a hyperlink +/// https://example.com?hello=12#xyz +//~^ ERROR this URL is not a hyperlink +/// https://example.com/a?hello=12#xyz +//~^ ERROR this URL is not a hyperlink +/// https://example.com#xyz +//~^ ERROR this URL is not a hyperlink +/// https://example.com/a#xyz +//~^ ERROR this URL is not a hyperlink +/// https://somewhere.com?hello=12&bye=11 +//~^ ERROR this URL is not a hyperlink +/// https://somewhere.com/a?hello=12&bye=11 +//~^ ERROR this URL is not a hyperlink +/// https://somewhere.com?hello=12&bye=11#xyz +//~^ ERROR this URL is not a hyperlink +/// hey! https://somewhere.com/a?hello=12&bye=11#xyz +//~^ ERROR this URL is not a hyperlink +pub fn c() {} + +/// <https://somewhere.com> +/// [a](http://a.com) +/// [b] +/// +/// [b]: http://b.com +/// +/// ``` +/// This link should not be linted: http://example.com +/// +/// Nor this one: <http://example.com> or this one: [x](http://example.com) +/// ``` +/// +/// [should_not.lint](should_not.lint) +pub fn everything_is_fine_here() {} + +#[allow(rustdoc::bare_urls)] +pub mod foo { + /// https://somewhere.com/a?hello=12&bye=11#xyz + pub fn bar() {} +} diff --git a/src/test/rustdoc-ui/bare-urls.stderr b/src/test/rustdoc-ui/bare-urls.stderr new file mode 100644 index 000000000..7097a8ddf --- /dev/null +++ b/src/test/rustdoc-ui/bare-urls.stderr @@ -0,0 +1,143 @@ +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:5:5 + | +LL | /// https://somewhere.com + | ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>` + | +note: the lint level is defined here + --> $DIR/bare-urls.rs:3:9 + | +LL | #![deny(rustdoc::bare_urls)] + | ^^^^^^^^^^^^^^^^^^ + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:7:5 + | +LL | /// https://somewhere.com/a + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:9:5 + | +LL | /// https://www.somewhere.com + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:11:5 + | +LL | /// https://www.somewhere.com/a + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:13:5 + | +LL | /// https://subdomain.example.com + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:15:5 + | +LL | /// https://somewhere.com? + | ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:17:5 + | +LL | /// https://somewhere.com/a? + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:19:5 + | +LL | /// https://somewhere.com?hello=12 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:21:5 + | +LL | /// https://somewhere.com/a?hello=12 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:23:5 + | +LL | /// https://example.com?hello=12#xyz + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:25:5 + | +LL | /// https://example.com/a?hello=12#xyz + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:27:5 + | +LL | /// https://example.com#xyz + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:29:5 + | +LL | /// https://example.com/a#xyz + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:31:5 + | +LL | /// https://somewhere.com?hello=12&bye=11 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:33:5 + | +LL | /// https://somewhere.com/a?hello=12&bye=11 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:35:5 + | +LL | /// https://somewhere.com?hello=12&bye=11#xyz + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:37:10 + | +LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>` + | + = note: bare URLs are not automatically turned into clickable links + +error: aborting due to 17 previous errors + diff --git a/src/test/rustdoc-ui/block-doc-comment.rs b/src/test/rustdoc-ui/block-doc-comment.rs new file mode 100644 index 000000000..ce529916e --- /dev/null +++ b/src/test/rustdoc-ui/block-doc-comment.rs @@ -0,0 +1,17 @@ +// check-pass +// compile-flags:--test +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// This test ensures that no code block is detected in the doc comments. + +pub mod Wormhole { + /** # Returns + * + */ + pub fn foofoo() {} + /** + * # Returns + * + */ + pub fn barbar() {} +} diff --git a/src/test/rustdoc-ui/block-doc-comment.stdout b/src/test/rustdoc-ui/block-doc-comment.stdout new file mode 100644 index 000000000..7326c0a25 --- /dev/null +++ b/src/test/rustdoc-ui/block-doc-comment.stdout @@ -0,0 +1,5 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/bounded-hr-lifetime.rs b/src/test/rustdoc-ui/bounded-hr-lifetime.rs new file mode 100644 index 000000000..b2e000b97 --- /dev/null +++ b/src/test/rustdoc-ui/bounded-hr-lifetime.rs @@ -0,0 +1,9 @@ +// This test ensures that rustdoc doesn't panic on higher-ranked lifetimes +// with bounds, because an error should have already been emitted by rustc. + +pub fn hrlt<'b, 'c>() +where + for<'a: 'b + 'c> &'a (): std::fmt::Debug, + //~^ ERROR lifetime bounds cannot be used in this context +{ +} diff --git a/src/test/rustdoc-ui/bounded-hr-lifetime.stderr b/src/test/rustdoc-ui/bounded-hr-lifetime.stderr new file mode 100644 index 000000000..d8fcd6cb4 --- /dev/null +++ b/src/test/rustdoc-ui/bounded-hr-lifetime.stderr @@ -0,0 +1,10 @@ +error: lifetime bounds cannot be used in this context + --> $DIR/bounded-hr-lifetime.rs:6:13 + | +LL | for<'a: 'b + 'c> &'a (): std::fmt::Debug, + | ^^ ^^ + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc-ui/c-help.rs b/src/test/rustdoc-ui/c-help.rs new file mode 100644 index 000000000..e166edf8b --- /dev/null +++ b/src/test/rustdoc-ui/c-help.rs @@ -0,0 +1,6 @@ +// check-pass +// compile-flags: -Chelp +// check-stdout +// regex-error-pattern: -C\s+incremental + +pub struct Foo; diff --git a/src/test/rustdoc-ui/c-help.stdout b/src/test/rustdoc-ui/c-help.stdout new file mode 100644 index 000000000..75b2e2a2a --- /dev/null +++ b/src/test/rustdoc-ui/c-help.stdout @@ -0,0 +1,51 @@ + -C ar=val -- this option is deprecated and does nothing + -C code-model=val -- choose the code model to use (`rustc --print code-models` for details) + -C codegen-units=val -- divide crate into N units to optimize in parallel + -C control-flow-guard=val -- use Windows Control Flow Guard (default: no) + -C debug-assertions=val -- explicitly enable the `cfg(debug_assertions)` directive + -C debuginfo=val -- debug info emission level (0 = no debug info, 1 = line tables only, 2 = full debug info with variable and type information; default: 0) + -C default-linker-libraries=val -- allow the linker to link its default libraries (default: no) + -C embed-bitcode=val -- emit bitcode in rlibs (default: yes) + -C extra-filename=val -- extra data to put in each output filename + -C force-frame-pointers=val -- force use of the frame pointers + -C force-unwind-tables=val -- force use of unwind tables + -C incremental=val -- enable incremental compilation + -C inline-threshold=val -- set the threshold for inlining a function + -C instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are: + `=all` (implicit value) + `=except-unused-generics` + `=except-unused-functions` + `=off` (default) + -C link-arg=val -- a single extra argument to append to the linker invocation (can be used several times) + -C link-args=val -- extra arguments to append to the linker invocation (space separated) + -C link-dead-code=val -- keep dead code at link time (useful for code coverage) (default: no) + -C link-self-contained=val -- control whether to link Rust provided C objects/libraries or rely + on C toolchain installed in the system + -C linker=val -- system linker to link outputs with + -C linker-flavor=val -- linker flavor + -C linker-plugin-lto=val -- generate build artifacts that are compatible with linker-based LTO + -C llvm-args=val -- a list of arguments to pass to LLVM (space separated) + -C lto=val -- perform LLVM link-time optimizations + -C metadata=val -- metadata to mangle symbol names with + -C no-prepopulate-passes=val -- give an empty list of passes to the pass manager + -C no-redzone=val -- disable the use of the redzone + -C no-stack-check=val -- this option is deprecated and does nothing + -C no-vectorize-loops=val -- disable loop vectorization optimization passes + -C no-vectorize-slp=val -- disable LLVM's SLP vectorization pass + -C opt-level=val -- optimization level (0-3, s, or z; default: 0) + -C overflow-checks=val -- use overflow checks for integer arithmetic + -C panic=val -- panic strategy to compile crate with + -C passes=val -- a list of extra LLVM passes to run (space separated) + -C prefer-dynamic=val -- prefer dynamic linking to static linking (default: no) + -C profile-generate=val -- compile the program with profiling instrumentation + -C profile-use=val -- use the given `.profdata` file for profile-guided optimization + -C relocation-model=val -- control generation of position-independent code (PIC) (`rustc --print relocation-models` for details) + -C remark=val -- print remarks for these optimization passes (space separated, or "all") + -C rpath=val -- set rpath values in libs/exes (default: no) + -C save-temps=val -- save all temporary output files during compilation (default: no) + -C soft-float=val -- use soft float ABI (*eabihf targets only) (default: no) + -C split-debuginfo=val -- how to handle split-debuginfo, a platform-specific option + -C strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`) + -C symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0') + -C target-cpu=val -- select target processor (`rustc --print target-cpus` for details) + -C target-feature=val -- target specific attributes. (`rustc --print target-features` for details). This feature is unsafe. diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs new file mode 100644 index 000000000..d4ca92585 --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.rs @@ -0,0 +1,31 @@ +// check-pass +// compile-flags:--test --test-args --test-threads=1 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// Crates like core have doctests gated on `cfg(not(test))` so we need to make +// sure `cfg(test)` is not active when running `rustdoc --test`. + +/// this doctest will be ignored: +/// +/// ``` +/// assert!(false); +/// ``` +#[cfg(test)] +pub struct Foo; + +/// this doctest will be tested: +/// +/// ``` +/// assert!(true); +/// ``` +#[cfg(not(test))] +pub struct Foo; + +/// this doctest will be tested, but will not appear in documentation: +/// +/// ``` +/// assert!(true) +/// ``` +#[cfg(doctest)] +pub struct Bar; diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout new file mode 100644 index 000000000..2960ff8d3 --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/cfg-test.rs - Bar (line 27) ... ok +test $DIR/cfg-test.rs - Foo (line 19) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/check-attr-test.rs b/src/test/rustdoc-ui/check-attr-test.rs new file mode 100644 index 000000000..e95547014 --- /dev/null +++ b/src/test/rustdoc-ui/check-attr-test.rs @@ -0,0 +1,31 @@ +// compile-flags:--test + +#![deny(rustdoc::invalid_codeblock_attributes)] + +/// foo +/// +/// ```compile-fail,compilefail,comPile_fail +/// boo +/// ``` +pub fn foo() {} + +/// bar +/// +/// ```should-panic,shouldpanic,shOuld_panic +/// boo +/// ``` +pub fn bar() {} + +/// foobar +/// +/// ```no-run,norun,nO_run +/// boo +/// ``` +pub fn foobar() {} + +/// b +/// +/// ```test-harness,testharness,tesT_harness +/// boo +/// ``` +pub fn b() {} diff --git a/src/test/rustdoc-ui/check-attr-test.stderr b/src/test/rustdoc-ui/check-attr-test.stderr new file mode 100644 index 000000000..b1fa9edf0 --- /dev/null +++ b/src/test/rustdoc-ui/check-attr-test.stderr @@ -0,0 +1,151 @@ +error: unknown attribute `compile-fail`. Did you mean `compile_fail`? + --> $DIR/check-attr-test.rs:5:1 + | +5 | / /// foo +6 | | /// +7 | | /// ```compile-fail,compilefail,comPile_fail +8 | | /// boo +9 | | /// ``` + | |_______^ + | +note: the lint level is defined here + --> $DIR/check-attr-test.rs:3:9 + | +3 | #![deny(rustdoc::invalid_codeblock_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + +error: unknown attribute `compilefail`. Did you mean `compile_fail`? + --> $DIR/check-attr-test.rs:5:1 + | +5 | / /// foo +6 | | /// +7 | | /// ```compile-fail,compilefail,comPile_fail +8 | | /// boo +9 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + +error: unknown attribute `comPile_fail`. Did you mean `compile_fail`? + --> $DIR/check-attr-test.rs:5:1 + | +5 | / /// foo +6 | | /// +7 | | /// ```compile-fail,compilefail,comPile_fail +8 | | /// boo +9 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + +error: unknown attribute `should-panic`. Did you mean `should_panic`? + --> $DIR/check-attr-test.rs:12:1 + | +12 | / /// bar +13 | | /// +14 | | /// ```should-panic,shouldpanic,shOuld_panic +15 | | /// boo +16 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + +error: unknown attribute `shouldpanic`. Did you mean `should_panic`? + --> $DIR/check-attr-test.rs:12:1 + | +12 | / /// bar +13 | | /// +14 | | /// ```should-panic,shouldpanic,shOuld_panic +15 | | /// boo +16 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + +error: unknown attribute `shOuld_panic`. Did you mean `should_panic`? + --> $DIR/check-attr-test.rs:12:1 + | +12 | / /// bar +13 | | /// +14 | | /// ```should-panic,shouldpanic,shOuld_panic +15 | | /// boo +16 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + +error: unknown attribute `no-run`. Did you mean `no_run`? + --> $DIR/check-attr-test.rs:19:1 + | +19 | / /// foobar +20 | | /// +21 | | /// ```no-run,norun,nO_run +22 | | /// boo +23 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + +error: unknown attribute `norun`. Did you mean `no_run`? + --> $DIR/check-attr-test.rs:19:1 + | +19 | / /// foobar +20 | | /// +21 | | /// ```no-run,norun,nO_run +22 | | /// boo +23 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + +error: unknown attribute `nO_run`. Did you mean `no_run`? + --> $DIR/check-attr-test.rs:19:1 + | +19 | / /// foobar +20 | | /// +21 | | /// ```no-run,norun,nO_run +22 | | /// boo +23 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + +error: unknown attribute `test-harness`. Did you mean `test_harness`? + --> $DIR/check-attr-test.rs:26:1 + | +26 | / /// b +27 | | /// +28 | | /// ```test-harness,testharness,tesT_harness +29 | | /// boo +30 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: unknown attribute `testharness`. Did you mean `test_harness`? + --> $DIR/check-attr-test.rs:26:1 + | +26 | / /// b +27 | | /// +28 | | /// ```test-harness,testharness,tesT_harness +29 | | /// boo +30 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: unknown attribute `tesT_harness`. Did you mean `test_harness`? + --> $DIR/check-attr-test.rs:26:1 + | +26 | / /// b +27 | | /// +28 | | /// ```test-harness,testharness,tesT_harness +29 | | /// boo +30 | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: aborting due to 12 previous errors + diff --git a/src/test/rustdoc-ui/check-attr.rs b/src/test/rustdoc-ui/check-attr.rs new file mode 100644 index 000000000..0b3f7bedd --- /dev/null +++ b/src/test/rustdoc-ui/check-attr.rs @@ -0,0 +1,41 @@ +#![deny(rustdoc::invalid_codeblock_attributes)] + +/// foo +//~^ ERROR +//~^^ ERROR +//~^^^ ERROR +/// +/// ```compile-fail,compilefail,comPile_fail +/// boo +/// ``` +pub fn foo() {} + +/// bar +//~^ ERROR +//~^^ ERROR +//~^^^ ERROR +/// +/// ```should-panic,shouldpanic,sHould_panic +/// boo +/// ``` +pub fn bar() {} + +/// foobar +//~^ ERROR +//~^^ ERROR +//~^^^ ERROR +/// +/// ```no-run,norun,no_Run +/// boo +/// ``` +pub fn foobar() {} + +/// b +//~^ ERROR +//~^^ ERROR +//~^^^ ERROR +/// +/// ```test-harness,testharness,teSt_harness +/// boo +/// ``` +pub fn b() {} diff --git a/src/test/rustdoc-ui/check-attr.stderr b/src/test/rustdoc-ui/check-attr.stderr new file mode 100644 index 000000000..370b804c5 --- /dev/null +++ b/src/test/rustdoc-ui/check-attr.stderr @@ -0,0 +1,175 @@ +error: unknown attribute `compile-fail`. Did you mean `compile_fail`? + --> $DIR/check-attr.rs:3:1 + | +LL | / /// foo +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | +note: the lint level is defined here + --> $DIR/check-attr.rs:1:9 + | +LL | #![deny(rustdoc::invalid_codeblock_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + +error: unknown attribute `compilefail`. Did you mean `compile_fail`? + --> $DIR/check-attr.rs:3:1 + | +LL | / /// foo +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + +error: unknown attribute `comPile_fail`. Did you mean `compile_fail`? + --> $DIR/check-attr.rs:3:1 + | +LL | / /// foo +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + +error: unknown attribute `should-panic`. Did you mean `should_panic`? + --> $DIR/check-attr.rs:13:1 + | +LL | / /// bar +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + +error: unknown attribute `shouldpanic`. Did you mean `should_panic`? + --> $DIR/check-attr.rs:13:1 + | +LL | / /// bar +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + +error: unknown attribute `sHould_panic`. Did you mean `should_panic`? + --> $DIR/check-attr.rs:13:1 + | +LL | / /// bar +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + +error: unknown attribute `no-run`. Did you mean `no_run`? + --> $DIR/check-attr.rs:23:1 + | +LL | / /// foobar +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + +error: unknown attribute `norun`. Did you mean `no_run`? + --> $DIR/check-attr.rs:23:1 + | +LL | / /// foobar +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + +error: unknown attribute `no_Run`. Did you mean `no_run`? + --> $DIR/check-attr.rs:23:1 + | +LL | / /// foobar +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + +error: unknown attribute `test-harness`. Did you mean `test_harness`? + --> $DIR/check-attr.rs:33:1 + | +LL | / /// b +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: unknown attribute `testharness`. Did you mean `test_harness`? + --> $DIR/check-attr.rs:33:1 + | +LL | / /// b +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: unknown attribute `teSt_harness`. Did you mean `test_harness`? + --> $DIR/check-attr.rs:33:1 + | +LL | / /// b +LL | | +LL | | +LL | | +... | +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: aborting due to 12 previous errors + diff --git a/src/test/rustdoc-ui/check-cfg-test.rs b/src/test/rustdoc-ui/check-cfg-test.rs new file mode 100644 index 000000000..626cc8387 --- /dev/null +++ b/src/test/rustdoc-ui/check-cfg-test.rs @@ -0,0 +1,12 @@ +// check-pass +// compile-flags: --test --nocapture --check-cfg=values(feature,"test") -Z unstable-options +// normalize-stderr-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// The doctest will produce a warning because feature invalid is unexpected +/// ``` +/// #[cfg(feature = "invalid")] +/// assert!(false); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/check-cfg-test.stderr b/src/test/rustdoc-ui/check-cfg-test.stderr new file mode 100644 index 000000000..dc25205da --- /dev/null +++ b/src/test/rustdoc-ui/check-cfg-test.stderr @@ -0,0 +1,11 @@ +warning: unexpected `cfg` condition value + --> $DIR/check-cfg-test.rs:9:7 + | +LL | #[cfg(feature = "invalid")] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + = note: expected values for `feature` are: test + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/check-cfg-test.stdout b/src/test/rustdoc-ui/check-cfg-test.stdout new file mode 100644 index 000000000..b7db49bcf --- /dev/null +++ b/src/test/rustdoc-ui/check-cfg-test.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/check-cfg-test.rs - Foo (line 8) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/check-cfg-unstable.rs b/src/test/rustdoc-ui/check-cfg-unstable.rs new file mode 100644 index 000000000..5c500ce6c --- /dev/null +++ b/src/test/rustdoc-ui/check-cfg-unstable.rs @@ -0,0 +1,2 @@ +// check-fail +// compile-flags: --check-cfg=names() diff --git a/src/test/rustdoc-ui/check-cfg-unstable.stderr b/src/test/rustdoc-ui/check-cfg-unstable.stderr new file mode 100644 index 000000000..9b27c2bc0 --- /dev/null +++ b/src/test/rustdoc-ui/check-cfg-unstable.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the flag `check-cfg` + diff --git a/src/test/rustdoc-ui/check-cfg.rs b/src/test/rustdoc-ui/check-cfg.rs new file mode 100644 index 000000000..fa8789ad3 --- /dev/null +++ b/src/test/rustdoc-ui/check-cfg.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: --check-cfg=names() -Z unstable-options + +/// uniz is nor a builtin nor pass as arguments so is unexpected +#[cfg(uniz)] +//~^ WARNING unexpected `cfg` condition name +pub struct Bar; diff --git a/src/test/rustdoc-ui/check-cfg.stderr b/src/test/rustdoc-ui/check-cfg.stderr new file mode 100644 index 000000000..1db8e1d91 --- /dev/null +++ b/src/test/rustdoc-ui/check-cfg.stderr @@ -0,0 +1,10 @@ +warning: unexpected `cfg` condition name + --> $DIR/check-cfg.rs:5:7 + | +LL | #[cfg(uniz)] + | ^^^^ help: did you mean: `unix` + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/check-doc-alias-attr-location.rs b/src/test/rustdoc-ui/check-doc-alias-attr-location.rs new file mode 100644 index 000000000..6de1960e2 --- /dev/null +++ b/src/test/rustdoc-ui/check-doc-alias-attr-location.rs @@ -0,0 +1,23 @@ +pub struct Bar; +pub trait Foo { + type X; + fn foo() -> Self::X; +} + +#[doc(alias = "foo")] //~ ERROR +extern "C" {} + +#[doc(alias = "bar")] //~ ERROR +impl Bar { + #[doc(alias = "const")] + pub const A: u32 = 0; +} + +#[doc(alias = "foobar")] //~ ERROR +impl Foo for Bar { + #[doc(alias = "assoc")] //~ ERROR + type X = i32; + fn foo() -> Self::X { + 0 + } +} diff --git a/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr b/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr new file mode 100644 index 000000000..85c951623 --- /dev/null +++ b/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr @@ -0,0 +1,26 @@ +error: `#[doc(alias = "...")]` isn't allowed on foreign module + --> $DIR/check-doc-alias-attr-location.rs:7:7 + | +LL | #[doc(alias = "foo")] + | ^^^^^^^^^^^^^ + +error: `#[doc(alias = "...")]` isn't allowed on implementation block + --> $DIR/check-doc-alias-attr-location.rs:10:7 + | +LL | #[doc(alias = "bar")] + | ^^^^^^^^^^^^^ + +error: `#[doc(alias = "...")]` isn't allowed on implementation block + --> $DIR/check-doc-alias-attr-location.rs:16:7 + | +LL | #[doc(alias = "foobar")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation block + --> $DIR/check-doc-alias-attr-location.rs:18:11 + | +LL | #[doc(alias = "assoc")] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs new file mode 100644 index 000000000..719b98604 --- /dev/null +++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs @@ -0,0 +1,28 @@ +#![crate_type = "lib"] + +#[doc(alias = "foo")] // ok! +#[doc(alias("bar", "baz"))] // ok! +pub struct Bar; + +#[doc(alias)] //~ ERROR +#[doc(alias = 0)] //~ ERROR +#[doc(alias = "\"")] //~ ERROR +#[doc(alias = "\n")] //~ ERROR +#[doc(alias = " +")] //~^ ERROR +#[doc(alias = "\t")] //~ ERROR +#[doc(alias = " hello")] //~ ERROR +#[doc(alias = "hello ")] //~ ERROR +#[doc(alias = "")] //~ ERROR +pub struct Foo; + +#[doc(alias(0))] //~ ERROR +#[doc(alias("\""))] //~ ERROR +#[doc(alias("\n"))] //~ ERROR +#[doc(alias(" +"))] //~^ ERROR +#[doc(alias("\t"))] //~ ERROR +#[doc(alias(" hello"))] //~ ERROR +#[doc(alias("hello "))] //~ ERROR +#[doc(alias(""))] //~ ERROR +pub struct Foo2; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr new file mode 100644 index 000000000..250568be3 --- /dev/null +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -0,0 +1,108 @@ +error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + --> $DIR/check-doc-alias-attr.rs:7:7 + | +LL | #[doc(alias)] + | ^^^^^ + +error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + --> $DIR/check-doc-alias-attr.rs:8:7 + | +LL | #[doc(alias = 0)] + | ^^^^^^^^^ + +error: '"' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:9:15 + | +LL | #[doc(alias = "\"")] + | ^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:10:15 + | +LL | #[doc(alias = "\n")] + | ^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:11:15 + | +LL | #[doc(alias = " + | _______________^ +LL | | ")] + | |_^ + +error: '\t' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:13:15 + | +LL | #[doc(alias = "\t")] + | ^^^^ + +error: `#[doc(alias = "...")]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:14:15 + | +LL | #[doc(alias = " hello")] + | ^^^^^^^^ + +error: `#[doc(alias = "...")]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:15:15 + | +LL | #[doc(alias = "hello ")] + | ^^^^^^^^ + +error: `#[doc(alias = "...")]` attribute cannot have empty value + --> $DIR/check-doc-alias-attr.rs:16:15 + | +LL | #[doc(alias = "")] + | ^^ + +error: `#[doc(alias("a"))]` expects string literals + --> $DIR/check-doc-alias-attr.rs:19:13 + | +LL | #[doc(alias(0))] + | ^ + +error: '"' character isn't allowed in `#[doc(alias("..."))]` + --> $DIR/check-doc-alias-attr.rs:20:13 + | +LL | #[doc(alias("\""))] + | ^^^^ + +error: '\n' character isn't allowed in `#[doc(alias("..."))]` + --> $DIR/check-doc-alias-attr.rs:21:13 + | +LL | #[doc(alias("\n"))] + | ^^^^ + +error: '\n' character isn't allowed in `#[doc(alias("..."))]` + --> $DIR/check-doc-alias-attr.rs:22:13 + | +LL | #[doc(alias(" + | _____________^ +LL | | "))] + | |_^ + +error: '\t' character isn't allowed in `#[doc(alias("..."))]` + --> $DIR/check-doc-alias-attr.rs:24:13 + | +LL | #[doc(alias("\t"))] + | ^^^^ + +error: `#[doc(alias("..."))]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:25:13 + | +LL | #[doc(alias(" hello"))] + | ^^^^^^^^ + +error: `#[doc(alias("..."))]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:26:13 + | +LL | #[doc(alias("hello "))] + | ^^^^^^^^ + +error: `#[doc(alias("..."))]` attribute cannot have empty value + --> $DIR/check-doc-alias-attr.rs:27:13 + | +LL | #[doc(alias(""))] + | ^^ + +error: aborting due to 17 previous errors + diff --git a/src/test/rustdoc-ui/check-fail.rs b/src/test/rustdoc-ui/check-fail.rs new file mode 100644 index 000000000..2355d6a3d --- /dev/null +++ b/src/test/rustdoc-ui/check-fail.rs @@ -0,0 +1,21 @@ +// compile-flags: -Z unstable-options --check + +#![deny(missing_docs)] +#![deny(rustdoc::all)] + +//! ```rust,testharness +//~^ ERROR +//! let x = 12; +//! ``` + +pub fn foo() {} +//~^ ERROR +//~^^ ERROR + +/// hello +//~^ ERROR +/// +/// ```rust,testharness +/// let x = 12; +/// ``` +pub fn bar() {} diff --git a/src/test/rustdoc-ui/check-fail.stderr b/src/test/rustdoc-ui/check-fail.stderr new file mode 100644 index 000000000..5d46dc720 --- /dev/null +++ b/src/test/rustdoc-ui/check-fail.stderr @@ -0,0 +1,52 @@ +error: missing documentation for a function + --> $DIR/check-fail.rs:11:1 + | +LL | pub fn foo() {} + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/check-fail.rs:3:9 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing code example in this documentation + --> $DIR/check-fail.rs:11:1 + | +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/check-fail.rs:4:9 + | +LL | #![deny(rustdoc::all)] + | ^^^^^^^^^^^^ + = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]` + +error: unknown attribute `testharness`. Did you mean `test_harness`? + --> $DIR/check-fail.rs:6:1 + | +LL | / //! ```rust,testharness +LL | | +LL | | //! let x = 12; +LL | | //! ``` + | |_______^ + | + = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(rustdoc::all)]` + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: unknown attribute `testharness`. Did you mean `test_harness`? + --> $DIR/check-fail.rs:15:1 + | +LL | / /// hello +LL | | +LL | | /// +LL | | /// ```rust,testharness +LL | | /// let x = 12; +LL | | /// ``` + | |_______^ + | + = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/check.rs b/src/test/rustdoc-ui/check.rs new file mode 100644 index 000000000..2b44ba24b --- /dev/null +++ b/src/test/rustdoc-ui/check.rs @@ -0,0 +1,12 @@ +// check-pass +// compile-flags: -Z unstable-options --check +// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" + +#![warn(missing_docs)] +//~^ WARN +//~^^ WARN +#![warn(rustdoc::all)] + +pub fn foo() {} +//~^ WARN +//~^^ WARN diff --git a/src/test/rustdoc-ui/check.stderr b/src/test/rustdoc-ui/check.stderr new file mode 100644 index 000000000..06e607fbe --- /dev/null +++ b/src/test/rustdoc-ui/check.stderr @@ -0,0 +1,55 @@ +warning: missing documentation for the crate + --> $DIR/check.rs:5:1 + | +LL | / #![warn(missing_docs)] +LL | | +LL | | +LL | | #![warn(rustdoc::all)] +LL | | +LL | | pub fn foo() {} + | |_______________^ + | +note: the lint level is defined here + --> $DIR/check.rs:5:9 + | +LL | #![warn(missing_docs)] + | ^^^^^^^^^^^^ + +warning: missing documentation for a function + --> $DIR/check.rs:10:1 + | +LL | pub fn foo() {} + | ^^^^^^^^^^^^ + +warning: no documentation found for this crate's top-level module + | +note: the lint level is defined here + --> $DIR/check.rs:8:9 + | +LL | #![warn(rustdoc::all)] + | ^^^^^^^^^^^^ + = note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]` + = help: The following guide may be of use: + https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html + +warning: missing code example in this documentation + --> $DIR/check.rs:5:1 + | +LL | / #![warn(missing_docs)] +LL | | +LL | | +LL | | #![warn(rustdoc::all)] +LL | | +LL | | pub fn foo() {} + | |_______________^ + | + = note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]` + +warning: missing code example in this documentation + --> $DIR/check.rs:10:1 + | +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^ + +warning: 5 warnings emitted + diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.args b/src/test/rustdoc-ui/commandline-argfile-badutf8.args new file mode 100644 index 000000000..c070b0c24 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.args @@ -0,0 +1,2 @@ +--cfg +unbroken
\ No newline at end of file diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.rs b/src/test/rustdoc-ui/commandline-argfile-badutf8.rs new file mode 100644 index 000000000..e2984e3ca --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.rs @@ -0,0 +1,12 @@ +// Check to see if we can get parameters from an @argsfile file +// +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr b/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr new file mode 100644 index 000000000..9af6fc0a5 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-badutf8.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args + diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.rs b/src/test/rustdoc-ui/commandline-argfile-missing.rs new file mode 100644 index 000000000..5a6465bd0 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-missing.rs @@ -0,0 +1,14 @@ +// Check to see if we can get parameters from an @argsfile file +// +// normalize-stderr-test: "os error \d+" -> "os error $$ERR" +// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING " +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/rustdoc-ui/commandline-argfile-missing.stderr b/src/test/rustdoc-ui/commandline-argfile-missing.stderr new file mode 100644 index 000000000..179ad8310 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile-missing.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR) + diff --git a/src/test/rustdoc-ui/commandline-argfile.args b/src/test/rustdoc-ui/commandline-argfile.args new file mode 100644 index 000000000..972938bf6 --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile.args @@ -0,0 +1,2 @@ +--cfg +unbroken
\ No newline at end of file diff --git a/src/test/rustdoc-ui/commandline-argfile.rs b/src/test/rustdoc-ui/commandline-argfile.rs new file mode 100644 index 000000000..cc8c8722c --- /dev/null +++ b/src/test/rustdoc-ui/commandline-argfile.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// check-pass +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.rs b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs new file mode 100644 index 000000000..c771c09da --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs @@ -0,0 +1,41 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! Make sure to have some docs on your crate root + +#[allow(missing_docs)] +pub mod mod_foo { + pub struct Bar; +} + +/// This is a struct with an `#[allow(missing_docs)]` +pub struct AllowTheMissingDocs { + #[allow(missing_docs)] + pub empty_str: String, + + /// This has + #[allow(missing_docs)] + /// but also has documentation comments + pub hello: usize, + + /// The doc id just to create a boilerplate comment + pub doc_id: Vec<u8>, +} + +/// A function that has a documentation +pub fn this_is_func() {} + +#[allow(missing_docs)] +pub struct DemoStruct { + something: usize, +} + +#[allow(missing_docs)] +pub mod bar { + #[warn(missing_docs)] + pub struct Bar { //~ WARN + pub f: u32, //~ WARN + } + + pub struct NeedsNoDocs; +} diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr new file mode 100644 index 000000000..3d5b512d1 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr @@ -0,0 +1,20 @@ +warning: missing documentation for a struct + --> $DIR/allow_missing_docs.rs:36:5 + | +LL | pub struct Bar { + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/allow_missing_docs.rs:35:12 + | +LL | #[warn(missing_docs)] + | ^^^^^^^^^^^^ + +warning: missing documentation for a struct field + --> $DIR/allow_missing_docs.rs:37:9 + | +LL | pub f: u32, + | ^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout new file mode 100644 index 000000000..17e8ee9e2 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...i/coverage/allow_missing_docs.rs | 5 | 71.4% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 5 | 71.4% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/basic.rs b/src/test/rustdoc-ui/coverage/basic.rs new file mode 100644 index 000000000..6c26b751c --- /dev/null +++ b/src/test/rustdoc-ui/coverage/basic.rs @@ -0,0 +1,50 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +#![feature(extern_types)] + +//! Make sure to have some docs on your crate root + +/// This struct is documented, but its fields are not. +/// +/// However, one field is private, so it shouldn't show in the total. +pub struct SomeStruct { + pub some_field: usize, + other_field: usize, +} + +impl SomeStruct { + /// Method with docs + pub fn this_fn(&self) {} + + // Method without docs + pub fn other_method(&self) {} +} + +// struct without docs +pub struct OtherStruct; + +// function with no docs +pub fn some_fn() {} + +/// Function with docs +pub fn other_fn() {} + +pub enum SomeEnum { + /// Some of these variants are documented... + VarOne, + /// ...but some of them are not. + VarTwo, + // (like this one) + VarThree, +} + +/// There's a macro here, too +#[macro_export] +macro_rules! some_macro { + () => {}; +} + +extern "C" { + pub type ExternType; +} diff --git a/src/test/rustdoc-ui/coverage/basic.stdout b/src/test/rustdoc-ui/coverage/basic.stdout new file mode 100644 index 000000000..3c602b3da --- /dev/null +++ b/src/test/rustdoc-ui/coverage/basic.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/basic.rs | 7 | 50.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 7 | 50.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/doc-examples-json.rs b/src/test/rustdoc-ui/coverage/doc-examples-json.rs new file mode 100644 index 000000000..1da181379 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples-json.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags:-Z unstable-options --output-format json --show-coverage + +// This check ensures that only one doc example is counted since they're "optional" on +// certain items. + +/// ``` +/// let x = 12; +/// ``` +pub const Foo: u32 = 0; + +/// doc +pub const Bar: u32 = 0; diff --git a/src/test/rustdoc-ui/coverage/doc-examples-json.stdout b/src/test/rustdoc-ui/coverage/doc-examples-json.stdout new file mode 100644 index 000000000..92f585569 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples-json.stdout @@ -0,0 +1 @@ +{"$DIR/doc-examples-json.rs":{"total":3,"with_docs":2,"total_examples":2,"with_examples":1}} diff --git a/src/test/rustdoc-ui/coverage/doc-examples.rs b/src/test/rustdoc-ui/coverage/doc-examples.rs new file mode 100644 index 000000000..cd718f8a3 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples.rs @@ -0,0 +1,27 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! This test ensure that only rust code examples are counted. + +/// Doc +/// +/// ``` +/// let x = 2; +/// ``` +pub struct Foo; + +/// Doc +/// +/// ```text +/// yolo +/// ``` +pub trait Bar {} + +/// Doc +/// +/// ```ignore (just for the sake of this test) +/// let x = 2; +/// ``` +pub fn foo<T: Bar, D: ::std::fmt::Debug>(a: Foo, b: u32, c: T, d: D) -> u32 { + 0 +} diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout new file mode 100644 index 000000000..8188740f8 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 4 | 100.0% | 1 | 25.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/empty.rs b/src/test/rustdoc-ui/coverage/empty.rs new file mode 100644 index 000000000..55a87e9d9 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/empty.rs @@ -0,0 +1,4 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +// an empty crate still has one item to document: the crate root diff --git a/src/test/rustdoc-ui/coverage/empty.stdout b/src/test/rustdoc-ui/coverage/empty.stdout new file mode 100644 index 000000000..890a7d56e --- /dev/null +++ b/src/test/rustdoc-ui/coverage/empty.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/empty.rs | 0 | 0.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 0 | 0.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs b/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs new file mode 100644 index 000000000..e9c165b19 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple-documented.rs @@ -0,0 +1,37 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +// The point of this test is to ensure that the number of "documented" items +// is higher than in `enum-tuple.rs`. + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// VarOne. + VarOne( + /// hello! + String, + ), + /// Var Two. + VarTwo( + /// Hello + String, + /// Bis repetita. + String, + ), +} + +/// Struct. +pub struct ThisStruct( + /// hello + u32, +); + +/// Struct. +pub struct ThisStruct2( + /// hello + u32, + /// Bis repetita. + u8, +); diff --git a/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout b/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout new file mode 100644 index 000000000..82c98f43f --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple-documented.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...overage/enum-tuple-documented.rs | 9 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 9 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enum-tuple.rs b/src/test/rustdoc-ui/coverage/enum-tuple.rs new file mode 100644 index 000000000..5fb205450 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple.rs @@ -0,0 +1,18 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// No need to document the field if there is only one in a tuple variant! + VarOne(String), + /// But if there is more than one... still fine! + VarTwo(String, String), +} + +/// Struct. +pub struct ThisStruct(u32); + +/// Struct. +pub struct ThisStruct2(u32, u8); diff --git a/src/test/rustdoc-ui/coverage/enum-tuple.stdout b/src/test/rustdoc-ui/coverage/enum-tuple.stdout new file mode 100644 index 000000000..a3377d59c --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enum-tuple.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...ustdoc-ui/coverage/enum-tuple.rs | 6 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enums.rs b/src/test/rustdoc-ui/coverage/enums.rs new file mode 100644 index 000000000..a4ae36d68 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enums.rs @@ -0,0 +1,22 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! (remember the crate root is still a module) + +/// so check out this enum here +pub enum ThisEnum { + /// this variant has some weird stuff going on + VarOne { + /// like, it has some named fields inside + field_one: usize, + // (these show up as struct fields) + field_two: usize, + }, + /// here's another variant for you + VarTwo(String), + // but not all of them need to be documented as thoroughly + VarThree, +} + +/// uninhabited enums? sure, let's throw one of those around +pub enum OtherEnum {} diff --git a/src/test/rustdoc-ui/coverage/enums.stdout b/src/test/rustdoc-ui/coverage/enums.stdout new file mode 100644 index 000000000..64c012c1f --- /dev/null +++ b/src/test/rustdoc-ui/coverage/enums.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/enums.rs | 6 | 75.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 75.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/exotic.rs b/src/test/rustdoc-ui/coverage/exotic.rs new file mode 100644 index 000000000..72b70d698 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/exotic.rs @@ -0,0 +1,15 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +#![feature(rustdoc_internals)] + +//! the features only used in std also have entries in the table, so make sure those get pulled out +//! properly as well + +/// woo, check it out, we can write our own primitive docs lol +#[doc(primitive="unit")] +mod prim_unit {} + +/// keywords? sure, pile them on +#[doc(keyword="where")] +mod where_keyword {} diff --git a/src/test/rustdoc-ui/coverage/exotic.stdout b/src/test/rustdoc-ui/coverage/exotic.stdout new file mode 100644 index 000000000..27798b813 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/exotic.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/exotic.rs | 3 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 3 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/html.rs b/src/test/rustdoc-ui/coverage/html.rs new file mode 100644 index 000000000..181cb4c50 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/html.rs @@ -0,0 +1,4 @@ +// compile-flags:-Z unstable-options --output-format html --show-coverage + +/// Foo +pub struct Xo; diff --git a/src/test/rustdoc-ui/coverage/html.stderr b/src/test/rustdoc-ui/coverage/html.stderr new file mode 100644 index 000000000..adca375d4 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/html.stderr @@ -0,0 +1,2 @@ +error: html output format isn't supported for the --show-coverage option + diff --git a/src/test/rustdoc-ui/coverage/json.rs b/src/test/rustdoc-ui/coverage/json.rs new file mode 100644 index 000000000..a591cd5db --- /dev/null +++ b/src/test/rustdoc-ui/coverage/json.rs @@ -0,0 +1,65 @@ +// check-pass +// compile-flags:-Z unstable-options --output-format json --show-coverage + +pub mod foo { + /// Hello! + pub struct Foo; + /// Bar + pub enum Bar { A } +} + +/// X +pub struct X; + +/// Bar +/// +/// ``` +/// let x = 12; +/// ``` +pub mod bar { + /// bar + pub struct Bar; + /// X + pub enum X { + /// ``` + /// let x = "should be ignored!"; + /// ``` + Y + } +} + +/// yolo +/// +/// ```text +/// should not be counted as a code example! +/// ``` +pub enum Yolo { X } + +impl Yolo { + /// ``` + /// let x = "should be ignored!"; + /// ``` + pub const Const: u32 = 0; +} + +pub struct Xo<T: Clone> { + /// ``` + /// let x = "should be ignored!"; + /// ``` + x: T, +} + +/// ``` +/// let x = "should be ignored!"; +/// ``` +pub static StaticFoo: u32 = 0; + +/// ``` +/// let x = "should be ignored!"; +/// ``` +pub const ConstFoo: u32 = 0; + +/// ``` +/// let x = "should be ignored!"; +/// ``` +pub type TypeFoo = u32; diff --git a/src/test/rustdoc-ui/coverage/json.stdout b/src/test/rustdoc-ui/coverage/json.stdout new file mode 100644 index 000000000..c2be73ce3 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/json.stdout @@ -0,0 +1 @@ +{"$DIR/json.rs":{"total":17,"with_docs":12,"total_examples":15,"with_examples":6}} diff --git a/src/test/rustdoc-ui/coverage/private.rs b/src/test/rustdoc-ui/coverage/private.rs new file mode 100644 index 000000000..2a0271727 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/private.rs @@ -0,0 +1,21 @@ +// compile-flags:-Z unstable-options --show-coverage --document-private-items +// check-pass + +#![allow(unused)] + +//! when `--document-private-items` is passed, nothing is safe. everything must have docs or your +//! score will suffer the consequences + +mod this_mod { + fn private_fn() {} +} + +/// See, our public items have docs! +pub struct SomeStruct { + /// Look, all perfectly documented! + pub field: usize, + other: usize, +} + +/// Nothing shady going on here. Just a bunch of well-documented code. (cough) +pub fn public_fn() {} diff --git a/src/test/rustdoc-ui/coverage/private.stdout b/src/test/rustdoc-ui/coverage/private.stdout new file mode 100644 index 000000000..37a0f5187 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/private.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...t/rustdoc-ui/coverage/private.rs | 4 | 57.1% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 4 | 57.1% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/statics-consts.rs b/src/test/rustdoc-ui/coverage/statics-consts.rs new file mode 100644 index 000000000..5a35260fa --- /dev/null +++ b/src/test/rustdoc-ui/coverage/statics-consts.rs @@ -0,0 +1,23 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! gotta make sure we can count statics and consts correctly, too + +/// static like electricity, right? +pub static THIS_STATIC: usize = 0; + +/// (it's not electricity, is it) +pub const THIS_CONST: usize = 1; + +/// associated consts show up separately, but let's throw them in as well +pub trait SomeTrait { + /// just like that, yeah + const ASSOC_CONST: usize; +} + +pub struct SomeStruct; + +impl SomeStruct { + /// wait, structs can have them too, can't forget those + pub const ASSOC_CONST: usize = 100; +} diff --git a/src/test/rustdoc-ui/coverage/statics-consts.stdout b/src/test/rustdoc-ui/coverage/statics-consts.stdout new file mode 100644 index 000000000..dbea3a3ea --- /dev/null +++ b/src/test/rustdoc-ui/coverage/statics-consts.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...oc-ui/coverage/statics-consts.rs | 6 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 6 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/traits.rs b/src/test/rustdoc-ui/coverage/traits.rs new file mode 100644 index 000000000..daa08ec25 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/traits.rs @@ -0,0 +1,38 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +#![feature(trait_alias)] +#![feature(type_alias_impl_trait)] + +/// look at this trait right here +pub trait ThisTrait { + /// that's a trait all right + fn right_here(&self); + + /// even the provided functions show up as trait methods + fn aww_yeah(&self) {} + + /// gotta check those associated types, they're slippery + type SomeType; +} + +/// so what happens if we take some struct... +#[derive(Clone)] +pub struct SomeStruct; + +/// ...and slap this trait on it? +impl ThisTrait for SomeStruct { + /// nothing! trait impls are totally ignored in this calculation, sorry. + fn right_here(&self) {} + + type SomeType = String; +} + +/// but what about those aliases? i hear they're pretty exotic +pub trait MyAlias = ThisTrait + Send + Sync; + +/// woah, getting all opaque in here +pub type ThisExists = impl ThisTrait; + +/// why don't we get a little more concrete +pub fn defines() -> ThisExists { SomeStruct {} } diff --git a/src/test/rustdoc-ui/coverage/traits.stdout b/src/test/rustdoc-ui/coverage/traits.stdout new file mode 100644 index 000000000..5053d0209 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/traits.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/traits.rs | 8 | 88.9% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 8 | 88.9% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs new file mode 100644 index 000000000..09da124b1 --- /dev/null +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs @@ -0,0 +1,4 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +/// [v2] //~ ERROR +pub fn foo() {} diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr new file mode 100644 index 000000000..67d9c3989 --- /dev/null +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -0,0 +1,15 @@ +error: unresolved link to `v2` + --> $DIR/deny-intra-link-resolution-failure.rs:3:6 + | +LL | /// [v2] + | ^^ no item named `v2` in scope + | +note: the lint level is defined here + --> $DIR/deny-intra-link-resolution-failure.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.rs b/src/test/rustdoc-ui/deny-missing-docs-crate.rs new file mode 100644 index 000000000..b74eba3f6 --- /dev/null +++ b/src/test/rustdoc-ui/deny-missing-docs-crate.rs @@ -0,0 +1,3 @@ +#![deny(missing_docs)] //~ ERROR + +pub struct Foo; //~ ERROR diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr new file mode 100644 index 000000000..5025b0b0c --- /dev/null +++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr @@ -0,0 +1,22 @@ +error: missing documentation for the crate + --> $DIR/deny-missing-docs-crate.rs:1:1 + | +LL | / #![deny(missing_docs)] +LL | | +LL | | pub struct Foo; + | |_______________^ + | +note: the lint level is defined here + --> $DIR/deny-missing-docs-crate.rs:1:9 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: missing documentation for a struct + --> $DIR/deny-missing-docs-crate.rs:3:1 + | +LL | pub struct Foo; + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.rs b/src/test/rustdoc-ui/deny-missing-docs-macro.rs new file mode 100644 index 000000000..b1c125317 --- /dev/null +++ b/src/test/rustdoc-ui/deny-missing-docs-macro.rs @@ -0,0 +1,8 @@ +//! foo + +#![deny(missing_docs)] + +#[macro_export] +macro_rules! foo { //~ ERROR + () => {} +} diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr new file mode 100644 index 000000000..0867b0818 --- /dev/null +++ b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr @@ -0,0 +1,14 @@ +error: missing documentation for a macro + --> $DIR/deny-missing-docs-macro.rs:6:1 + | +LL | macro_rules! foo { + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/deny-missing-docs-macro.rs:3:9 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/deprecated-attrs.rs b/src/test/rustdoc-ui/deprecated-attrs.rs new file mode 100644 index 000000000..4f6a14fc2 --- /dev/null +++ b/src/test/rustdoc-ui/deprecated-attrs.rs @@ -0,0 +1,16 @@ +// check-pass +// compile-flags: --passes unknown-pass +// error-pattern: the `passes` flag no longer functions + +#![doc(no_default_passes)] +//~^ WARNING attribute is deprecated +//~| NOTE see issue #44136 +//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]` +#![doc(passes = "collapse-docs unindent-comments")] +//~^ WARNING attribute is deprecated +//~| NOTE see issue #44136 +//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]` +#![doc(plugins = "xxx")] +//~^ WARNING attribute is deprecated +//~| NOTE see issue #44136 +//~| WARNING no longer functions; see CVE diff --git a/src/test/rustdoc-ui/deprecated-attrs.stderr b/src/test/rustdoc-ui/deprecated-attrs.stderr new file mode 100644 index 000000000..45b20ce70 --- /dev/null +++ b/src/test/rustdoc-ui/deprecated-attrs.stderr @@ -0,0 +1,34 @@ +warning: the `passes` flag no longer functions + | + = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information + = help: you may want to use --document-private-items + +warning: the `#![doc(no_default_passes)]` attribute is deprecated + --> $DIR/deprecated-attrs.rs:5:8 + | +LL | #![doc(no_default_passes)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information + = help: `#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]` + +warning: the `#![doc(passes = "...")]` attribute is deprecated + --> $DIR/deprecated-attrs.rs:9:8 + | +LL | #![doc(passes = "collapse-docs unindent-comments")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information + = help: `#![doc(passes = "...")]` no longer functions; you may want to use `#![doc(document_private_items)]` + +warning: the `#![doc(plugins = "...")]` attribute is deprecated + --> $DIR/deprecated-attrs.rs:13:8 + | +LL | #![doc(plugins = "xxx")] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information + = warning: `#![doc(plugins = "...")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622> + +warning: 3 warnings emitted + diff --git a/src/test/rustdoc-ui/deref-generic.rs b/src/test/rustdoc-ui/deref-generic.rs new file mode 100644 index 000000000..bc64beb1b --- /dev/null +++ b/src/test/rustdoc-ui/deref-generic.rs @@ -0,0 +1,15 @@ +// check-pass +// #81395: Fix ICE when recursing into Deref target only differing in type args + +pub struct Generic<T>(T); + +impl<'a> std::ops::Deref for Generic<&'a mut ()> { + type Target = Generic<&'a ()>; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +impl<'a> Generic<&'a ()> { + pub fn some_method(&self) {} +} diff --git a/src/test/rustdoc-ui/diagnostic-width.rs b/src/test/rustdoc-ui/diagnostic-width.rs new file mode 100644 index 000000000..61961d5ec --- /dev/null +++ b/src/test/rustdoc-ui/diagnostic-width.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zunstable-options --diagnostic-width=10 +#![deny(rustdoc::bare_urls)] + +/// This is a long line that contains a http://link.com +pub struct Foo; //~^ ERROR diff --git a/src/test/rustdoc-ui/diagnostic-width.stderr b/src/test/rustdoc-ui/diagnostic-width.stderr new file mode 100644 index 000000000..fed049d2b --- /dev/null +++ b/src/test/rustdoc-ui/diagnostic-width.stderr @@ -0,0 +1,15 @@ +error: this URL is not a hyperlink + --> $DIR/diagnostic-width.rs:4:41 + | +LL | ... a http://link.com + | ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>` + | +note: the lint level is defined here + --> $DIR/diagnostic-width.rs:2:9 + | +LL | ...ny(rustdoc::bare_url... + | ^^^^^^^^^^^^^^^^^^ + = note: bare URLs are not automatically turned into clickable links + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/display-output.rs b/src/test/rustdoc-ui/display-output.rs new file mode 100644 index 000000000..ec27a9f6b --- /dev/null +++ b/src/test/rustdoc-ui/display-output.rs @@ -0,0 +1,15 @@ +// Test that `--show-output` has an effect and `allow(unused)` can be overridden. + +// check-pass +// edition:2018 +// compile-flags:--test --test-args=--show-output +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// #![warn(unused)] +/// let x = 12; +/// +/// fn foo(x: &dyn std::fmt::Display) {} +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc-ui/display-output.stdout b/src/test/rustdoc-ui/display-output.stdout new file mode 100644 index 000000000..ad25d1ce5 --- /dev/null +++ b/src/test/rustdoc-ui/display-output.stdout @@ -0,0 +1,43 @@ + +running 1 test +test $DIR/display-output.rs - foo (line 9) ... ok + +successes: + +---- $DIR/display-output.rs - foo (line 9) stdout ---- +warning: unused variable: `x` + --> $DIR/display-output.rs:11:5 + | +LL | let x = 12; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/display-output.rs:9:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `x` + --> $DIR/display-output.rs:13:8 + | +LL | fn foo(x: &dyn std::fmt::Display) {} + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +warning: function `foo` is never used + --> $DIR/display-output.rs:13:4 + | +LL | fn foo(x: &dyn std::fmt::Display) {} + | ^^^ + | + = note: `#[warn(dead_code)]` implied by `#[warn(unused)]` + +warning: 3 warnings emitted + + + +successes: + $DIR/display-output.rs - foo (line 9) + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.rs b/src/test/rustdoc-ui/doc-alias-assoc-const.rs new file mode 100644 index 000000000..d95324734 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.rs @@ -0,0 +1,21 @@ +#![feature(trait_alias)] + +pub struct Foo; + +pub trait Bar { + const BAZ: u8; +} + +impl Bar for Foo { + #[doc(alias = "CONST_BAZ")] //~ ERROR + const BAZ: u8 = 0; +} + +impl Foo { + #[doc(alias = "CONST_FOO")] // ok! + pub const FOO: u8 = 0; + + pub fn bar() -> u8 { + Self::FOO + } +} diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.stderr b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr new file mode 100644 index 000000000..cbca40e13 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr @@ -0,0 +1,8 @@ +error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block + --> $DIR/doc-alias-assoc-const.rs:10:11 + | +LL | #[doc(alias = "CONST_BAZ")] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/doc-alias-crate-level.rs b/src/test/rustdoc-ui/doc-alias-crate-level.rs new file mode 100644 index 000000000..70618ac01 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-crate-level.rs @@ -0,0 +1,4 @@ +#![doc(alias = "crate-level-not-working")] //~ ERROR + +#[doc(alias = "shouldn't work!")] //~ ERROR +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc-alias-crate-level.stderr b/src/test/rustdoc-ui/doc-alias-crate-level.stderr new file mode 100644 index 000000000..fc8095e03 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-crate-level.stderr @@ -0,0 +1,14 @@ +error: '\'' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/doc-alias-crate-level.rs:3:15 + | +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ + +error: `#![doc(alias = "...")]` isn't allowed as a crate-level attribute + --> $DIR/doc-alias-crate-level.rs:1:8 + | +LL | #![doc(alias = "crate-level-not-working")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc-ui/doc-alias-same-name.rs b/src/test/rustdoc-ui/doc-alias-same-name.rs new file mode 100644 index 000000000..da97c2676 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-same-name.rs @@ -0,0 +1,4 @@ +#![crate_type = "lib"] + +#[doc(alias = "Foo")] //~ ERROR +pub struct Foo; diff --git a/src/test/rustdoc-ui/doc-alias-same-name.stderr b/src/test/rustdoc-ui/doc-alias-same-name.stderr new file mode 100644 index 000000000..5ba09a2ea --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-same-name.stderr @@ -0,0 +1,8 @@ +error: `#[doc(alias = "...")]` is the same as the item's name + --> $DIR/doc-alias-same-name.rs:3:7 + | +LL | #[doc(alias = "Foo")] + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/doc-attr.rs b/src/test/rustdoc-ui/doc-attr.rs new file mode 100644 index 000000000..980d1c0e2 --- /dev/null +++ b/src/test/rustdoc-ui/doc-attr.rs @@ -0,0 +1,25 @@ +#![crate_type = "lib"] +#![deny(warnings)] +#![doc(as_ptr)] +//~^ ERROR unknown `doc` attribute +//~^^ WARN + +#[doc(as_ptr)] +//~^ ERROR unknown `doc` attribute +//~^^ WARN +pub fn foo() {} + +#[doc(123)] +//~^ ERROR invalid `doc` attribute +//~| WARN +#[doc("hello", "bar")] +//~^ ERROR invalid `doc` attribute +//~| WARN +//~| ERROR invalid `doc` attribute +//~| WARN +#[doc(foo::bar, crate::bar::baz = "bye")] +//~^ ERROR unknown `doc` attribute +//~| WARN +//~| ERROR unknown `doc` attribute +//~| WARN +fn bar() {} diff --git a/src/test/rustdoc-ui/doc-attr.stderr b/src/test/rustdoc-ui/doc-attr.stderr new file mode 100644 index 000000000..cc2494c92 --- /dev/null +++ b/src/test/rustdoc-ui/doc-attr.stderr @@ -0,0 +1,71 @@ +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr.rs:7:7 + | +LL | #[doc(as_ptr)] + | ^^^^^^ + | +note: the lint level is defined here + --> $DIR/doc-attr.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: invalid `doc` attribute + --> $DIR/doc-attr.rs:12:7 + | +LL | #[doc(123)] + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: invalid `doc` attribute + --> $DIR/doc-attr.rs:15:7 + | +LL | #[doc("hello", "bar")] + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: invalid `doc` attribute + --> $DIR/doc-attr.rs:15:16 + | +LL | #[doc("hello", "bar")] + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: unknown `doc` attribute `foo::bar` + --> $DIR/doc-attr.rs:20:7 + | +LL | #[doc(foo::bar, crate::bar::baz = "bye")] + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: unknown `doc` attribute `crate::bar::baz` + --> $DIR/doc-attr.rs:20:17 + | +LL | #[doc(foo::bar, crate::bar::baz = "bye")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr.rs:3:8 + | +LL | #![doc(as_ptr)] + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: aborting due to 7 previous errors + diff --git a/src/test/rustdoc-ui/doc-cfg.rs b/src/test/rustdoc-ui/doc-cfg.rs new file mode 100644 index 000000000..354d76bc3 --- /dev/null +++ b/src/test/rustdoc-ui/doc-cfg.rs @@ -0,0 +1,9 @@ +#![feature(doc_cfg)] + +#[doc(cfg(), cfg(foo, bar))] +//~^ ERROR +//~^^ ERROR +#[doc(cfg(foo), cfg(bar))] // ok! +#[doc(cfg())] //~ ERROR +#[doc(cfg(foo, bar))] //~ ERROR +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc-cfg.stderr b/src/test/rustdoc-ui/doc-cfg.stderr new file mode 100644 index 000000000..b379f6feb --- /dev/null +++ b/src/test/rustdoc-ui/doc-cfg.stderr @@ -0,0 +1,26 @@ +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:3:7 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:3:23 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^ + +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:7:7 + | +LL | #[doc(cfg())] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:8:16 + | +LL | #[doc(cfg(foo, bar))] + | ^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs b/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs new file mode 100644 index 000000000..97259f782 --- /dev/null +++ b/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs @@ -0,0 +1,11 @@ +// Regression test for #97440: Multiline inner attribute triggers ICE during doctest +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// check-pass + +//! ```rust +//! #![deny( +//! unused_parens, +//! )] +//! ``` diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout b/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout new file mode 100644 index 000000000..e47edbd2a --- /dev/null +++ b/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-comment-multi-line-attr.rs - (line 7) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs new file mode 100644 index 000000000..b2a8133c9 --- /dev/null +++ b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.rs @@ -0,0 +1,12 @@ +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// check-pass + +/// ``` +/// # #![cfg_attr(not(dox), deny(missing_abi, +/// # non_ascii_idents))] +/// +/// pub struct Bar; +/// ``` +pub struct Bar; diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.stdout b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.stdout new file mode 100644 index 000000000..bf3521e4f --- /dev/null +++ b/src/test/rustdoc-ui/doc-comment-multi-line-cfg-attr.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-comment-multi-line-cfg-attr.rs - Bar (line 6) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/doc-include-suggestion.rs b/src/test/rustdoc-ui/doc-include-suggestion.rs new file mode 100644 index 000000000..0c0100735 --- /dev/null +++ b/src/test/rustdoc-ui/doc-include-suggestion.rs @@ -0,0 +1,10 @@ +// check-pass + +#[doc(include = "external-cross-doc.md")] +//~^ WARNING unknown `doc` attribute `include` +//~| HELP use `doc = include_str!` instead +// FIXME(#85497): make this a deny instead so it's more clear what's happening +//~| NOTE on by default +//~| WARNING previously accepted +//~| NOTE see issue #82730 +pub struct NeedMoreDocs; diff --git a/src/test/rustdoc-ui/doc-include-suggestion.stderr b/src/test/rustdoc-ui/doc-include-suggestion.stderr new file mode 100644 index 000000000..870b7efa2 --- /dev/null +++ b/src/test/rustdoc-ui/doc-include-suggestion.stderr @@ -0,0 +1,12 @@ +warning: unknown `doc` attribute `include` + --> $DIR/doc-include-suggestion.rs:3:7 + | +LL | #[doc(include = "external-cross-doc.md")] + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]` + | + = note: `#[warn(invalid_doc_attributes)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/doc-spotlight.fixed b/src/test/rustdoc-ui/doc-spotlight.fixed new file mode 100644 index 000000000..4b58778ea --- /dev/null +++ b/src/test/rustdoc-ui/doc-spotlight.fixed @@ -0,0 +1,8 @@ +// run-rustfix +#![deny(warnings)] +#![feature(doc_notable_trait)] + +#[doc(notable_trait)] +//~^ ERROR unknown `doc` attribute `spotlight` +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +trait MyTrait {} diff --git a/src/test/rustdoc-ui/doc-spotlight.rs b/src/test/rustdoc-ui/doc-spotlight.rs new file mode 100644 index 000000000..16e387245 --- /dev/null +++ b/src/test/rustdoc-ui/doc-spotlight.rs @@ -0,0 +1,8 @@ +// run-rustfix +#![deny(warnings)] +#![feature(doc_notable_trait)] + +#[doc(spotlight)] +//~^ ERROR unknown `doc` attribute `spotlight` +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +trait MyTrait {} diff --git a/src/test/rustdoc-ui/doc-spotlight.stderr b/src/test/rustdoc-ui/doc-spotlight.stderr new file mode 100644 index 000000000..8e7831139 --- /dev/null +++ b/src/test/rustdoc-ui/doc-spotlight.stderr @@ -0,0 +1,19 @@ +error: unknown `doc` attribute `spotlight` + --> $DIR/doc-spotlight.rs:5:7 + | +LL | #[doc(spotlight)] + | ^^^^^^^^^ help: use `notable_trait` instead + | +note: the lint level is defined here + --> $DIR/doc-spotlight.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: `doc(spotlight)` was renamed to `doc(notable_trait)` + = note: `doc(spotlight)` is now a no-op + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/doc-test-attr-pass.rs b/src/test/rustdoc-ui/doc-test-attr-pass.rs new file mode 100644 index 000000000..12608f244 --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-attr-pass.rs @@ -0,0 +1,8 @@ +// check-pass + +#![crate_type = "lib"] +#![deny(invalid_doc_attributes)] +#![doc(test(no_crate_inject))] +#![doc(test(attr(deny(warnings))))] + +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc-test-attr.rs b/src/test/rustdoc-ui/doc-test-attr.rs new file mode 100644 index 000000000..46178ad86 --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-attr.rs @@ -0,0 +1,14 @@ +#![crate_type = "lib"] +#![deny(invalid_doc_attributes)] + +#![doc(test)] +//~^ ERROR `#[doc(test(...)]` takes a list of attributes +//~^^ WARN this was previously accepted by the compiler +#![doc(test = "hello")] +//~^ ERROR `#[doc(test(...)]` takes a list of attributes +//~^^ WARN this was previously accepted by the compiler +#![doc(test(a))] +//~^ ERROR unknown `doc(test)` attribute `a` +//~^^ WARN this was previously accepted by the compiler + +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc-test-attr.stderr b/src/test/rustdoc-ui/doc-test-attr.stderr new file mode 100644 index 000000000..7f5e2d6bc --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-attr.stderr @@ -0,0 +1,34 @@ +error: `#[doc(test(...)]` takes a list of attributes + --> $DIR/doc-test-attr.rs:4:8 + | +LL | #![doc(test)] + | ^^^^ + | +note: the lint level is defined here + --> $DIR/doc-test-attr.rs:2:9 + | +LL | #![deny(invalid_doc_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: `#[doc(test(...)]` takes a list of attributes + --> $DIR/doc-test-attr.rs:7:8 + | +LL | #![doc(test = "hello")] + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: unknown `doc(test)` attribute `a` + --> $DIR/doc-test-attr.rs:10:13 + | +LL | #![doc(test(a))] + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.rs b/src/test/rustdoc-ui/doc-test-doctest-feature.rs new file mode 100644 index 000000000..0b79aaece --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-doctest-feature.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// Make sure `cfg(doctest)` is set when finding doctests but not inside +// the doctests. + +/// ``` +/// assert!(!cfg!(doctest)); +/// ``` +#[cfg(doctest)] +pub struct Foo; diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.stdout b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout new file mode 100644 index 000000000..d7de1f105 --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-test-doctest-feature.rs - Foo (line 9) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs new file mode 100644 index 000000000..bf334c67e --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs @@ -0,0 +1,15 @@ +// check-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +#![feature(doc_cfg)] + +// Make sure `cfg(doc)` is set when finding doctests but not inside the doctests. + +/// ``` +/// #![feature(doc_cfg)] +/// assert!(!cfg!(doc)); +/// ``` +#[cfg(doc)] +pub struct Foo; diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout new file mode 100644 index 000000000..5b07fc4c8 --- /dev/null +++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-test-rustdoc-feature.rs - Foo (line 10) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs new file mode 100644 index 000000000..315fca195 --- /dev/null +++ b/src/test/rustdoc-ui/doc-without-codeblock.rs @@ -0,0 +1,22 @@ +#![deny(rustdoc::missing_doc_code_examples)] //~ ERROR missing code example in this documentation + +/// Some docs. +//~^ ERROR missing code example in this documentation +pub struct Foo; + +/// And then, the princess died. +//~^ ERROR missing code example in this documentation +pub mod foo { + /// Or maybe not because she saved herself! + //~^ ERROR missing code example in this documentation + pub fn bar() {} +} + +// This impl is here to ensure the lint isn't emitted for foreign traits implementations. +impl std::ops::Neg for Foo { + type Output = Self; + + fn neg(self) -> Self::Output { + Self + } +} diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr new file mode 100644 index 000000000..1c1380441 --- /dev/null +++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr @@ -0,0 +1,38 @@ +error: missing code example in this documentation + --> $DIR/doc-without-codeblock.rs:1:1 + | +LL | / #![deny(rustdoc::missing_doc_code_examples)] +LL | | +LL | | /// Some docs. +LL | | +... | +LL | | } +LL | | } + | |_^ + | +note: the lint level is defined here + --> $DIR/doc-without-codeblock.rs:1:9 + | +LL | #![deny(rustdoc::missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing code example in this documentation + --> $DIR/doc-without-codeblock.rs:7:1 + | +LL | /// And then, the princess died. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing code example in this documentation + --> $DIR/doc-without-codeblock.rs:10:5 + | +LL | /// Or maybe not because she saved herself! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing code example in this documentation + --> $DIR/doc-without-codeblock.rs:3:1 + | +LL | /// Some docs. + | ^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/doctest-edition.rs b/src/test/rustdoc-ui/doctest-edition.rs new file mode 100644 index 000000000..b0787be97 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.rs @@ -0,0 +1,16 @@ +// edition:2021 + +#![deny(rustdoc::invalid_rust_codeblocks)] +//~^ NOTE lint level is defined here + +// By default, rustdoc should use the edition of the crate. +//! ``` +//! foo'b' +//! ``` +//~^^^ ERROR could not parse +//~| NOTE prefix `foo` is unknown + +// Rustdoc should respect `edition2018` when highlighting syntax. +//! ```edition2018 +//! foo'b' +//! ``` diff --git a/src/test/rustdoc-ui/doctest-edition.stderr b/src/test/rustdoc-ui/doctest-edition.stderr new file mode 100644 index 000000000..1643d6053 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.stderr @@ -0,0 +1,22 @@ +error: could not parse code block as Rust code + --> $DIR/doctest-edition.rs:7:5 + | +LL | //! ``` + | _____^ +LL | | //! foo'b' +LL | | //! ``` + | |_______^ + | +note: the lint level is defined here + --> $DIR/doctest-edition.rs:3:9 + | +LL | #![deny(rustdoc::invalid_rust_codeblocks)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: error from rustc: prefix `foo` is unknown +help: mark blocks that do not contain Rust code as text + | +LL | //! ```text + | ++++ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs new file mode 100644 index 000000000..a30472ac5 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs @@ -0,0 +1,10 @@ +// compile-flags:--test --test-args=--test-threads=1 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// check-pass + +/// ``` +/// #![deprecated(since = "5.2", note = "foo was rarely used. \ +/// Users should instead use bar")] +/// ``` +pub fn f() {} diff --git a/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout new file mode 100644 index 000000000..07a4f657d --- /dev/null +++ b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doctest-multiline-crate-attribute.rs - f (line 6) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/doctest-output.rs b/src/test/rustdoc-ui/doctest-output.rs new file mode 100644 index 000000000..2670fa572 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-output.rs @@ -0,0 +1,28 @@ +// edition:2018 +// aux-build:extern_macros.rs +// compile-flags:--test --test-args=--test-threads=1 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// check-pass + +//! ``` +//! assert_eq!(1 + 1, 2); +//! ``` + +extern crate extern_macros as macros; + +use macros::attrs_on_struct; + +pub mod foo { + + /// ``` + /// assert_eq!(1 + 1, 2); + /// ``` + pub fn bar() {} +} + +attrs_on_struct! { + /// ``` + /// assert!(true); + /// ``` +} diff --git a/src/test/rustdoc-ui/doctest-output.stdout b/src/test/rustdoc-ui/doctest-output.stdout new file mode 100644 index 000000000..35b0e366f --- /dev/null +++ b/src/test/rustdoc-ui/doctest-output.stdout @@ -0,0 +1,8 @@ + +running 3 tests +test $DIR/doctest-output.rs - (line 8) ... ok +test $DIR/doctest-output.rs - ExpandedStruct (line 24) ... ok +test $DIR/doctest-output.rs - foo::bar (line 18) ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/error-in-impl-trait/README.md b/src/test/rustdoc-ui/error-in-impl-trait/README.md new file mode 100644 index 000000000..1176a4a8c --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/README.md @@ -0,0 +1,7 @@ +Each of these needs to be in a separate file, +because the `delay_span_bug` ICE in rustdoc won't be triggerred +if even a single other error was emitted. + +However, conceptually they are all testing basically the same thing. +See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128 +for more details. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs new file mode 100644 index 000000000..cda53bff0 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.rs @@ -0,0 +1,7 @@ +// edition:2018 +// check-pass + +/// Should compile fine +pub async fn a() -> u32 { + error::_in::async_fn() +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs new file mode 100644 index 000000000..f1fd85bb2 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs @@ -0,0 +1,5 @@ +// check-pass +// manually desugared version of an `async fn` (but with a closure instead of a generator) +pub fn a() -> impl Fn() -> u32 { + || content::doesnt::matter() +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs b/src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs new file mode 100644 index 000000000..ed62f0208 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/const-generics.rs @@ -0,0 +1,23 @@ +// check-pass +// edition:2018 +trait ValidTrait {} + +/// This has docs +pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]> { + loop {} +} + +pub trait Trait<const N: usize> {} +impl Trait<1> for u8 {} +impl Trait<2> for u8 {} +impl<const N: usize> Trait<N> for [u8; N] {} + +/// This also has docs +pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> { + loop {} +} + +/// Document all the functions +pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> { + loop {} +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs new file mode 100644 index 000000000..dcec379d4 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs @@ -0,0 +1,7 @@ +// check-pass +trait ValidTrait {} + +/// This has docs +pub fn f() -> impl ValidTrait { + Vec::<DoesNotExist>::new() +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs new file mode 100644 index 000000000..b935b0832 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs @@ -0,0 +1,6 @@ +// check-pass +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + (|| error::_in::impl_trait::alias::nested::closure())() +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs new file mode 100644 index 000000000..701126f87 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs @@ -0,0 +1,6 @@ +// check-pass +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + error::_in::impl_trait() +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs b/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs new file mode 100644 index 000000000..248575d35 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs @@ -0,0 +1,28 @@ +// edition:2018 +// check-pass + +mod windows { + pub trait WinFoo { + fn foo(&self) {} + } + + impl WinFoo for () {} +} + +#[cfg(any(windows, doc))] +use windows::*; + +mod unix { + pub trait UnixFoo { + fn foo(&self) {} + } + + impl UnixFoo for () {} +} + +#[cfg(any(unix, doc))] +use unix::*; + +async fn bar() { + ().foo() +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs new file mode 100644 index 000000000..31dd786cb --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs @@ -0,0 +1,10 @@ +// check-pass +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + (|| error::_in::impl_trait::alias::nested::closure())() +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs new file mode 100644 index 000000000..c18a024af --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs @@ -0,0 +1,10 @@ +// check-pass +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + error::_in::impl_trait::alias() +} diff --git a/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs new file mode 100644 index 000000000..0901ac364 --- /dev/null +++ b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs @@ -0,0 +1,157 @@ +// check-pass +#![feature(lint_reasons)] + +//! This file tests the `#[expect]` attribute implementation for tool lints. The same +//! file is used to test clippy and rustdoc. Any changes to this file should be synced +//! to the other test files as well. +//! +//! Expectations: +//! * rustc: only rustc lint expectations are emitted +//! * clippy: rustc and Clippy's expectations are emitted +//! * rustdoc: only rustdoc lint expectations are emitted +//! +//! This test can't cover every lint from Clippy, rustdoc and potentially other +//! tools that will be developed. This therefore only tests a small subset of lints + +#![expect(rustdoc::missing_crate_level_docs)] +//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] +//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default + +mod rustc_ok { + //! See <https://doc.rust-lang.org/rustc/lints/index.html> + + #[expect(dead_code)] + pub fn rustc_lints() { + let x = 42.0; + + #[expect(illegal_floating_point_literal_pattern)] + match x { + 5.0 => {} + 6.0 => {} + _ => {} + } + } +} + +mod rustc_warn { + //! See <https://doc.rust-lang.org/rustc/lints/index.html> + + #[expect(dead_code)] + pub fn rustc_lints() { + let x = 42; + + #[expect(illegal_floating_point_literal_pattern)] + match x { + 5 => {} + 6 => {} + _ => {} + } + } +} + +pub mod rustdoc_ok { + //! See <https://doc.rust-lang.org/rustdoc/lints.html> + + #[expect(rustdoc::broken_intra_doc_links)] + /// I want to link to [`Nonexistent`] but it doesn't exist! + pub fn foo() {} + + #[expect(rustdoc::invalid_html_tags)] + /// <h1> + pub fn bar() {} + + #[expect(rustdoc::bare_urls)] + /// http://example.org + pub fn baz() {} +} + +pub mod rustdoc_warn { + //! See <https://doc.rust-lang.org/rustdoc/lints.html> + + #[expect(rustdoc::broken_intra_doc_links)] + //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + /// I want to link to [`bar`] but it doesn't exist! + pub fn foo() {} + + #[expect(rustdoc::invalid_html_tags)] + //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + /// <h1></h1> + pub fn bar() {} + + #[expect(rustdoc::bare_urls)] + //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + /// <http://example.org> + pub fn baz() {} +} + +mod clippy_ok { + //! See <https://rust-lang.github.io/rust-clippy/master/index.html> + + #[expect(clippy::almost_swapped)] + fn foo() { + let mut a = 0; + let mut b = 9; + a = b; + b = a; + } + + #[expect(clippy::bytes_nth)] + fn bar() { + let _ = "Hello".bytes().nth(3); + } + + #[expect(clippy::if_same_then_else)] + fn baz() { + let _ = if true { + 42 + } else { + 42 + }; + } + + #[expect(clippy::logic_bug)] + fn burger() { + let a = false; + let b = true; + + if a && b || a {} + } +} + +mod clippy_warn { + //! See <https://rust-lang.github.io/rust-clippy/master/index.html> + + #[expect(clippy::almost_swapped)] + fn foo() { + let mut a = 0; + let mut b = 9; + a = b; + } + + #[expect(clippy::bytes_nth)] + fn bar() { + let _ = "Hello".as_bytes().get(3); + } + + #[expect(clippy::if_same_then_else)] + fn baz() { + let _ = if true { + 33 + } else { + 42 + }; + } + + #[expect(clippy::logic_bug)] + fn burger() { + let a = false; + let b = true; + let c = false; + + if a && b || c {} + } +} + +fn main() { + rustc_warn::rustc_lints(); +} diff --git a/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr new file mode 100644 index 000000000..efc5f349f --- /dev/null +++ b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr @@ -0,0 +1,28 @@ +warning: this lint expectation is unfulfilled + --> $DIR/expect-tool-lint-rfc-2383.rs:16:11 + | +LL | #![expect(rustdoc::missing_crate_level_docs)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unfulfilled_lint_expectations)]` on by default + +warning: this lint expectation is unfulfilled + --> $DIR/expect-tool-lint-rfc-2383.rs:71:14 + | +LL | #[expect(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: this lint expectation is unfulfilled + --> $DIR/expect-tool-lint-rfc-2383.rs:76:14 + | +LL | #[expect(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: this lint expectation is unfulfilled + --> $DIR/expect-tool-lint-rfc-2383.rs:81:14 + | +LL | #[expect(rustdoc::bare_urls)] + | ^^^^^^^^^^^^^^^^^^ + +warning: 4 warnings emitted + diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.rs b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs new file mode 100644 index 000000000..6f2ff5d70 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs @@ -0,0 +1,12 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 + +/// ```compile_fail +/// println!("Hello"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout new file mode 100644 index 000000000..af3a90a74 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout @@ -0,0 +1,14 @@ + +running 1 test +test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) - compile fail ... FAILED + +failures: + +---- $DIR/failed-doctest-compile-fail.rs - Foo (line 9) stdout ---- +Test compiled successfully, but it's marked `compile_fail`. + +failures: + $DIR/failed-doctest-compile-fail.rs - Foo (line 9) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.rs b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.rs new file mode 100644 index 000000000..16d737106 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.rs @@ -0,0 +1,18 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 + +/// <https://github.com/rust-lang/rust/issues/91014> +/// +/// ```rust +/// struct S {}; // unexpected semicolon after struct def +/// +/// fn main() { +/// assert_eq!(0, 1); +/// } +/// ``` +mod m {} diff --git a/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.stdout b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.stdout new file mode 100644 index 000000000..61468b6c7 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-extra-semicolon-on-item.stdout @@ -0,0 +1,24 @@ + +running 1 test +test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... FAILED + +failures: + +---- $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) stdout ---- +error: expected item, found `;` + --> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12 + | +LL | struct S {}; // unexpected semicolon after struct def + | ^ help: remove this semicolon + | + = help: braced struct declarations are not followed by a semicolon + +error: aborting due to previous error + +Couldn't compile the test. + +failures: + $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.rs b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs new file mode 100644 index 000000000..57b70b478 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs @@ -0,0 +1,12 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 + +/// ```compile_fail,E0004 +/// let x: () = 5i32; +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout new file mode 100644 index 000000000..bacbb47b5 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout @@ -0,0 +1,25 @@ + +running 1 test +test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) - compile fail ... FAILED + +failures: + +---- $DIR/failed-doctest-missing-codes.rs - Foo (line 9) stdout ---- +error[E0308]: mismatched types + --> $DIR/failed-doctest-missing-codes.rs:10:13 + | +LL | let x: () = 5i32; + | -- ^^^^ expected `()`, found `i32` + | | + | expected due to this + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. +Some expected error codes were not found: ["E0004"] + +failures: + $DIR/failed-doctest-missing-codes.rs - Foo (line 9) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.rs b/src/test/rustdoc-ui/failed-doctest-output-windows.rs new file mode 100644 index 000000000..4cd9993d8 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-output-windows.rs @@ -0,0 +1,28 @@ +// only-windows +// There's a parallel generic version of this test for non-windows platforms. + +// Issue #51162: A failed doctest was not printing its stdout/stderr +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test --test-args --test-threads=1 +// rustc-env:RUST_BACKTRACE=0 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 + +// doctest fails at runtime +/// ``` +/// println!("stdout 1"); +/// eprintln!("stderr 1"); +/// println!("stdout 2"); +/// eprintln!("stderr 2"); +/// panic!("oh no"); +/// ``` +pub struct SomeStruct; + +// doctest fails at compile time +/// ``` +/// no +/// ``` +pub struct OtherStruct; diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.stdout b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout new file mode 100644 index 000000000..6c147054d --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout @@ -0,0 +1,39 @@ + +running 2 tests +test $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) ... FAILED +test $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) ... FAILED + +failures: + +---- $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) stdout ---- +error[E0425]: cannot find value `no` in this scope + --> $DIR/failed-doctest-output-windows.rs:26:1 + | +LL | no + | ^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. +Couldn't compile the test. +---- $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) stdout ---- +Test executable failed (exit code: 101). + +stdout: +stdout 1 +stdout 2 + +stderr: +stderr 1 +stderr 2 +thread 'main' panicked at 'oh no', $DIR/failed-doctest-output-windows.rs:7:1 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + + +failures: + $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) + $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) + +test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs new file mode 100644 index 000000000..42de954d0 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -0,0 +1,28 @@ +// ignore-windows +// There's a parallel version of this test for Windows. + +// Issue #51162: A failed doctest was not printing its stdout/stderr +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test --test-args --test-threads=1 +// rustc-env:RUST_BACKTRACE=0 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 + +// doctest fails at runtime +/// ``` +/// println!("stdout 1"); +/// eprintln!("stderr 1"); +/// println!("stdout 2"); +/// eprintln!("stderr 2"); +/// panic!("oh no"); +/// ``` +pub struct SomeStruct; + +// doctest fails at compile time +/// ``` +/// no +/// ``` +pub struct OtherStruct; diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout new file mode 100644 index 000000000..630198a56 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -0,0 +1,39 @@ + +running 2 tests +test $DIR/failed-doctest-output.rs - OtherStruct (line 25) ... FAILED +test $DIR/failed-doctest-output.rs - SomeStruct (line 15) ... FAILED + +failures: + +---- $DIR/failed-doctest-output.rs - OtherStruct (line 25) stdout ---- +error[E0425]: cannot find value `no` in this scope + --> $DIR/failed-doctest-output.rs:26:1 + | +LL | no + | ^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. +Couldn't compile the test. +---- $DIR/failed-doctest-output.rs - SomeStruct (line 15) stdout ---- +Test executable failed (exit status: 101). + +stdout: +stdout 1 +stdout 2 + +stderr: +stderr 1 +stderr 2 +thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:7:1 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + + +failures: + $DIR/failed-doctest-output.rs - OtherStruct (line 25) + $DIR/failed-doctest-output.rs - SomeStruct (line 15) + +test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.rs b/src/test/rustdoc-ui/failed-doctest-should-panic.rs new file mode 100644 index 000000000..2b8bb3168 --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-should-panic.rs @@ -0,0 +1,12 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 + +/// ```should_panic +/// println!("Hello, world!"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.stdout b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout new file mode 100644 index 000000000..57a20092a --- /dev/null +++ b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout @@ -0,0 +1,14 @@ + +running 1 test +test $DIR/failed-doctest-should-panic.rs - Foo (line 9) ... FAILED + +failures: + +---- $DIR/failed-doctest-should-panic.rs - Foo (line 9) stdout ---- +Test executable succeeded, but it's marked `should_panic`. + +failures: + $DIR/failed-doctest-should-panic.rs - Foo (line 9) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs new file mode 100644 index 000000000..17812018b --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs @@ -0,0 +1,7 @@ +#![doc(cfg_hide(test))] +//~^ ERROR `#[doc(cfg_hide)]` is experimental + +#[cfg(not(test))] +pub fn public_fn() {} +#[cfg(test)] +pub fn internal_use_only() {} diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr new file mode 100644 index 000000000..ba42c7bbb --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr @@ -0,0 +1,14 @@ +error[E0658]: `#[doc(cfg_hide)]` is experimental + --> $DIR/feature-gate-doc_cfg_hide.rs:1:1 + | +LL | #![doc(cfg_hide(test))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information + = help: add `#![feature(doc_cfg_hide)]` to the crate attributes to enable + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs new file mode 100644 index 000000000..87620d74e --- /dev/null +++ b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs @@ -0,0 +1,6 @@ +// This test purpose is to check that the "--generate-link-to-definition" +// option can only be used on nightly. + +// compile-flags: --generate-link-to-definition + +pub fn f() {} diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr new file mode 100644 index 000000000..a8ddf91bc --- /dev/null +++ b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the flag `generate-link-to-definition` + diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt.rs new file mode 100644 index 000000000..8f4f561b4 --- /dev/null +++ b/src/test/rustdoc-ui/generate-link-to-definition-opt.rs @@ -0,0 +1,6 @@ +// This test purpose is to check that the "--generate-link-to-definition" +// option can only be used with HTML generation. + +// compile-flags: -Zunstable-options --generate-link-to-definition --output-format json + +pub fn f() {} diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr new file mode 100644 index 000000000..4c8c607e7 --- /dev/null +++ b/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr @@ -0,0 +1,2 @@ +error: --generate-link-to-definition option can only be used with HTML output format + diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs new file mode 100644 index 000000000..da5142087 --- /dev/null +++ b/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs @@ -0,0 +1,6 @@ +// This test purpose is to check that the "--generate-link-to-definition" +// option can only be used with HTML generation. + +// compile-flags: -Zunstable-options --generate-link-to-definition --show-coverage + +pub fn f() {} diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr new file mode 100644 index 000000000..4c8c607e7 --- /dev/null +++ b/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr @@ -0,0 +1,2 @@ +error: --generate-link-to-definition option can only be used with HTML output format + diff --git a/src/test/rustdoc-ui/ignore-block-help.rs b/src/test/rustdoc-ui/ignore-block-help.rs new file mode 100644 index 000000000..86f6a2868 --- /dev/null +++ b/src/test/rustdoc-ui/ignore-block-help.rs @@ -0,0 +1,10 @@ +// check-pass + +/// ```ignore (to-prevent-tidy-error) +/// let heart = '❤️'; +/// ``` +//~^^^ WARNING could not parse code block +//~| NOTE on by default +//~| NOTE character literal may only contain one codepoint +//~| HELP `ignore` code blocks require valid Rust code +pub struct X; diff --git a/src/test/rustdoc-ui/ignore-block-help.stderr b/src/test/rustdoc-ui/ignore-block-help.stderr new file mode 100644 index 000000000..9c02ff11d --- /dev/null +++ b/src/test/rustdoc-ui/ignore-block-help.stderr @@ -0,0 +1,19 @@ +warning: could not parse code block as Rust code + --> $DIR/ignore-block-help.rs:3:5 + | +LL | /// ```ignore (to-prevent-tidy-error) + | _____^ +LL | | /// let heart = '❤️'; +LL | | /// ``` + | |_______^ + | + = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default +help: `ignore` code blocks require valid Rust code for syntax highlighting; mark blocks that do not contain Rust code as text: ```text + --> $DIR/ignore-block-help.rs:3:5 + | +LL | /// ```ignore (to-prevent-tidy-error) + | ^^^ + = note: error from rustc: character literal may only contain one codepoint + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs new file mode 100644 index 000000000..a927f6bd7 --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.rs @@ -0,0 +1,49 @@ +// Ensure that rustdoc gives errors for trait impls inside function bodies that don't resolve. +// See https://github.com/rust-lang/rust/pull/73566 +pub struct ValidType; +pub trait ValidTrait {} +pub trait NeedsBody { + type Item; + fn f(); +} + +/// This function has docs +pub fn f<B: UnknownBound>(a: UnknownType, b: B) { +//~^ ERROR cannot find trait `UnknownBound` in this scope +//~| ERROR cannot find type `UnknownType` in this scope + impl UnknownTrait for ValidType {} //~ ERROR cannot find trait `UnknownTrait` + impl<T: UnknownBound> UnknownTrait for T {} + //~^ ERROR cannot find trait `UnknownBound` in this scope + //~| ERROR cannot find trait `UnknownTrait` in this scope + impl ValidTrait for UnknownType {} + //~^ ERROR cannot find type `UnknownType` in this scope + impl ValidTrait for ValidType where ValidTrait: UnknownBound {} + //~^ ERROR cannot find trait `UnknownBound` in this scope + + /// This impl has documentation + impl NeedsBody for ValidType { + type Item = UnknownType; + //~^ ERROR cannot find type `UnknownType` in this scope + + /// This function has documentation + fn f() { + <UnknownTypeShouldBeIgnored>::a(); + content::shouldnt::matter(); + unknown_macro!(); + //~^ ERROR cannot find macro `unknown_macro` in this scope + + /// This is documentation for a macro + macro_rules! can_define_macros_here_too { + () => { + this::content::should::also::be::ignored() + } + } + can_define_macros_here_too!(); + + /// This also is documented. + pub fn doubly_nested(c: UnknownType) { + //~^ ERROR cannot find type `UnknownType` in this scope + } + } + } +} diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr new file mode 100644 index 000000000..608749af8 --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.stderr @@ -0,0 +1,66 @@ +error: cannot find macro `unknown_macro` in this scope + --> $DIR/impl-fn-nesting.rs:32:13 + | +LL | unknown_macro!(); + | ^^^^^^^^^^^^^ + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:11:13 + | +LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) { + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:11:30 + | +LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) { + | ^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownTrait` in this scope + --> $DIR/impl-fn-nesting.rs:14:10 + | +LL | impl UnknownTrait for ValidType {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownTrait` in this scope + --> $DIR/impl-fn-nesting.rs:15:27 + | +LL | impl<T: UnknownBound> UnknownTrait for T {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:15:13 + | +LL | impl<T: UnknownBound> UnknownTrait for T {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:18:25 + | +LL | impl ValidTrait for UnknownType {} + | ^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:20:53 + | +LL | impl ValidTrait for ValidType where ValidTrait: UnknownBound {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:25:21 + | +LL | type Item = UnknownType; + | ^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:44:37 + | +LL | pub fn doubly_nested(c: UnknownType) { + | ^^^^^^^^^^^ not found in this scope + +error: Compilation failed, aborting rustdoc + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0405, E0412. +For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs new file mode 100644 index 000000000..2319de556 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs @@ -0,0 +1,15 @@ +// normalize-stderr-test: "`.*`" -> "`DEF_ID`" +// normalize-stdout-test: "`.*`" -> "`DEF_ID`" +// edition:2018 + +pub async fn f() -> impl std::fmt::Debug { + #[derive(Debug)] + enum E { + //~^ ERROR recursive type `f::{closure#0}::E` has infinite size + This(E), + Unit, + } + E::Unit +} + +fn main() {} diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr new file mode 100644 index 000000000..aa39d26fe --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `DEF_ID` has infinite size + --> $DIR/infinite-recursive-type-impl-trait-return.rs:7:5 + | +LL | enum E { + | ^^^^^^ recursive type has infinite size +LL | +LL | This(E), + | - recursive without indirection + | +help: insert some indirection (e.g., a `DEF_ID` representable + | +LL | This(Box<E>), + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `DEF_ID`. diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs new file mode 100644 index 000000000..b3a7ee563 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.rs @@ -0,0 +1,7 @@ +fn f() -> impl Sized { + enum E { + //~^ ERROR recursive type `f::E` has infinite size + V(E), + } + unimplemented!() +} diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr new file mode 100644 index 000000000..009bedec5 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `f::E` has infinite size + --> $DIR/infinite-recursive-type-impl-trait.rs:2:5 + | +LL | enum E { + | ^^^^^^ recursive type has infinite size +LL | +LL | V(E), + | - recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `f::E` representable + | +LL | V(Box<E>), + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/rustdoc-ui/infinite-recursive-type.rs b/src/test/rustdoc-ui/infinite-recursive-type.rs new file mode 100644 index 000000000..32793fc4f --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.rs @@ -0,0 +1,4 @@ +enum E { +//~^ ERROR recursive type `E` has infinite size + V(E), +} diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr new file mode 100644 index 000000000..b33aba446 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `E` has infinite size + --> $DIR/infinite-recursive-type.rs:1:1 + | +LL | enum E { + | ^^^^^^ recursive type has infinite size +LL | +LL | V(E), + | - recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable + | +LL | V(Box<E>), + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/rustdoc-ui/intra-doc/alias-ice.rs b/src/test/rustdoc-ui/intra-doc/alias-ice.rs new file mode 100644 index 000000000..51922caeb --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/alias-ice.rs @@ -0,0 +1,6 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +pub type TypeAlias = usize; + +/// [broken cross-reference](TypeAlias::hoge) //~ ERROR +pub fn some_public_item() {} diff --git a/src/test/rustdoc-ui/intra-doc/alias-ice.stderr b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr new file mode 100644 index 000000000..5e7ffeeb8 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr @@ -0,0 +1,14 @@ +error: unresolved link to `TypeAlias::hoge` + --> $DIR/alias-ice.rs:5:30 + | +LL | /// [broken cross-reference](TypeAlias::hoge) + | ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge` + | +note: the lint level is defined here + --> $DIR/alias-ice.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-doc/ambiguity.rs b/src/test/rustdoc-ui/intra-doc/ambiguity.rs new file mode 100644 index 000000000..1f3dc722e --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/ambiguity.rs @@ -0,0 +1,40 @@ +#![deny(rustdoc::broken_intra_doc_links)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +pub fn ambiguous() {} + +pub struct ambiguous {} + +#[macro_export] +macro_rules! multi_conflict { () => {} } + +#[allow(non_camel_case_types)] +pub struct multi_conflict {} + +pub fn multi_conflict() {} + +pub mod type_and_value {} + +pub const type_and_value: i32 = 0; + +pub mod foo { + pub enum bar {} + + pub fn bar() {} +} + +/// [`ambiguous`] is ambiguous. //~ERROR `ambiguous` +/// +/// [ambiguous] is ambiguous. //~ERROR ambiguous +/// +/// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` +/// +/// Ambiguous [type_and_value]. //~ERROR type_and_value +/// +/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` +pub struct Docs {} + +/// [true] //~ ERROR `true` is both a module and a builtin type +/// [primitive@true] +pub mod r#true {} diff --git a/src/test/rustdoc-ui/intra-doc/ambiguity.stderr b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr new file mode 100644 index 000000000..7974796e4 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr @@ -0,0 +1,101 @@ +error: `true` is both a module and a builtin type + --> $DIR/ambiguity.rs:38:6 + | +LL | /// [true] + | ^^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/ambiguity.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the module, prefix with `mod@` + | +LL | /// [mod@true] + | ++++ +help: to link to the builtin type, prefix with `prim@` + | +LL | /// [prim@true] + | +++++ + +error: `ambiguous` is both a struct and a function + --> $DIR/ambiguity.rs:27:7 + | +LL | /// [`ambiguous`] is ambiguous. + | ^^^^^^^^^ ambiguous link + | +help: to link to the struct, prefix with `struct@` + | +LL | /// [`struct@ambiguous`] is ambiguous. + | +++++++ +help: to link to the function, add parentheses + | +LL | /// [`ambiguous()`] is ambiguous. + | ++ + +error: `ambiguous` is both a struct and a function + --> $DIR/ambiguity.rs:29:6 + | +LL | /// [ambiguous] is ambiguous. + | ^^^^^^^^^ ambiguous link + | +help: to link to the struct, prefix with `struct@` + | +LL | /// [struct@ambiguous] is ambiguous. + | +++++++ +help: to link to the function, add parentheses + | +LL | /// [ambiguous()] is ambiguous. + | ++ + +error: `multi_conflict` is a struct, a function, and a macro + --> $DIR/ambiguity.rs:31:7 + | +LL | /// [`multi_conflict`] is a three-way conflict. + | ^^^^^^^^^^^^^^ ambiguous link + | +help: to link to the struct, prefix with `struct@` + | +LL | /// [`struct@multi_conflict`] is a three-way conflict. + | +++++++ +help: to link to the function, add parentheses + | +LL | /// [`multi_conflict()`] is a three-way conflict. + | ++ +help: to link to the macro, add an exclamation mark + | +LL | /// [`multi_conflict!`] is a three-way conflict. + | + + +error: `type_and_value` is both a module and a constant + --> $DIR/ambiguity.rs:33:16 + | +LL | /// Ambiguous [type_and_value]. + | ^^^^^^^^^^^^^^ ambiguous link + | +help: to link to the module, prefix with `mod@` + | +LL | /// Ambiguous [mod@type_and_value]. + | ++++ +help: to link to the constant, prefix with `const@` + | +LL | /// Ambiguous [const@type_and_value]. + | ++++++ + +error: `foo::bar` is both an enum and a function + --> $DIR/ambiguity.rs:35:43 + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. + | ^^^^^^^^ ambiguous link + | +help: to link to the enum, prefix with `enum@` + | +LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. + | +++++ +help: to link to the function, add parentheses + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar()`]. + | ++ + +error: aborting due to 6 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/anchors.rs b/src/test/rustdoc-ui/intra-doc/anchors.rs new file mode 100644 index 000000000..34e11c7c7 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/anchors.rs @@ -0,0 +1,39 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +// A few tests on anchors. + +/// Hello people. +/// +/// You can anchors? Here's one! +/// +/// # hola +/// +/// Isn't it amazing? +pub struct Foo { + pub f: u8, +} + +pub enum Enum { + A, + B, +} + +/// Have you heard about stuff? +/// +/// Like [Foo#hola]. +/// +/// Or maybe [Foo::f#hola]. +//~^ ERROR `Foo::f#hola` contains an anchor +pub fn foo() {} + +/// Empty. +/// +/// Another anchor error: [hello#people#!]. +//~^ ERROR `hello#people#!` contains multiple anchors +pub fn bar() {} + +/// Empty? +/// +/// Damn enum's variants: [Enum::A#whatever]. +//~^ ERROR `Enum::A#whatever` contains an anchor +pub fn enum_link() {} diff --git a/src/test/rustdoc-ui/intra-doc/anchors.stderr b/src/test/rustdoc-ui/intra-doc/anchors.stderr new file mode 100644 index 000000000..0d226b277 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/anchors.stderr @@ -0,0 +1,32 @@ +error: `Foo::f#hola` contains an anchor, but links to fields are already anchored + --> $DIR/anchors.rs:25:15 + | +LL | /// Or maybe [Foo::f#hola]. + | ^^^^^^----- + | | + | invalid anchor + | +note: the lint level is defined here + --> $DIR/anchors.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `hello#people#!` contains multiple anchors + --> $DIR/anchors.rs:31:28 + | +LL | /// Another anchor error: [hello#people#!]. + | ^^^^^^^^^^^^-- + | | + | invalid anchor + +error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored + --> $DIR/anchors.rs:37:28 + | +LL | /// Damn enum's variants: [Enum::A#whatever]. + | ^^^^^^^--------- + | | + | invalid anchor + +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/assoc-field.rs b/src/test/rustdoc-ui/intra-doc/assoc-field.rs new file mode 100644 index 000000000..e18404e44 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/assoc-field.rs @@ -0,0 +1,26 @@ +// Traits in scope are collected for doc links in field attributes. + +// check-pass +// aux-build: assoc-field-dep.rs + +extern crate assoc_field_dep; +pub use assoc_field_dep::*; + +#[derive(Clone)] +pub struct Struct; + +pub mod mod1 { + pub struct Fields { + /// [crate::Struct::clone] + pub field: u8, + } +} + +pub mod mod2 { + pub enum Fields { + V { + /// [crate::Struct::clone] + field: u8, + }, + } +} diff --git a/src/test/rustdoc-ui/intra-doc/assoc-mod-inner-outer.rs b/src/test/rustdoc-ui/intra-doc/assoc-mod-inner-outer.rs new file mode 100644 index 000000000..b4ce3443c --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/assoc-mod-inner-outer.rs @@ -0,0 +1,19 @@ +// Traits in scope are collected for doc links in both outer and inner module attributes. + +// check-pass +// aux-build: assoc-mod-inner-outer-dep.rs + +extern crate assoc_mod_inner_outer_dep; +pub use assoc_mod_inner_outer_dep::*; + +#[derive(Clone)] +pub struct Struct; + +pub mod outer1 { + /// [crate::Struct::clone] + pub mod inner {} +} + +pub mod outer2 { + //! [crate::Struct::clone] +} diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs new file mode 100644 index 000000000..cfb24fc2c --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs @@ -0,0 +1,18 @@ +#[derive(Clone)] +pub struct Struct; + +pub mod dep_mod1 { + pub struct Fields { + /// [crate::Struct::clone] + pub field: u8, + } +} + +pub mod dep_mod2 { + pub enum Fields { + V { + /// [crate::Struct::clone] + field: u8, + }, + } +} diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-mod-inner-outer-dep.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-mod-inner-outer-dep.rs new file mode 100644 index 000000000..7a11a1657 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-mod-inner-outer-dep.rs @@ -0,0 +1,11 @@ +#[derive(Clone)] +pub struct Struct; + +pub mod dep_outer1 { + /// [crate::Struct::clone] + pub mod inner {} +} + +pub mod dep_outer2 { + //! [crate::Struct::clone] +} diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs new file mode 100644 index 000000000..d11c69f81 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs new file mode 100644 index 000000000..d11c69f81 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs new file mode 100644 index 000000000..d11c69f81 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs new file mode 100644 index 000000000..d11c69f81 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs new file mode 100644 index 000000000..31a8310d4 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs @@ -0,0 +1,4 @@ +#![crate_name = "intra_doc_broken"] + +/// [not_found] +pub fn foo() {} diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/pointer-reexports-allowed.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/pointer-reexports-allowed.rs new file mode 100644 index 000000000..0a3dc57f1 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/pointer-reexports-allowed.rs @@ -0,0 +1,4 @@ +#![feature(intra_doc_pointers)] +#![crate_name = "inner"] +/// Link to [some pointer](*const::to_raw_parts) +pub fn foo() {} diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs new file mode 100644 index 000000000..5c4a01ee3 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs @@ -0,0 +1,20 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] +#![crate_name="some_macros"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream { + item // This doesn't erase the spans. +} + +#[proc_macro_attribute] +pub fn second(_attr: TokenStream, item: TokenStream) -> TokenStream { + // Make a new `TokenStream` to erase the spans: + let mut out: TokenStream = TokenStream::new(); + out.extend(item); + out +} diff --git a/src/test/rustdoc-ui/intra-doc/broken-reexport.rs b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs new file mode 100644 index 000000000..862faa50b --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs @@ -0,0 +1,8 @@ +// aux-build:intra-doc-broken.rs +// check-pass + +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate intra_doc_broken; + +pub use intra_doc_broken::foo; diff --git a/src/test/rustdoc-ui/intra-doc/crate-nonexistent.rs b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.rs new file mode 100644 index 000000000..ceecfa681 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.rs @@ -0,0 +1,5 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +/// [crate::DoesNotExist] +//~^ ERROR unresolved link to `crate::DoesNotExist` +pub struct Item; diff --git a/src/test/rustdoc-ui/intra-doc/crate-nonexistent.stderr b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.stderr new file mode 100644 index 000000000..a69b1c52a --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/crate-nonexistent.stderr @@ -0,0 +1,14 @@ +error: unresolved link to `crate::DoesNotExist` + --> $DIR/crate-nonexistent.rs:3:6 + | +LL | /// [crate::DoesNotExist] + | ^^^^^^^^^^^^^^^^^^^ no item named `DoesNotExist` in module `crate_nonexistent` + | +note: the lint level is defined here + --> $DIR/crate-nonexistent.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs new file mode 100644 index 000000000..2d6656611 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs @@ -0,0 +1,81 @@ +#![deny(rustdoc::broken_intra_doc_links)] +//~^ NOTE lint level is defined +pub enum S {} +fn S() {} + +#[macro_export] +macro_rules! m { + () => {}; +} + +static s: usize = 0; +const c: usize = 0; + +trait T {} + +/// Link to [struct@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP prefix with `enum@` + +/// Link to [mod@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP prefix with `enum@` + +/// Link to [union@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP prefix with `enum@` + +/// Link to [trait@S] +//~^ ERROR incompatible link kind for `S` +//~| NOTE this link resolved +//~| HELP prefix with `enum@` + +/// Link to [struct@T] +//~^ ERROR incompatible link kind for `T` +//~| NOTE this link resolved +//~| HELP prefix with `trait@` + +/// Link to [derive@m] +//~^ ERROR incompatible link kind for `m` +//~| NOTE this link resolved +//~| HELP add an exclamation mark + +/// Link to [m()] +//~^ ERROR unresolved link to `m` +//~| NOTE this link resolves to the macro `m` +//~| HELP add an exclamation mark +/// and to [m!()] + +/// Link to [const@s] +//~^ ERROR incompatible link kind for `s` +//~| NOTE this link resolved +//~| HELP prefix with `static@` + +/// Link to [static@c] +//~^ ERROR incompatible link kind for `c` +//~| NOTE this link resolved +//~| HELP prefix with `const@` + +/// Link to [fn@c] +//~^ ERROR incompatible link kind for `c` +//~| NOTE this link resolved +//~| HELP prefix with `const@` + +/// Link to [c()] +//~^ ERROR incompatible link kind for `c` +//~| NOTE this link resolved +//~| HELP prefix with `const@` + +/// Link to [const@f] +//~^ ERROR incompatible link kind for `f` +//~| NOTE this link resolved +//~| HELP add parentheses + +/// Link to [fn@std] +//~^ ERROR unresolved link to `std` +//~| NOTE this link resolves to the crate `std` +//~| HELP to link to the crate, prefix with `mod@` +pub fn f() {} diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr new file mode 100644 index 000000000..ee35749ce --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -0,0 +1,153 @@ +error: incompatible link kind for `S` + --> $DIR/disambiguator-mismatch.rs:16:14 + | +LL | /// Link to [struct@S] + | ^^^^^^^^ this link resolved to an enum, which is not a struct + | +note: the lint level is defined here + --> $DIR/disambiguator-mismatch.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the enum, prefix with `enum@` + | +LL | /// Link to [enum@S] + | ~~~~~ + +error: incompatible link kind for `S` + --> $DIR/disambiguator-mismatch.rs:21:14 + | +LL | /// Link to [mod@S] + | ^^^^^ this link resolved to an enum, which is not a module + | +help: to link to the enum, prefix with `enum@` + | +LL | /// Link to [enum@S] + | ~~~~~ + +error: incompatible link kind for `S` + --> $DIR/disambiguator-mismatch.rs:26:14 + | +LL | /// Link to [union@S] + | ^^^^^^^ this link resolved to an enum, which is not a union + | +help: to link to the enum, prefix with `enum@` + | +LL | /// Link to [enum@S] + | ~~~~~ + +error: incompatible link kind for `S` + --> $DIR/disambiguator-mismatch.rs:31:14 + | +LL | /// Link to [trait@S] + | ^^^^^^^ this link resolved to an enum, which is not a trait + | +help: to link to the enum, prefix with `enum@` + | +LL | /// Link to [enum@S] + | ~~~~~ + +error: incompatible link kind for `T` + --> $DIR/disambiguator-mismatch.rs:36:14 + | +LL | /// Link to [struct@T] + | ^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// Link to [trait@T] + | ~~~~~~ + +error: incompatible link kind for `m` + --> $DIR/disambiguator-mismatch.rs:41:14 + | +LL | /// Link to [derive@m] + | ^^^^^^^^ this link resolved to a macro, which is not a derive macro + | +help: to link to the macro, add an exclamation mark + | +LL - /// Link to [derive@m] +LL + /// Link to [m!] + | + +error: unresolved link to `m` + --> $DIR/disambiguator-mismatch.rs:46:14 + | +LL | /// Link to [m()] + | ^^^ this link resolves to the macro `m`, which is not in the value namespace + | +help: to link to the macro, add an exclamation mark + | +LL | /// Link to [m!()] + | + + +error: incompatible link kind for `s` + --> $DIR/disambiguator-mismatch.rs:52:14 + | +LL | /// Link to [const@s] + | ^^^^^^^ this link resolved to a static, which is not a constant + | +help: to link to the static, prefix with `static@` + | +LL | /// Link to [static@s] + | ~~~~~~~ + +error: incompatible link kind for `c` + --> $DIR/disambiguator-mismatch.rs:57:14 + | +LL | /// Link to [static@c] + | ^^^^^^^^ this link resolved to a constant, which is not a static + | +help: to link to the constant, prefix with `const@` + | +LL | /// Link to [const@c] + | ~~~~~~ + +error: incompatible link kind for `c` + --> $DIR/disambiguator-mismatch.rs:62:14 + | +LL | /// Link to [fn@c] + | ^^^^ this link resolved to a constant, which is not a function + | +help: to link to the constant, prefix with `const@` + | +LL | /// Link to [const@c] + | ~~~~~~ + +error: incompatible link kind for `c` + --> $DIR/disambiguator-mismatch.rs:67:14 + | +LL | /// Link to [c()] + | ^^^ this link resolved to a constant, which is not a function + | +help: to link to the constant, prefix with `const@` + | +LL - /// Link to [c()] +LL + /// Link to [const@c] + | + +error: incompatible link kind for `f` + --> $DIR/disambiguator-mismatch.rs:72:14 + | +LL | /// Link to [const@f] + | ^^^^^^^ this link resolved to a function, which is not a constant + | +help: to link to the function, add parentheses + | +LL - /// Link to [const@f] +LL + /// Link to [f()] + | + +error: unresolved link to `std` + --> $DIR/disambiguator-mismatch.rs:77:14 + | +LL | /// Link to [fn@std] + | ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace + | +help: to link to the crate, prefix with `mod@` + | +LL | /// Link to [mod@std] + | ~~~~ + +error: aborting due to 13 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/double-anchor.rs b/src/test/rustdoc-ui/intra-doc/double-anchor.rs new file mode 100644 index 000000000..a01211c4f --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/double-anchor.rs @@ -0,0 +1,7 @@ +// check-pass + +// regression test for #73264 +// should only give one error +/// docs [label][with#anchor#error] +//~^ WARNING multiple anchors +pub struct S; diff --git a/src/test/rustdoc-ui/intra-doc/double-anchor.stderr b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr new file mode 100644 index 000000000..6addb010e --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr @@ -0,0 +1,12 @@ +warning: `with#anchor#error` contains multiple anchors + --> $DIR/double-anchor.rs:5:18 + | +LL | /// docs [label][with#anchor#error] + | ^^^^^^^^^^^------ + | | + | invalid anchor + | + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs new file mode 100644 index 000000000..7a5156e81 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs @@ -0,0 +1,7 @@ +// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" +// check-pass +#![deny(warnings)] + +//! Email me at <hello@localhost>. + +//! This should *not* warn: <hello@example.com>. diff --git a/src/test/rustdoc-ui/intra-doc/errors.rs b/src/test/rustdoc-ui/intra-doc/errors.rs new file mode 100644 index 000000000..b29f7c29b --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/errors.rs @@ -0,0 +1,105 @@ +#![deny(rustdoc::broken_intra_doc_links)] +//~^ NOTE lint level is defined + +// FIXME: this should say that it was skipped (maybe an allowed by default lint?) +/// [invalid intra-doc syntax!!] + +/// [path::to::nonexistent::module] +//~^ ERROR unresolved link +//~| NOTE no item named `path` in scope + +/// [path::to::nonexistent::macro!] +//~^ ERROR unresolved link +//~| NOTE no item named `path` in scope + +/// [type@path::to::nonexistent::type] +//~^ ERROR unresolved link +//~| NOTE no item named `path` in scope + +/// [std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE no item named `not` in module `io` + +/// [type@std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE no item named `not` in module `io` + +/// [std::io::Error::x] +//~^ ERROR unresolved link +//~| NOTE the struct `Error` has no field + +/// [std::io::ErrorKind::x] +//~^ ERROR unresolved link +//~| NOTE the enum `ErrorKind` has no variant + +/// [f::A] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + +/// [f::A!] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + +/// [S::A] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [S::fmt] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [E::D] +//~^ ERROR unresolved link +//~| NOTE enum `E` has no variant or associated item + +/// [u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [std::primitive::u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [type@Vec::into_iter] +//~^ ERROR unresolved link +//~| HELP to link to the associated function, add parentheses +//~| NOTE this link resolves to the associated function `into_iter` + +/// [S!] +//~^ ERROR unresolved link +//~| HELP to link to the struct, prefix with `struct@` +//~| NOTE this link resolves to the struct `S` +pub fn f() {} +#[derive(Debug)] +pub struct S; + +pub enum E { A, B, C } + +/// [type@S::h] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace +impl S { + pub fn h() {} +} + +/// [type@T::g] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace + +/// [T::h!] +//~^ ERROR unresolved link +//~| NOTE `T` has no macro named `h` +pub trait T { + fn g() {} +} + +/// [m()] +//~^ ERROR unresolved link +//~| HELP to link to the macro +//~| NOTE not in the value namespace +#[macro_export] +macro_rules! m { + () => {}; +} diff --git a/src/test/rustdoc-ui/intra-doc/errors.stderr b/src/test/rustdoc-ui/intra-doc/errors.stderr new file mode 100644 index 000000000..9a1896fb0 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/errors.stderr @@ -0,0 +1,157 @@ +error: unresolved link to `path::to::nonexistent::module` + --> $DIR/errors.rs:7:6 + | +LL | /// [path::to::nonexistent::module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope + | +note: the lint level is defined here + --> $DIR/errors.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `path::to::nonexistent::macro` + --> $DIR/errors.rs:11:6 + | +LL | /// [path::to::nonexistent::macro!] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope + +error: unresolved link to `path::to::nonexistent::type` + --> $DIR/errors.rs:15:6 + | +LL | /// [type@path::to::nonexistent::type] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope + +error: unresolved link to `std::io::not::here` + --> $DIR/errors.rs:19:6 + | +LL | /// [std::io::not::here] + | ^^^^^^^^^^^^^^^^^^ no item named `not` in module `io` + +error: unresolved link to `std::io::not::here` + --> $DIR/errors.rs:23:6 + | +LL | /// [type@std::io::not::here] + | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `not` in module `io` + +error: unresolved link to `std::io::Error::x` + --> $DIR/errors.rs:27:6 + | +LL | /// [std::io::Error::x] + | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` + +error: unresolved link to `std::io::ErrorKind::x` + --> $DIR/errors.rs:31:6 + | +LL | /// [std::io::ErrorKind::x] + | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` + +error: unresolved link to `f::A` + --> $DIR/errors.rs:35:6 + | +LL | /// [f::A] + | ^^^^ `f` is a function, not a module or type, and cannot have associated items + +error: unresolved link to `f::A` + --> $DIR/errors.rs:39:6 + | +LL | /// [f::A!] + | ^^^^^ `f` is a function, not a module or type, and cannot have associated items + +error: unresolved link to `S::A` + --> $DIR/errors.rs:43:6 + | +LL | /// [S::A] + | ^^^^ the struct `S` has no field or associated item named `A` + +error: unresolved link to `S::fmt` + --> $DIR/errors.rs:47:6 + | +LL | /// [S::fmt] + | ^^^^^^ the struct `S` has no field or associated item named `fmt` + +error: unresolved link to `E::D` + --> $DIR/errors.rs:51:6 + | +LL | /// [E::D] + | ^^^^ the enum `E` has no variant or associated item named `D` + +error: unresolved link to `u8::not_found` + --> $DIR/errors.rs:55:6 + | +LL | /// [u8::not_found] + | ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` + +error: unresolved link to `std::primitive::u8::not_found` + --> $DIR/errors.rs:59:6 + | +LL | /// [std::primitive::u8::not_found] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` + +error: unresolved link to `Vec::into_iter` + --> $DIR/errors.rs:63:6 + | +LL | /// [type@Vec::into_iter] + | ^^^^^^^^^^^^^^^^^^^ this link resolves to the associated function `into_iter`, which is not in the type namespace + | +help: to link to the associated function, add parentheses + | +LL - /// [type@Vec::into_iter] +LL + /// [Vec::into_iter()] + | + +error: unresolved link to `S` + --> $DIR/errors.rs:68:6 + | +LL | /// [S!] + | ^^ this link resolves to the struct `S`, which is not in the macro namespace + | +help: to link to the struct, prefix with `struct@` + | +LL - /// [S!] +LL + /// [struct@S] + | + +error: unresolved link to `S::h` + --> $DIR/errors.rs:78:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ this link resolves to the associated function `h`, which is not in the type namespace + | +help: to link to the associated function, add parentheses + | +LL - /// [type@S::h] +LL + /// [S::h()] + | + +error: unresolved link to `T::g` + --> $DIR/errors.rs:86:6 + | +LL | /// [type@T::g] + | ^^^^^^^^^ this link resolves to the associated function `g`, which is not in the type namespace + | +help: to link to the associated function, add parentheses + | +LL - /// [type@T::g] +LL + /// [T::g()] + | + +error: unresolved link to `T::h` + --> $DIR/errors.rs:91:6 + | +LL | /// [T::h!] + | ^^^^^ the trait `T` has no macro named `h` + +error: unresolved link to `m` + --> $DIR/errors.rs:98:6 + | +LL | /// [m()] + | ^^^ this link resolves to the macro `m`, which is not in the value namespace + | +help: to link to the macro, add an exclamation mark + | +LL | /// [m!()] + | + + +error: aborting due to 20 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs new file mode 100644 index 000000000..438c56aa5 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs @@ -0,0 +1,26 @@ +// check-pass +// aux-crate:dep1=dep1.rs +// aux-crate:dep2=dep2.rs +// aux-crate:dep3=dep3.rs +// aux-crate:dep4=dep4.rs +#![deny(rustdoc::broken_intra_doc_links)] + +pub trait Trait { + /// [dep1] + type Item; +} + +pub struct S { + /// [dep2] + pub x: usize, +} + +extern "C" { + /// [dep3] + pub fn printf(); +} + +pub enum E { + /// [dep4] + A +} diff --git a/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs new file mode 100644 index 000000000..3cfac942c --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.rs @@ -0,0 +1,6 @@ +//! [pointer::add] +//~^ ERROR: experimental +//! [pointer::wrapping_add] +//~^ ERROR: experimental +//! [pointer] // This is explicitly allowed +//! [reference] // This is explicitly allowed diff --git a/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr new file mode 100644 index 000000000..2c946ed48 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/feature-gate-intra-doc-pointers.stderr @@ -0,0 +1,23 @@ +error[E0658]: linking to associated items of raw pointers is experimental + --> $DIR/feature-gate-intra-doc-pointers.rs:1:6 + | +LL | //! [pointer::add] + | ^^^^^^^^^^^^ + | + = note: see issue #80896 <https://github.com/rust-lang/rust/issues/80896> for more information + = help: add `#![feature(intra_doc_pointers)]` to the crate attributes to enable + = note: rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does + +error[E0658]: linking to associated items of raw pointers is experimental + --> $DIR/feature-gate-intra-doc-pointers.rs:3:6 + | +LL | //! [pointer::wrapping_add] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #80896 <https://github.com/rust-lang/rust/issues/80896> for more information + = help: add `#![feature(intra_doc_pointers)]` to the crate attributes to enable + = note: rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/rustdoc-ui/intra-doc/field-ice.rs b/src/test/rustdoc-ui/intra-doc/field-ice.rs new file mode 100644 index 000000000..c5d501e38 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/field-ice.rs @@ -0,0 +1,11 @@ +#![deny(rustdoc::broken_intra_doc_links)] +//~^NOTE the lint level is defined here + +/// [`Foo::bar`] +/// [`Foo::bar()`] +//~^ERROR incompatible link kind for `Foo::bar` +//~|HELP to link to the field, remove the disambiguator +//~|NOTE this link resolved to a field, which is not a function +pub struct Foo { + pub bar: u8 +} diff --git a/src/test/rustdoc-ui/intra-doc/field-ice.stderr b/src/test/rustdoc-ui/intra-doc/field-ice.stderr new file mode 100644 index 000000000..f45a3ca61 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/field-ice.stderr @@ -0,0 +1,18 @@ +error: incompatible link kind for `Foo::bar` + --> $DIR/field-ice.rs:5:7 + | +LL | /// [`Foo::bar()`] + | ^^^^^^^^^^ this link resolved to a field, which is not a function + | +note: the lint level is defined here + --> $DIR/field-ice.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the field, remove the disambiguator + | +LL | /// [`Foo::bar`] + | ~~~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-doc/global-path.rs b/src/test/rustdoc-ui/intra-doc/global-path.rs new file mode 100644 index 000000000..cc7a5fa1c --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/global-path.rs @@ -0,0 +1,8 @@ +// Doc link path with empty prefix that resolves to "extern prelude" instead of a module. + +// check-pass +// edition:2018 + +/// [::Unresolved] +//~^ WARN unresolved link to `::Unresolved` +pub struct Item; diff --git a/src/test/rustdoc-ui/intra-doc/global-path.stderr b/src/test/rustdoc-ui/intra-doc/global-path.stderr new file mode 100644 index 000000000..02379cd6c --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/global-path.stderr @@ -0,0 +1,10 @@ +warning: unresolved link to `::Unresolved` + --> $DIR/global-path.rs:6:6 + | +LL | /// [::Unresolved] + | ^^^^^^^^^^^^ no item named `` in scope + | + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs new file mode 100644 index 000000000..b5470c859 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.rs @@ -0,0 +1,25 @@ +#![deny(rustdoc::invalid_html_tags)] +#![deny(rustdoc::broken_intra_doc_links)] + +pub struct ExistentStruct<T>(T); + +/// This [test][ExistentStruct<i32>] thing! +pub struct NoError; + +/// This [ExistentStruct<i32>] thing! +//~^ ERROR unclosed HTML tag `i32` +pub struct PartialErrorOnlyHtml; + +/// This [test][NonExistentStruct<i32>] thing! +//~^ ERROR unresolved link +pub struct PartialErrorOnlyResolve; + +/// This [NonExistentStruct2<i32>] thing! +//~^ ERROR unclosed HTML tag `i32` +//~| ERROR unresolved link +pub struct YesError; + +/// This [NonExistentStruct3<i32>][] thing! +//~^ ERROR unclosed HTML tag `i32` +//~| ERROR unresolved link +pub struct YesErrorCollapsed; diff --git a/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr new file mode 100644 index 000000000..00fe229da --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/html-as-generics-intra-doc.stderr @@ -0,0 +1,69 @@ +error: unresolved link to `NonExistentStruct` + --> $DIR/html-as-generics-intra-doc.rs:13:17 + | +LL | /// This [test][NonExistentStruct<i32>] thing! + | ^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct` in scope + | +note: the lint level is defined here + --> $DIR/html-as-generics-intra-doc.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `NonExistentStruct2` + --> $DIR/html-as-generics-intra-doc.rs:17:11 + | +LL | /// This [NonExistentStruct2<i32>] thing! + | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct2` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `NonExistentStruct3` + --> $DIR/html-as-generics-intra-doc.rs:22:11 + | +LL | /// This [NonExistentStruct3<i32>][] thing! + | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `NonExistentStruct3` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-intra-doc.rs:9:25 + | +LL | /// This [ExistentStruct<i32>] thing! + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/html-as-generics-intra-doc.rs:1:9 + | +LL | #![deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try marking as source code + | +LL | /// This [`ExistentStruct<i32>`] thing! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-intra-doc.rs:17:29 + | +LL | /// This [NonExistentStruct2<i32>] thing! + | ^^^^^ + | +help: try marking as source code + | +LL | /// This [`NonExistentStruct2<i32>`] thing! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-intra-doc.rs:22:29 + | +LL | /// This [NonExistentStruct3<i32>][] thing! + | ^^^^^ + | +help: try marking as source code + | +LL | /// This [`NonExistentStruct3<i32>`][] thing! + | + + + +error: aborting due to 6 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs new file mode 100644 index 000000000..3088bcd46 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs @@ -0,0 +1,3 @@ +#![deny(rustdoc::broken_intra_doc_links)] +//! [static@u8::MIN] +//~^ ERROR incompatible link kind diff --git a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr new file mode 100644 index 000000000..c43cda3eb --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr @@ -0,0 +1,18 @@ +error: incompatible link kind for `u8::MIN` + --> $DIR/incompatible-primitive-disambiguator.rs:2:6 + | +LL | //! [static@u8::MIN] + | ^^^^^^^^^^^^^^ this link resolved to an associated constant, which is not a static + | +note: the lint level is defined here + --> $DIR/incompatible-primitive-disambiguator.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the associated constant, prefix with `const@` + | +LL | //! [const@u8::MIN] + | ~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs new file mode 100644 index 000000000..8490584c1 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs @@ -0,0 +1,26 @@ +// `macro_rules` scopes are respected during doc link resolution. + +// compile-flags: --document-private-items + +#![deny(rustdoc::broken_intra_doc_links)] + +mod no_escape { + macro_rules! before_but_limited_to_module { + () => {}; + } +} + +/// [before_but_limited_to_module] +//~^ ERROR unresolved link to `before_but_limited_to_module` +/// [after] +//~^ ERROR unresolved link to `after` +/// [str] +fn check() {} + +macro_rules! after { + () => {}; +} + +macro_rules! str { + () => {}; +} diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr new file mode 100644 index 000000000..8e17323fd --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr @@ -0,0 +1,23 @@ +error: unresolved link to `before_but_limited_to_module` + --> $DIR/macro-rules-error.rs:13:6 + | +LL | /// [before_but_limited_to_module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `before_but_limited_to_module` in scope + | +note: the lint level is defined here + --> $DIR/macro-rules-error.rs:5:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `macro_rules` named `before_but_limited_to_module` exists in this crate, but it is not in scope at this link's location + +error: unresolved link to `after` + --> $DIR/macro-rules-error.rs:15:6 + | +LL | /// [after] + | ^^^^^ no item named `after` in scope + | + = note: `macro_rules` named `after` exists in this crate, but it is not in scope at this link's location + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules.rs b/src/test/rustdoc-ui/intra-doc/macro-rules.rs new file mode 100644 index 000000000..3aeb370ef --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/macro-rules.rs @@ -0,0 +1,24 @@ +// check-pass +#![allow(rustdoc::private_intra_doc_links)] + +macro_rules! foo { + () => {}; +} + +/// [foo!] +pub fn baz() {} + +#[macro_use] +mod macros { + macro_rules! escaping { + () => {}; + } +} + +pub mod inner { + /// [foo!] + /// [escaping] + pub fn baz() { + foo!(); + } +} diff --git a/src/test/rustdoc-ui/intra-doc/malformed-generics.rs b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs new file mode 100644 index 000000000..15e02925e --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs @@ -0,0 +1,19 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +//! [Vec<] //~ ERROR +//! [Vec<Box<T] //~ ERROR +//! [Vec<Box<T>] //~ ERROR +//! [Vec<Box<T>>>] //~ ERROR +//! [Vec<T>>>] //~ ERROR +//! [<Vec] //~ ERROR +//! [Vec::<] //~ ERROR +//! [<T>] //~ ERROR +//! [<invalid syntax>] //~ ERROR +//! [Vec:<T>:new()] //~ ERROR +//! [Vec<<T>>] //~ ERROR +//! [Vec<>] //~ ERROR +//! [Vec<<>>] //~ ERROR + +// FIXME(#74563) support UFCS +//! [<Vec as IntoIterator>::into_iter] //~ ERROR +//! [<Vec<T> as IntoIterator>::iter] //~ ERROR diff --git a/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr new file mode 100644 index 000000000..5bc0f84e2 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr @@ -0,0 +1,102 @@ +error: unresolved link to `Vec<` + --> $DIR/malformed-generics.rs:3:6 + | +LL | //! [Vec<] + | ^^^^ unbalanced angle brackets + | +note: the lint level is defined here + --> $DIR/malformed-generics.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `Vec<Box<T` + --> $DIR/malformed-generics.rs:4:6 + | +LL | //! [Vec<Box<T] + | ^^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `Vec<Box<T>` + --> $DIR/malformed-generics.rs:5:6 + | +LL | //! [Vec<Box<T>] + | ^^^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `Vec<Box<T>>>` + --> $DIR/malformed-generics.rs:6:6 + | +LL | //! [Vec<Box<T>>>] + | ^^^^^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `Vec<T>>>` + --> $DIR/malformed-generics.rs:7:6 + | +LL | //! [Vec<T>>>] + | ^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `<Vec` + --> $DIR/malformed-generics.rs:8:6 + | +LL | //! [<Vec] + | ^^^^ unbalanced angle brackets + +error: unresolved link to `Vec::<` + --> $DIR/malformed-generics.rs:9:6 + | +LL | //! [Vec::<] + | ^^^^^^ unbalanced angle brackets + +error: unresolved link to `<T>` + --> $DIR/malformed-generics.rs:10:6 + | +LL | //! [<T>] + | ^^^ missing type for generic parameters + +error: unresolved link to `<invalid syntax>` + --> $DIR/malformed-generics.rs:11:6 + | +LL | //! [<invalid syntax>] + | ^^^^^^^^^^^^^^^^ missing type for generic parameters + +error: unresolved link to `Vec:<T>:new` + --> $DIR/malformed-generics.rs:12:6 + | +LL | //! [Vec:<T>:new()] + | ^^^^^^^^^^^^^ has invalid path separator + +error: unresolved link to `Vec<<T>>` + --> $DIR/malformed-generics.rs:13:6 + | +LL | //! [Vec<<T>>] + | ^^^^^^^^ too many angle brackets + +error: unresolved link to `Vec<>` + --> $DIR/malformed-generics.rs:14:6 + | +LL | //! [Vec<>] + | ^^^^^ empty angle brackets + +error: unresolved link to `Vec<<>>` + --> $DIR/malformed-generics.rs:15:6 + | +LL | //! [Vec<<>>] + | ^^^^^^^ too many angle brackets + +error: unresolved link to `<Vec as IntoIterator>::into_iter` + --> $DIR/malformed-generics.rs:18:6 + | +LL | //! [<Vec as IntoIterator>::into_iter] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported + | + = note: see https://github.com/rust-lang/rust/issues/74563 for more information + +error: unresolved link to `<Vec<T> as IntoIterator>::iter` + --> $DIR/malformed-generics.rs:19:6 + | +LL | //! [<Vec<T> as IntoIterator>::iter] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported + | + = note: see https://github.com/rust-lang/rust/issues/74563 for more information + +error: aborting due to 15 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs new file mode 100644 index 000000000..587cbad68 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs @@ -0,0 +1,34 @@ +#![deny(rustdoc::broken_intra_doc_links)] +#![feature(intra_doc_pointers)] +// These are links that could reasonably expected to work, but don't. + +// `[]` isn't supported because it had too many false positives. +//! [X]([T]::not_here) +//! [Y](&[]::not_here) +//! [X]([]::not_here) +//! [Y]([T;N]::not_here) + +// These don't work because markdown syntax doesn't allow it. +//! [[T]::rotate_left] //~ ERROR unresolved link to `T` +//! [&[]::not_here] +//![Z]([T; N]::map) //~ ERROR unresolved link to `Z` +//! [`[T; N]::map`] +//! [[]::map] +//! [Z][] //~ ERROR unresolved link to `Z` +//! +//! [Z]: [T; N]::map //~ ERROR unresolved link to `Z` + +// `()` isn't supported because it had too many false positives. +//! [()::not_here] +//! [X]((,)::not_here) +//! [(,)::not_here] + +// FIXME: Associated items on some primitives aren't working, because the impls +// are part of the compiler instead of being part of the source code. +//! [unit::eq] //~ ERROR unresolved +//! [tuple::eq] //~ ERROR unresolved +//! [fn::eq] //~ ERROR unresolved + +// FIXME(#78800): This breaks because it's a blanket impl +// (I think? Might break for other reasons too.) +//! [reference::deref] //~ ERROR unresolved diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr new file mode 100644 index 000000000..4828a3044 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr @@ -0,0 +1,63 @@ +error: unresolved link to `T` + --> $DIR/non-path-primitives.rs:12:7 + | +LL | //! [[T]::rotate_left] + | ^ no item named `T` in scope + | +note: the lint level is defined here + --> $DIR/non-path-primitives.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Z` + --> $DIR/non-path-primitives.rs:14:5 + | +LL | //![Z]([T; N]::map) + | ^ no item named `Z` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Z` + --> $DIR/non-path-primitives.rs:17:6 + | +LL | //! [Z][] + | ^ no item named `Z` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Z` + --> $DIR/non-path-primitives.rs:19:6 + | +LL | //! [Z]: [T; N]::map + | ^ no item named `Z` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `unit::eq` + --> $DIR/non-path-primitives.rs:28:6 + | +LL | //! [unit::eq] + | ^^^^^^^^ the builtin type `unit` has no associated item named `eq` + +error: unresolved link to `tuple::eq` + --> $DIR/non-path-primitives.rs:29:6 + | +LL | //! [tuple::eq] + | ^^^^^^^^^ the builtin type `tuple` has no associated item named `eq` + +error: unresolved link to `fn::eq` + --> $DIR/non-path-primitives.rs:30:6 + | +LL | //! [fn::eq] + | ^^^^^^ the builtin type `fn` has no associated item named `eq` + +error: unresolved link to `reference::deref` + --> $DIR/non-path-primitives.rs:34:6 + | +LL | //! [reference::deref] + | ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref` + +error: aborting due to 8 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/pointer-reexports-allowed.rs b/src/test/rustdoc-ui/intra-doc/pointer-reexports-allowed.rs new file mode 100644 index 000000000..8654a8e1b --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/pointer-reexports-allowed.rs @@ -0,0 +1,4 @@ +// aux-build:pointer-reexports-allowed.rs +// check-pass +extern crate inner; +pub use inner::foo; diff --git a/src/test/rustdoc-ui/intra-doc/prim-conflict.rs b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs new file mode 100644 index 000000000..2c1a8b535 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs @@ -0,0 +1,30 @@ +#![deny(rustdoc::broken_intra_doc_links)] +//~^ NOTE lint level is defined + +/// [char] +//~^ ERROR both a module and a builtin type +//~| NOTE ambiguous link +//~| HELP to link to the module +//~| HELP to link to the builtin type + +/// [type@char] +//~^ ERROR both a module and a builtin type +//~| NOTE ambiguous link +//~| HELP to link to the module +//~| HELP to link to the builtin type + +/// [mod@char] // ok +/// [prim@char] // ok + +/// [struct@char] +//~^ ERROR incompatible link +//~| HELP prefix with `mod@` +//~| NOTE resolved to a module +pub mod char {} + +pub mod inner { + //! [struct@char] + //~^ ERROR incompatible link + //~| HELP prefix with `prim@` + //~| NOTE resolved to a builtin type +} diff --git a/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr new file mode 100644 index 000000000..6ef3b7eab --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr @@ -0,0 +1,59 @@ +error: `char` is both a module and a builtin type + --> $DIR/prim-conflict.rs:4:6 + | +LL | /// [char] + | ^^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/prim-conflict.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the module, prefix with `mod@` + | +LL | /// [mod@char] + | ++++ +help: to link to the builtin type, prefix with `prim@` + | +LL | /// [prim@char] + | +++++ + +error: `char` is both a module and a builtin type + --> $DIR/prim-conflict.rs:10:6 + | +LL | /// [type@char] + | ^^^^^^^^^ ambiguous link + | +help: to link to the module, prefix with `mod@` + | +LL | /// [mod@char] + | ~~~~ +help: to link to the builtin type, prefix with `prim@` + | +LL | /// [prim@char] + | ~~~~~ + +error: incompatible link kind for `char` + --> $DIR/prim-conflict.rs:19:6 + | +LL | /// [struct@char] + | ^^^^^^^^^^^ this link resolved to a module, which is not a struct + | +help: to link to the module, prefix with `mod@` + | +LL | /// [mod@char] + | ~~~~ + +error: incompatible link kind for `char` + --> $DIR/prim-conflict.rs:26:10 + | +LL | //! [struct@char] + | ^^^^^^^^^^^ this link resolved to a builtin type, which is not a struct + | +help: to link to the builtin type, prefix with `prim@` + | +LL | //! [prim@char] + | ~~~~~ + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/private-from-crate-level.rs b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.rs new file mode 100644 index 000000000..e429e75b2 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.rs @@ -0,0 +1,6 @@ +// check-pass + +//! [my_module] +//~^ WARN public documentation for `private_from_crate_level` links to private item `my_module` + +mod my_module {} diff --git a/src/test/rustdoc-ui/intra-doc/private-from-crate-level.stderr b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.stderr new file mode 100644 index 000000000..6172cd2e3 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/private-from-crate-level.stderr @@ -0,0 +1,11 @@ +warning: public documentation for `private_from_crate_level` links to private item `my_module` + --> $DIR/private-from-crate-level.rs:3:6 + | +LL | //! [my_module] + | ^^^^^^^^^ this item is private + | + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default + = note: this link will resolve properly if you pass `--document-private-items` + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-doc/private.private.stderr b/src/test/rustdoc-ui/intra-doc/private.private.stderr new file mode 100644 index 000000000..392321f9c --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/private.private.stderr @@ -0,0 +1,27 @@ +warning: public documentation for `DocMe` links to private item `DontDocMe` + --> $DIR/private.rs:7:11 + | +LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] + | ^^^^^^^^^ this item is private + | + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default + = note: this link resolves only because you passed `--document-private-items`, but will break without + +warning: public documentation for `DocMe` links to private item `DontDocMe::f` + --> $DIR/private.rs:7:23 + | +LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] + | ^^^^^^^^^^^^ this item is private + | + = note: this link resolves only because you passed `--document-private-items`, but will break without + +warning: public documentation for `DocMe` links to private item `DontDocMe::x` + --> $DIR/private.rs:7:38 + | +LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] + | ^^^^^^^^^^^^ this item is private + | + = note: this link resolves only because you passed `--document-private-items`, but will break without + +warning: 3 warnings emitted + diff --git a/src/test/rustdoc-ui/intra-doc/private.public.stderr b/src/test/rustdoc-ui/intra-doc/private.public.stderr new file mode 100644 index 000000000..5d1c34b91 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/private.public.stderr @@ -0,0 +1,27 @@ +warning: public documentation for `DocMe` links to private item `DontDocMe` + --> $DIR/private.rs:7:11 + | +LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] + | ^^^^^^^^^ this item is private + | + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default + = note: this link will resolve properly if you pass `--document-private-items` + +warning: public documentation for `DocMe` links to private item `DontDocMe::f` + --> $DIR/private.rs:7:23 + | +LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] + | ^^^^^^^^^^^^ this item is private + | + = note: this link will resolve properly if you pass `--document-private-items` + +warning: public documentation for `DocMe` links to private item `DontDocMe::x` + --> $DIR/private.rs:7:38 + | +LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] + | ^^^^^^^^^^^^ this item is private + | + = note: this link will resolve properly if you pass `--document-private-items` + +warning: 3 warnings emitted + diff --git a/src/test/rustdoc-ui/intra-doc/private.rs b/src/test/rustdoc-ui/intra-doc/private.rs new file mode 100644 index 000000000..525332dda --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/private.rs @@ -0,0 +1,18 @@ +// check-pass +// revisions: public private +// [private]compile-flags: --document-private-items + +// make sure to update `rustdoc/intra-doc/private.rs` if you update this file + +/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] +//~^ WARNING public documentation for `DocMe` links to private item `DontDocMe` +//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::x` +//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::f` +pub struct DocMe; +struct DontDocMe { + x: usize, +} + +impl DontDocMe { + fn f() {} +} diff --git a/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs new file mode 100644 index 000000000..041ec2932 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs @@ -0,0 +1,13 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +// An error in calculating spans while reporting intra-doc link resolution errors caused rustdoc to +// attempt to slice in the middle of a multibyte character. See +// https://github.com/rust-lang/rust/issues/55723 + +/// ## For example: +/// +/// (arr[i]) +//~^ ERROR `i` +pub fn test_ice() { + unimplemented!(); +} diff --git a/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr new file mode 100644 index 000000000..bf4ab9fdd --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr @@ -0,0 +1,15 @@ +error: unresolved link to `i` + --> $DIR/span-ice-55723.rs:9:10 + | +LL | /// (arr[i]) + | ^ no item named `i` in scope + | +note: the lint level is defined here + --> $DIR/span-ice-55723.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs b/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs new file mode 100644 index 000000000..7628c3928 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs @@ -0,0 +1,18 @@ +// check-pass +// aux-build:through-proc-macro-aux.rs +// build-aux-docs + +// Ensure rustdoc doesn't panic on this code. + +#![warn(rustdoc::broken_intra_doc_links)] + +extern crate some_macros; + +#[some_macros::second] +pub enum Boom { + /// [Oooops] + //~^ WARNING unresolved link to `Oooops` + Bam, +} + +fn main() {} diff --git a/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr b/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr new file mode 100644 index 000000000..f0a7ed178 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr @@ -0,0 +1,15 @@ +warning: unresolved link to `Oooops` + --> $DIR/through-proc-macro.rs:13:10 + | +LL | /// [Oooops] + | ^^^^^^ no item named `Oooops` in scope + | +note: the lint level is defined here + --> $DIR/through-proc-macro.rs:7:9 + | +LL | #![warn(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs new file mode 100644 index 000000000..0aa1e5a41 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs @@ -0,0 +1,14 @@ +// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" +#![deny(warnings)] + +//! Linking to [foo@banana] and [`bar@banana!()`]. +//~^ ERROR unknown disambiguator `foo` +//~| ERROR unknown disambiguator `bar` +//! And to [no disambiguator](@nectarine) and [another](@apricot!()). +//~^ ERROR unknown disambiguator `` +//~| ERROR unknown disambiguator `` +//! And with weird backticks: [``foo@hello``] [foo`@`hello]. +//~^ ERROR unknown disambiguator `foo` +//~| ERROR unknown disambiguator `foo` + +fn main() {} diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr new file mode 100644 index 000000000..d280e6497 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr @@ -0,0 +1,56 @@ +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:4:17 + | +LL | //! Linking to [foo@banana] and [`bar@banana!()`]. + | ^^^ + | +note: the lint level is defined here + --> $DIR/unknown-disambiguator.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +error: unknown disambiguator `bar` + --> $DIR/unknown-disambiguator.rs:4:35 + | +LL | //! Linking to [foo@banana] and [`bar@banana!()`]. + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:10:34 + | +LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:10:48 + | +LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +error: unknown disambiguator `` + --> $DIR/unknown-disambiguator.rs:7:31 + | +LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). + | ^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +error: unknown disambiguator `` + --> $DIR/unknown-disambiguator.rs:7:57 + | +LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). + | ^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +error: aborting due to 6 previous errors + diff --git a/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.rs b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.rs new file mode 100644 index 000000000..c71e5bee1 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.rs @@ -0,0 +1,6 @@ +// Regression test for issue #95879. + +use unresolved_crate::module::Name; //~ ERROR failed to resolve + +/// [Name] +pub struct S; diff --git a/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr new file mode 100644 index 000000000..b54f82006 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr @@ -0,0 +1,13 @@ +error[E0433]: failed to resolve: maybe a missing crate `unresolved_crate`? + --> $DIR/unresolved-import-recovery.rs:3:5 + | +LL | use unresolved_crate::module::Name; + | ^^^^^^^^^^^^^^^^ maybe a missing crate `unresolved_crate`? + | + = help: consider adding `extern crate unresolved_crate` to use the `unresolved_crate` crate + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs new file mode 100644 index 000000000..956583093 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs @@ -0,0 +1,5 @@ +// compile-flags: --extern zip=whatever.rlib +#![deny(rustdoc::broken_intra_doc_links)] +/// See [zip] crate. +//~^ ERROR unresolved +pub struct ArrayZip; diff --git a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr new file mode 100644 index 000000000..5c0df1d1b --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr @@ -0,0 +1,15 @@ +error: unresolved link to `zip` + --> $DIR/unused-extern-crate.rs:3:10 + | +LL | /// See [zip] crate. + | ^^^ no item named `zip` in scope + | +note: the lint level is defined here + --> $DIR/unused-extern-crate.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-doc/warning-crlf.rs b/src/test/rustdoc-ui/intra-doc/warning-crlf.rs new file mode 100644 index 000000000..ceb62f6d1 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.rs @@ -0,0 +1,26 @@ +// ignore-tidy-cr
+// check-pass
+
+// This file checks the spans of intra-link warnings in a file with CRLF line endings. The
+// .gitattributes file in this directory should enforce it.
+
+/// [error]
+pub struct A;
+//~^^ WARNING `error`
+
+///
+/// docs [error1]
+//~^ WARNING `error1`
+
+/// docs [error2]
+///
+pub struct B;
+//~^^^ WARNING `error2`
+
+/**
+ * This is a multi-line comment.
+ *
+ * It also has an [error].
+ */
+pub struct C;
+//~^^^ WARNING `error`
diff --git a/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr new file mode 100644 index 000000000..d46df9264 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr @@ -0,0 +1,35 @@ +warning: unresolved link to `error` + --> $DIR/warning-crlf.rs:7:6 + | +LL | /// [error] + | ^^^^^ no item named `error` in scope + | + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error1` + --> $DIR/warning-crlf.rs:12:11 + | +LL | /// docs [error1] + | ^^^^^^ no item named `error1` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error2` + --> $DIR/warning-crlf.rs:15:11 + | +LL | /// docs [error2] + | ^^^^^^ no item named `error2` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error` + --> $DIR/warning-crlf.rs:23:20 + | +LL | * It also has an [error]. + | ^^^^^ no item named `error` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: 4 warnings emitted + diff --git a/src/test/rustdoc-ui/intra-doc/warning.rs b/src/test/rustdoc-ui/intra-doc/warning.rs new file mode 100644 index 000000000..eab1f0348 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/warning.rs @@ -0,0 +1,84 @@ +// check-pass + + //! Test with [Foo::baz], [Bar::foo], ... +//~^ WARNING `Foo::baz` +//~| WARNING `Bar::foo` + //! , [Uniooon::X] and [Qux::Z]. +//~^ WARNING `Uniooon::X` +//~| WARNING `Qux::Z` + //! + //! , [Uniooon::X] and [Qux::Z]. +//~^ WARNING `Uniooon::X` +//~| WARNING `Qux::Z` + + /// [Qux:Y] +//~^ WARNING `Qux:Y` +pub struct Foo { + pub bar: usize, +} + +/// Foo +/// bar [BarA] bar //~ WARNING `BarA` +/// baz +pub fn a() {} + +/** + * Foo + * bar [BarB] bar //~ WARNING `BarB` + * baz + */ +pub fn b() {} + +/** Foo + +bar [BarC] bar //~ WARNING `BarC` +baz + + let bar_c_1 = 0; + let bar_c_2 = 0; + let g = [bar_c_1]; + let h = g[bar_c_2]; + +*/ +pub fn c() {} + +#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `BarD` +pub fn d() {} + +macro_rules! f { + ($f:expr) => { + #[doc = $f] //~ WARNING `BarF` + pub fn f() {} + } +} +f!("Foo\nbar [BarF] bar\nbaz"); + +/** # for example, + * + * time to introduce a link [error]*/ //~ WARNING `error` +pub struct A; + +/** + * # for example, + * + * time to introduce a link [error] //~ WARNING `error` + */ +pub struct B; + +#[doc = "single line [error]"] //~ WARNING `error` +pub struct C; + +#[doc = "single line with \"escaping\" [error]"] //~ WARNING `error` +pub struct D; + +/// Item docs. //~ WARNING `error` +#[doc="Hello there!"] +/// [error] +pub struct E; + +/// +/// docs [error1] //~ WARNING `error1` + +/// docs [error2] //~ WARNING `error2` +/// +pub struct F; diff --git a/src/test/rustdoc-ui/intra-doc/warning.stderr b/src/test/rustdoc-ui/intra-doc/warning.stderr new file mode 100644 index 000000000..19399a0df --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/warning.stderr @@ -0,0 +1,175 @@ +warning: unresolved link to `Foo::baz` + --> $DIR/warning.rs:3:23 + | +LL | //! Test with [Foo::baz], [Bar::foo], ... + | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz` + | + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + +warning: unresolved link to `Bar::foo` + --> $DIR/warning.rs:3:35 + | +LL | //! Test with [Foo::baz], [Bar::foo], ... + | ^^^^^^^^ no item named `Bar` in scope + +warning: unresolved link to `Uniooon::X` + --> $DIR/warning.rs:6:13 + | +LL | //! , [Uniooon::X] and [Qux::Z]. + | ^^^^^^^^^^ no item named `Uniooon` in scope + +warning: unresolved link to `Qux::Z` + --> $DIR/warning.rs:6:30 + | +LL | //! , [Uniooon::X] and [Qux::Z]. + | ^^^^^^ no item named `Qux` in scope + +warning: unresolved link to `Uniooon::X` + --> $DIR/warning.rs:10:14 + | +LL | //! , [Uniooon::X] and [Qux::Z]. + | ^^^^^^^^^^ no item named `Uniooon` in scope + +warning: unresolved link to `Qux::Z` + --> $DIR/warning.rs:10:31 + | +LL | //! , [Uniooon::X] and [Qux::Z]. + | ^^^^^^ no item named `Qux` in scope + +warning: unresolved link to `Qux:Y` + --> $DIR/warning.rs:14:13 + | +LL | /// [Qux:Y] + | ^^^^^ no item named `Qux:Y` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `BarA` + --> $DIR/warning.rs:21:10 + | +LL | /// bar [BarA] bar + | ^^^^ no item named `BarA` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `BarB` + --> $DIR/warning.rs:27:9 + | +LL | * bar [BarB] bar + | ^^^^ no item named `BarB` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `BarC` + --> $DIR/warning.rs:34:6 + | +LL | bar [BarC] bar + | ^^^^ no item named `BarC` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `BarD` + --> $DIR/warning.rs:45:1 + | +LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + bar [BarD] bar + ^^^^ + = note: no item named `BarD` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `BarF` + --> $DIR/warning.rs:50:9 + | +LL | #[doc = $f] + | ^^^^^^^^^^^ +... +LL | f!("Foo\nbar [BarF] bar\nbaz"); + | ------------------------------ in this macro invocation + | + = note: the link appears in this line: + + bar [BarF] bar + ^^^^ + = note: no item named `BarF` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: this warning originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unresolved link to `error` + --> $DIR/warning.rs:58:30 + | +LL | * time to introduce a link [error]*/ + | ^^^^^ no item named `error` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error` + --> $DIR/warning.rs:64:30 + | +LL | * time to introduce a link [error] + | ^^^^^ no item named `error` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error` + --> $DIR/warning.rs:68:1 + | +LL | #[doc = "single line [error]"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + single line [error] + ^^^^^ + = note: no item named `error` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error` + --> $DIR/warning.rs:71:1 + | +LL | #[doc = "single line with \"escaping\" [error]"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + single line with "escaping" [error] + ^^^^^ + = note: no item named `error` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error` + --> $DIR/warning.rs:74:1 + | +LL | / /// Item docs. +LL | | #[doc="Hello there!"] +LL | | /// [error] + | |___________^ + | + = note: the link appears in this line: + + [error] + ^^^^^ + = note: no item named `error` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error1` + --> $DIR/warning.rs:80:11 + | +LL | /// docs [error1] + | ^^^^^^ no item named `error1` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `error2` + --> $DIR/warning.rs:82:11 + | +LL | /// docs [error2] + | ^^^^^^ no item named `error2` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: 19 warnings emitted + diff --git a/src/test/rustdoc-ui/invalid-cfg.rs b/src/test/rustdoc-ui/invalid-cfg.rs new file mode 100644 index 000000000..d237b8605 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-cfg.rs @@ -0,0 +1,4 @@ +#![feature(doc_cfg)] +#[doc(cfg = "x")] //~ ERROR not followed by parentheses +#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +struct S {} diff --git a/src/test/rustdoc-ui/invalid-cfg.stderr b/src/test/rustdoc-ui/invalid-cfg.stderr new file mode 100644 index 000000000..dae238b05 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-cfg.stderr @@ -0,0 +1,14 @@ +error: `cfg` is not followed by parentheses + --> $DIR/invalid-cfg.rs:2:7 + | +LL | #[doc(cfg = "x")] + | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + +error: multiple `cfg` predicates are specified + --> $DIR/invalid-cfg.rs:3:14 + | +LL | #[doc(cfg(x, y))] + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc-ui/invalid-doc-attr.rs b/src/test/rustdoc-ui/invalid-doc-attr.rs new file mode 100644 index 000000000..de004b41e --- /dev/null +++ b/src/test/rustdoc-ui/invalid-doc-attr.rs @@ -0,0 +1,32 @@ +#![crate_type = "lib"] +#![deny(warnings)] + +#[doc(test(no_crate_inject))] +//~^ ERROR can only be applied at the crate level +//~| WARN is being phased out +//~| HELP to apply to the crate, use an inner attribute +//~| SUGGESTION #![doc(test(no_crate_inject))] +#[doc(inline)] +//~^ ERROR can only be applied to a `use` item +//~| WARN is being phased out +pub fn foo() {} + +pub mod bar { + #![doc(test(no_crate_inject))] + //~^ ERROR can only be applied at the crate level + //~| WARN is being phased out + + #[doc(test(no_crate_inject))] + //~^ ERROR can only be applied at the crate level + //~| WARN is being phased out + #[doc(inline)] + //~^ ERROR can only be applied to a `use` item + //~| WARN is being phased out + pub fn baz() {} +} + +#[doc(inline)] +#[doc(no_inline)] +//~^^ ERROR conflicting doc inlining attributes +//~| HELP remove one of the conflicting attributes +pub use bar::baz; diff --git a/src/test/rustdoc-ui/invalid-doc-attr.stderr b/src/test/rustdoc-ui/invalid-doc-attr.stderr new file mode 100644 index 000000000..a4fa38179 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-doc-attr.stderr @@ -0,0 +1,78 @@ +error: this attribute can only be applied at the crate level + --> $DIR/invalid-doc-attr.rs:4:7 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/invalid-doc-attr.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information +help: to apply to the crate, use an inner attribute + | +LL | #![doc(test(no_crate_inject))] + | + +error: this attribute can only be applied to a `use` item + --> $DIR/invalid-doc-attr.rs:9:7 + | +LL | #[doc(inline)] + | ^^^^^^ only applicable on `use` items +... +LL | pub fn foo() {} + | ------------ not a `use` item + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-doc-attr.rs:15:12 + | +LL | #![doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information + +error: conflicting doc inlining attributes + --> $DIR/invalid-doc-attr.rs:28:7 + | +LL | #[doc(inline)] + | ^^^^^^ this attribute... +LL | #[doc(no_inline)] + | ^^^^^^^^^ ...conflicts with this attribute + | + = help: remove one of the conflicting attributes + +error: this attribute can only be applied at the crate level + --> $DIR/invalid-doc-attr.rs:19:11 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information + +error: this attribute can only be applied to a `use` item + --> $DIR/invalid-doc-attr.rs:22:11 + | +LL | #[doc(inline)] + | ^^^^^^ only applicable on `use` items +... +LL | pub fn baz() {} + | ------------ not a `use` item + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information + +error: aborting due to 6 previous errors + diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs new file mode 100644 index 000000000..0f9d2e4b3 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-html-tags.rs @@ -0,0 +1,116 @@ +#![deny(rustdoc::invalid_html_tags)] + +//! <p>💩<p> +//~^ ERROR unclosed HTML tag `p` +//~^^ ERROR unclosed HTML tag `p` + +/// <img><input> +/// <script> +/// <img><input> +/// </script> +/// <unknown> +//~^ ERROR unclosed HTML tag `unknown` +/// < ok +/// <script> +//~^ ERROR unclosed HTML tag `script` +pub fn foo() {} + +/// <h1> +/// <h2> +//~^ ERROR unclosed HTML tag `h2` +/// <h3> +//~^ ERROR unclosed HTML tag `h3` +/// </h1> +/// </hello> +//~^ ERROR unopened HTML tag `hello` +pub fn bar() {} + +/// <div> +/// <br/> <p> +//~^ ERROR unclosed HTML tag `p` +/// </div> +pub fn a() {} + +/// <div> +/// <p> +/// <div></div> +/// </p> +/// </div> +pub fn b() {} + +/// <div style="hello"> +//~^ ERROR unclosed HTML tag `div` +/// <h3> +//~^ ERROR unclosed HTML tag `h3` +/// <script +//~^ ERROR unclosed HTML tag `script` +pub fn c() {} + +// Unclosed tags shouldn't warn if they are nested inside a <script> elem. +/// <script> +/// <h3><div> +/// </script> +/// <script> +/// <div> +/// <p> +/// </div> +/// </script> +pub fn d() {} + +// Unclosed tags shouldn't warn if they are nested inside a <style> elem. +/// <style> +/// <h3><div> +/// </style> +/// <stYle> +/// <div> +/// <p> +/// </div> +/// </style> +pub fn e() {} + +// Closing tags need to have ">" at the end, otherwise it's not a closing tag! +/// <div></div > +/// <div></div +//~^ ERROR unclosed HTML tag `div` +pub fn f() {} + +/// <!----> +/// <!-- --> +/// <!-- <div> --> +/// <!-- <!-- --> +pub fn g() {} + +/// <!-- +/// --> +pub fn h() {} + +/// <!-- +//~^ ERROR Unclosed HTML comment +pub fn i() {} + +/// hello +/// +/// ``` +/// uiapp.run(&env::args().collect::<Vec<_>>()); +/// ``` +pub fn j() {} + +// Check that nested codeblocks are working as well +/// hello +/// +/// ``````markdown +/// normal markdown +/// +/// ``` +/// uiapp.run(&env::args().collect::<Vec<_>>()); +/// ``` +/// +/// <Vec<_> shouldn't warn! +/// `````` +pub fn k() {} + +/// Web Components style <dashed-tags> +//~^ ERROR unclosed HTML tag `dashed-tags` +/// Web Components style </unopened-tag> +//~^ ERROR unopened HTML tag `unopened-tag` +pub fn m() {} diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr new file mode 100644 index 000000000..24a455576 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-html-tags.stderr @@ -0,0 +1,98 @@ +error: unclosed HTML tag `p` + --> $DIR/invalid-html-tags.rs:3:5 + | +LL | //! <p>💩<p> + | ^^^ + | +note: the lint level is defined here + --> $DIR/invalid-html-tags.rs:1:9 + | +LL | #![deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unclosed HTML tag `p` + --> $DIR/invalid-html-tags.rs:3:9 + | +LL | //! <p>💩<p> + | ^^^ + +error: unclosed HTML tag `unknown` + --> $DIR/invalid-html-tags.rs:11:5 + | +LL | /// <unknown> + | ^^^^^^^^^ + +error: unclosed HTML tag `script` + --> $DIR/invalid-html-tags.rs:14:5 + | +LL | /// <script> + | ^^^^^^^^ + +error: unclosed HTML tag `h2` + --> $DIR/invalid-html-tags.rs:19:7 + | +LL | /// <h2> + | ^^^^ + +error: unclosed HTML tag `h3` + --> $DIR/invalid-html-tags.rs:21:9 + | +LL | /// <h3> + | ^^^^ + +error: unopened HTML tag `hello` + --> $DIR/invalid-html-tags.rs:24:5 + | +LL | /// </hello> + | ^^^^^^^^ + +error: unclosed HTML tag `p` + --> $DIR/invalid-html-tags.rs:29:14 + | +LL | /// <br/> <p> + | ^^^ + +error: unclosed HTML tag `div` + --> $DIR/invalid-html-tags.rs:41:5 + | +LL | /// <div style="hello"> + | ^^^^ + +error: unclosed HTML tag `h3` + --> $DIR/invalid-html-tags.rs:43:7 + | +LL | /// <h3> + | ^^^^ + +error: unclosed HTML tag `script` + --> $DIR/invalid-html-tags.rs:45:5 + | +LL | /// <script + | ^^^^^^ + +error: unclosed HTML tag `div` + --> $DIR/invalid-html-tags.rs:73:5 + | +LL | /// <div></div + | ^^^^^ + +error: Unclosed HTML comment + --> $DIR/invalid-html-tags.rs:87:5 + | +LL | /// <!-- + | ^^^ + +error: unopened HTML tag `unopened-tag` + --> $DIR/invalid-html-tags.rs:114:26 + | +LL | /// Web Components style </unopened-tag> + | ^^^^^^^^^^^^^^^ + +error: unclosed HTML tag `dashed-tags` + --> $DIR/invalid-html-tags.rs:112:26 + | +LL | /// Web Components style <dashed-tags> + | ^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors + diff --git a/src/test/rustdoc-ui/invalid-keyword.rs b/src/test/rustdoc-ui/invalid-keyword.rs new file mode 100644 index 000000000..2d70471c8 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-keyword.rs @@ -0,0 +1,4 @@ +#![feature(rustdoc_internals)] + +#[doc(keyword = "foo df")] //~ ERROR +mod foo {} diff --git a/src/test/rustdoc-ui/invalid-keyword.stderr b/src/test/rustdoc-ui/invalid-keyword.stderr new file mode 100644 index 000000000..8658e3825 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-keyword.stderr @@ -0,0 +1,8 @@ +error: `foo df` is not a valid identifier + --> $DIR/invalid-keyword.rs:3:17 + | +LL | #[doc(keyword = "foo df")] + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs new file mode 100644 index 000000000..b503d1093 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-syntax.rs @@ -0,0 +1,101 @@ +// check-pass + +/// ``` +/// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ +/// ``` +pub fn foo() {} +//~^^^^ WARNING could not parse code block as Rust code + +/// ``` +/// | +/// LL | use foobar::Baz; +/// | ^^^^^^ did you mean `baz::foobar`? +/// ``` +pub fn bar() {} +//~^^^^^^ WARNING could not parse code block as Rust code + +/// ``` +/// valid +/// ``` +/// +/// ``` +/// \_ +/// ``` +/// +/// ```text +/// "invalid +/// ``` +pub fn valid_and_invalid() {} +//~^^^^^^^^ WARNING could not parse code block as Rust code + +/// This is a normal doc comment, but... +/// +/// There's a code block with bad syntax in it: +/// +/// ```rust +/// \_ +/// ``` +/// +/// Good thing we tested it! +pub fn baz() {} +//~^^^^^^ WARNING could not parse code block as Rust code + +/// Indented block start +/// +/// code with bad syntax +/// \_ +/// +/// Indented block end +pub fn quux() {} +//~^^^^^ could not parse code block as Rust code + +/// Unclosed fence +/// +/// ``` +/// slkdjf +pub fn xyzzy() {} + +/// Indented code that contains a fence +/// +/// ``` +pub fn blah() {} +//~^^ WARNING could not parse code block as Rust code + +/// ```edition2018 +/// \_ +/// ``` +pub fn blargh() {} +//~^^^^ WARNING could not parse code block as Rust code + +#[doc = "```"] +/// \_ +#[doc = "```"] +pub fn crazy_attrs() {} +//~^^^^ WARNING could not parse code block + +/// ```rust +/// ``` +pub fn empty_rust() {} +//~^^^ WARNING Rust code block is empty + +/// ``` +/// +/// +/// ``` +pub fn empty_rust_with_whitespace() {} +//~^^^^^ WARNING Rust code block is empty + +/// ``` +/// let x = 1; +/// ``` +/// +/// \____/ +/// +pub fn indent_after_fenced() {} +//~^^^ WARNING could not parse code block as Rust code + +/// ``` +/// "invalid +/// ``` +pub fn invalid() {} +//~^^^^ WARNING could not parse code block as Rust code diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr new file mode 100644 index 000000000..4c6249cc6 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -0,0 +1,154 @@ +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:3:5 + | +LL | /// ``` + | _____^ +LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ +LL | | /// ``` + | |_______^ + | + = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default + = note: error from rustc: unknown start of token: \ + = note: error from rustc: unknown start of token: \ + = note: error from rustc: unknown start of token: \ +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ++++ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:9:5 + | +LL | /// ``` + | _____^ +LL | | /// | +LL | | /// LL | use foobar::Baz; +LL | | /// | ^^^^^^ did you mean `baz::foobar`? +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: ` + = note: error from rustc: unknown start of token: ` +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ++++ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:21:5 + | +LL | /// ``` + | _____^ +LL | | /// \_ +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: \ +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ++++ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:35:5 + | +LL | /// ```rust + | _____^ +LL | | /// \_ +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: \ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:45:9 + | +LL | /// code with bad syntax + | _________^ +LL | | /// \_ + | |__________^ + | + = note: error from rustc: unknown start of token: \ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:60:9 + | +LL | /// ``` + | ^^^ + | + = note: error from rustc: unknown start of token: ` + = note: error from rustc: unknown start of token: ` + = note: error from rustc: unknown start of token: ` + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:64:5 + | +LL | /// ```edition2018 + | _____^ +LL | | /// \_ +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: \ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:70:1 + | +LL | / #[doc = "```"] +LL | | /// \_ +LL | | #[doc = "```"] + | |______________^ + | + = help: mark blocks that do not contain Rust code as text: ```text + = note: error from rustc: unknown start of token: \ + +warning: Rust code block is empty + --> $DIR/invalid-syntax.rs:76:5 + | +LL | /// ```rust + | _____^ +LL | | /// ``` + | |_______^ + +warning: Rust code block is empty + --> $DIR/invalid-syntax.rs:81:5 + | +LL | /// ``` + | _____^ +LL | | /// +LL | | /// +LL | | /// ``` + | |_______^ + | +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ++++ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:92:9 + | +LL | /// \____/ + | _________^ +LL | | /// + | |_ + | + = note: error from rustc: unknown start of token: \ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:97:5 + | +LL | /// ``` + | _____^ +LL | | /// "invalid +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unterminated double quote string +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ++++ + +warning: 12 warnings emitted + diff --git a/src/test/rustdoc-ui/invalid-theme-name.rs b/src/test/rustdoc-ui/invalid-theme-name.rs new file mode 100644 index 000000000..c22ebf027 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-theme-name.rs @@ -0,0 +1,3 @@ +// compile-flags:--theme {{src-base}}/invalid-theme-name.rs +// error-pattern: invalid argument +// error-pattern: must have a .css extension diff --git a/src/test/rustdoc-ui/invalid-theme-name.stderr b/src/test/rustdoc-ui/invalid-theme-name.stderr new file mode 100644 index 000000000..80204442d --- /dev/null +++ b/src/test/rustdoc-ui/invalid-theme-name.stderr @@ -0,0 +1,4 @@ +error: invalid argument: "$DIR/invalid-theme-name.rs" + | + = help: arguments to --theme must have a .css extension + diff --git a/src/test/rustdoc-ui/issue-58473-2.rs b/src/test/rustdoc-ui/issue-58473-2.rs new file mode 100644 index 000000000..000b6a329 --- /dev/null +++ b/src/test/rustdoc-ui/issue-58473-2.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(rustdoc::private_doc_tests)] + +mod foo { + /** + Does nothing, returns `()` + + yadda-yadda-yadda + */ + fn foo() {} +} diff --git a/src/test/rustdoc-ui/issue-58473.rs b/src/test/rustdoc-ui/issue-58473.rs new file mode 100644 index 000000000..44e1f58d0 --- /dev/null +++ b/src/test/rustdoc-ui/issue-58473.rs @@ -0,0 +1,10 @@ +// check-pass + +pub trait Foo { + /** + Does nothing, returns `()` + + yadda-yadda-yadda + */ + fn foo() {} +} diff --git a/src/test/rustdoc-ui/issue-61592-2.rs b/src/test/rustdoc-ui/issue-61592-2.rs new file mode 100644 index 000000000..5b4fc5ee7 --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592-2.rs @@ -0,0 +1,10 @@ +// aux-build:issue-61592.rs + +extern crate foo; + +#[doc = "bar"] +#[doc(inline)] //~ ERROR +#[doc = "baz"] +pub use foo::Foo as _; + +fn main() {} diff --git a/src/test/rustdoc-ui/issue-61592-2.stderr b/src/test/rustdoc-ui/issue-61592-2.stderr new file mode 100644 index 000000000..1b7f8bb55 --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592-2.stderr @@ -0,0 +1,12 @@ +error[E0780]: anonymous imports cannot be inlined + --> $DIR/issue-61592-2.rs:6:7 + | +LL | #[doc(inline)] + | ^^^^^^ +LL | #[doc = "baz"] +LL | pub use foo::Foo as _; + | ---------------------- anonymous import + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0780`. diff --git a/src/test/rustdoc-ui/issue-61592.rs b/src/test/rustdoc-ui/issue-61592.rs new file mode 100644 index 000000000..66772557f --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592.rs @@ -0,0 +1,8 @@ +// aux-build:issue-61592.rs + +extern crate foo; + +#[doc(inline)] //~ ERROR +pub use foo::Foo as _; + +fn main() {} diff --git a/src/test/rustdoc-ui/issue-61592.stderr b/src/test/rustdoc-ui/issue-61592.stderr new file mode 100644 index 000000000..9c9c9106f --- /dev/null +++ b/src/test/rustdoc-ui/issue-61592.stderr @@ -0,0 +1,11 @@ +error[E0780]: anonymous imports cannot be inlined + --> $DIR/issue-61592.rs:5:7 + | +LL | #[doc(inline)] + | ^^^^^^ +LL | pub use foo::Foo as _; + | ---------------------- anonymous import + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0780`. diff --git a/src/test/rustdoc-ui/issue-61732.rs b/src/test/rustdoc-ui/issue-61732.rs new file mode 100644 index 000000000..4bd8efeaa --- /dev/null +++ b/src/test/rustdoc-ui/issue-61732.rs @@ -0,0 +1,4 @@ +// This previously triggered an ICE. + +pub(in crate::r#mod) fn main() {} +//~^ ERROR failed to resolve: maybe a missing crate `r#mod` diff --git a/src/test/rustdoc-ui/issue-61732.stderr b/src/test/rustdoc-ui/issue-61732.stderr new file mode 100644 index 000000000..38fadaa44 --- /dev/null +++ b/src/test/rustdoc-ui/issue-61732.stderr @@ -0,0 +1,13 @@ +error[E0433]: failed to resolve: maybe a missing crate `r#mod`? + --> $DIR/issue-61732.rs:3:15 + | +LL | pub(in crate::r#mod) fn main() {} + | ^^^^^ maybe a missing crate `r#mod`? + | + = help: consider adding `extern crate r#mod` to use the `r#mod` crate + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/issue-74134.private.stderr b/src/test/rustdoc-ui/issue-74134.private.stderr new file mode 100644 index 000000000..31d2dbe96 --- /dev/null +++ b/src/test/rustdoc-ui/issue-74134.private.stderr @@ -0,0 +1,11 @@ +warning: public documentation for `public_item` links to private item `PrivateType` + --> $DIR/issue-74134.rs:19:11 + | +LL | /// [`PrivateType`] + | ^^^^^^^^^^^ this item is private + | + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default + = note: this link resolves only because you passed `--document-private-items`, but will break without + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr new file mode 100644 index 000000000..6a3173e3e --- /dev/null +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -0,0 +1,11 @@ +warning: public documentation for `public_item` links to private item `PrivateType` + --> $DIR/issue-74134.rs:19:11 + | +LL | /// [`PrivateType`] + | ^^^^^^^^^^^ this item is private + | + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default + = note: this link will resolve properly if you pass `--document-private-items` + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs new file mode 100644 index 000000000..b1be9123a --- /dev/null +++ b/src/test/rustdoc-ui/issue-74134.rs @@ -0,0 +1,41 @@ +// revisions: public private +// [private]compile-flags: --document-private-items +// check-pass + +// There are 4 cases here: +// 1. public item -> public type: no warning +// 2. public item -> private type: warning +// 3. private item -> public type: no warning +// 4. private item -> private type: no warning +// All 4 cases are tested with and without --document-private-items. +// +// Case 4 without --document-private-items is the one described in issue #74134. + +struct PrivateType; +pub struct PublicType; + +pub struct Public { + /// [`PublicType`] + /// [`PrivateType`] + //~^ WARNING public documentation for `public_item` links to private item `PrivateType` + pub public_item: u32, + + /// [`PublicType`] + /// [`PrivateType`] + private_item: u32, +} + +// The following cases are identical to the ones above, except that they are in a private +// module. Thus they all fall into cases 3 and 4 and should not produce a warning. + +mod private { + pub struct Public { + /// [`super::PublicType`] + /// [`super::PrivateType`] + pub public_item: u32, + + /// [`super::PublicType`] + /// [`super::PrivateType`] + private_item: u32, + } +} diff --git a/src/test/rustdoc-ui/issue-79465.rs b/src/test/rustdoc-ui/issue-79465.rs new file mode 100644 index 000000000..f1a77982f --- /dev/null +++ b/src/test/rustdoc-ui/issue-79465.rs @@ -0,0 +1,3 @@ +pub fn f1<T>(x: T::A) {} +//~^ ERROR +//~^^ ERROR diff --git a/src/test/rustdoc-ui/issue-79465.stderr b/src/test/rustdoc-ui/issue-79465.stderr new file mode 100644 index 000000000..489cc1442 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79465.stderr @@ -0,0 +1,15 @@ +error[E0220]: associated type `A` not found for `T` + --> $DIR/issue-79465.rs:1:20 + | +LL | pub fn f1<T>(x: T::A) {} + | ^ associated type `A` not found + +error[E0220]: associated type `A` not found for `T` + --> $DIR/issue-79465.rs:1:20 + | +LL | pub fn f1<T>(x: T::A) {} + | ^ associated type `A` not found + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0220`. diff --git a/src/test/rustdoc-ui/issue-79467.rs b/src/test/rustdoc-ui/issue-79467.rs new file mode 100644 index 000000000..eb0b9b380 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79467.rs @@ -0,0 +1,8 @@ +fn g() +where + 'static: 'static, + dyn 'static: 'static + Copy, //~ ERROR at least one trait is required for an object type +{ +} + +fn main() {} diff --git a/src/test/rustdoc-ui/issue-79467.stderr b/src/test/rustdoc-ui/issue-79467.stderr new file mode 100644 index 000000000..561513a43 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79467.stderr @@ -0,0 +1,9 @@ +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-79467.rs:4:5 + | +LL | dyn 'static: 'static + Copy, + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0224`. diff --git a/src/test/rustdoc-ui/issue-79494.rs b/src/test/rustdoc-ui/issue-79494.rs new file mode 100644 index 000000000..fc39424b7 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79494.rs @@ -0,0 +1,5 @@ +// only-x86_64-unknown-linux-gnu + +#![feature(const_transmute)] + +const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~ ERROR cannot transmute between types of different sizes, or dependently-sized types diff --git a/src/test/rustdoc-ui/issue-79494.stderr b/src/test/rustdoc-ui/issue-79494.stderr new file mode 100644 index 000000000..7ed5ed382 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79494.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/issue-79494.rs:5:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `usize` (64 bits) + = note: target type: `&[u8]` (128 bits) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0512`. diff --git a/src/test/rustdoc-ui/issue-80992.rs b/src/test/rustdoc-ui/issue-80992.rs new file mode 100644 index 000000000..8983439bb --- /dev/null +++ b/src/test/rustdoc-ui/issue-80992.rs @@ -0,0 +1,11 @@ +// check-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +pub fn test() -> Result<(), ()> { + //! ```compile_fail + //! fn test() -> Result< {} + //! ``` + Ok(()) +} diff --git a/src/test/rustdoc-ui/issue-80992.stdout b/src/test/rustdoc-ui/issue-80992.stdout new file mode 100644 index 000000000..d2b1cd1d5 --- /dev/null +++ b/src/test/rustdoc-ui/issue-80992.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/issue-80992.rs - test (line 7) - compile fail ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/issue-81662-shortness.rs b/src/test/rustdoc-ui/issue-81662-shortness.rs new file mode 100644 index 000000000..27a21a313 --- /dev/null +++ b/src/test/rustdoc-ui/issue-81662-shortness.rs @@ -0,0 +1,12 @@ +// compile-flags:--test --error-format=short +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 + +/// ```rust +/// foo(); +/// ``` +//~^^ ERROR cannot find function `foo` in this scope +fn foo() { + println!("Hello, world!"); +} diff --git a/src/test/rustdoc-ui/issue-81662-shortness.stdout b/src/test/rustdoc-ui/issue-81662-shortness.stdout new file mode 100644 index 000000000..748113be3 --- /dev/null +++ b/src/test/rustdoc-ui/issue-81662-shortness.stdout @@ -0,0 +1,16 @@ + +running 1 test +test $DIR/issue-81662-shortness.rs - foo (line 6) ... FAILED + +failures: + +---- $DIR/issue-81662-shortness.rs - foo (line 6) stdout ---- +$DIR/issue-81662-shortness.rs:7:1: error[E0425]: cannot find function `foo` in this scope +error: aborting due to previous error +Couldn't compile the test. + +failures: + $DIR/issue-81662-shortness.rs - foo (line 6) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.rs b/src/test/rustdoc-ui/issue-83883-describe-lints.rs new file mode 100644 index 000000000..0474d6c14 --- /dev/null +++ b/src/test/rustdoc-ui/issue-83883-describe-lints.rs @@ -0,0 +1,10 @@ +// compile-flags: -W help +// check-pass +// check-stdout +// error-pattern:Lint checks provided +// error-pattern:rustdoc::broken-intra-doc-links +// +// ignore-tidy-linelength +// +// normalize-stdout-test: "( +name default meaning\n +---- ------- -------\n)?( *[[:word:]:-]+ (allow |warn |deny |forbid ) [^\n]+\n)+" -> " $$NAMES $$LEVELS $$MEANINGS" +// normalize-stdout-test: " +name sub-lints\n +---- ---------\n( *[[:word:]:-]+ [^\n]+\n)+" -> " $$NAMES $$SUB_LINTS" diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.stdout b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout new file mode 100644 index 000000000..bbf66a315 --- /dev/null +++ b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout @@ -0,0 +1,24 @@ + +Available lint options: + -W <foo> Warn about <foo> + -A <foo> Allow <foo> + -D <foo> Deny <foo> + -F <foo> Forbid <foo> (deny <foo> and all attempts to override) + + +Lint checks provided by rustc: + + $NAMES $LEVELS $MEANINGS + +Lint groups provided by rustc: + + $NAMES $SUB_LINTS + +Lint checks provided by plugins loaded by this crate: + + $NAMES $LEVELS $MEANINGS + +Lint groups provided by plugins loaded by this crate: + + $NAMES $SUB_LINTS + diff --git a/src/test/rustdoc-ui/issue-91134.rs b/src/test/rustdoc-ui/issue-91134.rs new file mode 100644 index 000000000..d2ff3a252 --- /dev/null +++ b/src/test/rustdoc-ui/issue-91134.rs @@ -0,0 +1,14 @@ +// compile-flags: --test --crate-name=empty_fn --extern=empty_fn --test-args=--test-threads=1 +// aux-build:empty-fn.rs +// check-pass +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// edition:2021 + +/// <https://github.com/rust-lang/rust/issues/91134> +/// +/// ``` +/// extern crate empty_fn; +/// empty_fn::empty(); +/// ``` +pub struct Something; diff --git a/src/test/rustdoc-ui/issue-91134.stdout b/src/test/rustdoc-ui/issue-91134.stdout new file mode 100644 index 000000000..084062743 --- /dev/null +++ b/src/test/rustdoc-ui/issue-91134.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/issue-91134.rs - Something (line 10) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/issue-91713.rs b/src/test/rustdoc-ui/issue-91713.rs new file mode 100644 index 000000000..610bbf11d --- /dev/null +++ b/src/test/rustdoc-ui/issue-91713.rs @@ -0,0 +1,3 @@ +// check-pass +// compile-flags: --passes list +// error-pattern: the `passes` flag no longer functions diff --git a/src/test/rustdoc-ui/issue-91713.stderr b/src/test/rustdoc-ui/issue-91713.stderr new file mode 100644 index 000000000..44ead7a1d --- /dev/null +++ b/src/test/rustdoc-ui/issue-91713.stderr @@ -0,0 +1,5 @@ +warning: the `passes` flag no longer functions + | + = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information + = help: you may want to use --document-private-items + diff --git a/src/test/rustdoc-ui/issue-91713.stdout b/src/test/rustdoc-ui/issue-91713.stdout new file mode 100644 index 000000000..a19e452b4 --- /dev/null +++ b/src/test/rustdoc-ui/issue-91713.stdout @@ -0,0 +1,29 @@ +Available passes for running rustdoc: +check_doc_test_visibility - run various visibility-related lints on doctests + strip-hidden - strips all `#[doc(hidden)]` items from the output + strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports + strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate + propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items +collect-intra-doc-links - resolves intra-doc links +check-code-block-syntax - validates syntax inside Rust code blocks + collect-trait-impls - retrieves trait impls for items in the crate +calculate-doc-coverage - counts the number of items with and without documentation +check-invalid-html-tags - detects invalid HTML tags in doc comments + check-bare-urls - detects URLs that are not hyperlinks + +Default passes for rustdoc: + collect-trait-impls +check_doc_test_visibility + strip-hidden (when not --document-hidden-items) + strip-private (when not --document-private-items) + strip-priv-imports (when --document-private-items) +collect-intra-doc-links +check-code-block-syntax +check-invalid-html-tags + propagate-doc-cfg + check-bare-urls + +Passes run with `--show-coverage`: + strip-hidden (when not --document-hidden-items) + strip-private (when not --document-private-items) +calculate-doc-coverage diff --git a/src/test/rustdoc-ui/issue-98690.rs b/src/test/rustdoc-ui/issue-98690.rs new file mode 100644 index 000000000..fe9bd87ab --- /dev/null +++ b/src/test/rustdoc-ui/issue-98690.rs @@ -0,0 +1,10 @@ +// compile-flags: --test --persist-doctests /../../ -Z unstable-options +// failure-status: 101 +// only-linux + +#![crate_name = "foo"] + +//! ```rust +//! use foo::dummy; +//! dummy(); +//! ``` diff --git a/src/test/rustdoc-ui/issue-98690.stderr b/src/test/rustdoc-ui/issue-98690.stderr new file mode 100644 index 000000000..47d94f99a --- /dev/null +++ b/src/test/rustdoc-ui/issue-98690.stderr @@ -0,0 +1 @@ +Couldn't create directory for doctest executables: Permission denied (os error 13) diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs new file mode 100644 index 000000000..61555a6e6 --- /dev/null +++ b/src/test/rustdoc-ui/lint-group.rs @@ -0,0 +1,29 @@ +//! Documenting the kinds of lints emitted by rustdoc. +//! +//! ``` +//! println!("sup"); +//! ``` + +#![deny(rustdoc::all)] + +/// what up, let's make an [error] +/// +/// ``` +/// println!("sup"); +/// ``` +pub fn link_error() {} //~^^^^^ ERROR unresolved link to `error` + +/// wait, this doesn't have a doctest? +pub fn no_doctest() {} //~^ ERROR missing code example in this documentation + +/// wait, this *does* have a doctest? +/// +/// ``` +/// println!("sup"); +/// ``` +fn private_doctest() {} //~^^^^^ ERROR documentation test in private item + +/// <unknown> +//~^ ERROR unclosed HTML tag `unknown` +//~^^ ERROR missing code example +pub fn c() {} diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr new file mode 100644 index 000000000..e28600160 --- /dev/null +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -0,0 +1,50 @@ +error: missing code example in this documentation + --> $DIR/lint-group.rs:16:1 + | +LL | /// wait, this doesn't have a doctest? + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-group.rs:7:9 + | +LL | #![deny(rustdoc::all)] + | ^^^^^^^^^^^^ + = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc::all)]` + +error: documentation test in private item + --> $DIR/lint-group.rs:19:1 + | +LL | / /// wait, this *does* have a doctest? +LL | | /// +LL | | /// ``` +LL | | /// println!("sup"); +LL | | /// ``` + | |_______^ + | + = note: `#[deny(rustdoc::private_doc_tests)]` implied by `#[deny(rustdoc::all)]` + +error: missing code example in this documentation + --> $DIR/lint-group.rs:26:1 + | +LL | /// <unknown> + | ^^^^^^^^^^^^^ + +error: unresolved link to `error` + --> $DIR/lint-group.rs:9:29 + | +LL | /// what up, let's make an [error] + | ^^^^^ no item named `error` in scope + | + = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(rustdoc::all)]` + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unclosed HTML tag `unknown` + --> $DIR/lint-group.rs:26:5 + | +LL | /// <unknown> + | ^^^^^^^^^ + | + = note: `#[deny(rustdoc::invalid_html_tags)]` implied by `#[deny(rustdoc::all)]` + +error: aborting due to 5 previous errors + diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs new file mode 100644 index 000000000..fac6342cd --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs @@ -0,0 +1,100 @@ +#![deny(missing_docs)] +#![deny(rustdoc::missing_doc_code_examples)] + +//! crate level doc +//! ``` +//! println!("hello"): +//! ``` + + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +pub fn test() { +} + +#[allow(missing_docs)] +pub mod module1 { //~ ERROR +} + +#[allow(rustdoc::missing_doc_code_examples)] +/// doc +pub mod module2 { + + /// doc + pub fn test() {} +} + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +pub mod module3 { + + /// doc + //~^ ERROR + pub fn test() {} +} + +/// Doc, but no code example and it's fine! +pub const Const: u32 = 0; +/// Doc, but no code example and it's fine! +pub static Static: u32 = 0; +/// Doc, but no code example and it's fine! +pub type Type = u32; + +/// Doc +//~^ ERROR +pub struct Struct { + /// Doc, but no code example and it's fine! + pub field: u32, +} + +/// Doc +//~^ ERROR +pub enum Enum { + /// Doc, but no code example and it's fine! + X, +} + +/// Doc +//~^ ERROR +#[repr(C)] +pub union Union { + /// Doc, but no code example and it's fine! + a: i32, + /// Doc, but no code example and it's fine! + b: f32, +} + +// no code example and it's fine! +impl Clone for Struct { + fn clone(&self) -> Self { + Self { field: self.field } + } +} + + + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +#[derive(Clone)] +pub struct NiceStruct; + +#[doc(hidden)] +pub mod foo { + pub fn bar() {} +} + +fn babar() {} + + +mod fofoo { + pub fn tadam() {} +} diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr new file mode 100644 index 000000000..9e51ecd2b --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -0,0 +1,38 @@ +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:19:1 + | +LL | pub mod module1 { + | ^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-missing-doc-code-example.rs:2:9 + | +LL | #![deny(rustdoc::missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:37:3 + | +LL | /// doc + | ^^^^^^^ + +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:49:1 + | +LL | /// Doc + | ^^^^^^^ + +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:56:1 + | +LL | /// Doc + | ^^^^^^^ + +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:63:1 + | +LL | /// Doc + | ^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/rustdoc-ui/macro-docs.rs b/src/test/rustdoc-ui/macro-docs.rs new file mode 100644 index 000000000..0e8472eb2 --- /dev/null +++ b/src/test/rustdoc-ui/macro-docs.rs @@ -0,0 +1,12 @@ +// check-pass + +macro_rules! m { + () => { + /// A + //~^ WARNING + #[path = "auxiliary/module_macro_doc.rs"] + pub mod mymodule; + } +} + +m!(); diff --git a/src/test/rustdoc-ui/macro-docs.stderr b/src/test/rustdoc-ui/macro-docs.stderr new file mode 100644 index 000000000..e3cc17311 --- /dev/null +++ b/src/test/rustdoc-ui/macro-docs.stderr @@ -0,0 +1,20 @@ +warning: unresolved link to `long_cat` + --> $DIR/macro-docs.rs:5:9 + | +LL | /// A + | ^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + = note: the link appears in this line: + + [`long_cat`] is really long + ^^^^^^^^^^ + = note: no item named `long_cat` in scope + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/macro-docs.stdout b/src/test/rustdoc-ui/macro-docs.stdout new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/test/rustdoc-ui/macro-docs.stdout diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.rs b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs new file mode 100644 index 000000000..a186410ac --- /dev/null +++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs @@ -0,0 +1,6 @@ +// error-pattern: no documentation found +// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" +#![deny(rustdoc::missing_crate_level_docs)] +//^~ NOTE defined here + +pub fn foo() {} diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr new file mode 100644 index 000000000..1a1f8085a --- /dev/null +++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr @@ -0,0 +1,12 @@ +error: no documentation found for this crate's top-level module + | +note: the lint level is defined here + --> $DIR/no-crate-level-doc-lint.rs:3:9 + | +LL | #![deny(rustdoc::missing_crate_level_docs)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: The following guide may be of use: + https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/no-run-flag-error.rs b/src/test/rustdoc-ui/no-run-flag-error.rs new file mode 100644 index 000000000..4ead62148 --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag-error.rs @@ -0,0 +1,6 @@ +// test the behavior of the --no-run flag without the --test flag + +// compile-flags:-Z unstable-options --no-run --test-args=--test-threads=1 +// error-pattern: the `--test` flag must be passed + +pub fn f() {} diff --git a/src/test/rustdoc-ui/no-run-flag-error.stderr b/src/test/rustdoc-ui/no-run-flag-error.stderr new file mode 100644 index 000000000..d032646c3 --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag-error.stderr @@ -0,0 +1,2 @@ +error: the `--test` flag must be passed to enable `--no-run` + diff --git a/src/test/rustdoc-ui/no-run-flag.rs b/src/test/rustdoc-ui/no-run-flag.rs new file mode 100644 index 000000000..da1672c4a --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag.rs @@ -0,0 +1,38 @@ +// test the behavior of the --no-run flag + +// check-pass +// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// let a = true; +/// ``` +/// ```should_panic +/// panic!() +/// ``` +/// ```ignore (incomplete-code) +/// fn foo() { +/// ``` +/// ```no_run +/// loop { +/// println!("Hello, world"); +/// } +/// ``` +/// fails to compile +/// ```compile_fail +/// let x = 5; +/// x += 2; // shouldn't compile! +/// ``` +/// Ok the test does not run +/// ``` +/// panic!() +/// ``` +/// Ok the test does not run +/// ```should_panic +/// loop { +/// println!("Hello, world"); +/// panic!() +/// } +/// ``` +pub fn f() {} diff --git a/src/test/rustdoc-ui/no-run-flag.stdout b/src/test/rustdoc-ui/no-run-flag.stdout new file mode 100644 index 000000000..02f28aaf6 --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag.stdout @@ -0,0 +1,12 @@ + +running 7 tests +test $DIR/no-run-flag.rs - f (line 11) - compile ... ok +test $DIR/no-run-flag.rs - f (line 14) ... ignored +test $DIR/no-run-flag.rs - f (line 17) - compile ... ok +test $DIR/no-run-flag.rs - f (line 23) - compile fail ... ok +test $DIR/no-run-flag.rs - f (line 28) - compile ... ok +test $DIR/no-run-flag.rs - f (line 32) - compile ... ok +test $DIR/no-run-flag.rs - f (line 8) - compile ... ok + +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/nocapture-fail.rs b/src/test/rustdoc-ui/nocapture-fail.rs new file mode 100644 index 000000000..7706bd1f3 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.rs @@ -0,0 +1,12 @@ +// check-pass +// compile-flags:--test -Zunstable-options --nocapture +// normalize-stderr-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ```compile_fail +/// fn foo() { +/// Input: 123 +/// } +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/nocapture-fail.stderr b/src/test/rustdoc-ui/nocapture-fail.stderr new file mode 100644 index 000000000..b65b622c1 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.stderr @@ -0,0 +1,18 @@ +error: struct literal body without path + --> $DIR/nocapture-fail.rs:8:10 + | +LL | fn foo() { + | __________^ +LL | | Input: 123 +LL | | } + | |_^ + | +help: you might have forgotten to add the struct literal inside the block + | +LL ~ fn foo() { SomeStruct { +LL | Input: 123 +LL ~ } } + | + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/nocapture-fail.stdout b/src/test/rustdoc-ui/nocapture-fail.stdout new file mode 100644 index 000000000..754f77db5 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture-fail.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/nocapture-fail.rs - Foo (line 7) - compile fail ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/nocapture.rs b/src/test/rustdoc-ui/nocapture.rs new file mode 100644 index 000000000..321f5ca08 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.rs @@ -0,0 +1,10 @@ +// check-pass +// compile-flags:--test -Zunstable-options --nocapture +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// println!("hello!"); +/// eprintln!("stderr"); +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc-ui/nocapture.stderr b/src/test/rustdoc-ui/nocapture.stderr new file mode 100644 index 000000000..af6415db3 --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.stderr @@ -0,0 +1 @@ +stderr diff --git a/src/test/rustdoc-ui/nocapture.stdout b/src/test/rustdoc-ui/nocapture.stdout new file mode 100644 index 000000000..4880e75da --- /dev/null +++ b/src/test/rustdoc-ui/nocapture.stdout @@ -0,0 +1,7 @@ + +running 1 test +hello! +test $DIR/nocapture.rs - Foo (line 6) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/normalize-cycle.rs b/src/test/rustdoc-ui/normalize-cycle.rs new file mode 100644 index 000000000..f48cad373 --- /dev/null +++ b/src/test/rustdoc-ui/normalize-cycle.rs @@ -0,0 +1,25 @@ +// check-pass +// Regresion test for <https://github.com/rust-lang/rust/issues/79459>. +pub trait Query {} + +pub trait AsQuery { + type Query; +} + +impl<T: Query> AsQuery for T { + type Query = T; +} + +pub trait SelectDsl<Selection> { + type Output; +} + +impl<T, Selection> SelectDsl<Selection> for T +where + T: AsQuery, + T::Query: SelectDsl<Selection>, +{ + type Output = <T::Query as SelectDsl<Selection>>::Output; +} + +pub type Select<Source, Selection> = <Source as SelectDsl<Selection>>::Output; diff --git a/src/test/rustdoc-ui/normalize-overflow.rs b/src/test/rustdoc-ui/normalize-overflow.rs new file mode 100644 index 000000000..0cdcc88e3 --- /dev/null +++ b/src/test/rustdoc-ui/normalize-overflow.rs @@ -0,0 +1,3 @@ +// aux-crate:overflow=overflow.rs +// check-pass +// Regression test for <https://github.com/rust-lang/rust/issues/79506>. diff --git a/src/test/rustdoc-ui/output-format-html-stable.rs b/src/test/rustdoc-ui/output-format-html-stable.rs new file mode 100644 index 000000000..fa0362640 --- /dev/null +++ b/src/test/rustdoc-ui/output-format-html-stable.rs @@ -0,0 +1,4 @@ +// compile-flags: --output-format html +// check-pass +// This tests that `--output-format html` is accepted without `-Z unstable-options`, +// since it has been stable since 1.0. diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs new file mode 100644 index 000000000..a1f9f8dca --- /dev/null +++ b/src/test/rustdoc-ui/private-doc-test.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(rustdoc::private_doc_tests)] + +mod foo { + /// private doc test + /// + /// ```ignore (used for testing ignored doc tests) + /// assert!(false); + /// ``` + fn bar() {} +} diff --git a/src/test/rustdoc-ui/private-item-doc-test.rs b/src/test/rustdoc-ui/private-item-doc-test.rs new file mode 100644 index 000000000..1a3d6cc63 --- /dev/null +++ b/src/test/rustdoc-ui/private-item-doc-test.rs @@ -0,0 +1,11 @@ +#![deny(rustdoc::private_doc_tests)] + +mod foo { + /// private doc test + /// + /// ``` + /// assert!(false); + /// ``` + //~^^^^^ ERROR documentation test in private item + fn bar() {} +} diff --git a/src/test/rustdoc-ui/private-item-doc-test.stderr b/src/test/rustdoc-ui/private-item-doc-test.stderr new file mode 100644 index 000000000..5df613298 --- /dev/null +++ b/src/test/rustdoc-ui/private-item-doc-test.stderr @@ -0,0 +1,18 @@ +error: documentation test in private item + --> $DIR/private-item-doc-test.rs:4:5 + | +LL | / /// private doc test +LL | | /// +LL | | /// ``` +LL | | /// assert!(false); +LL | | /// ``` + | |___________^ + | +note: the lint level is defined here + --> $DIR/private-item-doc-test.rs:1:9 + | +LL | #![deny(rustdoc::private_doc_tests)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.rs b/src/test/rustdoc-ui/private-public-item-doc-test.rs new file mode 100644 index 000000000..7cc62b38c --- /dev/null +++ b/src/test/rustdoc-ui/private-public-item-doc-test.rs @@ -0,0 +1,11 @@ +#![deny(rustdoc::private_doc_tests)] + +mod foo { + /// private doc test + /// + /// ``` + /// assert!(false); + /// ``` + //~^^^^^ ERROR documentation test in private item + pub fn bar() {} +} diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.stderr b/src/test/rustdoc-ui/private-public-item-doc-test.stderr new file mode 100644 index 000000000..f50dbd184 --- /dev/null +++ b/src/test/rustdoc-ui/private-public-item-doc-test.stderr @@ -0,0 +1,18 @@ +error: documentation test in private item + --> $DIR/private-public-item-doc-test.rs:4:5 + | +LL | / /// private doc test +LL | | /// +LL | | /// ``` +LL | | /// assert!(false); +LL | | /// ``` + | |___________^ + | +note: the lint level is defined here + --> $DIR/private-public-item-doc-test.rs:1:9 + | +LL | #![deny(rustdoc::private_doc_tests)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/pub-export-lint.rs b/src/test/rustdoc-ui/pub-export-lint.rs new file mode 100644 index 000000000..f2e66b77b --- /dev/null +++ b/src/test/rustdoc-ui/pub-export-lint.rs @@ -0,0 +1,5 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +/// [aloha] +//~^ ERROR unresolved link to `aloha` +pub use std::task::RawWakerVTable; diff --git a/src/test/rustdoc-ui/pub-export-lint.stderr b/src/test/rustdoc-ui/pub-export-lint.stderr new file mode 100644 index 000000000..c6be9c6a9 --- /dev/null +++ b/src/test/rustdoc-ui/pub-export-lint.stderr @@ -0,0 +1,15 @@ +error: unresolved link to `aloha` + --> $DIR/pub-export-lint.rs:3:6 + | +LL | /// [aloha] + | ^^^^^ no item named `aloha` in scope + | +note: the lint level is defined here + --> $DIR/pub-export-lint.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/public-reexported-item-doc-test.rs b/src/test/rustdoc-ui/public-reexported-item-doc-test.rs new file mode 100644 index 000000000..b86a53305 --- /dev/null +++ b/src/test/rustdoc-ui/public-reexported-item-doc-test.rs @@ -0,0 +1,16 @@ +// check-pass + +#![deny(rustdoc::private_doc_tests)] + +pub fn foo() {} + +mod private { + /// re-exported doc test + /// + /// ``` + /// assert!(true); + /// ``` + pub fn bar() {} +} + +pub use private::bar; diff --git a/src/test/rustdoc-ui/range-pattern.rs b/src/test/rustdoc-ui/range-pattern.rs new file mode 100644 index 000000000..fd255d02f --- /dev/null +++ b/src/test/rustdoc-ui/range-pattern.rs @@ -0,0 +1,3 @@ +// check-pass + +fn func(0u8..=255: u8) {} diff --git a/src/test/rustdoc-ui/recursive-deref-ice.rs b/src/test/rustdoc-ui/recursive-deref-ice.rs new file mode 100644 index 000000000..c44fd27f4 --- /dev/null +++ b/src/test/rustdoc-ui/recursive-deref-ice.rs @@ -0,0 +1,19 @@ +// check-pass + +// ICE found in https://github.com/rust-lang/rust/issues/83123 + +pub struct Attribute; + +pub struct Map<'hir> {} +impl<'hir> Map<'hir> { + pub fn attrs(&self) -> &'hir [Attribute] { &[] } +} + +pub struct List<T>(T); + +impl<T> std::ops::Deref for List<T> { + type Target = [T]; + fn deref(&self) -> &[T] { + &[] + } +} diff --git a/src/test/rustdoc-ui/reference-link-reports-error-once.rs b/src/test/rustdoc-ui/reference-link-reports-error-once.rs new file mode 100644 index 000000000..71bd2c522 --- /dev/null +++ b/src/test/rustdoc-ui/reference-link-reports-error-once.rs @@ -0,0 +1,20 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +/// Links to [a] [link][a] +/// And also a [third link][a] +/// And also a [reference link][b] +/// +/// Other links to the same target should still emit error: [ref] //~ERROR unresolved link to `ref` +/// Duplicate [ref] //~ERROR unresolved link to `ref` +/// +/// Other links to other targets should still emit error: [ref2] //~ERROR unresolved link to `ref2` +/// Duplicate [ref2] //~ERROR unresolved link to `ref2` +/// +/// [a]: ref +//~^ ERROR unresolved link to `ref` +/// [b]: ref2 +//~^ ERROR unresolved link to + +/// [ref][] +//~^ ERROR unresolved link +pub fn f() {} diff --git a/src/test/rustdoc-ui/reference-link-reports-error-once.stderr b/src/test/rustdoc-ui/reference-link-reports-error-once.stderr new file mode 100644 index 000000000..b46a51e93 --- /dev/null +++ b/src/test/rustdoc-ui/reference-link-reports-error-once.stderr @@ -0,0 +1,63 @@ +error: unresolved link to `ref` + --> $DIR/reference-link-reports-error-once.rs:13:10 + | +LL | /// [a]: ref + | ^^^ no item named `ref` in scope + | +note: the lint level is defined here + --> $DIR/reference-link-reports-error-once.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `ref2` + --> $DIR/reference-link-reports-error-once.rs:15:10 + | +LL | /// [b]: ref2 + | ^^^^ no item named `ref2` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `ref` + --> $DIR/reference-link-reports-error-once.rs:7:62 + | +LL | /// Other links to the same target should still emit error: [ref] + | ^^^ no item named `ref` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `ref` + --> $DIR/reference-link-reports-error-once.rs:8:16 + | +LL | /// Duplicate [ref] + | ^^^ no item named `ref` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `ref2` + --> $DIR/reference-link-reports-error-once.rs:10:60 + | +LL | /// Other links to other targets should still emit error: [ref2] + | ^^^^ no item named `ref2` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `ref2` + --> $DIR/reference-link-reports-error-once.rs:11:16 + | +LL | /// Duplicate [ref2] + | ^^^^ no item named `ref2` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `ref` + --> $DIR/reference-link-reports-error-once.rs:18:6 + | +LL | /// [ref][] + | ^^^ no item named `ref` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to 7 previous errors + diff --git a/src/test/rustdoc-ui/reference-links.rs b/src/test/rustdoc-ui/reference-links.rs new file mode 100644 index 000000000..e81e03446 --- /dev/null +++ b/src/test/rustdoc-ui/reference-links.rs @@ -0,0 +1,6 @@ +// Test that errors point to the reference, not to the title text. +#![deny(rustdoc::broken_intra_doc_links)] +//! Links to [a] [link][a] +//! +//! [a]: std::process::Comman +//~^ ERROR unresolved diff --git a/src/test/rustdoc-ui/reference-links.stderr b/src/test/rustdoc-ui/reference-links.stderr new file mode 100644 index 000000000..c98a2fd7c --- /dev/null +++ b/src/test/rustdoc-ui/reference-links.stderr @@ -0,0 +1,14 @@ +error: unresolved link to `std::process::Comman` + --> $DIR/reference-links.rs:5:10 + | +LL | //! [a]: std::process::Comman + | ^^^^^^^^^^^^^^^^^^^^ no item named `Comman` in module `process` + | +note: the lint level is defined here + --> $DIR/reference-links.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.rs b/src/test/rustdoc-ui/renamed-lint-still-applies.rs new file mode 100644 index 000000000..a4d3a4b49 --- /dev/null +++ b/src/test/rustdoc-ui/renamed-lint-still-applies.rs @@ -0,0 +1,10 @@ +// compile-args: --crate-type lib +#![deny(broken_intra_doc_links)] +//~^ WARNING renamed to `rustdoc::broken_intra_doc_links` +//! [x] +//~^ ERROR unresolved link + +#![deny(rustdoc::non_autolinks)] +//~^ WARNING renamed to `rustdoc::bare_urls` +//! http://example.com +//~^ ERROR not a hyperlink diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.stderr b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr new file mode 100644 index 000000000..8e2a2cdd7 --- /dev/null +++ b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr @@ -0,0 +1,42 @@ +warning: lint `broken_intra_doc_links` has been renamed to `rustdoc::broken_intra_doc_links` + --> $DIR/renamed-lint-still-applies.rs:2:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +warning: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls` + --> $DIR/renamed-lint-still-applies.rs:7:9 + | +LL | #![deny(rustdoc::non_autolinks)] + | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls` + +error: unresolved link to `x` + --> $DIR/renamed-lint-still-applies.rs:4:6 + | +LL | //! [x] + | ^ no item named `x` in scope + | +note: the lint level is defined here + --> $DIR/renamed-lint-still-applies.rs:2:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: this URL is not a hyperlink + --> $DIR/renamed-lint-still-applies.rs:9:5 + | +LL | //! http://example.com + | ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.com>` + | +note: the lint level is defined here + --> $DIR/renamed-lint-still-applies.rs:7:9 + | +LL | #![deny(rustdoc::non_autolinks)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: bare URLs are not automatically turned into clickable links + +error: aborting due to 2 previous errors; 2 warnings emitted + diff --git a/src/test/rustdoc-ui/run-directory.correct.stdout b/src/test/rustdoc-ui/run-directory.correct.stdout new file mode 100644 index 000000000..e9b275479 --- /dev/null +++ b/src/test/rustdoc-ui/run-directory.correct.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/run-directory.rs - foo (line 10) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/run-directory.incorrect.stdout b/src/test/rustdoc-ui/run-directory.incorrect.stdout new file mode 100644 index 000000000..97a5dbc5c --- /dev/null +++ b/src/test/rustdoc-ui/run-directory.incorrect.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/run-directory.rs - foo (line 19) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/run-directory.rs b/src/test/rustdoc-ui/run-directory.rs new file mode 100644 index 000000000..0d432c1e6 --- /dev/null +++ b/src/test/rustdoc-ui/run-directory.rs @@ -0,0 +1,23 @@ +// this test asserts that the cwd of doctest invocations is set correctly. + +// revisions: correct incorrect +// check-pass +// [correct]compile-flags:--test --test-run-directory={{src-base}} -Zunstable-options +// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage -Zunstable-options +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// assert_eq!( +/// std::fs::read_to_string("run-directory.rs").unwrap(), +/// include_str!("run-directory.rs"), +/// ); +/// ``` +#[cfg(correct)] +pub fn foo() {} + +/// ``` +/// assert!(std::fs::read_to_string("run-directory.rs").is_err()); +/// ``` +#[cfg(incorrect)] +pub fn foo() {} diff --git a/src/test/rustdoc-ui/rustc-check-passes.rs b/src/test/rustdoc-ui/rustc-check-passes.rs new file mode 100644 index 000000000..731cc8ba6 --- /dev/null +++ b/src/test/rustdoc-ui/rustc-check-passes.rs @@ -0,0 +1,4 @@ +#![feature(box_syntax)] +#![feature(box_syntax)] //~ ERROR + +pub fn foo() {} diff --git a/src/test/rustdoc-ui/rustc-check-passes.stderr b/src/test/rustdoc-ui/rustc-check-passes.stderr new file mode 100644 index 000000000..9707895ff --- /dev/null +++ b/src/test/rustdoc-ui/rustc-check-passes.stderr @@ -0,0 +1,9 @@ +error[E0636]: the feature `box_syntax` has already been declared + --> $DIR/rustc-check-passes.rs:2:12 + | +LL | #![feature(box_syntax)] + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0636`. diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs new file mode 100644 index 000000000..8f4fde96d --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs @@ -0,0 +1,7 @@ +// check-fail +// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar + +pub fn foo() { + INVALID_FUNC(); + //~^ ERROR could not resolve path +} diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr new file mode 100644 index 000000000..750aa3207 --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: could not resolve path `INVALID_FUNC` + --> $DIR/scrape-examples-fail-if-type-error.rs:5:3 + | +LL | INVALID_FUNC(); + | ^^^^^^^^^^^^ could not resolve path `INVALID_FUNC` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/scrape-examples-ice.rs b/src/test/rustdoc-ui/scrape-examples-ice.rs new file mode 100644 index 000000000..d629b62a7 --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-ice.rs @@ -0,0 +1,4 @@ +// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar +// check-pass +#![no_std] +use core as _; diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs new file mode 100644 index 000000000..a1f005c32 --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs @@ -0,0 +1 @@ +// compile-flags: -Z unstable-options --scrape-examples-target-crate foobar diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr new file mode 100644 index 000000000..eb8e9f799 --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr @@ -0,0 +1,2 @@ +error: must use --scrape-examples-output-path and --scrape-examples-target-crate together + diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs new file mode 100644 index 000000000..4aacec7f0 --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs @@ -0,0 +1 @@ +// compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr new file mode 100644 index 000000000..eb8e9f799 --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr @@ -0,0 +1,2 @@ +error: must use --scrape-examples-output-path and --scrape-examples-target-crate together + diff --git a/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs new file mode 100644 index 000000000..ce51556dd --- /dev/null +++ b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs @@ -0,0 +1,11 @@ +// check-pass + +// Minimization of issue #59502 + +trait MyTrait<T> { + type Output; +} + +pub fn pow<T: MyTrait<T, Output = T>>(arg: T) -> T { + arg +} diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs new file mode 100644 index 000000000..744b3071f --- /dev/null +++ b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs @@ -0,0 +1,38 @@ +#![deny(rustdoc::invalid_html_tags)] + +/// This Vec<32> thing! +// Numbers aren't valid HTML tags, so no error. +pub struct ConstGeneric; + +/// This Vec<i32, i32> thing! +// HTML tags cannot contain commas, so no error. +pub struct MultipleGenerics; + +/// This Vec<i32 class="test"> thing! +//~^ERROR unclosed HTML tag `i32` +// HTML attributes shouldn't be treated as Rust syntax, so no suggestions. +pub struct TagWithAttributes; + +/// This Vec<i32></i32> thing! +// There should be no error, and no suggestion, since the tags are balanced. +pub struct DoNotWarnOnMatchingTags; + +/// This Vec</i32> thing! +//~^ERROR unopened HTML tag `i32` +// This should produce an error, but no suggestion. +pub struct EndTagsAreNotValidRustSyntax; + +/// This 123<i32> thing! +//~^ERROR unclosed HTML tag `i32` +// This should produce an error, but no suggestion. +pub struct NumbersAreNotPaths; + +/// This Vec:<i32> thing! +//~^ERROR unclosed HTML tag `i32` +// This should produce an error, but no suggestion. +pub struct InvalidTurbofish; + +/// This [link](https://rust-lang.org)<i32> thing! +//~^ERROR unclosed HTML tag `i32` +// This should produce an error, but no suggestion. +pub struct BareTurbofish; diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr new file mode 100644 index 000000000..832b8b2ca --- /dev/null +++ b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr @@ -0,0 +1,38 @@ +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-no-suggestions.rs:11:13 + | +LL | /// This Vec<i32 class="test"> thing! + | ^^^^ + | +note: the lint level is defined here + --> $DIR/html-as-generics-no-suggestions.rs:1:9 + | +LL | #![deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unopened HTML tag `i32` + --> $DIR/html-as-generics-no-suggestions.rs:20:13 + | +LL | /// This Vec</i32> thing! + | ^^^^^^ + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-no-suggestions.rs:25:13 + | +LL | /// This 123<i32> thing! + | ^^^^^ + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-no-suggestions.rs:30:14 + | +LL | /// This Vec:<i32> thing! + | ^^^^^ + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics-no-suggestions.rs:35:39 + | +LL | /// This [link](https://rust-lang.org)<i32> thing! + | ^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.fixed b/src/test/rustdoc-ui/suggestions/html-as-generics.fixed new file mode 100644 index 000000000..c0a0de24c --- /dev/null +++ b/src/test/rustdoc-ui/suggestions/html-as-generics.fixed @@ -0,0 +1,32 @@ +// run-rustfix +#![deny(rustdoc::invalid_html_tags)] + +/// This `Vec<i32>` thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct Generic; + +/// This `vec::Vec<i32>` thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct GenericPath; + +/// This `i32<i32>` thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct PathsCanContainTrailingNumbers; + +/// This `Vec::<i32>` thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct Turbofish; + +/// This [link](https://rust-lang.org)`::<i32>` thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct BareTurbofish; + +/// This <span>`Vec::<i32>`</span> thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct Nested; diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.rs b/src/test/rustdoc-ui/suggestions/html-as-generics.rs new file mode 100644 index 000000000..0b6009b0e --- /dev/null +++ b/src/test/rustdoc-ui/suggestions/html-as-generics.rs @@ -0,0 +1,32 @@ +// run-rustfix +#![deny(rustdoc::invalid_html_tags)] + +/// This Vec<i32> thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct Generic; + +/// This vec::Vec<i32> thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct GenericPath; + +/// This i32<i32> thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct PathsCanContainTrailingNumbers; + +/// This Vec::<i32> thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct Turbofish; + +/// This [link](https://rust-lang.org)::<i32> thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct BareTurbofish; + +/// This <span>Vec::<i32></span> thing! +//~^ERROR unclosed HTML tag `i32` +//~|HELP try marking as source +pub struct Nested; diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics.stderr new file mode 100644 index 000000000..df54b7126 --- /dev/null +++ b/src/test/rustdoc-ui/suggestions/html-as-generics.stderr @@ -0,0 +1,73 @@ +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:4:13 + | +LL | /// This Vec<i32> thing! + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/html-as-generics.rs:2:9 + | +LL | #![deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try marking as source code + | +LL | /// This `Vec<i32>` thing! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:9:18 + | +LL | /// This vec::Vec<i32> thing! + | ^^^^^ + | +help: try marking as source code + | +LL | /// This `vec::Vec<i32>` thing! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:14:13 + | +LL | /// This i32<i32> thing! + | ^^^^^ + | +help: try marking as source code + | +LL | /// This `i32<i32>` thing! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:19:15 + | +LL | /// This Vec::<i32> thing! + | ^^^^^ + | +help: try marking as source code + | +LL | /// This `Vec::<i32>` thing! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:24:41 + | +LL | /// This [link](https://rust-lang.org)::<i32> thing! + | ^^^^^ + | +help: try marking as source code + | +LL | /// This [link](https://rust-lang.org)`::<i32>` thing! + | + + + +error: unclosed HTML tag `i32` + --> $DIR/html-as-generics.rs:29:21 + | +LL | /// This <span>Vec::<i32></span> thing! + | ^^^^^ + | +help: try marking as source code + | +LL | /// This <span>`Vec::<i32>`</span> thing! + | + + + +error: aborting due to 6 previous errors + diff --git a/src/test/rustdoc-ui/test-compile-fail1.rs b/src/test/rustdoc-ui/test-compile-fail1.rs new file mode 100644 index 000000000..a05390238 --- /dev/null +++ b/src/test/rustdoc-ui/test-compile-fail1.rs @@ -0,0 +1,8 @@ +// compile-flags:--test + +/// ``` +/// assert!(true) +/// ``` +pub fn f() {} + +pub fn f() {} diff --git a/src/test/rustdoc-ui/test-compile-fail1.stderr b/src/test/rustdoc-ui/test-compile-fail1.stderr new file mode 100644 index 000000000..72915e46b --- /dev/null +++ b/src/test/rustdoc-ui/test-compile-fail1.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `f` is defined multiple times + --> $DIR/test-compile-fail1.rs:8:1 + | +6 | pub fn f() {} + | ---------- previous definition of the value `f` here +7 | +8 | pub fn f() {} + | ^^^^^^^^^^ `f` redefined here + | + = note: `f` must be defined only once in the value namespace of this module + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0428`. diff --git a/src/test/rustdoc-ui/test-compile-fail2.rs b/src/test/rustdoc-ui/test-compile-fail2.rs new file mode 100644 index 000000000..651ded0a0 --- /dev/null +++ b/src/test/rustdoc-ui/test-compile-fail2.rs @@ -0,0 +1,3 @@ +// compile-flags:--test + +fail diff --git a/src/test/rustdoc-ui/test-compile-fail2.stderr b/src/test/rustdoc-ui/test-compile-fail2.stderr new file mode 100644 index 000000000..cee5b63cf --- /dev/null +++ b/src/test/rustdoc-ui/test-compile-fail2.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found `<eof>` + --> $DIR/test-compile-fail2.rs:3:1 + | +3 | fail + | ^^^^ expected one of `!` or `::` + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/test-compile-fail3.rs b/src/test/rustdoc-ui/test-compile-fail3.rs new file mode 100644 index 000000000..faa30ad83 --- /dev/null +++ b/src/test/rustdoc-ui/test-compile-fail3.rs @@ -0,0 +1,3 @@ +// compile-flags:--test + +"fail diff --git a/src/test/rustdoc-ui/test-compile-fail3.stderr b/src/test/rustdoc-ui/test-compile-fail3.stderr new file mode 100644 index 000000000..fab801b3b --- /dev/null +++ b/src/test/rustdoc-ui/test-compile-fail3.stderr @@ -0,0 +1,9 @@ +error[E0765]: unterminated double quote string + --> $DIR/test-compile-fail3.rs:3:1 + | +3 | "fail + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0765`. diff --git a/src/test/rustdoc-ui/test-no_std.rs b/src/test/rustdoc-ui/test-no_std.rs new file mode 100644 index 000000000..ee919985e --- /dev/null +++ b/src/test/rustdoc-ui/test-no_std.rs @@ -0,0 +1,13 @@ +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// check-pass + +#![no_std] + +extern crate alloc; + +/// ``` +/// assert!(true) +/// ``` +pub fn f() {} diff --git a/src/test/rustdoc-ui/test-no_std.stdout b/src/test/rustdoc-ui/test-no_std.stdout new file mode 100644 index 000000000..8d5a30804 --- /dev/null +++ b/src/test/rustdoc-ui/test-no_std.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/test-no_std.rs - f (line 10) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/test-type.rs b/src/test/rustdoc-ui/test-type.rs new file mode 100644 index 000000000..882da5c25 --- /dev/null +++ b/src/test/rustdoc-ui/test-type.rs @@ -0,0 +1,26 @@ +// compile-flags: --test --test-args=--test-threads=1 +// check-pass +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// let a = true; +/// ``` +/// ```should_panic +/// panic!() +/// ``` +/// ```ignore (incomplete-code) +/// fn foo() { +/// ``` +/// ```no_run +/// loop { +/// println!("Hello, world"); +/// } +/// ``` +/// fails to compile +/// ```compile_fail +/// let x = 5; +/// x += 2; // shouldn't compile! +/// ``` + +pub fn f() {} diff --git a/src/test/rustdoc-ui/test-type.stdout b/src/test/rustdoc-ui/test-type.stdout new file mode 100644 index 000000000..a66fd240d --- /dev/null +++ b/src/test/rustdoc-ui/test-type.stdout @@ -0,0 +1,10 @@ + +running 5 tests +test $DIR/test-type.rs - f (line 12) ... ignored +test $DIR/test-type.rs - f (line 15) - compile ... ok +test $DIR/test-type.rs - f (line 21) - compile fail ... ok +test $DIR/test-type.rs - f (line 6) ... ok +test $DIR/test-type.rs - f (line 9) ... ok + +test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/tuple-variadic-check.rs b/src/test/rustdoc-ui/tuple-variadic-check.rs new file mode 100644 index 000000000..505de5348 --- /dev/null +++ b/src/test/rustdoc-ui/tuple-variadic-check.rs @@ -0,0 +1,15 @@ +#![feature(rustdoc_internals)] + +trait Mine {} + +// This one is fine +#[doc(fake_variadic)] +impl<T> Mine for (T,) {} + +trait Mine2 {} + +// This one is not +#[doc(fake_variadic)] //~ ERROR +impl<T, U> Mine for (T,U) {} + +fn main() {} diff --git a/src/test/rustdoc-ui/tuple-variadic-check.stderr b/src/test/rustdoc-ui/tuple-variadic-check.stderr new file mode 100644 index 000000000..d127fb858 --- /dev/null +++ b/src/test/rustdoc-ui/tuple-variadic-check.stderr @@ -0,0 +1,8 @@ +error: `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity + --> $DIR/tuple-variadic-check.rs:12:7 + | +LL | #[doc(fake_variadic)] + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs new file mode 100644 index 000000000..ddf03dd07 --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs @@ -0,0 +1,24 @@ +#![deny(unknown_lints)] +//~^ NOTE lint level is defined +#![deny(renamed_and_removed_lints)] +//~^ NOTE lint level is defined +#![deny(x)] +//~^ ERROR unknown lint +#![deny(rustdoc::x)] +//~^ ERROR unknown lint: `rustdoc::x` +#![deny(intra_doc_link_resolution_failure)] +//~^ ERROR renamed to `rustdoc::broken_intra_doc_links` +#![deny(non_autolinks)] +//~^ ERROR renamed to `rustdoc::bare_urls` +#![deny(rustdoc::non_autolinks)] +//~^ ERROR renamed to `rustdoc::bare_urls` + +#![deny(private_doc_tests)] +//~^ ERROR renamed to `rustdoc::private_doc_tests` + +#![deny(rustdoc)] +//~^ ERROR removed: use `rustdoc::all` instead + +// Explicitly don't try to handle this case, it was never valid +#![deny(rustdoc::intra_doc_link_resolution_failure)] +//~^ ERROR unknown lint diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr new file mode 100644 index 000000000..b105f47d7 --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr @@ -0,0 +1,64 @@ +error: unknown lint: `x` + --> $DIR/unknown-renamed-lints.rs:5:9 + | +LL | #![deny(x)] + | ^ + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:1:9 + | +LL | #![deny(unknown_lints)] + | ^^^^^^^^^^^^^ + +error: unknown lint: `rustdoc::x` + --> $DIR/unknown-renamed-lints.rs:7:9 + | +LL | #![deny(rustdoc::x)] + | ^^^^^^^^^^ help: did you mean: `rustdoc::all` + +error: lint `intra_doc_link_resolution_failure` has been renamed to `rustdoc::broken_intra_doc_links` + --> $DIR/unknown-renamed-lints.rs:9:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links` + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:3:9 + | +LL | #![deny(renamed_and_removed_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lint `non_autolinks` has been renamed to `rustdoc::bare_urls` + --> $DIR/unknown-renamed-lints.rs:11:9 + | +LL | #![deny(non_autolinks)] + | ^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls` + +error: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls` + --> $DIR/unknown-renamed-lints.rs:13:9 + | +LL | #![deny(rustdoc::non_autolinks)] + | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls` + +error: lint `private_doc_tests` has been renamed to `rustdoc::private_doc_tests` + --> $DIR/unknown-renamed-lints.rs:16:9 + | +LL | #![deny(private_doc_tests)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::private_doc_tests` + +error: lint `rustdoc` has been removed: use `rustdoc::all` instead + --> $DIR/unknown-renamed-lints.rs:19:9 + | +LL | #![deny(rustdoc)] + | ^^^^^^^ + +error: unknown lint: `rustdoc::intra_doc_link_resolution_failure` + --> $DIR/unknown-renamed-lints.rs:23:9 + | +LL | #![deny(rustdoc::intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Compilation failed, aborting rustdoc + +error: aborting due to 9 previous errors + diff --git a/src/test/rustdoc-ui/unparseable-doc-test.rs b/src/test/rustdoc-ui/unparseable-doc-test.rs new file mode 100644 index 000000000..0cff8cd9a --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.rs @@ -0,0 +1,11 @@ +// compile-flags: --test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// failure-status: 101 +// rustc-env: RUST_BACKTRACE=0 + +/// ```rust +/// let x = 7; +/// "unterminated +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout new file mode 100644 index 000000000..2641c66f2 --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout @@ -0,0 +1,23 @@ + +running 1 test +test $DIR/unparseable-doc-test.rs - foo (line 7) ... FAILED + +failures: + +---- $DIR/unparseable-doc-test.rs - foo (line 7) stdout ---- +error[E0765]: unterminated double quote string + --> $DIR/unparseable-doc-test.rs:9:1 + | +LL | "unterminated + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0765`. +Couldn't compile the test. + +failures: + $DIR/unparseable-doc-test.rs - foo (line 7) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/unused-braces-lint.rs b/src/test/rustdoc-ui/unused-braces-lint.rs new file mode 100644 index 000000000..be0e31e4b --- /dev/null +++ b/src/test/rustdoc-ui/unused-braces-lint.rs @@ -0,0 +1,14 @@ +// check-pass + +// This tests the bug in #70814, where the unused_braces lint triggered on the following code +// without providing a span. + +#![deny(unused_braces)] + +fn main() { + { + { + use std; + } + } +} diff --git a/src/test/rustdoc-ui/unused-extern-crate.rs b/src/test/rustdoc-ui/unused-extern-crate.rs new file mode 100644 index 000000000..f703a1837 --- /dev/null +++ b/src/test/rustdoc-ui/unused-extern-crate.rs @@ -0,0 +1,3 @@ +// check-pass +// aux-crate:panic_item=panic-item.rs +// @has unused_extern_crate/index.html diff --git a/src/test/rustdoc-ui/unused.rs b/src/test/rustdoc-ui/unused.rs new file mode 100644 index 000000000..702b24c36 --- /dev/null +++ b/src/test/rustdoc-ui/unused.rs @@ -0,0 +1,14 @@ +// check-pass + +// This test purpose is to check that unused_imports lint isn't fired +// by rustdoc. Why would it? Because when rustdoc is running, it uses +// "everybody-loops" which replaces parts of code with "loop {}" to get +// huge performance improvements. + +#![deny(unused_imports)] + +use std::fs::File; + +pub fn f() { + let _: File; +} diff --git a/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs new file mode 100644 index 000000000..5037043f1 --- /dev/null +++ b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs @@ -0,0 +1 @@ +// compile-flags: --output ./foo diff --git a/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr new file mode 100644 index 000000000..96d2295ac --- /dev/null +++ b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr @@ -0,0 +1,2 @@ +error: cannot use both 'out-dir' and 'output' at once + diff --git a/src/test/rustdoc-ui/wasm-safe.rs b/src/test/rustdoc-ui/wasm-safe.rs new file mode 100644 index 000000000..ba971342b --- /dev/null +++ b/src/test/rustdoc-ui/wasm-safe.rs @@ -0,0 +1,5 @@ +// check-pass + +#[cfg(any(target_arch = "wasm32", doc))] +#[target_feature(enable = "simd128")] +pub fn foo() {} diff --git a/src/test/rustdoc-ui/z-help.rs b/src/test/rustdoc-ui/z-help.rs new file mode 100644 index 000000000..c7cf841b9 --- /dev/null +++ b/src/test/rustdoc-ui/z-help.rs @@ -0,0 +1,6 @@ +// check-pass +// compile-flags: -Zhelp +// check-stdout +// regex-error-pattern: -Z\s+self-profile + +pub struct Foo; diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout new file mode 100644 index 000000000..6dc412315 --- /dev/null +++ b/src/test/rustdoc-ui/z-help.stdout @@ -0,0 +1,200 @@ + -Z allow-features=val -- only allow the listed language features to be enabled in code (space separated) + -Z always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no) + -Z assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no) + -Z asm-comments=val -- generate comments into the assembly (may change behavior) (default: no) + -Z assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`. + -Z binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no) + -Z box-noalias=val -- emit noalias metadata for box (default: yes) + -Z branch-protection=val -- set options for branch target identification and pointer authentication on AArch64 + -Z cf-protection=val -- instrument control-flow architecture protection + -Z cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use + -Z chalk=val -- enable the experimental Chalk-based trait solving engine + -Z codegen-backend=val -- the backend to use + -Z combine-cgu=val -- combine CGUs into a single one + -Z crate-attr=val -- inject the given attribute in the crate + -Z debug-info-for-profiling=val -- emit discriminators and other data necessary for AutoFDO + -Z debug-macros=val -- emit line numbers debug info inside macros (default: no) + -Z deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes) + -Z dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no) + -Z dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no) + -Z dlltool=val -- import library generation tool (windows-gnu only) + -Z dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no) + -Z drop-tracking=val -- enables drop tracking in generators (default: no) + -Z dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no) + -Z dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no) + -Z dump-drop-tracking-cfg=val -- dump drop-tracking control-flow graph as a `.dot` file (default: no) + -Z dump-mir=val -- dump MIR state to file. + `val` is used to select which passes and functions to dump. For example: + `all` matches all passes and functions, + `foo` matches all passes for functions whose name contains 'foo', + `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo', + `foo | bar` all passes for function names containing 'foo' or 'bar'. + -Z dump-mir-dataflow=val -- in addition to `.mir` files, create graphviz `.dot` files with dataflow results (default: no) + -Z dump-mir-dir=val -- the directory the MIR is dumped into (default: `mir_dump`) + -Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no) + -Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no) + -Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans. + -Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform) + -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no) + -Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes) + -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries + -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no) + -Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no) + -Z fuel=val -- set the optimization fuel quota for a crate + -Z function-sections=val -- whether each function should go in its own section + -Z future-incompat-test=val -- forces all lints to be future incompatible, used for internal testing (default: no) + -Z gcc-ld=val -- implementation of ld used by cc + -Z graphviz-dark-mode=val -- use dark-themed colors in graphviz output (default: no) + -Z graphviz-font=val -- use the given `fontname` in graphviz output; can be overridden by setting environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`) + -Z hir-stats=val -- print some statistics about AST and HIR (default: no) + -Z human-readable-cgu-names=val -- generate human-readable, predictable names for codegen units (default: no) + -Z identify-regions=val -- display unnamed regions as `'<id>`, using a non-ident unique id (default: no) + -Z incremental-ignore-spans=val -- ignore spans during ICH computation -- used for testing (default: no) + -Z incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no) + -Z incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no) + -Z incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no) + -Z inline-mir=val -- enable MIR inlining (default: no) + -Z inline-mir-threshold=val -- a default MIR inlining threshold (default: 50) + -Z inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100) + -Z inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs + -Z input-stats=val -- gather statistics about the input (default: no) + -Z instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are: + `=all` (implicit value) + `=except-unused-generics` + `=except-unused-functions` + `=off` (default) + -Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no) + -Z keep-hygiene-data=val -- keep hygiene data after analysis (default: no) + -Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes) + -Z link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no) + -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated) + -Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no) + -Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`) + -Z ls=val -- list the symbols defined by a library crate (default: no) + -Z macro-backtrace=val -- show macro backtraces (default: no) + -Z merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name + -Z meta-stats=val -- gather metadata statistics (default: no) + -Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no) + -Z mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual. + -Z mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing + -Z mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds) + -Z move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted + -Z mutable-noalias=val -- emit noalias metadata for mutable references (default: yes) + -Z new-llvm-pass-manager=val -- use new LLVM pass manager (default: no) + -Z nll-facts=val -- dump facts from NLL analysis into side files (default: no) + -Z nll-facts-dir=val -- the directory the NLL facts are dumped into (default: `nll-facts`) + -Z no-analysis=val -- parse and expand the source, but run no analysis + -Z no-codegen=val -- run all passes except codegen; no output + -Z no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups + -Z no-interleave-lints=val -- execute lints separately; allows benchmarking individual lints + -Z no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests + -Z no-link=val -- compile without linking + -Z no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO) + -Z no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used + -Z no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate + -Z normalize-docs=val -- normalize associated items in rustdoc when generating documentation + -Z oom=val -- panic strategy for out-of-memory handling + -Z osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no) + -Z diagnostic-width=val -- set the current output width for diagnostic truncation + -Z panic-abort-tests=val -- support compiling tests with panic=abort (default: no) + -Z panic-in-drop=val -- panic strategy for panics in drops + -Z parse-only=val -- parse only; do not compile, assemble, or link (default: no) + -Z perf-stats=val -- print some performance-related statistics (default: no) + -Z pick-stable-methods-before-any-unstable=val -- try to pick stable methods first before picking any unstable methods (default: yes) + -Z plt=val -- whether to use the PLT when calling into shared libraries; + only has effect for PIC code on systems with ELF binaries + (default: PLT is disabled if full relro is enabled) + -Z polonius=val -- enable polonius-based borrow-checker (default: no) + -Z polymorphize=val -- perform polymorphization analysis + -Z pre-link-arg=val -- a single extra argument to prepend the linker invocation (can be used several times) + -Z pre-link-args=val -- extra arguments to prepend to the linker invocation (space separated) + -Z precise-enum-drop-elaboration=val -- use a more precise version of drop elaboration for matches on enums (default: yes). This results in better codegen, but has caused miscompilations on some tier 2 platforms. See #77382 and #74551. + -Z print-fuel=val -- make rustc print the total optimization fuel used by a crate + -Z print-llvm-passes=val -- print the LLVM optimization passes being run (default: no) + -Z print-mono-items=val -- print the result of the monomorphization collection pass + -Z print-type-sizes=val -- print layout information for each type encountered (default: no) + -Z proc-macro-backtrace=val -- show backtraces for panics during proc-macro execution (default: no) + -Z proc-macro-execution-strategy=val -- how to run proc-macro code (default: same-thread) + -Z profile=val -- insert profiling code (default: no) + -Z profile-closures=val -- profile size of closures + -Z profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path) + -Z profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`) + -Z profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO) + -Z query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no) + -Z randomize-layout=val -- randomize the layout of types (default: no) + -Z layout-seed=val -- seed layout randomization + -Z relax-elf-relocations=val -- whether ELF relocations can be relaxed + -Z relro-level=val -- choose which RELRO level to use + -Z remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix + -Z simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes + -Z report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no) + -Z sanitizer=val -- use a sanitizer + -Z sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer + -Z sanitizer-recover=val -- enable recovery for selected sanitizers + -Z saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes) + -Z save-analysis=val -- write syntax and type analysis (in JSON format) information, in addition to normal output (default: no) + -Z self-profile=val -- run the self profiler and output the raw event data + -Z self-profile-events=val -- specify the events recorded by the self profiler; + for example: `-Z self-profile-events=default,query-keys` + all options: none, all, default, generic-activity, query-provider, query-cache-hit + query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes + -Z self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of: + `wall-time` (monotonic clock, i.e. `std::time::Instant`) + `instructions:u` (retired instructions, userspace-only) + `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy) + -Z share-generics=val -- make the current crate share its generic instantiations + -Z show-span=val -- show spans for compiler debugging (expr|pat|ty) + -Z span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span` + -Z span-free-formats=val -- exclude spans when debug-printing compiler state (default: no) + -Z src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`) + -Z stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details) + -Z strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB + -Z strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`) + -Z split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) + (default: `split`) + + `split`: sections which do not require relocation are written into a DWARF object (`.dwo`) + file which is ignored by the linker + `single`: sections which do not require relocation are written into object file but ignored + by the linker + -Z split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF + -Z symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0') + -Z teach=val -- show extended diagnostic help (default: no) + -Z temps-dir=val -- the directory the intermediate files are written to + -Z translate-lang=val -- language identifier for diagnostic output + -Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation) + -Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics + -Z tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details) + -Z thinlto=val -- enable ThinLTO when possible + -Z thir-unsafeck=val -- use the THIR unsafety checker (default: no) + -Z threads=val -- use a thread pool with N threads + -Z time=val -- measure time of rustc processes (default: no) + -Z time-llvm-passes=val -- measure time of each LLVM pass (default: no) + -Z time-passes=val -- measure time of each rustc pass (default: no) + -Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details) + -Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no) + -Z translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes) + -Z trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes) + -Z treat-err-as-bug=val -- treat error number `val` that occurs as bug + -Z trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items + -Z ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no) + -Z uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16) + -Z unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no) + -Z unpretty=val -- present the input source, unstable (and less-pretty) variants; + `normal`, `identified`, + `expanded`, `expanded,identified`, + `expanded,hygiene` (with internal representations), + `ast-tree` (raw AST before expansion), + `ast-tree,expanded` (raw AST after expansion), + `hir` (the HIR), `hir,identified`, + `hir,typed` (HIR with types for each node), + `hir-tree` (dump the raw HIR), + `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR) + -Z unsound-mir-opts=val -- enable unsound and buggy MIR optimizations (default: no) + -Z unstable-options=val -- adds unstable command line options to rustc interface (default: no) + -Z use-ctors-section=val -- use legacy .ctors section for initializers rather than .init_array + -Z validate-mir=val -- validate MIR after each transformation + -Z verbose=val -- in general, enable more debug printouts (default: no) + -Z verify-llvm-ir=val -- verify LLVM IR (default: no) + -Z virtual-function-elimination=val -- enables dead virtual function elimination optimization. Requires `-Clto[=[fat,yes]]` + -Z wasi-exec-model=val -- whether to build a wasi command or reactor diff --git a/src/test/rustdoc/all.rs b/src/test/rustdoc/all.rs new file mode 100644 index 000000000..a95d6c462 --- /dev/null +++ b/src/test/rustdoc/all.rs @@ -0,0 +1,28 @@ +#![crate_name = "foo"] + +// @has foo/all.html '//a[@href="struct.Struct.html"]' 'Struct' +// @has foo/all.html '//a[@href="enum.Enum.html"]' 'Enum' +// @has foo/all.html '//a[@href="union.Union.html"]' 'Union' +// @has foo/all.html '//a[@href="constant.CONST.html"]' 'CONST' +// @has foo/all.html '//a[@href="static.STATIC.html"]' 'STATIC' +// @has foo/all.html '//a[@href="fn.function.html"]' 'function' + +pub struct Struct; +pub enum Enum { + X, + Y, +} +pub union Union { + x: u32, +} +pub const CONST: u32 = 0; +pub static STATIC: &str = "baguette"; +pub fn function() {} + +mod private_module { + pub struct ReexportedStruct; +} + +// @has foo/all.html '//a[@href="struct.ReexportedStruct.html"]' 'ReexportedStruct' +// @!has foo/all.html 'private_module' +pub use private_module::ReexportedStruct; diff --git a/src/test/rustdoc/anchors.no_const_anchor.html b/src/test/rustdoc/anchors.no_const_anchor.html new file mode 100644 index 000000000..98f47e530 --- /dev/null +++ b/src/test/rustdoc/anchors.no_const_anchor.html @@ -0,0 +1 @@ +<div id="associatedconstant.YOLO" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#16">source</a></div><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></div> diff --git a/src/test/rustdoc/anchors.no_const_anchor2.html b/src/test/rustdoc/anchors.no_const_anchor2.html new file mode 100644 index 000000000..6d37e8e5e --- /dev/null +++ b/src/test/rustdoc/anchors.no_const_anchor2.html @@ -0,0 +1 @@ +<section id="associatedconstant.X" class="associatedconstant has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#42">source</a></span><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section> diff --git a/src/test/rustdoc/anchors.no_method_anchor.html b/src/test/rustdoc/anchors.no_method_anchor.html new file mode 100644 index 000000000..f46d3090e --- /dev/null +++ b/src/test/rustdoc/anchors.no_method_anchor.html @@ -0,0 +1 @@ +<section id="method.new" class="method has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#48">source</a></span><h4 class="code-header">pub fn <a href="#method.new" class="fnname">new</a>() -> Self</h4></section>
\ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_trait_method_anchor.html b/src/test/rustdoc/anchors.no_trait_method_anchor.html new file mode 100644 index 000000000..445a7bb56 --- /dev/null +++ b/src/test/rustdoc/anchors.no_trait_method_anchor.html @@ -0,0 +1 @@ +<div id="method.bar" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#23">source</a></div><h4 class="code-header">fn <a href="#method.bar" class="fnname">bar</a>()</h4></div>
\ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_tymethod_anchor.html b/src/test/rustdoc/anchors.no_tymethod_anchor.html new file mode 100644 index 000000000..bb0771b10 --- /dev/null +++ b/src/test/rustdoc/anchors.no_tymethod_anchor.html @@ -0,0 +1 @@ +<div id="tymethod.foo" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#20">source</a></div><h4 class="code-header">fn <a href="#tymethod.foo" class="fnname">foo</a>()</h4></div>
\ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_type_anchor.html b/src/test/rustdoc/anchors.no_type_anchor.html new file mode 100644 index 000000000..d317eb500 --- /dev/null +++ b/src/test/rustdoc/anchors.no_type_anchor.html @@ -0,0 +1 @@ +<div id="associatedtype.T" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#13">source</a></div><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></div>
\ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_type_anchor2.html b/src/test/rustdoc/anchors.no_type_anchor2.html new file mode 100644 index 000000000..72a1186bf --- /dev/null +++ b/src/test/rustdoc/anchors.no_type_anchor2.html @@ -0,0 +1 @@ +<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> diff --git a/src/test/rustdoc/anchors.rs b/src/test/rustdoc/anchors.rs new file mode 100644 index 000000000..034cf8eaf --- /dev/null +++ b/src/test/rustdoc/anchors.rs @@ -0,0 +1,49 @@ +// This test ensures that anchors are generated in the right places. + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] +#![crate_name = "foo"] + +pub struct Foo; + +// @has 'foo/trait.Bar.html' +pub trait Bar { + // There should be no anchors here. + // @snapshot no_type_anchor - '//*[@id="associatedtype.T"]' + type T; + // There should be no anchors here. + // @snapshot no_const_anchor - '//*[@id="associatedconstant.YOLO"]' + const YOLO: u32; + + // There should be no anchors here. + // @snapshot no_tymethod_anchor - '//*[@id="tymethod.foo"]' + fn foo(); + // There should be no anchors here. + // @snapshot no_trait_method_anchor - '//*[@id="method.bar"]' + fn bar() {} +} + +// @has 'foo/struct.Foo.html' +impl Bar for Foo { + // @has - '//*[@id="associatedtype.T"]/a[@class="anchor"]' '' + type T = u32; + // @has - '//*[@id="associatedconstant.YOLO"]/a[@class="anchor"]' '' + const YOLO: u32 = 0; + + // @has - '//*[@id="method.foo"]/a[@class="anchor"]' '' + fn foo() {} + // Same check for provided "bar" method. + // @has - '//*[@id="method.bar"]/a[@class="anchor"]' '' +} + +impl Foo { + // @snapshot no_const_anchor2 - '//*[@id="associatedconstant.X"]' + // There should be no anchors here. + pub const X: i32 = 0; + // @snapshot no_type_anchor2 - '//*[@id="associatedtype.Y"]' + // There should be no anchors here. + pub type Y = u32; + // @snapshot no_method_anchor - '//*[@id="method.new"]' + // There should be no anchors here. + pub fn new() -> Self { Self } +} diff --git a/src/test/rustdoc/anonymous-lifetime.rs b/src/test/rustdoc/anonymous-lifetime.rs new file mode 100644 index 000000000..f5a7d2258 --- /dev/null +++ b/src/test/rustdoc/anonymous-lifetime.rs @@ -0,0 +1,28 @@ +// Regression test for https://github.com/rust-lang/rust/issues/84634 +#![crate_name = "foo"] + +use std::pin::Pin; +use std::task::Poll; + +pub trait Stream { + type Item; + + fn poll_next(mut self: Pin<&mut Self>) -> Poll<Option<Self::Item>>; + fn size_hint(&self) -> (usize, Option<usize>); +} + +// @has 'foo/trait.Stream.html' +// @has - '//*[@class="code-header in-band"]' 'impl<S: ?Sized + Stream + Unpin> Stream for &mut S' +impl<S: ?Sized + Stream + Unpin> Stream for &mut S { + type Item = S::Item; + + fn poll_next( + mut self: Pin<&mut Self>, + ) -> Poll<Option<Self::Item>> { + S::poll_next(Pin::new(&mut **self), cx) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (**self).size_hint() + } +} diff --git a/src/test/rustdoc/anonymous-reexport.rs b/src/test/rustdoc/anonymous-reexport.rs new file mode 100644 index 000000000..6b884ff14 --- /dev/null +++ b/src/test/rustdoc/anonymous-reexport.rs @@ -0,0 +1,22 @@ +#![crate_name = "foo"] + +// This test ensures we don't display anonymous (non-inline) re-exports of public items. + +// @has 'foo/index.html' +// @has - '//*[@id="main-content"]' '' +// We check that the only "h2" present is for "Bla". +// @count - '//*[@id="main-content"]/h2' 1 +// @has - '//*[@id="main-content"]/h2' 'Structs' +// @count - '//*[@id="main-content"]//a[@class="struct"]' 1 + +mod ext { + pub trait Foo {} + pub trait Bar {} + pub struct S; +} + +pub use crate::ext::Foo as _; +pub use crate::ext::Bar as _; +pub use crate::ext::S as _; + +pub struct Bla; diff --git a/src/test/rustdoc/asm-foreign.rs b/src/test/rustdoc/asm-foreign.rs new file mode 100644 index 000000000..d7550ca5a --- /dev/null +++ b/src/test/rustdoc/asm-foreign.rs @@ -0,0 +1,20 @@ +// Make sure rustdoc accepts asm! for a foreign architecture. + +use std::arch::asm; + +// @has asm_foreign/fn.aarch64.html +pub unsafe fn aarch64(a: f64, b: f64) -> f64 { + let c; + asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + || {}; + b + }); + c +} + +// @has asm_foreign/fn.x86.html +pub unsafe fn x86(a: f64, b: f64) -> f64 { + let c; + asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b); + c +} diff --git a/src/test/rustdoc/asm-foreign2.rs b/src/test/rustdoc/asm-foreign2.rs new file mode 100644 index 000000000..87306901e --- /dev/null +++ b/src/test/rustdoc/asm-foreign2.rs @@ -0,0 +1,11 @@ +// only-aarch64 +// Make sure rustdoc accepts options(att_syntax) asm! on non-x86 targets. + +use std::arch::asm; + +// @has asm_foreign2/fn.x86.html +pub unsafe fn x86(x: i64) -> i64 { + let y; + asm!("movq {}, {}", in(reg) x, out(reg) y, options(att_syntax)); + y +} diff --git a/src/test/rustdoc/assoc-consts-version.rs b/src/test/rustdoc/assoc-consts-version.rs new file mode 100644 index 000000000..6060bc0a6 --- /dev/null +++ b/src/test/rustdoc/assoc-consts-version.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +#![feature(staged_api)] + +#![stable(since="1.1.1", feature="rust1")] + +#[stable(since="1.1.1", feature="rust1")] +pub struct SomeStruct; + +impl SomeStruct { + // @has 'foo/struct.SomeStruct.html' \ + // '//*[@id="associatedconstant.SOME_CONST"]//span[@class="since"]' '1.1.2' + #[stable(since="1.1.2", feature="rust2")] + pub const SOME_CONST: usize = 0; +} diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs new file mode 100644 index 000000000..a79e93145 --- /dev/null +++ b/src/test/rustdoc/assoc-consts.rs @@ -0,0 +1,103 @@ +pub trait Foo { + // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \ + // 'const FOO: usize = 13usize;' + // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize' + const FOO: usize = 12 + 1; + // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool' + const FOO_NO_DEFAULT: bool; + // @!has - FOO_HIDDEN + #[doc(hidden)] + const FOO_HIDDEN: u8 = 0; +} + +pub struct Bar; + +impl Foo for Bar { + // @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Foo for Bar' + // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize' + const FOO: usize = 12; + // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool' + const FOO_NO_DEFAULT: bool = false; + // @!has - FOO_HIDDEN + #[doc(hidden)] + const FOO_HIDDEN: u8 = 0; +} + +impl Bar { + // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \ + // 'const BAR: usize' + pub const BAR: usize = 3; + + // @has - '//*[@id="associatedconstant.BAR_ESCAPED"]' \ + // "const BAR_ESCAPED: &'static str = \"<em>markup</em>\"" + pub const BAR_ESCAPED: &'static str = "<em>markup</em>"; +} + +pub struct Baz<'a, U: 'a, T>(T, &'a [U]); + +impl Bar { + // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAZ"]' \ + // "const BAZ: Baz<'static, u8, u32>" + pub const BAZ: Baz<'static, u8, u32> = Baz(321, &[1, 2, 3]); +} + +pub fn f(_: &(ToString + 'static)) {} + +impl Bar { + // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \ + // "const F: fn(_: &(dyn ToString + 'static))" + pub const F: fn(_: &(ToString + 'static)) = f; +} + +impl Bar { + // @!has assoc_consts/struct.Bar.html 'BAR_PRIVATE' + const BAR_PRIVATE: char = 'a'; + // @!has assoc_consts/struct.Bar.html 'BAR_HIDDEN' + #[doc(hidden)] + pub const BAR_HIDDEN: &'static str = "a"; +} + +// @has assoc_consts/trait.Qux.html +pub trait Qux { + // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8' + // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait." + /// Docs for QUX0 in trait. + const QUX0: u8; + // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8' + // @has - '//*[@class="docblock"]' "Docs for QUX1 in trait." + /// Docs for QUX1 in trait. + const QUX1: i8; + // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16' + // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait." + /// Docs for QUX_DEFAULT12 in trait. + const QUX_DEFAULT0: u16 = 1; + // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16' + // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in trait." + /// Docs for QUX_DEFAULT1 in trait. + const QUX_DEFAULT1: i16 = 2; + // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32' + // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait." + /// Docs for QUX_DEFAULT2 in trait. + const QUX_DEFAULT2: u32 = 3; +} + +// @has assoc_consts/struct.Bar.html '//h3[@class="code-header in-band"]' 'impl Qux for Bar' +impl Qux for Bar { + // @has - '//*[@id="associatedconstant.QUX0"]' 'const QUX0: u8' + // @has - '//*[@class="docblock"]' "Docs for QUX0 in trait." + /// Docs for QUX0 in trait. + const QUX0: u8 = 4; + // @has - '//*[@id="associatedconstant.QUX1"]' 'const QUX1: i8' + // @has - '//*[@class="docblock"]' "Docs for QUX1 in impl." + /// Docs for QUX1 in impl. + const QUX1: i8 = 5; + // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16' + // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait." + const QUX_DEFAULT0: u16 = 6; + // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16' + // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl." + /// Docs for QUX_DEFAULT1 in impl. + const QUX_DEFAULT1: i16 = 7; + // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32' + // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait." +} diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs new file mode 100644 index 000000000..a409d6413 --- /dev/null +++ b/src/test/rustdoc/assoc-item-cast.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + +pub trait Expression { + type SqlType; +} + +pub trait AsExpression<T> { + type Expression: Expression<SqlType = T>; + fn as_expression(self) -> Self::Expression; +} + +// @has foo/type.AsExprOf.html +// @has - '//pre[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;' +pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression; diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs new file mode 100644 index 000000000..a9e5b8d00 --- /dev/null +++ b/src/test/rustdoc/assoc-types.rs @@ -0,0 +1,37 @@ +#![crate_type="lib"] + +// @has assoc_types/trait.Index.html +pub trait Index<I: ?Sized> { + // @has - '//*[@id="associatedtype.Output"]//h4[@class="code-header"]' 'type Output: ?Sized' + type Output: ?Sized; + // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]' \ + // "fn index<'a>(&'a self, index: I) -> &'a Self::Output" + // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]//a[@href="trait.Index.html#associatedtype.Output"]' \ + // "Output" + fn index<'a>(&'a self, index: I) -> &'a Self::Output; +} + +// @has assoc_types/fn.use_output.html +// @has - '//*[@class="rust fn"]' '-> &T::Output' +// @has - '//*[@class="rust fn"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output' +pub fn use_output<T: Index<usize>>(obj: &T, index: usize) -> &T::Output { + obj.index(index) +} + +pub trait Feed { + type Input; +} + +// @has assoc_types/fn.use_input.html +// @has - '//*[@class="rust fn"]' 'T::Input' +// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input' +pub fn use_input<T: Feed>(_feed: &T, _element: T::Input) { } + +// @has assoc_types/fn.cmp_input.html +// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq<U::Input>' +// @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input' +pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool + where T::Input: PartialEq<U::Input> +{ + a == b +} diff --git a/src/test/rustdoc/associated-consts.rs b/src/test/rustdoc/associated-consts.rs new file mode 100644 index 000000000..9319a073b --- /dev/null +++ b/src/test/rustdoc/associated-consts.rs @@ -0,0 +1,51 @@ +#![crate_name = "foo"] + +pub trait Trait { + const FOO: u32 = 12; + + fn foo(); +} + +pub struct Bar; + +// @has 'foo/struct.Bar.html' +// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants' +// @!has - '//div[@class="sidebar-elems"]//a' 'FOO' +impl Trait for Bar { + const FOO: u32 = 1; + + fn foo() {} +} + +pub enum Foo { + A, +} + +// @has 'foo/enum.Foo.html' +// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants' +// @!has - '//div[@class="sidebar-elems"]//a' 'FOO' +impl Trait for Foo { + const FOO: u32 = 1; + + fn foo() {} +} + +pub struct Baz; + +// @has 'foo/struct.Baz.html' +// @has - '//h3[@class="sidebar-title"]' 'Associated Constants' +// @has - '//div[@class="sidebar-elems"]//a' 'FOO' +impl Baz { + pub const FOO: u32 = 42; +} + +pub enum Quux { + B, +} + +// @has 'foo/enum.Quux.html' +// @has - '//h3[@class="sidebar-title"]' 'Associated Constants' +// @has - '//div[@class="sidebar-elems"]//a' 'FOO' +impl Quux { + pub const FOO: u32 = 42; +} diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs new file mode 100644 index 000000000..0277501de --- /dev/null +++ b/src/test/rustdoc/async-fn.rs @@ -0,0 +1,95 @@ +// edition:2018 +// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>' +pub async fn foo() -> Option<Foo> { + None +} + +// @has async_fn/fn.bar.html '//pre[@class="rust fn"]' 'pub async fn bar(a: i32, b: i32) -> i32' +pub async fn bar(a: i32, b: i32) -> i32 { + 0 +} + +// @has async_fn/fn.baz.html '//pre[@class="rust fn"]' 'pub async fn baz<T>(a: T) -> T' +pub async fn baz<T>(a: T) -> T { + a +} + +// @has async_fn/fn.qux.html '//pre[@class="rust fn"]' 'pub async unsafe fn qux() -> char' +pub async unsafe fn qux() -> char { + '⚠' +} + +// @has async_fn/fn.mut_args.html '//pre[@class="rust fn"]' 'pub async fn mut_args(a: usize)' +pub async fn mut_args(mut a: usize) {} + +// @has async_fn/fn.mut_ref.html '//pre[@class="rust fn"]' 'pub async fn mut_ref(x: i32)' +pub async fn mut_ref(ref mut x: i32) {} + +trait Bar {} + +impl Bar for () {} + +// @has async_fn/fn.quux.html '//pre[@class="rust fn"]' 'pub async fn quux() -> impl Bar' +pub async fn quux() -> impl Bar { + () +} + +// @has async_fn/struct.Foo.html +// @matches - '//h4[@class="code-header"]' 'pub async fn f\(\)$' +// @matches - '//h4[@class="code-header"]' 'pub async unsafe fn g\(\)$' +// @matches - '//h4[@class="code-header"]' 'pub async fn mut_self\(self, first: usize\)$' +pub struct Foo; + +impl Foo { + pub async fn f() {} + pub async unsafe fn g() {} + pub async fn mut_self(mut self, mut first: usize) {} +} + +pub trait Pattern<'a> {} + +pub trait Trait<const N: usize> {} +// @has async_fn/fn.const_generics.html +// @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)' +pub async fn const_generics<const N: usize>(_: impl Trait<N>) {} + +// test that elided lifetimes are properly elided and not displayed as `'_` +// regression test for #63037 +// @has async_fn/fn.elided.html +// @has - '//pre[@class="rust fn"]' 'pub async fn elided(foo: &str) -> &str' +pub async fn elided(foo: &str) -> &str {} +// This should really be shown as written, but for implementation reasons it's difficult. +// See `impl Clean for TyKind::Rptr`. +// @has async_fn/fn.user_elided.html +// @has - '//pre[@class="rust fn"]' 'pub async fn user_elided(foo: &str) -> &str' +pub async fn user_elided(foo: &'_ str) -> &str {} +// @has async_fn/fn.static_trait.html +// @has - '//pre[@class="rust fn"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>' +pub async fn static_trait(foo: &str) -> Box<dyn Bar> {} +// @has async_fn/fn.lifetime_for_trait.html +// @has - '//pre[@class="rust fn"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>" +pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {} +// @has async_fn/fn.elided_in_input_trait.html +// @has - '//pre[@class="rust fn"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)" +pub async fn elided_in_input_trait(t: impl Pattern<'_>) {} + +struct AsyncFdReadyGuard<'a, T> { x: &'a T } + +impl Foo { + // @has async_fn/struct.Foo.html + // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>' + pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {} + // taken from `tokio` as an example of a method that was particularly bad before + // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>" + pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {} + // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)" + pub async fn mut_self(&mut self) {} +} + +// test named lifetimes, just in case +// @has async_fn/fn.named.html +// @has - '//pre[@class="rust fn"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str" +pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {} +// @has async_fn/fn.named_trait.html +// @has - '//pre[@class="rust fn"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>" +pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {} diff --git a/src/test/rustdoc/async-move-doctest.rs b/src/test/rustdoc/async-move-doctest.rs new file mode 100644 index 000000000..2ba61388c --- /dev/null +++ b/src/test/rustdoc/async-move-doctest.rs @@ -0,0 +1,12 @@ +// compile-flags:--test +// edition:2018 + +// Prior to setting the default edition for the doctest pre-parser, +// this doctest would fail due to a fatal parsing error. +// see https://github.com/rust-lang/rust/issues/59313 + +//! ``` +//! fn foo() { +//! drop(async move {}); +//! } +//! ``` diff --git a/src/test/rustdoc/attribute-rendering.rs b/src/test/rustdoc/attribute-rendering.rs new file mode 100644 index 000000000..677787184 --- /dev/null +++ b/src/test/rustdoc/attribute-rendering.rs @@ -0,0 +1,7 @@ +#![crate_name = "foo"] + +// @has 'foo/fn.f.html' +// @has - //*[@'class="docblock item-decl"]' '#[export_name = "f"] pub fn f()' +#[export_name = "\ +f"] +pub fn f() {} diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs new file mode 100644 index 000000000..1c7f4b724 --- /dev/null +++ b/src/test/rustdoc/attributes.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +// @has foo/fn.f.html '//*[@class="rust fn"]' '#[no_mangle]' +#[no_mangle] +pub extern "C" fn f() {} + +// @has foo/fn.g.html '//*[@class="rust fn"]' '#[export_name = "bar"]' +#[export_name = "bar"] +pub extern "C" fn g() {} + +// @has foo/struct.Repr.html '//*[@class="docblock item-decl"]' '#[repr(C, align(8))]' +#[repr(C, align(8))] +pub struct Repr; diff --git a/src/test/rustdoc/auto-impl-for-trait.rs b/src/test/rustdoc/auto-impl-for-trait.rs new file mode 100644 index 000000000..bc658fbfc --- /dev/null +++ b/src/test/rustdoc/auto-impl-for-trait.rs @@ -0,0 +1,16 @@ +// Test for https://github.com/rust-lang/rust/issues/48463 issue. + +use std::any::Any; +use std::ops::Deref; + +pub struct AnyValue { + val: Box<Any>, +} + +impl Deref for AnyValue { + type Target = Any; + + fn deref(&self) -> &Any { + &*self.val + } +} diff --git a/src/test/rustdoc/auto-impl-primitive.rs b/src/test/rustdoc/auto-impl-primitive.rs new file mode 100644 index 000000000..172333d44 --- /dev/null +++ b/src/test/rustdoc/auto-impl-primitive.rs @@ -0,0 +1,10 @@ +#![feature(rustdoc_internals)] + +#![crate_name = "foo"] + +pub use std::fs::File; + +// @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation' +#[doc(primitive = "i16")] +/// I love poneys! +mod prim {} diff --git a/src/test/rustdoc/auto-trait-not-send.rs b/src/test/rustdoc/auto-trait-not-send.rs new file mode 100644 index 000000000..661d905ab --- /dev/null +++ b/src/test/rustdoc/auto-trait-not-send.rs @@ -0,0 +1,8 @@ +#![crate_name = "foo"] + +// @has 'foo/struct.Foo.html' +// @has - '//*[@id="impl-Send-for-Foo"]' 'impl !Send for Foo' +// @has - '//*[@id="impl-Sync-for-Foo"]' 'impl !Sync for Foo' +pub struct Foo(*const i8); +pub trait Whatever: Send {} +impl<T: Send + ?Sized> Whatever for T {} diff --git a/src/test/rustdoc/auto-traits.rs b/src/test/rustdoc/auto-traits.rs new file mode 100644 index 000000000..93d4bf2f6 --- /dev/null +++ b/src/test/rustdoc/auto-traits.rs @@ -0,0 +1,13 @@ +// aux-build:auto-traits.rs + +#![feature(auto_traits)] + +#![crate_name = "foo"] + +extern crate auto_traits; + +// @has 'foo/trait.Foo.html' '//pre' 'pub unsafe auto trait Foo' +pub unsafe auto trait Foo {} + +// @has 'foo/trait.Bar.html' '//pre' 'pub unsafe auto trait Bar' +pub use auto_traits::Bar; diff --git a/src/test/rustdoc/auto_aliases.rs b/src/test/rustdoc/auto_aliases.rs new file mode 100644 index 000000000..a047c76b6 --- /dev/null +++ b/src/test/rustdoc/auto_aliases.rs @@ -0,0 +1,6 @@ +#![feature(auto_traits)] + +// @has auto_aliases/trait.Bar.html '//*[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo' +pub struct Foo; + +pub auto trait Bar {} diff --git a/src/test/rustdoc/auxiliary/all-item-types.rs b/src/test/rustdoc/auxiliary/all-item-types.rs new file mode 100644 index 000000000..f94bd9987 --- /dev/null +++ b/src/test/rustdoc/auxiliary/all-item-types.rs @@ -0,0 +1,22 @@ +#![feature(extern_types)] + +pub mod foo_mod {} +extern "C" { + pub fn foo_ffn(); + pub static FOO_FSTATIC: FooStruct; + pub type FooFType; +} +pub fn foo_fn() {} +pub trait FooTrait {} +pub struct FooStruct; +pub enum FooEnum {} +pub union FooUnion { + x: (), +} +pub type FooType = FooStruct; +pub static FOO_STATIC: FooStruct = FooStruct; +pub const FOO_CONSTANT: FooStruct = FooStruct; +#[macro_export] +macro_rules! foo_macro { + () => (); +} diff --git a/src/test/rustdoc/auxiliary/auto-traits.rs b/src/test/rustdoc/auxiliary/auto-traits.rs new file mode 100644 index 000000000..84976c73b --- /dev/null +++ b/src/test/rustdoc/auxiliary/auto-traits.rs @@ -0,0 +1,3 @@ +#![feature(auto_traits)] + +pub unsafe auto trait Bar {} diff --git a/src/test/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs b/src/test/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs new file mode 100644 index 000000000..3baf8a6c0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs @@ -0,0 +1,19 @@ +pub trait Tr { + type VisibleAssoc; + #[doc(hidden)] + type HiddenAssoc; + + const VISIBLE_ASSOC: (); + #[doc(hidden)] + const HIDDEN_ASSOC: (); +} + +pub struct Ty; + +impl Tr for Ty { + type VisibleAssoc = (); + type HiddenAssoc = (); + + const VISIBLE_ASSOC: () = (); + const HIDDEN_ASSOC: () = (); +} diff --git a/src/test/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs b/src/test/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs new file mode 100644 index 000000000..159531222 --- /dev/null +++ b/src/test/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs @@ -0,0 +1,5 @@ +#[doc(hidden)] +pub enum HiddenType {} + +#[doc(hidden)] +pub trait HiddenTrait {} diff --git a/src/test/rustdoc/auxiliary/elided-lifetime.rs b/src/test/rustdoc/auxiliary/elided-lifetime.rs new file mode 100644 index 000000000..4f2c93379 --- /dev/null +++ b/src/test/rustdoc/auxiliary/elided-lifetime.rs @@ -0,0 +1,11 @@ +#![crate_name = "bar"] + +pub struct Ref<'a>(&'a u32); + +pub fn test5(a: &u32) -> Ref { + Ref(a) +} + +pub fn test6(a: &u32) -> Ref<'_> { + Ref(a) +} diff --git a/src/test/rustdoc/auxiliary/empty.rs b/src/test/rustdoc/auxiliary/empty.rs new file mode 100644 index 000000000..d11c69f81 --- /dev/null +++ b/src/test/rustdoc/auxiliary/empty.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc/auxiliary/enum-primitive.rs b/src/test/rustdoc/auxiliary/enum-primitive.rs new file mode 100644 index 000000000..ed1da253a --- /dev/null +++ b/src/test/rustdoc/auxiliary/enum-primitive.rs @@ -0,0 +1,207 @@ +// Copyright (c) 2015 Anders Kaseorg <andersk@mit.edu> + +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// “Software”), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: + +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +//! This crate exports a macro `enum_from_primitive!` that wraps an +//! `enum` declaration and automatically adds an implementation of +//! `num::FromPrimitive` (reexported here), to allow conversion from +//! primitive integers to the enum. It therefore provides an +//! alternative to the built-in `#[derive(FromPrimitive)]`, which +//! requires the unstable `std::num::FromPrimitive` and is disabled in +//! Rust 1.0. +//! +//! # Example +//! +//! ``` +//! #[macro_use] extern crate enum_primitive; +//! extern crate num_traits; +//! use num_traits::FromPrimitive; +//! +//! enum_from_primitive! { +//! #[derive(Debug, PartialEq)] +//! enum FooBar { +//! Foo = 17, +//! Bar = 42, +//! Baz, +//! } +//! } +//! +//! fn main() { +//! assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo)); +//! assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar)); +//! assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz)); +//! assert_eq!(FooBar::from_i32(91), None); +//! } +//! ``` + +pub mod num_traits { + pub trait FromPrimitive: Sized { + fn from_i64(n: i64) -> Option<Self>; + fn from_u64(n: u64) -> Option<Self>; + } +} + +pub use std::option::Option; +pub use num_traits::FromPrimitive; + +/// Helper macro for internal use by `enum_from_primitive!`. +#[macro_export] +macro_rules! enum_from_primitive_impl_ty { + ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => { + #[allow(non_upper_case_globals, unused)] + fn $meth(n: $ty) -> $crate::Option<Self> { + $( if n == $name::$variant as $ty { + $crate::Option::Some($name::$variant) + } else )* { + $crate::Option::None + } + } + }; +} + +/// Helper macro for internal use by `enum_from_primitive!`. +#[macro_export] +#[macro_use(enum_from_primitive_impl_ty)] +macro_rules! enum_from_primitive_impl { + ($name:ident, $( $variant:ident )*) => { + impl $crate::FromPrimitive for $name { + enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* } + enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* } + } + }; +} + +/// Wrap this macro around an `enum` declaration to get an +/// automatically generated implementation of `num::FromPrimitive`. +#[macro_export] +#[macro_use(enum_from_primitive_impl)] +macro_rules! enum_from_primitive { + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )* + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )* + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),* + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),* + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*, + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*, + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+, + } + ) => { + $( #[$enum_attr] )* + enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+, + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )+ } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )* + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )* + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),* + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),* + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( #[$variant_attr:meta] )* $variant:ident ),+ + $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*, + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( #[$variant_attr] )* $variant ),+ + $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*, + } + enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } + }; + + ( + $( #[$enum_attr:meta] )* + pub enum $name:ident { + $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+, + } + ) => { + $( #[$enum_attr] )* + pub enum $name { + $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+, + } + enum_from_primitive_impl! { $name, $( $( $variant )+ )+ } + }; +} diff --git a/src/test/rustdoc/auxiliary/extern-impl-trait.rs b/src/test/rustdoc/auxiliary/extern-impl-trait.rs new file mode 100644 index 000000000..dbd543930 --- /dev/null +++ b/src/test/rustdoc/auxiliary/extern-impl-trait.rs @@ -0,0 +1,27 @@ +pub trait Foo { + type Associated; +} + +pub struct X; +pub struct Y; + + +impl Foo for X { + type Associated = (); +} + +impl Foo for Y { + type Associated = (); +} + +impl X { + pub fn returns_sized<'a>(&'a self) -> impl Foo<Associated=()> + 'a { + X + } +} + +impl Y { + pub fn returns_unsized<'a>(&'a self) -> Box<impl ?Sized + Foo<Associated=()> + 'a> { + Box::new(X) + } +} diff --git a/src/test/rustdoc/auxiliary/extern-links.rs b/src/test/rustdoc/auxiliary/extern-links.rs new file mode 100644 index 000000000..4a835673a --- /dev/null +++ b/src/test/rustdoc/auxiliary/extern-links.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/src/test/rustdoc/auxiliary/external-cross-doc.md b/src/test/rustdoc/auxiliary/external-cross-doc.md new file mode 100644 index 000000000..d3c853265 --- /dev/null +++ b/src/test/rustdoc/auxiliary/external-cross-doc.md @@ -0,0 +1,4 @@ +# Cross-crate imported docs + +This file is to make sure `#[doc = include_str!("file.md")]` works when you re-export an item with included +docs. diff --git a/src/test/rustdoc/auxiliary/external-cross.rs b/src/test/rustdoc/auxiliary/external-cross.rs new file mode 100644 index 000000000..5de63cdab --- /dev/null +++ b/src/test/rustdoc/auxiliary/external-cross.rs @@ -0,0 +1,3 @@ +#[deny(missing_docs)] +#[doc = include_str!("external-cross-doc.md")] +pub struct NeedMoreDocs; diff --git a/src/test/rustdoc/auxiliary/external-doc.md b/src/test/rustdoc/auxiliary/external-doc.md new file mode 100644 index 000000000..babde0a05 --- /dev/null +++ b/src/test/rustdoc/auxiliary/external-doc.md @@ -0,0 +1,3 @@ +# External Docs + +This file is here to test the `#[doc = include_str!("file")]` attribute. diff --git a/src/test/rustdoc/auxiliary/external-macro-src.rs b/src/test/rustdoc/auxiliary/external-macro-src.rs new file mode 100644 index 000000000..ce20ca5c9 --- /dev/null +++ b/src/test/rustdoc/auxiliary/external-macro-src.rs @@ -0,0 +1,15 @@ +// compile-flags:--remap-path-prefix={{src-base}}=/does-not-exist + +#![doc(html_root_url = "https://example.com/")] + +#[macro_export] +macro_rules! make_foo { + () => { + pub struct Foo; + impl Foo { + pub fn new() -> Foo { + Foo + } + } + } +} diff --git a/src/test/rustdoc/auxiliary/html_root.rs b/src/test/rustdoc/auxiliary/html_root.rs new file mode 100644 index 000000000..4eb0b700f --- /dev/null +++ b/src/test/rustdoc/auxiliary/html_root.rs @@ -0,0 +1,2 @@ +#![doc(html_root_url="https://example.com/html_root")] +pub fn foo() {} diff --git a/src/test/rustdoc/auxiliary/inline-default-methods.rs b/src/test/rustdoc/auxiliary/inline-default-methods.rs new file mode 100644 index 000000000..8a636f449 --- /dev/null +++ b/src/test/rustdoc/auxiliary/inline-default-methods.rs @@ -0,0 +1,6 @@ +// compile-flags: -Cmetadata=aux + +pub trait Foo { + fn bar(&self); + fn foo(&mut self) {} +} diff --git a/src/test/rustdoc/auxiliary/issue-100204-aux.rs b/src/test/rustdoc/auxiliary/issue-100204-aux.rs new file mode 100644 index 000000000..df1b59069 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-100204-aux.rs @@ -0,0 +1,13 @@ +#![crate_name="first"] + +pub mod prelude { + pub use crate::Bot; +} + +pub struct Bot; + +impl Bot { + pub fn new() -> Bot { + Bot + } +} diff --git a/src/test/rustdoc/auxiliary/issue-13698.rs b/src/test/rustdoc/auxiliary/issue-13698.rs new file mode 100644 index 000000000..a65ebfe36 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-13698.rs @@ -0,0 +1,8 @@ +// compile-flags: -Cmetadata=aux + +pub trait Foo { + #[doc(hidden)] + fn foo(&self) {} +} + +impl Foo for i32 {} diff --git a/src/test/rustdoc/auxiliary/issue-15318.rs b/src/test/rustdoc/auxiliary/issue-15318.rs new file mode 100644 index 000000000..695fa58ef --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-15318.rs @@ -0,0 +1,16 @@ +// no-prefer-dynamic +// compile-flags: -Cmetadata=aux +#![crate_type = "rlib"] +#![doc(html_root_url = "http://example.com/")] +#![feature(lang_items)] +#![no_std] + +#[lang = "eh_personality"] +fn foo() {} + +#[panic_handler] +fn bar(_: &core::panic::PanicInfo) -> ! { loop {} } + +/// dox +#[doc(primitive = "pointer")] +pub mod ptr {} diff --git a/src/test/rustdoc/auxiliary/issue-17476.rs b/src/test/rustdoc/auxiliary/issue-17476.rs new file mode 100644 index 000000000..80c915eb7 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-17476.rs @@ -0,0 +1,7 @@ +// compile-flags: -Cmetadata=aux + +#![doc(html_root_url = "http://example.com")] + +pub trait Foo { + fn foo(&self) {} +} diff --git a/src/test/rustdoc/auxiliary/issue-19190-3.rs b/src/test/rustdoc/auxiliary/issue-19190-3.rs new file mode 100644 index 000000000..8c526a89a --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-19190-3.rs @@ -0,0 +1,23 @@ +// compile-flags: -Cmetadata=aux + +use std::ops::Deref; + +pub struct Foo; + +impl Deref for Foo { + type Target = String; + fn deref(&self) -> &String { loop {} } +} + +pub struct Bar; +pub struct Baz; + +impl Baz { + pub fn baz(&self) {} + pub fn static_baz() {} +} + +impl Deref for Bar { + type Target = Baz; + fn deref(&self) -> &Baz { loop {} } +} diff --git a/src/test/rustdoc/auxiliary/issue-20646.rs b/src/test/rustdoc/auxiliary/issue-20646.rs new file mode 100644 index 000000000..8e16f2de0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-20646.rs @@ -0,0 +1,7 @@ +// compile-flags: -Cmetadata=aux + +pub trait Trait { + type Output; +} + +pub fn fun<T>(_: T) where T: Trait<Output=i32> {} diff --git a/src/test/rustdoc/auxiliary/issue-20727.rs b/src/test/rustdoc/auxiliary/issue-20727.rs new file mode 100644 index 000000000..7ffc1985b --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-20727.rs @@ -0,0 +1,30 @@ +// compile-flags: -Cmetadata=aux + +pub trait Deref { + type Target: ?Sized; + + fn deref<'a>(&'a self) -> &'a Self::Target; +} + +pub trait Add<RHS = Self> { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + + +pub trait Bar {} +pub trait Deref2 { + type Target: Bar; + + fn deref(&self) -> Self::Target; +} + +pub trait Index<Idx: ?Sized> { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +pub trait IndexMut<Idx: ?Sized>: Index<Idx> { + fn index_mut(&mut self, index: Idx) -> &mut Self::Output; +} diff --git a/src/test/rustdoc/auxiliary/issue-21092.rs b/src/test/rustdoc/auxiliary/issue-21092.rs new file mode 100644 index 000000000..51ab7de1c --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-21092.rs @@ -0,0 +1,12 @@ +// compile-flags: -Cmetadata=aux + +pub trait Foo { + type Bar; + fn foo(&self) {} +} + +pub struct Bar; + +impl Foo for Bar { + type Bar = i32; +} diff --git a/src/test/rustdoc/auxiliary/issue-21801.rs b/src/test/rustdoc/auxiliary/issue-21801.rs new file mode 100644 index 000000000..732612ff0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-21801.rs @@ -0,0 +1,9 @@ +// compile-flags: -Cmetadata=aux + +pub struct Foo; + +impl Foo { + pub fn new<F>(f: F) -> Foo where F: FnMut() -> i32 { + loop {} + } +} diff --git a/src/test/rustdoc/auxiliary/issue-22025.rs b/src/test/rustdoc/auxiliary/issue-22025.rs new file mode 100644 index 000000000..5346c0e92 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-22025.rs @@ -0,0 +1,10 @@ +// compile-flags: -Cmetadata=aux + +pub mod foo { + + pub trait Foo {} + pub struct Bar; + + impl Foo for Bar {} + +} diff --git a/src/test/rustdoc/auxiliary/issue-23207-1.rs b/src/test/rustdoc/auxiliary/issue-23207-1.rs new file mode 100644 index 000000000..8531d5f1a --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-23207-1.rs @@ -0,0 +1,3 @@ +pub mod fmt { + pub struct Error; +} diff --git a/src/test/rustdoc/auxiliary/issue-23207-2.rs b/src/test/rustdoc/auxiliary/issue-23207-2.rs new file mode 100644 index 000000000..b92b16653 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-23207-2.rs @@ -0,0 +1,5 @@ +extern crate issue_23207_1; + +pub mod fmt { + pub use issue_23207_1::fmt::Error; +} diff --git a/src/test/rustdoc/auxiliary/issue-26606-macro.rs b/src/test/rustdoc/auxiliary/issue-26606-macro.rs new file mode 100644 index 000000000..d60d32526 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-26606-macro.rs @@ -0,0 +1,4 @@ +#[macro_export] +macro_rules! make_item ( + ($name: ident) => (pub const $name: usize = 42;) +); diff --git a/src/test/rustdoc/auxiliary/issue-27362-aux.rs b/src/test/rustdoc/auxiliary/issue-27362-aux.rs new file mode 100644 index 000000000..077bdc33e --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-27362-aux.rs @@ -0,0 +1,10 @@ +// compile-flags: -Cmetadata=aux + +pub const fn foo() {} +pub const unsafe fn bar() {} + +pub struct Foo; + +impl Foo { + pub const unsafe fn baz() {} +} diff --git a/src/test/rustdoc/auxiliary/issue-28927-1.rs b/src/test/rustdoc/auxiliary/issue-28927-1.rs new file mode 100644 index 000000000..688c73428 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-28927-1.rs @@ -0,0 +1,4 @@ +mod detail { + pub extern crate issue_28927_2 as inner2; +} +pub use detail::inner2 as bar; diff --git a/src/test/rustdoc/auxiliary/issue-28927-2.rs b/src/test/rustdoc/auxiliary/issue-28927-2.rs new file mode 100644 index 000000000..7c0937fce --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-28927-2.rs @@ -0,0 +1 @@ +pub struct Baz; diff --git a/src/test/rustdoc/auxiliary/issue-29584.rs b/src/test/rustdoc/auxiliary/issue-29584.rs new file mode 100644 index 000000000..a9b8796c0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-29584.rs @@ -0,0 +1,10 @@ +// compile-flags: -Cmetadata=aux + +pub struct Foo; + +#[doc(hidden)] +mod bar { + trait Bar {} + + impl Bar for ::Foo {} +} diff --git a/src/test/rustdoc/auxiliary/issue-30109-1.rs b/src/test/rustdoc/auxiliary/issue-30109-1.rs new file mode 100644 index 000000000..ca05a6a90 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-30109-1.rs @@ -0,0 +1 @@ +pub struct Bar; diff --git a/src/test/rustdoc/auxiliary/issue-34274.rs b/src/test/rustdoc/auxiliary/issue-34274.rs new file mode 100644 index 000000000..c46660579 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-34274.rs @@ -0,0 +1,3 @@ +extern "C" { + pub fn extern_c_fn(); +} diff --git a/src/test/rustdoc/auxiliary/issue-36031.rs b/src/test/rustdoc/auxiliary/issue-36031.rs new file mode 100644 index 000000000..da688139e --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-36031.rs @@ -0,0 +1,9 @@ +pub trait Foo { + const FOO: usize; +} + +pub struct Bar; + +impl Bar { + pub const BAR: usize = 3; +} diff --git a/src/test/rustdoc/auxiliary/issue-40936.rs b/src/test/rustdoc/auxiliary/issue-40936.rs new file mode 100644 index 000000000..b921e5201 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-40936.rs @@ -0,0 +1,5 @@ +pub mod outermod { + pub mod innermod { + pub use super::*; + } +} diff --git a/src/test/rustdoc/auxiliary/issue-46727.rs b/src/test/rustdoc/auxiliary/issue-46727.rs new file mode 100644 index 000000000..30dccfa77 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-46727.rs @@ -0,0 +1,7 @@ +// compile-flags: -Cmetadata=aux + +pub trait Foo {} + +pub struct Bar<T> { x: T } + +impl<T> Foo for Bar<[T; 1 + 1 + 1]> {} diff --git a/src/test/rustdoc/auxiliary/issue-48414.rs b/src/test/rustdoc/auxiliary/issue-48414.rs new file mode 100644 index 000000000..f442ac722 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-48414.rs @@ -0,0 +1,5 @@ +/// Woah, this trait links to [OtherTrait](OtherTrait)! +pub trait SomeTrait {} + +/// Woah, this trait links to [SomeTrait](SomeTrait)! +pub trait OtherTrait {} diff --git a/src/test/rustdoc/auxiliary/issue-53689.rs b/src/test/rustdoc/auxiliary/issue-53689.rs new file mode 100644 index 000000000..5003c2c00 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-53689.rs @@ -0,0 +1 @@ +pub struct MyStruct; diff --git a/src/test/rustdoc/auxiliary/issue-57180.rs b/src/test/rustdoc/auxiliary/issue-57180.rs new file mode 100644 index 000000000..4e2f4b87c --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-57180.rs @@ -0,0 +1,16 @@ +// compile-flags: -Cmetadata=aux + +pub trait Trait { +} + +pub struct Struct<F> +{ + _p: ::std::marker::PhantomData<F>, +} + +impl<F: Fn() -> u32> +Trait for Struct<F> + where + F: Fn() -> u32, +{ +} diff --git a/src/test/rustdoc/auxiliary/issue-61592.rs b/src/test/rustdoc/auxiliary/issue-61592.rs new file mode 100644 index 000000000..6e16a4caf --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-61592.rs @@ -0,0 +1,4 @@ +#![crate_name = "foo"] + +pub trait FooTrait {} +pub struct FooStruct; diff --git a/src/test/rustdoc/auxiliary/issue-73061.rs b/src/test/rustdoc/auxiliary/issue-73061.rs new file mode 100644 index 000000000..e05a3bc6d --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-73061.rs @@ -0,0 +1,17 @@ +//edition:2018 + +#![feature(type_alias_impl_trait)] + +pub trait Foo { + type X: std::future::Future<Output = ()>; + fn x(&self) -> Self::X; +} + +pub struct F; + +impl Foo for F { + type X = impl std::future::Future<Output = ()>; + fn x(&self) -> Self::X { + async {} + } +} diff --git a/src/test/rustdoc/auxiliary/issue-85454.rs b/src/test/rustdoc/auxiliary/issue-85454.rs new file mode 100644 index 000000000..45664dfc3 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-85454.rs @@ -0,0 +1,17 @@ +// @has issue_85454/trait.FromResidual.html +// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }' +pub trait FromResidual<R = <Self as Try>::Residual> { + fn from_residual(residual: R) -> Self; +} + +pub trait Try: FromResidual { + type Output; + type Residual; + fn from_output(output: Self::Output) -> Self; + fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; +} + +pub enum ControlFlow<B, C = ()> { + Continue(C), + Break(B), +} diff --git a/src/test/rustdoc/auxiliary/issue-86620-1.rs b/src/test/rustdoc/auxiliary/issue-86620-1.rs new file mode 100644 index 000000000..f6debf6fb --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-86620-1.rs @@ -0,0 +1,11 @@ +#![crate_name = "issue_86620_1"] + +pub trait VZip { + fn vzip() -> usize; +} + +impl<T> VZip for T { + fn vzip() -> usize { + 0 + } +} diff --git a/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs new file mode 100644 index 000000000..4e55e7ed5 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs @@ -0,0 +1,17 @@ +/// When reexporting this function, make sure the anonymous lifetimes are not rendered. +/// +/// https://github.com/rust-lang/rust/issues/98697 +pub fn repro<F>() +where + F: Fn(&str), +{ + unimplemented!() +} + +pub struct Extra; + +pub trait MyTrait<T> { + fn run() {} +} + +impl MyTrait<&Extra> for Extra {} diff --git a/src/test/rustdoc/auxiliary/issue-99221-aux.rs b/src/test/rustdoc/auxiliary/issue-99221-aux.rs new file mode 100644 index 000000000..e061e42b2 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-99221-aux.rs @@ -0,0 +1,20 @@ +pub struct Option; +impl Option { + pub fn unwrap(self) {} +} + +mod macros { + use crate::Option; + /// [`Option::unwrap`] + #[macro_export] + macro_rules! print { + () => () + } +} + +mod structs { + use crate::Option; + /// [`Option::unwrap`] + pub struct Print; +} +pub use structs::Print; diff --git a/src/test/rustdoc/auxiliary/issue-99734-aux.rs b/src/test/rustdoc/auxiliary/issue-99734-aux.rs new file mode 100644 index 000000000..234d55efb --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-99734-aux.rs @@ -0,0 +1,11 @@ +pub struct Option; +impl Option { + pub fn unwrap(self) {} +} + +/// [`Option::unwrap`] +pub mod task {} + +extern "C" { + pub fn main() -> std::ffi::c_int; +} diff --git a/src/test/rustdoc/auxiliary/macro_pub_in_module.rs b/src/test/rustdoc/auxiliary/macro_pub_in_module.rs new file mode 100644 index 000000000..137b12386 --- /dev/null +++ b/src/test/rustdoc/auxiliary/macro_pub_in_module.rs @@ -0,0 +1,13 @@ +// edition:2018 + +#![feature(decl_macro)] +#![crate_name = "external_crate"] + +pub mod some_module { + /* == Make sure the logic is not affected by a re-export == */ + mod private { + pub macro external_macro() {} + } + + pub use private::external_macro; +} diff --git a/src/test/rustdoc/auxiliary/masked.rs b/src/test/rustdoc/auxiliary/masked.rs new file mode 100644 index 000000000..f289359e5 --- /dev/null +++ b/src/test/rustdoc/auxiliary/masked.rs @@ -0,0 +1,10 @@ +#[derive(Clone)] +pub struct MaskedStruct; + +pub trait MaskedTrait { + fn masked_method(); +} + +impl MaskedTrait for String { + fn masked_method() {} +} diff --git a/src/test/rustdoc/auxiliary/mod-stackoverflow.rs b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs new file mode 100644 index 000000000..e0b90f180 --- /dev/null +++ b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs @@ -0,0 +1,11 @@ +// compile-flags: -Cmetadata=aux + +pub mod tree { + pub use tree; +} + +pub mod tree2 { + pub mod prelude { + pub use tree2; + } +} diff --git a/src/test/rustdoc/auxiliary/no_html_root.rs b/src/test/rustdoc/auxiliary/no_html_root.rs new file mode 100644 index 000000000..c5c0bc606 --- /dev/null +++ b/src/test/rustdoc/auxiliary/no_html_root.rs @@ -0,0 +1 @@ +pub fn bar() {} diff --git a/src/test/rustdoc/auxiliary/normalize-assoc-item.rs b/src/test/rustdoc/auxiliary/normalize-assoc-item.rs new file mode 100644 index 000000000..fbd111c30 --- /dev/null +++ b/src/test/rustdoc/auxiliary/normalize-assoc-item.rs @@ -0,0 +1,12 @@ +#![crate_name = "inner"] +pub trait MyTrait { + type Y; +} + +impl MyTrait for u32 { + type Y = i32; +} + +pub fn foo() -> <u32 as MyTrait>::Y { + 0 +} diff --git a/src/test/rustdoc/auxiliary/primitive-doc.rs b/src/test/rustdoc/auxiliary/primitive-doc.rs new file mode 100644 index 000000000..e8da852a5 --- /dev/null +++ b/src/test/rustdoc/auxiliary/primitive-doc.rs @@ -0,0 +1,9 @@ +// compile-flags: --crate-type lib --edition 2018 + +#![feature(no_core)] +#![no_core] + +#[doc(primitive = "usize")] +/// This is the built-in type `usize`. +mod usize { +} diff --git a/src/test/rustdoc/auxiliary/primitive-reexport.rs b/src/test/rustdoc/auxiliary/primitive-reexport.rs new file mode 100644 index 000000000..b2e9fa43b --- /dev/null +++ b/src/test/rustdoc/auxiliary/primitive-reexport.rs @@ -0,0 +1,8 @@ +// compile-flags: --emit metadata --crate-type lib --edition 2018 + +#![crate_name = "foo"] + +pub mod bar { + pub use bool; + pub use char as my_char; +} diff --git a/src/test/rustdoc/auxiliary/pub-extern-crate.rs b/src/test/rustdoc/auxiliary/pub-extern-crate.rs new file mode 100644 index 000000000..8c89c8d6c --- /dev/null +++ b/src/test/rustdoc/auxiliary/pub-extern-crate.rs @@ -0,0 +1,2 @@ +#![crate_name = "inner"] +pub struct SomeStruct; diff --git a/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs new file mode 100644 index 000000000..7934e0733 --- /dev/null +++ b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs @@ -0,0 +1,21 @@ +#![crate_name="macros"] + +#[macro_export] +macro_rules! foo { + () => {}; +} + +#[macro_export] +macro_rules! bar { + () => {}; +} + +#[macro_export] +macro_rules! baz { + () => {}; +} + +#[macro_export] +macro_rules! quux { + () => {}; +} diff --git a/src/test/rustdoc/auxiliary/real_gimli.rs b/src/test/rustdoc/auxiliary/real_gimli.rs new file mode 100644 index 000000000..80d5c4ba8 --- /dev/null +++ b/src/test/rustdoc/auxiliary/real_gimli.rs @@ -0,0 +1,13 @@ +// aux-build:realcore.rs + +#![crate_name = "real_gimli"] +#![feature(staged_api, extremely_unstable)] +#![unstable(feature = "rustc_private", issue = "none")] + +extern crate realcore; + +#[unstable(feature = "rustc_private", issue = "none")] +pub struct EndianSlice; + +#[unstable(feature = "rustc_private", issue = "none")] +impl realcore::Deref for EndianSlice {} diff --git a/src/test/rustdoc/auxiliary/realcore.rs b/src/test/rustdoc/auxiliary/realcore.rs new file mode 100644 index 000000000..e0a906df0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/realcore.rs @@ -0,0 +1,15 @@ +#![crate_name = "realcore"] +#![feature(staged_api)] +#![unstable(feature = "extremely_unstable", issue = "none")] + +#[unstable(feature = "extremely_unstable_foo", issue = "none")] +pub struct Foo {} + +#[unstable(feature = "extremely_unstable_foo", issue = "none")] +pub trait Join {} + +#[unstable(feature = "extremely_unstable_foo", issue = "none")] +impl Join for Foo {} + +#[stable(feature = "faked_deref", since = "1.47.0")] +pub trait Deref {} diff --git a/src/test/rustdoc/auxiliary/reexp-stripped.rs b/src/test/rustdoc/auxiliary/reexp-stripped.rs new file mode 100644 index 000000000..ccc3dc11f --- /dev/null +++ b/src/test/rustdoc/auxiliary/reexp-stripped.rs @@ -0,0 +1,11 @@ +pub use private::Quz; +pub use hidden::Bar; + +mod private { + pub struct Quz; +} + +#[doc(hidden)] +pub mod hidden { + pub struct Bar; +} diff --git a/src/test/rustdoc/auxiliary/reexport-check.rs b/src/test/rustdoc/auxiliary/reexport-check.rs new file mode 100644 index 000000000..672ccb1cf --- /dev/null +++ b/src/test/rustdoc/auxiliary/reexport-check.rs @@ -0,0 +1,2 @@ +/// Docs in original +pub struct S; diff --git a/src/test/rustdoc/auxiliary/reexports.rs b/src/test/rustdoc/auxiliary/reexports.rs new file mode 100644 index 000000000..4336993a3 --- /dev/null +++ b/src/test/rustdoc/auxiliary/reexports.rs @@ -0,0 +1,66 @@ +#![feature(decl_macro)] + +pub macro addr_of($place:expr) { + &raw const $place +} + +pub macro addr_of_crate($place:expr) { + &raw const $place +} + +pub macro addr_of_super($place:expr) { + &raw const $place +} + +pub macro addr_of_self($place:expr) { + &raw const $place +} + +pub macro addr_of_local($place:expr) { + &raw const $place +} + +pub struct Foo; +pub struct FooCrate; +pub struct FooSuper; +pub struct FooSelf; +pub struct FooLocal; + +pub enum Bar { Foo, } +pub enum BarCrate { Foo, } +pub enum BarSuper { Foo, } +pub enum BarSelf { Foo, } +pub enum BarLocal { Foo, } + +pub fn foo() {} +pub fn foo_crate() {} +pub fn foo_super() {} +pub fn foo_self() {} +pub fn foo_local() {} + +pub type Type = i32; +pub type TypeCrate = i32; +pub type TypeSuper = i32; +pub type TypeSelf = i32; +pub type TypeLocal = i32; + +pub union Union { + a: i8, + b: i8, +} +pub union UnionCrate { + a: i8, + b: i8, +} +pub union UnionSuper { + a: i8, + b: i8, +} +pub union UnionSelf { + a: i8, + b: i8, +} +pub union UnionLocal { + a: i8, + b: i8, +} diff --git a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs new file mode 100644 index 000000000..032db3b25 --- /dev/null +++ b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs @@ -0,0 +1,23 @@ +#![feature(auto_traits)] + +pub mod bar { + use std::marker; + + pub auto trait Bar {} + + pub trait Foo { + fn foo(&self) {} + } + + impl Foo { + pub fn test<T: Bar>(&self) {} + } + + pub struct TypeId; + + impl TypeId { + pub fn of<T: Bar + ?Sized>() -> TypeId { + panic!() + } + } +} diff --git a/src/test/rustdoc/auxiliary/rustdoc-extern-default-method.rs b/src/test/rustdoc/auxiliary/rustdoc-extern-default-method.rs new file mode 100644 index 000000000..12934238a --- /dev/null +++ b/src/test/rustdoc/auxiliary/rustdoc-extern-default-method.rs @@ -0,0 +1,11 @@ +#![crate_type="lib"] + +pub trait Trait { + fn provided(&self) {} +} + +pub struct Struct; + +impl Trait for Struct { + fn provided(&self) {} +} diff --git a/src/test/rustdoc/auxiliary/rustdoc-extern-method.rs b/src/test/rustdoc/auxiliary/rustdoc-extern-method.rs new file mode 100644 index 000000000..e493048d9 --- /dev/null +++ b/src/test/rustdoc/auxiliary/rustdoc-extern-method.rs @@ -0,0 +1,7 @@ +#![crate_type="lib"] +#![feature(unboxed_closures)] + +pub trait Foo { + extern "rust-call" fn foo(&self, _: ()) -> i32; + extern "rust-call" fn foo_(&self, _: ()) -> i32 { 0 } +} diff --git a/src/test/rustdoc/auxiliary/rustdoc-ffi.rs b/src/test/rustdoc/auxiliary/rustdoc-ffi.rs new file mode 100644 index 000000000..b74d190b5 --- /dev/null +++ b/src/test/rustdoc/auxiliary/rustdoc-ffi.rs @@ -0,0 +1,6 @@ +#![crate_type="lib"] + +extern "C" { + // @has lib/fn.foreigner.html //pre 'pub unsafe fn foreigner(cold_as_ice: u32)' + pub fn foreigner(cold_as_ice: u32); +} diff --git a/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs new file mode 100644 index 000000000..135987fc0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs @@ -0,0 +1,3 @@ +#![feature(auto_traits)] + +pub auto trait AnAutoTrait {} diff --git a/src/test/rustdoc/auxiliary/source-code-bar.rs b/src/test/rustdoc/auxiliary/source-code-bar.rs new file mode 100644 index 000000000..8700d688e --- /dev/null +++ b/src/test/rustdoc/auxiliary/source-code-bar.rs @@ -0,0 +1,17 @@ +//! just some other file. :) + +use crate::Foo; + +pub struct Bar { + field: Foo, +} + +pub struct Bar2 { + field: crate::Foo, +} + +pub mod sub { + pub trait Trait { + fn tadam() {} + } +} diff --git a/src/test/rustdoc/auxiliary/source_code.rs b/src/test/rustdoc/auxiliary/source_code.rs new file mode 100644 index 000000000..72a5c1a0a --- /dev/null +++ b/src/test/rustdoc/auxiliary/source_code.rs @@ -0,0 +1 @@ +pub struct SourceCode; diff --git a/src/test/rustdoc/auxiliary/src-links-external.rs b/src/test/rustdoc/auxiliary/src-links-external.rs new file mode 100644 index 000000000..4a835673a --- /dev/null +++ b/src/test/rustdoc/auxiliary/src-links-external.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/src/test/rustdoc/auxiliary/trait-alias-mention.rs b/src/test/rustdoc/auxiliary/trait-alias-mention.rs new file mode 100644 index 000000000..6df06c87a --- /dev/null +++ b/src/test/rustdoc/auxiliary/trait-alias-mention.rs @@ -0,0 +1,3 @@ +#![feature(trait_alias)] + +pub trait SomeAlias = std::fmt::Debug + std::marker::Copy; diff --git a/src/test/rustdoc/auxiliary/trait-visibility.rs b/src/test/rustdoc/auxiliary/trait-visibility.rs new file mode 100644 index 000000000..1e8d0b8e0 --- /dev/null +++ b/src/test/rustdoc/auxiliary/trait-visibility.rs @@ -0,0 +1,3 @@ +pub trait Bar { + fn foo(); +} diff --git a/src/test/rustdoc/auxiliary/unit-return.rs b/src/test/rustdoc/auxiliary/unit-return.rs new file mode 100644 index 000000000..7b9986162 --- /dev/null +++ b/src/test/rustdoc/auxiliary/unit-return.rs @@ -0,0 +1,3 @@ +pub fn f2<F: FnMut(u32) + Clone>(f: F) {} + +pub fn f3<F: FnMut(u64) -> () + Clone>(f: F) {} diff --git a/src/test/rustdoc/auxiliary/unstable-trait.rs b/src/test/rustdoc/auxiliary/unstable-trait.rs new file mode 100644 index 000000000..6f06a6e26 --- /dev/null +++ b/src/test/rustdoc/auxiliary/unstable-trait.rs @@ -0,0 +1,26 @@ +#![feature(staged_api)] +#![stable(feature = "private_general", since = "1.0.0")] + +#[unstable(feature = "private_trait", issue = "none")] +pub trait Bar {} + +#[stable(feature = "private_general", since = "1.0.0")] +pub struct Foo { + // nothing +} + +impl Foo { + #[stable(feature = "private_general", since = "1.0.0")] + pub fn stable_impl() {} +} + +impl Foo { + #[unstable(feature = "private_trait", issue = "none")] + pub fn bar() {} + + #[stable(feature = "private_general", since = "1.0.0")] + pub fn bar2() {} +} + +#[stable(feature = "private_general", since = "1.0.0")] +impl Bar for Foo {} diff --git a/src/test/rustdoc/auxiliary/variant-struct.rs b/src/test/rustdoc/auxiliary/variant-struct.rs new file mode 100644 index 000000000..0f3d2e5f1 --- /dev/null +++ b/src/test/rustdoc/auxiliary/variant-struct.rs @@ -0,0 +1,5 @@ +pub enum Foo { + Bar { + qux: (), + } +} diff --git a/src/test/rustdoc/bad-codeblock-syntax.rs b/src/test/rustdoc/bad-codeblock-syntax.rs new file mode 100644 index 000000000..9ec089fd7 --- /dev/null +++ b/src/test/rustdoc/bad-codeblock-syntax.rs @@ -0,0 +1,44 @@ +#![allow(rustdoc::invalid_rust_codeblocks)] + +// @has bad_codeblock_syntax/fn.foo.html +// @has - '//*[@class="docblock"]' '\_' +/// ``` +/// \_ +/// ``` +pub fn foo() {} + +// @has bad_codeblock_syntax/fn.bar.html +// @has - '//*[@class="docblock"]' '`baz::foobar`' +/// ``` +/// `baz::foobar` +/// ``` +pub fn bar() {} + +// @has bad_codeblock_syntax/fn.quux.html +// @has - '//*[@class="docblock"]' '\_' +/// ```rust +/// \_ +/// ``` +pub fn quux() {} + +// @has bad_codeblock_syntax/fn.ok.html +// @has - '//*[@class="docblock"]' '\_' +/// ```text +/// \_ +/// ``` +pub fn ok() {} + +// @has bad_codeblock_syntax/fn.escape.html +// @has - '//*[@class="docblock"]' '\_ <script>alert("not valid Rust");</script>' +/// ``` +/// \_ +/// <script>alert("not valid Rust");</script> +/// ``` +pub fn escape() {} + +// @has bad_codeblock_syntax/fn.unterminated.html +// @has - '//*[@class="docblock"]' '"unterminated' +/// ``` +/// "unterminated +/// ``` +pub fn unterminated() {} diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs new file mode 100644 index 000000000..676d656da --- /dev/null +++ b/src/test/rustdoc/blanket-reexport-item.rs @@ -0,0 +1,8 @@ +#![crate_name = "foo"] + +// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T' +pub struct S2 {} +mod m { + pub struct S {} +} +pub use m::*; diff --git a/src/test/rustdoc/cap-lints.rs b/src/test/rustdoc/cap-lints.rs new file mode 100644 index 000000000..08a353396 --- /dev/null +++ b/src/test/rustdoc/cap-lints.rs @@ -0,0 +1,9 @@ +// This should fail a normal compile due to non_camel_case_types, +// It should pass a doc-compile as it only needs to type-check and +// therefore should not concern itself with the lints. +#[deny(warnings)] + +// @has cap_lints/struct.Foo.html //* 'Foo' +pub struct Foo { + field: i32, +} diff --git a/src/test/rustdoc/cfg-doctest.rs b/src/test/rustdoc/cfg-doctest.rs new file mode 100644 index 000000000..6a9d26a4b --- /dev/null +++ b/src/test/rustdoc/cfg-doctest.rs @@ -0,0 +1,6 @@ +// @!has cfg_doctest/struct.SomeStruct.html +// @!has cfg_doctest/index.html '//a/@href' 'struct.SomeStruct.html' + +/// Sneaky, this isn't actually part of docs. +#[cfg(doctest)] +pub struct SomeStruct; diff --git a/src/test/rustdoc/check-source-code-urls-to-def-std.rs b/src/test/rustdoc/check-source-code-urls-to-def-std.rs new file mode 100644 index 000000000..3396b234a --- /dev/null +++ b/src/test/rustdoc/check-source-code-urls-to-def-std.rs @@ -0,0 +1,42 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +// @has 'src/foo/check-source-code-urls-to-def-std.rs.html' + +fn babar() {} + +// @has - '//a[@href="{{channel}}/std/primitive.u32.html"]' 'u32' +// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str' +// @has - '//a[@href="{{channel}}/std/primitive.bool.html"]' 'bool' +// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#7"]' 'babar' +pub fn foo(a: u32, b: &str, c: String) { + let x = 12; + let y: bool = true; + babar(); +} + +macro_rules! yolo { () => {}} + +fn bar(a: i32) {} + +macro_rules! bar { + ($a:ident) => { bar($a) } +} + +macro_rules! data { + ($x:expr) => { $x * 2 } +} + +pub fn another_foo() { + // This is known limitation: if the macro doesn't generate anything, the visitor + // can't find any item or anything that could tell us that it comes from expansion. + // @!has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#19"]' 'yolo!' + yolo!(); + // @has - '//a[@href="{{channel}}/std/macro.eprintln.html"]' 'eprintln!' + eprintln!(); + // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#27-29"]' 'data!' + let x = data!(4); + // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def-std.rs.html#23-25"]' 'bar!' + bar!(x); +} diff --git a/src/test/rustdoc/check-source-code-urls-to-def.rs b/src/test/rustdoc/check-source-code-urls-to-def.rs new file mode 100644 index 000000000..ec44e1bc6 --- /dev/null +++ b/src/test/rustdoc/check-source-code-urls-to-def.rs @@ -0,0 +1,69 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition +// aux-build:source_code.rs +// build-aux-docs + +#![feature(rustdoc_internals)] + +#![crate_name = "foo"] + +extern crate source_code; + +// @has 'src/foo/check-source-code-urls-to-def.rs.html' + +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#1-17"]' 'bar' +#[path = "auxiliary/source-code-bar.rs"] +pub mod bar; + +// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5"]' 4 +use bar::Bar; +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13"]' 'self' +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait' +use bar::sub::{self, Trait}; + +pub struct Foo; + +impl Foo { + fn hello(&self) {} +} + +fn babar() {} + +// @has - '//a/@href' '/struct.String.html' +// @has - '//a/@href' '/primitive.u32.html' +// @has - '//a/@href' '/primitive.str.html' +// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#23"]' 5 +// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode' +pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) { + let x = 12; + let y: Foo = Foo; + let z: Bar = bar::Bar { field: Foo }; + babar(); + // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#26"]' 'hello' + y.hello(); +} + +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait' +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait' +pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {} + +pub trait AnotherTrait {} +pub trait WhyNot {} + +// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#49"]' 'AnotherTrait' +// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#50"]' 'WhyNot' +pub fn foo3<T, V>(t: &T, v: &V) +where + T: AnotherTrait, + V: WhyNot +{} + +pub trait AnotherTrait2 {} + +// @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#60"]' 'AnotherTrait2' +pub fn foo4() { + let x: Vec<AnotherTrait2> = Vec::new(); +} + +// @has - '//a[@href="../../foo/primitive.bool.html"]' 'bool' +#[doc(primitive = "bool")] +mod whatever {} diff --git a/src/test/rustdoc/check-styled-link.rs b/src/test/rustdoc/check-styled-link.rs new file mode 100644 index 000000000..ed4a5ea21 --- /dev/null +++ b/src/test/rustdoc/check-styled-link.rs @@ -0,0 +1,8 @@ +#![crate_name = "foo"] + +pub struct Foo; + +// @has foo/struct.Bar.html '//a[@href="struct.Foo.html"]' 'Foo' + +/// Code-styled reference to [`Foo`]. +pub struct Bar; diff --git a/src/test/rustdoc/check.rs b/src/test/rustdoc/check.rs new file mode 100644 index 000000000..1fb4b35dd --- /dev/null +++ b/src/test/rustdoc/check.rs @@ -0,0 +1,5 @@ +// compile-flags: -Z unstable-options --check + +// @!has check/fn.foo.html +// @!has check/index.html +pub fn foo() {} diff --git a/src/test/rustdoc/codeblock-title.rs b/src/test/rustdoc/codeblock-title.rs new file mode 100644 index 000000000..140c5b3a6 --- /dev/null +++ b/src/test/rustdoc/codeblock-title.rs @@ -0,0 +1,25 @@ +#![crate_name = "foo"] + +// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]' "ⓘ" +// @has foo/fn.bar.html '//*[@class="tooltip ignore"]' "ⓘ" +// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]' "ⓘ" +// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ" + +/// foo +/// +/// ```compile_fail +/// foo(); +/// ``` +/// +/// ```ignore (tidy) +/// goo(); +/// ``` +/// +/// ```should_panic +/// hoo(); +/// ``` +/// +/// ```edition2018 +/// let x = 0; +/// ``` +pub fn bar() -> usize { 2 } diff --git a/src/test/rustdoc/comment-in-doctest.rs b/src/test/rustdoc/comment-in-doctest.rs new file mode 100644 index 000000000..5691d1735 --- /dev/null +++ b/src/test/rustdoc/comment-in-doctest.rs @@ -0,0 +1,20 @@ +// compile-flags:--test + +// comments, both doc comments and regular ones, used to trick rustdoc's doctest parser into +// thinking that everything after it was part of the regular program. combined with the librustc_ast +// parser loop failing to detect the manual main function, it would wrap everything in `fn main`, +// which would cause the doctest to fail as the "extern crate" declaration was no longer valid. +// oddly enough, it would pass in 2018 if a crate was in the extern prelude. see +// https://github.com/rust-lang/rust/issues/56727 + +//! ``` +//! // crate: proc-macro-test +//! //! this is a test +//! +//! // used to pull in proc-macro specific items +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! +//! # fn main() {} +//! ``` diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs new file mode 100644 index 000000000..8455dd9ef --- /dev/null +++ b/src/test/rustdoc/const-display.rs @@ -0,0 +1,86 @@ +#![crate_name = "foo"] + +#![unstable(feature = "humans", + reason = "who ever let humans program computers, we're apparently really bad at it", + issue = "none")] + +#![feature(foo, foo2)] +#![feature(staged_api)] + +// @has 'foo/fn.foo.html' '//pre' 'pub fn foo() -> u32' +// @has - '//span[@class="since"]' '1.0.0 (const: unstable)' +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +pub const fn foo() -> u32 { 42 } + +// @has 'foo/fn.foo_unsafe.html' '//pre' 'pub unsafe fn foo_unsafe() -> u32' +// @has - '//span[@class="since"]' '1.0.0 (const: unstable)' +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +pub const unsafe fn foo_unsafe() -> u32 { 42 } + +// @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32' +// @!has - '//span[@class="since"]' +#[unstable(feature = "humans", issue = "none")] +pub const fn foo2() -> u32 { 42 } + +// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32' +// @has - //span '1.0.0 (const: 1.0.0)' +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +pub const fn bar2() -> u32 { 42 } + + +// @has 'foo/fn.foo2_gated.html' '//pre' 'pub const unsafe fn foo2_gated() -> u32' +// @!has - '//span[@class="since"]' +#[unstable(feature = "foo2", issue = "none")] +pub const unsafe fn foo2_gated() -> u32 { 42 } + +// @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32' +// @has - '//span[@class="since"]' '1.0.0 (const: 1.0.0)' +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +pub const unsafe fn bar2_gated() -> u32 { 42 } + +// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' +// @!has - '//span[@class="since"]' +pub const unsafe fn bar_not_gated() -> u32 { 42 } + +pub struct Foo; + +impl Foo { + // @has 'foo/struct.Foo.html' '//*[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32' + // @has - '//span[@class="since"]' '1.0.0 (const: unstable)' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature="foo", issue = "none")] + pub const fn gated() -> u32 { 42 } + + // @has 'foo/struct.Foo.html' '//*[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32' + // @has - '//span[@class="since"]' '1.0.0 (const: unstable)' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature="foo", issue = "none")] + pub const unsafe fn gated_unsafe() -> u32 { 42 } + + // @has 'foo/struct.Foo.html' '//*[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32' + // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const2", since = "1.2.0")] + pub const fn stable_impl() -> u32 { 42 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Bar; + +impl Bar { + // Do not show non-const stabilities that are the same as the enclosing item. + // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.2.0$' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const2", since = "1.2.0")] + pub const fn stable_impl() -> u32 { 42 } + + // Show const-stability even for unstable functions. + // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$' + #[unstable(feature = "foo2", issue = "none")] + #[rustc_const_stable(feature = "const3", since = "1.3.0")] + pub const fn const_stable_unstable() -> u32 { 42 } +} diff --git a/src/test/rustdoc/const-doc.rs b/src/test/rustdoc/const-doc.rs new file mode 100644 index 000000000..74ab4af61 --- /dev/null +++ b/src/test/rustdoc/const-doc.rs @@ -0,0 +1,19 @@ +use std::marker::PhantomData; + +pub struct Foo<'a> { + f: PhantomData<&'a u32>, +} + +pub struct ContentType { + pub ttype: Foo<'static>, + pub subtype: Foo<'static>, + pub params: Option<Foo<'static>>, +} + +impl ContentType { + // @has const_doc/struct.ContentType.html + // @has - '//*[@id="associatedconstant.Any"]' 'const Any: ContentType' + pub const Any: ContentType = ContentType { ttype: Foo { f: PhantomData, }, + subtype: Foo { f: PhantomData, }, + params: None, }; +} diff --git a/src/test/rustdoc/const-evalutation-ice.rs b/src/test/rustdoc/const-evalutation-ice.rs new file mode 100644 index 000000000..68c7f9c56 --- /dev/null +++ b/src/test/rustdoc/const-evalutation-ice.rs @@ -0,0 +1,10 @@ +// Just check we don't get an ICE for `N`. + +use std::cell::Cell; +use std::mem; + +pub struct S { + s: Cell<usize> +} + +pub const N: usize = 0 - (mem::size_of::<S>() != 4) as usize; diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs new file mode 100644 index 000000000..28eba849a --- /dev/null +++ b/src/test/rustdoc/const-fn.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +// @has foo/fn.bar.html +// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> ' +/// foo +pub const fn bar() -> usize { + 2 +} + +// @has foo/struct.Foo.html +// @has - '//*[@class="method has-srclink"]' 'const fn new()' +pub struct Foo(usize); + +impl Foo { + pub const fn new() -> Foo { Foo(0) } +} diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs new file mode 100644 index 000000000..591139523 --- /dev/null +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -0,0 +1,17 @@ +#![crate_name = "foo"] + +use std::ops::Add; + +// @has foo/struct.Simd.html '//pre[@class="rust struct"]' 'pub struct Simd<T, const WIDTH: usize>' +pub struct Simd<T, const WIDTH: usize> { + inner: T, +} + +// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16>> for Simd<u8, 16>' +impl Add for Simd<u8, 16> { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { inner: 0 } + } +} diff --git a/src/test/rustdoc/const-generics/auxiliary/extern_crate.rs b/src/test/rustdoc/const-generics/auxiliary/extern_crate.rs new file mode 100644 index 000000000..55b632a48 --- /dev/null +++ b/src/test/rustdoc/const-generics/auxiliary/extern_crate.rs @@ -0,0 +1,16 @@ +// edition:2018 +pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]> { + [[0; N]; N].iter().copied() +} + +pub struct ExternTy<const N: usize> { + pub inner: [u8; N], +} + +pub type TyAlias<const N: usize> = ExternTy<N>; + +pub trait WTrait<const N: usize, const M: usize> { + fn hey<const P: usize>() -> usize { + N + M + P + } +} diff --git a/src/test/rustdoc/const-generics/const-generic-defaults.rs b/src/test/rustdoc/const-generics/const-generic-defaults.rs new file mode 100644 index 000000000..2693d9b59 --- /dev/null +++ b/src/test/rustdoc/const-generics/const-generic-defaults.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \ +// 'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(_);' +pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T); diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs new file mode 100644 index 000000000..4279de91f --- /dev/null +++ b/src/test/rustdoc/const-generics/const-generic-slice.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] + +pub trait Array { + type Item; +} + +// @has foo/trait.Array.html +// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]' +impl<T, const N: usize> Array for [T; N] { + type Item = T; +} diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs new file mode 100644 index 000000000..352a8e646 --- /dev/null +++ b/src/test/rustdoc/const-generics/const-generics-docs.rs @@ -0,0 +1,128 @@ +// edition:2018 +// aux-build: extern_crate.rs +#![crate_name = "foo"] + +extern crate extern_crate; +// @has foo/fn.extern_fn.html '//pre[@class="rust fn"]' \ +// 'pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]>' +pub use extern_crate::extern_fn; +// @has foo/struct.ExternTy.html '//pre[@class="rust struct"]' \ +// 'pub struct ExternTy<const N: usize> {' +pub use extern_crate::ExternTy; +// @has foo/type.TyAlias.html '//pre[@class="rust typedef"]' \ +// 'type TyAlias<const N: usize> = ExternTy<N>;' +pub use extern_crate::TyAlias; +// @has foo/trait.WTrait.html '//pre[@class="rust trait"]' \ +// 'pub trait WTrait<const N: usize, const M: usize>' +// @has - '//*[@class="rust trait"]' 'fn hey<const P: usize>() -> usize' +pub use extern_crate::WTrait; + +// @has foo/trait.Trait.html '//pre[@class="rust trait"]' \ +// 'pub trait Trait<const N: usize>' +// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<1> for u8' +// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<2> for u8' +// @has - '//*[@id="impl-Trait%3C{1%20+%202}%3E-for-u8"]//h3[@class="code-header in-band"]' 'impl Trait<{1 + 2}> for u8' +// @has - '//*[@id="impl-Trait%3CN%3E-for-%5Bu8%3B%20N%5D"]//h3[@class="code-header in-band"]' \ +// 'impl<const N: usize> Trait<N> for [u8; N]' +pub trait Trait<const N: usize> {} +impl Trait<1> for u8 {} +impl Trait<2> for u8 {} +impl Trait<{1 + 2}> for u8 {} +impl<const N: usize> Trait<N> for [u8; N] {} + +// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \ +// 'pub struct Foo<const N: usize> where u8: Trait<N>' +pub struct Foo<const N: usize> where u8: Trait<N>; +// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)' +pub struct Bar<T, const N: usize>([T; N]); + +// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>' +impl<const M: usize> Foo<M> where u8: Trait<M> { + // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize' + pub const FOO_ASSOC: usize = M + 13; + + // @has - '//*[@id="method.hey"]' 'pub fn hey<const N: usize>(&self) -> Bar<u8, N>' + pub fn hey<const N: usize>(&self) -> Bar<u8, N> { + Bar([0; N]) + } +} + +// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>' +impl<const M: usize> Bar<u8, M> { + // @has - '//*[@id="method.hey"]' \ + // 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>' + pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N> { + Foo + } +} + +// @has foo/fn.test.html '//pre[@class="rust fn"]' \ +// 'pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N>' +pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> { + 2u8 +} + +// @has foo/fn.a_sink.html '//pre[@class="rust fn"]' \ +// 'pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N>' +pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> { + v +} + +// @has foo/fn.b_sink.html '//pre[@class="rust fn"]' \ +// 'pub async fn b_sink<const N: usize>(_: impl Trait<N>)' +pub async fn b_sink<const N: usize>(_: impl Trait<N>) {} + +// @has foo/fn.concrete.html '//pre[@class="rust fn"]' \ +// 'pub fn concrete() -> [u8; 22]' +pub fn concrete() -> [u8; 3 + std::mem::size_of::<u64>() << 1] { + Default::default() +} + +// @has foo/type.Faz.html '//pre[@class="rust typedef"]' \ +// 'type Faz<const N: usize> = [u8; N];' +pub type Faz<const N: usize> = [u8; N]; +// @has foo/type.Fiz.html '//pre[@class="rust typedef"]' \ +// 'type Fiz<const N: usize> = [[u8; N]; 48];' +pub type Fiz<const N: usize> = [[u8; N]; 3 << 4]; + +macro_rules! define_me { + ($t:tt<$q:tt>) => { + pub struct $t<const $q: usize>([u8; $q]); + } +} + +// @has foo/struct.Foz.html '//pre[@class="rust struct"]' \ +// 'pub struct Foz<const N: usize>(_);' +define_me!(Foz<N>); + +trait Q { + const ASSOC: usize; +} + +impl<const N: usize> Q for [u8; N] { + const ASSOC: usize = N; +} + +// @has foo/fn.q_user.html '//pre[@class="rust fn"]' \ +// 'pub fn q_user() -> [u8; 13]' +pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] { + [0; <[u8; 13] as Q>::ASSOC] +} + +// @has foo/union.Union.html '//pre[@class="rust union"]' \ +// 'pub union Union<const N: usize>' +pub union Union<const N: usize> { + // @has - //pre "pub arr: [u8; N]" + pub arr: [u8; N], + // @has - //pre "pub another_arr: [(); N]" + pub another_arr: [(); N], +} + +// @has foo/enum.Enum.html '//pre[@class="rust enum"]' \ +// 'pub enum Enum<const N: usize>' +pub enum Enum<const N: usize> { + // @has - //pre "Variant([u8; N])" + Variant([u8; N]), + // @has - //pre "EmptyVariant" + EmptyVariant, +} diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs new file mode 100644 index 000000000..f1181d54a --- /dev/null +++ b/src/test/rustdoc/const-generics/const-impl.rs @@ -0,0 +1,37 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params)] +#![crate_name = "foo"] + +#[derive(PartialEq, Eq)] +pub enum Order { + Sorted, + Unsorted, +} + +// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>' +// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>' +// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>' +pub struct VSet<T, const ORDER: Order> { + inner: Vec<T>, +} + +// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3ASorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>' +impl<T> VSet<T, { Order::Sorted }> { + pub fn new() -> Self { + Self { inner: Vec::new() } + } +} + +// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3AUnsorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>' +impl<T> VSet<T, { Order::Unsorted }> { + pub fn new() -> Self { + Self { inner: Vec::new() } + } +} + +pub struct Escape<const S: &'static str>; + +// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr#%22%3Cscript%3Ealert(%22Escape%22)%3B%3C/script%3E%22#%3E"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>' +impl Escape<r#"<script>alert("Escape");</script>"#> { + pub fn f() {} +} diff --git a/src/test/rustdoc/const-generics/generic_const_exprs.rs b/src/test/rustdoc/const-generics/generic_const_exprs.rs new file mode 100644 index 000000000..215ee228e --- /dev/null +++ b/src/test/rustdoc/const-generics/generic_const_exprs.rs @@ -0,0 +1,7 @@ +#![crate_name = "foo"] +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] +// make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647 +// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \ +// 'pub struct Ice<const N: usize>;' +pub struct Ice<const N: usize> where [(); N + 1]:; diff --git a/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs b/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs new file mode 100644 index 000000000..4eac8e31e --- /dev/null +++ b/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs @@ -0,0 +1,18 @@ +#![crate_name = "foo"] +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +// Checking if `Send` is implemented for `Hasher` requires us to evaluate a `ConstEquate` predicate, +// which previously caused an ICE. + +pub struct Hasher<T> { + cv_stack: T, +} + +unsafe impl<T: Default> Send for Hasher<T> {} + +// @has foo/struct.Foo.html +// @has - '//h3[@class="code-header in-band"]' 'impl Send for Foo' +pub struct Foo { + hasher: Hasher<[u8; 3]>, +} diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs new file mode 100644 index 000000000..ebda5b194 --- /dev/null +++ b/src/test/rustdoc/const-generics/type-alias.rs @@ -0,0 +1,4 @@ +#![crate_name = "foo"] + +// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];' +pub type CellIndex<const D: usize> = [i64; D]; diff --git a/src/test/rustdoc/const-underscore.rs b/src/test/rustdoc/const-underscore.rs new file mode 100644 index 000000000..0d4809409 --- /dev/null +++ b/src/test/rustdoc/const-underscore.rs @@ -0,0 +1,7 @@ +// compile-flags: --document-private-items + +// @!has const_underscore/constant._.html +const _: () = { + #[no_mangle] + extern "C" fn implementation_detail() {} +}; diff --git a/src/test/rustdoc/const-value-display.rs b/src/test/rustdoc/const-value-display.rs new file mode 100644 index 000000000..5b2f3c48d --- /dev/null +++ b/src/test/rustdoc/const-value-display.rs @@ -0,0 +1,9 @@ +#![crate_name = "foo"] + +// @has 'foo/constant.HOUR_IN_SECONDS.html' +// @has - '//*[@class="docblock item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64' +pub const HOUR_IN_SECONDS: u64 = 60 * 60; + +// @has 'foo/constant.NEGATIVE.html' +// @has - '//*[@class="docblock item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64' +pub const NEGATIVE: i64 = -60 * 60; diff --git a/src/test/rustdoc/const.rs b/src/test/rustdoc/const.rs new file mode 100644 index 000000000..587ad4db4 --- /dev/null +++ b/src/test/rustdoc/const.rs @@ -0,0 +1,10 @@ +#![crate_type="lib"] + +pub struct Foo; + +impl Foo { + // @has const/struct.Foo.html '//*[@id="method.new"]//h4[@class="code-header"]' 'const unsafe fn new' + pub const unsafe fn new() -> Foo { + Foo + } +} diff --git a/src/test/rustdoc/constructor-imports.rs b/src/test/rustdoc/constructor-imports.rs new file mode 100644 index 000000000..26795c274 --- /dev/null +++ b/src/test/rustdoc/constructor-imports.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +pub mod a { + pub struct Foo; + pub enum Bar { + Baz, + } +} + +// @count 'foo/index.html' '//*[code="pub use a::Foo;"]' 1 +#[doc(no_inline)] +pub use a::Foo; +// @count 'foo/index.html' '//*[code="pub use a::Bar::Baz;"]' 1 +#[doc(no_inline)] +pub use a::Bar::Baz; diff --git a/src/test/rustdoc/crate-version-escape.rs b/src/test/rustdoc/crate-version-escape.rs new file mode 100644 index 000000000..8413709f1 --- /dev/null +++ b/src/test/rustdoc/crate-version-escape.rs @@ -0,0 +1,5 @@ +// compile-flags: --crate-version=<script>alert("hi")</script> -Z unstable-options + +#![crate_name = "foo"] + +// @has 'foo/index.html' '//li[@class="version"]' 'Version <script>alert("hi")</script>' diff --git a/src/test/rustdoc/crate-version.rs b/src/test/rustdoc/crate-version.rs new file mode 100644 index 000000000..2592c9853 --- /dev/null +++ b/src/test/rustdoc/crate-version.rs @@ -0,0 +1,3 @@ +// compile-flags: --crate-version=1.3.37 + +// @has 'crate_version/index.html' '//*[@class="version"]' 'Version 1.3.37' diff --git a/src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs b/src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs new file mode 100644 index 000000000..d02bc4fe7 --- /dev/null +++ b/src/test/rustdoc/cross-crate-hidden-assoc-trait-items.rs @@ -0,0 +1,23 @@ +// Regression test for issue #95717 +// Hide cross-crate `#[doc(hidden)]` associated items in trait impls. + +#![crate_name = "dependent"] +// edition:2021 +// aux-crate:dependency=cross-crate-hidden-assoc-trait-items.rs + +// The trait `Tr` contains 2 hidden and 2 visisible associated items. +// Instead of checking for the absence of the hidden items, check for the presence of the +// visible items instead and assert that there are *exactly two* associated items +// (by counting the number of `section`s). This is more robust and future-proof. + +// @has dependent/struct.Ty.html +// @has - '//*[@id="associatedtype.VisibleAssoc"]' 'type VisibleAssoc = ()' +// @has - '//*[@id="associatedconstant.VISIBLE_ASSOC"]' 'const VISIBLE_ASSOC: ()' +// @count - '//*[@class="impl-items"]/section' 2 + +// @has dependent/trait.Tr.html +// @has - '//*[@id="associatedtype.VisibleAssoc-1"]' 'type VisibleAssoc = ()' +// @has - '//*[@id="associatedconstant.VISIBLE_ASSOC-1"]' 'const VISIBLE_ASSOC: ()' +// @count - '//*[@class="impl-items"]/section' 2 + +pub use dependency::{Tr, Ty}; diff --git a/src/test/rustdoc/cross-crate-hidden-impl-parameter.rs b/src/test/rustdoc/cross-crate-hidden-impl-parameter.rs new file mode 100644 index 000000000..eb2ced2f7 --- /dev/null +++ b/src/test/rustdoc/cross-crate-hidden-impl-parameter.rs @@ -0,0 +1,35 @@ +// Issue #86448: test for cross-crate `doc(hidden)` +#![crate_name = "foo"] + +// aux-build:cross-crate-hidden-impl-parameter.rs +extern crate cross_crate_hidden_impl_parameter; + +pub use ::cross_crate_hidden_impl_parameter::{HiddenType, HiddenTrait}; // OK, not re-exported + +pub enum MyLibType {} + +// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CHiddenType%3E"]' 'impl From<HiddenType> for MyLibType' +impl From<HiddenType> for MyLibType { + fn from(it: HiddenType) -> MyLibType { + match it {} + } +} + +pub struct T<T>(T); + +// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CT%3CT%3CT%3CT%3CHiddenType%3E%3E%3E%3E%3E"]' 'impl From<T<T<T<T<HiddenType>>>>> for MyLibType' +impl From<T<T<T<T<HiddenType>>>>> for MyLibType { + fn from(it: T<T<T<T<HiddenType>>>>) -> MyLibType { + todo!() + } +} + +// @!has foo/enum.MyLibType.html '//*[@id="impl-HiddenTrait"]' 'impl HiddenTrait for MyLibType' +impl HiddenTrait for MyLibType {} + +// @!has foo/struct.T.html '//*[@id="impl-From%3CMyLibType%3E"]' 'impl From<MyLibType> for T<T<T<T<HiddenType>>>>' +impl From<MyLibType> for T<T<T<T<HiddenType>>>> { + fn from(it: MyLibType) -> T<T<T<T<HiddenType>>>> { + match it {} + } +} diff --git a/src/test/rustdoc/cross-crate-links.rs b/src/test/rustdoc/cross-crate-links.rs new file mode 100644 index 000000000..7c736a4cc --- /dev/null +++ b/src/test/rustdoc/cross-crate-links.rs @@ -0,0 +1,59 @@ +// aux-build:all-item-types.rs +// build-aux-docs + +#![crate_name = "foo"] + +#[macro_use] +extern crate all_item_types; + +// @has 'foo/index.html' '//a[@href="../all_item_types/foo_mod/index.html"]' 'foo_mod' +#[doc(no_inline)] +pub use all_item_types::foo_mod; + +// @has 'foo/index.html' '//a[@href="../all_item_types/fn.foo_ffn.html"]' 'foo_ffn' +#[doc(no_inline)] +pub use all_item_types::foo_ffn; + +// @has 'foo/index.html' '//a[@href="../all_item_types/static.FOO_FSTATIC.html"]' 'FOO_FSTATIC' +#[doc(no_inline)] +pub use all_item_types::FOO_FSTATIC; + +// @has 'foo/index.html' '//a[@href="../all_item_types/foreigntype.FooFType.html"]' 'FooFType' +#[doc(no_inline)] +pub use all_item_types::FooFType; + +// @has 'foo/index.html' '//a[@href="../all_item_types/fn.foo_fn.html"]' 'foo_fn' +#[doc(no_inline)] +pub use all_item_types::foo_fn; + +// @has 'foo/index.html' '//a[@href="../all_item_types/trait.FooTrait.html"]' 'FooTrait' +#[doc(no_inline)] +pub use all_item_types::FooTrait; + +// @has 'foo/index.html' '//a[@href="../all_item_types/struct.FooStruct.html"]' 'FooStruct' +#[doc(no_inline)] +pub use all_item_types::FooStruct; + +// @has 'foo/index.html' '//a[@href="../all_item_types/enum.FooEnum.html"]' 'FooEnum' +#[doc(no_inline)] +pub use all_item_types::FooEnum; + +// @has 'foo/index.html' '//a[@href="../all_item_types/union.FooUnion.html"]' 'FooUnion' +#[doc(no_inline)] +pub use all_item_types::FooUnion; + +// @has 'foo/index.html' '//a[@href="../all_item_types/type.FooType.html"]' 'FooType' +#[doc(no_inline)] +pub use all_item_types::FooType; + +// @has 'foo/index.html' '//a[@href="../all_item_types/static.FOO_STATIC.html"]' 'FOO_STATIC' +#[doc(no_inline)] +pub use all_item_types::FOO_STATIC; + +// @has 'foo/index.html' '//a[@href="../all_item_types/constant.FOO_CONSTANT.html"]' 'FOO_CONSTANT' +#[doc(no_inline)] +pub use all_item_types::FOO_CONSTANT; + +// @has 'foo/index.html' '//a[@href="../all_item_types/macro.foo_macro.html"]' 'foo_macro' +#[doc(no_inline)] +pub use all_item_types::foo_macro; diff --git a/src/test/rustdoc/cross-crate-primitive-doc.rs b/src/test/rustdoc/cross-crate-primitive-doc.rs new file mode 100644 index 000000000..4ba296ee0 --- /dev/null +++ b/src/test/rustdoc/cross-crate-primitive-doc.rs @@ -0,0 +1,13 @@ +// aux-build:primitive-doc.rs +// compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options +// only-linux + +#![feature(no_core)] +#![no_core] + +extern crate primitive_doc; + +// @has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'usize' +// @has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'link' +/// [link](usize) +pub fn foo() -> usize { 0 } diff --git a/src/test/rustdoc/decl-trailing-whitespace.declaration.html b/src/test/rustdoc/decl-trailing-whitespace.declaration.html new file mode 100644 index 000000000..e60caaeff --- /dev/null +++ b/src/test/rustdoc/decl-trailing-whitespace.declaration.html @@ -0,0 +1,7 @@ +<code>pub trait Write { + fn <a href="#tymethod.poll_write" class="fnname">poll_write</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; +<span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fnname">poll_flush</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; +<span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fnname">poll_close</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; + + fn <a href="#method.poll_write_vectored" class="fnname">poll_write_vectored</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>> { ... } +}</code> diff --git a/src/test/rustdoc/decl-trailing-whitespace.rs b/src/test/rustdoc/decl-trailing-whitespace.rs new file mode 100644 index 000000000..46a2307ab --- /dev/null +++ b/src/test/rustdoc/decl-trailing-whitespace.rs @@ -0,0 +1,30 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98803>. + +#![crate_name = "foo"] + +pub struct Error; + +// @has 'foo/trait.Write.html' + +pub trait Write { + // @snapshot 'declaration' - '//*[@class="docblock item-decl"]//code' + fn poll_write( + self: Option<String>, + cx: &mut Option<String>, + buf: &mut [usize] + ) -> Option<Result<usize, Error>>; + fn poll_flush( + self: Option<String>, + cx: &mut Option<String> + ) -> Option<Result<(), Error>>; + fn poll_close( + self: Option<String>, + cx: &mut Option<String>, + ) -> Option<Result<(), Error>>; + + fn poll_write_vectored( + self: Option<String>, + cx: &mut Option<String>, + bufs: &[usize] + ) -> Option<Result<usize, Error>> {} +} diff --git a/src/test/rustdoc/decl_macro.rs b/src/test/rustdoc/decl_macro.rs new file mode 100644 index 000000000..94ade31b5 --- /dev/null +++ b/src/test/rustdoc/decl_macro.rs @@ -0,0 +1,56 @@ +// compile-flags: --document-private-items + +#![feature(decl_macro)] + +// @has decl_macro/macro.my_macro.html //pre 'pub macro my_macro() {' +// @has - //pre '...' +// @has - //pre '}' +pub macro my_macro() { + +} + +// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok:tt)*) {' +// @has - //pre '...' +// @has - //pre '}' +pub macro my_macro_2($($tok:tt)*) { + +} + +// @has decl_macro/macro.my_macro_multi.html //pre 'pub macro my_macro_multi {' +// @has - //pre '(_) => { ... },' +// @has - //pre '($foo:ident . $bar:expr) => { ... },' +// @has - //pre '($($foo:literal),+) => { ... },' +// @has - //pre '}' +pub macro my_macro_multi { + (_) => { + + }, + ($foo:ident . $bar:expr) => { + + }, + ($($foo:literal),+) => { + + } +} + +// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo:expr) {' +// @has - //pre '...' +// @has - //pre '}' +pub macro by_example_single { + ($foo:expr) => {} +} + +mod a { + mod b { + // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {' + pub(in super) macro by_example_vis { + ($foo:expr) => {} + } + mod c { + // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {' + pub(in a) macro by_example_vis_named { + ($foo:expr) => {} + } + } + } +} diff --git a/src/test/rustdoc/decl_macro_priv.rs b/src/test/rustdoc/decl_macro_priv.rs new file mode 100644 index 000000000..4e1279e34 --- /dev/null +++ b/src/test/rustdoc/decl_macro_priv.rs @@ -0,0 +1,14 @@ +// compile-flags: --document-private-items + +#![feature(decl_macro)] + +// @has decl_macro_priv/macro.crate_macro.html //pre 'pub(crate) macro crate_macro() {' +// @has - //pre '...' +// @has - //pre '}' +pub(crate) macro crate_macro() {} + +// @has decl_macro_priv/macro.priv_macro.html //pre 'macro priv_macro() {' +// @!has - //pre 'pub macro priv_macro() {' +// @has - //pre '...' +// @has - //pre '}' +macro priv_macro() {} diff --git a/src/test/rustdoc/deep-structures.rs b/src/test/rustdoc/deep-structures.rs new file mode 100644 index 000000000..cd3b0d3ec --- /dev/null +++ b/src/test/rustdoc/deep-structures.rs @@ -0,0 +1,104 @@ +// This test verifies that we do not hit recursion limit trying to prove auto-trait bounds for +// reasonably deep structures. + +#![crate_type="rlib"] + +pub struct A01(A02); +pub struct A02(A03); +pub struct A03(A04); +pub struct A04(A05); +pub struct A05(A06); +pub struct A06(A07); +pub struct A07(A08); +pub struct A08(A09); +pub struct A09(A10); +pub struct A10(A11); +pub struct A11(A12); +pub struct A12(A13); +pub struct A13(A14); +pub struct A14(A15); +pub struct A15(A16); +pub struct A16(A17); +pub struct A17(A18); +pub struct A18(A19); +pub struct A19(A20); +pub struct A20(A21); +pub struct A21(A22); +pub struct A22(A23); +pub struct A23(A24); +pub struct A24(A25); +pub struct A25(A26); +pub struct A26(A27); +pub struct A27(A28); +pub struct A28(A29); +pub struct A29(A30); +pub struct A30(A31); +pub struct A31(A32); +pub struct A32(A33); +pub struct A33(A34); +pub struct A34(A35); +pub struct A35(A36); +pub struct A36(A37); +pub struct A37(A38); +pub struct A38(A39); +pub struct A39(A40); +pub struct A40(A41); +pub struct A41(A42); +pub struct A42(A43); +pub struct A43(A44); +pub struct A44(A45); +pub struct A45(A46); +pub struct A46(A47); +pub struct A47(A48); +pub struct A48(A49); +pub struct A49(A50); +pub struct A50(A51); +pub struct A51(A52); +pub struct A52(A53); +pub struct A53(A54); +pub struct A54(A55); +pub struct A55(A56); +pub struct A56(A57); +pub struct A57(A58); +pub struct A58(A59); +pub struct A59(A60); +pub struct A60(A61); +pub struct A61(A62); +pub struct A62(A63); +pub struct A63(A64); +pub struct A64(A65); +pub struct A65(A66); +pub struct A66(A67); +pub struct A67(A68); +pub struct A68(A69); +pub struct A69(A70); +pub struct A70(A71); +pub struct A71(A72); +pub struct A72(A73); +pub struct A73(A74); +pub struct A74(A75); +pub struct A75(A76); +pub struct A76(A77); +pub struct A77(A78); +pub struct A78(A79); +pub struct A79(A80); +pub struct A80(A81); +pub struct A81(A82); +pub struct A82(A83); +pub struct A83(A84); +pub struct A84(A85); +pub struct A85(A86); +pub struct A86(A87); +pub struct A87(A88); +pub struct A88(A89); +pub struct A89(A90); +pub struct A90(A91); +pub struct A91(A92); +pub struct A92(A93); +pub struct A93(A94); +pub struct A94(A95); +pub struct A95(A96); +pub struct A96(A97); +pub struct A97(A98); +pub struct A98(A99); +pub struct A99; diff --git a/src/test/rustdoc/default-impl.rs b/src/test/rustdoc/default-impl.rs new file mode 100644 index 000000000..f11b3b29b --- /dev/null +++ b/src/test/rustdoc/default-impl.rs @@ -0,0 +1,9 @@ +// aux-build:rustdoc-default-impl.rs +// ignore-cross-compile + +extern crate rustdoc_default_impl as foo; + +pub use foo::bar; + +pub fn wut<T: bar::Bar>() { +} diff --git a/src/test/rustdoc/default-theme.rs b/src/test/rustdoc/default-theme.rs new file mode 100644 index 000000000..ecb8f0b3b --- /dev/null +++ b/src/test/rustdoc/default-theme.rs @@ -0,0 +1,7 @@ +// compile-flags: --default-theme ayu + +// @has default_theme/index.html +// @has - '//script[@id="default-settings"]/@data-theme' 'ayu' +// @has - '//script[@id="default-settings"]/@data-use_system_theme' 'false' + +pub fn whatever() {} diff --git a/src/test/rustdoc/default-trait-method-link.rs b/src/test/rustdoc/default-trait-method-link.rs new file mode 100644 index 000000000..7bcd2a3c1 --- /dev/null +++ b/src/test/rustdoc/default-trait-method-link.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +// @has foo/trait.Foo.html '//a[@href="trait.Foo.html#tymethod.req"]' 'req' +// @has foo/trait.Foo.html '//a[@href="trait.Foo.html#method.prov"]' 'prov' + +/// Always make sure to implement [`req`], but you don't have to implement [`prov`]. +/// +/// [`req`]: Foo::req +/// [`prov`]: Foo::prov +pub trait Foo { + /// Required + fn req(); + /// Provided + fn prov() {} +} diff --git a/src/test/rustdoc/default-trait-method.rs b/src/test/rustdoc/default-trait-method.rs new file mode 100644 index 000000000..6d0e339c4 --- /dev/null +++ b/src/test/rustdoc/default-trait-method.rs @@ -0,0 +1,26 @@ +#![feature(min_specialization)] + +// @has default_trait_method/trait.Item.html +// @has - '//*[@id="tymethod.foo"]' 'fn foo()' +// @!has - '//*[@id="tymethod.foo"]' 'default fn foo()' +// @has - '//*[@id="tymethod.bar"]' 'fn bar()' +// @!has - '//*[@id="tymethod.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub trait Item { + fn foo(); + fn bar(); + fn baz() {} +} + +// @has default_trait_method/struct.Foo.html +// @has - '//*[@id="method.foo"]' 'default fn foo()' +// @has - '//*[@id="method.bar"]' 'fn bar()' +// @!has - '//*[@id="method.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub struct Foo; +impl Item for Foo { + default fn foo() {} + fn bar() {} +} diff --git a/src/test/rustdoc/deprecated-future-staged-api.rs b/src/test/rustdoc/deprecated-future-staged-api.rs new file mode 100644 index 000000000..2670e7f5d --- /dev/null +++ b/src/test/rustdoc/deprecated-future-staged-api.rs @@ -0,0 +1,18 @@ +#![feature(staged_api)] +#![stable(feature = "deprecated-future-staged-api", since = "1.0.0")] + +// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \ +// 'Deprecation planned' +// @has deprecated_future_staged_api/struct.S1.html '//*[@class="stab deprecated"]' \ +// 'Deprecating in 99.99.99: effectively never' +#[deprecated(since = "99.99.99", note = "effectively never")] +#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")] +pub struct S1; + +// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \ +// 'Deprecation planned' +// @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \ +// 'Deprecating in a future Rust version: literally never' +#[deprecated(since = "TBD", note = "literally never")] +#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")] +pub struct S2; diff --git a/src/test/rustdoc/deprecated-future.rs b/src/test/rustdoc/deprecated-future.rs new file mode 100644 index 000000000..7db8cc602 --- /dev/null +++ b/src/test/rustdoc/deprecated-future.rs @@ -0,0 +1,6 @@ +// @has deprecated_future/index.html '//*[@class="stab deprecated"]' \ +// 'Deprecated' +// @has deprecated_future/struct.S.html '//*[@class="stab deprecated"]' \ +// 'Deprecated since 99.99.99: effectively never' +#[deprecated(since = "99.99.99", note = "effectively never")] +pub struct S; diff --git a/src/test/rustdoc/deprecated-impls.rs b/src/test/rustdoc/deprecated-impls.rs new file mode 100644 index 000000000..efd250ce9 --- /dev/null +++ b/src/test/rustdoc/deprecated-impls.rs @@ -0,0 +1,118 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo0.html +pub struct Foo0; + +impl Foo0 { + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.1: fn_with_doc' + // @has - 'fn_with_doc short' + // @has - 'fn_with_doc full' + /// fn_with_doc short + /// + /// fn_with_doc full + #[deprecated(since = "1.0.1", note = "fn_with_doc")] + pub fn fn_with_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.2: fn_without_doc' + #[deprecated(since = "1.0.2", note = "fn_without_doc")] + pub fn fn_without_doc() {} +} + +pub trait Bar { + /// fn_empty_with_doc short + /// + /// fn_empty_with_doc full + #[deprecated(since = "1.0.3", note = "fn_empty_with_doc")] + fn fn_empty_with_doc(); + + #[deprecated(since = "1.0.4", note = "fn_empty_without_doc")] + fn fn_empty_without_doc(); + + /// fn_def_with_doc short + /// + /// fn_def_with_doc full + #[deprecated(since = "1.0.5", note = "fn_def_with_doc")] + fn fn_def_with_doc() {} + + #[deprecated(since = "1.0.6", note = "fn_def_without_doc")] + fn fn_def_without_doc() {} + + /// fn_def_def_with_doc short + /// + /// fn_def_def_with_doc full + #[deprecated(since = "1.0.7", note = "fn_def_def_with_doc")] + fn fn_def_def_with_doc() {} + + #[deprecated(since = "1.0.8", note = "fn_def_def_without_doc")] + fn fn_def_def_without_doc() {} +} + +// @has foo/struct.Foo1.html +pub struct Foo1; + +impl Bar for Foo1 { + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.3: fn_empty_with_doc' + // @has - 'fn_empty_with_doc_impl short' + // @has - 'fn_empty_with_doc_impl full' + /// fn_empty_with_doc_impl short + /// + /// fn_empty_with_doc_impl full + fn fn_empty_with_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.4: fn_empty_without_doc' + fn fn_empty_without_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc' + // @has - 'fn_def_with_doc_impl short' + // @has - 'fn_def_with_doc_impl full' + /// fn_def_with_doc_impl short + /// + /// fn_def_with_doc_impl full + fn fn_def_with_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc' + fn fn_def_without_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.7: fn_def_def_with_doc' + // @has - 'fn_def_def_with_doc short' + // @!has - 'fn_def_def_with_doc full' + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.8: fn_def_def_without_doc' +} + +// @has foo/struct.Foo2.html +pub struct Foo2; + +impl Bar for Foo2 { + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.3: fn_empty_with_doc' + // @has - 'fn_empty_with_doc short' + // @!has - 'fn_empty_with_doc full' + fn fn_empty_with_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.4: fn_empty_without_doc' + // @has - 'fn_empty_without_doc_impl short' + // @has - 'fn_empty_without_doc_impl full' + /// fn_empty_without_doc_impl short + /// + /// fn_empty_without_doc_impl full + fn fn_empty_without_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc' + // @has - 'fn_def_with_doc short' + // @!has - 'fn_def_with_doc full' + fn fn_def_with_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc' + // @has - 'fn_def_without_doc_impl short' + // @has - 'fn_def_without_doc_impl full' + /// fn_def_without_doc_impl short + /// + /// fn_def_without_doc_impl full + fn fn_def_without_doc() {} + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.7: fn_def_def_with_doc' + // @has - 'fn_def_def_with_doc short' + // @!has - 'fn_def_def_with_doc full' + + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.8: fn_def_def_without_doc' +} diff --git a/src/test/rustdoc/deprecated.rs b/src/test/rustdoc/deprecated.rs new file mode 100644 index 000000000..b3178da98 --- /dev/null +++ b/src/test/rustdoc/deprecated.rs @@ -0,0 +1,33 @@ +// @has deprecated/index.html '//*[@class="item-left module-item"]/span[@class="stab deprecated"]' \ +// 'Deprecated' +// @has - '//*[@class="item-right docblock-short"]' 'Deprecated docs' + +// @has deprecated/struct.S.html '//*[@class="stab deprecated"]' \ +// 'Deprecated since 1.0.0: text' +/// Deprecated docs +#[deprecated(since = "1.0.0", note = "text")] +pub struct S; + +// @matches deprecated/index.html '//*[@class="item-right docblock-short"]' '^Docs' +/// Docs +pub struct T; + +// @matches deprecated/struct.U.html '//*[@class="stab deprecated"]' \ +// 'Deprecated since 1.0.0$' +#[deprecated(since = "1.0.0")] +pub struct U; + +// @matches deprecated/struct.V.html '//*[@class="stab deprecated"]' \ +// 'Deprecated: text$' +#[deprecated(note = "text")] +pub struct V; + +// @matches deprecated/struct.W.html '//*[@class="stab deprecated"]' \ +// 'Deprecated$' +#[deprecated] +pub struct W; + +// @matches deprecated/struct.X.html '//*[@class="stab deprecated"]' \ +// 'Deprecated: shorthand reason$' +#[deprecated = "shorthand reason"] +pub struct X; diff --git a/src/test/rustdoc/deref-const-fn.rs b/src/test/rustdoc/deref-const-fn.rs new file mode 100644 index 000000000..8ecca6d12 --- /dev/null +++ b/src/test/rustdoc/deref-const-fn.rs @@ -0,0 +1,38 @@ +// This test ensures that the const methods from Deref aren't shown as const. +// For more information, see https://github.com/rust-lang/rust/issues/90855. + +#![crate_name = "foo"] + +#![feature(staged_api)] + +#![stable(feature = "rust1", since = "1.0.0")] + +// @has 'foo/struct.Bar.html' +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Bar; + +impl Bar { + // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize' + // @has - '//*[@id="method.len"]//span[@class="since"]' 'const: 1.0.0' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.0.0")] + pub const fn len(&self) -> usize { 0 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Foo { + value: Bar, +} + +// @has 'foo/struct.Foo.html' +// @has - '//*[@id="method.len"]' 'pub fn len(&self) -> usize' +// @!has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0' +// @!has - '//*[@id="method.len"]//span[@class="since"]' '(const: 1.0.0)' +#[stable(feature = "rust1", since = "1.0.0")] +impl std::ops::Deref for Foo { + type Target = Bar; + + fn deref(&self) -> &Self::Target { + &self.value + } +} diff --git a/src/test/rustdoc/deref-mut-methods.rs b/src/test/rustdoc/deref-mut-methods.rs new file mode 100644 index 000000000..fdf843422 --- /dev/null +++ b/src/test/rustdoc/deref-mut-methods.rs @@ -0,0 +1,29 @@ +#![crate_name = "foo"] + +use std::ops; + +pub struct Foo; + +impl Foo { + pub fn foo(&mut self) {} +} + +// @has foo/struct.Bar.html +// @has - '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.foo"]' 'foo' +pub struct Bar { + foo: Foo, +} + +impl ops::Deref for Bar { + type Target = Foo; + + fn deref(&self) -> &Foo { + &self.foo + } +} + +impl ops::DerefMut for Bar { + fn deref_mut(&mut self) -> &mut Foo { + &mut self.foo + } +} diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs new file mode 100644 index 000000000..746df9c80 --- /dev/null +++ b/src/test/rustdoc/deref-recursive-pathbuf.rs @@ -0,0 +1,25 @@ +// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing +// levels and across multiple crates. +// For `Deref` on non-foreign types, look at `deref-recursive.rs`. + +// @has 'foo/struct.Foo.html' +// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>' +// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)' +// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>' +// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)' +// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>' +// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path' +// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>' +// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists' + +#![crate_name = "foo"] + +use std::ops::Deref; +use std::path::PathBuf; + +pub struct Foo(PathBuf); + +impl Deref for Foo { + type Target = PathBuf; + fn deref(&self) -> &PathBuf { &self.0 } +} diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs new file mode 100644 index 000000000..d5f8473f2 --- /dev/null +++ b/src/test/rustdoc/deref-recursive.rs @@ -0,0 +1,41 @@ +// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing +// levels if needed. +// For `Deref` on foreign types, look at `deref-recursive-pathbuf.rs`. + +// @has 'foo/struct.Foo.html' +// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>' +// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)' +// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>' +// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)' +// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.bar"]' 'bar' +// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.baz"]' 'baz' + +#![crate_name = "foo"] + +use std::ops::Deref; + +pub struct Foo(Bar); +pub struct Bar(Baz); +pub struct Baz; + +impl Deref for Foo { + type Target = Bar; + fn deref(&self) -> &Bar { &self.0 } +} + +impl Deref for Bar { + type Target = Baz; + fn deref(&self) -> &Baz { &self.0 } +} + +impl Bar { + /// This appears under `Foo` methods + pub fn bar(&self) {} +} + +impl Baz { + /// This should also appear in `Foo` methods when recursing + pub fn baz(&self) {} +} diff --git a/src/test/rustdoc/deref-slice-core.rs b/src/test/rustdoc/deref-slice-core.rs new file mode 100644 index 000000000..cccf273a8 --- /dev/null +++ b/src/test/rustdoc/deref-slice-core.rs @@ -0,0 +1,22 @@ +// https://github.com/rust-lang/rust/issues/95325 +// +// Show methods reachable from Deref of primitive. +#![no_std] + +use core::ops::Deref; + +// @has 'deref_slice_core/struct.MyArray.html' +// @has '-' '//*[@id="deref-methods-%5BT%5D"]' 'Methods from Deref<Target = [T]>' +// @has '-' '//*[@class="impl-items"]//*[@id="method.len"]' 'pub fn len(&self)' + +pub struct MyArray<T> { + array: [T; 10], +} + +impl<T> Deref for MyArray<T> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.array + } +} diff --git a/src/test/rustdoc/deref-typedef.rs b/src/test/rustdoc/deref-typedef.rs new file mode 100644 index 000000000..28f977e31 --- /dev/null +++ b/src/test/rustdoc/deref-typedef.rs @@ -0,0 +1,46 @@ +#![crate_name = "foo"] + +// @has 'foo/struct.Bar.html' +// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>' +// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)' +// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)' +// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)' +// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)' +// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_a"]' 'foo_a' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_b"]' 'foo_b' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_c"]' 'foo_c' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_j"]' 'foo_j' + +pub struct FooA; +pub type FooB = FooA; +pub type FooC = FooB; +pub type FooD = FooC; +pub type FooE = FooD; +pub type FooF = FooE; +pub type FooG = FooF; +pub type FooH = FooG; +pub type FooI = FooH; +pub type FooJ = FooI; + +impl FooA { + pub fn foo_a(&self) {} +} + +impl FooB { + pub fn foo_b(&self) {} +} + +impl FooC { + pub fn foo_c(&self) {} +} + +impl FooJ { + pub fn foo_j(&self) {} +} + +pub struct Bar; +impl std::ops::Deref for Bar { + type Target = FooJ; + fn deref(&self) -> &Self::Target { unimplemented!() } +} diff --git a/src/test/rustdoc/description.rs b/src/test/rustdoc/description.rs new file mode 100644 index 000000000..05ec42822 --- /dev/null +++ b/src/test/rustdoc/description.rs @@ -0,0 +1,24 @@ +#![crate_name = "foo"] +//! # Description test crate +//! +//! This is the contents of the test crate docstring. +//! It should not show up in the description. + +// @has 'foo/index.html' '//meta[@name="description"]/@content' \ +// 'Description test crate' +// @!has - '//meta[@name="description"]/@content' 'should not show up' + +// @has 'foo/foo_mod/index.html' '//meta[@name="description"]/@content' \ +// 'First paragraph description.' +// @!has - '//meta[@name="description"]/@content' 'Second paragraph' +/// First paragraph description. +/// +/// Second paragraph should not show up. +pub mod foo_mod { + pub struct __Thing {} +} + +// @has 'foo/fn.foo_fn.html' '//meta[@name="description"]/@content' \ +// 'Only paragraph.' +/// Only paragraph. +pub fn foo_fn() {} diff --git a/src/test/rustdoc/description_default.rs b/src/test/rustdoc/description_default.rs new file mode 100644 index 000000000..21d8e04d3 --- /dev/null +++ b/src/test/rustdoc/description_default.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + +// @has 'foo/index.html' '//meta[@name="description"]/@content' \ +// 'API documentation for the Rust `foo` crate.' + +// @has 'foo/foo_mod/index.html' '//meta[@name="description"]/@content' \ +// 'API documentation for the Rust `foo_mod` mod in crate `foo`.' +pub mod foo_mod { + pub struct __Thing {} +} + +// @has 'foo/fn.foo_fn.html' '//meta[@name="description"]/@content' \ +// 'API documentation for the Rust `foo_fn` fn in crate `foo`.' +pub fn foo_fn() {} diff --git a/src/test/rustdoc/doc-assoc-item.rs b/src/test/rustdoc/doc-assoc-item.rs new file mode 100644 index 000000000..4f1541865 --- /dev/null +++ b/src/test/rustdoc/doc-assoc-item.rs @@ -0,0 +1,18 @@ +pub struct Foo<T> { + x: T, +} + +pub trait Bar { + type Fuu; + + fn foo(foo: Self::Fuu); +} + +// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>' +impl<T: Bar<Fuu = u32>> Foo<T> { + pub fn new(t: T) -> Foo<T> { + Foo { + x: t, + } + } +} diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs new file mode 100644 index 000000000..7842ee69c --- /dev/null +++ b/src/test/rustdoc/doc-auto-cfg.rs @@ -0,0 +1,35 @@ +#![feature(doc_auto_cfg)] +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-meowmeow' +#[cfg(not(meowmeow))] +pub fn foo() {} + +// @has foo/fn.bar.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'test' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doctest' +#[cfg(any(meowmeow, test, doc, doctest))] +pub fn bar() {} + +// @has foo/fn.appear_1.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test' +#[cfg(any(meowmeow, doc, not(test)))] +pub fn appear_1() {} // issue #98065 + +// @has foo/fn.appear_2.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'test' +#[cfg(any(meowmeow, doc, all(test)))] +pub fn appear_2() {} // issue #98065 + +// @has foo/fn.appear_3.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'meowmeow' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc' +#[cfg(any(meowmeow, doc, all()))] +pub fn appear_3() {} // issue #98065 diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs new file mode 100644 index 000000000..636957fe9 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -0,0 +1,32 @@ +#![crate_name = "oud"] +#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)] + +#![doc(cfg_hide(feature = "solecism"))] + +// @has 'oud/struct.Solecism.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="solecism" +#[cfg(feature = "solecism")] +pub struct Solecism; + +// @has 'oud/struct.Scribacious.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature solecism' +#[cfg(feature = "solecism")] +#[doc(cfg(feature = "solecism"))] +pub struct Scribacious; + +// @has 'oud/struct.Hyperdulia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature hyperdulia' +// compile-flags:--cfg feature="hyperdulia" +#[cfg(feature = "solecism")] +#[cfg(feature = "hyperdulia")] +pub struct Hyperdulia; + +// @has 'oud/struct.Oystercatcher.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature oystercatcher only' +// compile-flags:--cfg feature="oystercatcher" +#[cfg(all(feature = "solecism", feature = "oystercatcher"))] +pub struct Oystercatcher; diff --git a/src/test/rustdoc/doc-cfg-implicit-gate.rs b/src/test/rustdoc/doc-cfg-implicit-gate.rs new file mode 100644 index 000000000..92804d372 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit-gate.rs @@ -0,0 +1,7 @@ +// compile-flags:--cfg feature="worricow" +#![crate_name = "xenogenous"] + +// @has 'xenogenous/struct.Worricow.html' +// @count - '//*[@class="stab portability"]' 0 +#[cfg(feature = "worricow")] +pub struct Worricow; diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs new file mode 100644 index 000000000..5d17a4ede --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit.rs @@ -0,0 +1,31 @@ +#![crate_name = "funambulism"] +#![feature(doc_auto_cfg, doc_cfg)] + +// @has 'funambulism/struct.Disorbed.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature disorbed' +// compile-flags:--cfg feature="disorbed" +#[cfg(feature = "disorbed")] +pub struct Disorbed; + +// @has 'funambulism/struct.Aesthesia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature aesthesia' +// compile-flags:--cfg feature="aesthesia" +#[doc(cfg(feature = "aesthesia"))] +pub struct Aesthesia; + +// @has 'funambulism/struct.Pliothermic.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature pliothermic' +// compile-flags:--cfg feature="epopoeist" +#[cfg(feature = "epopoeist")] +#[doc(cfg(feature = "pliothermic"))] +pub struct Pliothermic; + +// @has 'funambulism/struct.Simillimum.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="simillimum" +#[cfg(feature = "simillimum")] +#[doc(cfg(all()))] +pub struct Simillimum; diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs new file mode 100644 index 000000000..633df661b --- /dev/null +++ b/src/test/rustdoc/doc-cfg-simplification.rs @@ -0,0 +1,182 @@ +#![crate_name = "globuliferous"] +#![feature(doc_cfg)] + +// @has 'globuliferous/index.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' '^ratel$' + +// @has 'globuliferous/ratel/index.html' +// @count - '//*[@class="stab portability"]' 8 +// @matches - '//*[@class="stab portability"]' 'crate feature ratel' +// @matches - '//*[@class="stab portability"]' '^zoonosology$' +// @matches - '//*[@class="stab portability"]' '^yusho$' +// @matches - '//*[@class="stab portability"]' '^nunciative$' +// @matches - '//*[@class="stab portability"]' '^thionic$' +// @matches - '//*[@class="stab portability"]' '^zincic$' +// @matches - '//*[@class="stab portability"]' '^cosmotellurian$' +// @matches - '//*[@class="stab portability"]' '^aposiopesis$' +#[doc(cfg(feature = "ratel"))] +pub mod ratel { + // @has 'globuliferous/ratel/fn.ovicide.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub fn ovicide() {} + + // @has 'globuliferous/ratel/fn.zoonosology.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zoonosology' + #[doc(cfg(feature = "zoonosology"))] + pub fn zoonosology() {} + + // @has 'globuliferous/ratel/constant.DIAGRAPHICS.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub const DIAGRAPHICS: () = (); + + // @has 'globuliferous/ratel/constant.YUSHO.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and yusho' + #[doc(cfg(feature = "yusho"))] + pub const YUSHO: () = (); + + // @has 'globuliferous/ratel/static.KEYBUGLE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub static KEYBUGLE: () = (); + + // @has 'globuliferous/ratel/static.NUNCIATIVE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and nunciative' + #[doc(cfg(feature = "nunciative"))] + pub static NUNCIATIVE: () = (); + + // @has 'globuliferous/ratel/type.Wrick.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub type Wrick = (); + + // @has 'globuliferous/ratel/type.Thionic.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and thionic' + #[doc(cfg(feature = "thionic"))] + pub type Thionic = (); + + // @has 'globuliferous/ratel/struct.Eventration.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub struct Eventration; + + // @has 'globuliferous/ratel/struct.Zincic.html' + // @count - '//*[@class="stab portability"]' 2 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zincic' + // @matches - '//*[@class="stab portability"]' 'crate feature rutherford' + #[doc(cfg(feature = "zincic"))] + pub struct Zincic { + pub rectigrade: (), + + #[doc(cfg(feature = "rutherford"))] + pub rutherford: (), + } + + // @has 'globuliferous/ratel/enum.Cosmotellurian.html' + // @count - '//*[@class="stab portability"]' 10 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and cosmotellurian' + // @matches - '//*[@class="stab portability"]' 'crate feature biotaxy' + // @matches - '//*[@class="stab portability"]' 'crate feature xiphopagus' + // @matches - '//*[@class="stab portability"]' 'crate feature juxtapositive' + // @matches - '//*[@class="stab portability"]' 'crate feature fuero' + // @matches - '//*[@class="stab portability"]' 'crate feature palaeophile' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and xanthocomic' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and whosoever' + #[doc(cfg(feature = "cosmotellurian"))] + pub enum Cosmotellurian { + Groundsel { + jagger: (), + + #[doc(cfg(feature = "xiphopagus"))] + xiphopagus: (), + }, + + #[doc(cfg(feature = "biotaxy"))] + Biotaxy { + glossography: (), + + #[doc(cfg(feature = "juxtapositive"))] + juxtapositive: (), + }, + } + + impl Cosmotellurian { + pub fn uxoricide() {} + + #[doc(cfg(feature = "fuero"))] + pub fn fuero() {} + + pub const MAMELLE: () = (); + + #[doc(cfg(feature = "palaeophile"))] + pub const PALAEOPHILE: () = (); + } + + #[doc(cfg(feature = "broadcloth"))] + impl Cosmotellurian { + pub fn trabeculated() {} + + #[doc(cfg(feature = "xanthocomic"))] + pub fn xanthocomic() {} + + pub const BRACHIFEROUS: () = (); + + #[doc(cfg(feature = "whosoever"))] + pub const WHOSOEVER: () = (); + } + + // @has 'globuliferous/ratel/trait.Gnotobiology.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + // @matches - '//*[@class="stab portability"]' 'crate feature unzymotic' + // @matches - '//*[@class="stab portability"]' 'crate feature summate' + // @matches - '//*[@class="stab portability"]' 'crate feature unctuous' + pub trait Gnotobiology { + const XYLOTHERAPY: (); + + #[doc(cfg(feature = "unzymotic"))] + const UNZYMOTIC: (); + + type Lepadoid; + + #[doc(cfg(feature = "summate"))] + type Summate; + + fn decalcomania(); + + #[doc(cfg(feature = "unctuous"))] + fn unctuous(); + } + + // @has 'globuliferous/ratel/trait.Aposiopesis.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and aposiopesis' + // @matches - '//*[@class="stab portability"]' 'crate feature umbracious' + // @matches - '//*[@class="stab portability"]' 'crate feature uakari' + // @matches - '//*[@class="stab portability"]' 'crate feature rotograph' + #[doc(cfg(feature = "aposiopesis"))] + pub trait Aposiopesis { + const REDHIBITION: (); + + #[doc(cfg(feature = "umbracious"))] + const UMBRACIOUS: (); + + type Ophthalmoscope; + + #[doc(cfg(feature = "uakari"))] + type Uakari; + + fn meseems(); + + #[doc(cfg(feature = "rotograph"))] + fn rotograph(); + } +} diff --git a/src/test/rustdoc/doc-cfg-target-feature.rs b/src/test/rustdoc/doc-cfg-target-feature.rs new file mode 100644 index 000000000..f1b000dc8 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-target-feature.rs @@ -0,0 +1,21 @@ +// only-x86_64 +// compile-flags:--test +// should-fail +// no-system-llvm + +// #49723: rustdoc didn't add target features when extracting or running doctests + +#![feature(doc_cfg)] + +/// Foo +/// +/// # Examples +/// +/// ``` +/// #![feature(cfg_target_feature)] +/// +/// #[cfg(target_feature = "sse")] +/// assert!(false); +/// ``` +#[doc(cfg(target_feature = "sse"))] +pub unsafe fn foo() {} diff --git a/src/test/rustdoc/doc-cfg-traits.rs b/src/test/rustdoc/doc-cfg-traits.rs new file mode 100644 index 000000000..13407b2c7 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-traits.rs @@ -0,0 +1,124 @@ +#![crate_name = "myrmecophagous"] +#![feature(doc_cfg, associated_type_defaults)] + +// @has 'myrmecophagous/index.html' +// @count - '//*[@class="stab portability"]' 2 +// @matches - '//*[@class="stab portability"]' '^jurisconsult$' +// @matches - '//*[@class="stab portability"]' '^quarter$' + +pub trait Lea {} + +// @has 'myrmecophagous/trait.Vortoscope.html' +// @count - '//*[@class="stab portability"]' 6 +// @matches - '//*[@class="stab portability"]' 'crate feature zibib' +// @matches - '//*[@class="stab portability"]' 'crate feature poriform' +// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia' +// @matches - '//*[@class="stab portability"]' 'crate feature lea' +// @matches - '//*[@class="stab portability"]' 'crate feature unit' +// @matches - '//*[@class="stab portability"]' 'crate feature quarter' +pub trait Vortoscope { + type Batology = (); + + #[doc(cfg(feature = "zibib"))] + type Zibib = (); + + const YAHRZEIT: () = (); + + #[doc(cfg(feature = "poriform"))] + const PORIFORM: () = (); + + fn javanais() {} + + #[doc(cfg(feature = "ethopoeia"))] + fn ethopoeia() {} +} + +#[doc(cfg(feature = "lea"))] +impl<T: Lea> Vortoscope for T {} + +#[doc(cfg(feature = "unit"))] +impl Vortoscope for () {} + +// @has 'myrmecophagous/trait.Jurisconsult.html' +// @count - '//*[@class="stab portability"]' 7 +// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult' +// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy' +// @matches - '//*[@class="stab portability"]' 'crate feature boodle' +// @matches - '//*[@class="stab portability"]' 'crate feature mistetch' +// @matches - '//*[@class="stab portability"]' 'crate feature lea' +// @matches - '//*[@class="stab portability"]' 'crate feature unit' +// @matches - '//*[@class="stab portability"]' 'crate feature quarter' +#[doc(cfg(feature = "jurisconsult"))] +pub trait Jurisconsult { + type Urbanist = (); + + #[doc(cfg(feature = "lithomancy"))] + type Lithomancy = (); + + const UNIFILAR: () = (); + + #[doc(cfg(feature = "boodle"))] + const BOODLE: () = (); + + fn mersion() {} + + #[doc(cfg(feature = "mistetch"))] + fn mistetch() {} +} + +#[doc(cfg(feature = "lea"))] +impl<T: Lea> Jurisconsult for T {} + +#[doc(cfg(feature = "unit"))] +impl Jurisconsult for () {} + +// @has 'myrmecophagous/struct.Ultimogeniture.html' +// @count - '//*[@class="stab portability"]' 8 +// +// @matches - '//*[@class="stab portability"]' 'crate feature zibib' +// @matches - '//*[@class="stab portability"]' 'crate feature poriform' +// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia' +// +// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult' +// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy' +// @matches - '//*[@class="stab portability"]' 'crate feature boodle' +// @matches - '//*[@class="stab portability"]' 'crate feature mistetch' +// +// @matches - '//*[@class="stab portability"]' 'crate feature copy' +#[derive(Clone)] +pub struct Ultimogeniture; + +impl Vortoscope for Ultimogeniture {} + +#[doc(cfg(feature = "jurisconsult"))] +impl Jurisconsult for Ultimogeniture {} + +#[doc(cfg(feature = "copy"))] +impl Copy for Ultimogeniture {} + +// @has 'myrmecophagous/struct.Quarter.html' +// @count - '//*[@class="stab portability"]' 9 +// @matches - '//*[@class="stab portability"]' 'crate feature quarter' +// +// @matches - '//*[@class="stab portability"]' 'crate feature zibib' +// @matches - '//*[@class="stab portability"]' 'crate feature poriform' +// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia' +// +// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult' +// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy' +// @matches - '//*[@class="stab portability"]' 'crate feature boodle' +// @matches - '//*[@class="stab portability"]' 'crate feature mistetch' +// +// @matches - '//*[@class="stab portability"]' 'crate feature copy' +#[doc(cfg(feature = "quarter"))] +#[derive(Clone)] +pub struct Quarter; + +#[doc(cfg(feature = "quarter"))] +impl Vortoscope for Quarter {} + +#[doc(cfg(all(feature = "jurisconsult", feature = "quarter")))] +impl Jurisconsult for Quarter {} + +#[doc(cfg(all(feature = "copy", feature = "quarter")))] +impl Copy for Quarter {} diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs new file mode 100644 index 000000000..4cddb0b76 --- /dev/null +++ b/src/test/rustdoc/doc-cfg.rs @@ -0,0 +1,101 @@ +#![feature(doc_cfg)] +#![feature(target_feature, cfg_target_feature)] + +// @has doc_cfg/struct.Portable.html +// @!has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' '' +// @has - '//*[@id="method.unix_and_arm_only_function"]' 'fn unix_and_arm_only_function()' +// @has - '//*[@class="stab portability"]' 'Available on Unix and ARM only.' +// @has - '//*[@id="method.wasi_and_wasm32_only_function"]' 'fn wasi_and_wasm32_only_function()' +// @has - '//*[@class="stab portability"]' 'Available on WASI and WebAssembly only.' +pub struct Portable; + +// @has doc_cfg/unix_only/index.html \ +// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on Unix only.' +// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AARM\Z' +// @count - '//*[@class="stab portability"]' 2 +#[doc(cfg(unix))] +pub mod unix_only { + // @has doc_cfg/unix_only/fn.unix_only_function.html \ + // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ + // 'Available on Unix only.' + // @count - '//*[@class="stab portability"]' 1 + pub fn unix_only_function() { + content::should::be::irrelevant(); + } + + // @has doc_cfg/unix_only/trait.ArmOnly.html \ + // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ + // 'Available on Unix and ARM only.' + // @count - '//*[@class="stab portability"]' 1 + #[doc(cfg(target_arch = "arm"))] + pub trait ArmOnly { + fn unix_and_arm_only_function(); + } + + #[doc(cfg(target_arch = "arm"))] + impl ArmOnly for super::Portable { + fn unix_and_arm_only_function() {} + } +} + +// @has doc_cfg/wasi_only/index.html \ +// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on WASI only.' +// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AWebAssembly\Z' +// @count - '//*[@class="stab portability"]' 2 +#[doc(cfg(target_os = "wasi"))] +pub mod wasi_only { + // @has doc_cfg/wasi_only/fn.wasi_only_function.html \ + // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ + // 'Available on WASI only.' + // @count - '//*[@class="stab portability"]' 1 + pub fn wasi_only_function() { + content::should::be::irrelevant(); + } + + // @has doc_cfg/wasi_only/trait.Wasm32Only.html \ + // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ + // 'Available on WASI and WebAssembly only.' + // @count - '//*[@class="stab portability"]' 1 + #[doc(cfg(target_arch = "wasm32"))] + pub trait Wasm32Only { + fn wasi_and_wasm32_only_function(); + } + + #[doc(cfg(target_arch = "wasm32"))] + impl Wasm32Only for super::Portable { + fn wasi_and_wasm32_only_function() {} + } +} + +// tagging a function with `#[target_feature]` creates a doc(cfg(target_feature)) node for that +// item as well + +// the portability header is different on the module view versus the full view +// @has doc_cfg/index.html +// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\Aavx\Z' + +// @has doc_cfg/fn.uses_target_feature.html +// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available with target feature avx only.' +#[target_feature(enable = "avx")] +pub unsafe fn uses_target_feature() { + content::should::be::irrelevant(); +} + +// @has doc_cfg/fn.uses_cfg_target_feature.html +// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available with target feature avx only.' +#[doc(cfg(target_feature = "avx"))] +pub fn uses_cfg_target_feature() { + uses_target_feature(); +} + +// multiple attributes should be allowed +// @has doc_cfg/fn.multiple_attrs.html \ +// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on x and y and z only.' +#[doc(cfg(x))] +#[doc(cfg(y), cfg(z))] +pub fn multiple_attrs() {} diff --git a/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs new file mode 100644 index 000000000..bfce46cf4 --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs @@ -0,0 +1,23 @@ +//! Test case for [#80737]. +//! +//! A SomeTrait that is implemented for `&mut T where T: SomeTrait` +//! should not be marked as "notable" for return values that do not +//! have bounds on the trait itself. +//! +//! [#80737]: https://github.com/rust-lang/rust/issues/80737 + +#![feature(rustdoc_internals)] +#![no_std] + +#[doc(primitive = "reference")] +/// Some useless docs, wouhou! +/// +/// We need to put this in here, because notable traits +/// that are implemented on foreign types don't show up. +mod reference {} + +// @has doc_notable_trait_mut_t_is_not_an_iterator/fn.fn_no_matches.html +// @!has - '//code[@class="content"]' 'Iterator' +pub fn fn_no_matches<'a, T: 'a>() -> &'a mut T { + panic!() +} diff --git a/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs new file mode 100644 index 000000000..b359dcea0 --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs @@ -0,0 +1,21 @@ +//! Test case for [#78160]. +//! +//! A SomeTrait that is implemented for `&mut T` should not be marked as +//! "notable" for return values that are `&T`. +//! +//! [#78160]: https://github.com/rust-lang/rust/issues/78160 + +#![feature(rustdoc_internals)] + +#[doc(primitive = "reference")] +/// Some useless docs, wouhou! +/// +/// We need to put this in here, because notable traits +/// that are implemented on foreign types don't show up. +mod reference {} + +// @has doc_notable_trait_mut_t_is_not_ref_t/fn.fn_no_matches.html +// @!has - '//code[@class="content"]' "impl<'_, I> Iterator for &'_ mut I" +pub fn fn_no_matches<'a, T: Iterator + 'a>() -> &'a T { + loop {} +} diff --git a/src/test/rustdoc/doc-notable_trait-slice.rs b/src/test/rustdoc/doc-notable_trait-slice.rs new file mode 100644 index 000000000..b0d414027 --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait-slice.rs @@ -0,0 +1,20 @@ +#![feature(doc_notable_trait)] + +#[doc(notable_trait)] +pub trait SomeTrait {} + +pub struct SomeStruct; +pub struct OtherStruct; +impl SomeTrait for &[SomeStruct] {} + +// @has doc_notable_trait_slice/fn.bare_fn_matches.html +// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]' +pub fn bare_fn_matches() -> &'static [SomeStruct] { + &[] +} + +// @has doc_notable_trait_slice/fn.bare_fn_no_matches.html +// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]' +pub fn bare_fn_no_matches() -> &'static [OtherStruct] { + &[] +} diff --git a/src/test/rustdoc/doc-notable_trait.rs b/src/test/rustdoc/doc-notable_trait.rs new file mode 100644 index 000000000..58a24b855 --- /dev/null +++ b/src/test/rustdoc/doc-notable_trait.rs @@ -0,0 +1,36 @@ +#![feature(doc_notable_trait)] + +pub struct Wrapper<T> { + inner: T, +} + +impl<T: SomeTrait> SomeTrait for Wrapper<T> {} + +#[doc(notable_trait)] +pub trait SomeTrait { + // @has doc_notable_trait/trait.SomeTrait.html + // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>' + fn wrap_me(self) -> Wrapper<Self> where Self: Sized { + Wrapper { + inner: self, + } + } +} + +pub struct SomeStruct; +impl SomeTrait for SomeStruct {} + +impl SomeStruct { + // @has doc_notable_trait/struct.SomeStruct.html + // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' + // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>' + pub fn new() -> SomeStruct { + SomeStruct + } +} + +// @has doc_notable_trait/fn.bare_fn.html +// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' +pub fn bare_fn() -> SomeStruct { + SomeStruct +} diff --git a/src/test/rustdoc/doc-proc-macro.rs b/src/test/rustdoc/doc-proc-macro.rs new file mode 100644 index 000000000..19172ffa4 --- /dev/null +++ b/src/test/rustdoc/doc-proc-macro.rs @@ -0,0 +1,8 @@ +// Issue #52129: ICE when trying to document the `quote` proc-macro from proc_macro + +// As of this writing, we don't currently attempt to document proc-macros. However, we shouldn't +// crash when we try. + +extern crate proc_macro; + +pub use proc_macro::*; diff --git a/src/test/rustdoc/doctest-manual-crate-name.rs b/src/test/rustdoc/doctest-manual-crate-name.rs new file mode 100644 index 000000000..3a5e3734e --- /dev/null +++ b/src/test/rustdoc/doctest-manual-crate-name.rs @@ -0,0 +1,7 @@ +// compile-flags:--test + +//! ``` +//! #![crate_name="asdf"] +//! +//! println!("yo"); +//! ``` diff --git a/src/test/rustdoc/double-quote-escape.rs b/src/test/rustdoc/double-quote-escape.rs new file mode 100644 index 000000000..350c89741 --- /dev/null +++ b/src/test/rustdoc/double-quote-escape.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] + +pub trait Foo<T> { + fn foo() {} +} + +pub struct Bar; + +// @has foo/struct.Bar.html +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E-for-Bar"]' 'Foo<unsafe extern "C" fn()>' +impl Foo<unsafe extern "C" fn()> for Bar {} diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs new file mode 100644 index 000000000..18f3900b2 --- /dev/null +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -0,0 +1,53 @@ +#![crate_name = "foo"] +#![feature(doc_cfg)] + +// @has 'foo/index.html' +// @matches '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]' '^sync$' +// @has '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only' + +// @has 'foo/struct.Foo.html' +// @has '-' '//*[@class="stab portability"]' 'sync' +#[doc(cfg(feature = "sync"))] +#[doc(cfg(feature = "sync"))] +/// my feature sync struct +pub struct Foo; + +// @has 'foo/bar/index.html' +// @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync only.' +#[doc(cfg(feature = "sync"))] +pub mod bar { + // @has 'foo/bar/struct.Bar.html' + // @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync only.' + #[doc(cfg(feature = "sync"))] + pub struct Bar; +} + +// @has 'foo/baz/index.html' +// @has '-' '//*[@class="stab portability"]' 'Available on crate features sync and send only.' +#[doc(cfg(all(feature = "sync", feature = "send")))] +pub mod baz { + // @has 'foo/baz/struct.Baz.html' + // @has '-' '//*[@class="stab portability"]' 'Available on crate features sync and send only.' + #[doc(cfg(feature = "sync"))] + pub struct Baz; +} + +// @has 'foo/qux/index.html' +// @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync only.' +#[doc(cfg(feature = "sync"))] +pub mod qux { + // @has 'foo/qux/struct.Qux.html' + // @has '-' '//*[@class="stab portability"]' 'Available on crate features sync and send only.' + #[doc(cfg(all(feature = "sync", feature = "send")))] + pub struct Qux; +} + +// @has 'foo/quux/index.html' +// @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync and crate feature send and foo only.' +#[doc(cfg(all(feature = "sync", feature = "send", foo)))] +pub mod quux { + // @has 'foo/quux/struct.Quux.html' + // @has '-' '//*[@class="stab portability"]' 'Available on crate feature sync and crate feature send and foo and bar only.' + #[doc(cfg(all(feature = "send", feature = "sync", bar)))] + pub struct Quux; +} diff --git a/src/test/rustdoc/duplicate-flags.rs b/src/test/rustdoc/duplicate-flags.rs new file mode 100644 index 000000000..dde36df2c --- /dev/null +++ b/src/test/rustdoc/duplicate-flags.rs @@ -0,0 +1,4 @@ +// compile-flags: --document-private-items --document-private-items + +// @has duplicate_flags/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/duplicate_impls/impls.rs b/src/test/rustdoc/duplicate_impls/impls.rs new file mode 100644 index 000000000..6875ad272 --- /dev/null +++ b/src/test/rustdoc/duplicate_impls/impls.rs @@ -0,0 +1,12 @@ +pub struct Foo; + +// just so that `Foo` doesn't show up on `Bar`s sidebar +pub mod bar { + pub trait Bar {} +} + +impl Foo { + pub fn new() -> Foo { Foo } +} + +impl bar::Bar for Foo {} diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs new file mode 100644 index 000000000..84c9e4ac0 --- /dev/null +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -0,0 +1,14 @@ +// ignore-tidy-linelength + +// @has issue_33054/impls/struct.Foo.html +// @has - '//h3[@class="code-header in-band"]' 'impl Foo' +// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo' +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="main-content"]/div[@id="implementations-list"]/details/summary/*[@class="impl has-srclink"]' 1 +// @has issue_33054/impls/bar/trait.Bar.html +// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo' +// @count - '//*[@class="struct"]' 1 +pub mod impls; + +#[doc(inline)] +pub use impls as impls2; diff --git a/src/test/rustdoc/duplicated_impl.rs b/src/test/rustdoc/duplicated_impl.rs new file mode 100644 index 000000000..4e901b31c --- /dev/null +++ b/src/test/rustdoc/duplicated_impl.rs @@ -0,0 +1,14 @@ +// This test ensures that the same implementation doesn't show more than once. +// It's a regression test for https://github.com/rust-lang/rust/issues/96036. + +#![crate_name = "foo"] + +// We check that there is only one "impl<T> Something<Whatever> for T" listed in the +// blanket implementations. + +// @has 'foo/struct.Whatever.html' +// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1 + +pub trait Something<T> { } +pub struct Whatever; +impl<T> Something<Whatever> for T {} diff --git a/src/test/rustdoc/early-unindent.rs b/src/test/rustdoc/early-unindent.rs new file mode 100644 index 000000000..791a452c9 --- /dev/null +++ b/src/test/rustdoc/early-unindent.rs @@ -0,0 +1,26 @@ +// This is a regression for https://github.com/rust-lang/rust/issues/96079. + +#![crate_name = "foo"] + +pub mod app { + pub struct S; + + impl S { + // @has 'foo/app/struct.S.html' + // @has - '//a[@href="../enums/enum.Foo.html#method.by_name"]' 'Foo::by_name' + /** + Doc comment hello! [`Foo::by_name`](`crate::enums::Foo::by_name`). + */ + pub fn whatever(&self) {} + } +} + +pub mod enums { + pub enum Foo { + Bar, + } + + impl Foo { + pub fn by_name(&self) {} + } +} diff --git a/src/test/rustdoc/edition-doctest.rs b/src/test/rustdoc/edition-doctest.rs new file mode 100644 index 000000000..6de25996b --- /dev/null +++ b/src/test/rustdoc/edition-doctest.rs @@ -0,0 +1,44 @@ +// compile-flags:--test + +/// ```rust,edition2018 +/// #![feature(try_blocks)] +/// +/// use std::num::ParseIntError; +/// +/// let result: Result<i32, ParseIntError> = try { +/// "1".parse::<i32>()? +/// + "2".parse::<i32>()? +/// + "3".parse::<i32>()? +/// }; +/// assert_eq!(result, Ok(6)); +/// +/// let result: Result<i32, ParseIntError> = try { +/// "1".parse::<i32>()? +/// + "foo".parse::<i32>()? +/// + "3".parse::<i32>()? +/// }; +/// assert!(result.is_err()); +/// ``` + + +/// ```rust,edition2015,compile_fail,E0574 +/// #![feature(try_blocks)] +/// +/// use std::num::ParseIntError; +/// +/// let result: Result<i32, ParseIntError> = try { +/// "1".parse::<i32>()? +/// + "2".parse::<i32>()? +/// + "3".parse::<i32>()? +/// }; +/// assert_eq!(result, Ok(6)); +/// +/// let result: Result<i32, ParseIntError> = try { +/// "1".parse::<i32>()? +/// + "foo".parse::<i32>()? +/// + "3".parse::<i32>()? +/// }; +/// assert!(result.is_err()); +/// ``` + +pub fn foo() {} diff --git a/src/test/rustdoc/edition-flag.rs b/src/test/rustdoc/edition-flag.rs new file mode 100644 index 000000000..e54c7d296 --- /dev/null +++ b/src/test/rustdoc/edition-flag.rs @@ -0,0 +1,11 @@ +// compile-flags:--test +// edition:2018 + +/// ```rust +/// fn main() { +/// let _ = async { }; +/// } +/// ``` +fn main() { + let _ = async { }; +} diff --git a/src/test/rustdoc/elided-lifetime.rs b/src/test/rustdoc/elided-lifetime.rs new file mode 100644 index 000000000..5a32554f9 --- /dev/null +++ b/src/test/rustdoc/elided-lifetime.rs @@ -0,0 +1,43 @@ +// aux-build:elided-lifetime.rs +// +// rust-lang/rust#75225 +// +// Since Rust 2018 we encourage writing out <'_> explicitly to make it clear +// that borrowing is occuring. Make sure rustdoc is following the same idiom. + +#![crate_name = "foo"] + +pub struct Ref<'a>(&'a u32); +type ARef<'a> = Ref<'a>; + +// @has foo/fn.test1.html +// @matches - "Ref</a><'_>" +pub fn test1(a: &u32) -> Ref { + Ref(a) +} + +// @has foo/fn.test2.html +// @matches - "Ref</a><'_>" +pub fn test2(a: &u32) -> Ref<'_> { + Ref(a) +} + +// @has foo/fn.test3.html +// @matches - "Ref</a><'_>" +pub fn test3(a: &u32) -> ARef { + Ref(a) +} + +// @has foo/fn.test4.html +// @matches - "Ref</a><'_>" +pub fn test4(a: &u32) -> ARef<'_> { + Ref(a) +} + +// Ensure external paths in inlined docs also display elided lifetime +// @has foo/bar/fn.test5.html +// @matches - "Ref</a><'_>" +// @has foo/bar/fn.test6.html +// @matches - "Ref</a><'_>" +#[doc(inline)] +pub extern crate bar; diff --git a/src/test/rustdoc/empty-doc-comment.rs b/src/test/rustdoc/empty-doc-comment.rs new file mode 100644 index 000000000..b1dae930e --- /dev/null +++ b/src/test/rustdoc/empty-doc-comment.rs @@ -0,0 +1,22 @@ +// Ensure that empty doc comments don't panic. + +/*! +*/ + +/// +/// +pub struct Foo; + +#[doc = " +"] +pub mod Mod { + //! + //! +} + +/** +*/ +pub mod Another { + #![doc = " +"] +} diff --git a/src/test/rustdoc/empty-impl-block.rs b/src/test/rustdoc/empty-impl-block.rs new file mode 100644 index 000000000..6a2a254f6 --- /dev/null +++ b/src/test/rustdoc/empty-impl-block.rs @@ -0,0 +1,20 @@ +#![crate_name = "foo"] + +// @has 'foo/struct.Foo.html' +pub struct Foo; + +// @has - '//*[@class="docblock"]' 'Hello empty impl block!' +// @has - '//*[@class="item-info"]' 'This impl block contains no items.' +/// Hello empty impl block! +impl Foo {} +// We ensure that this empty impl block without doc isn't rendered. +// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 1 +impl Foo {} + +// Just to ensure that empty trait impl blocks are rendered. +pub struct Another; +pub trait Bar {} + +// @has 'foo/struct.Another.html' +// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Another' +impl Bar for Another {} diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs new file mode 100644 index 000000000..83902d6f7 --- /dev/null +++ b/src/test/rustdoc/empty-impls.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send-for-Foo"]' 'impl Send for Foo' +pub struct Foo; + +pub trait EmptyTrait {} + +// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait-for-Foo"]' 'impl EmptyTrait for Foo' +impl EmptyTrait for Foo {} + +pub trait NotEmpty { + fn foo(&self); +} + +// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty-for-Foo"]' 'impl NotEmpty for Foo' +impl NotEmpty for Foo { + fn foo(&self) {} +} diff --git a/src/test/rustdoc/empty-mod-private.rs b/src/test/rustdoc/empty-mod-private.rs new file mode 100644 index 000000000..c2a98049a --- /dev/null +++ b/src/test/rustdoc/empty-mod-private.rs @@ -0,0 +1,16 @@ +// compile-flags: --document-private-items + +// @has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo' +// @has 'empty_mod_private/sidebar-items.js' 'foo' +// @matches 'empty_mod_private/foo/index.html' '//h1' 'Module empty_mod_private::foo' +mod foo {} + +// @has 'empty_mod_private/index.html' '//a[@href="bar/index.html"]' 'bar' +// @has 'empty_mod_private/sidebar-items.js' 'bar' +// @matches 'empty_mod_private/bar/index.html' '//h1' 'Module empty_mod_private::bar' +mod bar { + // @has 'empty_mod_private/bar/index.html' '//a[@href="baz/index.html"]' 'baz' + // @has 'empty_mod_private/bar/sidebar-items.js' 'baz' + // @matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module empty_mod_private::bar::baz' + mod baz {} +} diff --git a/src/test/rustdoc/empty-mod-public.rs b/src/test/rustdoc/empty-mod-public.rs new file mode 100644 index 000000000..d097fcf83 --- /dev/null +++ b/src/test/rustdoc/empty-mod-public.rs @@ -0,0 +1,14 @@ +// @has 'empty_mod_public/index.html' '//a[@href="foo/index.html"]' 'foo' +// @has 'empty_mod_public/sidebar-items.js' 'foo' +// @matches 'empty_mod_public/foo/index.html' '//h1' 'Module empty_mod_public::foo' +pub mod foo {} + +// @has 'empty_mod_public/index.html' '//a[@href="bar/index.html"]' 'bar' +// @has 'empty_mod_public/sidebar-items.js' 'bar' +// @matches 'empty_mod_public/bar/index.html' '//h1' 'Module empty_mod_public::bar' +pub mod bar { + // @has 'empty_mod_public/bar/index.html' '//a[@href="baz/index.html"]' 'baz' + // @has 'empty_mod_public/bar/sidebar-items.js' 'baz' + // @matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module empty_mod_public::bar::baz' + pub mod baz {} +} diff --git a/src/test/rustdoc/empty-section.rs b/src/test/rustdoc/empty-section.rs new file mode 100644 index 000000000..665aa38b1 --- /dev/null +++ b/src/test/rustdoc/empty-section.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +#![feature(negative_impls)] + +pub struct Foo; + +// @has foo/struct.Foo.html +// @!has - 'Auto Trait Implementations' +impl !Send for Foo {} +impl !Sync for Foo {} +impl !std::marker::Unpin for Foo {} +impl !std::panic::RefUnwindSafe for Foo {} +impl !std::panic::UnwindSafe for Foo {} diff --git a/src/test/rustdoc/ensure-src-link.rs b/src/test/rustdoc/ensure-src-link.rs new file mode 100644 index 000000000..9f8b0277e --- /dev/null +++ b/src/test/rustdoc/ensure-src-link.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +// This test ensures that the [src] link is present on traits items. + +// @has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="srclink"]' "source" +pub use std::iter::Iterator; diff --git a/src/test/rustdoc/enum-headings.rs b/src/test/rustdoc/enum-headings.rs new file mode 100644 index 000000000..2e5c34391 --- /dev/null +++ b/src/test/rustdoc/enum-headings.rs @@ -0,0 +1,40 @@ +#![crate_name = "foo"] +// @has foo/enum.Token.html +/// A token! +/// # First +/// Some following text... +// @has - '//h2[@id="first"]' "First" +pub enum Token { + /// A declaration! + /// # Variant-First + /// Some following text... + // @has - '//h4[@id="variant-first"]' "Variant-First" + Declaration { + /// A version! + /// # Variant-Field-First + /// Some following text... + // @has - '//h5[@id="variant-field-first"]' "Variant-Field-First" + version: String, + }, + /// A Zoople! + /// # Variant-First + Zoople( + // @has - '//h5[@id="variant-tuple-field-first"]' "Variant-Tuple-Field-First" + /// Zoople's first variant! + /// # Variant-Tuple-Field-First + /// Some following text... + usize, + ), + /// Unfinished business! + /// # Non-Exhaustive-First + /// Some following text... + // @has - '//h4[@id="non-exhaustive-first"]' "Non-Exhaustive-First" + #[non_exhaustive] + Unfinished { + /// This is x. + /// # X-First + /// Some following text... + // @has - '//h5[@id="x-first"]' "X-First" + x: usize, + }, +} diff --git a/src/test/rustdoc/escape-deref-methods.rs b/src/test/rustdoc/escape-deref-methods.rs new file mode 100644 index 000000000..a62ad2c40 --- /dev/null +++ b/src/test/rustdoc/escape-deref-methods.rs @@ -0,0 +1,35 @@ +#![crate_name = "foo"] + +use std::ops::{Deref, DerefMut}; + +#[derive(Debug, Clone)] +pub struct Title { + name: String, +} + +#[derive(Debug, Clone)] +pub struct TitleList { + pub members: Vec<Title>, +} + +impl TitleList { + pub fn new() -> Self { + TitleList { members: Vec::new() } + } +} + +impl Deref for TitleList { + type Target = Vec<Title>; + + fn deref(&self) -> &Self::Target { + &self.members + } +} + +// @has foo/struct.TitleList.html +// @has - '//*[@class="sidebar-title"]' 'Methods from Deref<Target=Vec<Title>>' +impl DerefMut for TitleList { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.members + } +} diff --git a/src/test/rustdoc/extern-default-method.no_href_on_anchor.html b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html new file mode 100644 index 000000000..dab0a6495 --- /dev/null +++ b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html @@ -0,0 +1 @@ +<a class="fnname">provided</a>(&self)
\ No newline at end of file diff --git a/src/test/rustdoc/extern-default-method.rs b/src/test/rustdoc/extern-default-method.rs new file mode 100644 index 000000000..8139f5b26 --- /dev/null +++ b/src/test/rustdoc/extern-default-method.rs @@ -0,0 +1,23 @@ +// aux-build:rustdoc-extern-default-method.rs +// ignore-cross-compile +// ignore-tidy-linelength + +extern crate rustdoc_extern_default_method as ext; + +// For this test, the dependency is compiled but not documented. +// +// Still, the struct from the external crate and its impl should be documented since +// the struct is re-exported from this crate. +// However, the method in the trait impl should *not* have a link (an `href` attribute) to +// its corresponding item in the trait declaration since it would otherwise be broken. +// +// In older versions of rustdoc, the impl item (`a[@class="fnname"]`) used to link to +// `#method.provided` – i.e. "to itself". Put in quotes since that was actually incorrect in +// general: If the type `Struct` also had an inherent method called `provided`, the impl item +// would link to that one even though those two methods are distinct items! + +// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1 +// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]' 1 +// @snapshot no_href_on_anchor - '//*[@id="method.provided"]//a[@class="fnname"]' +// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided +pub use ext::Struct; diff --git a/src/test/rustdoc/extern-html-root-url-precedence.rs b/src/test/rustdoc/extern-html-root-url-precedence.rs new file mode 100644 index 000000000..def6767ea --- /dev/null +++ b/src/test/rustdoc/extern-html-root-url-precedence.rs @@ -0,0 +1,7 @@ +// compile-flags:-Z unstable-options --extern-html-root-url core=https://example.com/core/0.1.0 --extern-html-root-takes-precedence + +// @has extern_html_root_url_precedence/index.html +// --extern-html-root should take precedence if `--takes-precedence` is passed +// @has - '//a/@href' 'https://example.com/core/0.1.0/core/iter/index.html' +#[doc(no_inline)] +pub use std::iter; diff --git a/src/test/rustdoc/extern-html-root-url.rs b/src/test/rustdoc/extern-html-root-url.rs new file mode 100644 index 000000000..17eedcf2a --- /dev/null +++ b/src/test/rustdoc/extern-html-root-url.rs @@ -0,0 +1,18 @@ +// compile-flags:-Z unstable-options --extern-html-root-url html_root=https://example.com/override --extern-html-root-url no_html_root=https://example.com/override +// aux-build:html_root.rs +// aux-build:no_html_root.rs +// NOTE: intentionally does not build any auxiliary docs + +extern crate html_root; +extern crate no_html_root; + +// @has extern_html_root_url/index.html +// `html_root_url` should override `--extern-html-root-url` +// @has - '//a/@href' 'https://example.com/html_root/html_root/fn.foo.html' +#[doc(no_inline)] +pub use html_root::foo; + +#[doc(no_inline)] +// `--extern-html-root-url` should apply if no `html_root_url` is given +// @has - '//a/@href' 'https://example.com/override/no_html_root/fn.bar.html' +pub use no_html_root::bar; diff --git a/src/test/rustdoc/extern-impl-trait.rs b/src/test/rustdoc/extern-impl-trait.rs new file mode 100644 index 000000000..8ab026afd --- /dev/null +++ b/src/test/rustdoc/extern-impl-trait.rs @@ -0,0 +1,11 @@ +// aux-build:extern-impl-trait.rs + +#![crate_name = "foo"] + +extern crate extern_impl_trait; + +// @has 'foo/struct.X.html' '//h4[@class="code-header"]' "impl Foo<Associated = ()> + 'a" +pub use extern_impl_trait::X; + +// @has 'foo/struct.Y.html' '//h4[@class="code-header"]' "impl ?Sized + Foo<Associated = ()> + 'a" +pub use extern_impl_trait::Y; diff --git a/src/test/rustdoc/extern-impl.rs b/src/test/rustdoc/extern-impl.rs new file mode 100644 index 000000000..f357d65df --- /dev/null +++ b/src/test/rustdoc/extern-impl.rs @@ -0,0 +1,27 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +pub struct Foo; + +impl Foo { + // @has - '//h4[@class="code-header"]' 'fn rust0()' + pub fn rust0() {} + // @has - '//h4[@class="code-header"]' 'fn rust1()' + pub extern "Rust" fn rust1() {} + // @has - '//h4[@class="code-header"]' 'extern "C" fn c0()' + pub extern fn c0() {} + // @has - '//h4[@class="code-header"]' 'extern "C" fn c1()' + pub extern "C" fn c1() {} + // @has - '//h4[@class="code-header"]' 'extern "system" fn system0()' + pub extern "system" fn system0() {} +} + +// @has foo/trait.Bar.html +pub trait Bar {} + +// @has - '//h3[@class="code-header in-band"]' 'impl Bar for fn()' +impl Bar for fn() {} +// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "C" fn()' +impl Bar for extern fn() {} +// @has - '//h3[@class="code-header in-band"]' 'impl Bar for extern "system" fn()' +impl Bar for extern "system" fn() {} diff --git a/src/test/rustdoc/extern-links.rs b/src/test/rustdoc/extern-links.rs new file mode 100644 index 000000000..0383ccf7d --- /dev/null +++ b/src/test/rustdoc/extern-links.rs @@ -0,0 +1,21 @@ +// aux-build:extern-links.rs +// ignore-cross-compile + +#![crate_name = "foo"] + +pub extern crate extern_links; + +// @!has foo/index.html '//a' 'extern_links' +#[doc(no_inline)] +pub use extern_links as extern_links2; + +// @!has foo/index.html '//a' 'Foo' +#[doc(no_inline)] +pub use extern_links::Foo; + +#[doc(hidden)] +pub mod hidden { + // @!has foo/hidden/extern_links/index.html + // @!has foo/hidden/extern_links/struct.Foo.html + pub use extern_links; +} diff --git a/src/test/rustdoc/extern-method.rs b/src/test/rustdoc/extern-method.rs new file mode 100644 index 000000000..9cf5fc190 --- /dev/null +++ b/src/test/rustdoc/extern-method.rs @@ -0,0 +1,19 @@ +// aux-build:rustdoc-extern-method.rs +// ignore-cross-compile + +#![feature(unboxed_closures)] + +extern crate rustdoc_extern_method as foo; + +// @has extern_method/trait.Foo.html //pre "pub trait Foo" +// @has - '//*[@id="tymethod.foo"]//h4[@class="code-header"]' 'extern "rust-call" fn foo' +// @has - '//*[@id="method.foo_"]//h4[@class="code-header"]' 'extern "rust-call" fn foo_' +pub use foo::Foo; + +// @has extern_method/trait.Bar.html //pre "pub trait Bar" +pub trait Bar { + // @has - '//*[@id="tymethod.bar"]//h4[@class="code-header"]' 'extern "rust-call" fn bar' + extern "rust-call" fn bar(&self, _: ()); + // @has - '//*[@id="method.bar_"]//h4[@class="code-header"]' 'extern "rust-call" fn bar_' + extern "rust-call" fn bar_(&self, _: ()) { } +} diff --git a/src/test/rustdoc/external-cross.rs b/src/test/rustdoc/external-cross.rs new file mode 100644 index 000000000..3f8e16882 --- /dev/null +++ b/src/test/rustdoc/external-cross.rs @@ -0,0 +1,10 @@ +// aux-build:external-cross.rs +// ignore-cross-compile + +#![crate_name="host"] + +extern crate external_cross; + +// @has host/struct.NeedMoreDocs.html +// @has - '//h2' 'Cross-crate imported docs' +pub use external_cross::NeedMoreDocs; diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs new file mode 100644 index 000000000..bd322d67a --- /dev/null +++ b/src/test/rustdoc/external-doc.rs @@ -0,0 +1,14 @@ +// @has external_doc/struct.IncludeStrDocs.html +// @has - '//h2' 'External Docs' +// @has - '//h3' 'Inline Docs' +#[doc = include_str!("auxiliary/external-doc.md")] +/// ## Inline Docs +pub struct IncludeStrDocs; + +macro_rules! dir { () => { "auxiliary" } } + +// @has external_doc/struct.EagerExpansion.html +// @has - '//h2' 'External Docs' +#[doc = include_str!(concat!(dir!(), "/external-doc.md"))] +/// ## Inline Docs +pub struct EagerExpansion; diff --git a/src/test/rustdoc/external-macro-src.rs b/src/test/rustdoc/external-macro-src.rs new file mode 100644 index 000000000..359551ab7 --- /dev/null +++ b/src/test/rustdoc/external-macro-src.rs @@ -0,0 +1,12 @@ +// aux-build:external-macro-src.rs + +#![crate_name = "foo"] + +#[macro_use] +extern crate external_macro_src; + +// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'source' + +// @has foo/struct.Foo.html +// @has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'source' +make_foo!(); diff --git a/src/test/rustdoc/feature-gate-doc_auto_cfg.rs b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs new file mode 100644 index 000000000..da76381e4 --- /dev/null +++ b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs @@ -0,0 +1,8 @@ +#![feature(doc_cfg)] + +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @count - '//*[@class="item-info"]/*[@class="stab portability"]' 0 +#[cfg(not(test))] +pub fn foo() {} diff --git a/src/test/rustdoc/ffi.rs b/src/test/rustdoc/ffi.rs new file mode 100644 index 000000000..8140dfc72 --- /dev/null +++ b/src/test/rustdoc/ffi.rs @@ -0,0 +1,12 @@ +// aux-build:rustdoc-ffi.rs +// ignore-cross-compile + +extern crate rustdoc_ffi as lib; + +// @has ffi/fn.foreigner.html //pre 'pub unsafe extern "C" fn foreigner(cold_as_ice: u32)' +pub use lib::foreigner; + +extern "C" { + // @has ffi/fn.another.html //pre 'pub unsafe extern "C" fn another(cold_as_ice: u32)' + pub fn another(cold_as_ice: u32); +} diff --git a/src/test/rustdoc/fn-bound.rs b/src/test/rustdoc/fn-bound.rs new file mode 100644 index 000000000..4c4ffddc8 --- /dev/null +++ b/src/test/rustdoc/fn-bound.rs @@ -0,0 +1,21 @@ +// Regression test for #100143 + +use std::iter::Peekable; + +pub struct Span<F: Fn(&i32)> { + inner: Peekable<ConditionalIterator<F>>, +} + +pub struct ConditionalIterator<F> { + f: F, +} + + +// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>' +impl<F: Fn(&i32)> Iterator for ConditionalIterator<F> { + type Item = (); + + fn next(&mut self) -> Option<Self::Item> { + todo!() + } +} diff --git a/src/test/rustdoc/fn-pointer-arg-name.rs b/src/test/rustdoc/fn-pointer-arg-name.rs new file mode 100644 index 000000000..4293d849d --- /dev/null +++ b/src/test/rustdoc/fn-pointer-arg-name.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - '//*[@class="rust fn"]' 'pub fn f(callback: fn(len: usize, foo: u32))' +pub fn f(callback: fn(len: usize, foo: u32)) {} diff --git a/src/test/rustdoc/fn-sidebar.rs b/src/test/rustdoc/fn-sidebar.rs new file mode 100644 index 000000000..2fe8ebec1 --- /dev/null +++ b/src/test/rustdoc/fn-sidebar.rs @@ -0,0 +1,9 @@ +#![crate_name = "foo"] + +// @has foo/fn.bar.html +// @has - '//*[@class="sidebar-elems"]' '' +pub fn bar() {} + +// @has foo/constant.BAR.html +// @has - '//*[@class="sidebar-elems"]' '' +pub const BAR: u32 = 0; diff --git a/src/test/rustdoc/fn-type.rs b/src/test/rustdoc/fn-type.rs new file mode 100644 index 000000000..3959aeb6c --- /dev/null +++ b/src/test/rustdoc/fn-type.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] +#![crate_type = "lib"] + +pub struct Foo<'a, T> { + pub generic: fn(val: &T) -> T, + + pub lifetime: fn(val: &'a i32) -> i32, + pub hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32), +} + +// @has 'foo/struct.Foo.html' '//span[@id="structfield.generic"]' "generic: fn(val: &T) -> T" +// @has 'foo/struct.Foo.html' '//span[@id="structfield.lifetime"]' "lifetime: fn(val: &'a i32) -> i32" +// @has 'foo/struct.Foo.html' '//span[@id="structfield.hrtb_lifetime"]' "hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32)" diff --git a/src/test/rustdoc/force-target-feature.rs b/src/test/rustdoc/force-target-feature.rs new file mode 100644 index 000000000..b6c10e834 --- /dev/null +++ b/src/test/rustdoc/force-target-feature.rs @@ -0,0 +1,11 @@ +// only-x86_64 +// compile-flags:--test -C target-feature=+avx +// should-fail + +/// (written on a spider's web) Some Struct +/// +/// ``` +/// panic!("oh no"); +/// ``` +#[doc(cfg(target_feature = "avx"))] +pub struct SomeStruct; diff --git a/src/test/rustdoc/foreigntype-reexport.rs b/src/test/rustdoc/foreigntype-reexport.rs new file mode 100644 index 000000000..1dec0ef3e --- /dev/null +++ b/src/test/rustdoc/foreigntype-reexport.rs @@ -0,0 +1,56 @@ +#![feature(extern_types)] + +mod sub { + extern "C" { + /// Another extern type. + pub type C2; + pub fn f2(); + pub static K: usize; + } +} + +pub mod sub2 { + extern "C" { + // @has foreigntype_reexport/sub2/foreigntype.C.html + pub type C; + // @has foreigntype_reexport/sub2/fn.f.html + pub fn f(); + // @has foreigntype_reexport/sub2/static.K3.html + pub static K3: usize; + } +} + +mod sub3 { + extern "C" { + pub type C4; + pub fn f4(); + pub static K4: usize; + type X4; + } +} + +// @has foreigntype_reexport/foreigntype.C2.html +// @has foreigntype_reexport/fn.f2.html +// @has foreigntype_reexport/static.K2.html +// @has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'C2' +// @has foreigntype_reexport/index.html '//a[@class="fn"]' 'f2' +// @has foreigntype_reexport/index.html '//a[@class="static"]' 'K2' +pub use self::sub::{f2, C2, K as K2}; + +// @has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'C' +// @has foreigntype_reexport/index.html '//a[@class="fn"]' 'f' +// @has foreigntype_reexport/index.html '//a[@class="static"]' 'K3' +// @has foreigntype_reexport/index.html '//code' 'pub use self::sub2::C as C3;' +// @has foreigntype_reexport/index.html '//code' 'pub use self::sub2::f as f3;' +// @has foreigntype_reexport/index.html '//code' 'pub use self::sub2::K3;' +pub use self::sub2::{f as f3, C as C3, K3}; + +// @has foreigntype_reexport/foreigntype.C4.html +// @has foreigntype_reexport/fn.f4.html +// @has foreigntype_reexport/static.K4.html +// @!has foreigntype_reexport/foreigntype.X4.html +// @has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'C4' +// @has foreigntype_reexport/index.html '//a[@class="fn"]' 'f4' +// @has foreigntype_reexport/index.html '//a[@class="static"]' 'K4' +// @!has foreigntype_reexport/index.html '//a[@class="foreigntype"]' 'X4' +pub use self::sub3::*; diff --git a/src/test/rustdoc/foreigntype.rs b/src/test/rustdoc/foreigntype.rs new file mode 100644 index 000000000..891cdd5fe --- /dev/null +++ b/src/test/rustdoc/foreigntype.rs @@ -0,0 +1,18 @@ +#![feature(extern_types)] + +extern "C" { + // @has foreigntype/foreigntype.ExtType.html + pub type ExtType; +} + +impl ExtType { + // @has - '//a[@class="fnname"]' 'do_something' + pub fn do_something(&self) {} +} + +pub trait Trait {} + +// @has foreigntype/trait.Trait.html '//a[@class="foreigntype"]' 'ExtType' +impl Trait for ExtType {} + +// @has foreigntype/index.html '//a[@class="foreigntype"]' 'ExtType' diff --git a/src/test/rustdoc/generic-associated-types/gats.rs b/src/test/rustdoc/generic-associated-types/gats.rs new file mode 100644 index 000000000..ae981b949 --- /dev/null +++ b/src/test/rustdoc/generic-associated-types/gats.rs @@ -0,0 +1,34 @@ +#![crate_name = "foo"] +#![feature(generic_associated_types)] + +// @has foo/trait.LendingIterator.html +pub trait LendingIterator { + // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a" + type Item<'a> where Self: 'a; + + // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \ + // "fn next<'a>(&'a self) -> Self::Item<'a>" + // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]//a[@href="trait.LendingIterator.html#associatedtype.Item"]' \ + // "Item" + fn next<'a>(&'a self) -> Self::Item<'a>; +} + +// @has foo/trait.LendingIterator.html +// @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item<'a> = ()" +impl LendingIterator for () { + type Item<'a> = (); + + fn next<'a>(&self) -> () {} +} + +pub struct Infinite<T>(T); + +// @has foo/trait.LendingIterator.html +// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T" +impl<T> LendingIterator for Infinite<T> { + type Item<'a> where Self: 'a = &'a T; + + fn next<'a>(&'a self) -> Self::Item<'a> { + &self.0 + } +} diff --git a/src/test/rustdoc/generic-associated-types/issue-94683.rs b/src/test/rustdoc/generic-associated-types/issue-94683.rs new file mode 100644 index 000000000..38ecf5283 --- /dev/null +++ b/src/test/rustdoc/generic-associated-types/issue-94683.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] +#![feature(generic_associated_types)] + +pub trait Trait { + type Gat<'a>; +} + +// Make sure that the elided lifetime shows up + +// @has foo/type.T.html +// @has - "pub type T = " +// @has - "<'_>" +pub type T = fn(&<() as Trait>::Gat<'_>); diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs new file mode 100644 index 000000000..c6beed70a --- /dev/null +++ b/src/test/rustdoc/generic-impl.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +use std::fmt; + +// @!has foo/struct.Bar.html '//*[@id="impl-ToString-for-Bar"]' '' +pub struct Bar; + +// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' +pub struct Foo; +// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-Foo"]' 'ToString' + +impl fmt::Display for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Foo") + } +} diff --git a/src/test/rustdoc/generic_const_exprs.rs b/src/test/rustdoc/generic_const_exprs.rs new file mode 100644 index 000000000..6ff591639 --- /dev/null +++ b/src/test/rustdoc/generic_const_exprs.rs @@ -0,0 +1,24 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/92859>. + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +#![crate_name = "foo"] + +// @has 'foo/trait.Foo.html' + +pub trait Foo: Sized { + const WIDTH: usize; + + fn arrayify(self) -> [Self; Self::WIDTH]; +} + +impl<T: Sized> Foo for T { + const WIDTH: usize = 1; + + // @has - '//*[@id="tymethod.arrayify"]/*[@class="code-header"]' \ + // 'fn arrayify(self) -> [Self; Self::WIDTH]' + fn arrayify(self) -> [Self; Self::WIDTH] { + [self] + } +} diff --git a/src/test/rustdoc/hidden-impls.rs b/src/test/rustdoc/hidden-impls.rs new file mode 100644 index 000000000..8f33a6604 --- /dev/null +++ b/src/test/rustdoc/hidden-impls.rs @@ -0,0 +1,17 @@ +#![crate_name = "foo"] + +mod hidden { + #[derive(Clone)] + pub struct Foo; +} + +#[doc(hidden)] +pub mod __hidden { + pub use hidden::Foo; +} + +// @has foo/trait.Clone.html +// @!has - 'Foo' +// @has implementors/core/clone/trait.Clone.js +// @!has - 'Foo' +pub use std::clone::Clone; diff --git a/src/test/rustdoc/hidden-line.rs b/src/test/rustdoc/hidden-line.rs new file mode 100644 index 000000000..f2f6173d2 --- /dev/null +++ b/src/test/rustdoc/hidden-line.rs @@ -0,0 +1,19 @@ +/// The '# ' lines should be removed from the output, but the #[derive] should be +/// retained. +/// +/// ```rust +/// # #[derive(PartialEq)] // invisible +/// # struct Foo; // invisible +/// +/// #[derive(PartialEq)] // Bar +/// struct Bar(Foo); +/// +/// fn test() { +/// let x = Bar(Foo); +/// assert_eq!(x, x); // check that the derivings worked +/// } +/// ``` +pub fn foo() {} + +// @!has hidden_line/fn.foo.html invisible +// @matches - //pre "#\[derive\(PartialEq\)\] // Bar" diff --git a/src/test/rustdoc/hidden-methods.rs b/src/test/rustdoc/hidden-methods.rs new file mode 100644 index 000000000..27181d489 --- /dev/null +++ b/src/test/rustdoc/hidden-methods.rs @@ -0,0 +1,29 @@ +#![crate_name = "foo"] + +#[doc(hidden)] +pub mod hidden { + pub struct Foo; + + impl Foo { + #[doc(hidden)] + pub fn this_should_be_hidden() {} + } + + pub struct Bar; + + impl Bar { + fn this_should_be_hidden() {} + } +} + +// @has foo/struct.Foo.html +// @!has - 'Methods' +// @!has - '//code' 'impl Foo' +// @!has - 'this_should_be_hidden' +pub use hidden::Foo; + +// @has foo/struct.Bar.html +// @!has - 'Methods' +// @!has - '//code' 'impl Bar' +// @!has - 'this_should_be_hidden' +pub use hidden::Bar; diff --git a/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs new file mode 100644 index 000000000..95b3e9b65 --- /dev/null +++ b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs @@ -0,0 +1,31 @@ +// compile-flags: -Z unstable-options --document-hidden-items + +// test for trait methods with `doc(hidden)` with `--document-hidden-items` passed. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff --git a/src/test/rustdoc/hidden-trait-methods.rs b/src/test/rustdoc/hidden-trait-methods.rs new file mode 100644 index 000000000..e924ba7d0 --- /dev/null +++ b/src/test/rustdoc/hidden-trait-methods.rs @@ -0,0 +1,29 @@ +// test for trait methods with `doc(hidden)`. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff --git a/src/test/rustdoc/hidden-trait-struct-impls.rs b/src/test/rustdoc/hidden-trait-struct-impls.rs new file mode 100644 index 000000000..cc3f63377 --- /dev/null +++ b/src/test/rustdoc/hidden-trait-struct-impls.rs @@ -0,0 +1,22 @@ +#![crate_name = "foo"] + +#[doc(hidden)] +pub trait Foo {} + +trait Dark {} + +pub trait Bam {} + +pub struct Bar; + +struct Hidden; + +// @!has foo/struct.Bar.html '//*[@id="impl-Foo-for-Bar"]' 'impl Foo for Bar' +impl Foo for Bar {} +// @!has foo/struct.Bar.html '//*[@id="impl-Dark-for-Bar"]' 'impl Dark for Bar' +impl Dark for Bar {} +// @has foo/struct.Bar.html '//*[@id="impl-Bam-for-Bar"]' 'impl Bam for Bar' +// @has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Bar' +impl Bam for Bar {} +// @!has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Hidden' +impl Bam for Hidden {} diff --git a/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs new file mode 100644 index 000000000..644a6e1cf --- /dev/null +++ b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs @@ -0,0 +1,82 @@ +// Test that certain unevaluated constant expression arguments that are +// deemed too verbose or complex and that may leak private or +// `doc(hidden)` struct fields are not displayed in the documentation. +// +// Read the documentation of `rustdoc::clean::utils::print_const_expr` +// for further details. +#![feature(const_trait_impl, generic_const_exprs)] +#![allow(incomplete_features)] + +// @has hide_complex_unevaluated_const_arguments/trait.Stage.html +pub trait Stage { + // A helper constant that prevents const expressions containing it + // from getting fully evaluated since it doesn't have a body and + // thus is non-reducible. This allows us to specifically test the + // pretty-printing of *unevaluated* consts. + const ABSTRACT: usize; + + // Currently considered "overly complex" by the `generic_const_exprs` + // feature. If / once this expression kind gets supported, this + // unevaluated const expression could leak the private struct field. + // + // FIXME: Once the line below compiles, make this a test that + // ensures that the private field is not printed. + // + //const ARRAY0: [u8; Struct { private: () } + Self::ABSTRACT]; + + // This assoc. const could leak the private assoc. function `Struct::new`. + // Ensure that this does not happen. + // + // @has - '//*[@id="associatedconstant.ARRAY1"]' \ + // 'const ARRAY1: [u8; { _ }]' + const ARRAY1: [u8; Struct::new(/* ... */) + Self::ABSTRACT * 1_000]; + + // @has - '//*[@id="associatedconstant.VERBOSE"]' \ + // 'const VERBOSE: [u16; { _ }]' + const VERBOSE: [u16; compute("thing", 9 + 9) * Self::ABSTRACT]; + + // Check that we do not leak the private struct field contained within + // the path. The output could definitely be improved upon + // (e.g. printing sth. akin to `<Self as Helper<{ _ }>>::OUT`) but + // right now “safe is safe”. + // + // @has - '//*[@id="associatedconstant.PATH"]' \ + // 'const PATH: usize = _' + const PATH: usize = <Self as Helper<{ Struct { private: () } }>>::OUT; +} + +const fn compute(input: &str, extra: usize) -> usize { + input.len() + extra +} + +pub trait Helper<const S: Struct> { + const OUT: usize; +} + +impl<const S: Struct, St: Stage + ?Sized> Helper<S> for St { + const OUT: usize = St::ABSTRACT; +} + +// Currently in rustdoc, const arguments are not evaluated in this position +// and therefore they fall under the realm of `print_const_expr`. +// If rustdoc gets patched to evaluate const arguments, it is fine to replace +// this test as long as one can ensure that private fields are not leaked! +// +// @has hide_complex_unevaluated_const_arguments/trait.Sub.html \ +// '//*[@class="rust trait"]' \ +// 'pub trait Sub: Sup<{ _ }, { _ }> { }' +pub trait Sub: Sup<{ 90 * 20 * 4 }, { Struct { private: () } }> {} + +pub trait Sup<const N: usize, const S: Struct> {} + +pub struct Struct { private: () } + +impl Struct { + const fn new() -> Self { Self { private: () } } +} + +impl const std::ops::Add<usize> for Struct { + type Output = usize; + + fn add(self, _: usize) -> usize { 0 } +} diff --git a/src/test/rustdoc/hide-complex-unevaluated-consts.rs b/src/test/rustdoc/hide-complex-unevaluated-consts.rs new file mode 100644 index 000000000..ba623246a --- /dev/null +++ b/src/test/rustdoc/hide-complex-unevaluated-consts.rs @@ -0,0 +1,71 @@ +// Regression test for issue #97933. +// +// Test that certain unevaluated constant expressions that are +// deemed too verbose or complex and that may leak private or +// `doc(hidden)` struct fields are not displayed in the documentation. +// +// Read the documentation of `rustdoc::clean::utils::print_const_expr` +// for further details. + +// @has hide_complex_unevaluated_consts/trait.Container.html +pub trait Container { + // A helper constant that prevents const expressions containing it + // from getting fully evaluated since it doesn't have a body and + // thus is non-reducible. This allows us to specifically test the + // pretty-printing of *unevaluated* consts. + const ABSTRACT: i32; + + // Ensure that the private field does not get leaked: + // + // @has - '//*[@id="associatedconstant.STRUCT0"]' \ + // 'const STRUCT0: Struct = _' + const STRUCT0: Struct = Struct { private: () }; + + // @has - '//*[@id="associatedconstant.STRUCT1"]' \ + // 'const STRUCT1: (Struct,) = _' + const STRUCT1: (Struct,) = (Struct{private: /**/()},); + + // Although the struct field is public here, check that it is not + // displayed. In a future version of rustdoc, we definitely want to + // show it. However for the time being, the printing logic is a bit + // conservative. + // + // @has - '//*[@id="associatedconstant.STRUCT2"]' \ + // 'const STRUCT2: Record = _' + const STRUCT2: Record = Record { public: 5 }; + + // Test that we do not show the incredibly verbose match expr: + // + // @has - '//*[@id="associatedconstant.MATCH0"]' \ + // 'const MATCH0: i32 = _' + const MATCH0: i32 = match 234 { + 0 => 1, + _ => Self::ABSTRACT, + }; + + // @has - '//*[@id="associatedconstant.MATCH1"]' \ + // 'const MATCH1: bool = _' + const MATCH1: bool = match Self::ABSTRACT { + _ => true, + }; + + // Check that we hide complex (arithmetic) operations. + // In this case, it is a bit unfortunate since the expression + // is not *that* verbose and it might be quite useful to the reader. + // + // However in general, the expression might be quite large and + // contain match expressions and structs with private fields. + // We would need to recurse over the whole expression and even more + // importantly respect operator precedence when pretty-printing + // the potentially partially censored expression. + // For now, the implementation is quite simple and the choices + // rather conservative. + // + // @has - '//*[@id="associatedconstant.ARITH_OPS"]' \ + // 'const ARITH_OPS: i32 = _' + const ARITH_OPS: i32 = Self::ABSTRACT * 2 + 1; +} + +pub struct Struct { private: () } + +pub struct Record { pub public: i32 } diff --git a/src/test/rustdoc/hide-unstable-trait.rs b/src/test/rustdoc/hide-unstable-trait.rs new file mode 100644 index 000000000..c30d6ed7b --- /dev/null +++ b/src/test/rustdoc/hide-unstable-trait.rs @@ -0,0 +1,11 @@ +// aux-build:unstable-trait.rs + +#![crate_name = "foo"] +#![feature(private_trait)] + +extern crate unstable_trait; + +// @has foo/struct.Foo.html 'bar' +// @has foo/struct.Foo.html 'bar2' +#[doc(inline)] +pub use unstable_trait::Foo; diff --git a/src/test/rustdoc/higher-ranked-trait-bounds.rs b/src/test/rustdoc/higher-ranked-trait-bounds.rs new file mode 100644 index 000000000..b75b8de52 --- /dev/null +++ b/src/test/rustdoc/higher-ranked-trait-bounds.rs @@ -0,0 +1,61 @@ +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +pub trait Trait<'x> {} + +// @has foo/fn.test1.html +// @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator," +pub fn test1<T>() +where + for<'a> &'a T: Iterator, +{ +} + +// @has foo/fn.test2.html +// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: Trait<'b>," +pub fn test2<T>() +where + for<'a, 'b> &'a T: Trait<'b>, +{ +} + +// @has foo/fn.test3.html +// @has - '//pre' "pub fn test3<F>() where F: for<'a, 'b> Fn(&'a u8, &'b u8)," +pub fn test3<F>() +where + F: for<'a, 'b> Fn(&'a u8, &'b u8), +{ +} + +// @has foo/struct.Foo.html +pub struct Foo<'a> { + _x: &'a u8, + pub some_trait: &'a dyn for<'b> Trait<'b>, + pub some_func: for<'c> fn(val: &'c i32) -> i32, +} + +// @has - '//span[@id="structfield.some_func"]' "some_func: for<'c> fn(val: &'c i32) -> i32" +// @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>" + +impl<'a> Foo<'a> { + // @has - '//h4[@class="code-header"]' "pub fn bar<T>() where T: Trait<'a>," + pub fn bar<T>() + where + T: Trait<'a>, + { + } +} + +// @has foo/trait.B.html +pub trait B<'x> {} + +// @has - '//h3[@class="code-header in-band"]' "impl<'a> B<'a> for dyn for<'b> Trait<'b>" +impl<'a> B<'a> for dyn for<'b> Trait<'b> {} + +// @has foo/struct.Bar.html +// @has - '//span[@id="structfield.bar"]' "bar: &'a (dyn for<'b> Trait<'b> + Unpin)" +// @has - '//span[@id="structfield.baz"]' "baz: &'a (dyn Unpin + for<'b> Trait<'b>)" +pub struct Bar<'a> { + pub bar: &'a (dyn for<'b> Trait<'b> + Unpin), + pub baz: &'a (dyn Unpin + for<'b> Trait<'b>), +} diff --git a/src/test/rustdoc/impl-box.rs b/src/test/rustdoc/impl-box.rs new file mode 100644 index 000000000..592b6c985 --- /dev/null +++ b/src/test/rustdoc/impl-box.rs @@ -0,0 +1,16 @@ +// https://github.com/rust-lang/rust/issues/92940 +// +// Show traits implemented on fundamental types that wrap local ones. + +pub struct MyType; + +// @has 'impl_box/struct.MyType.html' +// @has '-' '//*[@id="impl-Iterator-for-Box%3CMyType%3E"]' 'impl Iterator for Box<MyType>' + +impl Iterator for Box<MyType> { + type Item = (); + + fn next(&mut self) -> Option<Self::Item> { + todo!() + } +} diff --git a/src/test/rustdoc/impl-disambiguation.rs b/src/test/rustdoc/impl-disambiguation.rs new file mode 100644 index 000000000..d1d39ccff --- /dev/null +++ b/src/test/rustdoc/impl-disambiguation.rs @@ -0,0 +1,30 @@ +#![crate_name = "foo"] + +pub trait Foo {} + +pub struct Bar<T> { field: T } + +// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \ +// "impl Foo for Bar<u8>" +impl Foo for Bar<u8> {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \ +// "impl Foo for Bar<u16>" +impl Foo for Bar<u16> {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \ +// "impl<'a> Foo for &'a Bar<u8>" +impl<'a> Foo for &'a Bar<u8> {} + +pub mod mod1 { + pub struct Baz {} +} + +pub mod mod2 { + pub enum Baz {} +} + +// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \ +// "impl Foo for foo::mod1::Baz" +impl Foo for mod1::Baz {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \ +// "impl<'a> Foo for &'a foo::mod2::Baz" +impl<'a> Foo for &'a mod2::Baz {} diff --git a/src/test/rustdoc/impl-everywhere.rs b/src/test/rustdoc/impl-everywhere.rs new file mode 100644 index 000000000..44885d430 --- /dev/null +++ b/src/test/rustdoc/impl-everywhere.rs @@ -0,0 +1,30 @@ +#![crate_name = "foo"] + +pub trait Foo {} +pub trait Foo2 {} + +pub struct Bar; + +impl Foo for Bar {} +impl Foo2 for Bar {} + +// @has foo/fn.foo.html '//section[@id="main-content"]//pre' "x: &'x impl Foo" +// @has foo/fn.foo.html '//section[@id="main-content"]//pre' "-> &'x impl Foo" +pub fn foo<'x>(x: &'x impl Foo) -> &'x impl Foo { + x +} + +// @has foo/fn.foo2.html '//section[@id="main-content"]//pre' "x: &'x impl Foo" +// @has foo/fn.foo2.html '//section[@id="main-content"]//pre' '-> impl Foo2' +pub fn foo2<'x>(_x: &'x impl Foo) -> impl Foo2 { + Bar +} + +// @has foo/fn.foo_foo.html '//section[@id="main-content"]//pre' '-> impl Foo + Foo2' +pub fn foo_foo() -> impl Foo + Foo2 { + Bar +} + +// @has foo/fn.foo_foo_foo.html '//section[@id="main-content"]//pre' "x: &'x impl Foo + Foo2" +pub fn foo_foo_foo<'x>(_x: &'x (impl Foo + Foo2)) { +} diff --git a/src/test/rustdoc/impl-parts-crosscrate.rs b/src/test/rustdoc/impl-parts-crosscrate.rs new file mode 100644 index 000000000..6c5e79d5a --- /dev/null +++ b/src/test/rustdoc/impl-parts-crosscrate.rs @@ -0,0 +1,20 @@ +// aux-build:rustdoc-impl-parts-crosscrate.rs +// ignore-cross-compile + +#![feature(negative_impls)] + +extern crate rustdoc_impl_parts_crosscrate; + +pub struct Bar<T> { t: T } + +// The output file is html embedded in javascript, so the html tags +// aren't stripped by the processing script and we can't check for the +// full impl string. Instead, just make sure something from each part +// is mentioned. + +// @has implementors/rustdoc_impl_parts_crosscrate/trait.AnAutoTrait.js Bar +// @has - Send +// @has - !AnAutoTrait +// @has - Copy +impl<T: Send> !rustdoc_impl_parts_crosscrate::AnAutoTrait for Bar<T> + where T: Copy {} diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs new file mode 100644 index 000000000..249158c1a --- /dev/null +++ b/src/test/rustdoc/impl-parts.rs @@ -0,0 +1,12 @@ +#![feature(negative_impls)] +#![feature(auto_traits)] + +pub auto trait AnAutoTrait {} + +pub struct Foo<T> { field: T } + +// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync," +// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \ +// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync," +impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync {} diff --git a/src/test/rustdoc/impl-trait-alias.rs b/src/test/rustdoc/impl-trait-alias.rs new file mode 100644 index 000000000..54c3f856d --- /dev/null +++ b/src/test/rustdoc/impl-trait-alias.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] + +trait MyTrait {} +impl MyTrait for i32 {} + +// @has impl_trait_alias/type.Foo.html 'Foo' +/// debug type +pub type Foo = impl MyTrait; + +// @has impl_trait_alias/fn.foo.html 'foo' +/// debug function +pub fn foo() -> Foo { + 1 +} diff --git a/src/test/rustdoc/implementor-stable-version.rs b/src/test/rustdoc/implementor-stable-version.rs new file mode 100644 index 000000000..a1f3fd5a8 --- /dev/null +++ b/src/test/rustdoc/implementor-stable-version.rs @@ -0,0 +1,21 @@ +#![stable(feature = "bar", since = "OLD 1.0")] +#![crate_name = "foo"] + +#![feature(staged_api)] + +#[stable(feature = "bar", since = "OLD 1.0")] +pub trait Bar {} + +#[stable(feature = "baz", since = "OLD 1.0")] +pub trait Baz {} + +#[stable(feature = "baz", since = "OLD 1.0")] +pub struct Foo; + +// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0' +#[stable(feature = "foobar", since = "NEW 2.0")] +impl Bar for Foo {} + +// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0' +#[stable(feature = "foobaz", since = "OLD 1.0")] +impl Baz for Foo {} diff --git a/src/test/rustdoc/include_str_cut.rs b/src/test/rustdoc/include_str_cut.rs new file mode 100644 index 000000000..cbc1ba8db --- /dev/null +++ b/src/test/rustdoc/include_str_cut.rs @@ -0,0 +1,7 @@ +#![crate_name = "foo"] +#![no_std] + +// @has 'foo/fn.foo.html' +// @has - '//*[@class="docblock"]' 'inc2 x' +#[doc = include_str!("short-line.md")] +pub fn foo() {} diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs new file mode 100644 index 000000000..be668a127 --- /dev/null +++ b/src/test/rustdoc/index-page.rs @@ -0,0 +1,11 @@ +// aux-build:all-item-types.rs +// build-aux-docs +// compile-flags: -Z unstable-options --enable-index-page + +#![crate_name = "foo"] + +// @has foo/../index.html +// @has - '//span[@class="in-band"]' 'List of all crates' +// @has - '//ul[@class="crate mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="crate mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' +pub struct Foo; diff --git a/src/test/rustdoc/infinite-redirection.rs b/src/test/rustdoc/infinite-redirection.rs new file mode 100644 index 000000000..96a43323c --- /dev/null +++ b/src/test/rustdoc/infinite-redirection.rs @@ -0,0 +1,29 @@ +#![crate_name = "foo"] + +// This test ensures that there is no "infinite redirection" file generated (a +// file which redirects to itself). + +// We check it's not a redirection file. +// @has 'foo/builders/struct.ActionRowBuilder.html' +// @has - '//*[@id="synthetic-implementations"]' 'Auto Trait Implementations' + +// And that the link in the module is targetting it. +// @has 'foo/builders/index.html' +// @has - '//a[@href="struct.ActionRowBuilder.html"]' 'ActionRowBuilder' + +mod auto { + mod action_row { + pub struct ActionRowBuilder; + } + + #[doc(hidden)] + pub mod builders { + pub use super::action_row::ActionRowBuilder; + } +} + +pub use auto::*; + +pub mod builders { + pub use crate::auto::builders::*; +} diff --git a/src/test/rustdoc/inline-default-methods.rs b/src/test/rustdoc/inline-default-methods.rs new file mode 100644 index 000000000..c97644e7f --- /dev/null +++ b/src/test/rustdoc/inline-default-methods.rs @@ -0,0 +1,9 @@ +// aux-build:inline-default-methods.rs +// ignore-cross-compile + +extern crate inline_default_methods; + +// @has inline_default_methods/trait.Foo.html +// @has - '//*[@class="rust trait"]' 'fn bar(&self);' +// @has - '//*[@class="rust trait"]' 'fn foo(&mut self) { ... }' +pub use inline_default_methods::Foo; diff --git a/src/test/rustdoc/inline_cross/add-docs.rs b/src/test/rustdoc/inline_cross/add-docs.rs new file mode 100644 index 000000000..8f0c4e5e6 --- /dev/null +++ b/src/test/rustdoc/inline_cross/add-docs.rs @@ -0,0 +1,9 @@ +// aux-build:add-docs.rs + +extern crate inner; + + +// @has add_docs/struct.MyStruct.html +// @has add_docs/struct.MyStruct.html "Doc comment from ‘pub use’, Doc comment from definition" +/// Doc comment from 'pub use', +pub use inner::MyStruct; diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs new file mode 100644 index 000000000..231805a52 --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc-items.rs @@ -0,0 +1,42 @@ +// aux-build:assoc-items.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +extern crate assoc_items; + +// @has foo/struct.MyStruct.html +// @!has - 'PrivateConst' +// @has - '//*[@id="associatedconstant.PublicConst"]' 'pub const PublicConst: u8' +// @has - '//*[@class="docblock"]' 'docs for PublicConst' +// @!has - 'private_method' +// @has - '//*[@id="method.public_method"]' 'pub fn public_method()' +// @has - '//*[@class="docblock"]' 'docs for public_method' +// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16' +// @has - '//*[@class="docblock"]' 'dox for ConstNoDefault' +// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16' +// @has - '//div[@class="docblock"]' 'docs for ConstWithDefault' +// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32' +// @has - '//*[@class="docblock"]' 'dox for TypeNoDefault' +// @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32' +// @has - '//div[@class="docblock"]' 'docs for TypeWithDefault' +// @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()' +// @has - '//*[@class="docblock"]' 'dox for method_no_default' +// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()' +// @has - '//div[@class="docblock"]' 'docs for method_with_default' +pub use assoc_items::MyStruct; + +// @has foo/trait.MyTrait.html +// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16' +// @has - '//*[@class="docblock"]' 'docs for ConstNoDefault' +// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16' +// @has - '//*[@class="docblock"]' 'docs for ConstWithDefault' +// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault' +// @has - '//*[@class="docblock"]' 'docs for TypeNoDefault' +// @has - '//*[@class="docblock"]' 'docs for TypeWithDefault' +// @has - '//*[@id="tymethod.method_no_default"]' 'fn method_no_default()' +// @has - '//*[@class="docblock"]' 'docs for method_no_default' +// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()' +// @has - '//*[@class="docblock"]' 'docs for method_with_default' +pub use assoc_items::MyTrait; diff --git a/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs b/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs new file mode 100644 index 000000000..85efa508f --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/add-docs.rs @@ -0,0 +1,4 @@ +#![crate_name = "inner"] + +/// Doc comment from definition +pub struct MyStruct; diff --git a/src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs b/src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs new file mode 100644 index 000000000..5fa299914 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs @@ -0,0 +1,38 @@ +#![feature(associated_type_defaults)] + +pub struct MyStruct; + +impl MyStruct { + /// docs for PrivateConst + const PrivateConst: i8 = -123; + /// docs for PublicConst + pub const PublicConst: u8 = 123; + /// docs for private_method + fn private_method() {} + /// docs for public_method + pub fn public_method() {} +} + +pub trait MyTrait { + /// docs for ConstNoDefault + const ConstNoDefault: i16; + /// docs for ConstWithDefault + const ConstWithDefault: u16 = 12345; + /// docs for TypeNoDefault + type TypeNoDefault; + /// docs for TypeWithDefault + type TypeWithDefault = u32; + /// docs for method_no_default + fn method_no_default(); + /// docs for method_with_default + fn method_with_default() {} +} + +impl MyTrait for MyStruct { + /// dox for ConstNoDefault + const ConstNoDefault: i16 = -12345; + /// dox for TypeNoDefault + type TypeNoDefault = i32; + /// dox for method_no_default + fn method_no_default() {} +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/cross-glob.rs b/src/test/rustdoc/inline_cross/auxiliary/cross-glob.rs new file mode 100644 index 000000000..cde7f68ff --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/cross-glob.rs @@ -0,0 +1,5 @@ +#![crate_name = "inner"] + +pub struct SomeStruct; + +pub fn some_fn() {} diff --git a/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs b/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs new file mode 100644 index 000000000..ce60bbfb4 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/default-trait-method.rs @@ -0,0 +1,16 @@ +#![feature(specialization)] + +#![crate_name = "foo"] + +pub trait Item { + fn foo(); + fn bar(); + fn baz() {} +} + +pub struct Foo; + +impl Item for Foo { + default fn foo() {} + fn bar() {} +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs new file mode 100644 index 000000000..401a6a44a --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs @@ -0,0 +1,8 @@ +pub trait MyTrait { + /// docs for my_trait_method + fn my_trait_method() {} +} + +pub struct MyStruct; + +impl MyTrait for MyStruct {} diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs new file mode 100644 index 000000000..913ba8f2a --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -0,0 +1,28 @@ +// edition:2018 + +use std::ops::Deref; + +pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {} + +pub fn func2<T>( + _x: impl Deref<Target = Option<T>> + Iterator<Item = T>, + _y: impl Iterator<Item = u8>, +) {} + +pub fn func3(_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone) {} + +pub fn func4<T: Iterator<Item = impl Clone>>(_x: T) {} + +pub async fn async_fn() {} + +pub struct Foo; + +impl Foo { + pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {} +} + +pub struct Bar; + +impl Bar { + pub async fn async_foo(&self) {} +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs new file mode 100644 index 000000000..b003fb357 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs @@ -0,0 +1,18 @@ +pub mod my_trait { + pub trait MyTrait { + fn my_fn(&self) -> Self; + } +} + +pub mod prelude { + #[doc(inline)] + pub use crate::my_trait::MyTrait; +} + +pub struct SomeStruct; + +impl my_trait::MyTrait for SomeStruct { + fn my_fn(&self) -> SomeStruct { + SomeStruct + } +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/issue-33113.rs b/src/test/rustdoc/inline_cross/auxiliary/issue-33113.rs new file mode 100644 index 000000000..4e1f1918e --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/issue-33113.rs @@ -0,0 +1,7 @@ +#![crate_name="bar"] + +pub trait Bar {} +pub struct Foo; + +impl<'a> Bar for &'a char {} +impl Bar for Foo {} diff --git a/src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs b/src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs new file mode 100644 index 000000000..5615a4fdd --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/macro-vis.rs @@ -0,0 +1,25 @@ +#![crate_name = "qwop"] + +/// (written on a spider's web) Some Macro +#[macro_export] +macro_rules! some_macro { + () => { + println!("this is some macro, for sure"); + }; +} + +/// Some other macro, to fill space. +#[macro_export] +macro_rules! other_macro { + () => { + println!("this is some other macro, whatev"); + }; +} + +/// This macro is so cool, it's Super. +#[macro_export] +macro_rules! super_macro { + () => { + println!("is it a bird? a plane? no, it's Super Macro!"); + }; +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/macros.rs b/src/test/rustdoc/inline_cross/auxiliary/macros.rs new file mode 100644 index 000000000..651ae2f1a --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/macros.rs @@ -0,0 +1,10 @@ +#![feature(staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +/// docs for my_macro +#[unstable(feature = "macro_test", issue = "none")] +#[deprecated(since = "1.2.3", note = "text")] +#[macro_export] +macro_rules! my_macro { + () => {}; +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs new file mode 100644 index 000000000..d8e5746f3 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs @@ -0,0 +1,47 @@ +// force-host +// no-prefer-dynamic +// compile-flags: --crate-type proc-macro + +#![crate_type="proc-macro"] +#![crate_name="some_macros"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +macro_rules! make_attr_macro { + ($name:ident) => { + /// Generated doc comment + #[proc_macro_attribute] + pub fn $name(args: TokenStream, input: TokenStream) -> TokenStream { + panic!() + } + } +} + +make_attr_macro!(first_attr); +make_attr_macro!(second_attr); + +/// a proc-macro that swallows its input and does nothing. +#[proc_macro] +pub fn some_proc_macro(_input: TokenStream) -> TokenStream { + TokenStream::new() +} + +/// a proc-macro attribute that passes its item through verbatim. +#[proc_macro_attribute] +pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} + +/// a derive attribute that adds nothing to its input. +#[proc_macro_derive(SomeDerive)] +pub fn some_derive(_item: TokenStream) -> TokenStream { + TokenStream::new() +} + +/// Doc comment from the original crate +#[proc_macro] +pub fn reexported_macro(_input: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/renamed-via-module.rs b/src/test/rustdoc/inline_cross/auxiliary/renamed-via-module.rs new file mode 100644 index 000000000..2e5290782 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/renamed-via-module.rs @@ -0,0 +1,9 @@ +#![crate_name = "foo"] + +pub mod iter { + mod range { + pub struct StepBy; + } + pub use self::range::StepBy as DeprecatedStepBy; + pub struct StepBy; +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs new file mode 100644 index 000000000..6357b76df --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs @@ -0,0 +1,12 @@ +pub struct Bar; + +impl Bar { + pub fn bar(_: u8) -> hidden::Hidden { + hidden::Hidden + } +} + +#[doc(hidden)] +pub mod hidden { + pub struct Hidden; +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs new file mode 100644 index 000000000..0c75b3127 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs @@ -0,0 +1,4 @@ +#[doc(hidden)] +pub struct Foo; + +pub struct Bar; diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs new file mode 100644 index 000000000..4e461d3bc --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs @@ -0,0 +1,34 @@ +pub struct Foo; + +pub trait Woof {} +pub trait Bark {} + +mod private { + // should be shown + impl ::Woof for ::Foo {} + + pub trait Bar {} + pub struct Wibble; + + // these should not be shown + impl Bar for ::Foo {} + impl Bar for Wibble {} + impl ::Bark for Wibble {} + impl ::Woof for Wibble {} +} + +#[doc(hidden)] +pub mod hidden { + // should be shown + impl ::Bark for ::Foo {} + + pub trait Qux {} + pub struct Wobble; + + + // these should only be shown if they're re-exported correctly + impl Qux for ::Foo {} + impl Qux for Wobble {} + impl ::Bark for Wobble {} + impl ::Woof for Wobble {} +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs new file mode 100644 index 000000000..11d8733c4 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs @@ -0,0 +1,13 @@ +use std::fmt; + +pub trait Bar {} + +impl<'a> Bar + 'a { + pub fn bar(&self) -> usize { 42 } +} + +impl<'a> fmt::Debug for Bar + 'a { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs b/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs new file mode 100644 index 000000000..e5bc7969b --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/trait-vis.rs @@ -0,0 +1,13 @@ +#![crate_name = "inner"] + +pub struct SomeStruct; + +fn asdf() { + const _FOO: () = { + impl Clone for SomeStruct { + fn clone(&self) -> Self { + SomeStruct + } + } + }; +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs new file mode 100644 index 000000000..75efbe0db --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate.rs @@ -0,0 +1,5 @@ +pub mod asdf { + pub struct SomeStruct; +} + +pub trait SomeTrait {} diff --git a/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs new file mode 100644 index 000000000..25b4c202e --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/use_crate_2.rs @@ -0,0 +1 @@ +pub struct SomethingElse; diff --git a/src/test/rustdoc/inline_cross/cross-glob.rs b/src/test/rustdoc/inline_cross/cross-glob.rs new file mode 100644 index 000000000..f97da11a9 --- /dev/null +++ b/src/test/rustdoc/inline_cross/cross-glob.rs @@ -0,0 +1,11 @@ +// aux-build:cross-glob.rs +// build-aux-docs +// ignore-cross-compile + +extern crate inner; + +// @has cross_glob/struct.SomeStruct.html +// @has cross_glob/fn.some_fn.html +// @!has cross_glob/index.html '//code' 'pub use inner::*;' +#[doc(inline)] +pub use inner::*; diff --git a/src/test/rustdoc/inline_cross/default-trait-method.rs b/src/test/rustdoc/inline_cross/default-trait-method.rs new file mode 100644 index 000000000..a4ec73a12 --- /dev/null +++ b/src/test/rustdoc/inline_cross/default-trait-method.rs @@ -0,0 +1,20 @@ +// aux-build:default-trait-method.rs + +extern crate foo; + +// @has default_trait_method/trait.Item.html +// @has - '//*[@id="tymethod.foo"]' 'fn foo()' +// @!has - '//*[@id="tymethod.foo"]' 'default fn foo()' +// @has - '//*[@id="tymethod.bar"]' 'fn bar()' +// @!has - '//*[@id="tymethod.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub use foo::Item; + +// @has default_trait_method/struct.Foo.html +// @has - '//*[@id="method.foo"]' 'default fn foo()' +// @has - '//*[@id="method.bar"]' 'fn bar()' +// @!has - '//*[@id="method.bar"]' 'default fn bar()' +// @has - '//*[@id="method.baz"]' 'fn baz()' +// @!has - '//*[@id="method.baz"]' 'default fn baz()' +pub use foo::Foo; diff --git a/src/test/rustdoc/inline_cross/hidden-use.rs b/src/test/rustdoc/inline_cross/hidden-use.rs new file mode 100644 index 000000000..97715737f --- /dev/null +++ b/src/test/rustdoc/inline_cross/hidden-use.rs @@ -0,0 +1,12 @@ +// aux-build:rustdoc-hidden.rs +// build-aux-docs +// ignore-cross-compile + +extern crate rustdoc_hidden; + +// @has hidden_use/index.html +// @!has - 'rustdoc_hidden' +// @!has - 'Bar' +// @!has hidden_use/struct.Bar.html +#[doc(hidden)] +pub use rustdoc_hidden::Bar; diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs new file mode 100644 index 000000000..9b67022fd --- /dev/null +++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs @@ -0,0 +1,12 @@ +// aux-build:impl-inline-without-trait.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +extern crate impl_inline_without_trait; + +// @has 'foo/struct.MyStruct.html' +// @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()' +// @has - '//div[@class="docblock"]' 'docs for my_trait_method' +pub use impl_inline_without_trait::MyStruct; diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs new file mode 100644 index 000000000..ef615472b --- /dev/null +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -0,0 +1,40 @@ +// aux-build:impl_trait_aux.rs +// edition:2018 + +extern crate impl_trait_aux; + +// @has impl_trait/fn.func.html +// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func; + +// @has impl_trait/fn.func2.html +// @has - '//pre[@class="rust fn"]' "func2<T>(" +// @has - '//pre[@class="rust fn"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>," +// @has - '//pre[@class="rust fn"]' "_y: impl Iterator<Item = u8>)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func2; + +// @has impl_trait/fn.func3.html +// @has - '//pre[@class="rust fn"]' "func3(" +// @has - '//pre[@class="rust fn"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func3; + +// @has impl_trait/fn.func4.html +// @has - '//pre[@class="rust fn"]' "func4<T>(" +// @has - '//pre[@class="rust fn"]' "T: Iterator<Item = impl Clone>," +pub use impl_trait_aux::func4; + +// @has impl_trait/fn.async_fn.html +// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()" +pub use impl_trait_aux::async_fn; + +// @has impl_trait/struct.Foo.html +// @has - '//*[@id="method.method"]//h4[@class="code-header"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)" +// @!has - '//*[@id="method.method"]//h4[@class="code-header"]' 'where' +pub use impl_trait_aux::Foo; + +// @has impl_trait/struct.Bar.html +// @has - '//*[@id="method.async_foo"]' "pub async fn async_foo(" +pub use impl_trait_aux::Bar; diff --git a/src/test/rustdoc/inline_cross/implementors-js.rs b/src/test/rustdoc/inline_cross/implementors-js.rs new file mode 100644 index 000000000..c79f05d8d --- /dev/null +++ b/src/test/rustdoc/inline_cross/implementors-js.rs @@ -0,0 +1,25 @@ +// aux-build:implementors_inline.rs +// build-aux-docs +// ignore-cross-compile + +extern crate implementors_inline; + +// @!has implementors/implementors_js/trait.MyTrait.js +// @has implementors/implementors_inline/my_trait/trait.MyTrait.js +// @!has implementors/implementors_inline/prelude/trait.MyTrait.js +// @has implementors_inline/my_trait/trait.MyTrait.html +// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js' +// @has implementors_js/trait.MyTrait.html +// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js' +/// When re-exporting this trait, the HTML will be inlined, +/// but, vitally, the JavaScript will be located only at the +/// one canonical path. +pub use implementors_inline::prelude::MyTrait; + +pub struct OtherStruct; + +impl MyTrait for OtherStruct { + fn my_fn(&self) -> OtherStruct { + OtherStruct + } +} diff --git a/src/test/rustdoc/inline_cross/inline_hidden.rs b/src/test/rustdoc/inline_cross/inline_hidden.rs new file mode 100644 index 000000000..dcceaadb9 --- /dev/null +++ b/src/test/rustdoc/inline_cross/inline_hidden.rs @@ -0,0 +1,12 @@ +// aux-build:rustdoc-hidden.rs +// build-aux-docs +// ignore-cross-compile + +extern crate rustdoc_hidden; + +#[doc(no_inline)] +pub use rustdoc_hidden::Foo; + +// @has inline_hidden/fn.foo.html +// @!has - '//a/@title' 'Foo' +pub fn foo(_: Foo) {} diff --git a/src/test/rustdoc/inline_cross/issue-28480.rs b/src/test/rustdoc/inline_cross/issue-28480.rs new file mode 100644 index 000000000..99f5b9007 --- /dev/null +++ b/src/test/rustdoc/inline_cross/issue-28480.rs @@ -0,0 +1,13 @@ +// aux-build:rustdoc-hidden-sig.rs +// build-aux-docs +// ignore-cross-compile + +// @has rustdoc_hidden_sig/struct.Bar.html +// @!has - '//a/@title' 'Hidden' +// @has - '//a' 'u8' +extern crate rustdoc_hidden_sig; + +// @has issue_28480/struct.Bar.html +// @!has - '//a/@title' 'Hidden' +// @has - '//a' 'u8' +pub use rustdoc_hidden_sig::Bar; diff --git a/src/test/rustdoc/inline_cross/issue-31948-1.rs b/src/test/rustdoc/inline_cross/issue-31948-1.rs new file mode 100644 index 000000000..be8585dd1 --- /dev/null +++ b/src/test/rustdoc/inline_cross/issue-31948-1.rs @@ -0,0 +1,27 @@ +// aux-build:rustdoc-nonreachable-impls.rs +// build-aux-docs +// ignore-cross-compile + +extern crate rustdoc_nonreachable_impls; + +// @has issue_31948_1/struct.Wobble.html +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for' +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for' +// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for' +// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for' +pub use rustdoc_nonreachable_impls::hidden::Wobble; + +// @has issue_31948_1/trait.Bark.html +// @has - '//h3[@class="code-header in-band"]' 'for Foo' +// @has - '//h3[@class="code-header in-band"]' 'for Wobble' +// @!has - '//h3[@class="code-header in-band"]' 'for Wibble' +pub use rustdoc_nonreachable_impls::Bark; + +// @has issue_31948_1/trait.Woof.html +// @has - '//h3[@class="code-header in-band"]' 'for Foo' +// @has - '//h3[@class="code-header in-band"]' 'for Wobble' +// @!has - '//h3[@class="code-header in-band"]' 'for Wibble' +pub use rustdoc_nonreachable_impls::Woof; + +// @!has issue_31948_1/trait.Bar.html +// @!has issue_31948_1/trait.Qux.html diff --git a/src/test/rustdoc/inline_cross/issue-31948-2.rs b/src/test/rustdoc/inline_cross/issue-31948-2.rs new file mode 100644 index 000000000..7aa994f19 --- /dev/null +++ b/src/test/rustdoc/inline_cross/issue-31948-2.rs @@ -0,0 +1,21 @@ +// aux-build:rustdoc-nonreachable-impls.rs +// build-aux-docs +// ignore-cross-compile + +extern crate rustdoc_nonreachable_impls; + +// @has issue_31948_2/struct.Wobble.html +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Qux for' +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for' +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for' +// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Bar for' +pub use rustdoc_nonreachable_impls::hidden::Wobble; + +// @has issue_31948_2/trait.Qux.html +// @has - '//h3[@class="code-header in-band"]' 'for Foo' +// @has - '//h3[@class="code-header in-band"]' 'for Wobble' +pub use rustdoc_nonreachable_impls::hidden::Qux; + +// @!has issue_31948_2/trait.Bar.html +// @!has issue_31948_2/trait.Woof.html +// @!has issue_31948_2/trait.Bark.html diff --git a/src/test/rustdoc/inline_cross/issue-31948.rs b/src/test/rustdoc/inline_cross/issue-31948.rs new file mode 100644 index 000000000..7bf4110d3 --- /dev/null +++ b/src/test/rustdoc/inline_cross/issue-31948.rs @@ -0,0 +1,29 @@ +// aux-build:rustdoc-nonreachable-impls.rs +// build-aux-docs +// ignore-cross-compile + +extern crate rustdoc_nonreachable_impls; + +// @has issue_31948/struct.Foo.html +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bark for' +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Woof for' +// @!has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'Bar for' +// @!has - '//*[@class="impl"]//h3[@class="code-header in-band"]' 'Qux for' +pub use rustdoc_nonreachable_impls::Foo; + +// @has issue_31948/trait.Bark.html +// @has - '//h3[@class="code-header in-band"]' 'for Foo' +// @!has - '//h3[@class="code-header in-band"]' 'for Wibble' +// @!has - '//h3[@class="code-header in-band"]' 'for Wobble' +pub use rustdoc_nonreachable_impls::Bark; + +// @has issue_31948/trait.Woof.html +// @has - '//h3[@class="code-header in-band"]' 'for Foo' +// @!has - '//h3[@class="code-header in-band"]' 'for Wibble' +// @!has - '//h3[@class="code-header in-band"]' 'for Wobble' +pub use rustdoc_nonreachable_impls::Woof; + +// @!has issue_31948/trait.Bar.html +// @!has issue_31948/trait.Qux.html +// @!has issue_31948/struct.Wibble.html +// @!has issue_31948/struct.Wobble.html diff --git a/src/test/rustdoc/inline_cross/issue-32881.rs b/src/test/rustdoc/inline_cross/issue-32881.rs new file mode 100644 index 000000000..8052339a8 --- /dev/null +++ b/src/test/rustdoc/inline_cross/issue-32881.rs @@ -0,0 +1,11 @@ +// aux-build:rustdoc-trait-object-impl.rs +// build-aux-docs +// ignore-cross-compile + +extern crate rustdoc_trait_object_impl; + +// @has issue_32881/trait.Bar.html +// @has - '//h3[@class="code-header in-band"]' "impl<'a> dyn Bar" +// @has - '//h3[@class="code-header in-band"]' "impl<'a> Debug for dyn Bar" + +pub use rustdoc_trait_object_impl::Bar; diff --git a/src/test/rustdoc/inline_cross/issue-33113.rs b/src/test/rustdoc/inline_cross/issue-33113.rs new file mode 100644 index 000000000..c60859bbc --- /dev/null +++ b/src/test/rustdoc/inline_cross/issue-33113.rs @@ -0,0 +1,10 @@ +// aux-build:issue-33113.rs +// build-aux-docs +// ignore-cross-compile + +extern crate bar; + +// @has issue_33113/trait.Bar.html +// @has - '//h3[@class="code-header in-band"]' "for &'a char" +// @has - '//h3[@class="code-header in-band"]' "for Foo" +pub use bar::Bar; diff --git a/src/test/rustdoc/inline_cross/macro-vis.rs b/src/test/rustdoc/inline_cross/macro-vis.rs new file mode 100644 index 000000000..9fefd38ad --- /dev/null +++ b/src/test/rustdoc/inline_cross/macro-vis.rs @@ -0,0 +1,36 @@ +// aux-build:macro-vis.rs +// build-aux-docs +// ignore-cross-compile + +#[macro_use] extern crate qwop; + +// @has macro_vis/macro.some_macro.html +// @has macro_vis/index.html '//a/@href' 'macro.some_macro.html' +pub use qwop::some_macro; + +// @has macro_vis/macro.renamed_macro.html +// @!has - '//pre' 'some_macro' +// @has macro_vis/index.html '//a/@href' 'macro.renamed_macro.html' +#[doc(inline)] +pub use qwop::some_macro as renamed_macro; + +// @!has macro_vis/macro.other_macro.html +// @!has macro_vis/index.html '//a/@href' 'macro.other_macro.html' +// @!has - '//code' 'pub use qwop::other_macro;' +#[doc(hidden)] +pub use qwop::other_macro; + +// @has macro_vis/index.html '//code' 'pub use qwop::super_macro;' +// @!has macro_vis/macro.super_macro.html +#[doc(no_inline)] +pub use qwop::super_macro; + +// @has macro_vis/macro.this_is_dope.html +// @has macro_vis/index.html '//a/@href' 'macro.this_is_dope.html' +/// What it says on the tin. +#[macro_export] +macro_rules! this_is_dope { + () => { + println!("yo check this out"); + }; +} diff --git a/src/test/rustdoc/inline_cross/macros.rs b/src/test/rustdoc/inline_cross/macros.rs new file mode 100644 index 000000000..5daa0d4ba --- /dev/null +++ b/src/test/rustdoc/inline_cross/macros.rs @@ -0,0 +1,19 @@ +// aux-build:macros.rs +// build-aux-docs + +#![feature(macro_test)] +#![crate_name = "foo"] + +extern crate macros; + +// @has foo/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \ +// Deprecated +// @has - '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \ +// Experimental + +// @has foo/macro.my_macro.html +// @has - '//*[@class="docblock"]' 'docs for my_macro' +// @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text' +// @has - '//*[@class="stab unstable"]' 'macro_test' +// @has - '//a/@href' '../src/macros/macros.rs.html#8' +pub use macros::my_macro; diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs new file mode 100644 index 000000000..532a295c0 --- /dev/null +++ b/src/test/rustdoc/inline_cross/proc_macro.rs @@ -0,0 +1,36 @@ +// aux-build:proc_macro.rs +// build-aux-docs + +extern crate some_macros; + +// @has proc_macro/index.html +// @has - '//a/@href' 'macro.some_proc_macro.html' +// @has - '//a/@href' 'attr.some_proc_attr.html' +// @has - '//a/@href' 'derive.SomeDerive.html' +// @has proc_macro/macro.some_proc_macro.html +// @has proc_macro/attr.some_proc_attr.html +// @has proc_macro/derive.SomeDerive.html + +// @has proc_macro/macro.some_proc_macro.html +// @has - 'a proc-macro that swallows its input and does nothing.' +pub use some_macros::some_proc_macro; + +// @has proc_macro/macro.reexported_macro.html +// @has - 'Doc comment from the original crate' +pub use some_macros::reexported_macro; + +// @has proc_macro/attr.some_proc_attr.html +// @has - 'a proc-macro attribute that passes its item through verbatim.' +pub use some_macros::some_proc_attr; + +// @has proc_macro/derive.SomeDerive.html +// @has - 'a derive attribute that adds nothing to its input.' +pub use some_macros::SomeDerive; + +// @has proc_macro/attr.first_attr.html +// @has - 'Generated doc comment' +pub use some_macros::first_attr; + +// @has proc_macro/attr.second_attr.html +// @has - 'Generated doc comment' +pub use some_macros::second_attr; diff --git a/src/test/rustdoc/inline_cross/renamed-via-module.rs b/src/test/rustdoc/inline_cross/renamed-via-module.rs new file mode 100644 index 000000000..cdedbf070 --- /dev/null +++ b/src/test/rustdoc/inline_cross/renamed-via-module.rs @@ -0,0 +1,24 @@ +// aux-build:renamed-via-module.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "bar"] + +extern crate foo; + +// @has foo/iter/index.html +// @has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy" +// @has - '//a/[@href="struct.StepBy.html"]' "StepBy" +// @has foo/iter/struct.DeprecatedStepBy.html +// @has - '//h1' "Struct foo::iter::DeprecatedStepBy" +// @has foo/iter/struct.StepBy.html +// @has - '//h1' "Struct foo::iter::StepBy" + +// @has bar/iter/index.html +// @has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy" +// @has - '//a/[@href="struct.StepBy.html"]' "StepBy" +// @has bar/iter/struct.DeprecatedStepBy.html +// @has - '//h1' "Struct bar::iter::DeprecatedStepBy" +// @has bar/iter/struct.StepBy.html +// @has - '//h1' "Struct bar::iter::StepBy" +pub use foo::iter; diff --git a/src/test/rustdoc/inline_cross/trait-vis.rs b/src/test/rustdoc/inline_cross/trait-vis.rs new file mode 100644 index 000000000..363c52a33 --- /dev/null +++ b/src/test/rustdoc/inline_cross/trait-vis.rs @@ -0,0 +1,7 @@ +// aux-build:trait-vis.rs + +extern crate inner; + +// @has trait_vis/struct.SomeStruct.html +// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct' +pub use inner::SomeStruct; diff --git a/src/test/rustdoc/inline_cross/use_crate.rs b/src/test/rustdoc/inline_cross/use_crate.rs new file mode 100644 index 000000000..00e0f041c --- /dev/null +++ b/src/test/rustdoc/inline_cross/use_crate.rs @@ -0,0 +1,27 @@ +// aux-build:use_crate.rs +// aux-build:use_crate_2.rs +// build-aux-docs +// edition:2018 +// compile-flags:--extern use_crate --extern use_crate_2 + +// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it +// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement +// in docs... unless you added `#[doc(inline)]`. + +#![crate_name = "local"] + +// @!has-dir local/use_crate +// @has local/index.html +// @has - '//code' 'pub use use_crate' +pub use use_crate; + +// @has-dir local/asdf +// @has local/asdf/index.html +// @has local/index.html '//a/@href' 'asdf/index.html' +pub use use_crate::asdf; + +// @has-dir local/use_crate_2 +// @has local/use_crate_2/index.html +// @has local/index.html '//a/@href' 'use_crate_2/index.html' +#[doc(inline)] +pub use use_crate_2; diff --git a/src/test/rustdoc/inline_local/glob-extern-document-private-items.rs b/src/test/rustdoc/inline_local/glob-extern-document-private-items.rs new file mode 100644 index 000000000..a2f0d65ef --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-extern-document-private-items.rs @@ -0,0 +1,25 @@ +// compile-flags: --document-private-items + +#![crate_name = "foo"] + +mod mod1 { + extern "C" { + pub fn public_fn(); + fn private_fn(); + } +} + +pub use mod1::*; + +// @has foo/index.html +// @has - "mod1" +// @has - "public_fn" +// @!has - "private_fn" +// @has foo/fn.public_fn.html +// @!has foo/fn.private_fn.html + +// @has foo/mod1/index.html +// @has - "public_fn" +// @has - "private_fn" +// @has foo/mod1/fn.public_fn.html +// @has foo/mod1/fn.private_fn.html diff --git a/src/test/rustdoc/inline_local/glob-extern.rs b/src/test/rustdoc/inline_local/glob-extern.rs new file mode 100644 index 000000000..686e55de3 --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-extern.rs @@ -0,0 +1,21 @@ +#![crate_name = "foo"] + +mod mod1 { + extern "C" { + pub fn public_fn(); + fn private_fn(); + } +} + +pub use mod1::*; + +// @has foo/index.html +// @!has - "mod1" +// @has - "public_fn" +// @!has - "private_fn" +// @has foo/fn.public_fn.html +// @!has foo/fn.private_fn.html + +// @!has foo/mod1/index.html +// @has foo/mod1/fn.public_fn.html +// @!has foo/mod1/fn.private_fn.html diff --git a/src/test/rustdoc/inline_local/glob-private-document-private-items.rs b/src/test/rustdoc/inline_local/glob-private-document-private-items.rs new file mode 100644 index 000000000..f16d21ecd --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-private-document-private-items.rs @@ -0,0 +1,48 @@ +// compile-flags: --document-private-items + +#![crate_name = "foo"] + +mod mod1 { + mod mod2 { + pub struct Mod2Public; + struct Mod2Private; + } + pub use self::mod2::*; + + pub struct Mod1Public; + struct Mod1Private; +} +pub use mod1::*; + +// @has foo/index.html +// @has - "mod1" +// @has - "Mod1Public" +// @!has - "Mod1Private" +// @!has - "mod2" +// @has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/struct.Mod1Public.html +// @!has foo/struct.Mod1Private.html +// @has foo/struct.Mod2Public.html +// @!has foo/struct.Mod2Private.html + +// @has foo/mod1/index.html +// @has - "mod2" +// @has - "Mod1Public" +// @has - "Mod1Private" +// @!has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/mod1/struct.Mod1Public.html +// @has foo/mod1/struct.Mod1Private.html +// @!has foo/mod1/struct.Mod2Public.html +// @!has foo/mod1/struct.Mod2Private.html + +// @has foo/mod1/mod2/index.html +// @has - "Mod2Public" +// @has - "Mod2Private" +// @has foo/mod1/mod2/struct.Mod2Public.html +// @has foo/mod1/mod2/struct.Mod2Private.html + +// @!has foo/mod2/index.html +// @!has foo/mod2/struct.Mod2Public.html +// @!has foo/mod2/struct.Mod2Private.html diff --git a/src/test/rustdoc/inline_local/glob-private.rs b/src/test/rustdoc/inline_local/glob-private.rs new file mode 100644 index 000000000..d294d590e --- /dev/null +++ b/src/test/rustdoc/inline_local/glob-private.rs @@ -0,0 +1,42 @@ +#![crate_name = "foo"] + +mod mod1 { + mod mod2 { + pub struct Mod2Public; + struct Mod2Private; + } + pub use self::mod2::*; + + pub struct Mod1Public; + struct Mod1Private; +} +pub use mod1::*; + +// @has foo/index.html +// @!has - "mod1" +// @has - "Mod1Public" +// @!has - "Mod1Private" +// @!has - "mod2" +// @has - "Mod2Public" +// @!has - "Mod2Private" +// @has foo/struct.Mod1Public.html +// @!has foo/struct.Mod1Private.html +// @has foo/struct.Mod2Public.html +// @!has foo/struct.Mod2Private.html + +// @has-dir foo/mod1 +// @!has foo/mod1/index.html +// @has foo/mod1/struct.Mod1Public.html +// @!has foo/mod1/struct.Mod1Private.html +// @!has foo/mod1/struct.Mod2Public.html +// @!has foo/mod1/struct.Mod2Private.html + +// @has-dir foo/mod1/mod2 +// @!has foo/mod1/mod2/index.html +// @has foo/mod1/mod2/struct.Mod2Public.html +// @!has foo/mod1/mod2/struct.Mod2Private.html + +// @!has-dir foo/mod2 +// @!has foo/mod2/index.html +// @!has foo/mod2/struct.Mod2Public.html +// @!has foo/mod2/struct.Mod2Private.html diff --git a/src/test/rustdoc/inline_local/hidden-use.rs b/src/test/rustdoc/inline_local/hidden-use.rs new file mode 100644 index 000000000..a972d376a --- /dev/null +++ b/src/test/rustdoc/inline_local/hidden-use.rs @@ -0,0 +1,10 @@ +mod private { + pub struct Foo {} +} + +// @has hidden_use/index.html +// @!has - 'private' +// @!has - 'Foo' +// @!has hidden_use/struct.Foo.html +#[doc(hidden)] +pub use private::Foo; diff --git a/src/test/rustdoc/inline_local/issue-28537.rs b/src/test/rustdoc/inline_local/issue-28537.rs new file mode 100644 index 000000000..da9cc4c94 --- /dev/null +++ b/src/test/rustdoc/inline_local/issue-28537.rs @@ -0,0 +1,17 @@ +#[doc(hidden)] +pub mod foo { + pub struct Foo; +} + +mod bar { + pub use self::bar::Bar; + mod bar { + pub struct Bar; + } +} + +// @has issue_28537/struct.Foo.html +pub use foo::Foo; + +// @has issue_28537/struct.Bar.html +pub use self::bar::Bar; diff --git a/src/test/rustdoc/inline_local/issue-32343.rs b/src/test/rustdoc/inline_local/issue-32343.rs new file mode 100644 index 000000000..5620ae0dc --- /dev/null +++ b/src/test/rustdoc/inline_local/issue-32343.rs @@ -0,0 +1,23 @@ +// @!has issue_32343/struct.Foo.html +// @has issue_32343/index.html +// @has - '//code' 'pub use foo::Foo' +// @!has - '//code/a' 'Foo' +#[doc(no_inline)] +pub use foo::Foo; + +// @!has issue_32343/struct.Bar.html +// @has issue_32343/index.html +// @has - '//code' 'pub use foo::Bar' +// @has - '//code/a' 'Bar' +#[doc(no_inline)] +pub use foo::Bar; + +mod foo { + pub struct Foo; + pub struct Bar; +} + +pub mod bar { + // @has issue_32343/bar/struct.Bar.html + pub use ::foo::Bar; +} diff --git a/src/test/rustdoc/inline_local/macro_by_example.rs b/src/test/rustdoc/inline_local/macro_by_example.rs new file mode 100644 index 000000000..dacc7cfb3 --- /dev/null +++ b/src/test/rustdoc/inline_local/macro_by_example.rs @@ -0,0 +1,17 @@ +/// docs for foo +#[deprecated(since = "1.2.3", note = "text")] +#[macro_export] +macro_rules! foo { + ($($tt:tt)*) => {} +} + +// @has macro_by_example/macros/index.html +pub mod macros { + // @!has - 'pub use foo as bar;' + // @has macro_by_example/macros/macro.bar.html + // @has - '//*[@class="docblock"]' 'docs for foo' + // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text' + // @has - '//a/@href' 'macro_by_example.rs.html#4-6' + #[doc(inline)] + pub use foo as bar; +} diff --git a/src/test/rustdoc/inline_local/please_inline.rs b/src/test/rustdoc/inline_local/please_inline.rs new file mode 100644 index 000000000..48539361f --- /dev/null +++ b/src/test/rustdoc/inline_local/please_inline.rs @@ -0,0 +1,19 @@ +pub mod foo { + pub struct Foo; +} + +// @has please_inline/a/index.html +pub mod a { + // @!has - 'pub use foo::' + // @has please_inline/a/struct.Foo.html + #[doc(inline)] + pub use foo::Foo; +} + +// @has please_inline/b/index.html +pub mod b { + // @has - 'pub use foo::' + // @!has please_inline/b/struct.Foo.html + #[feature(inline)] + pub use foo::Foo; +} diff --git a/src/test/rustdoc/inline_local/trait-vis.rs b/src/test/rustdoc/inline_local/trait-vis.rs new file mode 100644 index 000000000..e7b08088f --- /dev/null +++ b/src/test/rustdoc/inline_local/trait-vis.rs @@ -0,0 +1,18 @@ +pub trait ThisTrait {} + +mod asdf { + use ThisTrait; + + pub struct SomeStruct; + + impl ThisTrait for SomeStruct {} + + trait PrivateTrait {} + + impl PrivateTrait for SomeStruct {} +} + +// @has trait_vis/struct.SomeStruct.html +// @has - '//h3[@class="code-header in-band"]' 'impl ThisTrait for SomeStruct' +// @!has - '//h3[@class="code-header in-band"]' 'impl PrivateTrait for SomeStruct' +pub use asdf::SomeStruct; diff --git a/src/test/rustdoc/internal.rs b/src/test/rustdoc/internal.rs new file mode 100644 index 000000000..f316eb24a --- /dev/null +++ b/src/test/rustdoc/internal.rs @@ -0,0 +1,16 @@ +// compile-flags: -Z force-unstable-if-unmarked + +// Check that the unstable marker is not added for "rustc_private". + +// @!matches internal/index.html \ +// '//*[@class="item-right docblock-short"]/span[@class="stab unstable"]' +// @!matches internal/index.html \ +// '//*[@class="item-right docblock-short"]/span[@class="stab internal"]' +// @matches - '//*[@class="item-right docblock-short"]' 'Docs' + +// @!has internal/struct.S.html '//*[@class="stab unstable"]' +// @!has internal/struct.S.html '//*[@class="stab internal"]' +/// Docs +pub struct S; + +fn main() {} diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/self.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/self.rs new file mode 100644 index 000000000..54902f12e --- /dev/null +++ b/src/test/rustdoc/intra-doc-crate/auxiliary/self.rs @@ -0,0 +1,10 @@ +#![crate_name = "cross_crate_self"] + +/// Link to [Self] +/// Link to [crate] +pub struct S; + +impl S { + /// Link to [Self::f] + pub fn f() {} +} diff --git a/src/test/rustdoc/intra-doc-crate/self.rs b/src/test/rustdoc/intra-doc-crate/self.rs new file mode 100644 index 000000000..8c36a7fa0 --- /dev/null +++ b/src/test/rustdoc/intra-doc-crate/self.rs @@ -0,0 +1,9 @@ +// aux-build:self.rs +// build-aux-docs + +extern crate cross_crate_self; + +// @has self/struct.S.html '//a[@href="struct.S.html#method.f"]' "Self::f" +// @has self/struct.S.html '//a[@href="struct.S.html"]' "Self" +// @has self/struct.S.html '//a[@href="../cross_crate_self/index.html"]' "crate" +pub use cross_crate_self::S; diff --git a/src/test/rustdoc/intra-doc/anchors.rs b/src/test/rustdoc/intra-doc/anchors.rs new file mode 100644 index 000000000..3d4c46496 --- /dev/null +++ b/src/test/rustdoc/intra-doc/anchors.rs @@ -0,0 +1,24 @@ +/// I want... +/// +/// # Anchor! +pub struct Something; + +// @has anchors/struct.SomeOtherType.html +// @has - '//a/@href' 'struct.Something.html#Anchor!' + +/// I want... +/// +/// To link to [Something#Anchor!] +pub struct SomeOtherType; + +/// Primitives? +/// +/// [u32#hello] +// @has anchors/fn.x.html +// @has - '//a/@href' '{{channel}}/std/primitive.u32.html#hello' +pub fn x() {} + +/// [prim@usize#x] +// @has anchors/usize/index.html +// @has - '//a/@href' '{{channel}}/std/primitive.usize.html#x' +pub mod usize {} diff --git a/src/test/rustdoc/intra-doc/associated-defaults.rs b/src/test/rustdoc/intra-doc/associated-defaults.rs new file mode 100644 index 000000000..c7e66c826 --- /dev/null +++ b/src/test/rustdoc/intra-doc/associated-defaults.rs @@ -0,0 +1,26 @@ +#![deny(rustdoc::broken_intra_doc_links)] +#![feature(associated_type_defaults)] + +pub trait TraitWithDefault { + type T = usize; + fn f() -> Self::T { + 0 + } +} + +/// Link to [UsesDefaults::T] and [UsesDefaults::f] +// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T' +// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f' +pub struct UsesDefaults; +impl TraitWithDefault for UsesDefaults {} + +/// Link to [OverridesDefaults::T] and [OverridesDefaults::f] +// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T' +// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f' +pub struct OverridesDefaults; +impl TraitWithDefault for OverridesDefaults { + type T = bool; + fn f() -> bool { + true + } +} diff --git a/src/test/rustdoc/intra-doc/associated-items.rs b/src/test/rustdoc/intra-doc/associated-items.rs new file mode 100644 index 000000000..0b958eb8e --- /dev/null +++ b/src/test/rustdoc/intra-doc/associated-items.rs @@ -0,0 +1,68 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +/// [`std::collections::BTreeMap::into_iter`] +/// [`String::from`] is ambiguous as to which `From` impl +/// [Vec::into_iter()] uses a disambiguator +// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' +// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/string/struct.String.html#method.from"]' 'String::from' +// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter' +pub fn foo() {} + +/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] +// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html"]' 'MyStruct' +// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from struct' +// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.clone"]' 'MyStruct::clone' +// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input' +pub struct MyStruct { foo: () } + +impl Clone for MyStruct { + fn clone(&self) -> Self { + MyStruct + } +} + +pub trait T { + type Input; + fn method(i: Self::Input); +} + +impl T for MyStruct { + type Input = usize; + + /// [link from method][MyStruct::method] on method + // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from method' + fn method(i: usize) { + } +} + +/// Ambiguity between which trait to use +pub trait T1 { + fn ambiguous_method(); +} + +pub trait T2 { + fn ambiguous_method(); +} + +/// Link to [S::ambiguous_method] +// FIXME: there is no way to disambiguate these. +// Since we have `#[deny(intra_doc_failure)]`, we still know it was one or the other. +pub struct S; + +impl T1 for S { + fn ambiguous_method() {} +} + +impl T2 for S { + fn ambiguous_method() {} +} + +// @has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant' +/// Link to [MyEnumAlias::MyVariant] +pub enum MyEnum { + MyVariant, +} + +pub type MyEnumAlias = MyEnum; + +fn main() {} diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty.rs b/src/test/rustdoc/intra-doc/auxiliary/empty.rs new file mode 100644 index 000000000..d11c69f81 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/empty.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty2.rs b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs new file mode 100644 index 000000000..d11c69f81 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs new file mode 100644 index 000000000..d9a08cb41 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs @@ -0,0 +1,28 @@ +// no-prefer-dynamic + +#![feature(lang_items, rustc_attrs)] +#![crate_type = "rlib"] +#![no_std] + +pub struct DerefsToF64(f64); + +impl core::ops::Deref for DerefsToF64 { + type Target = f64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +mod inner { + impl f64 { + /// [f64::clone] + #[rustc_allow_incoherent_impl] + pub fn method() {} + } +} + +#[lang = "eh_personality"] +fn foo() {} + +#[panic_handler] +fn bar(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs new file mode 100644 index 000000000..ee4138b68 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs @@ -0,0 +1,11 @@ +#[derive(Clone)] +pub struct PublicStruct; + +mod inner { + use super::PublicStruct; + + impl PublicStruct { + /// [PublicStruct::clone] + pub fn method() {} + } +} diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs new file mode 100644 index 000000000..db3bb38ad --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs @@ -0,0 +1,3 @@ +#![crate_name="inner"] + +//! ooh, i'm a rebel just for [kicks] diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs new file mode 100644 index 000000000..a4db2ffc4 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs @@ -0,0 +1,4 @@ +#![crate_name = "inner"] + +/// Documentation, including a link to [std::ptr] +pub fn f() {} diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs new file mode 100644 index 000000000..fc51995a9 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs @@ -0,0 +1,6 @@ +#![crate_name = "inner"] + +/// Links to [f()] +pub struct Inner; + +pub fn f() {} diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs new file mode 100644 index 000000000..6142dcda9 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs @@ -0,0 +1,6 @@ +pub trait ThisTrait { + fn asdf(&self); + + /// let's link to [`asdf`](ThisTrait::asdf) + fn qwop(&self); +} diff --git a/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs b/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs new file mode 100644 index 000000000..2f3d069bd --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs @@ -0,0 +1,2 @@ +/// This will be referred to by the test docstring +pub struct Something; diff --git a/src/test/rustdoc/intra-doc/auxiliary/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs new file mode 100644 index 000000000..e22feb03a --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs @@ -0,0 +1,23 @@ +#![feature(no_core, lang_items, rustdoc_internals, rustc_attrs)] +#![no_core] +#![rustc_coherence_is_core] +#![crate_type="rlib"] + +#[doc(primitive = "char")] +/// Some char docs +mod char {} + +impl char { + pub fn len_utf8(self) -> usize { + 42 + } +} + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "clone"] +pub trait Clone: Sized {} + +#[lang = "copy"] +pub trait Copy: Clone {} diff --git a/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs new file mode 100644 index 000000000..5ba132f25 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs @@ -0,0 +1,34 @@ +// force-host +// no-prefer-dynamic +// compile-flags: --crate-type proc-macro + +#![crate_type="proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(DeriveA)] +pub fn a_derive(input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_derive(DeriveB)] +pub fn b_derive(input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_derive(DeriveTrait)] +pub fn trait_derive(input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn attr_a(input: TokenStream, _args: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn attr_b(input: TokenStream, _args: TokenStream) -> TokenStream { + input +} diff --git a/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs new file mode 100644 index 000000000..75d428932 --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs @@ -0,0 +1 @@ +pub struct SomeStruct; diff --git a/src/test/rustdoc/intra-doc/basic.rs b/src/test/rustdoc/intra-doc/basic.rs new file mode 100644 index 000000000..39f5c298b --- /dev/null +++ b/src/test/rustdoc/intra-doc/basic.rs @@ -0,0 +1,84 @@ +// @has basic/index.html +// @has - '//a/@href' 'struct.ThisType.html' +// @has - '//a/@href' 'struct.ThisType.html#method.this_method' +// @has - '//a/@href' 'enum.ThisEnum.html' +// @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant' +// @has - '//a/@href' 'trait.ThisTrait.html' +// @has - '//a/@href' 'trait.ThisTrait.html#tymethod.this_associated_method' +// @has - '//a/@href' 'trait.ThisTrait.html#associatedtype.ThisAssociatedType' +// @has - '//a/@href' 'trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST' +// @has - '//a/@href' 'trait.ThisTrait.html' +// @has - '//a/@href' 'type.ThisAlias.html' +// @has - '//a/@href' 'union.ThisUnion.html' +// @has - '//a/@href' 'fn.this_function.html' +// @has - '//a/@href' 'constant.THIS_CONST.html' +// @has - '//a/@href' 'static.THIS_STATIC.html' +// @has - '//a/@href' 'macro.this_macro.html' +// @has - '//a/@href' 'trait.SoAmbiguous.html' +// @has - '//a/@href' 'fn.SoAmbiguous.html' +//! In this crate we would like to link to: +//! +//! * [`ThisType`](ThisType) +//! * [`ThisType::this_method`](ThisType::this_method) +//! * [`ThisEnum`](ThisEnum) +//! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant) +//! * [`ThisEnum::ThisVariantCtor`](ThisEnum::ThisVariantCtor) +//! * [`ThisTrait`](ThisTrait) +//! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method) +//! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType) +//! * [`ThisTrait::THIS_ASSOCIATED_CONST`](ThisTrait::THIS_ASSOCIATED_CONST) +//! * [`ThisAlias`](ThisAlias) +//! * [`ThisUnion`](ThisUnion) +//! * [`this_function`](this_function()) +//! * [`THIS_CONST`](const@THIS_CONST) +//! * [`THIS_STATIC`](static@THIS_STATIC) +//! * [`this_macro`](this_macro!) +//! +//! In addition, there's some specifics we want to look at. There's [a trait called +//! SoAmbiguous][ambig-trait], but there's also [a function called SoAmbiguous][ambig-fn] too! +//! Whatever shall we do? +//! +//! [ambig-trait]: trait@SoAmbiguous +//! [ambig-fn]: SoAmbiguous() + +#[macro_export] +macro_rules! this_macro { + () => {}; +} + +// @has basic/struct.ThisType.html '//a/@href' 'macro.this_macro.html' +/// another link to [`this_macro!()`] +pub struct ThisType; + +impl ThisType { + pub fn this_method() {} +} +pub enum ThisEnum { ThisVariant, ThisVariantCtor(u32), } +pub trait ThisTrait { + type ThisAssociatedType; + const THIS_ASSOCIATED_CONST: u8; + fn this_associated_method(); +} +pub type ThisAlias = Result<(), ()>; +pub union ThisUnion { this_field: usize, } + +pub fn this_function() {} +pub const THIS_CONST: usize = 5usize; +pub static THIS_STATIC: usize = 5usize; + +pub trait SoAmbiguous {} + +#[allow(nonstandard_style)] +pub fn SoAmbiguous() {} + + +// @has basic/struct.SomeOtherType.html '//a/@href' 'struct.ThisType.html' +// @has - '//a/@href' 'struct.ThisType.html#method.this_method' +// @has - '//a/@href' 'enum.ThisEnum.html' +// @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant' +/// Shortcut links for: +/// * [`ThisType`] +/// * [`ThisType::this_method`] +/// * [ThisEnum] +/// * [ThisEnum::ThisVariant] +pub struct SomeOtherType; diff --git a/src/test/rustdoc/intra-doc/builtin-macros.rs b/src/test/rustdoc/intra-doc/builtin-macros.rs new file mode 100644 index 000000000..bbdbe246b --- /dev/null +++ b/src/test/rustdoc/intra-doc/builtin-macros.rs @@ -0,0 +1,3 @@ +// @has builtin_macros/index.html +// @has - '//a/@href' '{{channel}}/core/macro.cfg.html' +//! [cfg] diff --git a/src/test/rustdoc/intra-doc/crate-relative-assoc.rs b/src/test/rustdoc/intra-doc/crate-relative-assoc.rs new file mode 100644 index 000000000..d4a0ecc35 --- /dev/null +++ b/src/test/rustdoc/intra-doc/crate-relative-assoc.rs @@ -0,0 +1,17 @@ +pub mod io { + pub trait Read { + fn read(&mut self); + } +} + +pub mod bufreader { + // @has crate_relative_assoc/bufreader/index.html '//a/@href' 'struct.TcpStream.html#method.read' + //! [`crate::TcpStream::read`] + use crate::io::Read; +} + +pub struct TcpStream; + +impl crate::io::Read for TcpStream { + fn read(&mut self) {} +} diff --git a/src/test/rustdoc/intra-doc/crate-relative.rs b/src/test/rustdoc/intra-doc/crate-relative.rs new file mode 100644 index 000000000..bacbcabfc --- /dev/null +++ b/src/test/rustdoc/intra-doc/crate-relative.rs @@ -0,0 +1,13 @@ +pub struct Test<'a> { + data: &'a (), +} + +impl<'a> Test<'a> { + pub fn do_test(&self) {} +} + +// @has crate_relative/demo/index.html +// @has - '//a/@href' '../struct.Test.html#method.do_test' +pub mod demo { + //! [`crate::Test::do_test`] +} diff --git a/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs new file mode 100644 index 000000000..e52fb9b1c --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs @@ -0,0 +1,10 @@ +// aux-build:additional_doc.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate my_rand; + +// @has 'additional_doc/trait.Rng.html' '//a[@href="trait.Rng.html"]' 'Rng' +// @has 'additional_doc/trait.Rng.html' '//a[@href="../my_rand/trait.RngCore.html"]' 'RngCore' +/// This is an [`Rng`]. +pub use my_rand::Rng; diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs new file mode 100644 index 000000000..684fdd449 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs @@ -0,0 +1,6 @@ +#![crate_name = "my_rand"] +#![deny(rustdoc::broken_intra_doc_links)] + +pub trait RngCore {} +/// Rng extends [`RngCore`]. +pub trait Rng: RngCore {} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs new file mode 100644 index 000000000..34f4e9f63 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs @@ -0,0 +1,19 @@ +#![crate_name = "hidden_dep"] +#![deny(rustdoc::broken_intra_doc_links)] + +#[doc(hidden)] +pub mod __reexport { + pub use crate::*; +} + +pub mod future { + mod ready { + + /// Link to [`ready`](function@ready) + pub struct Ready; + pub fn ready() {} + + } + pub use self::ready::{ready, Ready}; + +} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs new file mode 100644 index 000000000..d6a829966 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs @@ -0,0 +1,7 @@ +#![crate_name = "a"] +#![deny(rustdoc::broken_intra_doc_links)] + +pub struct Foo; + +/// Link to [Foo] +pub struct Bar; diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs new file mode 100644 index 000000000..a37848e23 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs @@ -0,0 +1,5 @@ +#![crate_name = "inner"] + +/// Links to [crate::g] +pub fn f() {} +pub fn g() {} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs new file mode 100644 index 000000000..cb7a8afb6 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs @@ -0,0 +1,10 @@ +#![crate_name = "macro_inner"] +#![deny(rustdoc::broken_intra_doc_links)] + +pub struct Foo; + +/// See also [`Foo`] +#[macro_export] +macro_rules! my_macro { + () => {} +} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs new file mode 100644 index 000000000..018fdedd9 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs @@ -0,0 +1,7 @@ +#![crate_name = "module_inner"] +#![deny(rustdoc::broken_intra_doc_links)] +/// [SomeType] links to [bar] +pub struct SomeType; +pub trait SomeTrait {} +/// [bar] links to [SomeTrait] and also [SomeType] +pub mod bar {} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs new file mode 100644 index 000000000..0d5a95407 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs @@ -0,0 +1,20 @@ +// force-host +// no-prefer-dynamic +// compile-flags: --crate-type proc-macro +#![crate_type="proc-macro"] +#![crate_name="proc_macro_inner"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +/// Links to [`OtherDerive`] +#[proc_macro_derive(DeriveA)] +pub fn a_derive(input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_derive(OtherDerive)] +pub fn other_derive(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs new file mode 100644 index 000000000..0612f53d6 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs @@ -0,0 +1,12 @@ +#![crate_name = "a"] +#![deny(rustdoc::broken_intra_doc_links)] + +pub mod bar { + pub struct Bar; +} + +pub mod foo { + use crate::bar; + /// link to [bar::Bar] + pub struct Foo; +} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs new file mode 100644 index 000000000..105eb8e11 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs @@ -0,0 +1,13 @@ +#![crate_name = "bar"] +#![deny(rustdoc::broken_intra_doc_links)] + +pub trait Foo { + /// [`Bar`] [`Baz`] + fn foo(); +} + +pub trait Bar { +} + +pub trait Baz { +} diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs new file mode 100644 index 000000000..c16e39d56 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs @@ -0,0 +1,16 @@ +#![crate_name = "inner"] +/// this is a trait +pub trait SomeTrait { + /// this is a method for [a trait][SomeTrait] + fn foo(); +} + +pub mod bar { + use super::SomeTrait; + + pub struct BarStruct; + + impl SomeTrait for BarStruct { + fn foo() {} + } +} diff --git a/src/test/rustdoc/intra-doc/cross-crate/basic.rs b/src/test/rustdoc/intra-doc/cross-crate/basic.rs new file mode 100644 index 000000000..ad7454918 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/basic.rs @@ -0,0 +1,9 @@ +// aux-build:intra-doc-basic.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] + +// from https://github.com/rust-lang/rust/issues/65983 +extern crate a; + +// @has 'basic/struct.Bar.html' '//a[@href="../a/struct.Foo.html"]' 'Foo' +pub use a::Bar; diff --git a/src/test/rustdoc/intra-doc/cross-crate/crate.rs b/src/test/rustdoc/intra-doc/cross-crate/crate.rs new file mode 100644 index 000000000..edf544708 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/crate.rs @@ -0,0 +1,6 @@ +// aux-build:intra-link-cross-crate-crate.rs +// build-aux-docs +#![crate_name = "outer"] +extern crate inner; +// @has outer/fn.f.html '//a[@href="../inner/fn.g.html"]' "crate::g" +pub use inner::f; diff --git a/src/test/rustdoc/intra-doc/cross-crate/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs new file mode 100644 index 000000000..4f7d075ba --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs @@ -0,0 +1,10 @@ +// aux-build:hidden.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] + +// tests https://github.com/rust-lang/rust/issues/73363 + +extern crate hidden_dep; + +// @has 'hidden/struct.Ready.html' '//a/@href' 'fn.ready.html' +pub use hidden_dep::future::{ready, Ready}; diff --git a/src/test/rustdoc/intra-doc/cross-crate/macro.rs b/src/test/rustdoc/intra-doc/cross-crate/macro.rs new file mode 100644 index 000000000..32f0a55d3 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/macro.rs @@ -0,0 +1,11 @@ +// aux-build:macro_inner.rs +// aux-build:proc_macro.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] +extern crate macro_inner; +extern crate proc_macro_inner; + +// @has 'macro/macro.my_macro.html' '//a[@href="../macro_inner/struct.Foo.html"]' 'Foo' +pub use macro_inner::my_macro; +// @has 'macro/derive.DeriveA.html' '//a[@href="../proc_macro_inner/derive.OtherDerive.html"]' 'OtherDerive' +pub use proc_macro_inner::DeriveA; diff --git a/src/test/rustdoc/intra-doc/cross-crate/module.rs b/src/test/rustdoc/intra-doc/cross-crate/module.rs new file mode 100644 index 000000000..fde932265 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/module.rs @@ -0,0 +1,8 @@ +// outer.rs +// aux-build: module.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] +extern crate module_inner; +// @has 'module/bar/index.html' '//a[@href="../../module_inner/trait.SomeTrait.html"]' 'SomeTrait' +// @has 'module/bar/index.html' '//a[@href="../../module_inner/struct.SomeType.html"]' 'SomeType' +pub use module_inner::bar; diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs new file mode 100644 index 000000000..577fe78a5 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs @@ -0,0 +1,8 @@ +// aux-build:submodule-inner.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate a; + +// @has 'submodule_inner/struct.Foo.html' '//a[@href="../a/bar/struct.Bar.html"]' 'Bar' +pub use a::foo::Foo; diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs new file mode 100644 index 000000000..d0c0b7e85 --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs @@ -0,0 +1,16 @@ +// aux-build:submodule-outer.rs +// edition:2018 +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate bar as bar_; + +// from https://github.com/rust-lang/rust/issues/60883 +pub mod bar { + pub use ::bar_::Bar; +} + +// NOTE: we re-exported both `Foo` and `Bar` here, +// NOTE: so they are inlined and therefore we link to the current module. +// @has 'submodule_outer/trait.Foo.html' '//a[@href="bar/trait.Bar.html"]' 'Bar' +// @has 'submodule_outer/trait.Foo.html' '//a[@href="trait.Baz.html"]' 'Baz' +pub use ::bar_::{Foo, Baz}; diff --git a/src/test/rustdoc/intra-doc/cross-crate/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/traits.rs new file mode 100644 index 000000000..7b9554bfd --- /dev/null +++ b/src/test/rustdoc/intra-doc/cross-crate/traits.rs @@ -0,0 +1,14 @@ +// aux-build:traits.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate inner; +use inner::SomeTrait; + +pub struct SomeStruct; + + // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'SomeTrait' +impl SomeTrait for SomeStruct { + // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'a trait' + fn foo() {} +} diff --git a/src/test/rustdoc/intra-doc/disambiguators-removed.rs b/src/test/rustdoc/intra-doc/disambiguators-removed.rs new file mode 100644 index 000000000..331a31413 --- /dev/null +++ b/src/test/rustdoc/intra-doc/disambiguators-removed.rs @@ -0,0 +1,50 @@ +#![deny(rustdoc::broken_intra_doc_links)] +// first try backticks +/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] +// @has disambiguators_removed/struct.AtDisambiguator.html +// @has - '//a[@href="trait.Name.html"][code]' "Name" +// @has - '//a[@href="fn.Name.html"][code]' "Name" +// @has - '//a[@href="macro.Name.html"][code]' "Name" +pub struct AtDisambiguator; + +/// fn: [`Name()`], macro: [`Name!`] +// @has disambiguators_removed/struct.SymbolDisambiguator.html +// @has - '//a[@href="fn.Name.html"][code]' "Name()" +// @has - '//a[@href="macro.Name.html"][code]' "Name!" +pub struct SymbolDisambiguator; + +// Now make sure that backticks aren't added if they weren't already there +/// [fn@Name] +// @has disambiguators_removed/trait.Name.html +// @has - '//a[@href="fn.Name.html"]' "Name" +// @!has - '//a[@href="fn.Name.html"][code]' "Name" + +// FIXME: this will turn !() into ! alone +/// [Name!()] +// @has - '//a[@href="macro.Name.html"]' "Name!" +pub trait Name {} + +#[allow(non_snake_case)] + +// Try collapsed reference links +/// [macro@Name][] +// @has disambiguators_removed/fn.Name.html +// @has - '//a[@href="macro.Name.html"]' "Name" + +// Try links that have the same text as a generated URL +/// Weird URL aligned [macro.Name.html][trait@Name] +// @has - '//a[@href="trait.Name.html"]' "macro.Name.html" +pub fn Name() {} + +#[macro_export] +// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. +/// [fn@Na`m`e] +// @has disambiguators_removed/macro.Name.html +// @has - '//a[@href="fn.Name.html"]' "fn@Name" + +// It also doesn't handle any case where the code block isn't the whole link text: +/// [trait@`Name`] +// @has - '//a[@href="trait.Name.html"]' "trait@Name" +macro_rules! Name { + () => () +} diff --git a/src/test/rustdoc/intra-doc/email-address.rs b/src/test/rustdoc/intra-doc/email-address.rs new file mode 100644 index 000000000..24161c3bb --- /dev/null +++ b/src/test/rustdoc/intra-doc/email-address.rs @@ -0,0 +1,10 @@ +#![forbid(rustdoc::broken_intra_doc_links)] + +//! Email me at <hello@example.com>. +//! Email me at <hello-world@example.com>. +//! Email me at <hello@localhost>. +//! Email me at <prim@i32>. +// @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com' +// @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com' +// @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost' +// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32' diff --git a/src/test/rustdoc/intra-doc/enum-struct-field.rs b/src/test/rustdoc/intra-doc/enum-struct-field.rs new file mode 100644 index 000000000..2270a1faf --- /dev/null +++ b/src/test/rustdoc/intra-doc/enum-struct-field.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + +pub enum Foo { + X { + y: u8, + } +} + +/// Hello +/// +/// I want [Foo::X::y]. +pub fn foo() {} + +// @has foo/fn.foo.html '//a/@href' 'enum.Foo.html#variant.X.field.y' diff --git a/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs new file mode 100644 index 000000000..7bb1ded3f --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs @@ -0,0 +1,11 @@ +// Reexport of a structure that derefs to a type with lang item impls having doc links in their +// comments. The doc link points to an associated item, so we check that traits in scope for that +// link are populated. + +// aux-build:extern-builtin-type-impl-dep.rs + +#![no_std] + +extern crate extern_builtin_type_impl_dep; + +pub use extern_builtin_type_impl_dep::DerefsToF64; diff --git a/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs new file mode 100644 index 000000000..5d8dcf8bc --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs @@ -0,0 +1,19 @@ +// This test is just a little cursed. +// aux-build:issue-66159-1.rs +// aux-crate:priv:issue_66159_1=issue-66159-1.rs +// aux-build:empty.rs +// aux-crate:priv:empty=empty.rs +// aux-build:empty2.rs +// aux-crate:priv:empty2=empty2.rs +// build-aux-docs +// compile-flags:-Z unstable-options --edition 2018 + +// @has extern_crate_only_used_in_link/index.html +// @has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something' +//! [issue_66159_1::Something] + +// @has - '//a[@href="../empty/index.html"]' 'empty' +//! [`empty`] + +// @has - '//a[@href="../empty2/index.html"]' 'empty2' +//! [empty2<x>] diff --git a/src/test/rustdoc/intra-doc/extern-crate.rs b/src/test/rustdoc/intra-doc/extern-crate.rs new file mode 100644 index 000000000..4e4438dea --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-crate.rs @@ -0,0 +1,9 @@ +// aux-build:intra-link-extern-crate.rs + +// When loading `extern crate` statements, we would pull in their docs at the same time, even +// though they would never actually get displayed. This tripped intra-doc-link resolution failures, +// for items that aren't under our control, and not actually getting documented! + +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate inner; diff --git a/src/test/rustdoc/intra-doc/extern-inherent-impl.rs b/src/test/rustdoc/intra-doc/extern-inherent-impl.rs new file mode 100644 index 000000000..2e41c2214 --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-inherent-impl.rs @@ -0,0 +1,8 @@ +// Reexport of a structure with public inherent impls having doc links in their comments. The doc +// link points to an associated item, so we check that traits in scope for that link are populated. + +// aux-build:extern-inherent-impl-dep.rs + +extern crate extern_inherent_impl_dep; + +pub use extern_inherent_impl_dep::PublicStruct; diff --git a/src/test/rustdoc/intra-doc/extern-reference-link.rs b/src/test/rustdoc/intra-doc/extern-reference-link.rs new file mode 100644 index 000000000..bad6ec755 --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-reference-link.rs @@ -0,0 +1,7 @@ +// compile-flags: --extern pub_struct +// aux-build:pub-struct.rs + +/// [SomeStruct] +/// +/// [SomeStruct]: pub_struct::SomeStruct +pub fn foo() {} diff --git a/src/test/rustdoc/intra-doc/extern-type.rs b/src/test/rustdoc/intra-doc/extern-type.rs new file mode 100644 index 000000000..ab088ab78 --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-type.rs @@ -0,0 +1,37 @@ +#![feature(extern_types)] + +extern { + pub type ExternType; +} + +pub trait T { + fn test(&self) {} +} + +pub trait G<N> { + fn g(&self, n: N) {} +} + +impl ExternType { + pub fn f(&self) {} +} + +impl T for ExternType { + fn test(&self) {} +} + +impl G<usize> for ExternType { + fn g(&self, n: usize) {} +} + +// @has 'extern_type/foreigntype.ExternType.html' +// @has 'extern_type/fn.links_to_extern_type.html' \ +// 'href="foreigntype.ExternType.html#method.f"' +// @has 'extern_type/fn.links_to_extern_type.html' \ +// 'href="foreigntype.ExternType.html#method.test"' +// @has 'extern_type/fn.links_to_extern_type.html' \ +// 'href="foreigntype.ExternType.html#method.g"' +/// See also [ExternType::f] +/// See also [ExternType::test] +/// See also [ExternType::g] +pub fn links_to_extern_type() {} diff --git a/src/test/rustdoc/intra-doc/external-traits.rs b/src/test/rustdoc/intra-doc/external-traits.rs new file mode 100644 index 000000000..a0a66f242 --- /dev/null +++ b/src/test/rustdoc/intra-doc/external-traits.rs @@ -0,0 +1,12 @@ +// aux-build:intra-links-external-traits.rs +// ignore-cross-compile + +#![crate_name = "outer"] +#![deny(rustdoc::broken_intra_doc_links)] + +// using a trait that has intra-doc links on it from another crate (whether re-exporting or just +// implementing it) used to give spurious resolution failure warnings + +extern crate intra_links_external_traits; + +pub use intra_links_external_traits::ThisTrait; diff --git a/src/test/rustdoc/intra-doc/field.rs b/src/test/rustdoc/intra-doc/field.rs new file mode 100644 index 000000000..001143489 --- /dev/null +++ b/src/test/rustdoc/intra-doc/field.rs @@ -0,0 +1,4 @@ +// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' +// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//! [start][std::ops::Range::start] +//! [not_found][std::io::ErrorKind::NotFound] diff --git a/src/test/rustdoc/intra-doc/generic-params.rs b/src/test/rustdoc/intra-doc/generic-params.rs new file mode 100644 index 000000000..fbc9fc6a9 --- /dev/null +++ b/src/test/rustdoc/intra-doc/generic-params.rs @@ -0,0 +1,62 @@ +// ignore-tidy-linelength + +#![crate_name = "foo"] + +//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`]. +//! Here's a link to [`Iterator<Box<T>>::Item`]. +//! +// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html"]' 'Vec<T>' +// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>' +// @has foo/index.html '//a[@href="{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item' + +//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)? +//! +// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'just Option' +// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'with the generic, Option<T>' + +//! We should also try linking to [`Result<T, E>`]; it has *two* generics! +//! And [`Result<T, !>`] and [`Result<!, E>`]. +//! +// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, E>' +// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, !>' +// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<!, E>' + +//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it +//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()]. +//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`]. +//! +// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new' +// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()' +// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()' + +//! This is also pretty tricky: [`TypeId::of::<String>()`]. +//! And this too: [`Vec::<std::error::Error>::len`]. +//! +// @has foo/index.html '//a[@href="{{channel}}/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()' +// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len' + +//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like +//! [`Box::<T>new()`]. We may not support them in the future! +//! +// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()' + +//! These will be resolved as regular links: +//! - [`this is <invalid syntax> first`](https://www.rust-lang.org) +//! - [`this is <invalid syntax> twice`] +//! - [`<invalid syntax> thrice`](https://www.rust-lang.org) +//! - [`<invalid syntax> four times`][rlo] +//! - [a < b][rlo] +//! - [c > d] +//! +//! [`this is <invalid syntax> twice`]: https://www.rust-lang.org +//! [rlo]: https://www.rust-lang.org +//! [c > d]: https://www.rust-lang.org +//! +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> first' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> twice' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> thrice' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> four times' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'a < b' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'c > d' + +use std::any::TypeId; diff --git a/src/test/rustdoc/intra-doc/generic-trait-impl.rs b/src/test/rustdoc/intra-doc/generic-trait-impl.rs new file mode 100644 index 000000000..ba8595abf --- /dev/null +++ b/src/test/rustdoc/intra-doc/generic-trait-impl.rs @@ -0,0 +1,20 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +// Test intra-doc links on trait implementations with generics +// regression test for issue #92662 + +use std::marker::PhantomData; + +pub trait Bar<T> { + fn bar(&self); +} + +pub struct Foo<U>(PhantomData<U>); + +impl<T, U> Bar<T> for Foo<U> { + fn bar(&self) {} +} + +// @has generic_trait_impl/fn.main.html '//a[@href="struct.Foo.html#method.bar"]' 'Foo::bar' +/// link to [`Foo::bar`] +pub fn main() {} diff --git a/src/test/rustdoc/intra-doc/in-bodies.rs b/src/test/rustdoc/intra-doc/in-bodies.rs new file mode 100644 index 000000000..55169e5d3 --- /dev/null +++ b/src/test/rustdoc/intra-doc/in-bodies.rs @@ -0,0 +1,30 @@ +// we need to make sure that intra-doc links on trait impls get resolved in the right scope + +#![deny(rustdoc::broken_intra_doc_links)] + +pub mod inner { + pub struct SomethingOutOfScope; +} + +pub mod other { + use inner::SomethingOutOfScope; + use SomeTrait; + + pub struct OtherStruct; + + /// Let's link to [SomethingOutOfScope] while we're at it. + impl SomeTrait for OtherStruct {} +} + +pub trait SomeTrait {} + +pub struct SomeStruct; + +fn __implementation_details() { + use inner::SomethingOutOfScope; + + // FIXME: intra-links resolve in their nearest module scope, not their actual scope in cases + // like this + // Let's link to [SomethingOutOfScope] while we're at it. + impl SomeTrait for SomeStruct {} +} diff --git a/src/test/rustdoc/intra-doc/issue-66159.rs b/src/test/rustdoc/intra-doc/issue-66159.rs new file mode 100644 index 000000000..56742b397 --- /dev/null +++ b/src/test/rustdoc/intra-doc/issue-66159.rs @@ -0,0 +1,10 @@ +// aux-crate:priv:pub_struct=pub-struct.rs +// compile-flags:-Z unstable-options + +// The issue was an ICE which meant that we never actually generated the docs +// so if we have generated the docs, we're okay. +// Since we don't generate the docs for the auxiliary files, we can't actually +// verify that the struct is linked correctly. + +// @has issue_66159/index.html +//! [pub_struct::SomeStruct] diff --git a/src/test/rustdoc/intra-doc/issue-82209.rs b/src/test/rustdoc/intra-doc/issue-82209.rs new file mode 100644 index 000000000..a5fe855cb --- /dev/null +++ b/src/test/rustdoc/intra-doc/issue-82209.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] +#![deny(rustdoc::broken_intra_doc_links)] +pub enum Foo { + Bar { + abc: i32, + /// [Self::Bar::abc] + xyz: i32, + }, +} + +// @has foo/enum.Foo.html '//a/@href' 'enum.Foo.html#variant.Bar.field.abc' diff --git a/src/test/rustdoc/intra-doc/libstd-re-export.rs b/src/test/rustdoc/intra-doc/libstd-re-export.rs new file mode 100644 index 000000000..6c41eb2b5 --- /dev/null +++ b/src/test/rustdoc/intra-doc/libstd-re-export.rs @@ -0,0 +1,4 @@ +#![deny(rustdoc::broken_intra_doc_links)] +#![feature(intra_doc_pointers)] + +pub use std::*; diff --git a/src/test/rustdoc/intra-doc/macros-disambiguators.rs b/src/test/rustdoc/intra-doc/macros-disambiguators.rs new file mode 100644 index 000000000..cd4caa6a8 --- /dev/null +++ b/src/test/rustdoc/intra-doc/macros-disambiguators.rs @@ -0,0 +1,25 @@ +#![crate_name = "foo"] +#![deny(rustdoc::broken_intra_doc_links)] + +//! [foo!()] +// @has foo/index.html '//a[@href="macro.foo.html"]' 'foo!()' + +//! [foo!{}] +// @has - '//a[@href="macro.foo.html"]' 'foo!{}' + +//! [foo![]](foo![]) +// @has - '//a[@href="macro.foo.html"]' 'foo![]' + +//! [foo1](foo!()) +// @has - '//a[@href="macro.foo.html"]' 'foo1' + +//! [foo2](foo!{}) +// @has - '//a[@href="macro.foo.html"]' 'foo2' + +//! [foo3](foo![]) +// @has - '//a[@href="macro.foo.html"]' 'foo3' + +#[macro_export] +macro_rules! foo { + () => {}; +} diff --git a/src/test/rustdoc/intra-doc/mod-ambiguity.rs b/src/test/rustdoc/intra-doc/mod-ambiguity.rs new file mode 100644 index 000000000..0c7acbaf0 --- /dev/null +++ b/src/test/rustdoc/intra-doc/mod-ambiguity.rs @@ -0,0 +1,16 @@ +#![deny(rustdoc::broken_intra_doc_links)] + + +pub fn foo() { + +} + +pub mod foo {} +// @has mod_ambiguity/struct.A.html '//a/@href' 'foo/index.html' +/// Module is [`module@foo`] +pub struct A; + + +// @has mod_ambiguity/struct.B.html '//a/@href' 'fn.foo.html' +/// Function is [`fn@foo`] +pub struct B; diff --git a/src/test/rustdoc/intra-doc/mod-relative.rs b/src/test/rustdoc/intra-doc/mod-relative.rs new file mode 100644 index 000000000..49d3399b9 --- /dev/null +++ b/src/test/rustdoc/intra-doc/mod-relative.rs @@ -0,0 +1,17 @@ +pub mod wrapper { + + pub struct Test<'a> { + data: &'a (), + } + + impl<'a> Test<'a> { + pub fn do_test(&self) {} + } + + // @has mod_relative/wrapper/demo/index.html + // @has - '//a/@href' '../struct.Test.html#method.do_test' + /// [`Test::do_test`] + pub mod demo { + } + +} diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs new file mode 100644 index 000000000..be4b44b31 --- /dev/null +++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs @@ -0,0 +1,46 @@ +#![crate_name = "foo"] +#![feature(intra_doc_pointers)] +#![deny(rustdoc::broken_intra_doc_links)] + +// @has foo/index.html '//a[@href="{{channel}}/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left' +//! [slice::rotate_left] + +// @has - '//a[@href="{{channel}}/std/primitive.array.html#method.map"]' 'array::map' +//! [array::map] + +// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'owned str' +// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str ref' +// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.is_empty"]' 'str::is_empty' +// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.len"]' '&str::len' +//! [owned str][str] +//! [str ref][&str] +//! [str::is_empty] +//! [&str::len] + +// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null' +// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*const::is_null' +// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*mut::is_null' +//! [pointer::is_null] +//! [*const::is_null] +//! [*mut::is_null] + +// @has - '//a[@href="{{channel}}/std/primitive.unit.html"]' 'unit' +//! [unit] + +// @has - '//a[@href="{{channel}}/std/primitive.tuple.html"]' 'tuple' +//! [tuple] + +// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' 'reference' +// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&' +// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&mut' +//! [reference] +//! [&] +//! [&mut] + +// @has - '//a[@href="{{channel}}/std/primitive.fn.html"]' 'fn' +//! [fn] + +// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' 'never' +// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' '!' +//! [never] +//! [!] diff --git a/src/test/rustdoc/intra-doc/prim-assoc.rs b/src/test/rustdoc/intra-doc/prim-assoc.rs new file mode 100644 index 000000000..dfa7db8a5 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-assoc.rs @@ -0,0 +1,4 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +//! [i32::MAX] +// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX" diff --git a/src/test/rustdoc/intra-doc/prim-associated-traits.rs b/src/test/rustdoc/intra-doc/prim-associated-traits.rs new file mode 100644 index 000000000..8639a24f7 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-associated-traits.rs @@ -0,0 +1,46 @@ +#![feature(never_type)] +use std::str::FromStr; + +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()' +/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`] +/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`] +/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`] +/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`] +/// [`str::eq()`] [`never::eq()`] +pub struct Number { + pub f_64: f64, + pub f_32: f32, + pub i_size: isize, + pub i_8: i8, + pub i_16: i16, + pub i_32: i32, + pub i_64: i64, + pub i_128: i128, + pub u_size: usize, + pub u_8: u8, + pub u_16: u16, + pub u_32: u32, + pub u_64: u64, + pub u_128: u128, + pub ch: char, + pub boolean: bool, + pub string: str, + pub n: !, +} diff --git a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs new file mode 100644 index 000000000..c3340af33 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs @@ -0,0 +1,17 @@ +// aux-build:my-core.rs +// build-aux-docs +// ignore-cross-compile +// only-linux + +#![deny(rustdoc::broken_intra_doc_links)] +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type = "rlib"] + +// @has prim_methods_external_core/index.html +// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html"]' 'char' +// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html#method.len_utf8"]' 'char::len_utf8' + +//! A [`char`] and its [`char::len_utf8`]. + +extern crate my_core; diff --git a/src/test/rustdoc/intra-doc/prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs new file mode 100644 index 000000000..79d8df045 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs @@ -0,0 +1,29 @@ +#![deny(rustdoc::broken_intra_doc_links)] +#![feature(no_core, lang_items, rustc_attrs, rustdoc_internals)] +#![no_core] +#![rustc_coherence_is_core] +#![crate_type = "rlib"] + +// @has prim_methods_local/index.html +// @has - '//*[@id="main-content"]//a[@href="primitive.char.html"]' 'char' +// @has - '//*[@id="main-content"]//a[@href="primitive.char.html#method.len_utf8"]' 'char::len_utf8' + +//! A [prim@`char`] and its [`char::len_utf8`]. + +#[doc(primitive = "char")] +mod char {} + +impl char { + pub fn len_utf8(self) -> usize { + 42 + } +} + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "clone"] +pub trait Clone: Sized {} + +#[lang = "copy"] +pub trait Copy: Clone {} diff --git a/src/test/rustdoc/intra-doc/prim-methods.rs b/src/test/rustdoc/intra-doc/prim-methods.rs new file mode 100644 index 000000000..a412a23fd --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-methods.rs @@ -0,0 +1,7 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +// @has prim_methods/index.html +// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char' +// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' + +//! A [`char`] and its [`char::len_utf8`]. diff --git a/src/test/rustdoc/intra-doc/prim-precedence.rs b/src/test/rustdoc/intra-doc/prim-precedence.rs new file mode 100644 index 000000000..25625b952 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-precedence.rs @@ -0,0 +1,16 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +pub mod char { + /// [char] + // @has prim_precedence/char/struct.Inner.html '//a/@href' '{{channel}}/std/primitive.char.html' + pub struct Inner; +} + +/// See [prim@char] +// @has prim_precedence/struct.MyString.html '//a/@href' '{{channel}}/std/primitive.char.html' +pub struct MyString; + +/// See also [crate::char] and [mod@char] +// @has prim_precedence/struct.MyString2.html '//*[@href="char/index.html"]' 'crate::char' +// @has - '//*[@href="char/index.html"]' 'mod@char' +pub struct MyString2; diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs new file mode 100644 index 000000000..c7ce71b15 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-self.rs @@ -0,0 +1,41 @@ +#![deny(rustdoc::broken_intra_doc_links)] +#![rustc_coherence_is_core] +#![allow(incomplete_features)] // inherent_associated_types +#![feature(rustc_attrs)] +#![feature(no_core)] +#![feature(rustdoc_internals)] +#![feature(inherent_associated_types)] +#![feature(lang_items)] +#![no_core] + +/// [Self::f] +/// [Self::MAX] +// @has prim_self/primitive.usize.html +// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f' +// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX' +impl usize { + /// Some docs + pub fn f() {} + + /// 10 and 2^32 are basically the same. + pub const MAX: usize = 10; + + // @has - '//a[@href="primitive.usize.html#associatedtype.ME"]' 'Self::ME' + /// [Self::ME] + pub type ME = usize; +} + +#[doc(primitive = "usize")] +/// This has some docs. +mod usize {} + +/// [S::f] +/// [Self::f] +pub struct S; + +impl S { + pub fn f() {} +} + +#[lang = "sized"] +pub trait Sized {} diff --git a/src/test/rustdoc/intra-doc/primitive-disambiguators.rs b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs new file mode 100644 index 000000000..adcab767d --- /dev/null +++ b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs @@ -0,0 +1,4 @@ +#![deny(rustdoc::broken_intra_doc_links)] +// @has primitive_disambiguators/index.html +// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim' +//! [str::trim()] diff --git a/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs new file mode 100644 index 000000000..474bf3477 --- /dev/null +++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs @@ -0,0 +1,31 @@ +#![deny(rustdoc::broken_intra_doc_links)] + + +// @has primitive_non_default_impl/fn.str_methods.html +/// [`str::trim`] +// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.trim"]' 'str::trim' +/// [`str::to_lowercase`] +// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase' +/// [`str::into_boxed_bytes`] +// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes' +/// [`str::replace`] +// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.replace"]' 'str::replace' +pub fn str_methods() {} + +// @has primitive_non_default_impl/fn.f32_methods.html +/// [f32::powi] +// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.powi"]' 'f32::powi' +/// [f32::sqrt] +// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt' +/// [f32::mul_add] +// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add' +pub fn f32_methods() {} + +// @has primitive_non_default_impl/fn.f64_methods.html +/// [`f64::powi`] +// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.powi"]' 'f64::powi' +/// [`f64::sqrt`] +// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt' +/// [`f64::mul_add`] +// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add' +pub fn f64_methods() {} diff --git a/src/test/rustdoc/intra-doc/private-failures-ignored.rs b/src/test/rustdoc/intra-doc/private-failures-ignored.rs new file mode 100644 index 000000000..b272bfb5a --- /dev/null +++ b/src/test/rustdoc/intra-doc/private-failures-ignored.rs @@ -0,0 +1,8 @@ +// Rustdoc would previously report resolution failures on items that weren't in the public docs. +// These failures were legitimate, but not truly relevant - the docs in question couldn't be +// checked for accuracy anyway. + +#![deny(rustdoc::broken_intra_doc_links)] + +/// ooh, i'm a [rebel] just for kicks +struct SomeStruct; diff --git a/src/test/rustdoc/intra-doc/private.rs b/src/test/rustdoc/intra-doc/private.rs new file mode 100644 index 000000000..349091e93 --- /dev/null +++ b/src/test/rustdoc/intra-doc/private.rs @@ -0,0 +1,20 @@ +// compile-flags: --document-private-items + +// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file + +#![allow(rustdoc::private_intra_doc_links)] + +#![crate_name = "private"] + +/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] +// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html"]' 'DontDocMe' +// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#method.f"]' 'DontDocMe::f' +// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#structfield.x"]' 'DontDocMe::x' +pub struct DocMe; +struct DontDocMe { + x: usize, +} + +impl DontDocMe { + fn f() {} +} diff --git a/src/test/rustdoc/intra-doc/proc-macro.rs b/src/test/rustdoc/intra-doc/proc-macro.rs new file mode 100644 index 000000000..78379a902 --- /dev/null +++ b/src/test/rustdoc/intra-doc/proc-macro.rs @@ -0,0 +1,27 @@ +// aux-build:proc-macro-macro.rs +// build-aux-docs +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate proc_macro_macro; + + +pub use proc_macro_macro::{DeriveA, attr_a}; +use proc_macro_macro::{DeriveB, attr_b}; + +// @has proc_macro/struct.Foo.html +// @has - '//a/@href' 'derive.DeriveA.html' +// @has - '//a/@href' 'attr.attr_a.html' +// @has - '//a/@href' 'trait.DeriveTrait.html' +// @has - '//a/@href' '../proc_macro_macro/derive.DeriveB.html' +// @has - '//a/@href' '../proc_macro_macro/attr.attr_b.html' +/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait] +pub struct Foo; + +// @has proc_macro/struct.Bar.html +// @has - '//a/@href' 'derive.DeriveA.html' +// @has - '//a/@href' 'attr.attr_a.html' +/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a) +pub struct Bar; + +// this should not cause ambiguity errors +pub trait DeriveTrait {} diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs new file mode 100644 index 000000000..8a998496c --- /dev/null +++ b/src/test/rustdoc/intra-doc/pub-use.rs @@ -0,0 +1,17 @@ +// aux-build: intra-link-pub-use.rs +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "outer"] + +extern crate inner; + +/// [mod@std::env] [g] +// @has outer/index.html +// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env" +// @has - '//a[@href="fn.f.html"]' "g" +pub use f as g; + +// Make sure the documentation is actually correct by documenting an inlined re-export +/// [mod@std::env] +// @has outer/fn.f.html +// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env" +pub use inner::f; diff --git a/src/test/rustdoc/intra-doc/raw-ident-self.rs b/src/test/rustdoc/intra-doc/raw-ident-self.rs new file mode 100644 index 000000000..1ed33db93 --- /dev/null +++ b/src/test/rustdoc/intra-doc/raw-ident-self.rs @@ -0,0 +1,13 @@ +#![deny(rustdoc::broken_intra_doc_links)] +pub mod r#impl { + pub struct S; + + impl S { + /// See [Self::b]. + // @has raw_ident_self/impl/struct.S.html + // @has - '//a[@href="struct.S.html#method.b"]' 'Self::b' + pub fn a() {} + + pub fn b() {} + } +} diff --git a/src/test/rustdoc/intra-doc/reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs new file mode 100644 index 000000000..64683bacd --- /dev/null +++ b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs @@ -0,0 +1,23 @@ +// aux-build:intra-link-reexport-additional-docs.rs +// build-aux-docs +#![crate_name = "foo"] +extern crate inner; + +// @has foo/struct.Inner.html '//a[@href="fn.with_code.html"]' 'crate::with_code' +/// [crate::with_code] +// @has - '//a[@href="fn.with_code.html"]' 'different text' +/// [different text][with_code] +// @has - '//a[@href="fn.me_too.html"]' 'me_too' +#[doc = "[me_too]"] +// @has - '//a[@href="fn.me_three.html"]' 'reference link' +/// This [reference link] +#[doc = "has an attr in the way"] +/// +/// [reference link]: me_three +// Should still resolve links from the original module in that scope +// @has - '//a[@href="../inner/fn.f.html"]' 'f()' +pub use inner::Inner; + +pub fn with_code() {} +pub fn me_too() {} +pub fn me_three() {} diff --git a/src/test/rustdoc/intra-doc/self-cache.rs b/src/test/rustdoc/intra-doc/self-cache.rs new file mode 100644 index 000000000..63bf7fa57 --- /dev/null +++ b/src/test/rustdoc/intra-doc/self-cache.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] +// @has foo/enum.E1.html '//a/@href' 'enum.E1.html#variant.A' + +/// [Self::A::b] +pub enum E1 { + A { b: usize } +} + +// @has foo/enum.E2.html '//a/@href' 'enum.E2.html#variant.A' + +/// [Self::A::b] +pub enum E2 { + A { b: usize } +} diff --git a/src/test/rustdoc/intra-doc/self.rs b/src/test/rustdoc/intra-doc/self.rs new file mode 100644 index 000000000..0ba7df8a7 --- /dev/null +++ b/src/test/rustdoc/intra-doc/self.rs @@ -0,0 +1,116 @@ +#![crate_name = "foo"] + + +// @has foo/index.html '//a/@href' 'struct.Foo.html#method.new' +// @has foo/struct.Foo.html '//a/@href' 'struct.Foo.html#method.new' + +/// Use [`new`] to create a new instance. +/// +/// [`new`]: Self::new +pub struct Foo; + +impl Foo { + pub fn new() -> Self { + unimplemented!() + } +} + +// @has foo/index.html '//a/@href' 'struct.Bar.html#method.new2' +// @has foo/struct.Bar.html '//a/@href' 'struct.Bar.html#method.new2' + +/// Use [`new2`] to create a new instance. +/// +/// [`new2`]: Self::new2 +pub struct Bar; + +impl Bar { + pub fn new2() -> Self { + unimplemented!() + } +} + +pub struct MyStruct { + // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#structfield.struct_field' + + /// [`struct_field`] + /// + /// [`struct_field`]: Self::struct_field + pub struct_field: u8, +} + +pub enum MyEnum { + // @has foo/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.EnumVariant' + + /// [`EnumVariant`] + /// + /// [`EnumVariant`]: Self::EnumVariant + EnumVariant, +} + +pub union MyUnion { + // @has foo/union.MyUnion.html '//a/@href' 'union.MyUnion.html#structfield.union_field' + + /// [`union_field`] + /// + /// [`union_field`]: Self::union_field + pub union_field: f32, +} + +pub trait MyTrait { + // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedtype.AssoType' + + /// [`AssoType`] + /// + /// [`AssoType`]: Self::AssoType + type AssoType; + + // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedconstant.ASSO_CONST' + + /// [`ASSO_CONST`] + /// + /// [`ASSO_CONST`]: Self::ASSO_CONST + const ASSO_CONST: i32 = 1; + + // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#method.asso_fn' + + /// [`asso_fn`] + /// + /// [`asso_fn`]: Self::asso_fn + fn asso_fn() {} +} + +impl MyStruct { + // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.for_impl' + + /// [`for_impl`] + /// + /// [`for_impl`]: Self::for_impl + pub fn for_impl() { + unimplemented!() + } +} + +impl MyTrait for MyStruct { + // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType' + + /// [`AssoType`] + /// + /// [`AssoType`]: Self::AssoType + type AssoType = u32; + + // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST' + + /// [`ASSO_CONST`] + /// + /// [`ASSO_CONST`]: Self::ASSO_CONST + const ASSO_CONST: i32 = 10; + + // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.asso_fn' + + /// [`asso_fn`] + /// + /// [`asso_fn`]: Self::asso_fn + fn asso_fn() { + unimplemented!() + } +} diff --git a/src/test/rustdoc/intra-doc/trait-impl.rs b/src/test/rustdoc/intra-doc/trait-impl.rs new file mode 100644 index 000000000..cf60dc1db --- /dev/null +++ b/src/test/rustdoc/intra-doc/trait-impl.rs @@ -0,0 +1,34 @@ +#![crate_name = "foo"] + + +pub struct MyStruct; + +impl MyTrait for MyStruct { + +// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType' + + /// [`AssoType`] + /// + /// [`AssoType`]: MyStruct::AssoType + type AssoType = u32; + +// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST' + + /// [`ASSO_CONST`] + /// + /// [`ASSO_CONST`]: MyStruct::ASSO_CONST + const ASSO_CONST: i32 = 10; + +// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.trait_fn' + + /// [`trait_fn`] + /// + /// [`trait_fn`]: MyStruct::trait_fn + fn trait_fn() { } +} + +pub trait MyTrait { + type AssoType; + const ASSO_CONST: i32 = 1; + fn trait_fn(); +} diff --git a/src/test/rustdoc/intra-doc/trait-item.rs b/src/test/rustdoc/intra-doc/trait-item.rs new file mode 100644 index 000000000..e95dba33b --- /dev/null +++ b/src/test/rustdoc/intra-doc/trait-item.rs @@ -0,0 +1,11 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +/// Link to [S::assoc_fn()] +/// Link to [Default::default()] +// @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()' +// @has - '//*[@href="{{channel}}/core/default/trait.Default.html#tymethod.default"]' 'Default::default()' +pub struct S; + +impl S { + pub fn assoc_fn() {} +} diff --git a/src/test/rustdoc/intra-doc/true-false.rs b/src/test/rustdoc/intra-doc/true-false.rs new file mode 100644 index 000000000..e02be9cab --- /dev/null +++ b/src/test/rustdoc/intra-doc/true-false.rs @@ -0,0 +1,8 @@ +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +// @has foo/index.html +// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true' +// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false' + +//! A `bool` is either [`true`] or [`false`]. diff --git a/src/test/rustdoc/intra-doc/type-alias.rs b/src/test/rustdoc/intra-doc/type-alias.rs new file mode 100644 index 000000000..6c52082a2 --- /dev/null +++ b/src/test/rustdoc/intra-doc/type-alias.rs @@ -0,0 +1,19 @@ +// Regression test for issue #86120. + +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +pub struct Foo; + +/// You should really try [`Self::bar`]! +pub type Bar = Foo; + +impl Bar { + pub fn bar() {} +} + +/// The minimum is [`Self::MIN`]. +pub type Int = i32; + +// @has foo/type.Bar.html '//a[@href="struct.Foo.html#method.bar"]' 'Self::bar' +// @has foo/type.Int.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MIN"]' 'Self::MIN' diff --git a/src/test/rustdoc/invalid.crate.name.rs b/src/test/rustdoc/invalid.crate.name.rs new file mode 100644 index 000000000..c19713b56 --- /dev/null +++ b/src/test/rustdoc/invalid.crate.name.rs @@ -0,0 +1,3 @@ +// compile-flags: --crate-name foo + +pub fn foo() {} diff --git a/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs new file mode 100644 index 000000000..3e20c5c07 --- /dev/null +++ b/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs @@ -0,0 +1,14 @@ +// aux-build:issue-100204-aux.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name="second"] + +extern crate first; + +pub mod prelude {} + +// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot' +// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot' +#[doc(inline)] +pub use first::*; diff --git a/src/test/rustdoc/issue-12834.rs b/src/test/rustdoc/issue-12834.rs new file mode 100644 index 000000000..9605a1e78 --- /dev/null +++ b/src/test/rustdoc/issue-12834.rs @@ -0,0 +1,12 @@ +// Tests that failing to syntax highlight a rust code-block doesn't cause +// rustdoc to fail, while still rendering the code-block (without highlighting). + +#![allow(rustdoc::invalid_rust_codeblocks)] + +// @has issue_12834/fn.foo.html +// @has - //pre 'a + b ' + +/// ``` +/// a + b ∈ Self ∀ a, b ∈ Self +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc/issue-13698.rs b/src/test/rustdoc/issue-13698.rs new file mode 100644 index 000000000..3046a8a28 --- /dev/null +++ b/src/test/rustdoc/issue-13698.rs @@ -0,0 +1,16 @@ +// aux-build:issue-13698.rs +// ignore-cross-compile + +extern crate issue_13698; + +pub struct Foo; +// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn foo' +impl issue_13698::Foo for Foo {} + +pub trait Bar { + #[doc(hidden)] + fn bar(&self) {} +} + +// @!has issue_13698/struct.Foo.html '//*[@id="method.bar"]' 'fn bar' +impl Bar for Foo {} diff --git a/src/test/rustdoc/issue-15169.rs b/src/test/rustdoc/issue-15169.rs new file mode 100644 index 000000000..e525d85e2 --- /dev/null +++ b/src/test/rustdoc/issue-15169.rs @@ -0,0 +1,3 @@ +// @has issue_15169/struct.Foo.html '//*[@id="method.eq"]' 'fn eq' +#[derive(PartialEq)] +pub struct Foo; diff --git a/src/test/rustdoc/issue-15318-2.rs b/src/test/rustdoc/issue-15318-2.rs new file mode 100644 index 000000000..f7f5052a3 --- /dev/null +++ b/src/test/rustdoc/issue-15318-2.rs @@ -0,0 +1,12 @@ +// aux-build:issue-15318.rs +// ignore-cross-compile +#![no_std] + +extern crate issue_15318; + +pub use issue_15318::ptr; + +// @has issue_15318_2/fn.bar.html \ +// '//*[@href="primitive.pointer.html"]' \ +// '*mut T' +pub fn bar<T>(ptr: *mut T) {} diff --git a/src/test/rustdoc/issue-15318-3.rs b/src/test/rustdoc/issue-15318-3.rs new file mode 100644 index 000000000..2fadc26b0 --- /dev/null +++ b/src/test/rustdoc/issue-15318-3.rs @@ -0,0 +1,7 @@ +#![feature(rustdoc_internals)] + +// @has issue_15318_3/primitive.pointer.html + +/// dox +#[doc(primitive = "pointer")] +pub mod ptr {} diff --git a/src/test/rustdoc/issue-15318.rs b/src/test/rustdoc/issue-15318.rs new file mode 100644 index 000000000..0349fe285 --- /dev/null +++ b/src/test/rustdoc/issue-15318.rs @@ -0,0 +1,11 @@ +// aux-build:issue-15318.rs +// ignore-cross-compile + +#![no_std] + +extern crate issue_15318; + +// @has issue_15318/fn.bar.html \ +// '//*[@href="http://example.com/issue_15318/primitive.pointer.html"]' \ +// '*mut T' +pub fn bar<T>(ptr: *mut T) {} diff --git a/src/test/rustdoc/issue-15347.rs b/src/test/rustdoc/issue-15347.rs new file mode 100644 index 000000000..e93d74011 --- /dev/null +++ b/src/test/rustdoc/issue-15347.rs @@ -0,0 +1,5 @@ +// compile-flags: -Z unstable-options --document-hidden-items + +// @has issue_15347/fn.foo.html +#[doc(hidden)] +pub fn foo() {} diff --git a/src/test/rustdoc/issue-16019.rs b/src/test/rustdoc/issue-16019.rs new file mode 100644 index 000000000..239d92378 --- /dev/null +++ b/src/test/rustdoc/issue-16019.rs @@ -0,0 +1,9 @@ +macro_rules! define_struct { + ($rounds:expr) => ( + struct Struct { + sk: [u32; $rounds + 1] + } + ) +} + +define_struct!(2); diff --git a/src/test/rustdoc/issue-16265-1.rs b/src/test/rustdoc/issue-16265-1.rs new file mode 100644 index 000000000..ec007e36b --- /dev/null +++ b/src/test/rustdoc/issue-16265-1.rs @@ -0,0 +1,10 @@ +pub struct Foo; + +// @has issue_16265_1/traits/index.html 'source' +pub mod traits { + impl PartialEq for super::Foo { + fn eq(&self, _: &super::Foo) -> bool { + true + } + } +} diff --git a/src/test/rustdoc/issue-16265-2.rs b/src/test/rustdoc/issue-16265-2.rs new file mode 100644 index 000000000..d5cd18d9d --- /dev/null +++ b/src/test/rustdoc/issue-16265-2.rs @@ -0,0 +1,4 @@ +// @has issue_16265_2/index.html 'source' + +trait Y {} +impl Y for Option<u32> {} diff --git a/src/test/rustdoc/issue-17476.rs b/src/test/rustdoc/issue-17476.rs new file mode 100644 index 000000000..a5b484c98 --- /dev/null +++ b/src/test/rustdoc/issue-17476.rs @@ -0,0 +1,11 @@ +// aux-build:issue-17476.rs +// ignore-cross-compile + +extern crate issue_17476; + +pub struct Foo; + +// @has issue_17476/struct.Foo.html \ +// '//*[@href="http://example.com/issue_17476/trait.Foo.html#method.foo"]' \ +// 'foo' +impl issue_17476::Foo for Foo {} diff --git a/src/test/rustdoc/issue-18199.rs b/src/test/rustdoc/issue-18199.rs new file mode 100644 index 000000000..bc0c4a565 --- /dev/null +++ b/src/test/rustdoc/issue-18199.rs @@ -0,0 +1,9 @@ +// compile-flags:--test + +#![doc(test(attr(feature(staged_api))))] + +/// ``` +/// #![unstable(feature="test", issue="18199")] +/// fn main() {} +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc/issue-19181.rs b/src/test/rustdoc/issue-19181.rs new file mode 100644 index 000000000..3dea152fc --- /dev/null +++ b/src/test/rustdoc/issue-19181.rs @@ -0,0 +1,5 @@ +// compile-flags:--test + +// rustdoc should not panic when target crate has compilation errors + +fn main() { 0 } diff --git a/src/test/rustdoc/issue-19190-2.rs b/src/test/rustdoc/issue-19190-2.rs new file mode 100644 index 000000000..b6416e2e5 --- /dev/null +++ b/src/test/rustdoc/issue-19190-2.rs @@ -0,0 +1,12 @@ +use std::ops::Deref; + +pub struct Bar; + +impl Deref for Bar { + type Target = String; + fn deref(&self) -> &String { loop {} } +} + +// @has issue_19190_2/struct.Bar.html +// @!has - '//*[@id="method.new"]' 'fn new() -> String' +// @has - '//*[@id="method.as_str"]' 'fn as_str(&self) -> &str' diff --git a/src/test/rustdoc/issue-19190-3.rs b/src/test/rustdoc/issue-19190-3.rs new file mode 100644 index 000000000..4d34ce650 --- /dev/null +++ b/src/test/rustdoc/issue-19190-3.rs @@ -0,0 +1,27 @@ +// aux-build:issue-19190-3.rs +// ignore-cross-compile + +extern crate issue_19190_3; + +use std::ops::Deref; +use issue_19190_3::Baz; + +// @has issue_19190_3/struct.Foo.html +// @has - '//*[@id="method.as_str"]' 'fn as_str(&self) -> &str' +// @!has - '//*[@id="method.new"]' 'fn new() -> String' +pub use issue_19190_3::Foo; + +// @has issue_19190_3/struct.Bar.html +// @has - '//*[@id="method.baz"]' 'fn baz(&self)' +// @!has - '//*[@id="method.static_baz"]' 'fn static_baz()' +pub use issue_19190_3::Bar; + +// @has issue_19190_3/struct.MyBar.html +// @has - '//*[@id="method.baz"]' 'fn baz(&self)' +// @!has - '//*[@id="method.static_baz"]' 'fn static_baz()' +pub struct MyBar; + +impl Deref for MyBar { + type Target = Baz; + fn deref(&self) -> &Baz { loop {} } +} diff --git a/src/test/rustdoc/issue-19190.rs b/src/test/rustdoc/issue-19190.rs new file mode 100644 index 000000000..2046273e2 --- /dev/null +++ b/src/test/rustdoc/issue-19190.rs @@ -0,0 +1,20 @@ +use std::ops::Deref; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn foo(&self) {} + pub fn static_foo() {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +// @has issue_19190/struct.Bar.html +// @has - '//*[@id="method.foo"]//h4[@class="code-header"]' 'fn foo(&self)' +// @has - '//*[@id="method.foo"]' 'fn foo(&self)' +// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()' +// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' diff --git a/src/test/rustdoc/issue-20175.rs b/src/test/rustdoc/issue-20175.rs new file mode 100644 index 000000000..6a42e2afb --- /dev/null +++ b/src/test/rustdoc/issue-20175.rs @@ -0,0 +1,10 @@ +pub trait Foo { + fn foo(&self) {} +} + +pub struct Bar; + +// @has issue_20175/struct.Bar.html \ +// '//*[@id="method.foo"]' \ +// 'fn foo' +impl<'a> Foo for &'a Bar {} diff --git a/src/test/rustdoc/issue-20646.rs b/src/test/rustdoc/issue-20646.rs new file mode 100644 index 000000000..2589e27f2 --- /dev/null +++ b/src/test/rustdoc/issue-20646.rs @@ -0,0 +1,26 @@ +// aux-build:issue-20646.rs +// ignore-cross-compile + +#![feature(associated_types)] + +extern crate issue_20646; + +// @has issue_20646/trait.Trait.html \ +// '//*[@id="associatedtype.Output"]' \ +// 'type Output' +pub trait Trait { + type Output; +} + +// @has issue_20646/fn.fun.html \ +// '//*[@class="rust fn"]' 'where T: Trait<Output = i32>' +pub fn fun<T>(_: T) where T: Trait<Output=i32> {} + +pub mod reexport { + // @has issue_20646/reexport/trait.Trait.html \ + // '//*[@id="associatedtype.Output"]' \ + // 'type Output' + // @has issue_20646/reexport/fn.fun.html \ + // '//*[@class="rust fn"]' 'where T: Trait<Output = i32>' + pub use issue_20646::{Trait, fun}; +} diff --git a/src/test/rustdoc/issue-20727-2.rs b/src/test/rustdoc/issue-20727-2.rs new file mode 100644 index 000000000..022ff290e --- /dev/null +++ b/src/test/rustdoc/issue-20727-2.rs @@ -0,0 +1,22 @@ +// aux-build:issue-20727.rs +// ignore-cross-compile + +extern crate issue_20727; + +// @has issue_20727_2/trait.Add.html +pub trait Add<RHS = Self> { + // @has - '//*[@class="rust trait"]' 'trait Add<RHS = Self> {' + // @has - '//*[@class="rust trait"]' 'type Output;' + type Output; + + // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;' + fn add(self, rhs: RHS) -> Self::Output; +} + +// @has issue_20727_2/reexport/trait.Add.html +pub mod reexport { + // @has - '//*[@class="rust trait"]' 'trait Add<RHS = Self> {' + // @has - '//*[@class="rust trait"]' 'type Output;' + // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;' + pub use issue_20727::Add; +} diff --git a/src/test/rustdoc/issue-20727-3.rs b/src/test/rustdoc/issue-20727-3.rs new file mode 100644 index 000000000..52032b75a --- /dev/null +++ b/src/test/rustdoc/issue-20727-3.rs @@ -0,0 +1,24 @@ +// aux-build:issue-20727.rs +// ignore-cross-compile + +extern crate issue_20727; + +pub trait Bar {} + +// @has issue_20727_3/trait.Deref2.html +pub trait Deref2 { + // @has - '//*[@class="rust trait"]' 'trait Deref2 {' + // @has - '//*[@class="rust trait"]' 'type Target: Bar;' + type Target: Bar; + + // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;' + fn deref(&self) -> Self::Target; +} + +// @has issue_20727_3/reexport/trait.Deref2.html +pub mod reexport { + // @has - '//*[@class="rust trait"]' 'trait Deref2 {' + // @has - '//*[@class="rust trait"]' 'type Target: Bar;' + // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;' + pub use issue_20727::Deref2; +} diff --git a/src/test/rustdoc/issue-20727-4.rs b/src/test/rustdoc/issue-20727-4.rs new file mode 100644 index 000000000..84fc6f94a --- /dev/null +++ b/src/test/rustdoc/issue-20727-4.rs @@ -0,0 +1,40 @@ +// aux-build:issue-20727.rs +// ignore-cross-compile + +extern crate issue_20727; + +// @has issue_20727_4/trait.Index.html +pub trait Index<Idx: ?Sized> { + // @has - '//*[@class="rust trait"]' 'trait Index<Idx: ?Sized> {' + // @has - '//*[@class="rust trait"]' 'type Output: ?Sized' + type Output: ?Sized; + + // @has - '//*[@class="rust trait"]' \ + // 'fn index(&self, index: Idx) -> &Self::Output' + fn index(&self, index: Idx) -> &Self::Output; +} + +// @has issue_20727_4/trait.IndexMut.html +pub trait IndexMut<Idx: ?Sized>: Index<Idx> { + // @has - '//*[@class="rust trait"]' \ + // 'trait IndexMut<Idx: ?Sized>: Index<Idx> {' + // @has - '//*[@class="rust trait"]' \ + // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;' + fn index_mut(&mut self, index: Idx) -> &mut Self::Output; +} + +pub mod reexport { + // @has issue_20727_4/reexport/trait.Index.html + // @has - '//*[@class="rust trait"]' 'trait Index<Idx> where Idx: ?Sized, {' + // @has - '//*[@class="rust trait"]' 'type Output: ?Sized' + // @has - '//*[@class="rust trait"]' \ + // 'fn index(&self, index: Idx) -> &Self::Output' + pub use issue_20727::Index; + + // @has issue_20727_4/reexport/trait.IndexMut.html + // @has - '//*[@class="rust trait"]' \ + // 'trait IndexMut<Idx>: Index<Idx> where Idx: ?Sized, {' + // @has - '//*[@class="rust trait"]' \ + // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;' + pub use issue_20727::IndexMut; +} diff --git a/src/test/rustdoc/issue-20727.rs b/src/test/rustdoc/issue-20727.rs new file mode 100644 index 000000000..f7acffcb4 --- /dev/null +++ b/src/test/rustdoc/issue-20727.rs @@ -0,0 +1,24 @@ +// aux-build:issue-20727.rs +// ignore-cross-compile + +extern crate issue_20727; + +// @has issue_20727/trait.Deref.html +pub trait Deref { + // @has - '//*[@class="rust trait"]' 'trait Deref {' + // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;' + type Target: ?Sized; + + // @has - '//*[@class="rust trait"]' \ + // "fn deref<'a>(&'a self) -> &'a Self::Target;" + fn deref<'a>(&'a self) -> &'a Self::Target; +} + +// @has issue_20727/reexport/trait.Deref.html +pub mod reexport { + // @has - '//*[@class="rust trait"]' 'trait Deref {' + // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;' + // @has - '//*[@class="rust trait"]' \ + // "fn deref(&'a self) -> &'a Self::Target;" + pub use issue_20727::Deref; +} diff --git a/src/test/rustdoc/issue-21092.rs b/src/test/rustdoc/issue-21092.rs new file mode 100644 index 000000000..b054145a4 --- /dev/null +++ b/src/test/rustdoc/issue-21092.rs @@ -0,0 +1,8 @@ +// aux-build:issue-21092.rs +// ignore-cross-compile + +extern crate issue_21092; + +// @has issue_21092/struct.Bar.html +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar = i32' +pub use issue_21092::{Foo, Bar}; diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs new file mode 100644 index 000000000..43ce13fd9 --- /dev/null +++ b/src/test/rustdoc/issue-21474.rs @@ -0,0 +1,11 @@ +pub use inner::*; + +mod inner { + impl super::Blah for super::What { } +} + +pub trait Blah { } + +// @count issue_21474/struct.What.html \ +// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +pub struct What; diff --git a/src/test/rustdoc/issue-21801.rs b/src/test/rustdoc/issue-21801.rs new file mode 100644 index 000000000..2a586b6ff --- /dev/null +++ b/src/test/rustdoc/issue-21801.rs @@ -0,0 +1,9 @@ +// aux-build:issue-21801.rs +// ignore-cross-compile + +extern crate issue_21801; + +// @has issue_21801/struct.Foo.html +// @has - '//*[@id="method.new"]' \ +// 'fn new<F>(f: F) -> Foo where F: FnMut() -> i32' +pub use issue_21801::Foo; diff --git a/src/test/rustdoc/issue-22025.rs b/src/test/rustdoc/issue-22025.rs new file mode 100644 index 000000000..a721a15f4 --- /dev/null +++ b/src/test/rustdoc/issue-22025.rs @@ -0,0 +1,6 @@ +// aux-build:issue-22025.rs +// ignore-cross-compile + +extern crate issue_22025; + +pub use issue_22025::foo::{Foo, Bar}; diff --git a/src/test/rustdoc/issue-22038.rs b/src/test/rustdoc/issue-22038.rs new file mode 100644 index 000000000..ff5813dac --- /dev/null +++ b/src/test/rustdoc/issue-22038.rs @@ -0,0 +1,19 @@ +extern "C" { + // @has issue_22038/fn.foo1.html \ + // '//*[@class="rust fn"]' 'pub unsafe extern "C" fn foo1()' + pub fn foo1(); +} + +extern "system" { + // @has issue_22038/fn.foo2.html \ + // '//*[@class="rust fn"]' 'pub unsafe extern "system" fn foo2()' + pub fn foo2(); +} + +// @has issue_22038/fn.bar.html \ +// '//*[@class="rust fn"]' 'pub extern "C" fn bar()' +pub extern "C" fn bar() {} + +// @has issue_22038/fn.baz.html \ +// '//*[@class="rust fn"]' 'pub extern "system" fn baz()' +pub extern "system" fn baz() {} diff --git a/src/test/rustdoc/issue-23106.rs b/src/test/rustdoc/issue-23106.rs new file mode 100644 index 000000000..8cda2fc33 --- /dev/null +++ b/src/test/rustdoc/issue-23106.rs @@ -0,0 +1,7 @@ +// compile-flags:--test + +/// ``` +/// # +/// ``` +pub fn main() { +} diff --git a/src/test/rustdoc/issue-23207.rs b/src/test/rustdoc/issue-23207.rs new file mode 100644 index 000000000..1a4b849ee --- /dev/null +++ b/src/test/rustdoc/issue-23207.rs @@ -0,0 +1,9 @@ +// aux-build:issue-23207-1.rs +// aux-build:issue-23207-2.rs +// ignore-cross-compile + +extern crate issue_23207_2; + +// @has issue_23207/fmt/index.html +// @count - '//*[@class="struct"]' 1 +pub use issue_23207_2::fmt; diff --git a/src/test/rustdoc/issue-23511.rs b/src/test/rustdoc/issue-23511.rs new file mode 100644 index 000000000..2d2a7908f --- /dev/null +++ b/src/test/rustdoc/issue-23511.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] +#![feature(rustdoc_internals)] +#![no_std] + +pub mod str { + #![doc(primitive = "str")] + + impl str { + // @has search-index.js foo + #[rustc_allow_incoherent_impl] + pub fn foo(&self) {} + } +} diff --git a/src/test/rustdoc/issue-23744.rs b/src/test/rustdoc/issue-23744.rs new file mode 100644 index 000000000..642817396 --- /dev/null +++ b/src/test/rustdoc/issue-23744.rs @@ -0,0 +1,12 @@ +// compile-flags:--test + +/// Example of rustdoc incorrectly parsing <code>```rust,should_panic</code>. +/// +/// ```should_panic +/// fn main() { panic!("fee"); } +/// ``` +/// +/// ```rust,should_panic +/// fn main() { panic!("fum"); } +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc/issue-23812.rs b/src/test/rustdoc/issue-23812.rs new file mode 100644 index 000000000..5dac8d87b --- /dev/null +++ b/src/test/rustdoc/issue-23812.rs @@ -0,0 +1,36 @@ +macro_rules! doc { + (#[$outer:meta] mod $i:ident { #![$inner:meta] }) => + ( + #[$outer] + pub mod $i { + #![$inner] + } + ) +} + +doc! { + /// Outer comment + mod Foo { + //! Inner comment + } +} + +// @has issue_23812/Foo/index.html +// @has - 'Outer comment' +// @!has - '/// Outer comment' +// @has - 'Inner comment' +// @!has - '//! Inner comment' + + +doc! { + /** Outer block comment */ + mod Bar { + /*! Inner block comment */ + } +} + +// @has issue_23812/Bar/index.html +// @has - 'Outer block comment' +// @!has - '/** Outer block comment */' +// @has - 'Inner block comment' +// @!has - '/*! Inner block comment */' diff --git a/src/test/rustdoc/issue-25001.rs b/src/test/rustdoc/issue-25001.rs new file mode 100644 index 000000000..c97b35ada --- /dev/null +++ b/src/test/rustdoc/issue-25001.rs @@ -0,0 +1,43 @@ +// @has issue_25001/struct.Foo.html +pub struct Foo<T>(T); + +pub trait Bar { + type Item; + + fn quux(self); +} + +impl Foo<u8> { + // @has - '//*[@id="method.pass"]//h4[@class="code-header"]' 'fn pass()' + pub fn pass() {} +} +impl Foo<u16> { + // @has - '//*[@id="method.pass-1"]//h4[@class="code-header"]' 'fn pass() -> usize' + pub fn pass() -> usize { 42 } +} +impl Foo<u32> { + // @has - '//*[@id="method.pass-2"]//h4[@class="code-header"]' 'fn pass() -> isize' + pub fn pass() -> isize { 42 } +} + +impl<T> Bar for Foo<T> { + // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' 'type Item = T' + type Item=T; + + // @has - '//*[@id="method.quux"]//h4[@class="code-header"]' 'fn quux(self)' + fn quux(self) {} +} +impl<'a, T> Bar for &'a Foo<T> { + // @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item = &'a T" + type Item=&'a T; + + // @has - '//*[@id="method.quux-1"]//h4[@class="code-header"]' 'fn quux(self)' + fn quux(self) {} +} +impl<'a, T> Bar for &'a mut Foo<T> { + // @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item = &'a mut T" + type Item=&'a mut T; + + // @has - '//*[@id="method.quux-2"]//h4[@class="code-header"]' 'fn quux(self)' + fn quux(self) {} +} diff --git a/src/test/rustdoc/issue-25944.rs b/src/test/rustdoc/issue-25944.rs new file mode 100644 index 000000000..49625294b --- /dev/null +++ b/src/test/rustdoc/issue-25944.rs @@ -0,0 +1,11 @@ +// compile-flags:--test + +/// ``` +/// let a = r#" +/// foo +/// bar"#; +/// let b = "\nfoo\nbar"; +/// assert_eq!(a, b); +/// ``` +pub fn main() { +} diff --git a/src/test/rustdoc/issue-26606.rs b/src/test/rustdoc/issue-26606.rs new file mode 100644 index 000000000..d5cb2c710 --- /dev/null +++ b/src/test/rustdoc/issue-26606.rs @@ -0,0 +1,11 @@ +// aux-build:issue-26606-macro.rs +// ignore-cross-compile +// build-aux-docs + +// @has issue_26606_macro/macro.make_item.html +#[macro_use] +extern crate issue_26606_macro; + +// @has issue_26606/constant.FOO.html +// @has - '//a[@href="../src/issue_26606/issue-26606.rs.html#11"]' 'source' +make_item!(FOO); diff --git a/src/test/rustdoc/issue-26995.rs b/src/test/rustdoc/issue-26995.rs new file mode 100644 index 000000000..fedc9f517 --- /dev/null +++ b/src/test/rustdoc/issue-26995.rs @@ -0,0 +1,7 @@ +// ignore-windows +// compile-flags: --no-defaults + +// @has src/issue_26995/dev/null.html +// @has issue_26995/null/index.html '//a/@href' '../../src/issue_26995/dev/null.html' +#[path="/dev/null"] +pub mod null; diff --git a/src/test/rustdoc/issue-27104.rs b/src/test/rustdoc/issue-27104.rs new file mode 100644 index 000000000..b74c3eb78 --- /dev/null +++ b/src/test/rustdoc/issue-27104.rs @@ -0,0 +1,10 @@ +// compile-flags:--no-defaults --passes strip-priv-imports +// aux-build:empty.rs +// ignore-cross-compile + +// @has issue_27104/index.html +// @!has - 'extern crate std' +// @!has - 'use std::prelude::' + +// @has - 'pub extern crate empty' +pub extern crate empty; diff --git a/src/test/rustdoc/issue-27362.rs b/src/test/rustdoc/issue-27362.rs new file mode 100644 index 000000000..097e4e3b0 --- /dev/null +++ b/src/test/rustdoc/issue-27362.rs @@ -0,0 +1,10 @@ +// aux-build:issue-27362-aux.rs +// ignore-cross-compile + +extern crate issue_27362_aux; + +pub use issue_27362_aux::*; + +// @matches issue_27362/fn.foo.html '//pre' "pub const fn foo()" +// @matches issue_27362/fn.bar.html '//pre' "pub const unsafe fn bar()" +// @matches issue_27362/struct.Foo.html '//h4[@class="code-header"]' "const unsafe fn baz()" diff --git a/src/test/rustdoc/issue-27759.rs b/src/test/rustdoc/issue-27759.rs new file mode 100644 index 000000000..f3739dafd --- /dev/null +++ b/src/test/rustdoc/issue-27759.rs @@ -0,0 +1,14 @@ +#![feature(staged_api)] +#![doc(issue_tracker_base_url = "http://issue_url/")] + +#![unstable(feature="test", issue="27759")] + +// @has issue_27759/unstable/index.html +// @has - '<code>test</code> <a href="http://issue_url/27759">#27759</a>' +#[unstable(feature="test", issue="27759")] +pub mod unstable { + // @has issue_27759/unstable/fn.issue.html + // @has - '<code>test_function</code> <a href="http://issue_url/12345">#12345</a>' + #[unstable(feature="test_function", issue="12345")] + pub fn issue() {} +} diff --git a/src/test/rustdoc/issue-27862.rs b/src/test/rustdoc/issue-27862.rs new file mode 100644 index 000000000..77522f1be --- /dev/null +++ b/src/test/rustdoc/issue-27862.rs @@ -0,0 +1,4 @@ +/// Tests | Table +/// ------|------------- +/// t = b | id = \|x\| x +pub struct Foo; // @has issue_27862/struct.Foo.html //td 'id = |x| x' diff --git a/src/test/rustdoc/issue-28478.rs b/src/test/rustdoc/issue-28478.rs new file mode 100644 index 000000000..497276e68 --- /dev/null +++ b/src/test/rustdoc/issue-28478.rs @@ -0,0 +1,31 @@ +#![feature(associated_type_defaults)] + +// @has issue_28478/trait.Bar.html +pub trait Bar { + // @has - '//*[@id="associatedtype.Bar"]' 'type Bar = ()' + // @has - '//*[@href="#associatedtype.Bar"]' 'Bar' + type Bar = (); + // @has - '//*[@id="associatedconstant.Baz"]' 'const Baz: usize' + // @has - '//*[@href="#associatedconstant.Baz"]' 'Baz' + const Baz: usize = 7; + // @has - '//*[@id="tymethod.bar"]' 'fn bar' + fn bar(); + // @has - '//*[@id="method.baz"]' 'fn baz' + fn baz() { } +} + +// @has issue_28478/struct.Foo.html +pub struct Foo; + +impl Foo { + // @has - '//*[@href="#method.foo"]' 'foo' + pub fn foo() {} +} + +impl Bar for Foo { + // @has - '//*[@href="trait.Bar.html#associatedtype.Bar"]' 'Bar' + // @has - '//*[@href="trait.Bar.html#associatedconstant.Baz"]' 'Baz' + // @has - '//*[@href="trait.Bar.html#tymethod.bar"]' 'bar' + fn bar() {} + // @has - '//*[@href="trait.Bar.html#method.baz"]' 'baz' +} diff --git a/src/test/rustdoc/issue-28927.rs b/src/test/rustdoc/issue-28927.rs new file mode 100644 index 000000000..38a520850 --- /dev/null +++ b/src/test/rustdoc/issue-28927.rs @@ -0,0 +1,6 @@ +// aux-build:issue-28927-2.rs +// aux-build:issue-28927-1.rs +// ignore-cross-compile + +pub extern crate issue_28927_1 as inner1; +pub use inner1 as foo; diff --git a/src/test/rustdoc/issue-29449.rs b/src/test/rustdoc/issue-29449.rs new file mode 100644 index 000000000..0d829cf6f --- /dev/null +++ b/src/test/rustdoc/issue-29449.rs @@ -0,0 +1,20 @@ +// @has issue_29449/struct.Foo.html +pub struct Foo; + +impl Foo { + // @has - '//*[@id="examples"]//a' 'Examples' + // @has - '//*[@id="panics"]//a' 'Panics' + /// # Examples + /// # Panics + pub fn bar() {} + + // @has - '//*[@id="examples-1"]//a' 'Examples' + /// # Examples + pub fn bar_1() {} + + // @has - '//*[@id="examples-2"]//a' 'Examples' + // @has - '//*[@id="panics-1"]//a' 'Panics' + /// # Examples + /// # Panics + pub fn bar_2() {} +} diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs new file mode 100644 index 000000000..635c3175f --- /dev/null +++ b/src/test/rustdoc/issue-29503.rs @@ -0,0 +1,18 @@ +use std::fmt; + +// @has issue_29503/trait.MyTrait.html +pub trait MyTrait { + fn my_string(&self) -> String; +} + +// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug" +impl<T> MyTrait for T +where + T: fmt::Debug, +{ + fn my_string(&self) -> String { + format!("{:?}", self) + } +} + +pub fn main() {} diff --git a/src/test/rustdoc/issue-29584.rs b/src/test/rustdoc/issue-29584.rs new file mode 100644 index 000000000..28e1efec6 --- /dev/null +++ b/src/test/rustdoc/issue-29584.rs @@ -0,0 +1,8 @@ +// aux-build:issue-29584.rs +// ignore-cross-compile + +extern crate issue_29584; + +// @has issue_29584/struct.Foo.html +// @!has - 'impl Bar for' +pub use issue_29584::Foo; diff --git a/src/test/rustdoc/issue-30109.rs b/src/test/rustdoc/issue-30109.rs new file mode 100644 index 000000000..e9447538a --- /dev/null +++ b/src/test/rustdoc/issue-30109.rs @@ -0,0 +1,14 @@ +// build-aux-docs +// aux-build:issue-30109-1.rs +// ignore-cross-compile + +pub mod quux { + extern crate issue_30109_1 as bar; + use self::bar::Bar; + + pub trait Foo {} + + // @has issue_30109/quux/trait.Foo.html \ + // '//a/@href' '../issue_30109_1/struct.Bar.html' + impl Foo for Bar {} +} diff --git a/src/test/rustdoc/issue-30252.rs b/src/test/rustdoc/issue-30252.rs new file mode 100644 index 000000000..c3777362a --- /dev/null +++ b/src/test/rustdoc/issue-30252.rs @@ -0,0 +1,6 @@ +// compile-flags:--test --cfg feature="bar" + +/// ```rust +/// assert_eq!(cfg!(feature = "bar"), true); +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc/issue-30366.rs b/src/test/rustdoc/issue-30366.rs new file mode 100644 index 000000000..c6274a058 --- /dev/null +++ b/src/test/rustdoc/issue-30366.rs @@ -0,0 +1,6 @@ +// @has issue_30366/index.html '//a/@href' 'http://www.rust-lang.org/' + +/// Describe it. [Link somewhere][1]. +/// +/// [1]: http://www.rust-lang.org/ +pub fn here_is_a_fn() { } diff --git a/src/test/rustdoc/issue-31808.rs b/src/test/rustdoc/issue-31808.rs new file mode 100644 index 000000000..e55c5bd4f --- /dev/null +++ b/src/test/rustdoc/issue-31808.rs @@ -0,0 +1,11 @@ +// Test that associated item impls on primitive types don't crash rustdoc + +pub trait Foo { + const BAR: usize; + type BAZ; +} + +impl Foo for () { + const BAR: usize = 0; + type BAZ = usize; +} diff --git a/src/test/rustdoc/issue-31899.rs b/src/test/rustdoc/issue-31899.rs new file mode 100644 index 000000000..e7a8ee239 --- /dev/null +++ b/src/test/rustdoc/issue-31899.rs @@ -0,0 +1,59 @@ +// @has issue_31899/index.html +// @has - 'Make this line a bit longer.' +// @!has - 'rust rust-example-rendered' +// @!has - 'use ndarray::arr2' +// @!has - 'prohibited' + +/// A tuple or fixed size array that can be used to index an array. +/// Make this line a bit longer. +/// +/// ``` +/// use ndarray::arr2; +/// +/// let mut a = arr2(&[[0, 1], [0, 0]]); +/// a[[1, 1]] = 1; +/// assert_eq!(a[[0, 1]], 1); +/// assert_eq!(a[[1, 1]], 1); +/// ``` +/// +/// **Note** the blanket implementation that's not visible in rustdoc: +/// `impl<D> NdIndex for D where D: Dimension { ... }` +pub fn bar() {} + +/// Some line +/// +/// # prohibited +pub fn foo() {} + +/// Some line +/// +/// 1. prohibited +/// 2. bar +pub fn baz() {} + +/// Some line +/// +/// - prohibited +/// - bar +pub fn qux() {} + +/// Some line +/// +/// * prohibited +/// * bar +pub fn quz() {} + +/// Some line +/// +/// > prohibited +/// > bar +pub fn qur() {} + +/// Some line +/// +/// prohibited +/// ===== +/// +/// Second +/// ------ +pub fn qut() {} diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs new file mode 100644 index 000000000..01f955381 --- /dev/null +++ b/src/test/rustdoc/issue-32374.rs @@ -0,0 +1,27 @@ +#![feature(staged_api)] +#![doc(issue_tracker_base_url = "https://issue_url/")] +#![unstable(feature = "test", issue = "32374")] + +// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \ +// 'Deprecated' +// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \ +// 'Experimental' +// @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs' + +// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \ +// '👎 Deprecated since 1.0.0: text' +// @has - '<code>test</code> <a href="https://issue_url/32374">#32374</a>' +// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \ +// '🔬 This is a nightly-only experimental API. \(test\s#32374\)$' +/// Docs +#[deprecated(since = "1.0.0", note = "text")] +#[unstable(feature = "test", issue = "32374")] +pub struct T; + +// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \ +// '👎 Deprecated since 1.0.0: deprecated' +// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \ +// '🔬 This is a nightly-only experimental API. (test #32374)' +#[deprecated(since = "1.0.0", note = "deprecated")] +#[unstable(feature = "test", issue = "32374", reason = "unstable")] +pub struct U; diff --git a/src/test/rustdoc/issue-32395.rs b/src/test/rustdoc/issue-32395.rs new file mode 100644 index 000000000..13468c153 --- /dev/null +++ b/src/test/rustdoc/issue-32395.rs @@ -0,0 +1,15 @@ +// aux-build:variant-struct.rs +// build-aux-docs +// ignore-cross-compile + +// @has variant_struct/enum.Foo.html +// @!has - 'pub qux' +// @!has - 'pub(crate) qux' +// @!has - 'pub Bar' +extern crate variant_struct; + +// @has issue_32395/enum.Foo.html +// @!has - 'pub qux' +// @!has - 'pub(crate) qux' +// @!has - 'pub Bar' +pub use variant_struct::Foo; diff --git a/src/test/rustdoc/issue-32556.rs b/src/test/rustdoc/issue-32556.rs new file mode 100644 index 000000000..e1cf11509 --- /dev/null +++ b/src/test/rustdoc/issue-32556.rs @@ -0,0 +1,5 @@ +/// Blah blah blah +/// ```ignore (testing rustdoc's handling of ignore) +/// bad_assert!(); +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc/issue-32890.rs b/src/test/rustdoc/issue-32890.rs new file mode 100644 index 000000000..970954433 --- /dev/null +++ b/src/test/rustdoc/issue-32890.rs @@ -0,0 +1,17 @@ +// @has issue_32890/struct.Foo.html +pub struct Foo<T>(T); + +impl Foo<u8> { + // @has - '//a[@href="#method.pass"]' 'pass' + pub fn pass() {} +} + +impl Foo<u16> { + // @has - '//a[@href="#method.pass-1"]' 'pass' + pub fn pass() {} +} + +impl Foo<u32> { + // @has - '//a[@href="#method.pass-2"]' 'pass' + pub fn pass() {} +} diff --git a/src/test/rustdoc/issue-33069.rs b/src/test/rustdoc/issue-33069.rs new file mode 100644 index 000000000..0213a53ca --- /dev/null +++ b/src/test/rustdoc/issue-33069.rs @@ -0,0 +1,10 @@ +pub trait Bar {} + +#[doc(hidden)] +pub mod hidden { + pub struct Foo; +} + +// @has issue_33069/trait.Bar.html +// @!has - '//code' 'impl Bar for Foo' +impl Bar for hidden::Foo {} diff --git a/src/test/rustdoc/issue-33178-1.rs b/src/test/rustdoc/issue-33178-1.rs new file mode 100644 index 000000000..4dc425346 --- /dev/null +++ b/src/test/rustdoc/issue-33178-1.rs @@ -0,0 +1,10 @@ +// aux-build:empty.rs +// aux-build:variant-struct.rs +// ignore-cross-compile + +// @has issue_33178_1/index.html +// @!has - //a/@title empty +pub extern crate empty; + +// @!has - //a/@title variant_struct +pub extern crate variant_struct as foo; diff --git a/src/test/rustdoc/issue-33178.rs b/src/test/rustdoc/issue-33178.rs new file mode 100644 index 000000000..1f45fe723 --- /dev/null +++ b/src/test/rustdoc/issue-33178.rs @@ -0,0 +1,13 @@ +// aux-build:empty.rs +// aux-build:variant-struct.rs +// build-aux-docs +// ignore-cross-compile + +// @has issue_33178/index.html +// @has - //a/@title empty +// @has - //a/@href ../empty/index.html +pub extern crate empty; + +// @has - //a/@title variant_struct +// @has - //a/@href ../variant_struct/index.html +pub extern crate variant_struct as foo; diff --git a/src/test/rustdoc/issue-33302.rs b/src/test/rustdoc/issue-33302.rs new file mode 100644 index 000000000..1e4791e01 --- /dev/null +++ b/src/test/rustdoc/issue-33302.rs @@ -0,0 +1,51 @@ +// Ensure constant and array length values are not taken from source +// code, which wreaks havoc with macros. + +macro_rules! make { + ($n:expr) => { + pub struct S; + + // @has issue_33302/constant.CST.html \ + // '//pre[@class="rust const"]' 'pub const CST: i32' + pub const CST: i32 = ($n * $n); + // @has issue_33302/static.ST.html \ + // '//pre[@class="rust static"]' 'pub static ST: i32' + pub static ST: i32 = ($n * $n); + + pub trait T<X> { + fn ignore(_: &X) {} + const C: X; + // @has issue_33302/trait.T.html \ + // '//*[@class="rust trait"]' 'const D: i32' + // @has - '//*[@id="associatedconstant.D"]' 'const D: i32' + const D: i32 = ($n * $n); + } + + // @has issue_33302/struct.S.html \ + // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]' + // @has - '//*[@id="associatedconstant.D"]' 'const D: i32' + impl T<[i32; ($n * $n)]> for S { + const C: [i32; ($n * $n)] = [0; ($n * $n)]; + } + + // @has issue_33302/struct.S.html \ + // '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' + // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)' + // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32' + impl T<(i32,)> for S { + const C: (i32,) = ($n,); + } + + // @has issue_33302/struct.S.html \ + // '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S' + // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)' + // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32' + impl T<(i32, i32)> for S { + const C: (i32, i32) = ($n, $n); + const D: i32 = ($n / $n); + } + }; +} + +make!(4); diff --git a/src/test/rustdoc/issue-33592.rs b/src/test/rustdoc/issue-33592.rs new file mode 100644 index 000000000..815439db9 --- /dev/null +++ b/src/test/rustdoc/issue-33592.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +pub trait Foo<T> {} + +pub struct Bar; + +pub struct Baz; + +// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl Foo<i32> for Bar' +impl Foo<i32> for Bar {} + +// @has foo/trait.Foo.html '//h3[@class="code-header in-band"]' 'impl<T> Foo<T> for Baz' +impl<T> Foo<T> for Baz {} diff --git a/src/test/rustdoc/issue-34025.rs b/src/test/rustdoc/issue-34025.rs new file mode 100644 index 000000000..9b9f21cb3 --- /dev/null +++ b/src/test/rustdoc/issue-34025.rs @@ -0,0 +1,12 @@ +#![crate_name = "foo"] + +// @!has 'foo/sys/index.html' +// @!has 'foo/sys/sidebar-items.js' +#[doc(hidden)] +pub mod sys { + extern "C" { + // @!has 'foo/sys/fn.foo.html' + #[doc(hidden)] + pub fn foo(); + } +} diff --git a/src/test/rustdoc/issue-34274.rs b/src/test/rustdoc/issue-34274.rs new file mode 100644 index 000000000..ce5be84a5 --- /dev/null +++ b/src/test/rustdoc/issue-34274.rs @@ -0,0 +1,10 @@ +// aux-build:issue-34274.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +extern crate issue_34274; + +// @has foo/fn.extern_c_fn.html '//a/@href' '../src/issue_34274/issue-34274.rs.html#2' +pub use issue_34274::extern_c_fn; diff --git a/src/test/rustdoc/issue-34423.rs b/src/test/rustdoc/issue-34423.rs new file mode 100644 index 000000000..b429bf8c9 --- /dev/null +++ b/src/test/rustdoc/issue-34423.rs @@ -0,0 +1,10 @@ +pub struct Foo; + +pub trait Bar { + #[doc(hidden)] + fn bar() {} +} + +impl Bar for Foo { + fn bar() {} +} diff --git a/src/test/rustdoc/issue-34473.rs b/src/test/rustdoc/issue-34473.rs new file mode 100644 index 000000000..d96301f3a --- /dev/null +++ b/src/test/rustdoc/issue-34473.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] + +mod second { + pub struct SomeTypeWithLongName; +} + +// @has foo/index.html +// @!has - SomeTypeWithLongName +// @has foo/struct.SomeType.html +// @!has foo/struct.SomeTypeWithLongName.html +pub use second::{SomeTypeWithLongName as SomeType}; diff --git a/src/test/rustdoc/issue-34928.rs b/src/test/rustdoc/issue-34928.rs new file mode 100644 index 000000000..4184086f6 --- /dev/null +++ b/src/test/rustdoc/issue-34928.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +pub trait Bar {} + +// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;' +pub struct Foo<T>(pub T) where T: Bar; diff --git a/src/test/rustdoc/issue-35169-2.rs b/src/test/rustdoc/issue-35169-2.rs new file mode 100644 index 000000000..f08466baf --- /dev/null +++ b/src/test/rustdoc/issue-35169-2.rs @@ -0,0 +1,40 @@ +use std::ops::Deref; +use std::ops::DerefMut; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn by_ref(&self) {} + pub fn by_explicit_ref(self: &Foo) {} + pub fn by_mut_ref(&mut self) {} + pub fn by_explicit_mut_ref(self: &mut Foo) {} + pub fn by_explicit_box(self: Box<Foo>) {} + pub fn by_explicit_self_box(self: Box<Self>) {} + pub fn static_foo() {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +impl DerefMut for Bar { + fn deref_mut(&mut self) -> &mut Foo { loop {} } +} + +// @has issue_35169_2/struct.Bar.html +// @has - '//*[@id="method.by_ref"]//h4[@class="code-header"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_explicit_ref"]//h4[@class="code-header"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="method.by_mut_ref"]//h4[@class="code-header"]' 'fn by_mut_ref(&mut self)' +// @has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)' +// @has - '//*[@id="method.by_explicit_mut_ref"]//h4[@class="code-header"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="method.by_explicit_box"]//h4[@class="code-header"]' 'fn by_explicit_box(self: Box<Foo>)' +// @!has - '//*[@id="method.by_explicit_box"]' 'fn by_explicit_box(self: Box<Foo>)' +// @!has - '//*[@id="method.by_explicit_self_box"]//h4[@class="code-header"]' 'fn by_explicit_self_box(self: Box<Self>)' +// @!has - '//*[@id="method.by_explicit_self_box"]' 'fn by_explicit_self_box(self: Box<Self>)' +// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()' +// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' diff --git a/src/test/rustdoc/issue-35169.rs b/src/test/rustdoc/issue-35169.rs new file mode 100644 index 000000000..70a2265c8 --- /dev/null +++ b/src/test/rustdoc/issue-35169.rs @@ -0,0 +1,35 @@ +use std::ops::Deref; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn by_ref(&self) {} + pub fn by_explicit_ref(self: &Foo) {} + pub fn by_mut_ref(&mut self) {} + pub fn by_explicit_mut_ref(self: &mut Foo) {} + pub fn by_explicit_box(self: Box<Foo>) {} + pub fn by_explicit_self_box(self: Box<Self>) {} + pub fn static_foo() {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +// @has issue_35169/struct.Bar.html +// @has - '//*[@id="method.by_ref"]//h4[@class="code-header"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_explicit_ref"]//h4[@class="code-header"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)' +// @!has - '//*[@id="method.by_mut_ref"]//h4[@class="code-header"]' 'fn by_mut_ref(&mut self)' +// @!has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)' +// @!has - '//*[@id="method.by_explicit_mut_ref"]//h4[@class="code-header"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="method.by_explicit_box"]//h4[@class="code-header"]' 'fn by_explicit_box(self: Box<Foo>)' +// @!has - '//*[@id="method.by_explicit_box"]' 'fn by_explicit_box(self: Box<Foo>)' +// @!has - '//*[@id="method.by_explicit_self_box"]//h4[@class="code-header"]' 'fn by_explicit_self_box(self: Box<Self>)' +// @!has - '//*[@id="method.by_explicit_self_box"]' 'fn by_explicit_self_box(self: Box<Self>)' +// @!has - '//*[@id="method.static_foo"]//h4[@class="code-header"]' 'fn static_foo()' +// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' diff --git a/src/test/rustdoc/issue-35488.rs b/src/test/rustdoc/issue-35488.rs new file mode 100644 index 000000000..c1bf9ceea --- /dev/null +++ b/src/test/rustdoc/issue-35488.rs @@ -0,0 +1,13 @@ +mod foo { + pub enum Foo { + Bar, + } + pub use self::Foo::*; +} + +// @has 'issue_35488/index.html' '//code' 'pub use self::Foo::*;' +// @has 'issue_35488/enum.Foo.html' +pub use self::foo::*; + +// @has 'issue_35488/index.html' '//code' 'pub use std::option::Option::None;' +pub use std::option::Option::None; diff --git a/src/test/rustdoc/issue-36031.rs b/src/test/rustdoc/issue-36031.rs new file mode 100644 index 000000000..af1b32fd2 --- /dev/null +++ b/src/test/rustdoc/issue-36031.rs @@ -0,0 +1,9 @@ +// aux-build:issue-36031.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +extern crate issue_36031; + +pub use issue_36031::Foo; diff --git a/src/test/rustdoc/issue-38129.rs b/src/test/rustdoc/issue-38129.rs new file mode 100644 index 000000000..156d50fa5 --- /dev/null +++ b/src/test/rustdoc/issue-38129.rs @@ -0,0 +1,99 @@ +// compile-flags:--test + +// This file tests the source-partitioning behavior of rustdoc. +// Each test contains some code that should be put into the generated +// `fn main` and some attributes should be left outside (except the first +// one, which has no attributes). +// If the #![recursion_limit] attribute is incorrectly left inside, +// then the tests will fail because the macro recurses 128 times. + +/// ``` +/// assert_eq!(1 + 1, 2); +/// ``` +pub fn simple() {} + +/// ``` +/// #![recursion_limit = "1024"] +/// macro_rules! recurse { +/// (()) => {}; +/// (() $($rest:tt)*) => { recurse!($($rest)*); } +/// } +/// recurse!(() () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () ()); +/// assert_eq!(1 + 1, 2); +/// ``` +pub fn non_feature_attr() {} + +/// ``` +/// #![feature(core_intrinsics)] +/// assert_eq!(1 + 1, 2); +/// ``` +pub fn feature_attr() {} + +/// ``` +/// #![feature(core_intrinsics)] +/// #![recursion_limit = "1024"] +/// macro_rules! recurse { +/// (()) => {}; +/// (() $($rest:tt)*) => { recurse!($($rest)*); } +/// } +/// recurse!(() () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () ()); +/// assert_eq!(1 + 1, 2); +/// ``` +pub fn both_attrs() {} + +/// ``` +/// #![recursion_limit = "1024"] +/// #![feature(core_intrinsics)] +/// macro_rules! recurse { +/// (()) => {}; +/// (() $($rest:tt)*) => { recurse!($($rest)*); } +/// } +/// recurse!(() () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () () +/// () () () () () () () ()); +/// assert_eq!(1 + 1, 2); +/// ``` +pub fn both_attrs_reverse() {} diff --git a/src/test/rustdoc/issue-38219.rs b/src/test/rustdoc/issue-38219.rs new file mode 100644 index 000000000..fa57c58c7 --- /dev/null +++ b/src/test/rustdoc/issue-38219.rs @@ -0,0 +1,8 @@ +// compile-flags:--test +// should-fail + +/// ``` +/// fail +/// ``` +#[macro_export] +macro_rules! foo { () => {} } diff --git a/src/test/rustdoc/issue-40936.rs b/src/test/rustdoc/issue-40936.rs new file mode 100644 index 000000000..4d2e4c17b --- /dev/null +++ b/src/test/rustdoc/issue-40936.rs @@ -0,0 +1,6 @@ +// aux-build:issue-40936.rs +// build-aux-docs + +#![crate_name = "foo"] + +extern crate issue_40936; diff --git a/src/test/rustdoc/issue-41783.rs b/src/test/rustdoc/issue-41783.rs new file mode 100644 index 000000000..cb9b9b153 --- /dev/null +++ b/src/test/rustdoc/issue-41783.rs @@ -0,0 +1,19 @@ +// @has issue_41783/struct.Foo.html +// @!has - 'space' +// @!has - 'comment' +// @has - '# <span class="ident">single' +// @has - '## <span class="ident">double</span>' +// @has - '### <span class="ident">triple</span>' +// @has - '<span class="attribute">#[<span class="ident">outer</span>]</span>' +// @has - '<span class="attribute">#![<span class="ident">inner</span>]</span>' + +/// ```no_run +/// # # space +/// # comment +/// ## single +/// ### double +/// #### triple +/// ##[outer] +/// ##![inner] +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc/issue-42760.rs b/src/test/rustdoc/issue-42760.rs new file mode 100644 index 000000000..a5394c7d9 --- /dev/null +++ b/src/test/rustdoc/issue-42760.rs @@ -0,0 +1,15 @@ +#![allow(rustdoc::invalid_rust_codeblocks)] + +// @has issue_42760/struct.NonGen.html +// @has - '//h2' 'Example' + +/// Item docs. +/// +#[doc="Hello there!"] +/// +/// # Example +/// +/// ```rust +/// // some code here +/// ``` +pub struct NonGen; diff --git a/src/test/rustdoc/issue-43153.rs b/src/test/rustdoc/issue-43153.rs new file mode 100644 index 000000000..0fe680f10 --- /dev/null +++ b/src/test/rustdoc/issue-43153.rs @@ -0,0 +1,10 @@ +// Test that `include!` in a doc test searches relative to the directory in +// which the test is declared. + +// compile-flags:--test + +/// ```rust +/// include!("auxiliary/empty.rs"); +/// fn main() {} +/// ``` +pub struct Foo; diff --git a/src/test/rustdoc/issue-43701.rs b/src/test/rustdoc/issue-43701.rs new file mode 100644 index 000000000..44335e961 --- /dev/null +++ b/src/test/rustdoc/issue-43701.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +pub use std::vec::Vec; + +// @!has implementors/core/clone/trait.Clone.js diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs new file mode 100644 index 000000000..767d09d85 --- /dev/null +++ b/src/test/rustdoc/issue-43869.rs @@ -0,0 +1,72 @@ +pub fn g() -> impl Iterator<Item=u8> { + Some(1u8).into_iter() +} + +#[allow(unused_parens)] +pub fn h() -> (impl Iterator<Item=u8>) { + Some(1u8).into_iter() +} + +pub fn i() -> impl Iterator<Item=u8> + 'static { + Some(1u8).into_iter() +} + +pub fn j() -> impl Iterator<Item=u8> + Clone { + Some(1u8).into_iter() +} + +pub fn k() -> [impl Clone; 2] { + [123u32, 456u32] +} + +pub fn l() -> (impl Clone, impl Default) { + (789u32, -123i32) +} + +pub fn m() -> &'static impl Clone { + &1u8 +} + +pub fn n() -> *const impl Clone { + &1u8 +} + +pub fn o() -> &'static [impl Clone] { + b":)" +} + +// issue #44731 +pub fn test_44731_0() -> Box<impl Iterator<Item=u8>> { + Box::new(g()) +} + +pub fn test_44731_1() -> Result<Box<impl Clone>, ()> { + Ok(Box::new(j())) +} + +// NOTE these involve Fn sugar, where impl Trait is disallowed for now, see issue #45994 +// +//pub fn test_44731_2() -> Box<Fn(impl Clone)> { +// Box::new(|_: u32| {}) +//} +// +//pub fn test_44731_3() -> Box<Fn() -> impl Clone> { +// Box::new(|| 0u32) +//} + +pub fn test_44731_4() -> Box<Iterator<Item=impl Clone>> { + Box::new(g()) +} + +// @has issue_43869/fn.g.html +// @has issue_43869/fn.h.html +// @has issue_43869/fn.i.html +// @has issue_43869/fn.j.html +// @has issue_43869/fn.k.html +// @has issue_43869/fn.l.html +// @has issue_43869/fn.m.html +// @has issue_43869/fn.n.html +// @has issue_43869/fn.o.html +// @has issue_43869/fn.test_44731_0.html +// @has issue_43869/fn.test_44731_1.html +// @has issue_43869/fn.test_44731_4.html diff --git a/src/test/rustdoc/issue-43893.rs b/src/test/rustdoc/issue-43893.rs new file mode 100644 index 000000000..95d551934 --- /dev/null +++ b/src/test/rustdoc/issue-43893.rs @@ -0,0 +1,19 @@ +// ignore-cross-compile + +#![crate_name = "foo"] + +pub trait SomeTrait {} +pub struct SomeStruct; + +// @has foo/trait.SomeTrait.html '//a/@href' '../src/foo/issue-43893.rs.html#9' +impl SomeTrait for usize {} + +// @has foo/trait.SomeTrait.html '//a/@href' '../src/foo/issue-43893.rs.html#12-14' +impl SomeTrait for SomeStruct { + // deliberately multi-line impl +} + +pub trait AnotherTrait {} + +// @has foo/trait.AnotherTrait.html '//a/@href' '../src/foo/issue-43893.rs.html#19' +impl<T> AnotherTrait for T {} diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs new file mode 100644 index 000000000..86479e6fb --- /dev/null +++ b/src/test/rustdoc/issue-45584.rs @@ -0,0 +1,15 @@ +#![crate_name = "foo"] + +pub trait Bar<T, U> {} + +// @has 'foo/struct.Foo1.html' +pub struct Foo1; +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1" +impl Bar<Foo1, &'static Foo1> for Foo1 {} + +// @has 'foo/struct.Foo2.html' +pub struct Foo2; +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8" +impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/src/test/rustdoc/issue-46271.rs b/src/test/rustdoc/issue-46271.rs new file mode 100644 index 000000000..b38ef20c5 --- /dev/null +++ b/src/test/rustdoc/issue-46271.rs @@ -0,0 +1,5 @@ +// hopefully this doesn't cause an ICE + +pub fn foo() { + extern crate std; +} diff --git a/src/test/rustdoc/issue-46377.rs b/src/test/rustdoc/issue-46377.rs new file mode 100644 index 000000000..4489f038c --- /dev/null +++ b/src/test/rustdoc/issue-46377.rs @@ -0,0 +1,3 @@ +// @has 'issue_46377/index.html' '//*[@class="item-right docblock-short"]' 'Check out this struct!' +/// # Check out this struct! +pub struct SomeStruct; diff --git a/src/test/rustdoc/issue-46380-2.rs b/src/test/rustdoc/issue-46380-2.rs new file mode 100644 index 000000000..7004d18dc --- /dev/null +++ b/src/test/rustdoc/issue-46380-2.rs @@ -0,0 +1,9 @@ +pub trait PublicTrait<T> {} + +// @has issue_46380_2/struct.PublicStruct.html +pub struct PublicStruct; + +// @!has - '//*[@class="impl"]' 'impl PublicTrait<PrivateStruct> for PublicStruct' +impl PublicTrait<PrivateStruct> for PublicStruct {} + +struct PrivateStruct; diff --git a/src/test/rustdoc/issue-46727.rs b/src/test/rustdoc/issue-46727.rs new file mode 100644 index 000000000..00e9127a3 --- /dev/null +++ b/src/test/rustdoc/issue-46727.rs @@ -0,0 +1,7 @@ +// aux-build:issue-46727.rs + +extern crate issue_46727; + +// @has issue_46727/trait.Foo.html +// @has - '//h3[@class="code-header in-band"]' 'impl<T> Foo for Bar<[T; 3]>' +pub use issue_46727::{Foo, Bar}; diff --git a/src/test/rustdoc/issue-46766.rs b/src/test/rustdoc/issue-46766.rs new file mode 100644 index 000000000..36ab73956 --- /dev/null +++ b/src/test/rustdoc/issue-46766.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +pub enum Enum{Variant} +pub use self::Enum::Variant; + +// @!has foo/index.html '//a/@href' './Enum/index.html' diff --git a/src/test/rustdoc/issue-46767.rs b/src/test/rustdoc/issue-46767.rs new file mode 100644 index 000000000..ef6ed104b --- /dev/null +++ b/src/test/rustdoc/issue-46767.rs @@ -0,0 +1,9 @@ +#![crate_name = "foo"] + +mod private { + pub enum Enum{Variant} +} +pub use self::private::Enum::*; + +// @!has-dir foo/private +// @!has foo/index.html '//a/@href' 'private/index.html' diff --git a/src/test/rustdoc/issue-46976.rs b/src/test/rustdoc/issue-46976.rs new file mode 100644 index 000000000..c59f8c72e --- /dev/null +++ b/src/test/rustdoc/issue-46976.rs @@ -0,0 +1 @@ +pub fn ice(f: impl Fn()) {} diff --git a/src/test/rustdoc/issue-47038.rs b/src/test/rustdoc/issue-47038.rs new file mode 100644 index 000000000..810ddca3e --- /dev/null +++ b/src/test/rustdoc/issue-47038.rs @@ -0,0 +1,10 @@ +#![feature(decl_macro)] + +#![crate_name = "foo"] + +use std::vec; + +// @has 'foo/index.html' +// @!has - '//*[@id="macros"]' 'Macros' +// @!has - '//a/@href' 'macro.vec.html' +// @!has 'foo/macro.vec.html' diff --git a/src/test/rustdoc/issue-47197-blank-line-in-doc-block.rs b/src/test/rustdoc/issue-47197-blank-line-in-doc-block.rs new file mode 100644 index 000000000..19994475d --- /dev/null +++ b/src/test/rustdoc/issue-47197-blank-line-in-doc-block.rs @@ -0,0 +1,8 @@ +// @has issue_47197_blank_line_in_doc_block/fn.whose_woods_these_are_i_think_i_know.html + +/** +* snow + +* ice +*/ +pub fn whose_woods_these_are_i_think_i_know() {} diff --git a/src/test/rustdoc/issue-47639.rs b/src/test/rustdoc/issue-47639.rs new file mode 100644 index 000000000..4b3456b86 --- /dev/null +++ b/src/test/rustdoc/issue-47639.rs @@ -0,0 +1,6 @@ +// This should not ICE +pub fn test() { + macro_rules! foo { + () => () + } +} diff --git a/src/test/rustdoc/issue-48377.rs b/src/test/rustdoc/issue-48377.rs new file mode 100644 index 000000000..c32bcf380 --- /dev/null +++ b/src/test/rustdoc/issue-48377.rs @@ -0,0 +1,13 @@ +// compile-flags:--test + +//! This is a doc comment +//! +//! ```rust +//! fn main() {} +//! ``` +//! +//! With a trailing code fence +//! ``` + +/// Some foo function +pub fn foo() {} diff --git a/src/test/rustdoc/issue-48414.rs b/src/test/rustdoc/issue-48414.rs new file mode 100644 index 000000000..b35743d88 --- /dev/null +++ b/src/test/rustdoc/issue-48414.rs @@ -0,0 +1,11 @@ +// aux-build:issue-48414.rs + +// ICE when resolving paths for a trait that linked to another trait, when both were in an external +// crate + +#![crate_name = "base"] + +extern crate issue_48414; + +#[doc(inline)] +pub use issue_48414::{SomeTrait, OtherTrait}; diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs new file mode 100644 index 000000000..d88c29217 --- /dev/null +++ b/src/test/rustdoc/issue-50159.rs @@ -0,0 +1,20 @@ +pub trait Signal { + type Item; +} + +pub trait Signal2 { + type Item2; +} + +impl<B, C> Signal2 for B where B: Signal<Item = C> { + type Item2 = C; +} + +// @has issue_50159/struct.Switch.html +// @has - '//h3[@class="code-header in-band"]' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send' +// @has - '//h3[@class="code-header in-band"]' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync' +// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +pub struct Switch<B: Signal> { + pub inner: <B as Signal2>::Item2, +} diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs new file mode 100644 index 000000000..ee11ccc68 --- /dev/null +++ b/src/test/rustdoc/issue-51236.rs @@ -0,0 +1,14 @@ +use std::marker::PhantomData; + +pub mod traits { + pub trait Owned<'a> { + type Reader; + } +} + +// @has issue_51236/struct.Owned.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send" +pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> { + marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>, +} diff --git a/src/test/rustdoc/issue-52873.rs b/src/test/rustdoc/issue-52873.rs new file mode 100644 index 000000000..8000ce73b --- /dev/null +++ b/src/test/rustdoc/issue-52873.rs @@ -0,0 +1,171 @@ +// Regression test for #52873. We used to ICE due to unexpected +// overflows when checking for "blanket impl inclusion". + +use std::marker::PhantomData; +use std::cmp::Ordering; +use std::ops::{Add, Mul}; + +pub type True = B1; +pub type False = B0; +pub type U0 = UTerm; +pub type U1 = UInt<UTerm, B1>; + +pub trait NonZero {} + +pub trait Bit { +} + +pub trait Unsigned { +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct B0; + +impl B0 { + #[inline] + pub fn new() -> B0 { + B0 + } +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct B1; + +impl B1 { + #[inline] + pub fn new() -> B1 { + B1 + } +} + +impl Bit for B0 { +} + +impl Bit for B1 { +} + +impl NonZero for B1 {} + +pub trait PrivatePow<Y, N> { + type Output; +} +pub type PrivatePowOut<A, Y, N> = <A as PrivatePow<Y, N>>::Output; + +pub type Add1<A> = <A as Add<::B1>>::Output; +pub type Prod<A, B> = <A as Mul<B>>::Output; +pub type Square<A> = <A as Mul>::Output; +pub type Sum<A, B> = <A as Add<B>>::Output; + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct UTerm; + +impl UTerm { + #[inline] + pub fn new() -> UTerm { + UTerm + } +} + +impl Unsigned for UTerm { +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct UInt<U, B> { + _marker: PhantomData<(U, B)>, +} + +impl<U: Unsigned, B: Bit> UInt<U, B> { + #[inline] + pub fn new() -> UInt<U, B> { + UInt { + _marker: PhantomData, + } + } +} + +impl<U: Unsigned, B: Bit> Unsigned for UInt<U, B> { +} + +impl<U: Unsigned, B: Bit> NonZero for UInt<U, B> {} + +impl Add<B0> for UTerm { + type Output = UTerm; + fn add(self, _: B0) -> Self::Output { + UTerm + } +} + +impl<U: Unsigned, B: Bit> Add<B0> for UInt<U, B> { + type Output = UInt<U, B>; + fn add(self, _: B0) -> Self::Output { + UInt::new() + } +} + +impl<U: Unsigned> Add<U> for UTerm { + type Output = U; + fn add(self, _: U) -> Self::Output { + unimplemented!() + } +} + +impl<U: Unsigned, B: Bit> Mul<B0> for UInt<U, B> { + type Output = UTerm; + fn mul(self, _: B0) -> Self::Output { + UTerm + } +} + +impl<U: Unsigned, B: Bit> Mul<B1> for UInt<U, B> { + type Output = UInt<U, B>; + fn mul(self, _: B1) -> Self::Output { + UInt::new() + } +} + +impl<U: Unsigned> Mul<U> for UTerm { + type Output = UTerm; + fn mul(self, _: U) -> Self::Output { + UTerm + } +} + +impl<Ul: Unsigned, B: Bit, Ur: Unsigned> Mul<UInt<Ur, B>> for UInt<Ul, B0> +where + Ul: Mul<UInt<Ur, B>>, +{ + type Output = UInt<Prod<Ul, UInt<Ur, B>>, B0>; + fn mul(self, _: UInt<Ur, B>) -> Self::Output { + unimplemented!() + } +} + +pub trait Pow<Exp> { + type Output; +} + +impl<X: Unsigned, N: Unsigned> Pow<N> for X +where + X: PrivatePow<U1, N>, +{ + type Output = PrivatePowOut<X, U1, N>; +} + +impl<Y: Unsigned, X: Unsigned> PrivatePow<Y, U0> for X { + type Output = Y; +} + +impl<Y: Unsigned, X: Unsigned> PrivatePow<Y, U1> for X +where + X: Mul<Y>, +{ + type Output = Prod<X, Y>; +} + +impl<Y: Unsigned, U: Unsigned, B: Bit, X: Unsigned> PrivatePow<Y, UInt<UInt<U, B>, B0>> for X +where + X: Mul, + Square<X>: PrivatePow<Y, UInt<U, B>>, +{ + type Output = PrivatePowOut<Square<X>, Y, UInt<U, B>>; +} diff --git a/src/test/rustdoc/issue-53689.rs b/src/test/rustdoc/issue-53689.rs new file mode 100644 index 000000000..52ce4159d --- /dev/null +++ b/src/test/rustdoc/issue-53689.rs @@ -0,0 +1,16 @@ +// aux-build:issue-53689.rs + +#![crate_name = "foo"] + +extern crate issue_53689; + +// @has foo/trait.MyTrait.html +// @!has - 'MyStruct' +// @count - '//*[h3="impl<T> MyTrait for T"]' 1 +pub trait MyTrait {} + +impl<T> MyTrait for T {} + +mod a { + pub use issue_53689::MyStruct; +} diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs new file mode 100644 index 000000000..c68ffd521 --- /dev/null +++ b/src/test/rustdoc/issue-53812.rs @@ -0,0 +1,20 @@ +pub trait MyIterator {} + +pub struct MyStruct<T>(T); + +macro_rules! array_impls { + ($($N:expr)+) => { + $( + impl<'a, T> MyIterator for &'a MyStruct<[T; $N]> { + } + )+ + } +} + +// @has issue_53812/trait.MyIterator.html +// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>' +array_impls! { 10 3 2 1 0 } diff --git a/src/test/rustdoc/issue-54478-demo-allocator.rs b/src/test/rustdoc/issue-54478-demo-allocator.rs new file mode 100644 index 000000000..4811f363b --- /dev/null +++ b/src/test/rustdoc/issue-54478-demo-allocator.rs @@ -0,0 +1,42 @@ +// Issue #54478: regression test showing that we can demonstrate +// `#[global_allocator]` in code blocks built by `rustdoc`. +// +// ## Background +// +// Changes in lang-item visibility injected failures that were only +// exposed when compiling with `-C prefer-dynamic`. But `rustdoc` used +// `-C prefer-dynamic` (and had done so for years, for reasons we did +// not document at that time). +// +// Rather than try to revise the visbility semanics, we instead +// decided to change `rustdoc` to behave more like the compiler's +// default setting, by leaving off `-C prefer-dynamic`. + +// compile-flags:--test + +//! This is a doc comment +//! +//! ```rust +//! use std::alloc::*; +//! +//! #[global_allocator] +//! static ALLOC: A = A; +//! +//! static mut HIT: bool = false; +//! +//! struct A; +//! +//! unsafe impl GlobalAlloc for A { +//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { +//! HIT = true; +//! System.alloc(layout) +//! } +//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { +//! System.dealloc(ptr, layout); +//! } +//! } +//! +//! fn main() { +//! assert!(unsafe { HIT }); +//! } +//! ``` diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs new file mode 100644 index 000000000..bedaf5c4d --- /dev/null +++ b/src/test/rustdoc/issue-54705.rs @@ -0,0 +1,29 @@ +pub trait ScopeHandle<'scope> {} + + + +// @has issue_54705/struct.ScopeFutureContents.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync" +// +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync" +pub struct ScopeFutureContents<'scope, S> + where S: ScopeHandle<'scope>, +{ + dummy: &'scope S, + this: Box<ScopeFuture<'scope, S>>, +} + +struct ScopeFuture<'scope, S> + where S: ScopeHandle<'scope>, +{ + contents: ScopeFutureContents<'scope, S>, +} + +unsafe impl<'scope, S> Send for ScopeFuture<'scope, S> + where S: ScopeHandle<'scope>, +{} +unsafe impl<'scope, S> Sync for ScopeFuture<'scope, S> + where S: ScopeHandle<'scope>, +{} diff --git a/src/test/rustdoc/issue-55001.rs b/src/test/rustdoc/issue-55001.rs new file mode 100644 index 000000000..f6c7f9a3d --- /dev/null +++ b/src/test/rustdoc/issue-55001.rs @@ -0,0 +1,31 @@ +// Regression test for issue #55001. Previously, we would incorrectly +// cache certain trait selection results when checking for blanket impls, +// resulting in an ICE when we tried to confirm the cached ParamCandidate +// against an obligation. + +pub struct DefaultAllocator; +pub struct Standard; +pub struct Inner; + +pub trait Rand {} + +pub trait Distribution<T> {} +pub trait Allocator<N> {} + +impl<T> Rand for T where Standard: Distribution<T> {} + +impl<A> Distribution<Point<A>> for Standard +where +DefaultAllocator: Allocator<A>, +Standard: Distribution<A> {} + +impl Distribution<Inner> for Standard {} + + +pub struct Point<N> +where DefaultAllocator: Allocator<N> +{ + field: N +} + +fn main() {} diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs new file mode 100644 index 000000000..ee2420d86 --- /dev/null +++ b/src/test/rustdoc/issue-55321.rs @@ -0,0 +1,18 @@ +#![feature(negative_impls)] + +// @has issue_55321/struct.A.html +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl !Send for A" +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl !Sync for A" +pub struct A(); + +impl !Send for A {} +impl !Sync for A {} + +// @has issue_55321/struct.B.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> !Send for B<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> !Sync for B<T>" +pub struct B<T: ?Sized>(A, Box<T>); diff --git a/src/test/rustdoc/issue-55364.rs b/src/test/rustdoc/issue-55364.rs new file mode 100644 index 000000000..14a6f5041 --- /dev/null +++ b/src/test/rustdoc/issue-55364.rs @@ -0,0 +1,86 @@ +// First a module with inner documentation + +// @has issue_55364/subone/index.html +// These foo/bar links in the module's documentation should refer inside `subone` +// @has - '//section[@id="main-content"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo' +// @has - '//section[@id="main-content"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar' +pub mod subone { + //! See either [foo] or [bar]. + + // This should refer to subone's `bar` + // @has issue_55364/subone/fn.foo.html + // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar' + /// See [bar] + pub fn foo() {} + // This should refer to subone's `foo` + // @has issue_55364/subone/fn.bar.html + // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo' + /// See [foo] + pub fn bar() {} +} + +// A module with outer documentation + +// @has issue_55364/subtwo/index.html +// These foo/bar links in the module's documentation should not reference inside `subtwo` +// @!has - '//section[@id="main-content"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo' +// @!has - '//section[@id="main-content"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar' +// Instead it should be referencing the top level functions +// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo' +// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar' +// Though there should be such links later +// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.foo.html"]' 'foo' +// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.bar.html"]' 'bar' +/// See either [foo] or [bar]. +pub mod subtwo { + + // Despite the module's docs referring to the top level foo/bar, + // this should refer to subtwo's `bar` + // @has issue_55364/subtwo/fn.foo.html + // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar' + /// See [bar] + pub fn foo() {} + // Despite the module's docs referring to the top level foo/bar, + // this should refer to subtwo's `foo` + // @has issue_55364/subtwo/fn.bar.html + // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo' + /// See [foo] + pub fn bar() {} +} + +// These are the function referred to by the module above with outer docs + +/// See [bar] +pub fn foo() {} +/// See [foo] +pub fn bar() {} + +// This module refers to the outer foo/bar by means of `super::` + +// @has issue_55364/subthree/index.html +// This module should also refer to the top level foo/bar +// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo' +// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar' +pub mod subthree { + //! See either [foo][super::foo] or [bar][super::bar] +} + +// Next we go *deeper* - In order to ensure it's not just "this or parent" +// we test `crate::` and a `super::super::...` chain +// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html +// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo' +// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar' +pub mod subfour { + pub mod subfive { + pub mod subsix { + pub mod subseven { + pub mod subeight { + /// See [other foo][crate::subone::foo] + pub fn foo() {} + /// See [other bar][super::super::super::super::super::subtwo::bar] + pub fn bar() {} + } + } + } + } +} diff --git a/src/test/rustdoc/issue-56701.rs b/src/test/rustdoc/issue-56701.rs new file mode 100644 index 000000000..ba00743fc --- /dev/null +++ b/src/test/rustdoc/issue-56701.rs @@ -0,0 +1,33 @@ +// This shouldn't cause a stack overflow when rustdoc is run + +use std::ops::Deref; +use std::ops::DerefMut; + +pub trait SimpleTrait { + type SimpleT; +} + +impl<Inner: SimpleTrait, Outer: Deref<Target = Inner>> SimpleTrait for Outer { + type SimpleT = Inner::SimpleT; +} + +pub trait AnotherTrait { + type AnotherT; +} + +impl<T, Simple: SimpleTrait<SimpleT = Vec<T>>> AnotherTrait for Simple { + type AnotherT = T; +} + +pub struct Unrelated<Inner, UnrelatedT: DerefMut<Target = Vec<Inner>>>(UnrelatedT); + +impl<Inner, UnrelatedT: DerefMut<Target = Vec<Inner>>> Deref for Unrelated<Inner, UnrelatedT> { + type Target = Vec<Inner>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + + +pub fn main() { } diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs new file mode 100644 index 000000000..aef6ddd8d --- /dev/null +++ b/src/test/rustdoc/issue-56822.rs @@ -0,0 +1,24 @@ +struct Wrapper<T>(T); + +trait MyTrait { + type Output; +} + +impl<'a, I, T: 'a> MyTrait for Wrapper<I> + where I: MyTrait<Output=&'a T> +{ + type Output = T; +} + +struct Inner<'a, T>(&'a T); + +impl<'a, T> MyTrait for Inner<'a, T> { + type Output = &'a T; +} + +// @has issue_56822/struct.Parser.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'a> Send for Parser<'a>" +pub struct Parser<'a> { + field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output +} diff --git a/src/test/rustdoc/issue-57180.rs b/src/test/rustdoc/issue-57180.rs new file mode 100644 index 000000000..14bd2b0fe --- /dev/null +++ b/src/test/rustdoc/issue-57180.rs @@ -0,0 +1,7 @@ +// aux-build:issue-57180.rs + +extern crate issue_57180; +use issue_57180::Trait; + +fn main() { +} diff --git a/src/test/rustdoc/issue-60482.rs b/src/test/rustdoc/issue-60482.rs new file mode 100644 index 000000000..0fd1daa74 --- /dev/null +++ b/src/test/rustdoc/issue-60482.rs @@ -0,0 +1,9 @@ +// This code caused a panic in `pulldown-cmark` 0.4.1. + +pub const BASIC_UNICODE: bool = true; + + +/// # `BASIC_UNICODE`: `A` `|` +/// ```text +/// ``` +pub const BASIC_FONTS: bool = true; diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs new file mode 100644 index 000000000..167f0f039 --- /dev/null +++ b/src/test/rustdoc/issue-60726.rs @@ -0,0 +1,35 @@ +use std::marker::PhantomData; + +pub struct True; +pub struct False; + +pub trait InterfaceType{ + type Send; +} + + +pub struct FooInterface<T>(PhantomData<fn()->T>); + +impl<T> InterfaceType for FooInterface<T> { + type Send=False; +} + + +pub struct DynTrait<I>{ + _interface:PhantomData<fn()->I>, + _unsync_unsend:PhantomData<::std::rc::Rc<()>>, +} + +unsafe impl<I> Send for DynTrait<I> +where + I:InterfaceType<Send=True> +{} + +// @has issue_60726/struct.IntoIter.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> !Send for IntoIter<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> !Sync for IntoIter<T>" +pub struct IntoIter<T>{ + hello:DynTrait<FooInterface<T>>, +} diff --git a/src/test/rustdoc/issue-61592.rs b/src/test/rustdoc/issue-61592.rs new file mode 100644 index 000000000..aef038c07 --- /dev/null +++ b/src/test/rustdoc/issue-61592.rs @@ -0,0 +1,15 @@ +// aux-build:issue-61592.rs + +extern crate foo; + +// @has issue_61592/index.html +// @has - '//a[@href="#reexports"]' 'Re-exports' +// @has - '//code' 'pub use foo::FooTrait as _;' +// @!has - '//a[@href="trait._.html"]' +pub use foo::FooTrait as _; + +// @has issue_61592/index.html +// @has - '//a[@href="#reexports"]' 'Re-exports' +// @has - '//code' 'pub use foo::FooStruct as _;' +// @!has - '//a[@href="struct._.html"]' +pub use foo::FooStruct as _; diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs new file mode 100644 index 000000000..d69b94317 --- /dev/null +++ b/src/test/rustdoc/issue-67851-both.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunstable-options --document-private-items --document-hidden-items + +// @has issue_67851_both/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @has issue_67851_both/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs new file mode 100644 index 000000000..8a3cafe4c --- /dev/null +++ b/src/test/rustdoc/issue-67851-hidden.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunstable-options --document-hidden-items + +// @has issue_67851_hidden/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @!has issue_67851_hidden/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs new file mode 100644 index 000000000..4e3cd8328 --- /dev/null +++ b/src/test/rustdoc/issue-67851-neither.rs @@ -0,0 +1,6 @@ +// @!has issue_67851_neither/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @!has issue_67851_neither/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs new file mode 100644 index 000000000..8addc7f3e --- /dev/null +++ b/src/test/rustdoc/issue-67851-private.rs @@ -0,0 +1,8 @@ +// compile-flags: --document-private-items + +// @!has issue_67851_private/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @has issue_67851_private/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-72340.rs b/src/test/rustdoc/issue-72340.rs new file mode 100644 index 000000000..64044cfe9 --- /dev/null +++ b/src/test/rustdoc/issue-72340.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] + +pub struct Body; + +impl Body { + pub fn empty() -> Self { + Body + } + +} + +impl Default for Body { + // @has foo/struct.Body.html '//a/@href' 'struct.Body.html#method.empty' + + /// Returns [`Body::empty()`](Body::empty). + fn default() -> Body { + Body::empty() + } +} diff --git a/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs b/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs new file mode 100644 index 000000000..2700f2370 --- /dev/null +++ b/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs @@ -0,0 +1,14 @@ +// Regression test for ICE #73061 + +// aux-build:issue-73061.rs + +extern crate issue_73061; + +pub struct Z; + +impl issue_73061::Foo for Z { + type X = <issue_73061::F as issue_73061::Foo>::X; + fn x(&self) -> Self::X { + issue_73061::F.x() + } +} diff --git a/src/test/rustdoc/issue-74083.rs b/src/test/rustdoc/issue-74083.rs new file mode 100644 index 000000000..c7f5d7eaa --- /dev/null +++ b/src/test/rustdoc/issue-74083.rs @@ -0,0 +1,21 @@ +use std::ops::Deref; + +pub struct Foo; + +impl Foo { + pub fn foo(&mut self) {} +} + +// @has issue_74083/struct.Bar.html +// @!has - '//div[@class="sidebar-links"]/a[@href="#method.foo"]' 'foo' +pub struct Bar { + foo: Foo, +} + +impl Deref for Bar { + type Target = Foo; + + fn deref(&self) -> &Foo { + &self.foo + } +} diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs new file mode 100644 index 000000000..ac97b94fb --- /dev/null +++ b/src/test/rustdoc/issue-75588.rs @@ -0,0 +1,17 @@ +// aux-build:realcore.rs +// aux-build:real_gimli.rs + +// Ensure unstably exported traits have their Implementors sections. + +#![crate_name = "foo"] +#![feature(extremely_unstable_foo)] + +extern crate realcore; +extern crate real_gimli; + +// issue #74672 +// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice' +pub use realcore::Deref; + +// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo' +pub use realcore::Join; diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs new file mode 100644 index 000000000..a90e0fea0 --- /dev/null +++ b/src/test/rustdoc/issue-76501.rs @@ -0,0 +1,17 @@ +// @has 'issue_76501/fn.bloop.html' '//pre' 'pub const fn bloop() -> i32' +/// A useless function that always returns 1. +pub const fn bloop() -> i32 { + 1 +} + +/// A struct. +pub struct Struct {} + +impl Struct { + // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \ + // 'pub const fn blurp() -> i32' + /// A useless function that always returns 1. + pub const fn blurp() -> i32 { + 1 + } +} diff --git a/src/test/rustdoc/issue-78673.rs b/src/test/rustdoc/issue-78673.rs new file mode 100644 index 000000000..2e4bec254 --- /dev/null +++ b/src/test/rustdoc/issue-78673.rs @@ -0,0 +1,24 @@ +#![crate_name = "issue_78673"] + +pub trait Something {} + +pub trait AnAmazingTrait {} + +impl<T: Something> AnAmazingTrait for T {} + +// @has 'issue_78673/struct.MyStruct.html' +// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct' +// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +pub struct MyStruct; + +impl AnAmazingTrait for MyStruct {} + +// generic structs may have _both_ specific and blanket impls that apply + +// @has 'issue_78673/struct.AnotherStruct.html' +// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>' +// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' +pub struct AnotherStruct<T>(T); + +impl<T: Something> Something for AnotherStruct<T> {} +impl AnAmazingTrait for AnotherStruct<()> {} diff --git a/src/test/rustdoc/issue-78701.rs b/src/test/rustdoc/issue-78701.rs new file mode 100644 index 000000000..e3e46468f --- /dev/null +++ b/src/test/rustdoc/issue-78701.rs @@ -0,0 +1,20 @@ +#![crate_name = "foo"] + +// This test ensures that if a blanket impl has the same ID as another impl, it'll +// link to the blanket impl and not the other impl. Basically, we're checking if +// the ID is correctly derived. + +// @has 'foo/struct.AnotherStruct.html' +// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3C()%3E"]' 1 +// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3CT%3E"]' 1 + +pub trait Something {} + +pub trait AnAmazingTrait {} + +impl<T: Something> AnAmazingTrait for T {} + +pub struct AnotherStruct<T>(T); + +impl<T: Something> Something for AnotherStruct<T> {} +impl AnAmazingTrait for AnotherStruct<()> {} diff --git a/src/test/rustdoc/issue-79201.rs b/src/test/rustdoc/issue-79201.rs new file mode 100644 index 000000000..f95d79cd4 --- /dev/null +++ b/src/test/rustdoc/issue-79201.rs @@ -0,0 +1,41 @@ +#![feature(doc_cfg)] + +// @has 'issue_79201/trait.Foo.html' +// @count - '//*[@class="stab portability"]' 6 +// @matches - '//*[@class="stab portability"]' 'crate feature foo-root' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-public-mod' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-private-mod' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-fn' +// @matches - '//*[@class="stab portability"]' 'crate feature foo-method' + +pub trait Foo {} + +#[doc(cfg(feature = "foo-root"))] +impl crate::Foo for usize {} + +#[doc(cfg(feature = "foo-public-mod"))] +pub mod public { + impl crate::Foo for u8 {} +} + +#[doc(cfg(feature = "foo-private-mod"))] +mod private { + impl crate::Foo for u16 {} +} + +#[doc(cfg(feature = "foo-const"))] +const _: () = { + impl crate::Foo for u32 {} +}; + +#[doc(cfg(feature = "foo-fn"))] +fn __() { + impl crate::Foo for u64 {} +} + +#[doc(cfg(feature = "foo-method"))] +impl dyn Foo { + fn __() { + impl crate::Foo for u128 {} + } +} diff --git a/src/test/rustdoc/issue-80233-normalize-auto-trait.rs b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs new file mode 100644 index 000000000..515e617b4 --- /dev/null +++ b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs @@ -0,0 +1,37 @@ +// Regression test for issue #80233 +// Tests that we don't ICE when processing auto traits + +#![crate_type = "lib"] +pub trait Trait1 {} + +pub trait Trait2 { + type Type2; +} + +pub trait Trait3 { + type Type3; +} + +impl Trait2 for Struct1 { + type Type2 = Struct1; +} + +impl<I: Trait2> Trait2 for Vec<I> { + type Type2 = Vec<I::Type2>; +} + +impl<T: Trait1> Trait3 for T { + type Type3 = Struct1; +} + +impl<T: Trait3> Trait3 for Vec<T> { + type Type3 = Vec<T::Type3>; +} + +pub struct Struct1 {} + +// @has issue_80233_normalize_auto_trait/struct.Question.html +// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Question<T>' +pub struct Question<T: Trait1> { + pub ins: <<Vec<T> as Trait3>::Type3 as Trait2>::Type2, +} diff --git a/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs new file mode 100644 index 000000000..8999e6a88 --- /dev/null +++ b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs @@ -0,0 +1,16 @@ +use std::convert::AsRef; +pub struct Local; + +// @has issue_82465_asref_for_and_of_local/struct.Local.html '//h3[@class="code-header in-band"]' 'impl AsRef<str> for Local' +impl AsRef<str> for Local { + fn as_ref(&self) -> &str { + todo!() + } +} + +// @has - '//h3[@class="code-header in-band"]' 'impl AsRef<Local> for str' +impl AsRef<Local> for str { + fn as_ref(&self) -> &Local { + todo!() + } +} diff --git a/src/test/rustdoc/issue-85454.rs b/src/test/rustdoc/issue-85454.rs new file mode 100644 index 000000000..3351b5c83 --- /dev/null +++ b/src/test/rustdoc/issue-85454.rs @@ -0,0 +1,29 @@ +// aux-build:issue-85454.rs +// build-aux-docs +#![crate_name = "foo"] + +extern crate issue_85454; + +// @has foo/trait.FromResidual.html +// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }' +pub trait FromResidual<R = <Self as Try>::Residual> { + fn from_residual(residual: R) -> Self; +} + +pub trait Try: FromResidual { + type Output; + type Residual; + fn from_output(output: Self::Output) -> Self; + fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; +} + +pub enum ControlFlow<B, C = ()> { + Continue(C), + Break(B), +} + +pub mod reexport { + // @has foo/reexport/trait.FromResidual.html + // @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }' + pub use issue_85454::*; +} diff --git a/src/test/rustdoc/issue-86620.rs b/src/test/rustdoc/issue-86620.rs new file mode 100644 index 000000000..ef15946ec --- /dev/null +++ b/src/test/rustdoc/issue-86620.rs @@ -0,0 +1,9 @@ +// aux-build:issue-86620-1.rs + +extern crate issue_86620_1; + +use issue_86620_1::*; + +// @!has issue_86620/struct.S.html '//*[@id="method.vzip"]//a[@class="fnname"]/@href' #tymethod.vzip +// @has issue_86620/struct.S.html '//*[@id="method.vzip"]//a[@class="anchor"]/@href' #method.vzip +pub struct S; diff --git a/src/test/rustdoc/issue-88600.rs b/src/test/rustdoc/issue-88600.rs new file mode 100644 index 000000000..fc63ed343 --- /dev/null +++ b/src/test/rustdoc/issue-88600.rs @@ -0,0 +1,35 @@ +// This test ensure that #[doc(hidden)] is applied correctly in enum variant fields. + +// Denotes a field which should be hidden. +pub struct H; + +// Denotes a field which should not be hidden (shown). +pub struct S; + +// @has issue_88600/enum.FooEnum.html +pub enum FooEnum { + // @has - '//*[@id="variant.HiddenTupleItem"]//code' 'HiddenTupleItem(_)' + // @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0 + HiddenTupleItem(#[doc(hidden)] H), + // @has - '//*[@id="variant.MultipleHidden"]//code' 'MultipleHidden(_, _)' + // @count - '//*[@id="variant.MultipleHidden.field.0"]' 0 + // @count - '//*[@id="variant.MultipleHidden.field.1"]' 0 + MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H), + // @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)' + // @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0 + // @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S' + MixedHiddenFirst(#[doc(hidden)] H, /** dox */ S), + // @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)' + // @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S' + // @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0 + MixedHiddenLast(/** dox */ S, #[doc(hidden)] H), + // @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct' + // @count - '//*[@id="variant.HiddenStruct.field.h"]' 0 + // @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S' + HiddenStruct { + #[doc(hidden)] + h: H, + /// dox + s: S, + }, +} diff --git a/src/test/rustdoc/issue-89309-heading-levels.rs b/src/test/rustdoc/issue-89309-heading-levels.rs new file mode 100644 index 000000000..bb706c28f --- /dev/null +++ b/src/test/rustdoc/issue-89309-heading-levels.rs @@ -0,0 +1,29 @@ +#![crate_name = "foo"] + +// @has foo/trait.Read.html +// @has - '//h2' 'Trait examples' +/// # Trait examples +pub trait Read { + // @has - '//h5' 'Function examples' + /// # Function examples + fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()>; +} + +pub struct Foo; + +// @has foo/struct.Foo.html +impl Foo { + // @has - '//h5' 'Implementation header' + /// # Implementation header + pub fn bar(&self) -> usize { + 1 + } +} + +impl Read for Foo { + // @has - '//h5' 'Trait implementation header' + /// # Trait implementation header + fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> { + Ok(1) + } +} diff --git a/src/test/rustdoc/issue-89852.rs b/src/test/rustdoc/issue-89852.rs new file mode 100644 index 000000000..45544dbee --- /dev/null +++ b/src/test/rustdoc/issue-89852.rs @@ -0,0 +1,14 @@ +// edition:2018 + +#![no_core] +#![feature(no_core)] + +// @matches 'issue_89852/sidebar-items.js' '"repro"' +// @!matches 'issue_89852/sidebar-items.js' '"repro".*"repro"' + +#[macro_export] +macro_rules! repro { + () => {}; +} + +pub use crate::repro as repro2; diff --git a/src/test/rustdoc/issue-95633.rs b/src/test/rustdoc/issue-95633.rs new file mode 100644 index 000000000..a71d0a037 --- /dev/null +++ b/src/test/rustdoc/issue-95633.rs @@ -0,0 +1,7 @@ +// compile-flags: --document-private-items + +// This ensures that no ICE is triggered when rustdoc is run on this code. + +mod stdlib { + pub (crate) use std::i8; +} diff --git a/src/test/rustdoc/issue-95873.rs b/src/test/rustdoc/issue-95873.rs new file mode 100644 index 000000000..ff33fb63a --- /dev/null +++ b/src/test/rustdoc/issue-95873.rs @@ -0,0 +1,2 @@ +// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;" +pub use ::std as x; diff --git a/src/test/rustdoc/issue-96381.rs b/src/test/rustdoc/issue-96381.rs new file mode 100644 index 000000000..f0f123f85 --- /dev/null +++ b/src/test/rustdoc/issue-96381.rs @@ -0,0 +1,16 @@ +// should-fail + +#![allow(unused)] + +trait Foo<T>: Sized { + fn bar(i: i32, t: T, s: &Self) -> (T, i32); +} + +impl Foo<usize> for () { + fn bar(i: _, t: _, s: _) -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions + (1, 2) + } +} + +fn main() {} diff --git a/src/test/rustdoc/issue-98697.rs b/src/test/rustdoc/issue-98697.rs new file mode 100644 index 000000000..83e08094c --- /dev/null +++ b/src/test/rustdoc/issue-98697.rs @@ -0,0 +1,17 @@ +// aux-build:issue-98697-reexport-with-anonymous-lifetime.rs +// ignore-cross-compile + +// When reexporting a function with a HRTB with anonymous lifetimes, +// make sure the anonymous lifetimes are not rendered. +// +// https://github.com/rust-lang/rust/issues/98697 + +extern crate issue_98697_reexport_with_anonymous_lifetime; + +// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>() where F: Fn(&str)' +// @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<' +pub use issue_98697_reexport_with_anonymous_lifetime::repro; + +// @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl MyTrait<&Extra> for Extra' +// @!has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl<' +pub use issue_98697_reexport_with_anonymous_lifetime::Extra; diff --git a/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs new file mode 100644 index 000000000..e74881d38 --- /dev/null +++ b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs @@ -0,0 +1,19 @@ +// aux-build:issue-99221-aux.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +#[macro_use] +extern crate issue_99221_aux; + +pub use issue_99221_aux::*; + +// @count foo/index.html '//a[@class="macro"]' 1 + +mod inner { + #[macro_export] + macro_rules! print { + () => () + } +} diff --git a/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs new file mode 100644 index 000000000..46d59654b --- /dev/null +++ b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs @@ -0,0 +1,17 @@ +// aux-build:issue-99221-aux.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +#[macro_use] +extern crate issue_99221_aux; + +pub use issue_99221_aux::*; + +// @count foo/index.html '//a[@class="macro"]' 1 + +#[macro_export] +macro_rules! print { + () => () +} diff --git a/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs new file mode 100644 index 000000000..41e64726a --- /dev/null +++ b/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs @@ -0,0 +1,14 @@ +// aux-build:issue-99221-aux.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +#[macro_use] +extern crate issue_99221_aux; + +pub use issue_99221_aux::*; + +// @count foo/index.html '//a[@class="struct"][@title="foo::Print struct"]' 1 + +pub struct Print; diff --git a/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs new file mode 100644 index 000000000..3208fea05 --- /dev/null +++ b/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs @@ -0,0 +1,16 @@ +// aux-build:issue-99734-aux.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +#[macro_use] +extern crate issue_99734_aux; + +pub use issue_99734_aux::*; + +// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1 + +extern "C" { + pub fn main() -> std::ffi::c_int; +} diff --git a/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs new file mode 100644 index 000000000..b2f9b8b46 --- /dev/null +++ b/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs @@ -0,0 +1,14 @@ +// aux-build:issue-99734-aux.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +#[macro_use] +extern crate issue_99734_aux; + +pub use issue_99734_aux::*; + +// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1 + +pub mod task {} diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs new file mode 100644 index 000000000..1cebe4c67 --- /dev/null +++ b/src/test/rustdoc/keyword.rs @@ -0,0 +1,23 @@ +#![crate_name = "foo"] + +#![feature(rustdoc_internals)] + +// @has foo/index.html '//h2[@id="keywords"]' 'Keywords' +// @has foo/index.html '//a[@href="keyword.match.html"]' 'match' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords' +// @has foo/keyword.match.html '//a[@class="keyword"]' 'match' +// @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match' +// @has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +// @has foo/index.html '//a/@href' '../foo/index.html' +// @!has foo/foo/index.html +// @!has-dir foo/foo +// @!has foo/index.html '//span' '🔒' +#[doc(keyword = "match")] +/// this is a test! +mod foo{} + +// @has foo/keyword.foo.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[doc(keyword = "foo")] +/// hello +mod bar {} diff --git a/src/test/rustdoc/legacy-const-generic.rs b/src/test/rustdoc/legacy-const-generic.rs new file mode 100644 index 000000000..46a50e2fc --- /dev/null +++ b/src/test/rustdoc/legacy-const-generic.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] +#![feature(rustc_attrs)] + +// @has 'foo/fn.foo.html' +// @has - '//*[@class="rust fn"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]' +#[rustc_legacy_const_generics(1)] +pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] { + [x, Y, z] +} + +// @has 'foo/fn.bar.html' +// @has - '//*[@class="rust fn"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]' +#[rustc_legacy_const_generics(1, 2)] +pub fn bar<const Y: usize, const Z: usize>(x: usize) -> [usize; 3] { + [x, Y, z] +} diff --git a/src/test/rustdoc/lifetime-name.rs b/src/test/rustdoc/lifetime-name.rs new file mode 100644 index 000000000..5d30a745a --- /dev/null +++ b/src/test/rustdoc/lifetime-name.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +// @has 'foo/type.Resolutions.html' +// @has - '//*[@class="rust typedef"]' "pub type Resolutions<'tcx> = &'tcx u8;" +pub type Resolutions<'tcx> = &'tcx u8; diff --git a/src/test/rustdoc/line-breaks.rs b/src/test/rustdoc/line-breaks.rs new file mode 100644 index 000000000..29c16fcd4 --- /dev/null +++ b/src/test/rustdoc/line-breaks.rs @@ -0,0 +1,30 @@ +#![crate_name = "foo"] + +use std::ops::Add; +use std::fmt::Display; + +//@count foo/fn.function_with_a_really_long_name.html //pre/br 2 +pub fn function_with_a_really_long_name(parameter_one: i32, + parameter_two: i32) + -> Option<i32> { + Some(parameter_one + parameter_two) +} + +//@count foo/fn.short_name.html //pre/br 0 +pub fn short_name(param: i32) -> i32 { param + 1 } + +//@count foo/fn.where_clause.html //pre/br 4 +pub fn where_clause<T, U>(param_one: T, + param_two: U) + where T: Add<U> + Display + Copy, + U: Add<T> + Display + Copy, + T::Output: Display + Add<U::Output> + Copy, + <T::Output as Add<U::Output>>::Output: Display, + U::Output: Display + Copy +{ + let x = param_one + param_two; + println!("{} + {} = {}", param_one, param_two, x); + let y = param_two + param_one; + println!("{} + {} = {}", param_two, param_one, y); + println!("{} + {} = {}", x, y, x + y); +} diff --git a/src/test/rustdoc/link-assoc-const.rs b/src/test/rustdoc/link-assoc-const.rs new file mode 100644 index 000000000..75a2531a3 --- /dev/null +++ b/src/test/rustdoc/link-assoc-const.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +// @has foo/index.html '//a[@href="foo/constant.FIRSTCONST.html"]' 'foo::FIRSTCONST' +// @has foo/index.html '//a[@href="struct.Bar.html#associatedconstant.CONST"]' 'Bar::CONST' + +//! We have here [`foo::FIRSTCONST`] and [`Bar::CONST`]. + +pub mod foo { + pub const FIRSTCONST: u32 = 42; +} + +pub struct Bar; + +impl Bar { + pub const CONST: u32 = 42; +} diff --git a/src/test/rustdoc/link-title-escape.rs b/src/test/rustdoc/link-title-escape.rs new file mode 100644 index 000000000..01aa8d00b --- /dev/null +++ b/src/test/rustdoc/link-title-escape.rs @@ -0,0 +1,9 @@ +#![allow(rustdoc::broken_intra_doc_links)] + +#![crate_name = "foo"] + +//! hello [foo] +//! +//! [foo]: url 'title & <stuff> & "things"' + +// @has 'foo/index.html' 'title & <stuff> & "things"' diff --git a/src/test/rustdoc/logo-class-default.rs b/src/test/rustdoc/logo-class-default.rs new file mode 100644 index 000000000..a7016d227 --- /dev/null +++ b/src/test/rustdoc/logo-class-default.rs @@ -0,0 +1,4 @@ +// Note: this test is paired with logo-class.rs. +// @has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' '' +// @has logo_class_default/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' '' +pub struct SomeStruct; diff --git a/src/test/rustdoc/logo-class.rs b/src/test/rustdoc/logo-class.rs new file mode 100644 index 000000000..f071f356a --- /dev/null +++ b/src/test/rustdoc/logo-class.rs @@ -0,0 +1,10 @@ +#![doc(html_logo_url = + "https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png")] +// Note: this test is paired with logo-class-default.rs. + +// @has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' '' +// @!has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' '' +// +// @has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' '' +// @!has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' '' +pub struct SomeStruct; diff --git a/src/test/rustdoc/macro-document-private-duplicate.rs b/src/test/rustdoc/macro-document-private-duplicate.rs new file mode 100644 index 000000000..7576c1326 --- /dev/null +++ b/src/test/rustdoc/macro-document-private-duplicate.rs @@ -0,0 +1,25 @@ +// ignore-test (fails spuriously, see issue #89228) + +// FIXME: If two macros in the same module have the same name +// (yes, that's a thing), rustdoc lists both of them on the index page, +// but only documents the first one on the page for the macro. +// Fortunately, this can only happen in document private items mode, +// but it still isn't ideal beahvior. +// +// See https://github.com/rust-lang/rust/pull/88019#discussion_r693920453 +// +// compile-flags: --document-private-items + +// @has macro_document_private_duplicate/index.html 'Doc 1.' +// @has macro_document_private_duplicate/macro.a_macro.html 'Doc 1.' +/// Doc 1. +macro_rules! a_macro { + () => () +} + +// @has macro_document_private_duplicate/index.html 'Doc 2.' +// @!has macro_document_private_duplicate/macro.a_macro.html 'Doc 2.' +/// Doc 2. +macro_rules! a_macro { + () => () +} diff --git a/src/test/rustdoc/macro-document-private.rs b/src/test/rustdoc/macro-document-private.rs new file mode 100644 index 000000000..d2496913f --- /dev/null +++ b/src/test/rustdoc/macro-document-private.rs @@ -0,0 +1,19 @@ +// Checks that private macros are documented when `--document-private-items` +// is present. +// +// This is a regression test for issue #73754. +// +// compile-flags: --document-private-items + +#![feature(decl_macro)] + + +// @has macro_document_private/macro.some_macro.html +macro some_macro { + (a: tt) => {} +} + +// @has macro_document_private/macro.another_macro.html +macro_rules! another_macro { + (a: tt) => {} +} diff --git a/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html new file mode 100644 index 000000000..ce5d3a846 --- /dev/null +++ b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html @@ -0,0 +1,6 @@ +macro_rules! linebreak { + ( + <= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 + 26 27 28 => + ) => { ... }; +}
\ No newline at end of file diff --git a/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html new file mode 100644 index 000000000..28f15522a --- /dev/null +++ b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html @@ -0,0 +1,15 @@ +macro_rules! morestuff { + ( + <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static + "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* + "space inside curly brace" : { 2 a } + "no space inside empty delimiters" : () [] {} + "no space before comma or semicolon" : a, (a), { a }, a; [T; 0]; + "the three repetition specifiers" : $(@)*, $(@)+, $(@)? + "repetition separators" : $(@)|*, $(@)|+, $(@)==*, $(@)static* + "plus or star cannot be a repetition separator" : $(@)+ * $(@)* + + "no space between ident and paren" : let _ = f(0) + f[0] + Struct {}; + "space between keyword and paren" : return (a,) & for x in (..) + "some special case keywords" : pub(crate), fn() -> u8, Self(0, 0) => + ) => { ... }; +}
\ No newline at end of file diff --git a/src/test/rustdoc/macro-generated-macro.rs b/src/test/rustdoc/macro-generated-macro.rs new file mode 100644 index 000000000..1a423cac1 --- /dev/null +++ b/src/test/rustdoc/macro-generated-macro.rs @@ -0,0 +1,39 @@ +macro_rules! make_macro { + ($macro_name:ident $($matcher:tt)*) => { + #[macro_export] + macro_rules! $macro_name { + (<= $($matcher)* =>) => {}; + } + } +} + +// @has macro_generated_macro/macro.interpolations.html //pre 'macro_rules! interpolations {' +// @has - //pre '(<= type $($i:ident)::* + $e:expr =>) => { ... };' +make_macro!(interpolations type $($i:ident)::* + $e:expr); +interpolations!(<= type foo::bar + x.sort() =>); + +// @has macro_generated_macro/macro.attributes.html //pre 'macro_rules! attributes {' +// @has - //pre '(<= #![no_std] #[cfg(feature = "alloc")] =>) => { ... };' +make_macro!(attributes #![no_std] #[cfg(feature = "alloc")]); + +// @has macro_generated_macro/macro.groups.html //pre 'macro_rules! groups {' +// @has - //pre '(<= fn {} () { foo[0] } =>) => { ... };' +make_macro!(groups fn {}() {foo[0]}); + +// @snapshot macro_linebreak_pre macro_generated_macro/macro.linebreak.html //pre/text() +make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28); + +// @snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text() +make_macro!(morestuff + "space between most kinds of tokens": 1 $x + @ :: >>= 'static + "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)* + "space inside curly brace": { 2 a } + "no space inside empty delimiters": () [] {} + "no space before comma or semicolon": a, (a), { a }, a; [T; 0]; + "the three repetition specifiers": $(@)*, $(@)+, $(@)? + "repetition separators": $(@)|*, $(@)|+, $(@)==*, $(@)static* + "plus or star cannot be a repetition separator": $(@)+ * $(@)* + + "no space between ident and paren": let _ = f(0) + f[0] + Struct {}; + "space between keyword and paren": return (a,) & for x in (..) + "some special case keywords": pub(crate), fn() -> u8, Self(0, 0) +); diff --git a/src/test/rustdoc/macro-higher-kinded-function.rs b/src/test/rustdoc/macro-higher-kinded-function.rs new file mode 100644 index 000000000..02a430564 --- /dev/null +++ b/src/test/rustdoc/macro-higher-kinded-function.rs @@ -0,0 +1,21 @@ +#![crate_name = "foo"] + +pub struct TyCtxt<'tcx>(&'tcx u8); + +macro_rules! gen { + ($(($name:ident, $tcx:lifetime, [$k:ty], [$r:ty]))*) => { + pub struct Providers { + $(pub $name: for<$tcx> fn(TyCtxt<$tcx>, $k) -> $r,)* + } + } +} + +// @has 'foo/struct.Providers.html' +// @has - '//*[@class="docblock item-decl"]//code' "pub a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8," +// @has - '//*[@class="docblock item-decl"]//code' "pub b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16," +// @has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8" +// @has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16" +gen! { + (a, 'tcx, [u8], [i8]) + (b, 'tcx, [u16], [i16]) +} diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs new file mode 100644 index 000000000..b4aaacf7b --- /dev/null +++ b/src/test/rustdoc/macro-in-async-block.rs @@ -0,0 +1,9 @@ +// Regression issue for rustdoc ICE encountered in PR #72088. +// edition:2018 +#![feature(decl_macro)] + +fn main() { + async { + macro m() {} + }; +} diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs new file mode 100644 index 000000000..b4411d927 --- /dev/null +++ b/src/test/rustdoc/macro-in-closure.rs @@ -0,0 +1,16 @@ +// Regression issue for rustdoc ICE encountered in PR #65252. + +#![feature(decl_macro)] + +fn main() { + || { + macro m() {} + }; + + let _ = || { + macro n() {} + }; + + let cond = true; + let _ = || if cond { macro n() {} } else { panic!() }; +} diff --git a/src/test/rustdoc/macro-indirect-use.rs b/src/test/rustdoc/macro-indirect-use.rs new file mode 100644 index 000000000..b2d9336cf --- /dev/null +++ b/src/test/rustdoc/macro-indirect-use.rs @@ -0,0 +1,16 @@ +// Checks that it is possible to make a macro public through a `pub use` of its +// parent module. +// +// This is a regression test for issue #87257. + +#![feature(decl_macro)] + +mod outer { + pub mod inner { + pub macro some_macro() {} + } +} + +// @has macro_indirect_use/inner/index.html +// @has macro_indirect_use/inner/macro.some_macro.html +pub use outer::inner; diff --git a/src/test/rustdoc/macro-private-not-documented.rs b/src/test/rustdoc/macro-private-not-documented.rs new file mode 100644 index 000000000..ae8b0e722 --- /dev/null +++ b/src/test/rustdoc/macro-private-not-documented.rs @@ -0,0 +1,19 @@ +// Checks that private macros aren't documented by default. They +// should be still be documented in `--document-private-items` mode, +// but that's tested in `macro-document-private.rs`. +// +// +// This is a regression text for issue #88453. +#![feature(decl_macro)] + +// @!has macro_private_not_documented/index.html 'a_macro' +// @!has macro_private_not_documented/macro.a_macro.html +macro_rules! a_macro { + () => () +} + +// @!has macro_private_not_documented/index.html 'another_macro' +// @!has macro_private_not_documented/macro.another_macro.html +macro another_macro { + () => () +} diff --git a/src/test/rustdoc/macro_pub_in_module.rs b/src/test/rustdoc/macro_pub_in_module.rs new file mode 100644 index 000000000..4fd85d689 --- /dev/null +++ b/src/test/rustdoc/macro_pub_in_module.rs @@ -0,0 +1,82 @@ +// aux-build:macro_pub_in_module.rs +// edition:2018 +// build-aux-docs + +//! See issue #74355 +#![feature(decl_macro, no_core, rustc_attrs)] +#![crate_name = "krate"] +#![no_core] + + // @has external_crate/some_module/macro.external_macro.html + // @!has external_crate/macro.external_macro.html +extern crate external_crate; + +pub mod inner { + // @has krate/inner/macro.raw_const.html + // @!has krate/macro.raw_const.html + pub macro raw_const() {} + + // @has krate/inner/macro.test.html + // @!has krate/macro.test.html + #[rustc_builtin_macro] + pub macro test($item:item) {} + + // @has krate/inner/macro.Clone.html + // @!has krate/macro.Clone.html + #[rustc_builtin_macro] + pub macro Clone($item:item) {} + + // Make sure the logic is not affected by re-exports. + mod unrenamed { + // @!has krate/macro.unrenamed.html + #[rustc_macro_transparency = "semitransparent"] + pub macro unrenamed() {} + } + // @has krate/inner/macro.unrenamed.html + pub use unrenamed::unrenamed; + + mod private { + // @!has krate/macro.m.html + pub macro m() {} + } + // @has krate/inner/macro.renamed.html + // @!has krate/macro.renamed.html + pub use private::m as renamed; + + mod private2 { + // @!has krate/macro.m2.html + pub macro m2() {} + } + use private2 as renamed_mod; + // @has krate/inner/macro.m2.html + pub use renamed_mod::m2; + + // @has krate/inner/macro.external_macro.html + // @!has krate/macro.external_macro.html + pub use ::external_crate::some_module::external_macro; +} + +// Namespaces: Make sure the logic does not mix up a function name with a module name… +fn both_fn_and_mod() { + // @!has krate/macro.in_both_fn_and_mod.html + pub macro in_both_fn_and_mod() {} +} +pub mod both_fn_and_mod { + // @!has krate/both_fn_and_mod/macro.in_both_fn_and_mod.html +} + +const __: () = { + // @!has krate/macro.in_both_const_and_mod.html + pub macro in_both_const_and_mod() {} +}; +pub mod __ { + // @!has krate/__/macro.in_both_const_and_mod.html +} + +enum Enum { + Crazy = { + // @!has krate/macro.this_is_getting_weird.html; + pub macro this_is_getting_weird() {} + 42 + }, +} diff --git a/src/test/rustdoc/macro_rules-matchers.rs b/src/test/rustdoc/macro_rules-matchers.rs new file mode 100644 index 000000000..efc3b21e6 --- /dev/null +++ b/src/test/rustdoc/macro_rules-matchers.rs @@ -0,0 +1,39 @@ +// This is a regression test for issue #86208. +// It is also a general test of macro_rules! display. + +#![crate_name = "foo"] + +// @has 'foo/macro.todo.html' +// @has - '//span[@class="macro"]' 'macro_rules!' +// @has - '//span[@class="ident"]' 'todo' +// Note: the only op is the `+` +// @count - '//pre[@class="rust macro"]//span[@class="op"]' 1 + +// @has - '{ () => { ... }; ($(' +// @has - '//span[@class="macro-nonterminal"]' '$' +// @has - '//span[@class="macro-nonterminal"]' 'arg' +// @has - ':' +// @has - '//span[@class="ident"]' 'tt' +// @has - '),' +// @has - '//span[@class="op"]' '+' +// @has - ') => { ... }; }' +pub use std::todo; + +mod mod1 { + // @has 'foo/macro.macro1.html' + // @has - 'macro_rules!' + // @has - 'macro1' + // @has - '{ () => { ... }; ($(' + // @has - '//span[@class="macro-nonterminal"]' '$' + // @has - '//span[@class="macro-nonterminal"]' 'arg' + // @has - ':' + // @has - 'expr' + // @has - '),' + // @has - '+' + // @has - ') => { ... }; }' + #[macro_export] + macro_rules! macro1 { + () => {}; + ($($arg:expr),+) => { stringify!($($arg),+) }; + } +} diff --git a/src/test/rustdoc/macros.rs b/src/test/rustdoc/macros.rs new file mode 100644 index 000000000..ae0cf7a14 --- /dev/null +++ b/src/test/rustdoc/macros.rs @@ -0,0 +1,24 @@ +// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {' +// @has - //pre '() => { ... };' +// @has - //pre '($a:tt) => { ... };' +// @has - //pre '($e:expr) => { ... };' +#[macro_export] +macro_rules! my_macro { + () => []; + ($a:tt) => (); + ($e:expr) => {}; +} + +// Check that exported macro defined in a module are shown at crate root. +// @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {' +// @has - //pre '() => { ... };' +// @has - //pre '($a:tt) => { ... };' +// @has - //pre '($e:expr) => { ... };' +mod sub { + #[macro_export] + macro_rules! my_sub_macro { + () => {}; + ($a:tt) => {}; + ($e:expr) => {}; + } +} diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs new file mode 100644 index 000000000..b2ee077bc --- /dev/null +++ b/src/test/rustdoc/manual_impl.rs @@ -0,0 +1,77 @@ +// @has manual_impl/trait.T.html +// @has - '//*[@class="docblock"]' 'Docs associated with the trait definition.' +// @has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.' +// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.' +/// Docs associated with the trait definition. +pub trait T { + /// Docs associated with the trait a_method definition. + fn a_method(&self) -> usize; + + /// Docs associated with the trait b_method definition. + fn b_method(&self) -> usize { + self.a_method() + } + + /// Docs associated with the trait c_method definition. + /// + /// There is another line + fn c_method(&self) -> usize { + self.a_method() + } +} + +// @has manual_impl/struct.S1.html '//*[@class="trait"]' 'T' +// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.' +// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.' +// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.' +// @!has - '//*[@class="docblock"]' 'There is another line' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Read more' +pub struct S1(usize); + +/// Docs associated with the S1 trait implementation. +impl T for S1 { + /// Docs associated with the S1 trait a_method implementation. + fn a_method(&self) -> usize { + self.0 + } +} + +// @has manual_impl/struct.S2.html '//*[@class="trait"]' 'T' +// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.' +// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.' +// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' +pub struct S2(usize); + +/// Docs associated with the S2 trait implementation. +impl T for S2 { + /// Docs associated with the S2 trait a_method implementation. + fn a_method(&self) -> usize { + self.0 + } + + /// Docs associated with the S2 trait c_method implementation. + fn c_method(&self) -> usize { + 5 + } +} + +// @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T' +// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait implementation.' +// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.' +pub struct S3(usize); + +/// Docs associated with the S3 trait implementation. +impl T for S3 { + fn a_method(&self) -> usize { + self.0 + } + + /// Docs associated with the S3 trait b_method implementation. + fn b_method(&self) -> usize { + 5 + } +} diff --git a/src/test/rustdoc/markdown-summaries.rs b/src/test/rustdoc/markdown-summaries.rs new file mode 100644 index 000000000..b843e28e7 --- /dev/null +++ b/src/test/rustdoc/markdown-summaries.rs @@ -0,0 +1,27 @@ +#![crate_type = "lib"] +#![crate_name = "summaries"] + +//! This *summary* has a [link] and `code`. +//! +//! This is the second paragraph. +//! +//! [link]: https://example.com + +// @has search-index.js 'This <em>summary</em> has a link and <code>code</code>.' +// @!has - 'second paragraph' + +/// This `code` will be rendered in a code tag. +/// +/// This text should not be rendered. +pub struct Sidebar; + +// @has search-index.js 'This <code>code</code> will be rendered in a code tag.' +// @has summaries/sidebar-items.js 'This `code` will be rendered in a code tag.' +// @!has - 'text should not be rendered' + +/// ```text +/// this block should not be rendered +/// ``` +pub struct Sidebar2; + +// @!has summaries/sidebar-items.js 'block should not be rendered' diff --git a/src/test/rustdoc/masked.rs b/src/test/rustdoc/masked.rs new file mode 100644 index 000000000..c7ad690d6 --- /dev/null +++ b/src/test/rustdoc/masked.rs @@ -0,0 +1,30 @@ +// aux-build:masked.rs + +#![feature(doc_masked)] + +#![crate_name = "foo"] + +#[doc(masked)] +extern crate masked; + +// @!has 'search-index.js' 'masked_method' + +// @!has 'foo/struct.String.html' 'MaskedTrait' +// @!has 'foo/struct.String.html' 'masked_method' +pub use std::string::String; + +// @!has 'foo/trait.Clone.html' 'MaskedStruct' +pub use std::clone::Clone; + +// @!has 'foo/struct.MyStruct.html' 'MaskedTrait' +// @!has 'foo/struct.MyStruct.html' 'masked_method' +pub struct MyStruct; + +impl masked::MaskedTrait for MyStruct { + fn masked_method() {} +} + +// @!has 'foo/trait.MyTrait.html' 'MaskedStruct' +pub trait MyTrait {} + +impl MyTrait for masked::MaskedStruct {} diff --git a/src/test/rustdoc/method-list.rs b/src/test/rustdoc/method-list.rs new file mode 100644 index 000000000..50f4af3aa --- /dev/null +++ b/src/test/rustdoc/method-list.rs @@ -0,0 +1,18 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//*[@class="sidebar-elems"]//section//a' 'super_long_name' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Disp' +pub struct Foo(usize); + +impl Foo { + pub fn super_long_name() {} +} + +pub trait Disp { + fn disp_trait_method(); +} + +impl Disp for Foo { + fn disp_trait_method() {} +} diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html new file mode 100644 index 000000000..8ff114b99 --- /dev/null +++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html @@ -0,0 +1,4 @@ +<div class="docblock"><p>Hello world!</p> +<p>Goodbye! +Hello again!</p> +</div>
\ No newline at end of file diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html new file mode 100644 index 000000000..8ff114b99 --- /dev/null +++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html @@ -0,0 +1,4 @@ +<div class="docblock"><p>Hello world!</p> +<p>Goodbye! +Hello again!</p> +</div>
\ No newline at end of file diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html new file mode 100644 index 000000000..a4ee4b141 --- /dev/null +++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html @@ -0,0 +1,3 @@ +<div class="docblock"><p>Par 1</p> +<p>Par 2</p> +</div>
\ No newline at end of file diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.rs b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs new file mode 100644 index 000000000..a27c5ae6d --- /dev/null +++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs @@ -0,0 +1,25 @@ +#![crate_name = "foo"] + +// @has 'foo/struct.S1.html' +// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]' + +#[doc = "Hello world!\n\n"] +/// Goodbye! +#[doc = " Hello again!\n"] +pub struct S1; + +// @has 'foo/struct.S2.html' +// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]' + +/// Hello world! +/// +#[doc = "Goodbye!"] +/// Hello again! +pub struct S2; + +// @has 'foo/struct.S3.html' +// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]' +/** Par 1 +*/ /// +/// Par 2 +pub struct S3; diff --git a/src/test/rustdoc/mod-stackoverflow.rs b/src/test/rustdoc/mod-stackoverflow.rs new file mode 100644 index 000000000..45b1de216 --- /dev/null +++ b/src/test/rustdoc/mod-stackoverflow.rs @@ -0,0 +1,6 @@ +// aux-build:mod-stackoverflow.rs +// ignore-cross-compile + +extern crate mod_stackoverflow; +pub use mod_stackoverflow::tree; +pub use mod_stackoverflow::tree2; diff --git a/src/test/rustdoc/module-impls.rs b/src/test/rustdoc/module-impls.rs new file mode 100644 index 000000000..198b3446c --- /dev/null +++ b/src/test/rustdoc/module-impls.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +pub use std::marker::Send; + +// @!has foo/index.html 'Implementations' diff --git a/src/test/rustdoc/must_implement_one_of.rs b/src/test/rustdoc/must_implement_one_of.rs new file mode 100644 index 000000000..1f1dd5d57 --- /dev/null +++ b/src/test/rustdoc/must_implement_one_of.rs @@ -0,0 +1,10 @@ +#![crate_name = "c"] +#![feature(rustc_attrs)] + +#[rustc_must_implement_one_of(a, b)] +// @matches c/trait.Trait.html '//*[@class="stab must_implement"]' \ +// 'At least one of the `a`, `b` methods is required.$' +pub trait Trait { + fn a() {} + fn b() {} +} diff --git a/src/test/rustdoc/mut-params.rs b/src/test/rustdoc/mut-params.rs new file mode 100644 index 000000000..f3ea69958 --- /dev/null +++ b/src/test/rustdoc/mut-params.rs @@ -0,0 +1,18 @@ +// Rustdoc shouldn't display `mut` in function arguments, which are +// implementation details. Regression test for #81289. + +#![crate_name = "foo"] + +pub struct Foo; + +// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2 +// @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut' +impl Foo { + pub fn foo(mut self) {} + + pub fn bar(mut bar: ()) {} +} + +// @count foo/fn.baz.html '//*[@class="rust fn"]' 1 +// @!has - '//*[@class="rust fn"]' 'mut' +pub fn baz(mut foo: Foo) {} diff --git a/src/test/rustdoc/namespaces.rs b/src/test/rustdoc/namespaces.rs new file mode 100644 index 000000000..ad828e5ee --- /dev/null +++ b/src/test/rustdoc/namespaces.rs @@ -0,0 +1,16 @@ +// issue #34843: rustdoc prioritises documenting reexports from the type namespace + +mod inner { + pub mod sync { + pub struct SomeStruct; + } + + pub fn sync() {} +} + +// @has namespaces/sync/index.html +// @has namespaces/fn.sync.html +// @has namespaces/index.html '//a/@href' 'sync/index.html' +// @has - '//a/@href' 'fn.sync.html' +#[doc(inline)] +pub use inner::sync; diff --git a/src/test/rustdoc/negative-impl-sidebar.rs b/src/test/rustdoc/negative-impl-sidebar.rs new file mode 100644 index 000000000..b995fff1f --- /dev/null +++ b/src/test/rustdoc/negative-impl-sidebar.rs @@ -0,0 +1,9 @@ +#![feature(negative_impls)] +#![crate_name = "foo"] + +pub struct Foo; + +// @has foo/struct.Foo.html +// @has - '//*[@class="sidebar-title"]/a[@href="#trait-implementations"]' 'Trait Implementations' +// @has - '//*[@class="sidebar-elems"]//section//a' '!Sync' +impl !Sync for Foo {} diff --git a/src/test/rustdoc/negative-impl.rs b/src/test/rustdoc/negative-impl.rs new file mode 100644 index 000000000..61a239868 --- /dev/null +++ b/src/test/rustdoc/negative-impl.rs @@ -0,0 +1,14 @@ +#![feature(negative_impls)] + +// @matches negative_impl/struct.Alpha.html '//pre' "pub struct Alpha" +pub struct Alpha; +// @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>" +pub struct Bravo<B>(B); + +// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl !Send for Alpha" +impl !Send for Alpha {} + +// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' "\ +// impl<B> !Send for Bravo<B>" +impl<B> !Send for Bravo<B> {} diff --git a/src/test/rustdoc/nested-modules.rs b/src/test/rustdoc/nested-modules.rs new file mode 100644 index 000000000..1596f4674 --- /dev/null +++ b/src/test/rustdoc/nested-modules.rs @@ -0,0 +1,42 @@ +#![crate_name = "aCrate"] + +mod a_module { + pub fn private_function() {} + + pub use a_module::private_function as other_private_function; + + pub mod a_nested_module { + // @has aCrate/a_nested_module/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function' + // @has aCrate/a_nested_module/fn.a_nested_public_function.html 'pub fn a_nested_public_function()' + pub fn a_nested_public_function() {} + + // @has aCrate/a_nested_module/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function' + // @has aCrate/a_nested_module/fn.another_nested_public_function.html 'pub fn another_nested_public_function()' + pub use a_nested_module::a_nested_public_function as another_nested_public_function; + } + + // @!has aCrate/a_nested_module/index.html 'yet_another_nested_public_function' + pub use a_nested_module::a_nested_public_function as yet_another_nested_public_function; + + // @!has aCrate/a_nested_module/index.html 'one_last_nested_public_function' + pub use a_nested_module::another_nested_public_function as one_last_nested_public_function; +} + +// @!has aCrate/index.html 'a_module' +// @has aCrate/index.html '//a[@href="a_nested_module/index.html"]' 'a_nested_module' +pub use a_module::a_nested_module; + +// @has aCrate/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function' +// @has aCrate/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function' +// @has aCrate/index.html '//a[@href="fn.yet_another_nested_public_function.html"]' 'yet_another_nested_public_function' +// @has aCrate/index.html '//a[@href="fn.one_last_nested_public_function.html"]' 'one_last_nested_public_function' +pub use a_module::{ + a_nested_module::{a_nested_public_function, another_nested_public_function}, + one_last_nested_public_function, yet_another_nested_public_function, +}; + +// @has aCrate/index.html '//a[@href="fn.private_function.html"]' 'private_function' +// @!has aCrate/fn.private_function.html 'a_module' +// @has aCrate/index.html '//a[@href="fn.other_private_function.html"]' 'other_private_function' +// @!has aCrate/fn.other_private_function.html 'a_module' +pub use a_module::{other_private_function, private_function}; diff --git a/src/test/rustdoc/no-compiler-reexport.rs b/src/test/rustdoc/no-compiler-reexport.rs new file mode 100644 index 000000000..d28fdf87b --- /dev/null +++ b/src/test/rustdoc/no-compiler-reexport.rs @@ -0,0 +1,7 @@ +// compile-flags: -Z unstable-options --document-hidden-items --document-private-items + +#![crate_name = "foo"] + +// @!has 'foo/index.html' '//code' 'extern crate std;' +// @!has 'foo/index.html' '//code' 'use std::prelude' +pub struct Foo; diff --git a/src/test/rustdoc/no-crate-filter.rs b/src/test/rustdoc/no-crate-filter.rs new file mode 100644 index 000000000..c694d1456 --- /dev/null +++ b/src/test/rustdoc/no-crate-filter.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +// compile-flags: -Z unstable-options --disable-per-crate-search + +// @!has 'foo/struct.Foo.html' '//*[id="crate-search"]' +pub struct Foo; diff --git a/src/test/rustdoc/no-run-still-checks-lints.rs b/src/test/rustdoc/no-run-still-checks-lints.rs new file mode 100644 index 000000000..9f7d1c884 --- /dev/null +++ b/src/test/rustdoc/no-run-still-checks-lints.rs @@ -0,0 +1,9 @@ +// compile-flags:--test +// should-fail + +#![doc(test(attr(deny(warnings))))] + +/// ```no_run +/// let a = 3; +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc/no-stack-overflow-25295.rs b/src/test/rustdoc/no-stack-overflow-25295.rs new file mode 100644 index 000000000..dd79f1e4b --- /dev/null +++ b/src/test/rustdoc/no-stack-overflow-25295.rs @@ -0,0 +1,35 @@ +// Ensure this code doesn't stack overflow. +// aux-build:enum-primitive.rs + +#[macro_use] extern crate enum_primitive; + +enum_from_primitive! { + pub enum Test { + A1,A2,A3,A4,A5,A6, + B1,B2,B3,B4,B5,B6, + C1,C2,C3,C4,C5,C6, + D1,D2,D3,D4,D5,D6, + E1,E2,E3,E4,E5,E6, + F1,F2,F3,F4,F5,F6, + G1,G2,G3,G4,G5,G6, + H1,H2,H3,H4,H5,H6, + I1,I2,I3,I4,I5,I6, + J1,J2,J3,J4,J5,J6, + K1,K2,K3,K4,K5,K6, + L1,L2,L3,L4,L5,L6, + M1,M2,M3,M4,M5,M6, + N1,N2,N3,N4,N5,N6, + O1,O2,O3,O4,O5,O6, + P1,P2,P3,P4,P5,P6, + Q1,Q2,Q3,Q4,Q5,Q6, + R1,R2,R3,R4,R5,R6, + S1,S2,S3,S4,S5,S6, + T1,T2,T3,T4,T5,T6, + U1,U2,U3,U4,U5,U6, + V1,V2,V3,V4,V5,V6, + W1,W2,W3,W4,W5,W6, + X1,X2,X3,X4,X5,X6, + Y1,Y2,Y3,Y4,Y5,Y6, + Z1,Z2,Z3,Z4,Z5,Z6, + } +} diff --git a/src/test/rustdoc/no_std-primitive.rs b/src/test/rustdoc/no_std-primitive.rs new file mode 100644 index 000000000..22fd392dd --- /dev/null +++ b/src/test/rustdoc/no_std-primitive.rs @@ -0,0 +1,6 @@ +#![no_std] + +/// Link to [intra-doc link][u8] +// @has 'no_std_primitive/fn.foo.html' '//a[@href="{{channel}}/core/primitive.u8.html"]' 'intra-doc link' +// @has - '//a[@href="{{channel}}/core/primitive.u8.html"]' 'u8' +pub fn foo() -> u8 {} diff --git a/src/test/rustdoc/normalize-assoc-item.rs b/src/test/rustdoc/normalize-assoc-item.rs new file mode 100644 index 000000000..ad1a868ee --- /dev/null +++ b/src/test/rustdoc/normalize-assoc-item.rs @@ -0,0 +1,69 @@ +// ignore-tidy-linelength +// aux-build:normalize-assoc-item.rs +// build-aux-docs +// compile-flags:-Znormalize-docs + +pub trait Trait { + type X; +} + +impl Trait for usize { + type X = isize; +} + +// @has 'normalize_assoc_item/fn.f.html' '//pre[@class="rust fn"]' 'pub fn f() -> isize' +pub fn f() -> <usize as Trait>::X { + 0 +} + +pub struct S { + // @has 'normalize_assoc_item/struct.S.html' '//span[@id="structfield.box_me_up"]' 'box_me_up: Box<S, Global>' + pub box_me_up: <S as Trait>::X, + // @has 'normalize_assoc_item/struct.S.html' '//span[@id="structfield.generic"]' 'generic: (usize, isize)' + pub generic: <Generic<usize> as Trait>::X, +} + +impl Trait for S { + type X = Box<S>; +} + +pub struct Generic<Inner>(Inner); + +impl<Inner: Trait> Trait for Generic<Inner> { + type X = (Inner, Inner::X); +} + +// These can't be normalized because they depend on a generic parameter. +// However the user can choose whether the text should be displayed as `Inner::X` or `<Inner as Trait>::X`. + +// @has 'normalize_assoc_item/struct.Unknown.html' '//pre[@class="rust struct"]' 'pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);' +pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X); + +// @has 'normalize_assoc_item/struct.Unknown2.html' '//pre[@class="rust struct"]' 'pub struct Unknown2<Inner: Trait>(pub Inner::X);' +pub struct Unknown2<Inner: Trait>(pub Inner::X); + +trait Lifetimes<'a> { + type Y; +} + +impl<'a> Lifetimes<'a> for usize { + type Y = &'a isize; +} + +// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust fn"]' "pub fn g() -> &isize" +pub fn g() -> <usize as Lifetimes<'static>>::Y { + &0 +} + +// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust const"]' "pub const A: &isize" +pub const A: <usize as Lifetimes<'static>>::Y = &0; + +// test cross-crate re-exports +extern crate inner; +// @has 'normalize_assoc_item/fn.foo.html' '//pre[@class="rust fn"]' "pub fn foo() -> i32" +pub use inner::foo; + +// @has 'normalize_assoc_item/fn.h.html' '//pre[@class="rust fn"]' "pub fn h<T>() -> IntoIter<T, Global>" +pub fn h<T>() -> <Vec<T> as IntoIterator>::IntoIter { + vec![].into_iter() +} diff --git a/src/test/rustdoc/nul-error.rs b/src/test/rustdoc/nul-error.rs new file mode 100644 index 000000000..3d30f5f6b --- /dev/null +++ b/src/test/rustdoc/nul-error.rs @@ -0,0 +1,8 @@ +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +// @has foo/fn.foo.html '//code' '' +#[doc = "Attempted to pass a string containing `\0`"] +pub fn foo() {} diff --git a/src/test/rustdoc/playground-arg.rs b/src/test/rustdoc/playground-arg.rs new file mode 100644 index 000000000..69c896265 --- /dev/null +++ b/src/test/rustdoc/playground-arg.rs @@ -0,0 +1,13 @@ +// compile-flags: --playground-url=https://example.com/ -Z unstable-options + +#![crate_name = "foo"] + +//! ``` +//! use foo::dummy; +//! dummy(); +//! ``` + +pub fn dummy() {} + +// ensure that `extern crate foo;` was inserted into code snips automatically: +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20r%23foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run" diff --git a/src/test/rustdoc/playground-empty.rs b/src/test/rustdoc/playground-empty.rs new file mode 100644 index 000000000..7d8bd3ffe --- /dev/null +++ b/src/test/rustdoc/playground-empty.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +#![doc(html_playground_url = "")] + +// compile-flags:-Z unstable-options --playground-url https://play.rust-lang.org/ + +//! module docs +//! +//! ``` +//! println!("Hello, world!"); +//! ``` + +// @!has foo/index.html '//a[@class="test-arrow"]' "Run" diff --git a/src/test/rustdoc/playground-none.rs b/src/test/rustdoc/playground-none.rs new file mode 100644 index 000000000..ff51c68d8 --- /dev/null +++ b/src/test/rustdoc/playground-none.rs @@ -0,0 +1,9 @@ +#![crate_name = "foo"] + +//! module docs +//! +//! ``` +//! println!("Hello, world!"); +//! ``` + +// @!has foo/index.html '//a[@class="test-arrow"]' "Run" diff --git a/src/test/rustdoc/playground-syntax-error.rs b/src/test/rustdoc/playground-syntax-error.rs new file mode 100644 index 000000000..8918ae874 --- /dev/null +++ b/src/test/rustdoc/playground-syntax-error.rs @@ -0,0 +1,21 @@ +#![crate_name = "foo"] +#![doc(html_playground_url = "https://play.rust-lang.org/")] + +/// bar docs +/// +/// ```edition2015 +/// use std::future::Future; +/// use std::pin::Pin; +/// fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> { +/// Box::pin(async move { +/// if n > 0 { +/// foo_recursive(n - 1).await; +/// } +/// }) +/// } +/// ``` +pub fn bar() {} + +// @has foo/fn.bar.html +// @has - '//a[@class="test-arrow"]' "Run" +// @has - '//*[@class="docblock"]' 'foo_recursive' diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs new file mode 100644 index 000000000..877ea1cfb --- /dev/null +++ b/src/test/rustdoc/playground.rs @@ -0,0 +1,27 @@ +#![crate_name = "foo"] + +#![doc(html_playground_url = "https://www.example.com/")] + +//! module docs +//! +//! ``` +//! println!("Hello, world!"); +//! ``` +//! +//! ``` +//! fn main() { +//! println!("Hello, world!"); +//! } +//! ``` +//! +//! ``` +//! #![feature(something)] +//! +//! fn main() { +//! println!("Hello, world!"); +//! } +//! ``` + +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run" diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs new file mode 100644 index 000000000..125e0c849 --- /dev/null +++ b/src/test/rustdoc/primitive-link.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + + +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.u32.html"]' 'u32' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i64.html"]' 'i64' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html"]' 'std::primitive::i32' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.str.html"]' 'std::primitive::str' + +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX' + +/// It contains [`u32`] and [i64]. +/// It also links to [std::primitive::i32], [std::primitive::str], +/// and [`std::primitive::i32::MAX`]. +pub struct Foo; diff --git a/src/test/rustdoc/primitive-reexport.rs b/src/test/rustdoc/primitive-reexport.rs new file mode 100644 index 000000000..10a8a47db --- /dev/null +++ b/src/test/rustdoc/primitive-reexport.rs @@ -0,0 +1,28 @@ +// aux-build: primitive-reexport.rs +// compile-flags:--extern foo --edition 2018 + +#![crate_name = "bar"] + +// @has bar/p/index.html +// @has - '//code' 'pub use bool;' +// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool' +// @has - '//code' 'pub use char as my_char;' +// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char' +pub mod p { + pub use foo::bar::*; +} + +// @has bar/baz/index.html +// @has - '//code' 'pub use bool;' +// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool' +// @has - '//code' 'pub use char as my_char;' +// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char' +pub use foo::bar as baz; + +// @has bar/index.html +// @has - '//code' 'pub use str;' +// @has - '//code/a[@href="{{channel}}/std/primitive.str.html"]' 'str' +// @has - '//code' 'pub use i32 as my_i32;' +// @has - '//code/a[@href="{{channel}}/std/primitive.i32.html"]' 'i32' +pub use str; +pub use i32 as my_i32; diff --git a/src/test/rustdoc/primitive-slice-auto-trait.rs b/src/test/rustdoc/primitive-slice-auto-trait.rs new file mode 100644 index 000000000..b3f511bc1 --- /dev/null +++ b/src/test/rustdoc/primitive-slice-auto-trait.rs @@ -0,0 +1,14 @@ +// compile-flags: --crate-type lib --edition 2018 + +#![crate_name = "foo"] +#![feature(rustdoc_internals)] + +// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice' +// @has - '//span[@class="in-band"]' 'Primitive Type slice' +// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync' +#[doc(primitive = "slice")] +/// this is a test! +mod slice_prim {} diff --git a/src/test/rustdoc/primitive-tuple-auto-trait.rs b/src/test/rustdoc/primitive-tuple-auto-trait.rs new file mode 100644 index 000000000..a2fbbf078 --- /dev/null +++ b/src/test/rustdoc/primitive-tuple-auto-trait.rs @@ -0,0 +1,22 @@ +// compile-flags: --crate-type lib --edition 2018 + +#![crate_name = "foo"] +#![feature(rustdoc_internals)] + +// @has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple' +// @has - '//span[@class="in-band"]' 'Primitive Type tuple' +// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'Send' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'Sync' +#[doc(primitive = "tuple")] +/// this is a test! +/// +// Hardcoded anchor to header written in library/core/src/primitive_docs.rs +// @has - '//h2[@id="trait-implementations-1"]' 'Trait implementations' +/// # Trait implementations +/// +/// This header is hard-coded in the HTML format linking for `#[doc(fake_variadics)]`. +/// To make sure it gets linked correctly, we need to make sure the hardcoded anchor +/// in the code matches what rustdoc generates for the header. +mod tuple_prim {} diff --git a/src/test/rustdoc/primitive-tuple-variadic.rs b/src/test/rustdoc/primitive-tuple-variadic.rs new file mode 100644 index 000000000..db7cfd60c --- /dev/null +++ b/src/test/rustdoc/primitive-tuple-variadic.rs @@ -0,0 +1,18 @@ +// compile-flags: --crate-type lib --edition 2018 + +#![crate_name = "foo"] +#![feature(rustdoc_internals)] + +pub trait Foo {} + +// @has foo/trait.Foo.html +// @has - '//section[@id="impl-Foo-for-(T%2C)"]/h3' 'impl<T> Foo for (T₁, T₂, …, Tₙ)' +#[doc(fake_variadic)] +impl<T> Foo for (T,) {} + +pub trait Bar {} + +// @has foo/trait.Bar.html +// @has - '//section[@id="impl-Bar-for-(U%2C)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)' +#[doc(fake_variadic)] +impl<U: Foo> Bar for (U,) {} diff --git a/src/test/rustdoc/primitive-unit-auto-trait.rs b/src/test/rustdoc/primitive-unit-auto-trait.rs new file mode 100644 index 000000000..76182622e --- /dev/null +++ b/src/test/rustdoc/primitive-unit-auto-trait.rs @@ -0,0 +1,14 @@ +// compile-flags: --crate-type lib --edition 2018 + +#![crate_name = "foo"] +#![feature(rustdoc_internals)] + +// @has foo/primitive.unit.html '//a[@class="primitive"]' 'unit' +// @has - '//span[@class="in-band"]' 'Primitive Type unit' +// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for ()' +#[doc(primitive = "unit")] +/// this is a test! +mod unit_prim {} diff --git a/src/test/rustdoc/primitive.rs b/src/test/rustdoc/primitive.rs new file mode 100644 index 000000000..605ca4d17 --- /dev/null +++ b/src/test/rustdoc/primitive.rs @@ -0,0 +1,21 @@ +#![crate_name = "foo"] + +#![feature(rustdoc_internals)] + +// @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types' +// @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Primitive Types' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#primitives' +// @has foo/primitive.i32.html '//a[@class="primitive"]' 'i32' +// @has foo/primitive.i32.html '//span[@class="in-band"]' 'Primitive Type i32' +// @has foo/primitive.i32.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +// @has foo/index.html '//a/@href' '../foo/index.html' +// @!has foo/index.html '//span' '🔒' +#[doc(primitive = "i32")] +/// this is a test! +mod i32{} + +// @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[doc(primitive = "bool")] +/// hello +mod bool {} diff --git a/src/test/rustdoc/primitive/no_std.rs b/src/test/rustdoc/primitive/no_std.rs new file mode 100644 index 000000000..f0f70cb6c --- /dev/null +++ b/src/test/rustdoc/primitive/no_std.rs @@ -0,0 +1,16 @@ +#![no_std] +#![deny(warnings)] +#![deny(rustdoc::broken_intra_doc_links)] + +// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'u8' +// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'primitive link' +/// Link to [primitive link][u8] +pub fn foo() -> u8 {} + +// Test that all primitives can be linked to. +/// [isize] [i8] [i16] [i32] [i64] [i128] +/// [usize] [u8] [u16] [u32] [u64] [u128] +/// [f32] [f64] +/// [char] [bool] [str] [slice] [array] [tuple] [unit] +/// [pointer] [reference] [fn] [never] +pub fn bar() {} diff --git a/src/test/rustdoc/primitive/primitive-generic-impl.rs b/src/test/rustdoc/primitive/primitive-generic-impl.rs new file mode 100644 index 000000000..eebb2cf5a --- /dev/null +++ b/src/test/rustdoc/primitive/primitive-generic-impl.rs @@ -0,0 +1,8 @@ +#![feature(rustdoc_internals)] +#![crate_name = "foo"] + +// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' + +#[doc(primitive = "i32")] +/// Some useless docs, wouhou! +mod i32 {} diff --git a/src/test/rustdoc/private-type-alias.rs b/src/test/rustdoc/private-type-alias.rs new file mode 100644 index 000000000..ec7385404 --- /dev/null +++ b/src/test/rustdoc/private-type-alias.rs @@ -0,0 +1,31 @@ +type MyResultPriv<T> = Result<T, u16>; +pub type MyResultPub<T> = Result<T, u64>; + +// @has private_type_alias/fn.get_result_priv.html '//pre' 'Result<u8, u16>' +pub fn get_result_priv() -> MyResultPriv<u8> { + panic!(); +} + +// @has private_type_alias/fn.get_result_pub.html '//pre' 'MyResultPub<u32>' +pub fn get_result_pub() -> MyResultPub<u32> { + panic!(); +} + +pub type PubRecursive = u16; +type PrivRecursive3 = u8; +type PrivRecursive2 = PubRecursive; +type PrivRecursive1 = PrivRecursive3; + +// PrivRecursive1 is expanded twice and stops at u8 +// PrivRecursive2 is expanded once and stops at public type alias PubRecursive +// @has private_type_alias/fn.get_result_recursive.html '//pre' '(u8, PubRecursive)' +pub fn get_result_recursive() -> (PrivRecursive1, PrivRecursive2) { + panic!(); +} + +type MyLifetimePriv<'a> = &'a isize; + +// @has private_type_alias/fn.get_lifetime_priv.html '//pre' "&'static isize" +pub fn get_lifetime_priv() -> MyLifetimePriv<'static> { + panic!(); +} diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs new file mode 100644 index 000000000..10acb7ac4 --- /dev/null +++ b/src/test/rustdoc/proc-macro.rs @@ -0,0 +1,72 @@ +// force-host +// no-prefer-dynamic +// compile-flags: --crate-type proc-macro --document-private-items + +#![crate_type="proc-macro"] +#![crate_name="some_macros"] + +// @has some_macros/index.html +// @has - '//a/[@href="attr.some_proc_attr.html"]' 'some_proc_attr' + +//! include a link to [some_proc_macro!] to make sure it works. + +extern crate proc_macro; + +use proc_macro::TokenStream; + +// @has some_macros/index.html +// @has - '//h2' 'Macros' +// @has - '//h2' 'Attribute Macros' +// @has - '//h2' 'Derive Macros' +// @!has - '//h2' 'Functions' + +// @has some_macros/all.html +// @has - '//a[@href="macro.some_proc_macro.html"]' 'some_proc_macro' +// @has - '//a[@href="attr.some_proc_attr.html"]' 'some_proc_attr' +// @has - '//a[@href="derive.SomeDerive.html"]' 'SomeDerive' +// @!has - '//a/@href' 'fn.some_proc_macro.html' +// @!has - '//a/@href' 'fn.some_proc_attr.html' +// @!has - '//a/@href' 'fn.some_derive.html' + +// @has some_macros/index.html '//a/@href' 'macro.some_proc_macro.html' +// @!has - '//a/@href' 'fn.some_proc_macro.html' +// @has some_macros/macro.some_proc_macro.html +// @!has some_macros/fn.some_proc_macro.html +/// a proc-macro that swallows its input and does nothing. +#[proc_macro] +pub fn some_proc_macro(_input: TokenStream) -> TokenStream { + TokenStream::new() +} + +// @has some_macros/index.html '//a/@href' 'attr.some_proc_attr.html' +// @!has - '//a/@href' 'fn.some_proc_attr.html' +// @has some_macros/attr.some_proc_attr.html +// @!has some_macros/fn.some_proc_attr.html +/// a proc-macro attribute that passes its item through verbatim. +#[proc_macro_attribute] +pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} + +// @has some_macros/index.html '//a/@href' 'derive.SomeDerive.html' +// @!has - '//a/@href' 'fn.some_derive.html' +// @has some_macros/derive.SomeDerive.html +// @!has some_macros/fn.some_derive.html +/// a derive attribute that adds nothing to its input. +#[proc_macro_derive(SomeDerive)] +pub fn some_derive(_item: TokenStream) -> TokenStream { + TokenStream::new() +} + +// @has some_macros/foo/index.html +mod foo { + // @has - '//code' 'pub use some_proc_macro;' + // @has - '//a/@href' '../macro.some_proc_macro.html' + pub use some_proc_macro; + // @has - '//code' 'pub use some_proc_attr;' + // @has - '//a/@href' '../attr.some_proc_attr.html' + pub use some_proc_attr; + // @has - '//code' 'pub use some_derive;' + // @has - '//a/@href' '../derive.SomeDerive.html' + pub use some_derive; +} diff --git a/src/test/rustdoc/process-termination.rs b/src/test/rustdoc/process-termination.rs new file mode 100644 index 000000000..32258792b --- /dev/null +++ b/src/test/rustdoc/process-termination.rs @@ -0,0 +1,24 @@ +// compile-flags:--test + +/// A check of using various process termination strategies +/// +/// # Examples +/// +/// ```rust +/// assert!(true); // this returns `()`, all is well +/// ``` +/// +/// You can also simply return `Ok(())`, but you'll need to disambiguate the +/// type using turbofish, because we cannot infer the type: +/// +/// ```rust +/// Ok::<(), &'static str>(()) +/// ``` +/// +/// You can err with anything that implements `Debug`: +/// +/// ```rust,should_panic +/// Err("This is returned from `main`, leading to panic")?; +/// Ok::<(), &'static str>(()) +/// ``` +pub fn check_process_termination() {} diff --git a/src/test/rustdoc/pub-extern-crate.rs b/src/test/rustdoc/pub-extern-crate.rs new file mode 100644 index 000000000..26747a4d1 --- /dev/null +++ b/src/test/rustdoc/pub-extern-crate.rs @@ -0,0 +1,9 @@ +// aux-build:pub-extern-crate.rs + +// @has pub_extern_crate/index.html +// @!has - '//code' 'pub extern crate inner' +// @has - '//a/@href' 'inner/index.html' +// @has pub_extern_crate/inner/index.html +// @has pub_extern_crate/inner/struct.SomeStruct.html +#[doc(inline)] +pub extern crate inner; diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs new file mode 100644 index 000000000..fa7de0aff --- /dev/null +++ b/src/test/rustdoc/pub-method.rs @@ -0,0 +1,20 @@ +// compile-flags: --document-private-items + +#![crate_name = "foo"] + +// @has foo/fn.bar.html +// @has - '//*[@class="rust fn"]' 'pub fn bar() -> ' +/// foo +pub fn bar() -> usize { + 2 +} + +// @has foo/struct.Foo.html +// @has - '//*[@class="method has-srclink"]' 'pub fn new()' +// @has - '//*[@class="method has-srclink"]' 'fn not_pub()' +pub struct Foo(usize); + +impl Foo { + pub fn new() -> Foo { Foo(0) } + fn not_pub() {} +} diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs new file mode 100644 index 000000000..eefe6b4b0 --- /dev/null +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -0,0 +1,17 @@ +// aux-build:pub-use-extern-macros.rs + +extern crate macros; + +// @has pub_use_extern_macros/macro.bar.html +// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::bar;' +pub use macros::bar; + +// @has pub_use_extern_macros/macro.baz.html +// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::baz;' +#[doc(inline)] +pub use macros::baz; + +// @!has pub_use_extern_macros/macro.quux.html +// @!has pub_use_extern_macros/index.html '//code' 'pub use macros::quux;' +#[doc(hidden)] +pub use macros::quux; diff --git a/src/test/rustdoc/range-arg-pattern.rs b/src/test/rustdoc/range-arg-pattern.rs new file mode 100644 index 000000000..756939ae3 --- /dev/null +++ b/src/test/rustdoc/range-arg-pattern.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - '//*[@class="rust fn"]' 'pub fn f(_: u8)' +pub fn f(0u8..=255: u8) {} diff --git a/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs b/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs new file mode 100644 index 000000000..7dbe63854 --- /dev/null +++ b/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs @@ -0,0 +1,21 @@ +#![crate_type="lib"] + +pub mod internal { + // @has 'raw_ident_eliminate_r_hashtag/internal/struct.mod.html' + #[allow(non_camel_case_types)] + pub struct r#mod; + + /// See [name], [other name] + /// + /// [name]: mod + /// [other name]: crate::internal::mod + // @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="struct.mod.html"]' 'name' + // @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="struct.mod.html"]' 'other name' + pub struct B; +} + +/// See [name]. +/// +/// [name]: internal::mod +// @has 'raw_ident_eliminate_r_hashtag/struct.A.html' '//*a[@href="internal/struct.mod.html"]' 'name' +pub struct A; diff --git a/src/test/rustdoc/recursion1.rs b/src/test/rustdoc/recursion1.rs new file mode 100644 index 000000000..edf7e440f --- /dev/null +++ b/src/test/rustdoc/recursion1.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +mod m { + pub use self::a::Foo; + + mod a { + pub struct Foo; + } + + mod b { + pub use super::*; + } +} diff --git a/src/test/rustdoc/recursion2.rs b/src/test/rustdoc/recursion2.rs new file mode 100644 index 000000000..edf7e440f --- /dev/null +++ b/src/test/rustdoc/recursion2.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +mod m { + pub use self::a::Foo; + + mod a { + pub struct Foo; + } + + mod b { + pub use super::*; + } +} diff --git a/src/test/rustdoc/recursion3.rs b/src/test/rustdoc/recursion3.rs new file mode 100644 index 000000000..e69b43016 --- /dev/null +++ b/src/test/rustdoc/recursion3.rs @@ -0,0 +1,13 @@ +pub mod longhands { + pub use super::*; + + pub use super::common_types::computed::compute_CSSColor as to_computed_value; + + pub fn computed_as_specified() {} +} + +pub mod common_types { + pub mod computed { + pub use super::super::longhands::computed_as_specified as compute_CSSColor; + } +} diff --git a/src/test/rustdoc/recursive-deref-sidebar.rs b/src/test/rustdoc/recursive-deref-sidebar.rs new file mode 100644 index 000000000..619f40eff --- /dev/null +++ b/src/test/rustdoc/recursive-deref-sidebar.rs @@ -0,0 +1,22 @@ +use std::ops::Deref; + +pub struct A {} +impl A { pub fn foo_a(&self) {} } + +pub struct B {} +impl B { pub fn foo_b(&self) {} } + +pub struct C {} +impl C { pub fn foo_c(&self) {} } + +// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_b' +impl Deref for A { + type Target = B; + fn deref(&self) -> &B { todo!() } +} + +// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_c' +impl Deref for B { + type Target = C; + fn deref(&self) -> &C { todo!() } +} diff --git a/src/test/rustdoc/recursive-deref.rs b/src/test/rustdoc/recursive-deref.rs new file mode 100644 index 000000000..a7504fbcc --- /dev/null +++ b/src/test/rustdoc/recursive-deref.rs @@ -0,0 +1,120 @@ +use std::ops::Deref; + +// Cyclic deref with the parent (which is not the top parent). +pub struct A; +pub struct B; +pub struct C; + +impl C { + pub fn c(&self) {} +} + +// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A' +// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)' +impl Deref for A { + type Target = B; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B' +// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)' +impl Deref for B { + type Target = C; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C' +impl Deref for C { + type Target = B; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// Cyclic deref with the grand-parent (which is not the top parent). +pub struct D; +pub struct E; +pub struct F; +pub struct G; + +impl G { + // There is no "self" parameter so it shouldn't be listed! + pub fn g() {} +} + +// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D' +// We also check that `G::g` method isn't rendered because there is no `self` argument. +// @!has '-' '//*[@id="deref-methods-G"]' +impl Deref for D { + type Target = E; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E' +// We also check that `G::g` method isn't rendered because there is no `self` argument. +// @!has '-' '//*[@id="deref-methods-G"]' +impl Deref for E { + type Target = F; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F' +// We also check that `G::g` method isn't rendered because there is no `self` argument. +// @!has '-' '//*[@id="deref-methods-G"]' +impl Deref for F { + type Target = G; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G' +impl Deref for G { + type Target = E; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// Cyclic deref with top parent. +pub struct H; +pub struct I; + +impl I { + // There is no "self" parameter so it shouldn't be listed! + pub fn i() {} +} + +// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H' +// @!has '-' '//*[@id="deref-methods-I"]' +impl Deref for H { + type Target = I; + + fn deref(&self) -> &Self::Target { + panic!() + } +} + +// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I' +impl Deref for I { + type Target = H; + + fn deref(&self) -> &Self::Target { + panic!() + } +} diff --git a/src/test/rustdoc/redirect-const.rs b/src/test/rustdoc/redirect-const.rs new file mode 100644 index 000000000..453da8387 --- /dev/null +++ b/src/test/rustdoc/redirect-const.rs @@ -0,0 +1,13 @@ +#![crate_name="foo"] + +pub use hidden::STATIC_FOO; +pub use hidden::CONST_FOO; + +mod hidden { + // @has foo/hidden/static.STATIC_FOO.html + // @has - '//p/a' '../../foo/static.STATIC_FOO.html' + pub static STATIC_FOO: u64 = 0; + // @has foo/hidden/constant.CONST_FOO.html + // @has - '//p/a' '../../foo/constant.CONST_FOO.html' + pub const CONST_FOO: u64 = 0; +} diff --git a/src/test/rustdoc/redirect-map-empty.rs b/src/test/rustdoc/redirect-map-empty.rs new file mode 100644 index 000000000..e9d021e0f --- /dev/null +++ b/src/test/rustdoc/redirect-map-empty.rs @@ -0,0 +1,6 @@ +// compile-flags: -Z unstable-options --generate-redirect-map + +#![crate_name = "foo"] + +// @!has foo/redirect-map.json +pub struct Foo; diff --git a/src/test/rustdoc/redirect-map.rs b/src/test/rustdoc/redirect-map.rs new file mode 100644 index 000000000..b7f16b64e --- /dev/null +++ b/src/test/rustdoc/redirect-map.rs @@ -0,0 +1,23 @@ +// compile-flags: -Z unstable-options --generate-redirect-map + +#![crate_name = "foo"] + +// @!has foo/private/struct.Quz.html +// @!has foo/hidden/struct.Bar.html +// @has foo/redirect-map.json +pub use private::Quz; +pub use hidden::Bar; + +mod private { + pub struct Quz; +} + +#[doc(hidden)] +pub mod hidden { + pub struct Bar; +} + +#[macro_export] +macro_rules! foo { + () => {} +} diff --git a/src/test/rustdoc/redirect-rename.rs b/src/test/rustdoc/redirect-rename.rs new file mode 100644 index 000000000..504c0687c --- /dev/null +++ b/src/test/rustdoc/redirect-rename.rs @@ -0,0 +1,34 @@ +#![crate_name = "foo"] + +mod hidden { + // @has foo/hidden/struct.Foo.html + // @has - '//p/a' '../../foo/struct.FooBar.html' + pub struct Foo {} + pub union U { a: usize } + pub enum Empty {} + pub const C: usize = 1; + pub static S: usize = 1; + + // @has foo/hidden/bar/index.html + // @has - '//p/a' '../../foo/baz/index.html' + pub mod bar { + // @has foo/hidden/bar/struct.Thing.html + // @has - '//p/a' '../../foo/baz/struct.Thing.html' + pub struct Thing {} + } +} + +// @has foo/struct.FooBar.html +pub use hidden::Foo as FooBar; +// @has foo/union.FooU.html +pub use hidden::U as FooU; +// @has foo/enum.FooEmpty.html +pub use hidden::Empty as FooEmpty; +// @has foo/constant.FooC.html +pub use hidden::C as FooC; +// @has foo/static.FooS.html +pub use hidden::S as FooS; + +// @has foo/baz/index.html +// @has foo/baz/struct.Thing.html +pub use hidden::bar as baz; diff --git a/src/test/rustdoc/redirect.rs b/src/test/rustdoc/redirect.rs new file mode 100644 index 000000000..e3a14c7a7 --- /dev/null +++ b/src/test/rustdoc/redirect.rs @@ -0,0 +1,39 @@ +// aux-build:reexp-stripped.rs +// build-aux-docs +// ignore-cross-compile + +extern crate reexp_stripped; + +pub trait Foo {} + +// @has redirect/index.html +// @has - '//code' 'pub use reexp_stripped::Bar' +// @has - '//code/a' 'Bar' +// @has reexp_stripped/hidden/struct.Bar.html +// @has - '//p/a' '../../reexp_stripped/struct.Bar.html' +// @has 'reexp_stripped/struct.Bar.html' +#[doc(no_inline)] +pub use reexp_stripped::Bar; +impl Foo for Bar {} + +// @has redirect/index.html +// @has - '//code' 'pub use reexp_stripped::Quz' +// @has - '//code/a' 'Quz' +// @has reexp_stripped/private/struct.Quz.html +// @has - '//p/a' '../../reexp_stripped/struct.Quz.html' +// @has 'reexp_stripped/struct.Quz.html' +#[doc(no_inline)] +pub use reexp_stripped::Quz; +impl Foo for Quz {} + +mod private_no_inline { + pub struct Qux; + impl ::Foo for Qux {} +} + +// @has redirect/index.html +// @has - '//code' 'pub use private_no_inline::Qux' +// @!has - '//a' 'Qux' +// @!has redirect/struct.Qux.html +#[doc(no_inline)] +pub use private_no_inline::Qux; diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs new file mode 100644 index 000000000..db1f90c69 --- /dev/null +++ b/src/test/rustdoc/reexport-check.rs @@ -0,0 +1,18 @@ +// aux-build:reexport-check.rs +#![crate_name = "foo"] + +extern crate reexport_check; + +// @!has 'foo/index.html' '//code' 'pub use self::i32;' +// @has 'foo/index.html' '//div[@class="item-left deprecated module-item"]' 'i32' +// @has 'foo/i32/index.html' +#[allow(deprecated, deprecated_in_future)] +pub use std::i32; +// @!has 'foo/index.html' '//code' 'pub use self::string::String;' +// @has 'foo/index.html' '//div[@class="item-left module-item"]' 'String' +pub use std::string::String; + +// @has 'foo/index.html' '//div[@class="item-right docblock-short"]' 'Docs in original' +// this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment +#[doc(inline)] +pub use reexport_check::S; diff --git a/src/test/rustdoc/reexport-dep-foreign-fn.rs b/src/test/rustdoc/reexport-dep-foreign-fn.rs new file mode 100644 index 000000000..6e1dc4539 --- /dev/null +++ b/src/test/rustdoc/reexport-dep-foreign-fn.rs @@ -0,0 +1,12 @@ +// aux-build:all-item-types.rs + +// This test is to ensure there is no problem on handling foreign functions +// coming from a dependency. + +#![crate_name = "foo"] + +extern crate all_item_types; + +// @has 'foo/fn.foo_ffn.html' +// @has - '//*[@class="docblock item-decl"]//code' 'pub unsafe extern "C" fn foo_ffn()' +pub use all_item_types::foo_ffn; diff --git a/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs b/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs new file mode 100644 index 000000000..a79d05904 --- /dev/null +++ b/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs @@ -0,0 +1,48 @@ +#![crate_name = "foo"] +#![feature(doc_cfg)] + +pub mod tag { + #[deprecated(since = "0.1.8", note = "Use bar() instead")] + pub trait Deprecated {} + + #[doc(cfg(feature = "sync"))] + pub trait Portability {} + + #[deprecated(since = "0.1.8", note = "Use bar() instead")] + #[doc(cfg(feature = "sync"))] + pub trait Both {} + + pub trait None {} +} + +// @has foo/mod1/index.html +pub mod mod1 { + // @has - '//code' 'pub use tag::Deprecated;' + // @has - '//span' 'Deprecated' + // @!has - '//span' 'sync' + pub use tag::Deprecated; +} + +// @has foo/mod2/index.html +pub mod mod2 { + // @has - '//code' 'pub use tag::Portability;' + // @!has - '//span' 'Deprecated' + // @has - '//span' 'sync' + pub use tag::Portability; +} + +// @has foo/mod3/index.html +pub mod mod3 { + // @has - '//code' 'pub use tag::Both;' + // @has - '//span' 'Deprecated' + // @has - '//span' 'sync' + pub use tag::Both; +} + +// @has foo/mod4/index.html +pub mod mod4 { + // @has - '//code' 'pub use tag::None;' + // @!has - '//span' 'Deprecated' + // @!has - '//span' 'sync' + pub use tag::None; +} diff --git a/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs b/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs new file mode 100644 index 000000000..ff8a910f5 --- /dev/null +++ b/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs @@ -0,0 +1,61 @@ +#![crate_name = "foo"] +#![feature(doc_cfg)] +#![feature(staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod tag { + #[unstable(feature = "humans", issue = "none")] + pub trait Unstable {} + + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(cfg(feature = "sync"))] + pub trait Portability {} + + #[unstable(feature = "humans", issue = "none")] + #[doc(cfg(feature = "sync"))] + pub trait Both {} + + #[stable(feature = "rust1", since = "1.0.0")] + pub trait None {} +} + +// @has foo/mod1/index.html +#[stable(feature = "rust1", since = "1.0.0")] +pub mod mod1 { + // @has - '//code' 'pub use tag::Unstable;' + // @has - '//span' 'Experimental' + // @!has - '//span' 'sync' + #[stable(feature = "rust1", since = "1.0.0")] + pub use tag::Unstable; +} + +// @has foo/mod2/index.html +#[stable(feature = "rust1", since = "1.0.0")] +pub mod mod2 { + // @has - '//code' 'pub use tag::Portability;' + // @!has - '//span' 'Experimental' + // @has - '//span' 'sync' + #[stable(feature = "rust1", since = "1.0.0")] + pub use tag::Portability; +} + +// @has foo/mod3/index.html +#[stable(feature = "rust1", since = "1.0.0")] +pub mod mod3 { + // @has - '//code' 'pub use tag::Both;' + // @has - '//span' 'Experimental' + // @has - '//span' 'sync' + #[stable(feature = "rust1", since = "1.0.0")] + pub use tag::Both; +} + +// @has foo/mod4/index.html +#[stable(feature = "rust1", since = "1.0.0")] +pub mod mod4 { + // @has - '//code' 'pub use tag::None;' + // @!has - '//span' 'Experimental' + // @!has - '//span' 'sync' + #[stable(feature = "rust1", since = "1.0.0")] + pub use tag::None; +} diff --git a/src/test/rustdoc/reexports-priv.rs b/src/test/rustdoc/reexports-priv.rs new file mode 100644 index 000000000..aea9b9f2b --- /dev/null +++ b/src/test/rustdoc/reexports-priv.rs @@ -0,0 +1,135 @@ +// aux-build: reexports.rs +// compile-flags: --document-private-items + +#![crate_name = "foo"] + +extern crate reexports; + +// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' +pub use reexports::addr_of; +// @!has 'foo/macro.addr_of_crate.html' +pub(crate) use reexports::addr_of_crate; +// @!has 'foo/macro.addr_of_self.html' +pub(self) use reexports::addr_of_self; +// @!has 'foo/macro.addr_of_local.html' +use reexports::addr_of_local; + +// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;' +pub use reexports::Foo; +// @!has 'foo/struct.FooCrate.html' +pub(crate) use reexports::FooCrate; +// @!has 'foo/struct.FooSelf.html' +pub(self) use reexports::FooSelf; +// @!has 'foo/struct.FooLocal.html' +use reexports::FooLocal; + +// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {' +pub use reexports::Bar; +// @!has 'foo/enum.BarCrate.html' +pub(crate) use reexports::BarCrate; +// @!has 'foo/enum.BarSelf.html' +pub(self) use reexports::BarSelf; +// @!has 'foo/enum.BarLocal.html' +use reexports::BarLocal; + +// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()' +pub use reexports::foo; +// @!has 'foo/fn.foo_crate.html' +pub(crate) use reexports::foo_crate; +// @!has 'foo/fn.foo_self.html' +pub(self) use reexports::foo_self; +// @!has 'foo/fn.foo_local.html' +use reexports::foo_local; + +// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type =' +pub use reexports::Type; +// @!has 'foo/type.TypeCrate.html' +pub(crate) use reexports::TypeCrate; +// @!has 'foo/type.TypeSelf.html' +pub(self) use reexports::TypeSelf; +// @!has 'foo/type.TypeLocal.html' +use reexports::TypeLocal; + +// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {' +pub use reexports::Union; +// @!has 'foo/union.UnionCrate.html' +pub(crate) use reexports::UnionCrate; +// @!has 'foo/union.UnionSelf.html' +pub(self) use reexports::UnionSelf; +// @!has 'foo/union.UnionLocal.html' +use reexports::UnionLocal; + +pub mod outer { + pub mod inner { + // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' + pub use reexports::addr_of; + // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {' + pub(crate) use reexports::addr_of_crate; + // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {' + pub(super) use reexports::addr_of_super; + // @!has 'foo/outer/inner/macro.addr_of_self.html' + pub(self) use reexports::addr_of_self; + // @!has 'foo/outer/inner/macro.addr_of_local.html' + use reexports::addr_of_local; + + // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;' + pub use reexports::Foo; + // @has 'foo/outer/inner/struct.FooCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooCrate;' + pub(crate) use reexports::FooCrate; + // @has 'foo/outer/inner/struct.FooSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) struct FooSuper;' + pub(super) use reexports::FooSuper; + // @!has 'foo/outer/inner/struct.FooSelf.html' + pub(self) use reexports::FooSelf; + // @!has 'foo/outer/inner/struct.FooLocal.html' + use reexports::FooLocal; + + // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {' + pub use reexports::Bar; + // @has 'foo/outer/inner/enum.BarCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarCrate {' + pub(crate) use reexports::BarCrate; + // @has 'foo/outer/inner/enum.BarSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) enum BarSuper {' + pub(super) use reexports::BarSuper; + // @!has 'foo/outer/inner/enum.BarSelf.html' + pub(self) use reexports::BarSelf; + // @!has 'foo/outer/inner/enum.BarLocal.html' + use reexports::BarLocal; + + // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()' + pub use reexports::foo; + // @has 'foo/outer/inner/fn.foo_crate.html' '//*[@class="rust fn"]' 'pub(crate) fn foo_crate()' + pub(crate) use reexports::foo_crate; + // @has 'foo/outer/inner/fn.foo_super.html' '//*[@class="rust fn"]' 'pub(in outer) fn foo_super()' + pub(super) use::reexports::foo_super; + // @!has 'foo/outer/inner/fn.foo_self.html' + pub(self) use reexports::foo_self; + // @!has 'foo/outer/inner/fn.foo_local.html' + use reexports::foo_local; + + // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type =' + pub use reexports::Type; + // @has 'foo/outer/inner/type.TypeCrate.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeCrate =' + pub(crate) use reexports::TypeCrate; + // @has 'foo/outer/inner/type.TypeSuper.html' '//*[@class="rust typedef"]' 'pub(in outer) type TypeSuper =' + pub(super) use reexports::TypeSuper; + // @!has 'foo/outer/inner/type.TypeSelf.html' + pub(self) use reexports::TypeSelf; + // @!has 'foo/outer/inner/type.TypeLocal.html' + use reexports::TypeLocal; + + // @has 'foo/outer/inner/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {' + pub use reexports::Union; + // @has 'foo/outer/inner/union.UnionCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionCrate {' + pub(crate) use reexports::UnionCrate; + // @has 'foo/outer/inner/union.UnionSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) union UnionSuper {' + pub(super) use reexports::UnionSuper; + // @!has 'foo/outer/inner/union.UnionSelf.html' + pub(self) use reexports::UnionSelf; + // @!has 'foo/outer/inner/union.UnionLocal.html' + use reexports::UnionLocal; + } +} + +mod re_re_exports { + // @!has 'foo/re_re_exports/union.Union.html' + use crate::reexports::Union; +} diff --git a/src/test/rustdoc/reexports.rs b/src/test/rustdoc/reexports.rs new file mode 100644 index 000000000..7abcbfb61 --- /dev/null +++ b/src/test/rustdoc/reexports.rs @@ -0,0 +1,129 @@ +// aux-build: reexports.rs + +#![crate_name = "foo"] + +extern crate reexports; + +// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' +pub use reexports::addr_of; +// @!has 'foo/macro.addr_of_crate.html' +pub(crate) use reexports::addr_of_crate; +// @!has 'foo/macro.addr_of_self.html' +pub(self) use reexports::addr_of_self; +// @!has 'foo/macro.addr_of_local.html' +use reexports::addr_of_local; + +// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;' +pub use reexports::Foo; +// @!has 'foo/struct.FooCrate.html' +pub(crate) use reexports::FooCrate; +// @!has 'foo/struct.FooSelf.html' +pub(self) use reexports::FooSelf; +// @!has 'foo/struct.FooLocal.html' +use reexports::FooLocal; + +// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {' +pub use reexports::Bar; +// @!has 'foo/enum.BarCrate.html' +pub(crate) use reexports::BarCrate; +// @!has 'foo/enum.BarSelf.html' +pub(self) use reexports::BarSelf; +// @!has 'foo/enum.BarLocal.html' +use reexports::BarLocal; + +// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()' +pub use reexports::foo; +// @!has 'foo/fn.foo_crate.html' +pub(crate) use reexports::foo_crate; +// @!has 'foo/fn.foo_self.html' +pub(self) use reexports::foo_self; +// @!has 'foo/fn.foo_local.html' +use reexports::foo_local; + +// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type =' +pub use reexports::Type; +// @!has 'foo/type.TypeCrate.html' +pub(crate) use reexports::TypeCrate; +// @!has 'foo/type.TypeSelf.html' +pub(self) use reexports::TypeSelf; +// @!has 'foo/type.TypeLocal.html' +use reexports::TypeLocal; + +// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {' +pub use reexports::Union; +// @!has 'foo/union.UnionCrate.html' +pub(crate) use reexports::UnionCrate; +// @!has 'foo/union.UnionSelf.html' +pub(self) use reexports::UnionSelf; +// @!has 'foo/union.UnionLocal.html' +use reexports::UnionLocal; + +pub mod outer { + pub mod inner { + // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' + pub use reexports::addr_of; + // @!has 'foo/outer/inner/macro.addr_of_crate.html' + pub(crate) use reexports::addr_of_crate; + // @!has 'foo/outer/inner/macro.addr_of_super.html' + pub(super) use reexports::addr_of_super; + // @!has 'foo/outer/inner/macro.addr_of_self.html' + pub(self) use reexports::addr_of_self; + // @!has 'foo/outer/inner/macro.addr_of_local.html' + use reexports::addr_of_local; + + // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;' + pub use reexports::Foo; + // @!has 'foo/outer/inner/struct.FooCrate.html' + pub(crate) use reexports::FooCrate; + // @!has 'foo/outer/inner/struct.FooSuper.html' + pub(super) use reexports::FooSuper; + // @!has 'foo/outer/inner/struct.FooSelf.html' + pub(self) use reexports::FooSelf; + // @!has 'foo/outer/inner/struct.FooLocal.html' + use reexports::FooLocal; + + // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {' + pub use reexports::Bar; + // @!has 'foo/outer/inner/enum.BarCrate.html' + pub(crate) use reexports::BarCrate; + // @!has 'foo/outer/inner/enum.BarSuper.html' + pub(super) use reexports::BarSuper; + // @!has 'foo/outer/inner/enum.BarSelf.html' + pub(self) use reexports::BarSelf; + // @!has 'foo/outer/inner/enum.BarLocal.html' + use reexports::BarLocal; + + // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()' + pub use reexports::foo; + // @!has 'foo/outer/inner/fn.foo_crate.html' + pub(crate) use reexports::foo_crate; + // @!has 'foo/outer/inner/fn.foo_super.html' + pub(super) use::reexports::foo_super; + // @!has 'foo/outer/inner/fn.foo_self.html' + pub(self) use reexports::foo_self; + // @!has 'foo/outer/inner/fn.foo_local.html' + use reexports::foo_local; + + // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type =' + pub use reexports::Type; + // @!has 'foo/outer/inner/type.TypeCrate.html' + pub(crate) use reexports::TypeCrate; + // @!has 'foo/outer/inner/type.TypeSuper.html' + pub(super) use reexports::TypeSuper; + // @!has 'foo/outer/inner/type.TypeSelf.html' + pub(self) use reexports::TypeSelf; + // @!has 'foo/outer/inner/type.TypeLocal.html' + use reexports::TypeLocal; + + // @has 'foo/outer/inner/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {' + pub use reexports::Union; + // @!has 'foo/outer/inner/union.UnionCrate.html' + pub(crate) use reexports::UnionCrate; + // @!has 'foo/outer/inner/union.UnionSuper.html' + pub(super) use reexports::UnionSuper; + // @!has 'foo/outer/inner/union.UnionSelf.html' + pub(self) use reexports::UnionSelf; + // @!has 'foo/outer/inner/union.UnionLocal.html' + use reexports::UnionLocal; + } +} diff --git a/src/test/rustdoc/remove-duplicates.rs b/src/test/rustdoc/remove-duplicates.rs new file mode 100644 index 000000000..759bf84db --- /dev/null +++ b/src/test/rustdoc/remove-duplicates.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + +mod foo { + pub use bar::*; + pub mod bar { + pub trait Foo { + fn foo(); + } + } +} + +// @count foo/index.html '//*[@class="trait"]' 1 +pub use foo::bar::*; +pub use foo::*; diff --git a/src/test/rustdoc/remove-url-from-headings.rs b/src/test/rustdoc/remove-url-from-headings.rs new file mode 100644 index 000000000..e2b232a6e --- /dev/null +++ b/src/test/rustdoc/remove-url-from-headings.rs @@ -0,0 +1,17 @@ +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @!has - '//a[@href="http://a.a"]' +// @has - '//a[@href="#implementing-stuff-somewhere"]' 'Implementing stuff somewhere' +// @has - '//a[@href="#another-one-urg"]' 'Another one urg' + +/// fooo +/// +/// # Implementing [stuff](http://a.a "title") somewhere +/// +/// hello +/// +/// # Another [one][two] urg +/// +/// [two]: http://a.a +pub fn foo() {} diff --git a/src/test/rustdoc/return-impl-trait.rs b/src/test/rustdoc/return-impl-trait.rs new file mode 100644 index 000000000..1ccf5ac46 --- /dev/null +++ b/src/test/rustdoc/return-impl-trait.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +pub trait Backend {} + +impl Backend for () {} + +pub struct Module<T>(T); + +pub type BackendImpl = impl Backend; + +// @has return_impl_trait/fn.make_module.html +/// Documentation +pub fn make_module() -> Module<BackendImpl> { + Module(()) +} diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs new file mode 100644 index 000000000..f3e211e30 --- /dev/null +++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs @@ -0,0 +1,70 @@ +// Test that we do not currently display `~const` in rustdoc +// as that syntax is currently provisional; `~const Destruct` has +// no effect on stable code so it should be hidden as well. +// +// To future blessers: make sure that `const_trait_impl` is +// stabilized when changing `@!has` to `@has`, and please do +// not remove this test. +#![feature(const_trait_impl)] +#![crate_name = "foo"] + +use std::marker::Destruct; + +pub struct S<T>(T); + +// @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const' +// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone' +// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const' +// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone' +#[const_trait] +pub trait Tr<T> { + // @!has - '//div[@id="method.a"]/h4[@class="code-header"]' '~const' + // @has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone' + // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const' + // @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone' + fn a<A: ~const Clone + ~const Destruct>() + where + Option<A>: ~const Clone + ~const Destruct, + { + } +} + +// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]' '' +// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]' '~const' +// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone' +// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const' +// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone' +impl<T: ~const Clone + ~const Destruct> const Tr<T> for T +where + Option<T>: ~const Clone + ~const Destruct, +{ + fn a<A: ~const Clone + ~const Destruct>() + where + Option<A>: ~const Clone + ~const Destruct, + { + } +} + +// @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const' +// @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone' +// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const' +// @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone' +pub const fn foo<F: ~const Clone + ~const Destruct>() +where + Option<F>: ~const Clone + ~const Destruct, +{ + F::a() +} + +impl<T> S<T> { + // @!has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '~const' + // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone' + // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const' + // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone' + pub const fn foo<B: ~const Clone + ~const Destruct>() + where + B: ~const Clone + ~const Destruct, + { + B::a() + } +} diff --git a/src/test/rustdoc/rustc-macro-crate.rs b/src/test/rustdoc/rustc-macro-crate.rs new file mode 100644 index 000000000..dd5edc984 --- /dev/null +++ b/src/test/rustdoc/rustc-macro-crate.rs @@ -0,0 +1,14 @@ +// force-host +// no-prefer-dynamic +// compile-flags: --crate-type proc-macro + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Foo)] +pub fn foo(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/rustdoc/safe-intrinsic.rs b/src/test/rustdoc/safe-intrinsic.rs new file mode 100644 index 000000000..d3bb8514b --- /dev/null +++ b/src/test/rustdoc/safe-intrinsic.rs @@ -0,0 +1,20 @@ +#![feature(intrinsics)] +#![feature(no_core)] + +#![no_core] +#![crate_name = "foo"] + +extern "rust-intrinsic" { + // @has 'foo/fn.abort.html' + // @has - '//pre[@class="rust fn"]' 'pub extern "rust-intrinsic" fn abort() -> !' + pub fn abort() -> !; + // @has 'foo/fn.unreachable.html' + // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !' + pub fn unreachable() -> !; +} + +extern "C" { + // @has 'foo/fn.needs_drop.html' + // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !' + pub fn needs_drop() -> !; +} diff --git a/src/test/rustdoc/same-crate-hidden-impl-parameter.rs b/src/test/rustdoc/same-crate-hidden-impl-parameter.rs new file mode 100644 index 000000000..d55393af8 --- /dev/null +++ b/src/test/rustdoc/same-crate-hidden-impl-parameter.rs @@ -0,0 +1,36 @@ +// test for `doc(hidden)` with impl parameters in the same crate. +#![crate_name = "foo"] + +#[doc(hidden)] +pub enum HiddenType {} + +#[doc(hidden)] +pub trait HiddenTrait {} + +pub enum MyLibType {} + +// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CHiddenType%3E"]' 'impl From<HiddenType> for MyLibType' +impl From<HiddenType> for MyLibType { + fn from(it: HiddenType) -> MyLibType { + match it {} + } +} + +pub struct T<T>(T); + +// @!has foo/enum.MyLibType.html '//*[@id="impl-From%3CT%3CT%3CT%3CT%3CHiddenType%3E%3E%3E%3E%3E"]' 'impl From<T<T<T<T<HiddenType>>>>> for MyLibType' +impl From<T<T<T<T<HiddenType>>>>> for MyLibType { + fn from(it: T<T<T<T<HiddenType>>>>) -> MyLibType { + todo!() + } +} + +// @!has foo/enum.MyLibType.html '//*[@id="impl-HiddenTrait"]' 'impl HiddenTrait for MyLibType' +impl HiddenTrait for MyLibType {} + +// @!has foo/struct.T.html '//*[@id="impl-From%3CMyLibType%3E"]' 'impl From<MyLibType> for T<T<T<T<HiddenType>>>>' +impl From<MyLibType> for T<T<T<T<HiddenType>>>> { + fn from(it: MyLibType) -> T<T<T<T<HiddenType>>>> { + match it {} + } +} diff --git a/src/test/rustdoc/sanitizer-option.rs b/src/test/rustdoc/sanitizer-option.rs new file mode 100644 index 000000000..1abba468f --- /dev/null +++ b/src/test/rustdoc/sanitizer-option.rs @@ -0,0 +1,18 @@ +// needs-sanitizer-support +// needs-sanitizer-address +// compile-flags: --test -Z sanitizer=address +// +// #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern +// function that is provided by the sanitizer runtime, if flag is not passed +// correctly, then linking will fail. + +/// ``` +/// extern "C" { +/// fn __sanitizer_print_stack_trace(); +/// } +/// +/// fn main() { +/// unsafe { __sanitizer_print_stack_trace() }; +/// } +/// ``` +pub fn z_flag_is_passed_to_rustc() {} diff --git a/src/test/rustdoc/search-index-summaries.rs b/src/test/rustdoc/search-index-summaries.rs new file mode 100644 index 000000000..dd9c1a0b4 --- /dev/null +++ b/src/test/rustdoc/search-index-summaries.rs @@ -0,0 +1,10 @@ +#![crate_name = "foo"] + +// @has 'search-index.js' 'Foo short link.' +// @!has - 'www.example.com' +// @!has - 'More Foo.' + +/// Foo short [link](https://www.example.com/). +/// +/// More Foo. +pub struct Foo; diff --git a/src/test/rustdoc/search-index.rs b/src/test/rustdoc/search-index.rs new file mode 100644 index 000000000..f1b78f172 --- /dev/null +++ b/src/test/rustdoc/search-index.rs @@ -0,0 +1,26 @@ +#![crate_name = "rustdoc_test"] + +use std::ops::Deref; + +// @has search-index.js Foo +pub use private::Foo; + +mod private { + pub struct Foo; + impl Foo { + pub fn test_method() {} // @has - test_method + fn priv_method() {} // @!has - priv_method + } + + pub trait PrivateTrait { + fn trait_method(&self) {} // @!has - priv_method + } +} + +pub struct Bar; + +impl Deref for Bar { + // @!has search-index.js Target + type Target = Bar; + fn deref(&self) -> &Bar { self } +} diff --git a/src/test/rustdoc/short-docblock-codeblock.rs b/src/test/rustdoc/short-docblock-codeblock.rs new file mode 100644 index 000000000..c6b318b06 --- /dev/null +++ b/src/test/rustdoc/short-docblock-codeblock.rs @@ -0,0 +1,12 @@ +#![crate_name = "foo"] + +// @has foo/index.html '//*[@class="item-right docblock-short"]' "" +// @!has foo/index.html '//*[@class="item-right docblock-short"]' "Some text." +// @!has foo/index.html '//*[@class="item-right docblock-short"]' "let x = 12;" + +/// ``` +/// let x = 12; +/// ``` +/// +/// Some text. +pub fn foo() {} diff --git a/src/test/rustdoc/short-docblock.rs b/src/test/rustdoc/short-docblock.rs new file mode 100644 index 000000000..17c44eab0 --- /dev/null +++ b/src/test/rustdoc/short-docblock.rs @@ -0,0 +1,25 @@ +#![crate_name = "foo"] + +// @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'fooo' +// @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h1' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo' + +/// # fooo +/// +/// foo +pub fn foo() {} + +// @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'mooood' +// @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h2' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood' + +/// ## mooood +/// +/// foo mod +pub mod foo {} + +// @has foo/index.html '//*[@class="item-right docblock-short"]/p/a[@href=\ +// "https://nougat.world"]/code' 'nougat' + +/// [`nougat`](https://nougat.world) +pub struct Bar; diff --git a/src/test/rustdoc/short-line.md b/src/test/rustdoc/short-line.md new file mode 100644 index 000000000..eff713baa --- /dev/null +++ b/src/test/rustdoc/short-line.md @@ -0,0 +1,2 @@ +inc2 +x diff --git a/src/test/rustdoc/show-const-contents.rs b/src/test/rustdoc/show-const-contents.rs new file mode 100644 index 000000000..48b608859 --- /dev/null +++ b/src/test/rustdoc/show-const-contents.rs @@ -0,0 +1,68 @@ +// Test that the contents of constants are displayed as part of the +// documentation. + +// @has show_const_contents/constant.CONST_S.html 'show this' +// @!has show_const_contents/constant.CONST_S.html '; //' +pub const CONST_S: &'static str = "show this"; + +// @has show_const_contents/constant.CONST_I32.html '= 42;' +// @!has show_const_contents/constant.CONST_I32.html '; //' +pub const CONST_I32: i32 = 42; + +// @has show_const_contents/constant.CONST_I32_HEX.html '= 0x42;' +// @!has show_const_contents/constant.CONST_I32_HEX.html '; //' +pub const CONST_I32_HEX: i32 = 0x42; + +// @has show_const_contents/constant.CONST_NEG_I32.html '= -42;' +// @!has show_const_contents/constant.CONST_NEG_I32.html '; //' +pub const CONST_NEG_I32: i32 = -42; + +// @has show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '= 42i32;' +// @!has show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '// 42i32' +pub const CONST_EQ_TO_VALUE_I32: i32 = 42i32; + +// @has show_const_contents/constant.CONST_CALC_I32.html '= _; // 43i32' +pub const CONST_CALC_I32: i32 = 42 + 1; + +// @!has show_const_contents/constant.CONST_REF_I32.html '= &42;' +// @!has show_const_contents/constant.CONST_REF_I32.html '; //' +pub const CONST_REF_I32: &'static i32 = &42; + +// @has show_const_contents/constant.CONST_I32_MAX.html '= i32::MAX; // 2_147_483_647i32' +pub const CONST_I32_MAX: i32 = i32::MAX; + +// @!has show_const_contents/constant.UNIT.html '= ();' +// @!has show_const_contents/constant.UNIT.html '; //' +pub const UNIT: () = (); + +pub struct MyType(i32); + +// @!has show_const_contents/constant.MY_TYPE.html '= MyType(42);' +// @!has show_const_contents/constant.MY_TYPE.html '; //' +pub const MY_TYPE: MyType = MyType(42); + +pub struct MyTypeWithStr(&'static str); + +// @!has show_const_contents/constant.MY_TYPE_WITH_STR.html '= MyTypeWithStr("show this");' +// @!has show_const_contents/constant.MY_TYPE_WITH_STR.html '; //' +pub const MY_TYPE_WITH_STR: MyTypeWithStr = MyTypeWithStr("show this"); + +// @has show_const_contents/constant.PI.html '= 3.14159265358979323846264338327950288f32;' +// @has show_const_contents/constant.PI.html '; // 3.14159274f32' +pub use std::f32::consts::PI; + +// @has show_const_contents/constant.MAX.html '= i32::MAX; // 2_147_483_647i32' +#[allow(deprecated, deprecated_in_future)] +pub use std::i32::MAX; + +macro_rules! int_module { + ($T:ident) => ( + pub const MIN: $T = $T::MIN; + ) +} + +// @has show_const_contents/constant.MIN.html '= i16::MIN; // -32_768i16' +int_module!(i16); + +// @has show_const_contents/constant.ESCAPE.html //pre '= r#"<script>alert("ESCAPE");</script>"#;' +pub const ESCAPE: &str = r#"<script>alert("ESCAPE");</script>"#; diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs new file mode 100644 index 000000000..b5b681ab0 --- /dev/null +++ b/src/test/rustdoc/sidebar-items.rs @@ -0,0 +1,56 @@ +#![feature(associated_type_defaults)] +#![crate_name = "foo"] + +// @has foo/trait.Foo.html +// @has - '//*[@class="sidebar-title"]/a[@href="#required-methods"]' 'Required Methods' +// @has - '//*[@class="sidebar-elems"]//section//a' 'bar' +// @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods' +// @has - '//*[@class="sidebar-elems"]//section//a' 'foo' +// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-consts"]' 'Required Associated Constants' +// @has - '//*[@class="sidebar-elems"]//section//a' 'FOO' +// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-consts"]' 'Provided Associated Constants' +// @has - '//*[@class="sidebar-elems"]//section//a' 'BAR' +// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-types"]' 'Required Associated Types' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Output' +// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-types"]' 'Provided Associated Types' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Extra' +pub trait Foo { + const FOO: usize; + const BAR: u32 = 0; + type Extra: Copy = (); + type Output: ?Sized; + + fn foo() {} + fn bar() -> Self::Output; +} + +// @has foo/struct.Bar.html +// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u' +// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza' +pub struct Bar { + pub f: u32, + pub u: u32, + waza: u32, +} + +// @has foo/enum.En.html +// @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Foo' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Bar' +pub enum En { + Foo, + Bar, +} + +// @has foo/union.MyUnion.html +// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2' +// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza' +pub union MyUnion { + pub f1: u32, + pub f2: f32, + waza: u32, +} diff --git a/src/test/rustdoc/sidebar-link-generation.rs b/src/test/rustdoc/sidebar-link-generation.rs new file mode 100644 index 000000000..7858f35a2 --- /dev/null +++ b/src/test/rustdoc/sidebar-link-generation.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +// @has foo/struct.SomeStruct.html '//*[@class="sidebar-elems"]//section//li/a[@href="#method.some_fn-1"]' \ +// "some_fn" +pub struct SomeStruct<T> { _inner: T } + +impl SomeStruct<()> { + pub fn some_fn(&self) {} +} + +impl SomeStruct<usize> { + pub fn some_fn(&self) {} +} diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs new file mode 100644 index 000000000..155150396 --- /dev/null +++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs @@ -0,0 +1,16 @@ +// issue #56018: "Implementations on Foreign Types" sidebar items should link to specific impls + +#![crate_name = "foo"] + +// @has foo/trait.Foo.html +// @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types' +// @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32' +// @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str" +// @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str" +pub trait Foo {} + +impl Foo for u32 {} + +impl<'a> Foo for &'a str {} diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs new file mode 100644 index 000000000..9d2c19677 --- /dev/null +++ b/src/test/rustdoc/sized_trait.rs @@ -0,0 +1,17 @@ +#![crate_name = "foo"] + +// @has foo/struct.Bar.html +// @!has - '//*[@id="impl-Sized"]' +pub struct Bar { + a: u16, +} + +// @has foo/struct.Foo.html +// @!has - '//*[@id="impl-Sized"]' +pub struct Foo<T: ?Sized>(T); + +// @has foo/struct.Unsized.html +// @has - '//*[@id="impl-Sized-for-Unsized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized' +pub struct Unsized { + data: [u8], +} diff --git a/src/test/rustdoc/slice-links.link_box_generic.html b/src/test/rustdoc/slice-links.link_box_generic.html new file mode 100644 index 000000000..38aaf2080 --- /dev/null +++ b/src/test/rustdoc/slice-links.link_box_generic.html @@ -0,0 +1 @@ +<code>pub fn delta<T>() -> <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a><<a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a>></code>
\ No newline at end of file diff --git a/src/test/rustdoc/slice-links.link_box_u32.html b/src/test/rustdoc/slice-links.link_box_u32.html new file mode 100644 index 000000000..7bec7582d --- /dev/null +++ b/src/test/rustdoc/slice-links.link_box_u32.html @@ -0,0 +1 @@ +<code>pub fn gamma() -> <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a><[<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]></code>
\ No newline at end of file diff --git a/src/test/rustdoc/slice-links.link_slice_generic.html b/src/test/rustdoc/slice-links.link_slice_generic.html new file mode 100644 index 000000000..1d0f2bf75 --- /dev/null +++ b/src/test/rustdoc/slice-links.link_slice_generic.html @@ -0,0 +1 @@ +<code>pub fn beta<T>() -> &'static <a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a></code>
\ No newline at end of file diff --git a/src/test/rustdoc/slice-links.link_slice_u32.html b/src/test/rustdoc/slice-links.link_slice_u32.html new file mode 100644 index 000000000..c86d38304 --- /dev/null +++ b/src/test/rustdoc/slice-links.link_slice_u32.html @@ -0,0 +1 @@ +<code>pub fn alpha() -> &'static [<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]</code>
\ No newline at end of file diff --git a/src/test/rustdoc/slice-links.rs b/src/test/rustdoc/slice-links.rs new file mode 100644 index 000000000..9a78e963e --- /dev/null +++ b/src/test/rustdoc/slice-links.rs @@ -0,0 +1,28 @@ +#![crate_name = "foo"] +#![no_std] + +pub struct MyBox<T: ?Sized>(*const T); + +// @has 'foo/fn.alpha.html' +// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code' +pub fn alpha() -> &'static [u32] { + loop {} +} + +// @has 'foo/fn.beta.html' +// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code' +pub fn beta<T>() -> &'static [T] { + loop {} +} + +// @has 'foo/fn.gamma.html' +// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code' +pub fn gamma() -> MyBox<[u32]> { + loop {} +} + +// @has 'foo/fn.delta.html' +// @snapshot link_box_generic - '//pre[@class="rust fn"]/code' +pub fn delta<T>() -> MyBox<[T]> { + loop {} +} diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs new file mode 100644 index 000000000..7ae5bd699 --- /dev/null +++ b/src/test/rustdoc/smart-punct.rs @@ -0,0 +1,28 @@ +#![crate_name = "foo"] + +//! This is the "start" of the 'document'! How'd you know that "it's" the start? +//! +//! # Header with "smart punct'" +//! +//! [link with "smart punct'" -- yessiree!][] +//! +//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org +//! +//! # Code should not be smart-punct'd +//! +//! `this inline code -- it shouldn't have "smart punct"` +//! +//! ``` +//! let x = "don't smart-punct me -- please!"; +//! ``` +//! +//! ```text +//! I say "don't smart-punct me -- please!" +//! ``` + +// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" +// @has "foo/index.html" "//h2" "Header with “smart punct’”" +// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" +// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\"" +// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";" +// @has "foo/index.html" '//pre' "I say \"don't smart-punct me -- please!\"" diff --git a/src/test/rustdoc/smoke.rs b/src/test/rustdoc/smoke.rs new file mode 100644 index 000000000..c1ed3a0c9 --- /dev/null +++ b/src/test/rustdoc/smoke.rs @@ -0,0 +1,25 @@ +// @has smoke/index.html + +//! Very docs + +// @has smoke/bar/index.html +pub mod bar { + + /// So correct + // @has smoke/bar/baz/index.html + pub mod baz { + /// Much detail + // @has smoke/bar/baz/fn.baz.html + pub fn baz() { } + } + + /// *wow* + // @has smoke/bar/trait.Doge.html + pub trait Doge { fn dummy(&self) { } } + + // @has smoke/bar/struct.Foo.html + pub struct Foo { x: isize, y: usize } + + // @has smoke/bar/fn.prawns.html + pub fn prawns((a, b): (isize, usize), Foo { x, y }: Foo) { } +} diff --git a/src/test/rustdoc/sort-modules-by-appearance.rs b/src/test/rustdoc/sort-modules-by-appearance.rs new file mode 100644 index 000000000..5be6b9826 --- /dev/null +++ b/src/test/rustdoc/sort-modules-by-appearance.rs @@ -0,0 +1,13 @@ +// Tests the rustdoc --sort-modules-by-appearance option, that allows module declarations to appear +// in the order they are declared in the source code, rather than only alphabetically. + +// compile-flags: -Z unstable-options --sort-modules-by-appearance + +pub mod module_b {} + +pub mod module_c {} + +pub mod module_a {} + +// @matches 'sort_modules_by_appearance/index.html' '(?s)module_b.*module_c.*module_a' +// @matches 'sort_modules_by_appearance/sidebar-items.js' '"module_b".*"module_c".*"module_a"' diff --git a/src/test/rustdoc/source-file.rs b/src/test/rustdoc/source-file.rs new file mode 100644 index 000000000..968899dab --- /dev/null +++ b/src/test/rustdoc/source-file.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +// @has source-files.js source-file.rs + +pub struct Foo; diff --git a/src/test/rustdoc/source-version-separator.rs b/src/test/rustdoc/source-version-separator.rs new file mode 100644 index 000000000..14580373b --- /dev/null +++ b/src/test/rustdoc/source-version-separator.rs @@ -0,0 +1,30 @@ +#![stable(feature = "bar", since = "1.0")] +#![crate_name = "foo"] +#![feature(staged_api)] + +// @has foo/trait.Bar.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "bar", since = "1.0")] +pub trait Bar { + // @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source' + #[stable(feature = "foobar", since = "3.0")] + fn foo(); +} + +// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source' + +// @has foo/struct.Foo.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "baz", since = "1.0")] +pub struct Foo; + +impl Foo { + // @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source' + #[stable(feature = "foobar", since = "3.0")] + pub fn foofoo() {} +} + +#[stable(feature = "yolo", since = "4.0")] +impl Bar for Foo { + fn foo() {} +} diff --git a/src/test/rustdoc/spotlight-from-dependency.rs b/src/test/rustdoc/spotlight-from-dependency.rs new file mode 100644 index 000000000..524578921 --- /dev/null +++ b/src/test/rustdoc/spotlight-from-dependency.rs @@ -0,0 +1,24 @@ +#![crate_name = "foo"] + +use std::iter::Iterator; + +// @has foo/struct.Odd.html +// @has - '//*[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd' +pub struct Odd { + current: usize, +} + +impl Odd { + pub fn new() -> Odd { + Odd { current: 1 } + } +} + +impl Iterator for Odd { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + self.current += 2; + Some(self.current - 2) + } +} diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs new file mode 100644 index 000000000..69be9aa8d --- /dev/null +++ b/src/test/rustdoc/src-links-auto-impls.rs @@ -0,0 +1,12 @@ +#![crate_name = "foo"] + +// @has foo/struct.Unsized.html +// @has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized' +// @!has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="srclink"]' 'source' +// @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized' +// @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="srclink"]' 'source' +// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header in-band"]' 'impl<T> Any for T' +// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="srclink"]' 'source' +pub struct Unsized { + data: [u8], +} diff --git a/src/test/rustdoc/src-links-external.rs b/src/test/rustdoc/src-links-external.rs new file mode 100644 index 000000000..8012e4422 --- /dev/null +++ b/src/test/rustdoc/src-links-external.rs @@ -0,0 +1,13 @@ +// aux-build:src-links-external.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +extern crate src_links_external; + +// @has foo/bar/index.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#1' +#[doc(inline)] +pub use src_links_external as bar; + +// @has foo/bar/struct.Foo.html '//a/@href' '../../src/src_links_external/src-links-external.rs.html#1' diff --git a/src/test/rustdoc/src-links.rs b/src/test/rustdoc/src-links.rs new file mode 100644 index 000000000..353ce1024 --- /dev/null +++ b/src/test/rustdoc/src-links.rs @@ -0,0 +1,46 @@ +#![crate_name = "foo"] + +//! Dox +// @has src/foo/src-links.rs.html +// @has foo/index.html '//a/@href' '../src/foo/src-links.rs.html' + +#[path = "src-links/mod.rs"] +pub mod qux; + +// @has foo/bar/index.html '//a/@href' '../../src/foo/src-links.rs.html' +pub mod bar { + + /// Dox + // @has foo/bar/baz/index.html '//a/@href' '../../../src/foo/src-links.rs.html' + pub mod baz { + /// Dox + // @has foo/bar/baz/fn.baz.html '//a/@href' '../../../src/foo/src-links.rs.html' + pub fn baz() { } + } + + /// Dox + // @has foo/bar/trait.Foobar.html '//a/@href' '../../src/foo/src-links.rs.html' + pub trait Foobar { fn dummy(&self) { } } + + // @has foo/bar/struct.Foo.html '//a/@href' '../../src/foo/src-links.rs.html' + pub struct Foo { x: i32, y: u32 } + + // @has foo/bar/fn.prawns.html '//a/@href' '../../src/foo/src-links.rs.html' + pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } +} + +/// Dox +// @has foo/fn.modfn.html '//a/@href' '../src/foo/src-links.rs.html' +pub fn modfn() { } + +// same hierarchy as above, but just for the submodule + +// @has src/foo/src-links/mod.rs.html +// @has foo/qux/index.html '//a/@href' '../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/index.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/baz/index.html '//a/@href' '../../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/baz/fn.baz.html '//a/@href' '../../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/trait.Foobar.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/struct.Foo.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/fn.prawns.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/fn.modfn.html '//a/@href' '../../src/foo/src-links/mod.rs.html' diff --git a/src/test/rustdoc/src-links/compiletest-ignore-dir b/src/test/rustdoc/src-links/compiletest-ignore-dir new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/test/rustdoc/src-links/compiletest-ignore-dir diff --git a/src/test/rustdoc/src-links/mod.rs b/src/test/rustdoc/src-links/mod.rs new file mode 100644 index 000000000..27b239681 --- /dev/null +++ b/src/test/rustdoc/src-links/mod.rs @@ -0,0 +1,19 @@ +//! Dox +pub mod bar { + + /// Dox + pub mod baz { + /// Dox + pub fn baz() { } + } + + /// Dox + pub trait Foobar { fn dummy(&self) { } } + + pub struct Foo { x: i32, y: u32 } + + pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } +} + +/// Dox +pub fn modfn() { } diff --git a/src/test/rustdoc/stability.rs b/src/test/rustdoc/stability.rs new file mode 100644 index 000000000..90be2050d --- /dev/null +++ b/src/test/rustdoc/stability.rs @@ -0,0 +1,12 @@ +#![feature(staged_api)] + +#![unstable(feature = "test", issue = "none")] + +pub struct Unstable { + // @has stability/struct.Unstable.html \ + // '//span[@class="item-info"]//div[@class="stab unstable"]' \ + // 'This is a nightly-only experimental API' + // @count stability/struct.Unstable.html '//span[@class="stab unstable"]' 0 + pub foo: u32, + pub bar: u32, +} diff --git a/src/test/rustdoc/static-root-path.rs b/src/test/rustdoc/static-root-path.rs new file mode 100644 index 000000000..f1d49b9fc --- /dev/null +++ b/src/test/rustdoc/static-root-path.rs @@ -0,0 +1,18 @@ +// compile-flags:-Z unstable-options --static-root-path /cache/ + +// @has static_root_path/struct.SomeStruct.html +// @matches - '"/cache/main\.js"' +// @!matches - '"\.\./main\.js"' +// @matches - 'data-root-path="\.\./"' +// @!matches - '"/cache/search-index\.js"' +pub struct SomeStruct; + +// @has src/static_root_path/static-root-path.rs.html +// @matches - '"/cache/source-script\.js"' +// @!matches - '"\.\./\.\./source-script\.js"' +// @matches - '"\.\./\.\./source-files.js"' +// @!matches - '"/cache/source-files\.js"' + +// @has settings.html +// @matches - '/cache/settings\.js' +// @!matches - '\./settings\.js' diff --git a/src/test/rustdoc/static.rs b/src/test/rustdoc/static.rs new file mode 100644 index 000000000..90dafd8b3 --- /dev/null +++ b/src/test/rustdoc/static.rs @@ -0,0 +1,12 @@ +// compile-flags: --document-private-items + +#![crate_type = "lib"] + +// @has static/static.FOO.html '//pre' 'static FOO: usize' +static FOO: usize = 1; + +// @has static/static.BAR.html '//pre' 'pub static BAR: usize' +pub static BAR: usize = 1; + +// @has static/static.BAZ.html '//pre' 'pub static mut BAZ: usize' +pub static mut BAZ: usize = 1; diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html new file mode 100644 index 000000000..22b0b5dc4 --- /dev/null +++ b/src/test/rustdoc/strip-block-doc-comments-stars.docblock.html @@ -0,0 +1,2 @@ +<div class="docblock"><p>a</p> +</div>
\ No newline at end of file diff --git a/src/test/rustdoc/strip-block-doc-comments-stars.rs b/src/test/rustdoc/strip-block-doc-comments-stars.rs new file mode 100644 index 000000000..ea28d84f1 --- /dev/null +++ b/src/test/rustdoc/strip-block-doc-comments-stars.rs @@ -0,0 +1,11 @@ +#![crate_name = "foo"] + +// The goal of this test is to ensure that it won't be generated as a list because +// block doc comments can have their lines starting with a star. + +// @has foo/fn.foo.html +// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]' +/** + * a + */ +pub fn foo() {} diff --git a/src/test/rustdoc/strip-enum-variant.no-not-shown.html b/src/test/rustdoc/strip-enum-variant.no-not-shown.html new file mode 100644 index 000000000..c4ee1a991 --- /dev/null +++ b/src/test/rustdoc/strip-enum-variant.no-not-shown.html @@ -0,0 +1 @@ +<ul><li><a href="#variant.Shown">Shown</a></li></ul>
\ No newline at end of file diff --git a/src/test/rustdoc/strip-enum-variant.rs b/src/test/rustdoc/strip-enum-variant.rs new file mode 100644 index 000000000..f82ffdfed --- /dev/null +++ b/src/test/rustdoc/strip-enum-variant.rs @@ -0,0 +1,11 @@ +// @has strip_enum_variant/enum.MyThing.html +// @has - '//code' 'Shown' +// @!has - '//code' 'NotShown' +// @has - '//code' '// some variants omitted' +// Also check that `NotShown` isn't displayed in the sidebar. +// @snapshot no-not-shown - '//*[@class="sidebar-elems"]/section/*[@class="block"][1]/ul' +pub enum MyThing { + Shown, + #[doc(hidden)] + NotShown, +} diff --git a/src/test/rustdoc/struct-arg-pattern.rs b/src/test/rustdoc/struct-arg-pattern.rs new file mode 100644 index 000000000..3c0369e3d --- /dev/null +++ b/src/test/rustdoc/struct-arg-pattern.rs @@ -0,0 +1,10 @@ +#![crate_name = "foo"] + +struct BodyId { + hir_id: usize, +} + +// @has 'foo/fn.body_owner.html' '//*[@class="rust fn"]' 'pub fn body_owner(_: BodyId)' +pub fn body_owner(BodyId { hir_id }: BodyId) { + // ... +} diff --git a/src/test/rustdoc/struct-field.rs b/src/test/rustdoc/struct-field.rs new file mode 100644 index 000000000..998683bdd --- /dev/null +++ b/src/test/rustdoc/struct-field.rs @@ -0,0 +1,22 @@ +#![crate_name = "foo"] + + +// @has foo/index.html '//*[@class="docblock"]/p/a[@href="struct.Foo.html#structfield.bar"]' 'Foo::bar' +// @has foo/index.html '//*[@class="docblock"]/p/a[@href="union.Bar.html#structfield.foo"]' 'Bar::foo' +// @has foo/index.html '//*[@class="docblock"]/p/a[@href="enum.Uniooon.html#variant.X"]' 'Uniooon::X' + +//! Test with [Foo::bar], [Bar::foo], [Uniooon::X] + +pub struct Foo { + pub bar: usize, +} + +pub union Bar { + pub foo: u32, +} + +pub enum Uniooon { + F, + X, + Y, +} diff --git a/src/test/rustdoc/struct-implementations-title.rs b/src/test/rustdoc/struct-implementations-title.rs new file mode 100644 index 000000000..5468796f6 --- /dev/null +++ b/src/test/rustdoc/struct-implementations-title.rs @@ -0,0 +1,9 @@ +#![crate_name = "foo"] + +pub struct Struc; + +// @has foo/struct.Struc.html +// @has - '//*[@id="main-content"]/h2[@id="implementations"]' "Implementations" +impl Struc { + pub const S: u64 = 0; +} diff --git a/src/test/rustdoc/structfields.rs b/src/test/rustdoc/structfields.rs new file mode 100644 index 000000000..7e1cada4b --- /dev/null +++ b/src/test/rustdoc/structfields.rs @@ -0,0 +1,44 @@ +// @has structfields/struct.Foo.html +pub struct Foo { + // @has - //pre "pub a: ()" + pub a: (), + // @has - //pre "/* private fields */" + // @!has - //pre "b: ()" + b: (), + // @!has - //pre "c: usize" + #[doc(hidden)] + c: usize, + // @has - //pre "pub d: usize" + pub d: usize, +} + +// @has structfields/struct.Bar.html +pub struct Bar { + // @has - //pre "pub a: ()" + pub a: (), + // @!has - //pre "/* private fields */" +} + +// @has structfields/enum.Qux.html +pub enum Qux { + Quz { + // @has - //pre "a: ()" + a: (), + // @!has - //pre "b: ()" + #[doc(hidden)] + b: (), + // @has - //pre "c: usize" + c: usize, + // @has - //pre "/* private fields */" + }, +} + +// @has structfields/struct.Baz.html //pre "pub struct Baz { /* private fields */ }" +pub struct Baz { + x: u8, + #[doc(hidden)] + pub y: u8, +} + +// @has structfields/struct.Quux.html //pre "pub struct Quux {}" +pub struct Quux {} diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs new file mode 100644 index 000000000..54c54fdbf --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -0,0 +1,8 @@ +// @has basic/struct.Foo.html +// @has - '//h3[@class="code-header in-band"]' 'impl<T> Send for Foo<T> where T: Send' +// @has - '//h3[@class="code-header in-band"]' 'impl<T> Sync for Foo<T> where T: Sync' +// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 +pub struct Foo<T> { + field: T, +} diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs new file mode 100644 index 000000000..f9017b90c --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -0,0 +1,42 @@ +mod foo { + pub trait MyTrait<'a> { + type MyItem: ?Sized; + } + + pub struct Inner<'a, Q, R: ?Sized> { + field: Q, + field3: &'a u8, + my_foo: Foo<Q>, + field2: R, + } + + pub struct Outer<'a, T, K: ?Sized> { + my_inner: Inner<'a, T, K>, + } + + pub struct Foo<T> { + myfield: T, + } +} + +// @has complex/struct.NotOuter.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ +// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static" + +pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter}; + +unsafe impl<T> Send for Foo<T> +where + T: NotMyTrait<'static>, +{ +} + +unsafe impl<'a, Q, R: ?Sized> Send for NotInner<'a, Q, R> +where + Q: NotMyTrait<'a>, + <Q as NotMyTrait<'a>>::MyItem: Copy, + R: for<'b> Fn((&'b bool, &'a u8)) -> &'b i8, + Foo<Q>: Send, +{ +} diff --git a/src/test/rustdoc/synthetic_auto/crate-local.rs b/src/test/rustdoc/synthetic_auto/crate-local.rs new file mode 100644 index 000000000..58b787dfa --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/crate-local.rs @@ -0,0 +1,9 @@ +#![feature(auto_traits)] + +pub auto trait Banana {} + +// @has crate_local/struct.Peach.html +// @has - '//h3[@class="code-header in-band"]' 'impl Banana for Peach' +// @has - '//h3[@class="code-header in-band"]' 'impl Send for Peach' +// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Peach' +pub struct Peach; diff --git a/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs b/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs new file mode 100644 index 000000000..6f66b8e55 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs @@ -0,0 +1,25 @@ +// Regression test for issue #72213 +// Tests that we don't ICE when we have projection predicates +// in our initial ParamEnv + +pub struct Lines<'a, L> +where + L: Iterator<Item = &'a ()>, +{ + words: std::iter::Peekable<Words<'a, L>>, +} + +pub struct Words<'a, L> { + _m: std::marker::PhantomData<&'a L>, +} + +impl<'a, L> Iterator for Words<'a, L> +where + L: Iterator<Item = &'a ()>, +{ + type Item = (); + + fn next(&mut self) -> Option<Self::Item> { + unimplemented!() + } +} diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs new file mode 100644 index 000000000..ee1393f97 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs @@ -0,0 +1,19 @@ +pub struct Inner<'a, T: 'a> { + field: &'a T, +} + +unsafe impl<'a, T> Send for Inner<'a, T> +where + 'a: 'static, + T: for<'b> Fn(&'b bool) -> &'a u8, +{} + +// @has lifetimes/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" +// +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'c, K> Sync for Foo<'c, K> where K: Sync" +pub struct Foo<'c, K: 'c> { + inner_field: Inner<'c, K>, +} diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs new file mode 100644 index 000000000..49bad1622 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -0,0 +1,14 @@ +// @has manual/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// 'impl<T> Sync for Foo<T> where T: Sync' +// +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// 'impl<T> Send for Foo<T>' +// +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4 +pub struct Foo<T> { + field: T, +} + +unsafe impl<T> Send for Foo<T> {} diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs new file mode 100644 index 000000000..66e749ac3 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/negative.rs @@ -0,0 +1,13 @@ +pub struct Inner<T: Copy> { + field: *mut T, +} + +// @has negative/struct.Outer.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> !Send for Outer<T>" +// +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> !Sync for Outer<T>" +pub struct Outer<T: Copy> { + inner_field: Inner<T>, +} diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs new file mode 100644 index 000000000..69edbee61 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/nested.rs @@ -0,0 +1,19 @@ +pub struct Inner<T> { + field: T, +} + +unsafe impl<T> Send for Inner<T> +where + T: Copy, +{ +} + +// @has nested/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// 'impl<T> Send for Foo<T> where T: Copy' +// +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// 'impl<T> Sync for Foo<T> where T: Sync' +pub struct Foo<T> { + inner_field: Inner<T>, +} diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs new file mode 100644 index 000000000..16ab876e8 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -0,0 +1,16 @@ +pub struct Inner<T> { + field: T, +} + +unsafe impl<T> Send for Inner<T> +where + T: Copy + Send, +{ +} + +// @has no_redundancy/struct.Outer.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> Send for Outer<T> where T: Send + Copy" +pub struct Outer<T> { + inner_field: Inner<T>, +} diff --git a/src/test/rustdoc/synthetic_auto/overflow.rs b/src/test/rustdoc/synthetic_auto/overflow.rs new file mode 100644 index 000000000..c132ab6fb --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/overflow.rs @@ -0,0 +1,35 @@ +// Tests that we don't fail with an overflow error for certain +// strange types +// See https://github.com/rust-lang/rust/pull/72936#issuecomment-643676915 + +pub trait Interner { + type InternedType; +} + +struct RustInterner<'tcx> { + foo: &'tcx () +} + +impl<'tcx> Interner for RustInterner<'tcx> { + type InternedType = Box<TyData<Self>>; +} + +enum TyData<I: Interner> { + FnDef(I::InternedType) +} + +struct VariableKind<I: Interner>(I::InternedType); + +// @has overflow/struct.BoundVarsCollector.html +// @has - '//h3[@class="code-header in-band"]' "impl<'tcx> Send for BoundVarsCollector<'tcx>" +pub struct BoundVarsCollector<'tcx> { + val: VariableKind<RustInterner<'tcx>> +} + +fn is_send<T: Send>() {} + +struct MyInterner<'tcx> { + val: &'tcx () +} + +fn main() {} diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs new file mode 100644 index 000000000..8b0205825 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/project.rs @@ -0,0 +1,34 @@ +pub struct Inner<'a, T: 'a> { + field: &'a T, +} + +trait MyTrait { + type MyItem; +} + +trait OtherTrait {} + +unsafe impl<'a, T> Send for Inner<'a, T> +where + 'a: 'static, + T: MyTrait<MyItem = bool>, +{ +} +unsafe impl<'a, T> Sync for Inner<'a, T> +where + 'a: 'static, + T: MyTrait, + <T as MyTrait>::MyItem: OtherTrait, +{ +} + +// @has project/struct.Foo.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static" +// +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \ +// 'c: 'static," +pub struct Foo<'c, K: 'c> { + inner_field: Inner<'c, K>, +} diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs new file mode 100644 index 000000000..ccef901b1 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -0,0 +1,29 @@ +// Some unusual code minimized from +// https://github.com/sile/handy_async/tree/7b619b762c06544fc67792c8ff8ebc24a88fdb98 + +pub trait Pattern { + type Value; +} + +pub struct Constrain<A, B = A, C = A>(A, B, C); + +impl<A, B, C> Pattern for Constrain<A, B, C> + where A: Pattern, + B: Pattern<Value = A::Value>, + C: Pattern<Value = A::Value>, +{ + type Value = A::Value; +} + +pub struct Wrapper<T>(T); + +impl<T> Pattern for Wrapper<T> { + type Value = T; +} + + +// @has self_referential/struct.WriteAndThen.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<P1> Send for WriteAndThen<P1> where <P1 as Pattern>::Value: Send" +pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value) + where P1: Pattern; diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs new file mode 100644 index 000000000..36e985144 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/static-region.rs @@ -0,0 +1,10 @@ +pub trait OwnedTrait<'a> { + type Reader; +} + +// @has static_region/struct.Owned.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send" +pub struct Owned<T> where T: OwnedTrait<'static> { + marker: <T as OwnedTrait<'static>>::Reader, +} diff --git a/src/test/rustdoc/tab_title.rs b/src/test/rustdoc/tab_title.rs new file mode 100644 index 000000000..0cc4f147e --- /dev/null +++ b/src/test/rustdoc/tab_title.rs @@ -0,0 +1,44 @@ +#![crate_name = "foo"] +#![feature(rustdoc_internals)] + +// tests for the html <title> element + +// @has foo/index.html '//head/title' 'foo - Rust' + +// @has foo/fn.widget_count.html '//head/title' 'widget_count in foo - Rust' +/// blah +pub fn widget_count() {} + +// @has foo/struct.Widget.html '//head/title' 'Widget in foo - Rust' +pub struct Widget; + +// @has foo/constant.ANSWER.html '//head/title' 'ANSWER in foo - Rust' +pub const ANSWER: u8 = 42; + +// @has foo/blah/index.html '//head/title' 'foo::blah - Rust' +pub mod blah { + // @has foo/blah/struct.Widget.html '//head/title' 'Widget in foo::blah - Rust' + pub struct Widget; + + // @has foo/blah/trait.Awesome.html '//head/title' 'Awesome in foo::blah - Rust' + pub trait Awesome {} + + // @has foo/blah/fn.make_widget.html '//head/title' 'make_widget in foo::blah - Rust' + pub fn make_widget() {} + + // @has foo/macro.cool_macro.html '//head/title' 'cool_macro in foo - Rust' + #[macro_export] + macro_rules! cool_macro { + ($t:tt) => { $t } + } +} + +// @has foo/keyword.continue.html '//head/title' 'continue - Rust' +#[doc(keyword = "continue")] +mod continue_keyword {} + +// @has foo/primitive.u8.html '//head/title' 'u8 - Rust' +// @!has - '//head/title' 'foo' +#[doc(primitive = "u8")] +/// `u8` docs +mod u8 {} diff --git a/src/test/rustdoc/table-in-docblock.rs b/src/test/rustdoc/table-in-docblock.rs new file mode 100644 index 000000000..858b58919 --- /dev/null +++ b/src/test/rustdoc/table-in-docblock.rs @@ -0,0 +1,16 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @count - '//*[@class="docblock"]/div/table' 2 +// @!has - '//*[@class="docblock"]/table' +/// | hello | hello2 | +/// | ----- | ------ | +/// | data | data2 | +pub struct Foo; + +impl Foo { + /// | hello | hello2 | + /// | ----- | ------ | + /// | data | data2 | + pub fn foo(&self) {} +} diff --git a/src/test/rustdoc/task-lists.rs b/src/test/rustdoc/task-lists.rs new file mode 100644 index 000000000..c2e7dd60f --- /dev/null +++ b/src/test/rustdoc/task-lists.rs @@ -0,0 +1,13 @@ +// ignore-tidy-linelength +// FIXME: this doesn't test as much as I'd like; ideally it would have these query too: + // has task_lists/index.html '//li/input[@type="checkbox" and disabled]/following-sibling::text()' 'a' + // has task_lists/index.html '//li/input[@type="checkbox"]/following-sibling::text()' 'b' +// Unfortunately that requires LXML, because the built-in xml module doesn't support all of xpath. + +// @has task_lists/index.html '//ul/li/input[@type="checkbox"]' '' +// @has task_lists/index.html '//ul/li/input[@disabled]' '' +// @has task_lists/index.html '//ul/li' 'a' +// @has task_lists/index.html '//ul/li' 'b' +//! This tests 'task list' support, a common markdown extension. +//! - [ ] a +//! - [x] b diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs new file mode 100644 index 000000000..6a510b9ac --- /dev/null +++ b/src/test/rustdoc/test-lists.rs @@ -0,0 +1,26 @@ +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - //ol/li "list" +// @has - //ol/li/ol/li "fooooo" +// @has - //ol/li/ol/li "x" +// @has - //ol/li "foo" +/// 1. list +/// 1. fooooo +/// 2. x +/// 2. foo +pub fn f() {} + +// @has foo/fn.foo2.html +// @has - //ul/li "normal list" +// @has - //ul/li/ul/li "sub list" +// @has - //ul/li/ul/li "new elem still same elem and again same elem!" +// @has - //ul/li "new big elem" +/// * normal list +/// * sub list +/// * new elem +/// still same elem +/// +/// and again same elem! +/// * new big elem +pub fn foo2() {} diff --git a/src/test/rustdoc/test-parens.rs b/src/test/rustdoc/test-parens.rs new file mode 100644 index 000000000..d9b9c7957 --- /dev/null +++ b/src/test/rustdoc/test-parens.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//*[@class="rust fn"]' "_: &(dyn ToString + 'static)" +pub fn foo(_: &(ToString + 'static)) {} diff --git a/src/test/rustdoc/test-strikethrough.rs b/src/test/rustdoc/test-strikethrough.rs new file mode 100644 index 000000000..c7855729a --- /dev/null +++ b/src/test/rustdoc/test-strikethrough.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - //del "Y" +/// ~~Y~~ +pub fn f() {} diff --git a/src/test/rustdoc/test_option_check/bar.rs b/src/test/rustdoc/test_option_check/bar.rs new file mode 100644 index 000000000..50a182cf7 --- /dev/null +++ b/src/test/rustdoc/test_option_check/bar.rs @@ -0,0 +1,9 @@ +// compile-flags: --test +// check-test-line-numbers-match + +/// This looks like another awesome test! +/// +/// ``` +/// println!("foo?"); +/// ``` +pub fn foooo() {} diff --git a/src/test/rustdoc/test_option_check/test.rs b/src/test/rustdoc/test_option_check/test.rs new file mode 100644 index 000000000..964e8e37e --- /dev/null +++ b/src/test/rustdoc/test_option_check/test.rs @@ -0,0 +1,18 @@ +// compile-flags: --test +// check-test-line-numbers-match + +pub mod bar; + +/// This is a Foo; +/// +/// ``` +/// println!("baaaaaar"); +/// ``` +pub struct Foo; + +/// This is a Bar; +/// +/// ``` +/// println!("fooooo"); +/// ``` +pub struct Bar; diff --git a/src/test/rustdoc/thread-local-src.rs b/src/test/rustdoc/thread-local-src.rs new file mode 100644 index 000000000..6de35e323 --- /dev/null +++ b/src/test/rustdoc/thread-local-src.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +// @has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'source' + +// @has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'source' +thread_local!(pub static FOO: bool = false); diff --git a/src/test/rustdoc/titles.rs b/src/test/rustdoc/titles.rs new file mode 100644 index 000000000..69e8b856b --- /dev/null +++ b/src/test/rustdoc/titles.rs @@ -0,0 +1,56 @@ +#![crate_name = "foo"] +#![feature(rustdoc_internals)] + +// @matches 'foo/index.html' '//h1' 'Crate foo' +// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo' + +// @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod' +// @matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod' +pub mod foo_mod { + pub struct __Thing {} +} + +extern "C" { + // @matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn' + pub fn foo_ffn(); +} + +// @matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn' +pub fn foo_fn() {} + +// @matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait' +// @matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait' +pub trait FooTrait {} + +// @matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct' +// @matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct' +pub struct FooStruct; + +// @matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum' +// @matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum' +pub enum FooEnum {} + +// @matches 'foo/type.FooType.html' '//h1' 'Type Definition foo::FooType' +// @matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType' +pub type FooType = FooStruct; + +// @matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro' +#[macro_export] +macro_rules! foo_macro { + () => {}; +} + +// @matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool' +#[doc(primitive = "bool")] +mod bool {} + +// @matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC' +pub static FOO_STATIC: FooStruct = FooStruct; + +extern "C" { + // @matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC' + pub static FOO_FSTATIC: FooStruct; +} + +// @matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT' +pub const FOO_CONSTANT: FooStruct = FooStruct; diff --git a/src/test/rustdoc/toggle-item-contents.rs b/src/test/rustdoc/toggle-item-contents.rs new file mode 100644 index 000000000..c1df4613e --- /dev/null +++ b/src/test/rustdoc/toggle-item-contents.rs @@ -0,0 +1,185 @@ +#![allow(unused)] + +// @has 'toggle_item_contents/struct.PubStruct.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +pub struct PubStruct { + pub a: usize, + pub b: usize, +} + +// @has 'toggle_item_contents/struct.BigPubStruct.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields' +pub struct BigPubStruct { + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize, + pub e: usize, + pub f: usize, + pub g: usize, + pub h: usize, + pub i: usize, + pub j: usize, + pub k: usize, + pub l: usize, + pub m: usize, +} + +// @has 'toggle_item_contents/union.BigUnion.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields' +pub union BigUnion { + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize, + pub e: usize, + pub f: usize, + pub g: usize, + pub h: usize, + pub i: usize, + pub j: usize, + pub k: usize, + pub l: usize, + pub m: usize, +} + +// @has 'toggle_item_contents/union.Union.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +pub union Union { + pub a: usize, + pub b: usize, + pub c: usize, +} + +// @has 'toggle_item_contents/struct.PrivStruct.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +// @has - '//div[@class="docblock item-decl"]' '/* private fields */' +pub struct PrivStruct { + a: usize, + b: usize, +} + +// @has 'toggle_item_contents/enum.Enum.html' +// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' +pub enum Enum { + A, B, C, + D { + a: u8, + b: u8 + } +} + +// @has 'toggle_item_contents/enum.EnumStructVariant.html' +// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' +pub enum EnumStructVariant { + A, B, C, + D { + a: u8, + } +} + +// @has 'toggle_item_contents/enum.LargeEnum.html' +// @count - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 variants' +pub enum LargeEnum { + A, B, C, D, E, F(u8), G, H, I, J, K, L, M +} + +// @has 'toggle_item_contents/trait.Trait.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 +pub trait Trait { + type A; + #[must_use] + fn foo(); + fn bar(); +} + +// @has 'toggle_item_contents/trait.GinormousTrait.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 16 associated items' +pub trait GinormousTrait { + type A; + type B; + type C; + type D; + type E; + type F; + type G; + type H; + type I; + type J; + type K; + type L; + type M; + const N: usize = 1; + #[must_use] + fn foo(); + fn bar(); +} + +// @has 'toggle_item_contents/trait.HugeTrait.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods' +pub trait HugeTrait { + type A; + const M: usize = 1; + const N: usize = 1; + const O: usize = 1; + const P: usize = 1; + const Q: usize = 1; + const R: usize = 1; + const S: usize = 1; + const T: usize = 1; + const U: usize = 1; + const V: usize = 1; + const W: usize = 1; + const X: usize = 1; + #[must_use] + fn foo(); + fn bar(); +} + +// @has 'toggle_item_contents/trait.GiganticTrait.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method' +pub trait GiganticTrait { + type A; + type B; + type C; + type D; + type E; + type F; + type G; + type H; + type I; + type J; + type K; + type L; + const M: usize = 1; + #[must_use] + fn foo(); +} + +// @has 'toggle_item_contents/trait.BigTrait.html' +// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 +// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 14 methods' +pub trait BigTrait { + type A; + #[must_use] + fn foo(); + fn bar(); + fn baz(); + fn quux(); + fn frob(); + fn greeble(); + fn blap(); + fn whoop(); + fn pow(); + fn bang(); + fn oomph(); + fn argh(); + fn wap(); + fn ouch(); +} diff --git a/src/test/rustdoc/toggle-method.rs b/src/test/rustdoc/toggle-method.rs new file mode 100644 index 000000000..1aa74e596 --- /dev/null +++ b/src/test/rustdoc/toggle-method.rs @@ -0,0 +1,18 @@ +#![crate_name = "foo"] + +// Struct methods with documentation should be wrapped in a <details> toggle with an appropriate +// summary. Struct methods with no documentation should not be wrapped. +// +// @has foo/struct.Foo.html +// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' +// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented' +// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' +pub struct Foo { +} + +impl Foo { + pub fn not_documented() {} + + /// is_documented is documented + pub fn is_documented() {} +} diff --git a/src/test/rustdoc/toggle-trait-fn.rs b/src/test/rustdoc/toggle-trait-fn.rs new file mode 100644 index 000000000..65e8daeb0 --- /dev/null +++ b/src/test/rustdoc/toggle-trait-fn.rs @@ -0,0 +1,23 @@ +#![crate_name = "foo"] + +// Trait methods with documentation should be wrapped in a <details> toggle with an appropriate +// summary. Trait methods with no documentation should not be wrapped. +// +// @has foo/trait.Foo.html +// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' +// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' +// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented' +// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()' +// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()' +// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented' +pub trait Foo { + fn not_documented(); + + /// is_documented is documented + fn is_documented(); + + fn not_documented_optional() {} + + /// is_documented_optional is documented + fn is_documented_optional() {} +} diff --git a/src/test/rustdoc/trait-alias-mention.rs b/src/test/rustdoc/trait-alias-mention.rs new file mode 100644 index 000000000..6da0dc687 --- /dev/null +++ b/src/test/rustdoc/trait-alias-mention.rs @@ -0,0 +1,10 @@ +// aux-build:trait-alias-mention.rs +// build-aux-docs + +#![crate_name = "foo"] + +extern crate trait_alias_mention; + +// @has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias' +pub fn mention_alias_in_bounds<T: trait_alias_mention::SomeAlias>() { +} diff --git a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs new file mode 100644 index 000000000..b5a97c610 --- /dev/null +++ b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs @@ -0,0 +1,65 @@ +pub trait MyTrait { + type Assoc; + const VALUE: u32 = 12; + fn trait_function(&self); + fn defaulted(&self) {} + fn defaulted_override(&self) {} +} + +impl MyTrait for String { + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-1"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1 + type Assoc = (); + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1 + const VALUE: u32 = 5; + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function + fn trait_function(&self) {} + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1 + fn defaulted_override(&self) {} +} + +impl MyTrait for Vec<u8> { + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-2"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2 + type Assoc = (); + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2 + const VALUE: u32 = 5; + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1 + fn trait_function(&self) {} + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2 + fn defaulted_override(&self) {} +} + +impl MyTrait for MyStruct { + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3 + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedtype.Assoc"]//a[@class="associatedtype"]/@href' trait.MyTrait.html#associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc + type Assoc = bool; + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3 + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE + const VALUE: u32 = 20; + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function + fn trait_function(&self) {} + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override + fn defaulted_override(&self) {} + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted +} + +pub struct MyStruct; + +// We check that associated items with default values aren't generated in the implementors list. +impl MyTrait for (u8, u8) { + // @!has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-4"]' + type Assoc = bool; + fn trait_function(&self) {} +} diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs new file mode 100644 index 000000000..4f7e2dfe3 --- /dev/null +++ b/src/test/rustdoc/trait-impl.rs @@ -0,0 +1,47 @@ +pub trait Trait { + /// Some long docs here. + /// + /// These docs are long enough that a link will be added to the end. + fn a(); + + /// These docs contain a [reference link]. + /// + /// [reference link]: https://example.com + fn b(); + + /// ``` + /// This code block should not be in the output, but a Read more link should be generated + /// ``` + fn c(); + + /// Escaped formatting a\*b\*c\* works + fn d(); +} + +pub struct Struct; + +impl Trait for Struct { + // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'Some long docs' + // @!has - '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'link will be added' + // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a' 'Read more' + // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.a' + fn a() {} + + // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p' 'These docs contain' + // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'reference link' + // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'https://example.com' + // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'Read more' + // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.b' + fn b() {} + + // @!has - '//*[@id="method.c"]/../../div[@class="docblock"]/p' 'code block' + // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a' 'Read more' + // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.c' + fn c() {} + + // @has - '//*[@id="method.d"]/../../div[@class="docblock"]/p' 'Escaped formatting a*b*c* works' + // @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em' + fn d() {} + + // @has - '//*[@id="impl-Trait-for-Struct"]/h3//a/@href' 'trait.Trait.html' +} diff --git a/src/test/rustdoc/trait-self-link.rs b/src/test/rustdoc/trait-self-link.rs new file mode 100644 index 000000000..e311dadff --- /dev/null +++ b/src/test/rustdoc/trait-self-link.rs @@ -0,0 +1,6 @@ +// @has trait_self_link/trait.Foo.html //a/@href trait.Foo.html +pub trait Foo {} + +pub struct Bar; + +impl Foo for Bar {} diff --git a/src/test/rustdoc/trait-src-link.rs b/src/test/rustdoc/trait-src-link.rs new file mode 100644 index 000000000..a6367efba --- /dev/null +++ b/src/test/rustdoc/trait-src-link.rs @@ -0,0 +1,26 @@ +#![crate_name = "quix"] +pub trait Foo { + // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'source' + fn required(); + + // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source' + fn provided() {} +} + +pub struct Bar; + +impl Foo for Bar { + // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'source' + fn required() {} + // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source' +} + +pub struct Baz; + +impl Foo for Baz { + // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'source' + fn required() {} + + // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'source' + fn provided() {} +} diff --git a/src/test/rustdoc/trait-visibility.rs b/src/test/rustdoc/trait-visibility.rs new file mode 100644 index 000000000..8ba3ee03a --- /dev/null +++ b/src/test/rustdoc/trait-visibility.rs @@ -0,0 +1,8 @@ +// aux-build:trait-visibility.rs + +#![crate_name = "foo"] + +extern crate trait_visibility; + +// @has foo/trait.Bar.html '//a[@href="#tymethod.foo"]/..' "fn foo()" +pub use trait_visibility::Bar; diff --git a/src/test/rustdoc/trait_alias.rs b/src/test/rustdoc/trait_alias.rs new file mode 100644 index 000000000..a0c657d9a --- /dev/null +++ b/src/test/rustdoc/trait_alias.rs @@ -0,0 +1,26 @@ +#![feature(trait_alias)] + +#![crate_name = "foo"] + +use std::fmt::Debug; + +// @has foo/all.html '//a[@href="traitalias.CopyAlias.html"]' 'CopyAlias' +// @has foo/all.html '//a[@href="traitalias.Alias2.html"]' 'Alias2' +// @has foo/all.html '//a[@href="traitalias.Foo.html"]' 'Foo' + +// @has foo/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases' +// @has foo/index.html '//a[@class="traitalias"]' 'CopyAlias' +// @has foo/index.html '//a[@class="traitalias"]' 'Alias2' +// @has foo/index.html '//a[@class="traitalias"]' 'Foo' + +// @has foo/traitalias.CopyAlias.html +// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait CopyAlias = Copy;' +pub trait CopyAlias = Copy; +// @has foo/traitalias.Alias2.html +// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait Alias2 = Copy + Debug;' +pub trait Alias2 = Copy + Debug; +// @has foo/traitalias.Foo.html +// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait Foo<T> = Into<T> + Debug;' +pub trait Foo<T> = Into<T> + Debug; +// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2' +pub fn bar<T>() where T: Alias2 {} diff --git a/src/test/rustdoc/traits-in-bodies-private.rs b/src/test/rustdoc/traits-in-bodies-private.rs new file mode 100644 index 000000000..96b7c4f9d --- /dev/null +++ b/src/test/rustdoc/traits-in-bodies-private.rs @@ -0,0 +1,13 @@ +// when implementing the fix for traits-in-bodies, there was an ICE when documenting private items +// and a trait was defined in non-module scope + +// compile-flags:--document-private-items + +// @has traits_in_bodies_private/struct.SomeStruct.html +// @!has - '//code' 'impl HiddenTrait for SomeStruct' +pub struct SomeStruct; + +fn __implementation_details() { + trait HiddenTrait {} + impl HiddenTrait for SomeStruct {} +} diff --git a/src/test/rustdoc/traits-in-bodies.rs b/src/test/rustdoc/traits-in-bodies.rs new file mode 100644 index 000000000..6d450a625 --- /dev/null +++ b/src/test/rustdoc/traits-in-bodies.rs @@ -0,0 +1,52 @@ +//prior to fixing `everybody_loops` to preserve items, rustdoc would crash on this file, as it +//didn't see that `SomeStruct` implemented `Clone` + +pub struct Bounded<T: Clone>(T); + +// @has traits_in_bodies/struct.SomeStruct.html +// @has - '//h3[@class="code-header in-band"]' 'impl Clone for SomeStruct' +pub struct SomeStruct; + +fn asdf() -> Bounded<SomeStruct> { + impl Clone for SomeStruct { + fn clone(&self) -> SomeStruct { + SomeStruct + } + } + + Bounded(SomeStruct) +} + +// @has traits_in_bodies/struct.Point.html +// @has - '//h3[@class="code-header in-band"]' 'impl Copy for Point' +#[derive(Clone)] +pub struct Point { + x: i32, + y: i32, +} + +const _FOO: () = { + impl Copy for Point {} + () +}; + +// @has traits_in_bodies/struct.Inception.html +// @has - '//h3[@class="code-header in-band"]' 'impl Clone for Inception' +pub struct Inception; + +static _BAR: usize = { + trait HiddenTrait { + fn hidden_fn(&self) { + for _ in 0..5 { + impl Clone for Inception { + fn clone(&self) -> Self { + // we need to go deeper + Inception + } + } + } + } + } + + 5 +}; diff --git a/src/test/rustdoc/tuple-struct-fields-doc.rs b/src/test/rustdoc/tuple-struct-fields-doc.rs new file mode 100644 index 000000000..31426131b --- /dev/null +++ b/src/test/rustdoc/tuple-struct-fields-doc.rs @@ -0,0 +1,50 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//h2[@id="fields"]' 'Tuple Fields' +// @has - '//h3[@class="sidebar-title"]/a[@href="#fields"]' 'Tuple Fields' +// @has - '//*[@id="structfield.0"]' '0: u32' +// @has - '//*[@id="main-content"]/div[@class="docblock"]' 'hello' +// @!has - '//*[@id="structfield.1"]' +// @has - '//*[@id="structfield.2"]' '2: char' +// @has - '//*[@id="structfield.3"]' '3: i8' +// @has - '//*[@id="main-content"]/div[@class="docblock"]' 'not hello' +pub struct Foo( + /// hello + pub u32, + char, + pub char, + /// not hello + pub i8, +); + +// @has foo/enum.Bar.html +// @has - '//pre[@class="rust enum"]' 'BarVariant(String),' +// @matches - '//*[@id="variant.BarVariant.fields"]/h4' '^Tuple Fields$' +// @has - '//*[@id="variant.BarVariant.field.0"]' '0: String' +// @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs' +// @matches - '//*[@id="variant.FooVariant.fields"]/h4' '^Fields$' +// @has - '//*[@id="variant.BazVariant.fields"]//*[@class="docblock"]' 'dox' +// @has - '//*[@id="variant.OtherVariant.fields"]//*[@class="docblock"]' 'dox' +// @!matches - '//*[@id="variant.QuuxVariant.fields"]/h4' '^Tuple Fields$' +pub enum Bar { + BarVariant( + /// Hello docs + String + ), + FooVariant { + /// hello + x: u32, + }, + BazVariant( + String, + /// dox + u32, + ), + OtherVariant( + /// dox + String, + u32, + ), + QuuxVariant(String), +} diff --git a/src/test/rustdoc/tuples.link1_i32.html b/src/test/rustdoc/tuples.link1_i32.html new file mode 100644 index 000000000..4efde28ed --- /dev/null +++ b/src/test/rustdoc/tuples.link1_i32.html @@ -0,0 +1 @@ +<code>pub fn tuple1(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)) -> (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)</code>
\ No newline at end of file diff --git a/src/test/rustdoc/tuples.link1_t.html b/src/test/rustdoc/tuples.link1_t.html new file mode 100644 index 000000000..1cbaec057 --- /dev/null +++ b/src/test/rustdoc/tuples.link1_t.html @@ -0,0 +1 @@ +<code>pub fn tuple1_t<T>(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a>) -> <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a></code>
\ No newline at end of file diff --git a/src/test/rustdoc/tuples.link2_i32.html b/src/test/rustdoc/tuples.link2_i32.html new file mode 100644 index 000000000..77c8d81b8 --- /dev/null +++ b/src/test/rustdoc/tuples.link2_i32.html @@ -0,0 +1 @@ +<code>pub fn tuple2(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)) -> (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)</code>
\ No newline at end of file diff --git a/src/test/rustdoc/tuples.link2_t.html b/src/test/rustdoc/tuples.link2_t.html new file mode 100644 index 000000000..2477aa6be --- /dev/null +++ b/src/test/rustdoc/tuples.link2_t.html @@ -0,0 +1 @@ +<code>pub fn tuple2_t<T>(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a>) -> <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a></code>
\ No newline at end of file diff --git a/src/test/rustdoc/tuples.link2_tu.html b/src/test/rustdoc/tuples.link2_tu.html new file mode 100644 index 000000000..b02f8dd8d --- /dev/null +++ b/src/test/rustdoc/tuples.link2_tu.html @@ -0,0 +1 @@ +<code>pub fn tuple2_tu<T, U>(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a>) -> <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a></code>
\ No newline at end of file diff --git a/src/test/rustdoc/tuples.link_unit.html b/src/test/rustdoc/tuples.link_unit.html new file mode 100644 index 000000000..839990e15 --- /dev/null +++ b/src/test/rustdoc/tuples.link_unit.html @@ -0,0 +1 @@ +<code>pub fn tuple0(x: <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>)</code>
\ No newline at end of file diff --git a/src/test/rustdoc/tuples.rs b/src/test/rustdoc/tuples.rs new file mode 100644 index 000000000..62e2f9e7e --- /dev/null +++ b/src/test/rustdoc/tuples.rs @@ -0,0 +1,20 @@ +#![crate_name = "foo"] + +// @has foo/fn.tuple0.html //pre 'pub fn tuple0(x: ())' +// @snapshot link_unit - '//pre[@class="rust fn"]/code' +pub fn tuple0(x: ()) -> () { x } +// @has foo/fn.tuple1.html //pre 'pub fn tuple1(x: (i32,)) -> (i32,)' +// @snapshot link1_i32 - '//pre[@class="rust fn"]/code' +pub fn tuple1(x: (i32,)) -> (i32,) { x } +// @has foo/fn.tuple2.html //pre 'pub fn tuple2(x: (i32, i32)) -> (i32, i32)' +// @snapshot link2_i32 - '//pre[@class="rust fn"]/code' +pub fn tuple2(x: (i32, i32)) -> (i32, i32) { x } +// @has foo/fn.tuple1_t.html //pre 'pub fn tuple1_t<T>(x: (T,)) -> (T,)' +// @snapshot link1_t - '//pre[@class="rust fn"]/code' +pub fn tuple1_t<T>(x: (T,)) -> (T,) { x } +// @has foo/fn.tuple2_t.html //pre 'pub fn tuple2_t<T>(x: (T, T)) -> (T, T)' +// @snapshot link2_t - '//pre[@class="rust fn"]/code' +pub fn tuple2_t<T>(x: (T, T)) -> (T, T) { x } +// @has foo/fn.tuple2_tu.html //pre 'pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U)' +// @snapshot link2_tu - '//pre[@class="rust fn"]/code' +pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U) { x } diff --git a/src/test/rustdoc/type-layout-flag-required.rs b/src/test/rustdoc/type-layout-flag-required.rs new file mode 100644 index 000000000..a01fbd229 --- /dev/null +++ b/src/test/rustdoc/type-layout-flag-required.rs @@ -0,0 +1,4 @@ +// Tests that `--show-type-layout` is required in order to show layout info. + +// @!has type_layout_flag_required/struct.Foo.html 'Size: ' +pub struct Foo(usize); diff --git a/src/test/rustdoc/type-layout.rs b/src/test/rustdoc/type-layout.rs new file mode 100644 index 000000000..e5c6e9dc3 --- /dev/null +++ b/src/test/rustdoc/type-layout.rs @@ -0,0 +1,85 @@ +// compile-flags: --show-type-layout -Z unstable-options + +// @has type_layout/struct.Foo.html 'Size: ' +// @has - ' bytes' +// @has - '//*[@id="layout"]/a[@href="#layout"]' '' +pub struct Foo { + pub a: usize, + b: Vec<String>, +} + +// @has type_layout/enum.Bar.html 'Size: ' +// @has - ' bytes' +pub enum Bar<'a> { + A(String), + B(&'a str, (std::collections::HashMap<String, usize>, Foo)), +} + +// @has type_layout/union.Baz.html 'Size: ' +// @has - ' bytes' +pub union Baz { + a: &'static str, + b: usize, + c: &'static [u8], +} + +// @has type_layout/struct.X.html 'Size: ' +// @has - ' bytes' +pub struct X(usize); + +// @has type_layout/struct.Y.html 'Size: ' +// @has - '1 byte' +// @!has - ' bytes' +pub struct Y(u8); + +// @has type_layout/struct.Z.html 'Size: ' +// @has - '0 bytes' +pub struct Z; + +// We can't compute layout for generic types. +// @has type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters' +// @!has - 'Size: ' +pub struct Generic<T>(T); + +// We *can*, however, compute layout for types that are only generic over lifetimes, +// because lifetimes are a type-system construct. +// @has type_layout/struct.GenericLifetimes.html 'Size: ' +// @has - ' bytes' +pub struct GenericLifetimes<'a>(&'a str); + +// @has type_layout/struct.Unsized.html 'Size: ' +// @has - '(unsized)' +pub struct Unsized([u8]); + +// @has type_layout/type.TypeAlias.html 'Size: ' +// @has - ' bytes' +pub type TypeAlias = X; + +// @has type_layout/type.GenericTypeAlias.html 'Size: ' +// @has - '8 bytes' +pub type GenericTypeAlias = (Generic<(u32, ())>, Generic<u32>); + +// Regression test for the rustdoc equivalent of #85103. +// @has type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.' +pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>; + +// @!has type_layout/trait.MyTrait.html 'Size: ' +pub trait MyTrait {} + +// @has type_layout/enum.Variants.html 'Size: ' +// @has - '2 bytes' +// @has - '<code>A</code>: 0 bytes' +// @has - '<code>B</code>: 1 byte' +pub enum Variants { + A, + B(u8), +} + +// @has type_layout/enum.WithNiche.html 'Size: ' +// @has - //p '4 bytes' +// @has - '<code>None</code>: 0 bytes' +// @has - '<code>Some</code>: 4 bytes' +pub enum WithNiche { + None, + Some(std::num::NonZeroU32), +} diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs new file mode 100644 index 000000000..4ecd62cde --- /dev/null +++ b/src/test/rustdoc/typedef.rs @@ -0,0 +1,25 @@ +pub trait MyTrait { + fn method_on_mytrait() {} +} + +pub struct MyStruct; + +impl MyStruct { + pub fn method_on_mystruct() {} +} + +// @has typedef/type.MyAlias.html +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyAlias' +// @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyTrait for MyAlias' +// @has - 'Alias docstring' +// @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias' +// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods' +// @has - '//*[@class="sidebar"]//a[@href="#trait-implementations"]' 'Trait Implementations' +/// Alias docstring +pub type MyAlias = MyStruct; + +impl MyAlias { + pub fn method_on_myalias() {} +} + +impl MyTrait for MyAlias {} diff --git a/src/test/rustdoc/unindent.md b/src/test/rustdoc/unindent.md new file mode 100644 index 000000000..8e4e7a25a --- /dev/null +++ b/src/test/rustdoc/unindent.md @@ -0,0 +1 @@ +Just some text. diff --git a/src/test/rustdoc/unindent.rs b/src/test/rustdoc/unindent.rs new file mode 100644 index 000000000..372af5f46 --- /dev/null +++ b/src/test/rustdoc/unindent.rs @@ -0,0 +1,62 @@ +#![crate_name = "foo"] + +// @has foo/struct.Example.html +// @matches - '//pre[@class="rust rust-example-rendered"]' \ +// '(?m)let example = Example::new\(\)\n \.first\(\)\n \.second\(\)\n \.build\(\);\Z' +/// ```rust +/// let example = Example::new() +/// .first() +#[cfg_attr(not(feature = "one"), doc = " .second()")] +/// .build(); +/// ``` +pub struct Example; + +// @has foo/struct.F.html +// @matches - '//pre[@class="rust rust-example-rendered"]' \ +// '(?m)let example = Example::new\(\)\n \.first\(\)\n \.another\(\)\n \.build\(\);\Z' +///```rust +///let example = Example::new() +/// .first() +#[cfg_attr(not(feature = "one"), doc = " .another()")] +/// .build(); +/// ``` +pub struct F; + +// @has foo/struct.G.html +// @matches - '//pre[@class="rust rust-example-rendered"]' \ +// '(?m)let example = Example::new\(\)\n\.first\(\)\n \.another\(\)\n\.build\(\);\Z' +///```rust +///let example = Example::new() +///.first() +#[cfg_attr(not(feature = "one"), doc = " .another()")] +///.build(); +///``` +pub struct G; + +// @has foo/struct.H.html +// @has - '//div[@class="docblock"]/p' 'no whitespace lol' +///no whitespace +#[doc = " lol"] +pub struct H; + +// @has foo/struct.I.html +// @matches - '//pre[@class="rust rust-example-rendered"]' '(?m)4 whitespaces!\Z' +/// 4 whitespaces! +#[doc = "something"] +pub struct I; + +// @has foo/struct.J.html +// @matches - '//div[@class="docblock"]/p' '(?m)a\nno whitespace\nJust some text.\Z' +///a +///no whitespace +#[doc = include_str!("unindent.md")] +pub struct J; + +// @has foo/struct.K.html +// @matches - '//pre[@class="rust rust-example-rendered"]' '(?m)4 whitespaces!\Z' +///a +/// +/// 4 whitespaces! +/// +#[doc = include_str!("unindent.md")] +pub struct K; diff --git a/src/test/rustdoc/union.rs b/src/test/rustdoc/union.rs new file mode 100644 index 000000000..5a788eb1b --- /dev/null +++ b/src/test/rustdoc/union.rs @@ -0,0 +1,8 @@ +// @has union/union.U.html +pub union U { + // @has - //pre "pub a: u8" + pub a: u8, + // @has - //pre "/* private fields */" + // @!has - //pre "b: u16" + b: u16, +} diff --git a/src/test/rustdoc/unit-return.rs b/src/test/rustdoc/unit-return.rs new file mode 100644 index 000000000..ae3a60315 --- /dev/null +++ b/src/test/rustdoc/unit-return.rs @@ -0,0 +1,17 @@ +// aux-build:unit-return.rs + +#![crate_name = "foo"] + +extern crate unit_return; + +// @has 'foo/fn.f0.html' '//*[@class="rust fn"]' 'F: FnMut(u8) + Clone' +pub fn f0<F: FnMut(u8) + Clone>(f: F) {} + +// @has 'foo/fn.f1.html' '//*[@class="rust fn"]' 'F: FnMut(u16) + Clone' +pub fn f1<F: FnMut(u16) -> () + Clone>(f: F) {} + +// @has 'foo/fn.f2.html' '//*[@class="rust fn"]' 'F: FnMut(u32) + Clone' +pub use unit_return::f2; + +// @has 'foo/fn.f3.html' '//*[@class="rust fn"]' 'F: FnMut(u64) + Clone' +pub use unit_return::f3; diff --git a/src/test/rustdoc/universal-impl-trait.rs b/src/test/rustdoc/universal-impl-trait.rs new file mode 100644 index 000000000..b10b1b865 --- /dev/null +++ b/src/test/rustdoc/universal-impl-trait.rs @@ -0,0 +1,55 @@ +#![crate_name = "foo"] + +use std::io::Read; +use std::borrow::Borrow; + +// @has foo/fn.foo.html +// @has - //pre 'foo(' +// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Clone\.html"' +// @matches - '_z: .+impl.+trait\.Copy\.html.+, impl.+trait\.Clone\.html' +pub fn foo(_x: impl Clone, _y: i32, _z: (impl Copy, impl Clone)) { +} + +pub trait Trait { + // @has foo/trait.Trait.html + // @has - 'method</a>(' + // @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"' + fn method(&self, _x: impl std::fmt::Debug) { + } +} + +pub struct S<T>(T); + +impl<T> S<T> { + // @has foo/struct.S.html + // @has - 'bar</a>(' + // @matches - '_bar: impl <a class="trait" href="[^"]+/trait\.Copy\.html"' + pub fn bar(_bar: impl Copy) { + } + + // @has - 'baz</a>(' + // @matches - '_baz:.+struct\.S\.html.+impl .+trait\.Clone\.html' + pub fn baz(_baz: S<impl Clone>) { + } + + // @has - 'qux</a>(' + // @matches - 'trait\.Read\.html' + pub fn qux(_qux: impl IntoIterator<Item = S<impl Read>>) { + } +} + +// @has - 'method</a>(' +// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"' +impl<T> Trait for S<T> {} + +// @has foo/fn.much_universe.html +// @matches - 'T:.+Borrow.+impl .+trait\.Trait\.html' +// @matches - 'U:.+IntoIterator.+= impl.+Iterator\.html.+= impl.+Clone\.html' +// @matches - '_: impl .+trait\.Read\.html.+ \+ .+trait\.Clone\.html' +pub fn much_universe< + T: Borrow<impl Trait>, + U: IntoIterator<Item = impl Iterator<Item = impl Clone>>, +>( + _: impl Read + Clone, +) { +} diff --git a/src/test/rustdoc/unneeded-trait-implementations-title.rs b/src/test/rustdoc/unneeded-trait-implementations-title.rs new file mode 100644 index 000000000..e1bcfd3b9 --- /dev/null +++ b/src/test/rustdoc/unneeded-trait-implementations-title.rs @@ -0,0 +1,5 @@ +#![crate_name = "foo"] + +pub struct Bar; + +// @count foo/struct.Bar.html '//*[@id="implementations"]' 0 diff --git a/src/test/rustdoc/use-attr.rs b/src/test/rustdoc/use-attr.rs new file mode 100644 index 000000000..996b7bba6 --- /dev/null +++ b/src/test/rustdoc/use-attr.rs @@ -0,0 +1,8 @@ +// edition:2018 + +// ICE when rustdoc encountered a use statement of a non-macro attribute (see #58054) + +// @has use_attr/index.html +// @has - '//code' 'pub use proc_macro_attribute' +pub use proc_macro_attribute; +use proc_macro_derive; diff --git a/src/test/rustdoc/useless_lifetime_bound.rs b/src/test/rustdoc/useless_lifetime_bound.rs new file mode 100644 index 000000000..f530d8a65 --- /dev/null +++ b/src/test/rustdoc/useless_lifetime_bound.rs @@ -0,0 +1,13 @@ +use std::marker::PhantomData; + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "'env: 'env" +pub struct Scope<'env> { + _marker: PhantomData<&'env mut &'env ()>, +} + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "T: 'a + 'a" +pub struct SomeStruct<'a, T: 'a> { + _marker: PhantomData<&'a T>, +} diff --git a/src/test/rustdoc/variadic.rs b/src/test/rustdoc/variadic.rs new file mode 100644 index 000000000..bd8f1775b --- /dev/null +++ b/src/test/rustdoc/variadic.rs @@ -0,0 +1,4 @@ +extern "C" { + // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, ...)' + pub fn foo(x: i32, ...); +} diff --git a/src/test/rustdoc/version-separator-without-source.rs b/src/test/rustdoc/version-separator-without-source.rs new file mode 100644 index 000000000..ae866deba --- /dev/null +++ b/src/test/rustdoc/version-separator-without-source.rs @@ -0,0 +1,23 @@ +#![doc(html_no_source)] +#![feature(staged_api)] +#![stable(feature = "bar", since = "1.0")] +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "bar", since = "1.0")] +pub fn foo() {} + +// @has foo/struct.Bar.html +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +#[stable(feature = "bar", since = "1.0")] +pub struct Bar; + +impl Bar { + // @has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0' + // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·' + #[stable(feature = "foobar", since = "2.0")] + pub fn bar() {} +} diff --git a/src/test/rustdoc/viewpath-rename.rs b/src/test/rustdoc/viewpath-rename.rs new file mode 100644 index 000000000..546127637 --- /dev/null +++ b/src/test/rustdoc/viewpath-rename.rs @@ -0,0 +1,21 @@ +#![crate_name = "foo"] + +pub mod io { + pub trait Reader { fn dummy(&self) { } } +} + +pub enum Maybe<A> { + Just(A), + Nothing +} + +// @has foo/prelude/index.html +pub mod prelude { + // @has foo/prelude/index.html '//code' 'pub use io as FooIo;' + // @has foo/prelude/index.html '//code' 'pub use io::Reader as FooReader;' + #[doc(no_inline)] pub use io::{self as FooIo, Reader as FooReader}; + // @has foo/prelude/index.html '//code' 'pub use Maybe;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Just as MaybeJust;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Nothing;' + #[doc(no_inline)] pub use Maybe::{self, Just as MaybeJust, Nothing}; +} diff --git a/src/test/rustdoc/viewpath-self.rs b/src/test/rustdoc/viewpath-self.rs new file mode 100644 index 000000000..a6b659295 --- /dev/null +++ b/src/test/rustdoc/viewpath-self.rs @@ -0,0 +1,21 @@ +#![crate_name = "foo"] + +pub mod io { + pub trait Reader { fn dummy(&self) { } } +} + +pub enum Maybe<A> { + Just(A), + Nothing +} + +// @has foo/prelude/index.html +pub mod prelude { + // @has foo/prelude/index.html '//code' 'pub use io;' + // @has foo/prelude/index.html '//code' 'pub use io::Reader;' + #[doc(no_inline)] pub use io::{self, Reader}; + // @has foo/prelude/index.html '//code' 'pub use Maybe;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Just;' + // @has foo/prelude/index.html '//code' 'pub use Maybe::Nothing;' + #[doc(no_inline)] pub use Maybe::{self, Just, Nothing}; +} diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs new file mode 100644 index 000000000..4099b54f0 --- /dev/null +++ b/src/test/rustdoc/visibility.rs @@ -0,0 +1,105 @@ +// compile-flags: --document-private-items + +#![crate_name = "foo"] + +// @!has 'foo/index.html' '//a[@href="struct.FooPublic.html"]/..' 'FooPublic 🔒' +// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic' +pub struct FooPublic; +// @has 'foo/index.html' '//a[@href="struct.FooJustCrate.html"]/..' 'FooJustCrate 🔒' +// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate' +pub(crate) struct FooJustCrate; +// @has 'foo/index.html' '//a[@href="struct.FooPubCrate.html"]/..' 'FooPubCrate 🔒' +// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate' +pub(crate) struct FooPubCrate; +// @has 'foo/index.html' '//a[@href="struct.FooSelf.html"]/..' 'FooSelf 🔒' +// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf' +pub(self) struct FooSelf; +// @has 'foo/index.html' '//a[@href="struct.FooInSelf.html"]/..' 'FooInSelf 🔒' +// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf' +pub(in self) struct FooInSelf; +// @has 'foo/index.html' '//a[@href="struct.FooPriv.html"]/..' 'FooPriv 🔒' +// @has 'foo/struct.FooPriv.html' '//pre' 'pub(crate) struct FooPriv' +struct FooPriv; + +// @!has 'foo/index.html' '//a[@href="pub_mod/index.html"]/..' 'pub_mod 🔒' +pub mod pub_mod {} + +// @has 'foo/index.html' '//a[@href="pub_crate_mod/index.html"]/..' 'pub_crate_mod 🔒' +pub(crate) mod pub_crate_mod {} + +// @has 'foo/index.html' '//a[@href="a/index.html"]/..' 'a 🔒' +mod a { + // @has 'foo/a/index.html' '//a[@href="struct.FooASuper.html"]/..' 'FooASuper 🔒' + // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper' + pub(super) struct FooASuper; + // @has 'foo/a/index.html' '//a[@href="struct.FooAInSuper.html"]/..' 'FooAInSuper 🔒' + // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper' + pub(in super) struct FooAInSuper; + // @has 'foo/a/index.html' '//a[@href="struct.FooAInA.html"]/..' 'FooAInA 🔒' + // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA' + // @!has 'foo/a/struct.FooAInA.html' '//pre' 'pub' + pub(in a) struct FooAInA; + // @has 'foo/a/index.html' '//a[@href="struct.FooAPriv.html"]/..' 'FooAPriv 🔒' + // @has 'foo/a/struct.FooAPriv.html' '//pre' 'struct FooAPriv' + // @!has 'foo/a/struct.FooAPriv.html' '//pre' 'pub' + struct FooAPriv; + + // @has 'foo/a/index.html' '//a[@href="b/index.html"]/..' 'b 🔒' + mod b { + // @has 'foo/a/b/index.html' '//a[@href="struct.FooBSuper.html"]/..' 'FooBSuper 🔒' + // @has 'foo/a/b/struct.FooBSuper.html' '//pre' 'pub(super) struct FooBSuper' + pub(super) struct FooBSuper; + // @has 'foo/a/b/index.html' '//a[@href="struct.FooBInSuperSuper.html"]/..' 'FooBInSuperSuper 🔒' + // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper' + pub(in super::super) struct FooBInSuperSuper; + // @has 'foo/a/b/index.html' '//a[@href="struct.FooBInAB.html"]/..' 'FooBInAB 🔒' + // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB' + // @!has 'foo/a/b/struct.FooBInAB.html' '//pre' 'pub' + pub(in a::b) struct FooBInAB; + // @has 'foo/a/b/index.html' '//a[@href="struct.FooBPriv.html"]/..' 'FooBPriv 🔒' + // @has 'foo/a/b/struct.FooBPriv.html' '//pre' 'struct FooBPriv' + // @!has 'foo/a/b/struct.FooBPriv.html' '//pre' 'pub' + struct FooBPriv; + + // @!has 'foo/a/b/index.html' '//a[@href="struct.FooBPub.html"]/..' 'FooBPub 🔒' + // @has 'foo/a/b/struct.FooBPub.html' '//pre' 'pub struct FooBPub' + pub struct FooBPub; + } +} + +// @has 'foo/trait.PubTrait.html' '//pre' 'pub trait PubTrait' +// +// @has 'foo/trait.PubTrait.html' '//pre' 'type Type;' +// @!has 'foo/trait.PubTrait.html' '//pre' 'pub type Type;' +// +// @has 'foo/trait.PubTrait.html' '//pre' 'const CONST: usize;' +// @!has 'foo/trait.PubTrait.html' '//pre' 'pub const CONST: usize;' +// +// @has 'foo/trait.PubTrait.html' '//pre' 'fn function();' +// @!has 'foo/trait.PubTrait.html' '//pre' 'pub fn function();' +// +// @!has 'foo/index.html' '//a[@href="trait.PubTrait.html"]/..' 'PubTrait 🔒' + +pub trait PubTrait { + type Type; + const CONST: usize; + fn function(); +} + +// @has 'foo/index.html' '//a[@href="trait.PrivTrait.html"]/..' 'PrivTrait 🔒' +trait PrivTrait {} + +// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'type Type' +// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub type Type' +// +// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'const CONST: usize' +// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub const CONST: usize' +// +// @has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'fn function()' +// @!has 'foo/struct.FooPublic.html' '//h4[@class="code-header"]' 'pub fn function()' + +impl PubTrait for FooPublic { + type Type = usize; + const CONST: usize = 0; + fn function() {} +} diff --git a/src/test/rustdoc/where-clause-order.rs b/src/test/rustdoc/where-clause-order.rs new file mode 100644 index 000000000..3150a8ea0 --- /dev/null +++ b/src/test/rustdoc/where-clause-order.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] + +pub trait SomeTrait<Rhs = Self> +where + Rhs: ?Sized, +{ +} + +// @has 'foo/trait.SomeTrait.html' +// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, " +impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) +where + A: PartialOrd<A> + PartialEq<A>, + B: PartialOrd<B> + PartialEq<B>, + C: PartialOrd<C> + PartialEq<C>, + D: PartialOrd<D> + PartialEq<D>, + E: PartialOrd<E> + PartialEq<E> + ?Sized, +{ +} diff --git a/src/test/rustdoc/where-sized.rs b/src/test/rustdoc/where-sized.rs new file mode 100644 index 000000000..fe7cad8c3 --- /dev/null +++ b/src/test/rustdoc/where-sized.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +// @has foo/fn.foo.html +// @has - '//*[@class="rust fn"]' 'pub fn foo<X, Y: ?Sized>(_: &X)' +// @has - '//*[@class="rust fn"]' 'where X: ?Sized,' +pub fn foo<X, Y: ?Sized>(_: &X) where X: ?Sized {} diff --git a/src/test/rustdoc/where.SWhere_Simd_item-decl.html b/src/test/rustdoc/where.SWhere_Simd_item-decl.html new file mode 100644 index 000000000..0133bcaeb --- /dev/null +++ b/src/test/rustdoc/where.SWhere_Simd_item-decl.html @@ -0,0 +1 @@ +<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Simd<T>(_) <br /><span class="where">where<br />    T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file diff --git a/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html new file mode 100644 index 000000000..54026ff03 --- /dev/null +++ b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html @@ -0,0 +1,3 @@ +<div class="docblock item-decl"><pre class="rust trait"><code>pub trait TraitWhere { + type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a><br />    <span class="where">where<br />        Self: 'a</span>; +}</code></pre></div>
\ No newline at end of file diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs new file mode 100644 index 000000000..50a5722fb --- /dev/null +++ b/src/test/rustdoc/where.rs @@ -0,0 +1,51 @@ +#![feature(generic_associated_types)] +#![crate_name = "foo"] + +pub trait MyTrait { fn dummy(&self) { } } + +// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait" +pub struct Alpha<A>(A) where A: MyTrait; +// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B> where B: MyTrait" +pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); } +// @has foo/fn.charlie.html '//pre' "pub fn charlie<C>() where C: MyTrait" +pub fn charlie<C>() where C: MyTrait {} + +pub struct Delta<D>(D); + +// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<D> Delta<D> where D: MyTrait" +impl<D> Delta<D> where D: MyTrait { + pub fn delta() {} +} + +pub struct Echo<E>(E); + +// @has 'foo/struct.Simd.html' +// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]' +pub struct Simd<T>([T; 1]) +where + T: MyTrait; + +// @has 'foo/trait.TraitWhere.html' +// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]' +pub trait TraitWhere { + type Item<'a> where Self: 'a; +} + +// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<E> MyTrait for Echo<E> where E: MyTrait" +// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \ +// "impl<E> MyTrait for Echo<E> where E: MyTrait" +impl<E> MyTrait for Echo<E> where E: MyTrait {} + +pub enum Foxtrot<F> { Foxtrot1(F) } + +// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ +// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait" +// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \ +// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait" +impl<F> MyTrait for Foxtrot<F> where F: MyTrait {} + +// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \ +// "type Golf<T> where T: Clone, = (T, T)" +pub type Golf<T> where T: Clone = (T, T); diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum.html b/src/test/rustdoc/whitespace-after-where-clause.enum.html new file mode 100644 index 000000000..9e5bf45ae --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.enum.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a> <span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>, </span>{ + Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B), + Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>), +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum2.html b/src/test/rustdoc/whitespace-after-where-clause.enum2.html new file mode 100644 index 000000000..6bc47beae --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.enum2.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { + Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B), + Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>), +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.rs b/src/test/rustdoc/whitespace-after-where-clause.rs new file mode 100644 index 000000000..c36386a2a --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.rs @@ -0,0 +1,77 @@ +// This test ensures there is no whitespace before the first brace of +// trait, enum, struct and union items when they have a where clause. + +#![crate_name = "foo"] + +// @has 'foo/trait.ToOwned.html' +// @snapshot trait - '//*[@class="docblock item-decl"]' +pub trait ToOwned<T> +where T: Clone +{ + type Owned; + fn to_owned(&self) -> Self::Owned; + fn whatever(&self) -> T; +} + +// @has 'foo/trait.ToOwned2.html' +// @snapshot trait2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub trait ToOwned2<T: Clone> { + type Owned; + fn to_owned(&self) -> Self::Owned; + fn whatever(&self) -> T; +} + +// @has 'foo/enum.Cow.html' +// @snapshot enum - '//*[@class="docblock item-decl"]' +pub enum Cow<'a, B: ?Sized + 'a> +where + B: ToOwned<Clone>, +{ + Borrowed(&'a B), + Whatever(u32), +} + +// @has 'foo/enum.Cow2.html' +// @snapshot enum2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub enum Cow2<'a, B: ?Sized + ToOwned<Clone> + 'a> { + Borrowed(&'a B), + Whatever(u32), +} + +// @has 'foo/struct.Struct.html' +// @snapshot struct - '//*[@class="docblock item-decl"]' +pub struct Struct<'a, B: ?Sized + 'a> +where + B: ToOwned<Clone>, +{ + pub a: &'a B, + pub b: u32, +} + +// @has 'foo/struct.Struct2.html' +// @snapshot struct2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub struct Struct2<'a, B: ?Sized + ToOwned<Clone> + 'a> { + pub a: &'a B, + pub b: u32, +} + +// @has 'foo/union.Union.html' +// @snapshot union - '//*[@class="docblock item-decl"]' +pub union Union<'a, B: ?Sized + 'a> +where + B: ToOwned<Clone>, +{ + a: &'a B, + b: u32, +} + +// @has 'foo/union.Union2.html' +// @snapshot union2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub union Union2<'a, B: ?Sized + ToOwned<Clone> + 'a> { + a: &'a B, + b: u32, +} diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct.html b/src/test/rustdoc/whitespace-after-where-clause.struct.html new file mode 100644 index 000000000..236cc3b30 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.struct.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a> <span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>, </span>{ + pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B, + pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>, +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct2.html b/src/test/rustdoc/whitespace-after-where-clause.struct2.html new file mode 100644 index 000000000..47f5c6ba9 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.struct2.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { + pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B, + pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>, +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait.html b/src/test/rustdoc/whitespace-after-where-clause.trait.html new file mode 100644 index 000000000..98f03b837 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.trait.html @@ -0,0 +1,6 @@ +<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned<T> <span class="where fmt-newline">where<br />    T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>, </span>{ + type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>; + + fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&self) -> Self::<a class="associatedtype" href="trait.ToOwned.html#associatedtype.Owned" title="type foo::ToOwned::Owned">Owned</a>; +<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&self) -> T; +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait2.html b/src/test/rustdoc/whitespace-after-where-clause.trait2.html new file mode 100644 index 000000000..35052869e --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.trait2.html @@ -0,0 +1,6 @@ +<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned2<T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> { + type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>; + + fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&self) -> Self::<a class="associatedtype" href="trait.ToOwned2.html#associatedtype.Owned" title="type foo::ToOwned2::Owned">Owned</a>; +<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&self) -> T; +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.union.html b/src/test/rustdoc/whitespace-after-where-clause.union.html new file mode 100644 index 000000000..97e1bbcf3 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.union.html @@ -0,0 +1,3 @@ +<div class="docblock item-decl"><pre class="rust union"><code>pub union Union<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a> <span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>, </span>{ + /* private fields */ +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.union2.html b/src/test/rustdoc/whitespace-after-where-clause.union2.html new file mode 100644 index 000000000..6c752a8b4 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.union2.html @@ -0,0 +1,3 @@ +<div class="docblock item-decl"><pre class="rust union"><code>pub union Union2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { + /* private fields */ +}</code></pre></div> diff --git a/src/test/rustdoc/without-redirect.rs b/src/test/rustdoc/without-redirect.rs new file mode 100644 index 000000000..a076f8a3c --- /dev/null +++ b/src/test/rustdoc/without-redirect.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] + +// @has foo/macro.bar.html +// @has foo/macro.bar!.html +// @!has foo/bar.m.html +#[macro_export] +macro_rules! bar { + () => {} +} + +// @has foo/struct.Bar.html +// @!has foo/Bar.t.html +pub struct Bar; diff --git a/src/test/rustdoc/wrapping.rs b/src/test/rustdoc/wrapping.rs new file mode 100644 index 000000000..8d8221bcd --- /dev/null +++ b/src/test/rustdoc/wrapping.rs @@ -0,0 +1,5 @@ +use std::fmt::Debug; + +// @has 'wrapping/fn.foo.html' '//pre[@class="rust fn"]' 'pub fn foo() -> impl Debug' +// @count - '//pre[@class="rust fn"]/br' 0 +pub fn foo() -> impl Debug {} |