@@ -5,7 +5,8 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
5
5
use rustc_ast as ast;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir:: def:: Res ;
8
- use rustc_hir:: { GenericArg , HirId , Item , ItemKind , Node , Path , PathSegment , QPath , Ty , TyKind } ;
8
+ use rustc_hir:: { Expr , ExprKind , GenericArg , Path , PathSegment , QPath } ;
9
+ use rustc_hir:: { HirId , Item , ItemKind , Node , Ty , TyKind } ;
9
10
use rustc_middle:: ty;
10
11
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11
12
use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
@@ -48,6 +49,63 @@ impl LateLintPass<'_> for DefaultHashTypes {
48
49
}
49
50
}
50
51
52
+ declare_tool_lint ! {
53
+ pub rustc:: POTENTIAL_QUERY_INSTABILITY ,
54
+ Allow ,
55
+ "require explicit opt-in when using potentially unstable methods or functions" ,
56
+ report_in_external_macro: true
57
+ }
58
+
59
+ declare_lint_pass ! ( QueryStability => [ POTENTIAL_QUERY_INSTABILITY ] ) ;
60
+
61
+ impl LateLintPass < ' _ > for QueryStability {
62
+ fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
63
+ // FIXME(rustdoc): This lint uses typecheck results, causing rustdoc to
64
+ // error if there are resolution failures.
65
+ //
66
+ // As internal lints are currently always run if there are `unstable_options`,
67
+ // they are added to the lint store of rustdoc. Internal lints are also
68
+ // not used via the `lint_mod` query. Crate lints run outside of a query
69
+ // so rustdoc currently doesn't disable them.
70
+ //
71
+ // Instead of relying on this, either change crate lints to a query disabled by
72
+ // rustdoc, only run internal lints if the user is explicitly opting in
73
+ // or figure out a different way to avoid running lints for rustdoc.
74
+ if cx. tcx . sess . opts . actually_rustdoc {
75
+ return ;
76
+ }
77
+
78
+ let ( span, def_id, substs) = match expr. kind {
79
+ ExprKind :: MethodCall ( segment, _, _)
80
+ if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) =>
81
+ {
82
+ ( segment. ident . span , def_id, cx. typeck_results ( ) . node_substs ( expr. hir_id ) )
83
+ } ,
84
+ _ => {
85
+ let & ty:: FnDef ( def_id, substs) =
86
+ cx. typeck_results ( )
87
+ . node_type ( expr. hir_id )
88
+ . kind ( ) else { return } ;
89
+ ( expr. span , def_id, substs)
90
+ }
91
+ } ;
92
+ if let Ok ( Some ( instance) ) = ty:: Instance :: resolve ( cx. tcx , cx. param_env , def_id, substs) {
93
+ let def_id = instance. def_id ( ) ;
94
+ if cx. tcx . has_attr ( def_id, sym:: rustc_lint_query_instability) {
95
+ cx. struct_span_lint ( POTENTIAL_QUERY_INSTABILITY , span, |lint| {
96
+ let msg = format ! (
97
+ "using `{}` can result in unstable query results" ,
98
+ cx. tcx. item_name( def_id)
99
+ ) ;
100
+ lint. build ( & msg)
101
+ . note ( "if you believe this case to be fine, allow this lint and add a comment explaining your rationale" )
102
+ . emit ( ) ;
103
+ } )
104
+ }
105
+ }
106
+ }
107
+ }
108
+
51
109
declare_tool_lint ! {
52
110
pub rustc:: USAGE_OF_TY_TYKIND ,
53
111
Allow ,
0 commit comments