1
+ use super :: mappings:: { AddressableAst , AddressableHir } ;
1
2
use crate :: generated:: MacroCall ;
2
3
use crate :: generated:: { self } ;
3
4
use crate :: trap:: { DiagnosticSeverity , TrapFile , TrapId } ;
4
5
use crate :: trap:: { Label , TrapClass } ;
5
6
use codeql_extractor:: trap:: { self } ;
6
7
use log:: Level ;
8
+ use ra_ap_base_db:: salsa:: InternKey ;
9
+ use ra_ap_base_db:: CrateOrigin ;
7
10
use 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 ;
9
14
use ra_ap_hir_expand:: ExpandTo ;
10
15
use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
11
16
use ra_ap_ide_db:: RootDatabase ;
12
17
use ra_ap_parser:: SyntaxKind ;
13
18
use ra_ap_span:: { EditionedFileId , TextSize } ;
14
- use ra_ap_syntax:: ast:: RangeItem ;
19
+ use ra_ap_syntax:: ast:: HasName ;
15
20
use ra_ap_syntax:: {
16
21
ast, AstNode , NodeOrToken , SyntaxElementChildren , SyntaxError , SyntaxNode , SyntaxToken ,
17
22
TextRange ,
@@ -20,62 +25,30 @@ use ra_ap_syntax::{
20
25
#[ macro_export]
21
26
macro_rules! emit_detached {
22
27
( MacroCall , $self: ident, $node: ident, $label: ident) => {
23
- $self. extract_macro_call_expanded( & $node, $label. into ( ) ) ;
28
+ $self. extract_macro_call_expanded( & $node, $label) ;
24
29
} ;
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
25
49
( $( $_: tt) * ) => { } ;
26
50
}
27
51
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
-
79
52
pub struct Translator < ' a > {
80
53
pub trap : TrapFile ,
81
54
path : & ' a str ,
@@ -325,4 +298,118 @@ impl<'a> Translator<'a> {
325
298
) ;
326
299
}
327
300
}
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
+ }
328
415
}
0 commit comments