1+ use super :: mappings:: { AddressableAst , AddressableHir } ;
12use crate :: generated:: MacroCall ;
23use crate :: generated:: { self } ;
34use crate :: trap:: { DiagnosticSeverity , TrapFile , TrapId } ;
45use crate :: trap:: { Label , TrapClass } ;
56use codeql_extractor:: trap:: { self } ;
67use log:: Level ;
8+ use ra_ap_base_db:: CrateOrigin ;
79use ra_ap_hir:: db:: ExpandDatabase ;
8- use ra_ap_hir:: Semantics ;
10+ use ra_ap_hir:: { Adt , ItemContainer , Module , Semantics , Type } ;
11+ use ra_ap_hir_def:: type_ref:: Mutability ;
912use ra_ap_hir_expand:: ExpandTo ;
1013use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
1114use ra_ap_ide_db:: RootDatabase ;
1215use ra_ap_parser:: SyntaxKind ;
1316use ra_ap_span:: { EditionedFileId , TextSize } ;
14- use ra_ap_syntax:: ast:: RangeItem ;
17+ use ra_ap_syntax:: ast:: HasName ;
1518use ra_ap_syntax:: {
1619 ast, AstNode , NodeOrToken , SyntaxElementChildren , SyntaxError , SyntaxNode , SyntaxToken ,
1720 TextRange ,
@@ -20,62 +23,30 @@ use ra_ap_syntax::{
2023#[ macro_export]
2124macro_rules! emit_detached {
2225 ( MacroCall , $self: ident, $node: ident, $label: ident) => {
23- $self. extract_macro_call_expanded( & $node, $label. into ( ) ) ;
26+ $self. extract_macro_call_expanded( & $node, $label) ;
2427 } ;
28+ ( Function , $self: ident, $node: ident, $label: ident) => {
29+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
30+ } ;
31+ ( Trait , $self: ident, $node: ident, $label: ident) => {
32+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
33+ } ;
34+ ( Struct , $self: ident, $node: ident, $label: ident) => {
35+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
36+ } ;
37+ ( Enum , $self: ident, $node: ident, $label: ident) => {
38+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
39+ } ;
40+ ( Union , $self: ident, $node: ident, $label: ident) => {
41+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
42+ } ;
43+ ( Module , $self: ident, $node: ident, $label: ident) => {
44+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
45+ } ;
46+ // TODO canonical origin of other items
2547 ( $( $_: tt) * ) => { } ;
2648}
2749
28- pub trait TextValue {
29- fn try_get_text ( & self ) -> Option < String > ;
30- }
31-
32- impl TextValue for ast:: Lifetime {
33- fn try_get_text ( & self ) -> Option < String > {
34- self . text ( ) . to_string ( ) . into ( )
35- }
36- }
37- impl TextValue for ast:: Name {
38- fn try_get_text ( & self ) -> Option < String > {
39- self . text ( ) . to_string ( ) . into ( )
40- }
41- }
42- impl TextValue for ast:: Literal {
43- fn try_get_text ( & self ) -> Option < String > {
44- self . token ( ) . text ( ) . to_string ( ) . into ( )
45- }
46- }
47- impl TextValue for ast:: NameRef {
48- fn try_get_text ( & self ) -> Option < String > {
49- self . text ( ) . to_string ( ) . into ( )
50- }
51- }
52- impl TextValue for ast:: Abi {
53- fn try_get_text ( & self ) -> Option < String > {
54- self . abi_string ( ) . map ( |x| x. to_string ( ) )
55- }
56- }
57-
58- impl TextValue for ast:: BinExpr {
59- fn try_get_text ( & self ) -> Option < String > {
60- self . op_token ( ) . map ( |x| x. text ( ) . to_string ( ) )
61- }
62- }
63- impl TextValue for ast:: PrefixExpr {
64- fn try_get_text ( & self ) -> Option < String > {
65- self . op_token ( ) . map ( |x| x. text ( ) . to_string ( ) )
66- }
67- }
68- impl TextValue for ast:: RangeExpr {
69- fn try_get_text ( & self ) -> Option < String > {
70- self . op_token ( ) . map ( |x| x. text ( ) . to_string ( ) )
71- }
72- }
73- impl TextValue for ast:: RangePat {
74- fn try_get_text ( & self ) -> Option < String > {
75- self . op_token ( ) . map ( |x| x. text ( ) . to_string ( ) )
76- }
77- }
78-
7950pub struct Translator < ' a > {
8051 pub trap : TrapFile ,
8152 path : & ' a str ,
@@ -325,4 +296,114 @@ impl<'a> Translator<'a> {
325296 ) ;
326297 }
327298 }
299+ fn canonical_path_from_type ( & self , ty : Type ) -> Option < String > {
300+ let sema = self . semantics . as_ref ( ) . unwrap ( ) ;
301+ // rust-analyzer doesn't provide a type enum directly
302+ if let Some ( it) = ty. as_adt ( ) {
303+ return match it {
304+ Adt :: Struct ( it) => self . canonical_path_from_hir ( it) ,
305+ Adt :: Union ( it) => self . canonical_path_from_hir ( it) ,
306+ Adt :: Enum ( it) => self . canonical_path_from_hir ( it) ,
307+ } ;
308+ } ;
309+ if let Some ( ( it, size) ) = ty. as_array ( sema. db ) {
310+ return self
311+ . canonical_path_from_type ( it)
312+ . map ( |p| format ! ( "[{p}; {size}]" ) ) ;
313+ }
314+ if let Some ( it) = ty. as_slice ( ) {
315+ return self
316+ . canonical_path_from_type ( it)
317+ . map ( |p| format ! ( "[{}]" , p) ) ;
318+ }
319+ if let Some ( it) = ty. as_builtin ( ) {
320+ return Some ( it. name ( ) . as_str ( ) . to_owned ( ) ) ;
321+ }
322+ if let Some ( it) = ty. as_dyn_trait ( ) {
323+ return self . canonical_path_from_hir ( it) . map ( |p| format ! ( "dyn {p}" ) ) ;
324+ }
325+ if let Some ( ( it, mutability) ) = ty. as_reference ( ) {
326+ let mut_str = match mutability {
327+ Mutability :: Shared => "" ,
328+ Mutability :: Mut => "mut " ,
329+ } ;
330+ return self
331+ . canonical_path_from_type ( it)
332+ . map ( |p| format ! ( "&{mut_str}{p}" ) ) ;
333+ }
334+ if let Some ( it) = ty. as_impl_traits ( sema. db ) {
335+ let paths = it
336+ . map ( |t| self . canonical_path_from_hir ( t) )
337+ . collect :: < Option < Vec < _ > > > ( ) ?;
338+ return Some ( format ! ( "impl {}" , paths. join( " + " ) ) ) ;
339+ }
340+ if let Some ( _) = ty. as_type_param ( sema. db ) {
341+ // from the canonical path perspective, we just want a special name
342+ // e.g. `crate::<_ as SomeTrait>::func`
343+ return Some ( "_" . to_owned ( ) ) ;
344+ }
345+ None
346+ }
347+
348+ fn canonical_path_from_hir_module ( & self , item : Module ) -> Option < String > {
349+ if item. is_crate_root ( ) {
350+ return Some ( "crate" . into ( ) ) ;
351+ }
352+ self . canonical_path_from_hir :: < ast:: Module > ( item)
353+ }
354+
355+ fn canonical_path_from_hir < T : AstNode > ( & self , item : impl AddressableHir < T > ) -> Option < String > {
356+ // if we have a Hir entity, it means we have semantics
357+ let sema = self . semantics . as_ref ( ) . unwrap ( ) ;
358+ let name = item. name ( sema) ?;
359+ let container = item. container ( sema. db ) ;
360+ let prefix = match container {
361+ ItemContainer :: Trait ( it) => self . canonical_path_from_hir ( it) ,
362+ ItemContainer :: Impl ( it) => {
363+ let ty = self . canonical_path_from_type ( it. self_ty ( sema. db ) ) ?;
364+ if let Some ( trait_) = it. trait_ ( sema. db ) {
365+ let tr = self . canonical_path_from_hir ( trait_) ?;
366+ Some ( format ! ( "<{ty} as {tr}>" ) )
367+ } else {
368+ Some ( format ! ( "<{ty}>" ) )
369+ }
370+ }
371+ ItemContainer :: Module ( it) => self . canonical_path_from_hir_module ( it) ,
372+ ItemContainer :: ExternBlock ( ) | ItemContainer :: Crate ( _) => Some ( "" . to_owned ( ) ) ,
373+ } ?;
374+ Some ( format ! ( "{prefix}::{name}" ) )
375+ }
376+
377+ fn origin_from_hir < T : AstNode > ( & self , item : impl AddressableHir < T > ) -> String {
378+ // if we have a Hir entity, it means we have semantics
379+ let sema = self . semantics . as_ref ( ) . unwrap ( ) ;
380+ match item. module ( sema) . krate ( ) . origin ( sema. db ) {
381+ CrateOrigin :: Rustc { name } => format ! ( "rustc:{}" , name) ,
382+ CrateOrigin :: Local { repo, name } => format ! (
383+ "repo:{}:{}" ,
384+ repo. unwrap_or_default( ) ,
385+ name. map( |s| s. as_str( ) . to_owned( ) ) . unwrap_or_default( )
386+ ) ,
387+ CrateOrigin :: Library { repo, name } => {
388+ format ! ( "repo:{}:{}" , repo. unwrap_or_default( ) , name)
389+ }
390+ CrateOrigin :: Lang ( it) => format ! ( "lang:{}" , it) ,
391+ }
392+ }
393+
394+ pub ( crate ) fn extract_canonical_origin < T : AddressableAst + HasName > (
395+ & mut self ,
396+ item : & T ,
397+ label : Label < generated:: Item > ,
398+ ) {
399+ ( || {
400+ let sema = self . semantics . as_ref ( ) ?;
401+ let def = T :: Hir :: try_from_source ( item, sema) ?;
402+ let path = self . canonical_path_from_hir ( def) ?;
403+ let origin = self . origin_from_hir ( def) ;
404+ generated:: Item :: emit_crate_origin ( label, origin, & mut self . trap . writer ) ;
405+ generated:: Item :: emit_canonical_path ( label, path, & mut self . trap . writer ) ;
406+ Some ( ( ) )
407+ } ) ( ) ;
408+ }
328409}
0 commit comments