Skip to content

Commit 32374a1

Browse files
committed
Auto merge of rust-lang#12930 - DaniPopes:missing-const-for-fn-suggestion, r=Jarcho
[`missing_const_for_fn`]: add machine-applicable suggestion Add a machine-applicable suggestion to the `missing_const_for_fn` lint. changelog: [`missing_const_for_fn`]: add machine-applicable suggestion
2 parents 9628130 + 82f0dc9 commit 32374a1

File tree

3 files changed

+275
-6
lines changed

3 files changed

+275
-6
lines changed

Diff for: clippy_lints/src/missing_const_for_fn.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use clippy_config::msrvs::{self, Msrv};
2-
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
44
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
5-
use rustc_hir as hir;
5+
use rustc_errors::Applicability;
66
use rustc_hir::def_id::CRATE_DEF_ID;
77
use rustc_hir::intravisit::FnKind;
8-
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind};
8+
use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::lint::in_external_macro;
1111
use rustc_session::impl_lint_pass;
@@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
120120
}
121121
},
122122
FnKind::Method(_, sig, ..) => {
123-
if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) {
123+
if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() {
124124
return;
125125
}
126126
},
@@ -147,10 +147,22 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
147147

148148
let mir = cx.tcx.optimized_mir(def_id);
149149

150-
if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
151-
span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`");
150+
if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv)
151+
&& let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) =
152+
cx.tcx.hir_node_by_def_id(def_id)
153+
{
154+
let suggestion = if vis_span.is_empty() { "const " } else { " const" };
155+
span_lint_and_then(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`", |diag| {
156+
diag.span_suggestion_verbose(
157+
vis_span.shrink_to_hi(),
158+
"make the function `const`",
159+
suggestion,
160+
Applicability::MachineApplicable,
161+
);
162+
});
152163
}
153164
}
165+
154166
extract_msrv_attr!(LateContext);
155167
}
156168

Diff for: tests/ui/missing_const_for_fn/could_be_const.fixed

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#![warn(clippy::missing_const_for_fn)]
2+
#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
3+
#![feature(const_mut_refs)]
4+
#![feature(const_trait_impl)]
5+
6+
use std::mem::transmute;
7+
8+
struct Game {
9+
guess: i32,
10+
}
11+
12+
impl Game {
13+
// Could be const
14+
pub const fn new() -> Self {
15+
//~^ ERROR: this could be a `const fn`
16+
//~| NOTE: `-D clippy::missing-const-for-fn` implied by `-D warnings`
17+
Self { guess: 42 }
18+
}
19+
20+
const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] {
21+
//~^ ERROR: this could be a `const fn`
22+
b
23+
}
24+
}
25+
26+
// Could be const
27+
const fn one() -> i32 {
28+
//~^ ERROR: this could be a `const fn`
29+
1
30+
}
31+
32+
// Could also be const
33+
const fn two() -> i32 {
34+
//~^ ERROR: this could be a `const fn`
35+
let abc = 2;
36+
abc
37+
}
38+
39+
// Could be const (since Rust 1.39)
40+
const fn string() -> String {
41+
//~^ ERROR: this could be a `const fn`
42+
String::new()
43+
}
44+
45+
// Could be const
46+
const unsafe fn four() -> i32 {
47+
//~^ ERROR: this could be a `const fn`
48+
4
49+
}
50+
51+
// Could also be const
52+
const fn generic<T>(t: T) -> T {
53+
//~^ ERROR: this could be a `const fn`
54+
t
55+
}
56+
57+
fn sub(x: u32) -> usize {
58+
unsafe { transmute(&x) }
59+
}
60+
61+
const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
62+
//~^ ERROR: this could be a `const fn`
63+
t[0]
64+
}
65+
66+
mod with_drop {
67+
pub struct A;
68+
pub struct B;
69+
impl Drop for A {
70+
fn drop(&mut self) {}
71+
}
72+
73+
impl B {
74+
// This can be const, because `a` is passed by reference
75+
pub const fn b(self, a: &A) -> B {
76+
//~^ ERROR: this could be a `const fn`
77+
B
78+
}
79+
}
80+
}
81+
82+
#[clippy::msrv = "1.47.0"]
83+
mod const_fn_stabilized_before_msrv {
84+
// This could be const because `u8::is_ascii_digit` is a stable const function in 1.47.
85+
const fn const_fn_stabilized_before_msrv(byte: u8) {
86+
//~^ ERROR: this could be a `const fn`
87+
byte.is_ascii_digit();
88+
}
89+
}
90+
91+
#[clippy::msrv = "1.45"]
92+
fn msrv_1_45() -> i32 {
93+
45
94+
}
95+
96+
#[clippy::msrv = "1.46"]
97+
const fn msrv_1_46() -> i32 {
98+
//~^ ERROR: this could be a `const fn`
99+
46
100+
}
101+
102+
// Should not be const
103+
fn main() {}
104+
105+
struct D;
106+
107+
impl const Drop for D {
108+
fn drop(&mut self) {
109+
todo!();
110+
}
111+
}
112+
113+
// Lint this, since it can be dropped in const contexts
114+
// FIXME(effects)
115+
fn d(this: D) {}
116+
117+
mod msrv {
118+
struct Foo(*const u8, &'static u8);
119+
120+
impl Foo {
121+
#[clippy::msrv = "1.58"]
122+
const fn deref_ptr_can_be_const(self) -> usize {
123+
//~^ ERROR: this could be a `const fn`
124+
unsafe { *self.0 as usize }
125+
}
126+
127+
const fn deref_copied_val(self) -> usize {
128+
//~^ ERROR: this could be a `const fn`
129+
*self.1 as usize
130+
}
131+
}
132+
133+
union Bar {
134+
val: u8,
135+
}
136+
137+
#[clippy::msrv = "1.56"]
138+
const fn union_access_can_be_const() {
139+
//~^ ERROR: this could be a `const fn`
140+
let bar = Bar { val: 1 };
141+
let _ = unsafe { bar.val };
142+
}
143+
}
144+
145+
mod issue12677 {
146+
pub struct Wrapper {
147+
pub strings: Vec<String>,
148+
}
149+
150+
impl Wrapper {
151+
#[must_use]
152+
pub const fn new(strings: Vec<String>) -> Self {
153+
Self { strings }
154+
}
155+
156+
#[must_use]
157+
pub const fn empty() -> Self {
158+
Self { strings: Vec::new() }
159+
}
160+
}
161+
162+
pub struct Other {
163+
pub text: String,
164+
pub vec: Vec<String>,
165+
}
166+
167+
impl Other {
168+
pub const fn new(text: String) -> Self {
169+
let vec = Vec::new();
170+
Self { text, vec }
171+
}
172+
}
173+
}

0 commit comments

Comments
 (0)