]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_lint/src/internal.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_lint / src / internal.rs
index fadb1c87933989d788250739603e74f4708fd5af..c26d7824758ef06f11b40692b10ff2a2d367ea49 100644 (file)
@@ -3,7 +3,7 @@
 
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability};
 use rustc_hir::def::Res;
 use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
 use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
@@ -36,13 +36,10 @@ impl LateLintPass<'_> for DefaultHashTypes {
             _ => return,
         };
         cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
-            let msg = format!(
-                "prefer `{}` over `{}`, it has better performance",
-                replace,
-                cx.tcx.item_name(def_id)
-            );
-            lint.build(&msg)
-                .note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
+            lint.build(fluent::lint::default_hash_types)
+                .set_arg("preferred", replace)
+                .set_arg("used", cx.tcx.item_name(def_id))
+                .note(fluent::lint::note)
                 .emit();
         });
     }
@@ -54,20 +51,6 @@ fn typeck_results_of_method_fn<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &Expr<'_>,
 ) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> {
-    // FIXME(rustdoc): Lints which use this function use typecheck results which can cause
-    // `rustdoc` to error if there are resolution failures.
-    //
-    // As internal lints are currently always run if there are `unstable_options`, they are added
-    // to the lint store of rustdoc. Internal lints are also not used via the `lint_mod` query.
-    // Crate lints run outside of a query so rustdoc currently doesn't disable them.
-    //
-    // Instead of relying on this, either change crate lints to a query disabled by rustdoc, only
-    // run internal lints if the user is explicitly opting in or figure out a different way to
-    // avoid running lints for rustdoc.
-    if cx.tcx.sess.opts.actually_rustdoc {
-        return None;
-    }
-
     match expr.kind {
         ExprKind::MethodCall(segment, _, _)
             if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
@@ -99,12 +82,9 @@ impl LateLintPass<'_> for QueryStability {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
                 cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
-                    let msg = format!(
-                        "using `{}` can result in unstable query results",
-                        cx.tcx.item_name(def_id)
-                    );
-                    lint.build(&msg)
-                        .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
+                    lint.build(fluent::lint::query_instability)
+                        .set_arg("query", cx.tcx.item_name(def_id))
+                        .note(fluent::lint::note)
                         .emit();
                 })
             }
@@ -146,10 +126,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                 segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
             );
             cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
-                lint.build("usage of `ty::TyKind::<kind>`")
+                lint.build(fluent::lint::tykind_kind)
                     .span_suggestion(
                         span,
-                        "try using `ty::<kind>` directly",
+                        fluent::lint::suggestion,
                         "ty",
                         Applicability::MaybeIncorrect, // ty maybe needs an import
                     )
@@ -175,10 +155,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                 if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                     && qpath_ty.hir_id == ty.hir_id
                                 {
-                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                    lint.build(fluent::lint::tykind_kind)
                                         .span_suggestion(
                                             path.span,
-                                            "try using `ty::<kind>` directly",
+                                            fluent::lint::suggestion,
                                             "ty",
                                             Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
@@ -193,10 +173,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                 if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                     && qpath_ty.hir_id == ty.hir_id
                                 {
-                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                    lint.build(fluent::lint::tykind_kind)
                                         .span_suggestion(
                                             path.span,
-                                            "try using `ty::<kind>` directly",
+                                            fluent::lint::suggestion,
                                             "ty",
                                             Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
@@ -213,10 +193,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                 if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                     && qpath_ty.hir_id == ty.hir_id
                                 {
-                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                    lint.build(fluent::lint::tykind_kind)
                                         .span_suggestion(
                                             path.span,
-                                            "try using `ty::<kind>` directly",
+                                            fluent::lint::suggestion,
                                             "ty",
                                             Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
@@ -226,15 +206,16 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                             }
                             _ => {}
                         }
-                        lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit();
+                        lint.build(fluent::lint::tykind).help(fluent::lint::help).emit();
                     })
                 } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
                     if path.segments.len() > 1 {
                         cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
-                            lint.build(&format!("usage of qualified `ty::{}`", t))
+                            lint.build(fluent::lint::ty_qualified)
+                                .set_arg("ty", t.clone())
                                 .span_suggestion(
                                     path.span,
-                                    "try importing it and using it unqualified",
+                                    fluent::lint::suggestion,
                                     t,
                                     // The import probably needs to be changed
                                     Applicability::MaybeIncorrect,
@@ -330,8 +311,8 @@ impl EarlyLintPass for LintPassImpl {
                             LINT_PASS_IMPL_WITHOUT_MACRO,
                             lint_pass.path.span,
                             |lint| {
-                                lint.build("implementing `LintPass` by hand")
-                                    .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
+                                lint.build(fluent::lint::lintpass_by_hand)
+                                    .help(fluent::lint::help)
                                     .emit();
                             },
                         )
@@ -371,13 +352,10 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
                             return;
                         }
                         cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
-                            lint.build(&format!(
-                                "Found non-existing keyword `{}` used in \
-                                     `#[doc(keyword = \"...\")]`",
-                                v,
-                            ))
-                            .help("only existing keywords are allowed in core/std")
-                            .emit();
+                            lint.build(fluent::lint::non_existant_doc_keyword)
+                                .set_arg("keyword", v)
+                                .help(fluent::lint::help)
+                                .emit();
                         });
                     }
                 }
