@@ -2,6 +2,113 @@ import * as vscode from "vscode";
2
2
import * as path from "path" ;
3
3
import { assert } from "../assert" ;
4
4
5
+ /**
6
+ * Demangle JVM method names.
7
+ *
8
+ * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2
9
+ */
10
+ function demangleJVMTypeNames ( mangled : string ) : string [ ] | undefined {
11
+ let arrayCnt = 0 ;
12
+ const types = [ ] as string [ ] ;
13
+ const flushType = ( type : string ) => {
14
+ for ( let i = 0 ; i < arrayCnt ; ++ i ) {
15
+ type += "[]" ;
16
+ }
17
+ types . push ( type ) ;
18
+ arrayCnt = 0 ;
19
+ } ;
20
+ let idx = 0 ;
21
+ while ( idx < mangled . length ) {
22
+ switch ( mangled [ idx ] ) {
23
+ case "B" :
24
+ flushType ( "bool" ) ;
25
+ break ;
26
+ case "C" :
27
+ flushType ( "char" ) ;
28
+ break ;
29
+ case "D" :
30
+ flushType ( "double" ) ;
31
+ break ;
32
+ case "F" :
33
+ flushType ( "float" ) ;
34
+ break ;
35
+ case "I" :
36
+ flushType ( "int" ) ;
37
+ break ;
38
+ case "J" :
39
+ flushType ( "long" ) ;
40
+ break ;
41
+ case "S" :
42
+ flushType ( "short" ) ;
43
+ break ;
44
+ case "Z" :
45
+ flushType ( "boolean" ) ;
46
+ break ;
47
+ case "V" :
48
+ flushType ( "void" ) ;
49
+ break ;
50
+ case "[" :
51
+ ++ arrayCnt ;
52
+ break ;
53
+ case "L" : {
54
+ const startIdx = idx + 1 ;
55
+ while ( idx < mangled . length && mangled [ idx ] !== ";" ) ++ idx ;
56
+ if ( idx === mangled . length ) return undefined ;
57
+ const fullClassName = mangled . substring ( startIdx , idx - startIdx + 1 ) ;
58
+ const shortClassName = fullClassName . split ( "/" ) . pop ( ) ;
59
+ flushType ( shortClassName ) ;
60
+ break ;
61
+ }
62
+ default :
63
+ return undefined ;
64
+ }
65
+ ++ idx ;
66
+ }
67
+ if ( arrayCnt ) return undefined ;
68
+ return types ;
69
+ }
70
+
71
+ function demangleJVMTypeName ( mangled : string ) : string | undefined {
72
+ const demangled = demangleJVMTypeNames ( mangled ) ?? [ ] ;
73
+ if ( demangled . length !== 1 ) return undefined ;
74
+ return demangled [ 0 ] ;
75
+ }
76
+
77
+ /**
78
+ * Demangle JVM method names.
79
+ *
80
+ * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3
81
+ *
82
+ * Examples:
83
+ * ```
84
+ * com/example/myproject/Greeter::<clinit> ()V
85
+ * com/example/myproject/Greeter::<init> ()V
86
+ * com/example/myproject/Greeter::convertStreamToString (Ljava/io/InputStream;)Ljava/lang/String;
87
+ * com/example/myproject/Greeter::hello (Ljava/lang/String;)V
88
+ * com/example/myproject/Greeter::main ([Ljava/lang/String;)V
89
+ * ```
90
+ */
91
+ function demangleJVMMethodName ( mangled : string ) : string | undefined {
92
+ const match = mangled . match (
93
+ // eslint-disable-next-line max-len
94
+ / ^ ( [ \p{ XIDS} \p{ XIDC} / ] + ) : : ( [ \p{ XIDS} \p{ XIDC} < > ] + ) \( ( [ \p{ XIDS} \p{ XIDC} ; / [ ] * ) \) ( [ \p{ XIDS} \p{ XIDC} ; / [ ] * ) $ / u,
95
+ ) ;
96
+ if ( ! match ) return undefined ;
97
+ const fullClassName = match [ 1 ] ;
98
+ const functionName = match [ 2 ] ;
99
+ const mangledArgList = match [ 3 ] ;
100
+ const mangledReturnType = match [ 4 ] ;
101
+
102
+ const shortClassName = fullClassName . split ( "/" ) . pop ( ) ;
103
+ const argList = demangleJVMTypeNames ( mangledArgList ) ;
104
+ if ( ! argList ) return undefined ;
105
+ const argListStr = argList . join ( ", " ) ;
106
+ const returnType = demangleJVMTypeName ( mangledReturnType ) ;
107
+ if ( ! returnType ) return undefined ;
108
+
109
+ return `${ returnType } ${ shortClassName } ::${ functionName } (${ argListStr } )` ;
110
+ }
111
+
5
112
/**
6
113
* Coverage data from a Bazel run.
7
114
*
@@ -111,20 +218,20 @@ export function parseLcov(
111
218
location = new vscode . Position ( startLine , 0 ) ;
112
219
}
113
220
if ( ! info . functionsByLine . has ( startLine ) ) {
114
- // TODO: For Java, C++ and Rust the function names should be demangled .
221
+ // TODO: Also add demangling for C++ and Rust.
115
222
// https://internals.rust-lang.org/t/symbol-mangling-of-rust-vs-c/7222
116
223
// https://github.com/rust-lang/rustc-demangle
117
- // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3
118
224
//
119
225
// Tested with:
120
226
// * Go -> no function names, only line coverage
121
227
// * C++ -> mangled names
122
228
// * Java -> mangled names
123
229
// * Rust -> mangled names
124
230
// Not tested with Python, Swift, Kotlin etc.
231
+ const demangled = demangleJVMMethodName ( funcName ) ?? funcName ;
125
232
info . functionsByLine . set (
126
233
startLine ,
127
- new vscode . DeclarationCoverage ( funcName , 0 , location ) ,
234
+ new vscode . DeclarationCoverage ( demangled , 0 , location ) ,
128
235
) ;
129
236
}
130
237
functionsByName . set ( funcName , info . functionsByLine . get ( startLine ) ) ;
0 commit comments