Skip to content

Commit 5cadc06

Browse files
committed
Warn on unqualified top-level calls to Any or AnyRef methods
1 parent 872c69f commit 5cadc06

File tree

5 files changed

+199
-119
lines changed

5 files changed

+199
-119
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
194194
case MissingArgumentListID // errorNumber: 178
195195
case MatchTypeScrutineeCannotBeHigherKindedID // errorNumber: 179
196196
case AmbiguousExtensionMethodID // errorNumber 180
197-
case CallToAnyRefMethodOnPredefID // errorNumber: 181
198-
case CallToAnyRefMethodOnPackageObjectID // errorNumber: 182
197+
case UnqualifiedCallToAnyRefMethodID // errorNumber: 181
199198

200199
def errorNumber = ordinal - 1
201200

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,23 +2284,14 @@ class PureExpressionInStatementPosition(stat: untpd.Tree, val exprOwner: Symbol)
22842284
|It can be removed without changing the semantics of the program. This may indicate an error."""
22852285
}
22862286

2287-
class CallToAnyRefMethodOnPredef(stat: untpd.Tree, method: Symbol)(using Context)
2288-
extends Message(CallToAnyRefMethodOnPredefID) {
2287+
class UnqualifiedCallToAnyRefMethod(stat: untpd.Tree, method: Symbol)(using Context)
2288+
extends Message(UnqualifiedCallToAnyRefMethodID) {
22892289
def kind = MessageKind.PotentialIssue
2290-
def msg(using Context) = i"Suspicious call to ${hl("Predef." + method.name)}"
2290+
def msg(using Context) = i"Suspicious top-level unqualified call to ${hl(method.name.toString)}"
22912291
def explain(using Context) =
22922292
i"""Top-level unqualified calls to ${hl("AnyRef")} or ${hl("Any")} methods such as ${hl(method.name.toString)} are
2293-
|resolved to calls on ${hl("Predef")}. This might not be what you intended."""
2294-
}
2295-
2296-
class CallToAnyRefMethodOnPackageObject(stat: untpd.Tree, method: Symbol)(using Context)
2297-
extends Message(CallToAnyRefMethodOnPackageObjectID) {
2298-
def kind = MessageKind.PotentialIssue
2299-
def msg(using Context) = i"Suspicious top-level call to ${hl("this." + method.name)}"
2300-
def explain(using Context) =
2301-
i"""Top-level calls to ${hl("AnyRef")} or ${hl("Any")} methods are resolved to calls on the
2302-
|synthetic package object generated for the current file. This might not be
2303-
|what you intended."""
2293+
|resolved to calls on ${hl("Predef")} or on imported methods. This might not be what
2294+
|you intended."""
23042295
}
23052296

23062297
class TraitCompanionWithMutableStatic()(using Context)

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

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,16 +1090,11 @@ object RefChecks {
10901090

10911091
end checkImplicitNotFoundAnnotation
10921092

1093-
def checkSynchronizedCall(tree: Tree, symbol: Symbol)(using Context) =
1094-
if symbol.exists && defn.topClasses.contains(symbol.owner) then
1095-
tree.tpe match
1096-
case tp: NamedType =>
1097-
val prefixSymbol = tp.prefix.typeSymbol
1098-
if prefixSymbol == defn.ScalaPredefModuleClass then
1099-
report.warning(CallToAnyRefMethodOnPredef(tree, symbol), tree)
1100-
if prefixSymbol.isPackageObject && !tp.symbol.isConstructor then
1101-
report.warning(CallToAnyRefMethodOnPackageObject(tree, symbol), tree)
1102-
case _ => ()
1093+
def checkAnyRefMethodCall(tree: Tree)(using Context) =
1094+
if tree.symbol.exists
1095+
&& defn.topClasses.contains(tree.symbol.owner)
1096+
&& (!ctx.owner.enclosingClass.exists || ctx.owner.enclosingClass.isPackageObject) then
1097+
report.warning(UnqualifiedCallToAnyRefMethod(tree, tree.symbol), tree)
11031098

11041099
}
11051100
import RefChecks._
@@ -1180,12 +1175,8 @@ class RefChecks extends MiniPhase { thisPhase =>
11801175
tree
11811176
}
11821177