@@ -406,9 +384,12 @@ impl LateLintPass<'_> for Diagnostics {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         let Some((span, def_id, substs)) = typeck_results_of_method_fn(cx, expr) else { return };
         debug!(?span, ?def_id, ?substs);
-        if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) &&
-            !cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_diagnostics)
-        {
+        let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs)
+            .ok()
+            .and_then(|inst| inst)
+            .map(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics))
+            .unwrap_or(false);
+        if !has_attr {
             return;
         }
 
@@ -419,7 +400,7 @@ impl LateLintPass<'_> for Diagnostics {
                 let Impl { of_trait: Some(of_trait), .. } = impl_ &&
                 let Some(def_id) = of_trait.trait_def_id() &&
                 let Some(name) = cx.tcx.get_diagnostic_name(def_id) &&
-                matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic)
+                matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic | sym::DecorateLint)
             {
                 found_impl = true;
                 break;
@@ -428,8 +409,7 @@ impl LateLintPass<'_> for Diagnostics {
         debug!(?found_impl);
         if !found_impl {
             cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
-                lint.build("diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls")
-                    .emit();
+                lint.build(fluent::lint::diag_out_of_impl).emit();
             })
         }
 
@@ -447,8 +427,43 @@ impl LateLintPass<'_> for Diagnostics {
         debug!(?found_diagnostic_message);
         if !found_diagnostic_message {
             cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| {
-                lint.build("diagnostics should be created using translatable messages").emit();
+                lint.build(fluent::lint::untranslatable_diag).emit();
             })
         }
     }
 }
+
+declare_tool_lint! {
+    pub rustc::BAD_OPT_ACCESS,
+    Deny,
+    "prevent using options by field access when there is a wrapper function",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(BadOptAccess => [ BAD_OPT_ACCESS ]);
+
+impl LateLintPass<'_> for BadOptAccess {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        let ExprKind::Field(base, target) = expr.kind else { return };
+        let Some(adt_def) = cx.typeck_results().expr_ty(base).ty_adt_def() else { return };
+        // Skip types without `#[rustc_lint_opt_ty]` - only so that the rest of the lint can be
+        // avoided.
+        if !cx.tcx.has_attr(adt_def.did(), sym::rustc_lint_opt_ty) {
+            return;
+        }
+
+        for field in adt_def.all_fields() {
+            if field.name == target.name &&
+                let Some(attr) = cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) &&
+                let Some(items) = attr.meta_item_list()  &&
+                let Some(item) = items.first()  &&
+                let Some(literal) = item.literal()  &&
+                let ast::LitKind::Str(val, _) = literal.kind
+            {
+                cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, |lint| {
+                    lint.build(val.as_str()).emit(); }
+                );
+            }
+        }
+    }
+}