Skip to content

Commit ec5b882

Browse files
committed
Auto merge of rust-lang#114414 - cjgillot:early-unnameable-test, r=petrochenkov
Make test harness lint about unnnameable tests. Implementation of rust-lang#113734 (comment) About the options suggested in rust-lang#36629 (comment): adding this case to unused_attribute was just more complicated. I'll try to understand a bit more what you had in mind in rust-lang/rfcs#2471 (comment) This was just simpler to do in a standalone PR. I'll remove the corresponding changes from rust-lang#113734 later. r? `@petrochenkov`
2 parents 4f7bb98 + 2a0a1f9 commit ec5b882

File tree

7 files changed

+65
-85
lines changed

7 files changed

+65
-85
lines changed

compiler/rustc_builtin_macros/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,5 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
227227
.label = not a trait
228228
.str_lit = try using `#[derive({$sym})]`
229229
.other = for example, write `#[derive(Debug)]` for `Debug`
230+
231+
builtin_macros_unnameable_test_items = cannot test inner items

compiler/rustc_builtin_macros/src/test_harness.rs

+22
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ use rustc_ast as ast;
44
use rustc_ast::entry::EntryPointType;
55
use rustc_ast::mut_visit::{ExpectOne, *};
66
use rustc_ast::ptr::P;
7+
use rustc_ast::visit::{walk_item, Visitor};
78
use rustc_ast::{attr, ModKind};
89
use rustc_expand::base::{ExtCtxt, ResolverExpand};
910
use rustc_expand::expand::{AstFragment, ExpansionConfig};
1011
use rustc_feature::Features;
12+
use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
1113
use rustc_session::Session;
1214
use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
1315
use rustc_span::symbol::{sym, Ident, Symbol};
@@ -137,11 +139,31 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
137139
let prev_tests = mem::take(&mut self.tests);
138140
noop_visit_item_kind(&mut item.kind, self);
139141
self.add_test_cases(item.id, span, prev_tests);
142+
} else {
143+
// But in those cases, we emit a lint to warn the user of these missing tests.
144+
walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
140145
}
141146
smallvec![P(item)]
142147
}
143148
}
144149

150+
struct InnerItemLinter<'a> {
151+
sess: &'a Session,
152+
}
153+
154+
impl<'a> Visitor<'a> for InnerItemLinter<'_> {
155+
fn visit_item(&mut self, i: &'a ast::Item) {
156+
if let Some(attr) = attr::find_by_name(&i.attrs, sym::rustc_test_marker) {
157+
self.sess.parse_sess.buffer_lint(
158+
UNNAMEABLE_TEST_ITEMS,
159+
attr.span,
160+
i.id,
161+
crate::fluent_generated::builtin_macros_unnameable_test_items,
162+
);
163+
}
164+
}
165+
}
166+
145167
// Beware, this is duplicated in librustc_passes/entry.rs (with
146168
// `rustc_hir::Item`), so make sure to keep them in sync.
147169
fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType {

compiler/rustc_lint/messages.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
130130
lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
131131
.help = was set with `--cfg` but isn't in the `--check-cfg` expected values
132132
133-
lint_builtin_unnameable_test_items = cannot test inner items
134-
135133
lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
136134
lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
137135

compiler/rustc_lint/src/builtin.rs

+1-77
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use crate::{
3535
BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
3636
BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
3737
BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue,
38-
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit,
38+
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
3939
BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
4040
BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
4141
BuiltinWhileTrue, SuggestChangingAssocTypes,
@@ -1770,82 +1770,6 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
17701770
}
17711771
}
17721772

