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:: CrateOrigin ;
7
9
use 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 ;
9
12
use ra_ap_hir_expand:: ExpandTo ;
10
13
use ra_ap_ide_db:: line_index:: { LineCol , LineIndex } ;
11
14
use ra_ap_ide_db:: RootDatabase ;
12
15
use ra_ap_parser:: SyntaxKind ;
13
16
use ra_ap_span:: { EditionedFileId , TextSize } ;
14
- use ra_ap_syntax:: ast:: RangeItem ;
17
+ use ra_ap_syntax:: ast:: HasName ;
15
18
use ra_ap_syntax:: {
16
19
ast, AstNode , NodeOrToken , SyntaxElementChildren , SyntaxError , SyntaxNode , SyntaxToken ,
17
20
TextRange ,
@@ -20,62 +23,30 @@ use ra_ap_syntax::{
20
23
#[ macro_export]
21
24
macro_rules! emit_detached {
22
25
( MacroCall , $self: ident, $node: ident, $label: ident) => {
23
- $self. extract_macro_call_expanded( & $node, $label. into ( ) ) ;
26
+ $self. extract_macro_call_expanded( & $node, $label) ;
24
27
} ;
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
25
47
( $( $_: tt) * ) => { } ;
26
48
}
27
49
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
50
pub struct Translator < ' a > {
80
51
pub trap : TrapFile ,
81
52
path : & ' a str ,
@@ -325,4 +296,114 @@ impl<'a> Translator<'a> {
325
296
) ;
326
297
}
327
298
}
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
+ }
328
409
}
0 commit comments