mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #98914 - fee1-dead-contrib:min-deref-patterns, r=compiler-errors
Minimal implementation of implicit deref patterns for Strings cc `@compiler-errors` `@BoxyUwU` https://github.com/rust-lang/lang-team/issues/88 #87121 ~~I forgot to add a feature gate, will do so in a minute~~ Done
This commit is contained in:
commit
e07425d55b
@ -506,6 +506,8 @@ declare_features! (
|
||||
(active, stmt_expr_attributes, "1.6.0", Some(15701), None),
|
||||
/// Allows lints part of the strict provenance effort.
|
||||
(active, strict_provenance, "1.61.0", Some(95228), None),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(active, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None),
|
||||
/// Allows the use of `#[target_feature]` on safe functions.
|
||||
(active, target_feature_11, "1.45.0", Some(69098), None),
|
||||
/// Allows using `#[thread_local]` on `static` items.
|
||||
|
@ -312,6 +312,8 @@ language_item_table! {
|
||||
Range, sym::Range, range_struct, Target::Struct, GenericRequirement::None;
|
||||
RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None;
|
||||
RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;
|
||||
|
||||
String, sym::String, string, Target::Struct, GenericRequirement::None;
|
||||
}
|
||||
|
||||
pub enum GenericRequirement {
|
||||
|
@ -464,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ref_cnt += 1;
|
||||
}
|
||||
if let ty::Adt(adt, _) = peeled.kind()
|
||||
&& self.tcx.is_diagnostic_item(sym::String, adt.did())
|
||||
&& Some(adt.did()) == self.tcx.lang_items().string()
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
|
@ -821,10 +821,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty.is_str()
|
||||
|| matches!(
|
||||
ty.kind(),
|
||||
ty::Adt(adt, _) if self.tcx.is_diagnostic_item(sym::String, adt.did())
|
||||
ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
|
||||
)
|
||||
}
|
||||
ty::Adt(adt, _) => self.tcx.is_diagnostic_item(sym::String, adt.did()),
|
||||
ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
|
||||
_ => false,
|
||||
};
|
||||
if is_string_or_ref_str && item_name.name == sym::iter {
|
||||
|
@ -556,9 +556,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let rm_borrow_msg = "remove the borrow to obtain an owned `String`";
|
||||
let to_owned_msg = "create an owned `String` from a string reference";
|
||||
|
||||
let string_type = self.tcx.lang_items().string();
|
||||
let is_std_string = |ty: Ty<'tcx>| {
|
||||
ty.ty_adt_def()
|
||||
.map_or(false, |ty_def| self.tcx.is_diagnostic_item(sym::String, ty_def.did()))
|
||||
ty.ty_adt_def().map_or(false, |ty_def| Some(ty_def.did()) == string_type)
|
||||
};
|
||||
|
||||
match (lhs_ty.kind(), rhs_ty.kind()) {
|
||||
|
@ -401,6 +401,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if self.tcx.features().string_deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind {
|
||||
let tcx = self.tcx;
|
||||
let expected = self.resolve_vars_if_possible(expected);
|
||||
pat_ty = match expected.kind() {
|
||||
ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected,
|
||||
ty::Str => tcx.mk_static_str(),
|
||||
_ => pat_ty,
|
||||
};
|
||||
}
|
||||
|
||||
// Somewhat surprising: in this case, the subtyping relation goes the
|
||||
// opposite way as the other cases. Actually what we really want is not
|
||||
// a subtyping relation at all but rather that there exists a LUB
|
||||
|
@ -148,7 +148,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
||||
ty::Ref(_, r, _) if *r.kind() == ty::Str,
|
||||
) || matches!(
|
||||
ty.ty_adt_def(),
|
||||
Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did()),
|
||||
Some(ty_def) if Some(ty_def.did()) == cx.tcx.lang_items().string(),
|
||||
);
|
||||
|
||||
let infcx = cx.tcx.infer_ctxt().build();
|
||||
|
@ -240,6 +240,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
TestKind::Eq { value, ty } => {
|
||||
let tcx = self.tcx;
|
||||
if let ty::Adt(def, _) = ty.kind() && Some(def.did()) == tcx.lang_items().string() {
|
||||
if !tcx.features().string_deref_patterns {
|
||||
bug!("matching on `String` went through without enabling string_deref_patterns");
|
||||
}
|
||||
let re_erased = tcx.lifetimes.re_erased;
|
||||
let ref_string = self.temp(tcx.mk_imm_ref(re_erased, ty), test.span);
|
||||
let ref_str_ty = tcx.mk_imm_ref(re_erased, tcx.types.str_);
|
||||
let ref_str = self.temp(ref_str_ty, test.span);
|
||||
let deref = tcx.require_lang_item(LangItem::Deref, None);
|
||||
let method = trait_method(tcx, deref, sym::deref, ty, &[]);
|
||||
let eq_block = self.cfg.start_new_block();
|
||||
self.cfg.push_assign(block, source_info, ref_string, Rvalue::Ref(re_erased, BorrowKind::Shared, place));
|
||||
self.cfg.terminate(
|
||||
block,
|
||||
source_info,
|
||||
TerminatorKind::Call {
|
||||
func: Operand::Constant(Box::new(Constant {
|
||||
span: test.span,
|
||||
user_ty: None,
|
||||
literal: method,
|
||||
})),
|
||||
args: vec![Operand::Move(ref_string)],
|
||||
destination: ref_str,
|
||||
target: Some(eq_block),
|
||||
cleanup: None,
|
||||
from_hir_call: false,
|
||||
fn_span: source_info.span
|
||||
}
|
||||
);
|
||||
self.non_scalar_compare(eq_block, make_target_blocks, source_info, value, ref_str, ref_str_ty);
|
||||
return;
|
||||
}
|
||||
if !ty.is_scalar() {
|
||||
// Use `PartialEq::eq` instead of `BinOp::Eq`
|
||||
// (the binop can only handle primitives)
|
||||
|
@ -1407,6 +1407,7 @@ symbols! {
|
||||
str_trim_end,
|
||||
str_trim_start,
|
||||
strict_provenance,
|
||||
string_deref_patterns,
|
||||
stringify,
|
||||
struct_field_attributes,
|
||||
struct_inherit,
|
||||
|
@ -1729,7 +1729,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
ty::Bool => Some(0),
|
||||
ty::Char => Some(1),
|
||||
ty::Str => Some(2),
|
||||
ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did()) => Some(2),
|
||||
ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2),
|
||||
ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
|
@ -362,8 +362,8 @@ use crate::vec::Vec;
|
||||
/// [`Deref`]: core::ops::Deref "ops::Deref"
|
||||
/// [`as_str()`]: String::as_str
|
||||
#[derive(PartialOrd, Eq, Ord)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "String")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(all(not(bootstrap), not(test)), lang = "String")]
|
||||
pub struct String {
|
||||
vec: Vec<u8>,
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
// MIR for `foo` after PreCodegen
|
||||
|
||||
fn foo(_1: Option<String>) -> i32 {
|
||||
debug s => _1; // in scope 0 at $DIR/string.rs:+0:12: +0:13
|
||||
let mut _0: i32; // return place in scope 0 at $DIR/string.rs:+0:34: +0:37
|
||||
let mut _2: &std::string::String; // in scope 0 at $DIR/string.rs:+2:14: +2:17
|
||||
let mut _3: &str; // in scope 0 at $DIR/string.rs:+2:14: +2:17
|
||||
let mut _4: bool; // in scope 0 at $DIR/string.rs:+2:14: +2:17
|
||||
let mut _5: isize; // in scope 0 at $DIR/string.rs:+2:9: +2:18
|
||||
let _6: std::option::Option<std::string::String>; // in scope 0 at $DIR/string.rs:+3:9: +3:10
|
||||
let mut _7: bool; // in scope 0 at $DIR/string.rs:+5:1: +5:2
|
||||
scope 1 {
|
||||
debug s => _6; // in scope 1 at $DIR/string.rs:+3:9: +3:10
|
||||
}
|
||||
|
||||
bb0: {
|
||||
_7 = const false; // scope 0 at $DIR/string.rs:+1:11: +1:12
|
||||
_7 = const true; // scope 0 at $DIR/string.rs:+1:11: +1:12
|
||||
_5 = discriminant(_1); // scope 0 at $DIR/string.rs:+1:11: +1:12
|
||||
switchInt(move _5) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/string.rs:+1:5: +1:12
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_6); // scope 0 at $DIR/string.rs:+3:9: +3:10
|
||||
_7 = const false; // scope 0 at $DIR/string.rs:+3:9: +3:10
|
||||
_6 = move _1; // scope 0 at $DIR/string.rs:+3:9: +3:10
|
||||
_0 = const 4321_i32; // scope 1 at $DIR/string.rs:+3:14: +3:18
|
||||
drop(_6) -> bb6; // scope 0 at $DIR/string.rs:+3:17: +3:18
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_2 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17
|
||||
_3 = <String as Deref>::deref(move _2) -> bb3; // scope 0 at $DIR/string.rs:+2:14: +2:17
|
||||
// mir::Constant
|
||||
// + span: $DIR/string.rs:9:14: 9:17
|
||||
// + literal: Const { ty: for<'a> fn(&'a String) -> &'a <String as Deref>::Target {<String as Deref>::deref}, val: Value(<ZST>) }
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_4 = <str as PartialEq>::eq(_3, const "a") -> bb4; // scope 0 at $DIR/string.rs:+2:14: +2:17
|
||||
// mir::Constant
|
||||
// + span: $DIR/string.rs:9:14: 9:17
|
||||
// + literal: Const { ty: for<'a, 'b> fn(&'a str, &'b str) -> bool {<str as PartialEq>::eq}, val: Value(<ZST>) }
|
||||
// mir::Constant
|
||||
// + span: $DIR/string.rs:9:14: 9:17
|
||||
// + literal: Const { ty: &str, val: Value(Slice(..)) }
|
||||
}
|
||||
|
||||
bb4: {
|
||||
switchInt(move _4) -> [false: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+2:14: +2:17
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_0 = const 1234_i32; // scope 0 at $DIR/string.rs:+2:22: +2:26
|
||||
goto -> bb9; // scope 0 at $DIR/string.rs:+2:22: +2:26
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_6); // scope 0 at $DIR/string.rs:+3:17: +3:18
|
||||
goto -> bb9; // scope 0 at $DIR/string.rs:+3:17: +3:18
|
||||
}
|
||||
|
||||
bb7: {
|
||||
return; // scope 0 at $DIR/string.rs:+5:2: +5:2
|
||||
}
|
||||
|
||||
bb8: {
|
||||
drop(_1) -> bb7; // scope 0 at $DIR/string.rs:+5:1: +5:2
|
||||
}
|
||||
|
||||
bb9: {
|
||||
switchInt(_7) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2
|
||||
}
|
||||
}
|
12
src/test/mir-opt/deref-patterns/string.rs
Normal file
12
src/test/mir-opt/deref-patterns/string.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// compile-flags: -Z mir-opt-level=0 -C panic=abort
|
||||
|
||||
#![feature(string_deref_patterns)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// EMIT_MIR string.foo.PreCodegen.after.mir
|
||||
pub fn foo(s: Option<String>) -> i32 {
|
||||
match s {
|
||||
Some("a") => 1234,
|
||||
s => 4321,
|
||||
}
|
||||
}
|
17
src/test/ui/deref-patterns/basic.rs
Normal file
17
src/test/ui/deref-patterns/basic.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// run-pass
|
||||
// check-run-results
|
||||
#![feature(string_deref_patterns)]
|
||||
|
||||
fn main() {
|
||||
test(Some(String::from("42")));
|
||||
test(Some(String::new()));
|
||||
test(None);
|
||||
}
|
||||
|
||||
fn test(o: Option<String>) {
|
||||
match o {
|
||||
Some("42") => println!("the answer"),
|
||||
Some(_) => println!("something else?"),
|
||||
None => println!("nil"),
|
||||
}
|
||||
}
|
3
src/test/ui/deref-patterns/basic.run.stdout
Normal file
3
src/test/ui/deref-patterns/basic.run.stdout
Normal file
@ -0,0 +1,3 @@
|
||||
the answer
|
||||
something else?
|
||||
nil
|
9
src/test/ui/deref-patterns/default-infer.rs
Normal file
9
src/test/ui/deref-patterns/default-infer.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// check-pass
|
||||
#![feature(string_deref_patterns)]
|
||||
|
||||
fn main() {
|
||||
match <_ as Default>::default() {
|
||||
"" => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
7
src/test/ui/deref-patterns/gate.rs
Normal file
7
src/test/ui/deref-patterns/gate.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// gate-test-string_deref_patterns
|
||||
fn main() {
|
||||
match String::new() {
|
||||
"" | _ => {}
|
||||
//~^ mismatched types
|
||||
}
|
||||
}
|
11
src/test/ui/deref-patterns/gate.stderr
Normal file
11
src/test/ui/deref-patterns/gate.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/gate.rs:4:9
|
||||
|
|
||||
LL | match String::new() {
|
||||
| ------------- this expression has type `String`
|
||||
LL | "" | _ => {}
|
||||
| ^^ expected struct `String`, found `&str`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
18
src/test/ui/deref-patterns/refs.rs
Normal file
18
src/test/ui/deref-patterns/refs.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
#![feature(string_deref_patterns)]
|
||||
|
||||
fn foo(s: &String) -> i32 {
|
||||
match *s {
|
||||
"a" => 42,
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
|
||||
fn bar(s: Option<&&&&String>) -> i32 {
|
||||
match s {
|
||||
Some(&&&&"&&&&") => 1,
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
||||
if format_args.format_string.parts == [kw::Empty];
|
||||
if arg.format.is_default();
|
||||
if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
|
||||
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()),
|
||||
ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(),
|
||||
ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::{match_def_path, paths, peel_hir_expr_refs};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
@ -41,7 +41,7 @@ declare_clippy_lint! {
|
||||
declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
|
||||
|
||||
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String)
|
||||
is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
|
||||
}
|
||||
fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
if let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id {
|
||||
|
@ -1,10 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_integer_literal;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind};
|
||||
use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -98,5 +98,5 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
|
||||
|
||||
/// Checks if a Ty is `String` or `&str`
|
||||
fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
is_type_diagnostic_item(cx, ty, sym::String) || is_type_diagnostic_item(cx, ty, sym::str)
|
||||
is_type_lang_item(cx, ty, LangItem::String) || is_type_diagnostic_item(cx, ty, sym::str)
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||
use clippy_utils::{return_ty, trait_ref_of_method};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind};
|
||||
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
|
||||
if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
|
||||
|
||||
// Check if return type is String
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
|
||||
if is_type_lang_item(cx, return_ty(cx, impl_item.hir_id()), LangItem::String);
|
||||
|
||||
// Filters instances of to_string which are required by a trait
|
||||
if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use rustc_errors::Applicability;
|
||||
@ -140,7 +140,7 @@ fn check_to_owned(
|
||||
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
|
||||
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
|
||||
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
|
||||
&& is_type_diagnostic_item(cx, ty, sym::String)
|
||||
&& is_type_lang_item(cx, ty, hir::LangItem::String)
|
||||
&& SpanlessEq::new(cx).eq_expr(left_expr, str_expr) {
|
||||
suggest(cx, parent_expr, left_expr, filter_expr);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ impl LateLintPass<'_> for ManualStringNew {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
match ty.kind() {
|
||||
ty::Adt(adt_def, _) if adt_def.is_struct() => {
|
||||
if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) {
|
||||
if cx.tcx.lang_items().string() != Some(adt_def.did()) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
@ -1,13 +1,13 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, PatKind};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::MATCH_STR_CASE_MISMATCH;
|
||||
|
||||
@ -59,7 +59,7 @@ impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
|
||||
if let Some(case_method) = get_case_method(segment_ident) {
|
||||
let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
|
||||
|
||||
if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str {
|
||||
if is_type_lang_item(self.cx, ty, LangItem::String) || ty.kind() == &ty::Str {
|
||||
self.case_method = Some(case_method);
|
||||
return true;
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::BYTES_COUNT_TO_LEN;
|
||||
|
||||
@ -20,7 +19,7 @@ pub(super) fn check<'tcx>(
|
||||
if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
|
||||
if cx.tcx.type_of(impl_id).is_str();
|
||||
let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
|
||||
if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String);
|
||||
if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
|
@ -1,10 +1,9 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir::{Expr, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::BYTES_NTH;
|
||||
|
||||
@ -12,7 +11,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
|
||||
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
let caller_type = if ty.is_str() {
|
||||
"str"
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::String) {
|
||||
} else if is_type_lang_item(cx, ty, LangItem::String) {
|
||||
"String"
|
||||
} else {
|
||||
return;
|
||||
|
@ -1,10 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{source_map::Spanned, symbol::sym, Span};
|
||||
use rustc_span::{source_map::Spanned, Span};
|
||||
|
||||
use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
|
||||
|
||||
@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
|
||||
if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
|
||||
|| ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
|
||||
let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String);
|
||||
if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String);
|
||||
then {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -33,7 +33,7 @@ pub(super) fn check<'tcx>(
|
||||
if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
|
||||
let arg_type = cx.typeck_results().expr_ty(receiver);
|
||||
let base_type = arg_type.peel_refs();
|
||||
*base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
|
||||
*base_type.kind() == ty::Str || is_type_lang_item(cx, base_type, hir::LangItem::String)
|
||||
} {
|
||||
receiver
|
||||
} else {
|
||||
@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(
|
||||
// converted to string.
|
||||
fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
if is_type_diagnostic_item(cx, arg_ty, sym::String) {
|
||||
if is_type_lang_item(cx, arg_ty, hir::LangItem::String) {
|
||||
return false;
|
||||
}
|
||||
if let ty::Ref(_, ty, ..) = arg_ty.kind() {
|
||||
|
@ -1,13 +1,13 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, walk_ptrs_ty_depth};
|
||||
use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
|
||||
use super::INEFFICIENT_TO_STRING;
|
||||
|
||||
@ -60,7 +60,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
if is_type_diagnostic_item(cx, ty, sym::String) {
|
||||
if is_type_lang_item(cx, ty, hir::LangItem::String) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -36,14 +36,14 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
|
||||
}
|
||||
} else {
|
||||
let ty = cx.typeck_results().expr_ty(e);
|
||||
if is_type_diagnostic_item(cx, ty, sym::String)
|
||||
if is_type_lang_item(cx, ty, LangItem::String)
|
||||
|| (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str))
|
||||
|| (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str))
|
||||
{
|
||||
Some(RepeatKind::String)
|
||||
} else {
|
||||
let ty = ty.peel_refs();
|
||||
(ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)).then_some(RepeatKind::String)
|
||||
(ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)).then_some(RepeatKind::String)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,7 @@ pub(super) fn check(
|
||||
if_chain! {
|
||||
if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
|
||||
if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat);
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String);
|
||||
if is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String);
|
||||
if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
|
||||
if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
|
||||
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||
|
@ -1,11 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::SpanlessEq;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_hir::ExprKind;
|
||||
use rustc_hir::{ExprKind, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::NO_EFFECT_REPLACE;
|
||||
|
||||
@ -16,7 +15,7 @@ pub(super) fn check<'tcx>(
|
||||
arg2: &'tcx rustc_hir::Expr<'_>,
|
||||
) {
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
if !(ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)) {
|
||||
if !(ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
use clippy_utils::consts::{constant_context, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir::{Expr, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::REPEAT_ONCE;
|
||||
|
||||
@ -37,7 +36,7 @@ pub(super) fn check<'tcx>(
|
||||
format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::String) {
|
||||
} else if is_type_lang_item(cx, ty, LangItem::String) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REPEAT_ONCE,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::sugg::deref_closure_args;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::{is_trait_method, strip_pat_refs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
@ -105,7 +105,7 @@ pub(super) fn check<'tcx>(
|
||||
else if search_method == "find" {
|
||||
let is_string_or_str_slice = |e| {
|
||||
let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
|
||||
if is_type_diagnostic_item(cx, self_ty, sym::String) {
|
||||
if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
|
||||
true
|
||||
} else {
|
||||
*self_ty.kind() == ty::Str
|
||||
|
@ -1,18 +1,17 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::STRING_EXTEND_CHARS;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
|
||||
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
if !is_type_diagnostic_item(cx, obj_ty, sym::String) {
|
||||
if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) {
|
||||
return;
|
||||
}
|
||||
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
|
||||
@ -20,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
|
||||
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
||||
let ref_str = if *self_ty.kind() == ty::Str {
|
||||
""
|
||||
} else if is_type_diagnostic_item(cx, self_ty, sym::String) {
|
||||
} else if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
|
||||
"&"
|
||||
} else {
|
||||
return;
|
||||
|
@ -1,10 +1,10 @@
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{Ref, Slice};
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::UNNECESSARY_JOIN;
|
||||
|
||||
@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
|
||||
// the turbofish for collect is ::<Vec<String>>
|
||||
if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind();
|
||||
if let Slice(slice) = ref_type.kind();
|
||||
if is_type_diagnostic_item(cx, *slice, sym::String);
|
||||
if is_type_lang_item(cx, *slice, LangItem::String);
|
||||
// the argument for join is ""
|
||||
if let ExprKind::Lit(spanned) = &join_arg.kind;
|
||||
if let LitKind::Str(symbol, _) = spanned.node;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
||||
use clippy_utils::ptr::get_spans;
|
||||
use clippy_utils::source::{snippet, snippet_opt};
|
||||
use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item};
|
||||
use clippy_utils::{get_trait_def_id, is_self, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::Attribute;
|
||||
@ -11,7 +11,7 @@ use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
|
||||
};
|
||||
use rustc_hir::{HirIdMap, HirIdSet};
|
||||
use rustc_hir::{HirIdMap, HirIdSet, LangItem};
|
||||
use rustc_hir_typeck::expr_use_visitor as euv;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -249,7 +249,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
||||
}
|
||||
}
|
||||
|
||||
if is_type_diagnostic_item(cx, ty, sym::String) {
|
||||
if is_type_lang_item(cx, ty, LangItem::String) {
|
||||
if let Some(clone_spans) =
|
||||
get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
|
||||
diag.span_suggestion(
|
||||
|
@ -450,7 +450,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
|
||||
substs.type_at(0),
|
||||
),
|
||||
),
|
||||
Some(sym::String) => (
|
||||
_ if Some(adt.did()) == cx.tcx.lang_items().string() => (
|
||||
[("clone", ".to_owned()"), ("as_str", "")].as_slice(),
|
||||
DerefTy::Str,
|
||||
),
|
||||
|
@ -1,12 +1,12 @@
|
||||
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
|
||||
use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
|
||||
use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth};
|
||||
use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{def_id, Body, FnDecl, HirId};
|
||||
use rustc_hir::{def_id, Body, FnDecl, HirId, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
|
||||
let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
|
||||
|| match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD)
|
||||
|| (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD)
|
||||
&& is_type_diagnostic_item(cx, arg_ty, sym::String));
|
||||
&& is_type_lang_item(cx, arg_ty, LangItem::String));
|
||||
|
||||
let from_deref = !from_borrow
|
||||
&& (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF)
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
|
||||
use clippy_utils::{peel_blocks, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
|
||||
},
|
||||
ExprKind::Index(target, _idx) => {
|
||||
let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
||||
if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) {
|
||||
if matches!(e_ty.kind(), ty::Str) || is_type_lang_item(cx, e_ty, LangItem::String) {
|
||||
span_lint(
|
||||
cx,
|
||||
STRING_SLICE,
|
||||
@ -205,7 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
|
||||
}
|
||||
|
||||
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String)
|
||||
is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
|
||||
}
|
||||
|
||||
fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
|
||||
@ -446,7 +446,7 @@ impl<'tcx> LateLintPass<'tcx> for StringToString {
|
||||
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
|
||||
if path.ident.name == sym::to_string;
|
||||
let ty = cx.typeck_results().expr_ty(self_arg);
|
||||
if is_type_diagnostic_item(cx, ty, sym::String);
|
||||
if is_type_lang_item(cx, ty, LangItem::String);
|
||||
then {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
@ -37,18 +37,19 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Symbol> {
|
||||
let param = qpath_generic_tys(qpath).next()?;
|
||||
let id = path_def_id(cx, param)?;
|
||||
cx.tcx.get_diagnostic_name(id).filter(|&name| {
|
||||
matches!(
|
||||
name,
|
||||
sym::HashMap
|
||||
| sym::String
|
||||
| sym::Vec
|
||||
| sym::HashSet
|
||||
| sym::VecDeque
|
||||
| sym::LinkedList
|
||||
| sym::BTreeMap
|
||||
| sym::BTreeSet
|
||||
| sym::BinaryHeap
|
||||
)
|
||||
})
|
||||
cx.tcx
|
||||
.get_diagnostic_name(id)
|
||||
.filter(|&name| matches!(name, sym::HashMap | sym::Vec | sym::HashSet
|
||||
| sym::VecDeque
|
||||
| sym::LinkedList
|
||||
| sym::BTreeMap
|
||||
| sym::BTreeSet
|
||||
| sym::BinaryHeap))
|
||||
.or_else(|| {
|
||||
cx.tcx
|
||||
.lang_items()
|
||||
.string()
|
||||
.filter(|did| id == *did)
|
||||
.map(|_| sym::String)
|
||||
})
|
||||
}
|
||||
|
@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
|
||||
let ty = qpath_generic_tys(qpath).next()?;
|
||||
let id = path_def_id(cx, ty)?;
|
||||
let path = match cx.tcx.get_diagnostic_name(id)? {
|
||||
sym::String => "str",
|
||||
sym::OsString => "std::ffi::OsStr",
|
||||
sym::PathBuf => "std::path::Path",
|
||||
let path = match cx.tcx.get_diagnostic_name(id) {
|
||||
Some(sym::OsString) => "std::ffi::OsStr",
|
||||
Some(sym::PathBuf) => "std::path::Path",
|
||||
_ if Some(id) == cx.tcx.lang_items().string() => "str",
|
||||
_ => return None,
|
||||
};
|
||||
Some(path)
|
||||
|
@ -1,13 +1,12 @@
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_diagnostic_item};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item};
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -61,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
|
||||
if let LitKind::Str(symbol, _) = spanned.node;
|
||||
if symbol.is_empty();
|
||||
let inner_expr_type = cx.typeck_results().expr_ty(inner_expr);
|
||||
if is_type_diagnostic_item(cx, inner_expr_type, sym::String);
|
||||
if is_type_lang_item(cx, inner_expr_type, LangItem::String);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -434,6 +434,16 @@ pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[
|
||||
path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
|
||||
}
|
||||
|
||||
/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
|
||||
/// it matches the given lang item.
|
||||
pub fn is_path_lang_item<'tcx>(
|
||||
cx: &LateContext<'_>,
|
||||
maybe_path: &impl MaybePath<'tcx>,
|
||||
lang_item: LangItem,
|
||||
) -> bool {
|
||||
path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.lang_items().get(lang_item) == Some(id))
|
||||
}
|
||||
|
||||
/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
|
||||
/// it matches the given diagnostic item.
|
||||
pub fn is_path_diagnostic_item<'tcx>(
|
||||
@ -760,7 +770,6 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -
|
||||
/// constructor from the std library
|
||||
fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
|
||||
let std_types_symbols = &[
|
||||
sym::String,
|
||||
sym::Vec,
|
||||
sym::VecDeque,
|
||||
sym::LinkedList,
|
||||
@ -777,7 +786,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
|
||||
if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
|
||||
return std_types_symbols
|
||||
.iter()
|
||||
.any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did()));
|
||||
.any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -834,7 +843,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
|
||||
ExprKind::Lit(hir::Lit {
|
||||
node: LitKind::Str(ref sym, _),
|
||||
..
|
||||
}) => return sym.is_empty() && is_path_diagnostic_item(cx, ty, sym::String),
|
||||
}) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
|
||||
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
|
||||
ExprKind::Repeat(_, ArrayLen::Body(len)) => {
|
||||
if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind &&
|
||||
|
Loading…
Reference in New Issue
Block a user