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:: salsa:: InternKey ;
9+ use ra_ap_base_db:: CrateOrigin ;
710use ra_ap_hir:: db:: ExpandDatabase ;
8- use ra_ap_hir:: Semantics ;
11+ use ra_ap_hir:: { Adt , ItemContainer , Module , Semantics , Type } ;
12+ use ra_ap_hir_def:: type_ref:: Mutability ;
13+ use ra_ap_hir_def:: ModuleId ;
914use ra_ap_hir_expand:: ExpandTo ;
1015use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
1116use ra_ap_ide_db:: RootDatabase ;
1217use ra_ap_parser:: SyntaxKind ;
1318use ra_ap_span:: { EditionedFileId , TextSize } ;
14- use ra_ap_syntax:: ast:: RangeItem ;
19+ use ra_ap_syntax:: ast:: HasName ;
1520use ra_ap_syntax:: {
1621 ast, AstNode , NodeOrToken , SyntaxElementChildren , SyntaxError , SyntaxNode , SyntaxToken ,
1722 TextRange ,
@@ -20,62 +25,30 @@ use ra_ap_syntax::{
2025#[ macro_export]
2126macro_rules! emit_detached {
2227 ( MacroCall , $self: ident, $node: ident, $label: ident) => {
23- $self. extract_macro_call_expanded( & $node, $label. into ( ) ) ;
28+ $self. extract_macro_call_expanded( & $node, $label) ;
2429 } ;
30+ ( Function , $self: ident, $node: ident, $label: ident) => {
31+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
32+ } ;
33+ ( Trait , $self: ident, $node: ident, $label: ident) => {
34+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
35+ } ;
36+ ( Struct , $self: ident, $node: ident, $label: ident) => {
37+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
38+ } ;
39+ ( Enum , $self: ident, $node: ident, $label: ident) => {
40+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
41+ } ;
42+ ( Union , $self: ident, $node: ident, $label: ident) => {
43+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
44+ } ;
45+ ( Module , $self: ident, $node: ident, $label: ident) => {
46+ $self. extract_canonical_origin( & $node, $label. into( ) ) ;
47+ } ;
48+ // TODO canonical origin of other items
2549 ( $( $_: tt) * ) => { } ;
2650}
2751
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-
7952pub struct Translator < ' a > {
8053 pub trap : TrapFile ,
8154 path : & ' a str ,
@@ -325,4 +298,118 @@ impl<'a> Translator<'a> {
325298 ) ;
326299 }
327300 }
301+ fn canonical_path_from_type ( & self , ty : Type ) -> Option < String > {
302+ let sema = self . semantics . as_ref ( ) . unwrap ( ) ;
303+ // rust-analyzer doesn't provide a type enum directly
304+ if let Some ( it) = ty. as_adt ( ) {
305+ return match it {
306+ Adt :: Struct ( it) => self . canonical_path_from_hir ( it) ,
307+ Adt :: Union ( it) => self . canonical_path_from_hir ( it) ,
308+ Adt :: Enum ( it) => self . canonical_path_from_hir ( it) ,
309+ } ;
310+ } ;
311+ if let Some ( ( it, size) ) = ty. as_array ( sema. db ) {
312+ return self
313+ . canonical_path_from_type ( it)
314+ . map ( |p| format ! ( "[{p}; {size}]" ) ) ;
315+ }
316+ if let Some ( it) = ty. as_slice ( ) {
317+ return self
318+ . canonical_path_from_type ( it)
319+ . map ( |p| format ! ( "[{}]" , p) ) ;
320+ }
321+ if let Some ( it) = ty. as_builtin ( ) {
322+ return Some ( it. name ( ) . as_str ( ) . to_owned ( ) ) ;
323+ }
324+ if let Some ( it) = ty. as_dyn_trait ( ) {
325+ return self . canonical_path_from_hir ( it) . map ( |p| format ! ( "dyn {p}" ) ) ;
326+ }
327+ if let Some ( ( it, mutability) ) = ty. as_reference ( ) {
328+ let mut_str = match mutability {
329+ Mutability :: Shared => "" ,
330+ Mutability :: Mut => "mut " ,
331+ } ;
332+ return self
333+ . canonical_path_from_type ( it)
334+ . map ( |p| format ! ( "&{mut_str}{p}" ) ) ;
335+ }
336+ if let Some ( it) = ty. as_impl_traits ( sema. db ) {
337+ let paths = it
338+ . map ( |t| self . canonical_path_from_hir ( t) )
339+ . collect :: < Option < Vec < _ > > > ( ) ?;
340+ return Some ( format ! ( "impl {}" , paths. join( " + " ) ) ) ;
341+ }
342+ if ty. as_type_param ( sema. db ) . is_some ( ) {
343+ // from the canonical path perspective, we just want a special name
344+ // e.g. `crate::<_ as SomeTrait>::func`
345+ return Some ( "_" . to_owned ( ) ) ;
346+ }
347+ None
348+ }
349+
350+ fn canonical_path_from_hir_module ( & self , item : Module ) -> Option < String > {
351+ if let Some ( block_id) = ModuleId :: from ( item) . containing_block ( ) {
352+ // this means this is a block module, i.e. a virtual module for a block scope
353+ return Some ( format ! ( "{{{}}}" , block_id. as_intern_id( ) ) ) ;
354+ }
355+ if item. is_crate_root ( ) {
356+ return Some ( "crate" . into ( ) ) ;
357+ }
358+ self . canonical_path_from_hir :: < ast:: Module > ( item)
359+ }
360+
361+ fn canonical_path_from_hir < T : AstNode > ( & self , item : impl AddressableHir < T > ) -> Option < String > {
362+ // if we have a Hir entity, it means we have semantics
363+ let sema = self . semantics . as_ref ( ) . unwrap ( ) ;
364+ let name = item. name ( sema) ?;
365+ let container = item. container ( sema. db ) ;
366+ let prefix = match container {
367+ ItemContainer :: Trait ( it) => self . canonical_path_from_hir ( it) ,
368+ ItemContainer :: Impl ( it) => {
369+ let ty = self . canonical_path_from_type ( it. self_ty ( sema. db ) ) ?;
370+ if let Some ( trait_) = it. trait_ ( sema. db ) {
371+ let tr = self . canonical_path_from_hir ( trait_) ?;
372+ Some ( format ! ( "<{ty} as {tr}>" ) )
373+ } else {
374+ Some ( format ! ( "<{ty}>" ) )
375+ }
376+ }
377+ ItemContainer :: Module ( it) => self . canonical_path_from_hir_module ( it) ,
378+ ItemContainer :: ExternBlock ( ) | ItemContainer :: Crate ( _) => Some ( "" . to_owned ( ) ) ,
379+ } ?;
380+ Some ( format ! ( "{prefix}::{name}" ) )
381+ }
382+
383+ fn origin_from_hir < T : AstNode > ( & self , item : impl AddressableHir < T > ) -> String {
384+ // if we have a Hir entity, it means we have semantics
385+ let sema = self . semantics . as_ref ( ) . unwrap ( ) ;
386+ match item. module ( sema) . krate ( ) . origin ( sema. db ) {
387+ CrateOrigin :: Rustc { name } => format ! ( "rustc:{}" , name) ,
388+ CrateOrigin :: Local { repo, name } => format ! (
389+ "repo:{}:{}" ,
390+ repo. unwrap_or_default( ) ,
391+ name. map( |s| s. as_str( ) . to_owned( ) ) . unwrap_or_default( )
392+ ) ,
393+ CrateOrigin :: Library { repo, name } => {
394+ format ! ( "repo:{}:{}" , repo. unwrap_or_default( ) , name)
395+ }
396+ CrateOrigin :: Lang ( it) => format ! ( "lang:{}" , it) ,
397+ }
398+ }
399+
400+ pub ( crate ) fn extract_canonical_origin < T : AddressableAst + HasName > (
401+ & mut self ,
402+ item : & T ,
403+ label : Label < generated:: Item > ,
404+ ) {
405+ ( || {
406+ let sema = self . semantics . as_ref ( ) ?;
407+ let def = T :: Hir :: try_from_source ( item, sema) ?;
408+ let path = self . canonical_path_from_hir ( def) ?;
409+ let origin = self . origin_from_hir ( def) ;
410+ generated:: Item :: emit_crate_origin ( label, origin, & mut self . trap . writer ) ;
411+ generated:: Item :: emit_extended_canonical_path ( label, path, & mut self . trap . writer ) ;
412+ Some ( ( ) )
413+ } ) ( ) ;
414+ }
328415}
0 commit comments