1183-
override def transformSelect(tree: Select)(using Context): Tree =
1184-
checkSynchronizedCall(tree, tree.denot.symbol)
1185-
tree
1186-
11871178
override def transformIdent(tree: Ident)(using Context): Tree =
1188-
checkSynchronizedCall(tree, tree.symbol)
1179+
checkAnyRefMethodCall(tree)
11891180
tree
11901181

11911182
}

tests/neg/i17266.check

Lines changed: 76 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,88 @@
11
-- [E181] Potential Issue Error: tests/neg/i17266.scala:4:2 ------------------------------------------------------------
22
4 | synchronized { // error
33
| ^^^^^^^^^^^^
4-
| Suspicious call to Predef.synchronized
4+
| Suspicious top-level unqualified call to synchronized
55
|---------------------------------------------------------------------------------------------------------------------
66
| Explanation (enabled by `-explain`)
77
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
88
| Top-level unqualified calls to AnyRef or Any methods such as synchronized are
9-
| resolved to calls on Predef. This might not be what you intended.
9+
| resolved to calls on Predef or on imported methods. This might not be what
10+
| you intended.
1011
---------------------------------------------------------------------------------------------------------------------
11-
-- [E182] Potential Issue Error: tests/neg/i17266.scala:9:7 ------------------------------------------------------------
12-
9 | this.synchronized { // error
13-
| ^^^^^^^^^^^^^^^^^
14-
| Suspicious top-level call to this.synchronized
15-
|---------------------------------------------------------------------------------------------------------------------
16-
| Explanation (enabled by `-explain`)
17-
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
18-
| Top-level calls to AnyRef or Any methods are resolved to calls on the
19-
| synthetic package object generated for the current file. This might not be
20-
| what you intended.
21-
---------------------------------------------------------------------------------------------------------------------
22-
-- [E181] Potential Issue Error: tests/neg/i17266.scala:22:2 -----------------------------------------------------------
23-
22 | wait() // error
24-
| ^^^^
25-
| Suspicious call to Predef.wait
26-
|--------------------------------------------------------------------------------------------------------------------
27-
| Explanation (enabled by `-explain`)
28-
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29-
| Top-level unqualified calls to AnyRef or Any methods such as wait are
30-
| resolved to calls on Predef. This might not be what you intended.
31-
--------------------------------------------------------------------------------------------------------------------
32-
-- [E182] Potential Issue Error: tests/neg/i17266.scala:25:7 -----------------------------------------------------------
33-
25 | this.wait() // error
34-
| ^^^^^^^^^
35-
| Suspicious top-level call to this.wait
36-
|--------------------------------------------------------------------------------------------------------------------
37-
| Explanation (enabled by `-explain`)
38-
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
39-
| Top-level calls to AnyRef or Any methods are resolved to calls on the
40-
| synthetic package object generated for the current file. This might not be
41-
| what you intended.
42-
--------------------------------------------------------------------------------------------------------------------
43-
-- [E181] Potential Issue Error: tests/neg/i17266.scala:32:2 -----------------------------------------------------------
44-
32 | wait(10) // error
45-
| ^^^^
46-
| Suspicious call to Predef.wait
47-
|--------------------------------------------------------------------------------------------------------------------
48-
| Explanation (enabled by `-explain`)
49-
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
50-
| Top-level unqualified calls to AnyRef or Any methods such as wait are
51-
| resolved to calls on Predef. This might not be what you intended.
52-
--------------------------------------------------------------------------------------------------------------------
53-
-- [E182] Potential Issue Error: tests/neg/i17266.scala:35:7 -----------------------------------------------------------
54-
35 | this.wait(10) // error
55-
| ^^^^^^^^^
56-
| Suspicious top-level call to this.wait
57-
|--------------------------------------------------------------------------------------------------------------------
58-
| Explanation (enabled by `-explain`)
59-
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
60-
| Top-level calls to AnyRef or Any methods are resolved to calls on the
61-
| synthetic package object generated for the current file. This might not be
62-
| what you intended.
63-
--------------------------------------------------------------------------------------------------------------------
64-
-- [E181] Potential Issue Error: tests/neg/i17266.scala:42:2 -----------------------------------------------------------
65-
42 | hashCode() // error
66-
| ^^^^^^^^
67-
| Suspicious call to Predef.hashCode
68-
|--------------------------------------------------------------------------------------------------------------------
69-
| Explanation (enabled by `-explain`)
70-
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71-
| Top-level unqualified calls to AnyRef or Any methods such as hashCode are
72-
| resolved to calls on Predef. This might not be what you intended.
73-
--------------------------------------------------------------------------------------------------------------------
74-
-- [E182] Potential Issue Error: tests/neg/i17266.scala:45:7 -----------------------------------------------------------
75-
45 | this.hashCode() // error
76-
| ^^^^^^^^^^^^^
77-
| Suspicious top-level call to this.hashCode
12+
-- [E181] Potential Issue Error: tests/neg/i17266.scala:17:2 -----------------------------------------------------------
13+
17 | synchronized { // error
14+
| ^^^^^^^^^^^^
15+
| Suspicious top-level unqualified call to synchronized
7816
|--------------------------------------------------------------------------------------------------------------------
7917
| Explanation (enabled by `-explain`)
8018
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
81-
| Top-level calls to AnyRef or Any methods are resolved to calls on the
82-
| synthetic package object generated for the current file. This might not be
83-
| what you intended.
19+
| Top-level unqualified calls to AnyRef or Any methods such as synchronized are
20+
| resolved to calls on Predef or on imported methods. This might not be what
21+
| you intended.
8422
--------------------------------------------------------------------------------------------------------------------
23+
-- [E181] Potential Issue Error: tests/neg/i17266.scala:108:2 ----------------------------------------------------------
24+
108 | wait() // error
25+
| ^^^^
26+
| Suspicious top-level unqualified call to wait
27+
|-------------------------------------------------------------------------------------------------------------------
28+
| Explanation (enabled by `-explain`)
29+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
30+
| Top-level unqualified calls to AnyRef or Any methods such as wait are
31+
| resolved to calls on Predef or on imported methods. This might not be what
32+
| you intended.
33+
-------------------------------------------------------------------------------------------------------------------
34+
-- [E181] Potential Issue Error: tests/neg/i17266.scala:115:2 ----------------------------------------------------------
35+
115 | wait() // error
36+
| ^^^^
37+
| Suspicious top-level unqualified call to wait
38+
|-------------------------------------------------------------------------------------------------------------------
39+
| Explanation (enabled by `-explain`)
40+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
41+
| Top-level unqualified calls to AnyRef or Any methods such as wait are
42+
| resolved to calls on Predef or on imported methods. This might not be what
43+
| you intended.
44+
-------------------------------------------------------------------------------------------------------------------
45+
-- [E181] Potential Issue Error: tests/neg/i17266.scala:121:2 ----------------------------------------------------------
46+
121 | wait(10) // error
47+
| ^^^^
48+
| Suspicious top-level unqualified call to wait
49+
|-------------------------------------------------------------------------------------------------------------------
50+
| Explanation (enabled by `-explain`)
51+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
52+
| Top-level unqualified calls to AnyRef or Any methods such as wait are
53+
| resolved to calls on Predef or on imported methods. This might not be what
54+
| you intended.
55+
-------------------------------------------------------------------------------------------------------------------
56+
-- [E181] Potential Issue Error: tests/neg/i17266.scala:128:2 ----------------------------------------------------------
57+
128 | wait(10) // error
58+
| ^^^^
59+
| Suspicious top-level unqualified call to wait
60+
|-------------------------------------------------------------------------------------------------------------------
61+
| Explanation (enabled by `-explain`)
62+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
63+
| Top-level unqualified calls to AnyRef or Any methods such as wait are
64+
| resolved to calls on Predef or on imported methods. This might not be what
65+
| you intended.
66+
-------------------------------------------------------------------------------------------------------------------
67+
-- [E181] Potential Issue Error: tests/neg/i17266.scala:134:2 ----------------------------------------------------------
68+
134 | hashCode() // error
69+
| ^^^^^^^^
70+
| Suspicious top-level unqualified call to hashCode
71+
|-------------------------------------------------------------------------------------------------------------------
72+
| Explanation (enabled by `-explain`)
73+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
74+
| Top-level unqualified calls to AnyRef or Any methods such as hashCode are
75+
| resolved to calls on Predef or on imported methods. This might not be what
76+
| you intended.
77+
-------------------------------------------------------------------------------------------------------------------
78+
-- [E181] Potential Issue Error: tests/neg/i17266.scala:141:2 ----------------------------------------------------------
79+
141 | hashCode() // error
80+
| ^^^^^^^^
81+
| Suspicious top-level unqualified call to hashCode
82+
|-------------------------------------------------------------------------------------------------------------------
83+
| Explanation (enabled by `-explain`)
84+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85+
| Top-level unqualified calls to AnyRef or Any methods such as hashCode are
86+
| resolved to calls on Predef or on imported methods. This might not be what
87+
| you intended.
88+
-------------------------------------------------------------------------------------------------------------------

tests/neg/i17266.scala

Lines changed: 111 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,139 @@ def test1 =
66
}
77

88
def test2 =
9-
this.synchronized { // error
9+
this.synchronized { // not an error (should be?)
1010
println("hello")
1111
}
1212

1313
object MyLib
1414

1515
def test3 =
1616
import MyLib.*
17-
synchronized { // not an error (should be?)
17+
synchronized { // error
1818
println("hello")
1919
}
2020

2121
def test4 =
22+
1.synchronized { // not an error (should be?)
23+
println("hello")
24+
}
25+
26+
object Test4:
27+
synchronized { // not an error
28+
println("hello")
29+
}
30+
31+
object Test5:
32+
def test5 =
33+
synchronized { // not an error
34+
println("hello")
35+
}
36+
37+
object Test6:
38+
import MyLib.*
39+
synchronized { // not an error
40+
println("hello")
41+
}
42+
43+
object Test7:
44+
import MyLib.*
45+
def test7 =
46+
synchronized { // not an error
47+
println("hello")
48+
}
49+
50+
/*
51+
object Test7b:
52+
def test8 =
53+
import MyLib.*
54+
synchronized { // already an error: Reference to synchronized is ambiguous.
55+
println("hello")
56+
}
57+
*/
58+
59+
class Test8:
60+
synchronized { // not an error
61+
println("hello")
62+
}
63+
64+
class Test9:
65+
def test5 =
66+
synchronized { // not an error
67+
println("hello")
68+
}
69+
70+
class Test10:
71+
import MyLib.*
72+
synchronized { // not an error
73+
println("hello")
74+
}
75+
76+
class Test11:
77+
import MyLib.*
78+
def test7 =
79+
synchronized { // not an error
80+
println("hello")
81+
}
82+
83+
trait Test12:
84+
synchronized { // not an error
85+
println("hello")
86+
}
87+
88+
trait Test13:
89+
def test5 =
90+
synchronized { // not an error
91+
println("hello")
92+
}
93+
94+
trait Test14:
95+
import MyLib.*
96+
synchronized { // not an error
97+
println("hello")
98+
}
99+
100+
trait Test15:
101+
import MyLib.*
102+
def test7 =
103+
synchronized { // not an error
104+
println("hello")
105+
}
106+
107+
def test16 =
22108
wait() // error
23109

24-
def test5 =
25-
this.wait() // error
110+
def test17 =
111+
this.wait() // not an error (should be?)
26112

27-
def test6 =
113+
def test18 =
28114
import MyLib.*
29-
wait() // not an error (should be?)
115+
wait() // error
30116

31-
def test7 =
117+
def test19 =
118+
1.wait() // not an error (should be?)
119+
120+
def test20 =
32121
wait(10) // error
33122

34-
def test8 =
35-
this.wait(10) // error
123+
def test21 =
124+
this.wait(10) // not an error (should be?)
36125

37-
def test9 =
126+
def test22 =
38127
import MyLib.*
39-
wait(10) // not an error (should be?)
128+
wait(10) // error
129+
130+
def test23 =
131+
1.wait(10) // not an error (should be?)
40132

41-
def test10 =
133+
def test24 =
42134
hashCode() // error
43135

44-
def test11 =
45-
this.hashCode() // error
136+
def test25 =
137+
this.hashCode() // not an error (should be?)
46138

47-
def test12 =
139+
def test26 =
48140
import MyLib.*
49-
hashCode() // not an error (should be?)
141+
hashCode() // error
142+
143+
def test27 =
144+
1.hashCode()// not an error (should be? probably not)

0 commit comments

Comments
 (0)