1773-
declare_lint! {
1774-
/// The `unnameable_test_items` lint detects [`#[test]`][test] functions
1775-
/// that are not able to be run by the test harness because they are in a
1776-
/// position where they are not nameable.
1777-
///
1778-
/// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
1779-
///
1780-
/// ### Example
1781-
///
1782-
/// ```rust,test
1783-
/// fn main() {
1784-
/// #[test]
1785-
/// fn foo() {
1786-
/// // This test will not fail because it does not run.
1787-
/// assert_eq!(1, 2);
1788-
/// }
1789-
/// }
1790-
/// ```
1791-
///
1792-
/// {{produces}}
1793-
///
1794-
/// ### Explanation
1795-
///
1796-
/// In order for the test harness to run a test, the test function must be
1797-
/// located in a position where it can be accessed from the crate root.
1798-
/// This generally means it must be defined in a module, and not anywhere
1799-
/// else such as inside another function. The compiler previously allowed
1800-
/// this without an error, so a lint was added as an alert that a test is
1801-
/// not being used. Whether or not this should be allowed has not yet been
1802-
/// decided, see [RFC 2471] and [issue #36629].
1803-
///
1804-
/// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
1805-
/// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
1806-
UNNAMEABLE_TEST_ITEMS,
1807-
Warn,
1808-
"detects an item that cannot be named being marked as `#[test_case]`",
1809-
report_in_external_macro
1810-
}
1811-
1812-
pub struct UnnameableTestItems {
1813-
boundary: Option<hir::OwnerId>, // Id of the item under which things are not nameable
1814-
items_nameable: bool,
1815-
}
1816-
1817-
impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]);
1818-
1819-
impl UnnameableTestItems {
1820-
pub fn new() -> Self {
1821-
Self { boundary: None, items_nameable: true }
1822-
}
1823-
}
1824-
1825-
impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
1826-
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
1827-
if self.items_nameable {
1828-
if let hir::ItemKind::Mod(..) = it.kind {
1829-
} else {
1830-
self.items_nameable = false;
1831-
self.boundary = Some(it.owner_id);
1832-
}
1833-
return;
1834-
}
1835-
1836-
let attrs = cx.tcx.hir().attrs(it.hir_id());
1837-
if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) {
1838-
cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems);
1839-
}
1840-
}
1841-
1842-
fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
1843-
if !self.items_nameable && self.boundary == Some(it.owner_id) {
1844-
self.items_nameable = true;
1845-
}
1846-
}
1847-
}
1848-
18491773
declare_lint! {
18501774
/// The `keyword_idents` lint detects edition keywords being used as an
18511775
/// identifier.

compiler/rustc_lint/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,6 @@ late_lint_methods!(
189189
[
190190
pub BuiltinCombinedLateLintPass,
191191
[
192-
// Tracks state across modules
193-
UnnameableTestItems: UnnameableTestItems::new(),
194192
// Tracks attributes of parents
195193
MissingDoc: MissingDoc::new(),
196194
// Builds a global list of all impls of `Debug`.

compiler/rustc_lint/src/lints.rs

-4
Original file line numberDiff line numberDiff line change
@@ -370,10 +370,6 @@ pub enum BuiltinEllipsisInclusiveRangePatternsLint {
370370
},
371371
}
372372

373-
#[derive(LintDiagnostic)]
374-
#[diag(lint_builtin_unnameable_test_items)]
375-
pub struct BuiltinUnnameableTestItems;
376-
377373
#[derive(LintDiagnostic)]
378374
#[diag(lint_builtin_keyword_idents)]
379375
pub struct BuiltinKeywordIdents {

compiler/rustc_lint_defs/src/builtin.rs

+40
Original file line numberDiff line numberDiff line change
@@ -2846,6 +2846,45 @@ declare_lint! {
28462846
};
28472847
}
28482848

2849+
declare_lint! {
2850+
/// The `unnameable_test_items` lint detects [`#[test]`][test] functions
2851+
/// that are not able to be run by the test harness because they are in a
2852+
/// position where they are not nameable.
2853+
///
2854+
/// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
2855+
///
2856+
/// ### Example
2857+
///
2858+
/// ```rust,test
2859+
/// fn main() {
2860+
/// #[test]
2861+
/// fn foo() {
2862+
/// // This test will not fail because it does not run.
2863+
/// assert_eq!(1, 2);
2864+
/// }
2865+
/// }
2866+
/// ```
2867+
///
2868+
/// {{produces}}
2869+
///
2870+
/// ### Explanation
2871+
///
2872+
/// In order for the test harness to run a test, the test function must be
2873+
/// located in a position where it can be accessed from the crate root.
2874+
/// This generally means it must be defined in a module, and not anywhere
2875+
/// else such as inside another function. The compiler previously allowed
2876+
/// this without an error, so a lint was added as an alert that a test is
2877+
/// not being used. Whether or not this should be allowed has not yet been
2878+
/// decided, see [RFC 2471] and [issue #36629].
2879+
///
2880+
/// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
2881+
/// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
2882+
pub UNNAMEABLE_TEST_ITEMS,
2883+
Warn,
2884+
"detects an item that cannot be named being marked as `#[test_case]`",
2885+
report_in_external_macro
2886+
}
2887+
28492888
declare_lint! {
28502889
/// The `useless_deprecated` lint detects deprecation attributes with no effect.
28512890
///
@@ -3403,6 +3442,7 @@ declare_lint_pass! {
34033442
UNKNOWN_CRATE_TYPES,
34043443
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
34053444
UNKNOWN_LINTS,
3445+
UNNAMEABLE_TEST_ITEMS,
34063446
UNNAMEABLE_TYPES,
34073447
UNREACHABLE_CODE,
34083448
UNREACHABLE_PATTERNS,

0 commit comments

Comments
 (0)