1
+ use crate :: consts:: { constant_simple, Constant } ;
1
2
use crate :: utils:: {
2
3
is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints,
3
4
snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq ,
@@ -14,9 +15,11 @@ use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
14
15
use rustc_hir:: { Crate , Expr , ExprKind , HirId , Item , MutTy , Mutability , Node , Path , StmtKind , Ty , TyKind } ;
15
16
use rustc_lint:: { EarlyContext , EarlyLintPass , LateContext , LateLintPass } ;
16
17
use rustc_middle:: hir:: map:: Map ;
18
+ use rustc_middle:: ty;
17
19
use rustc_session:: { declare_lint_pass, declare_tool_lint, impl_lint_pass} ;
18
20
use rustc_span:: source_map:: { Span , Spanned } ;
19
21
use rustc_span:: symbol:: { Symbol , SymbolStr } ;
22
+ use rustc_typeck:: hir_ty_to_ty;
20
23
21
24
use std:: borrow:: { Borrow , Cow } ;
22
25
@@ -229,6 +232,21 @@ declare_clippy_lint! {
229
232
"using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
230
233
}
231
234
235
+ declare_clippy_lint ! {
236
+ /// **What it does:**
237
+ /// Checks the paths module for invalid paths.
238
+ ///
239
+ /// **Why is this bad?**
240
+ /// It indicates a bug in the code.
241
+ ///
242
+ /// **Known problems:** None.
243
+ ///
244
+ /// **Example:** None.
245
+ pub INVALID_PATHS ,
246
+ internal,
247
+ "invalid path"
248
+ }
249
+
232
250
declare_lint_pass ! ( ClippyLintsInternal => [ CLIPPY_LINTS_INTERNAL ] ) ;
233
251
234
252
impl EarlyLintPass for ClippyLintsInternal {
@@ -761,3 +779,64 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
761
779
762
780
None
763
781
}
782
+
783
+ // This is not a complete resolver for paths. It works on all the paths currently used in the paths
784
+ // module. That's all it does and all it needs to do.
785
+ pub fn check_path ( cx : & LateContext < ' _ > , path : & [ & str ] ) -> bool {
786
+ if path_to_res ( cx, path) . is_some ( ) {
787
+ return true ;
788
+ }
789
+
790
+ // Some implementations can't be found by `path_to_res`, particularly inherent
791
+ // implementations of native types. Check lang items.
792
+ let path_syms: Vec < _ > = path. iter ( ) . map ( |p| Symbol :: intern ( p) ) . collect ( ) ;
793
+ let lang_items = cx. tcx . lang_items ( ) ;
794
+ for lang_item in lang_items. items ( ) {
795
+ if let Some ( def_id) = lang_item {
796
+ let lang_item_path = cx. get_def_path ( * def_id) ;
797
+ if path_syms. starts_with ( & lang_item_path) {
798
+ if let [ item] = & path_syms[ lang_item_path. len ( ) ..] {
799
+ for child in cx. tcx . item_children ( * def_id) {
800
+ if child. ident . name == * item {
801
+ return true ;
802
+ }
803
+ }
804
+ }
805
+ }
806
+ }
807
+ }
808
+
809
+ false
810
+ }
811
+
812
+ declare_lint_pass ! ( InvalidPaths => [ INVALID_PATHS ] ) ;
813
+
814
+ impl < ' tcx > LateLintPass < ' tcx > for InvalidPaths {
815
+ fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' _ > ) {
816
+ let local_def_id = & cx. tcx . parent_module ( item. hir_id ) ;
817
+ let mod_name = & cx. tcx . item_name ( local_def_id. to_def_id ( ) ) ;
818
+ if_chain ! {
819
+ if mod_name. as_str( ) == "paths" ;
820
+ if let hir:: ItemKind :: Const ( ty, body_id) = item. kind;
821
+ let ty = hir_ty_to_ty( cx. tcx, ty) ;
822
+ if let ty:: Array ( el_ty, _) = & ty. kind( ) ;
823
+ if let ty:: Ref ( _, el_ty, _) = & el_ty. kind( ) ;
824
+ if el_ty. is_str( ) ;
825
+ let body = cx. tcx. hir( ) . body( body_id) ;
826
+ let typeck_results = cx. tcx. typeck_body( body_id) ;
827
+ if let Some ( Constant :: Vec ( path) ) = constant_simple( cx, typeck_results, & body. value) ;
828
+ let path: Vec <& str > = path. iter( ) . map( |x| {
829
+ if let Constant :: Str ( s) = x {
830
+ s. as_str( )
831
+ } else {
832
+ // We checked the type of the constant above
833
+ unreachable!( )
834
+ }
835
+ } ) . collect( ) ;
836
+ if !check_path( cx, & path[ ..] ) ;
837
+ then {
838
+ span_lint( cx, CLIPPY_LINTS_INTERNAL , item. span, "invalid path" ) ;
839
+ }
840
+ }
841
+ }
842
+ }
0 commit comments