Skip to content

Commit 9362f57

Browse files
Ensure that calls to methods without parameter list are instrumented
1 parent 8d2f6c0 commit 9362f57

File tree

4 files changed

+302
-1
lines changed

4 files changed

+302
-1
lines changed

compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,17 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
118118
instrument(tree)
119119
else
120120
val transformed = cpy.Select(tree)(transform(qual), name)
121-
if transformed.qualifier.isDef then
121+
if transformed.symbol.is(Method) then
122122
// instrument calls to methods without parameter list
123123
instrument(transformed)
124124
else
125125
transformed
126126

127+
// f
128+
case tree: Ident if tree.symbol.is(Method) =>
129+
// instrument calls to method without parameter list
130+
instrument(tree)
131+
127132
case tree: CaseDef => instrumentCaseDef(tree)
128133
case tree: ValDef =>
129134
// only transform the rhs

compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala

+3
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,13 @@ object LiftCoverage extends LiftImpure {
177177
* - all the impure arguments
178178
*
179179
* There's no need to lift the other arguments.
180+
* Note: at the instrumentCoverage phase, calls to functions that have no parameter list aren't Apply,
181+
* but Ident (e.g. `f` with f in scope) or Select (e.g. `A.f`).
180182
*/
181183
private def noLiftArg(arg: tpd.Tree)(using Context): Boolean =
182184
arg match
183185
case a: tpd.Apply => a.symbol.is(Erased) // don't lift erased applications, but lift all others
186+
case s: (tpd.Select | tpd.Ident) if s.symbol.is(Method) => s.symbol.is(Erased) // take care of calls to functions without parameter lists
184187
case tpd.Block(stats, expr) => stats.forall(noLiftArg) && noLiftArg(expr)
185188
case tpd.Inlined(_, bindings, expr) => noLiftArg(expr)
186189
case tpd.Typed(expr, _) => noLiftArg(expr)

tests/coverage/pos/NoParams.scala

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
object A:
2+
def noParam = 0
3+
4+
object B:
5+
def f(x: Any) = println("f")
6+
def noParam = 0
7+
8+
def testSelect =
9+
A.noParam // call should be instrumented
10+
11+
def testSelectArg =
12+
f(A.noParam) // arg should be lifted and instrumented
13+
14+
def testIdent =
15+
noParam // call should be instrumented
16+
17+
def testIdentArg =
18+
f(noParam) // arg should be lifted and instrumented
+275
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
# Coverage data, format version: 3.0
2+
# Statement data:
3+
# - id
4+
# - source path
5+
# - package name
6+
# - class name
7+
# - class type (Class, Object or Trait)
8+
# - full class name
9+
# - method name
10+
# - start offset
11+
# - end offset
12+
# - line number
13+
# - symbol name
14+
# - tree name
15+
# - is branch
16+
# - invocations count
17+
# - is ignored
18+
# - description (can be multi-line)
19+
# ' ' sign
20+
# ------------------------------------------
21+
0
22+
NoParams.scala
23+
<empty>
24+
A$
25+
Object
26+
<empty>.A$
27+
noParam
28+
12
29+
23
30+
1
31+
noParam
32+
DefDef
33+
false
34+
0
35+
false
36+
def noParam
37+
38+
1
39+
NoParams.scala
40+
<empty>
41+
B$
42+
Object
43+
<empty>.B$
44+
f
45+
57
46+
64
47+
4
48+
println
49+
Ident
50+
false
51+
0
52+
false
53+
println
54+
55+
2
56+
NoParams.scala
57+
<empty>
58+
B$
59+
Object
60+
<empty>.B$
61+
f
62+
57
63+
69
64+
4
65+
<none>
66+
Apply
67+
false
68+
0
69+
false
70+
println("f")
71+
72+
3
73+
NoParams.scala
74+
<empty>
75+
B$
76+
Object
77+
<empty>.B$
78+
f
79+
41
80+
46
81+
4
82+
f
83+
DefDef
84+
false
85+
0
86+
false
87+
def f
88+
89+
4
90+
NoParams.scala
91+
<empty>
92+
B$
93+
Object
94+
<empty>.B$
95+
noParam
96+
72
97+
83
98+
5
99+
noParam
100+
DefDef
101+
false
102+
0
103+
false
104+
def noParam
105+
106+
5
107+
NoParams.scala
108+
<empty>
109+
B$
110+
Object
111+
<empty>.B$
112+
testSelect
113+
112
114+
121
115+
8
116+
noParam
117+
Select
118+
false
119+
0
120+
false
121+
A.noParam
122+
123+
6
124+
NoParams.scala
125+
<empty>
126+
B$
127+
Object
128+
<empty>.B$
129+
testSelect
130+
91
131+
105
132+
7
133+
testSelect
134+
DefDef
135+
false
136+
0
137+
false
138+
def testSelect
139+
140+
7
141+
NoParams.scala
142+
<empty>
143+
B$
144+
Object
145+
<empty>.B$
146+
testSelectArg
147+
182
148+
191
149+
11
150+
noParam
151+
Select
152+
false
153+
0
154+
false
155+
A.noParam
156+
157+
8
158+
NoParams.scala
159+
<empty>
160+
B$
161+
Object
162+
<empty>.B$
163+
testSelectArg
164+
180
165+
192
166+
11
167+
f
168+
Apply
169+
false
170+
0
171+
false
172+
f(A.noParam)
173+
174+
9
175+
NoParams.scala
176+
<empty>
177+
B$
178+
Object
179+
<empty>.B$
180+
testSelectArg
181+
156
182+
173
183+
10
184+
testSelectArg
185+
DefDef
186+
false
187+
0
188+
false
189+
def testSelectArg
190+
191+
10
192+
NoParams.scala
193+
<empty>
194+
B$
195+
Object
196+
<empty>.B$
197+
testIdent
198+
257
199+
264
200+
14
201+
noParam
202+
Ident
203+
false
204+
0
205+
false
206+
noParam
207+
208+
11
209+
NoParams.scala
210+
<empty>
211+
B$
212+
Object
213+
<empty>.B$
214+
testIdent
215+
237
216+
250
217+
13
218+
testIdent
219+
DefDef
220+
false
221+
0
222+
false
223+
def testIdent
224+
225+
12
226+
NoParams.scala
227+
<empty>
228+
B$
229+
Object
230+
<empty>.B$
231+
testIdentArg
232+
324
233+
331
234+
17
235+
noParam
236+
Ident
237+
false
238+
0
239+
false
240+
noParam
241+
242+
13
243+
NoParams.scala
244+
<empty>
245+
B$
246+
Object
247+
<empty>.B$
248+
testIdentArg
249+
322
250+
332
251+
17
252+
f
253+
Apply
254+
false
255+
0
256+
false
257+
f(noParam)
258+
259+
14
260+
NoParams.scala
261+
<empty>
262+
B$
263+
Object
264+
<empty>.B$
265+
testIdentArg
266+
299
267+
315
268+
16
269+
testIdentArg
270+
DefDef
271+
false
272+
0
273+
false
274+
def testIdentArg
275+

0 commit comments

Comments
 (0)