Skip to content

Commit 662d54e

Browse files
committed
Fix #18234: Warn of identifiers with $ in their name
1 parent b1ccc6a commit 662d54e

File tree

6 files changed

+535
-1
lines changed

6 files changed

+535
-1
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class Compiler {
3535
protected def frontendPhases: List[List[Phase]] =
3636
List(new Parser) :: // Compiler frontend: scanner, parser
3737
List(new TyperPhase) :: // Compiler frontend: namer, typer
38-
List(new CheckUnused.PostTyper) :: // Check for unused elements
38+
List(new CheckUnused.PostTyper) :: // Check for unused elements
39+
List(new CheckDollarInIdentifier) :: // Warn if identifier contains a dollar sign $
3940
List(new CheckShadowing) :: // Check shadowing elements
4041
List(new YCheckPositions) :: // YCheck positions
4142
List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ private sealed trait WarningSettings:
195195
),
196196
default = Nil
197197
)
198+
val WdollarCheck: Setting[Boolean] = BooleanSetting("-Wdollar-check", "Warn if identifier contains a dollar sign")
198199
object WunusedHas:
199200
def isChoiceSet(s: String)(using Context) = Wunused.value.pipe(us => us.contains(s))
200201
def allOr(s: String)(using Context) = Wunused.value.pipe(us => us.contains("all") || us.contains(s))
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package dotty.tools.dotc.transform
2+
3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.ast.tpd.Tree
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
7+
import dotty.tools.dotc.core.Contexts.*
8+
import dotty.tools.dotc.core.StdNames.nme
9+
import dotty.tools.dotc.report
10+
import dotty.tools.dotc.reporting.*
11+
import dotty.tools.dotc.util.SourcePosition
12+
13+
14+
class CheckDollarInIdentifier extends MiniPhase:
15+
import CheckDollarInIdentifier.ShouldNotContainDollarSignError
16+
17+
override def phaseName: String = CheckUnused.phaseNamePrefix
18+
19+
override def description: String = CheckUnused.description
20+
21+
override def isRunnable(using Context): Boolean =
22+
super.isRunnable && ctx.settings.WdollarCheck.value
23+
24+
override def transformValDef(tree: tpd.ValDef)(using Context): tpd.Tree =
25+
reportDollarInIdentifier(tree)
26+
27+
override def transformDefDef(tree: tpd.DefDef)(using Context): tpd.Tree =
28+
reportDollarInIdentifier(tree)
29+
30+
override def transformTypeDef(tree: tpd.TypeDef)(using Context): tpd.Tree =
31+
reportDollarInIdentifier(tree)
32+
33+
override def transformTemplate(tree: tpd.Template)(using Context): tpd.Tree =
34+
reportDollarInIdentifier(tree)
35+
36+
override def transformCaseDef(tree: tpd.CaseDef)(using Context): tpd.Tree =
37+
reportDollarInIdentifier(tree)
38+
39+
override def transformPackageDef(tree: tpd.PackageDef)(using Context): tpd.Tree =
40+
reportDollarInIdentifier(tree)
41+
42+
43+
private val allowedValTermNames = List(
44+
nme.DOLLAR_VALUES,
45+
nme.ordinalDollar_,
46+
).map(_.toString)
47+
48+
private val allowedDefTermNames = List(
49+
nme.DOLLAR_NEW,
50+
).map(_.toString)
51+
52+
private def allowedTerms[T <: Tree](tree: T): List[String] =
53+
tree match
54+
case _: tpd.ValDef => allowedValTermNames
55+
case _: tpd.DefDef => allowedDefTermNames
56+
case _ => Nil
57+
58+
private def containsAllowedTerms[T <: Tree](tree: T, name: String): Boolean =
59+
allowedTerms(tree).contains(name)
60+
61+
private def symbolName[T <: Tree](tree: T)(using Context): String =
62+
tree match
63+
case typeDef: tpd.TypeDef =>
64+
typeDef.symbol.toString match {
65+
case s"module class $className$$" => className // to catch the compiled singleton class which includes a $ at the end
66+
case _ => tree.symbol.name.toString
67+
}
68+
case _ => tree.symbol.name.toString
69+
70+
private def reportDollarInIdentifier[T <: Tree](tree: T)(using Context): T =
71+
val name = symbolName(tree)
72+
val originalSrcPos = tree.srcPos.sourcePos
73+
val originalSpan = originalSrcPos.span
74+
75+
// only report source-derived (non-synthetic) spans
76+
if name.contains("$") && !containsAllowedTerms(tree, name) && !originalSpan.isSynthetic then
77+
val srcPos = originalSrcPos.withSpan(originalSrcPos.span.focus) // focus span to place a single `^` at identifier position
78+
report.warning(ShouldNotContainDollarSignError, srcPos)
79+
80+
tree
81+
82+
83+
object CheckDollarInIdentifier:
84+
val name: String = "dollarWarn"
85+
val description: String = "warns if identifiers contain dollar sign, $"
86+
87+
private val ShouldNotContainDollarSignError = s"identifiers should not include dollar sign"
88+

tests/neg/i18234.check

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
-- Error: tests/neg/i18234.scala:40:7 ----------------------------------------------------------------------------------
2+
40 | case $BadCaseStart // error
3+
| ^
4+
| identifiers should not include dollar sign
5+
-- Error: tests/neg/i18234.scala:41:7 ----------------------------------------------------------------------------------
6+
41 | case BadCase$Middle // error
7+
| ^
8+
| identifiers should not include dollar sign
9+
-- Error: tests/neg/i18234.scala:42:7 ----------------------------------------------------------------------------------
10+
42 | case BadCaseEnd$ // error
11+
| ^
12+
| identifiers should not include dollar sign
13+
-- Error: tests/neg/i18234.scala:44:5 ----------------------------------------------------------------------------------
14+
44 |enum $BadEnumStart: // error
15+
| ^
16+
| identifiers should not include dollar sign
17+
-- Error: tests/neg/i18234.scala:46:7 ----------------------------------------------------------------------------------
18+
46 | case $BadCase // error
19+
| ^
20+
| identifiers should not include dollar sign
21+
-- Error: tests/neg/i18234.scala:48:5 ----------------------------------------------------------------------------------
22+
48 |enum BadEnum$Middle: // error
23+
| ^
24+
| identifiers should not include dollar sign
25+
-- Error: tests/neg/i18234.scala:50:7 ----------------------------------------------------------------------------------
26+
50 | case Bad$Case // error
27+
| ^
28+
| identifiers should not include dollar sign
29+
-- Error: tests/neg/i18234.scala:52:5 ----------------------------------------------------------------------------------
30+
52 |enum BadEnumEnd$: // error
31+
| ^
32+
| identifiers should not include dollar sign
33+
-- Error: tests/neg/i18234.scala:54:7 ----------------------------------------------------------------------------------
34+
54 | case BadCase$ // error
35+
| ^
36+
| identifiers should not include dollar sign
37+
-- Error: tests/neg/i18234.scala:56:5 ----------------------------------------------------------------------------------
38+
56 |enum E$numWithEndKeyword: // error
39+
| ^
40+
| identifiers should not include dollar sign
41+
-- Error: tests/neg/i18234.scala:68:6 ----------------------------------------------------------------------------------
42+
68 | val $badVal = 2 // error
43+
| ^
44+
| identifiers should not include dollar sign
45+
-- Error: tests/neg/i18234.scala:66:7 ----------------------------------------------------------------------------------
46+
66 |object $ObjectStart: // error
47+
| ^
48+
| identifiers should not include dollar sign
49+
-- Error: tests/neg/i18234.scala:72:6 ----------------------------------------------------------------------------------
50+
72 | val bad$Val = 2 // error
51+
| ^
52+
| identifiers should not include dollar sign
53+
-- Error: tests/neg/i18234.scala:70:7 ----------------------------------------------------------------------------------
54+
70 |object Object$Middle: // error
55+
| ^
56+
| identifiers should not include dollar sign
57+
-- Error: tests/neg/i18234.scala:76:6 ----------------------------------------------------------------------------------
58+
76 | val badVal$ = 2 // error
59+
| ^
60+
| identifiers should not include dollar sign
61+
-- Error: tests/neg/i18234.scala:74:7 ----------------------------------------------------------------------------------
62+
74 |object ObjectEnd$: // error
63+
| ^
64+
| identifiers should not include dollar sign
65+
-- Error: tests/neg/i18234.scala:80:6 ----------------------------------------------------------------------------------
66+
80 | val b$adVal = 2 // error
67+
| ^
68+
| identifiers should not include dollar sign
69+
-- Error: tests/neg/i18234.scala:82:7 ----------------------------------------------------------------------------------
70+
82 |object Ob$jectWithEndKeyword: // error
71+
| ^
72+
| identifiers should not include dollar sign
73+
-- Error: tests/neg/i18234.scala:89:11 ---------------------------------------------------------------------------------
74+
89 |case class $InlineCaseClassStart(someField: Int) // error
75+
| ^
76+
| identifiers should not include dollar sign
77+
-- Error: tests/neg/i18234.scala:90:11 ---------------------------------------------------------------------------------
78+
90 |case class InlineCaseClass$Middle(someField: Int) // error
79+
| ^
80+
| identifiers should not include dollar sign
81+
-- Error: tests/neg/i18234.scala:91:11 ---------------------------------------------------------------------------------
82+
91 |case class InlineCaseClassEnd$(someField: Int) // error
83+
| ^
84+
| identifiers should not include dollar sign
85+
-- Error: tests/neg/i18234.scala:93:43 ---------------------------------------------------------------------------------
86+
93 |case class InlineCaseClass(goodField: Int, badFiel$d: Int) // error
87+
| ^
88+
| identifiers should not include dollar sign
89+
-- Error: tests/neg/i18234.scala:97:2 ----------------------------------------------------------------------------------
90+
97 | b$adfield: Int // error
91+
| ^
92+
| identifiers should not include dollar sign
93+
-- Error: tests/neg/i18234.scala:95:11 ---------------------------------------------------------------------------------
94+
95 |case class $CaseClassStart( // error
95+
| ^
96+
| identifiers should not include dollar sign
97+
-- Error: tests/neg/i18234.scala:102:2 ---------------------------------------------------------------------------------
98+
102 | bad$Field: Int // error
99+
| ^
100+
| identifiers should not include dollar sign
101+
-- Error: tests/neg/i18234.scala:100:11 --------------------------------------------------------------------------------
102+
100 |case class CaseClass$Middle( // error
103+
| ^
104+
| identifiers should not include dollar sign
105+
-- Error: tests/neg/i18234.scala:107:2 ---------------------------------------------------------------------------------
106+
107 | badField$: Int // error
107+
| ^
108+
| identifiers should not include dollar sign
109+
-- Error: tests/neg/i18234.scala:105:11 --------------------------------------------------------------------------------
110+
105 |case class CaseClassEnd$( // error
111+
| ^
112+
| identifiers should not include dollar sign
113+
-- Error: tests/neg/i18234.scala:111:7 ---------------------------------------------------------------------------------
114+
111 |object CaseClassEnd$: // error
115+
| ^
116+
| identifiers should not include dollar sign
117+
-- Error: tests/neg/i18234.scala:118:6 ---------------------------------------------------------------------------------
118+
118 |class $StartClass // error
119+
| ^
120+
| identifiers should not include dollar sign
121+
-- Error: tests/neg/i18234.scala:119:6 ---------------------------------------------------------------------------------
122+
119 |class Middle$Class // error
123+
| ^
124+
| identifiers should not include dollar sign
125+
-- Error: tests/neg/i18234.scala:120:6 ---------------------------------------------------------------------------------
126+
120 |class EndClass$ // error
127+
| ^
128+
| identifiers should not include dollar sign
129+
-- Error: tests/neg/i18234.scala:124:7 ---------------------------------------------------------------------------------
130+
124 | var badM$ember: Int // error
131+
| ^
132+
| identifiers should not include dollar sign
133+
-- Error: tests/neg/i18234.scala:127:6 ---------------------------------------------------------------------------------
134+
127 | def bad$Method(y: Int) = goodMember // error
135+
| ^
136+
| identifiers should not include dollar sign
137+
-- Error: tests/neg/i18234.scala:128:28 --------------------------------------------------------------------------------
138+
128 | def methodWithBadArgNames(b$ad$arg: Int) = goodMember // error
139+
| ^
140+
| identifiers should not include dollar sign
141+
-- Error: tests/neg/i18234.scala:129:6 ---------------------------------------------------------------------------------
142+
129 | def method$WithEndKeyword() = // error
143+
| ^
144+
| identifiers should not include dollar sign
145+
-- Error: tests/neg/i18234.scala:122:6 ---------------------------------------------------------------------------------
146+
122 |class Cla$$( // error
147+
| ^
148+
| identifiers should not include dollar sign
149+
-- Error: tests/neg/i18234.scala:142:6 ---------------------------------------------------------------------------------
150+
142 |trait $BadTraitStart // error
151+
| ^
152+
| identifiers should not include dollar sign
153+
-- Error: tests/neg/i18234.scala:143:6 ---------------------------------------------------------------------------------
154+
143 |trait BadTrait$Middle // error
155+
| ^
156+
| identifiers should not include dollar sign
157+
-- Error: tests/neg/i18234.scala:144:6 ---------------------------------------------------------------------------------
158+
144 |trait BadTraitEnd$ // error
159+
| ^
160+
| identifiers should not include dollar sign
161+
-- Error: tests/neg/i18234.scala:150:6 ---------------------------------------------------------------------------------
162+
150 | val b$adVal = 2 // error
163+
| ^
164+
| identifiers should not include dollar sign
165+
-- Error: tests/neg/i18234.scala:154:6 ---------------------------------------------------------------------------------
166+
154 | val $badVal = 2 // error
167+
| ^
168+
| identifiers should not include dollar sign
169+
-- Error: tests/neg/i18234.scala:152:8 ---------------------------------------------------------------------------------
170+
152 |package $BadPackageStart: // error
171+
| ^
172+
| identifiers should not include dollar sign
173+
-- Error: tests/neg/i18234.scala:158:6 ---------------------------------------------------------------------------------
174+
158 | val bad$Val = 2 // error
175+
| ^
176+
| identifiers should not include dollar sign
177+
-- Error: tests/neg/i18234.scala:156:8 ---------------------------------------------------------------------------------
178+
156 |package BadPackage$Middle: // error
179+
| ^
180+
| identifiers should not include dollar sign
181+
-- Error: tests/neg/i18234.scala:162:6 ---------------------------------------------------------------------------------
182+
162 | val badVal$ = 2 // error
183+
| ^
184+
| identifiers should not include dollar sign
185+
-- Error: tests/neg/i18234.scala:160:8 ---------------------------------------------------------------------------------
186+
160 |package BadPackageEnd$: // error
187+
| ^
188+
| identifiers should not include dollar sign
189+
-- Error: tests/neg/i18234.scala:5:4 -----------------------------------------------------------------------------------
190+
5 |val $startVal = 1 // error
191+
| ^
192+
| identifiers should not include dollar sign
193+
-- Error: tests/neg/i18234.scala:6:4 -----------------------------------------------------------------------------------
194+
6 |val mid$dleVal = 1 // error
195+
| ^
196+
| identifiers should not include dollar sign
197+
-- Error: tests/neg/i18234.scala:7:4 -----------------------------------------------------------------------------------
198+
7 |val endVal$ = 1 // error
199+
| ^
200+
| identifiers should not include dollar sign
201+
-- Error: tests/neg/i18234.scala:13:4 ----------------------------------------------------------------------------------
202+
13 |def $funcStart() = 3 // error
203+
| ^
204+
| identifiers should not include dollar sign
205+
-- Error: tests/neg/i18234.scala:14:4 ----------------------------------------------------------------------------------
206+
14 |def func$Middle() = 3 // error
207+
| ^
208+
| identifiers should not include dollar sign
209+
-- Error: tests/neg/i18234.scala:15:4 ----------------------------------------------------------------------------------
210+
15 |def funcEnd$() = 3 // error
211+
| ^
212+
| identifiers should not include dollar sign
213+
-- Error: tests/neg/i18234.scala:17:30 ---------------------------------------------------------------------------------
214+
17 |def func1badArg(goodArg: Int, bad$Arg: Int) = 5 // error
215+
| ^
216+
| identifiers should not include dollar sign
217+
-- Error: tests/neg/i18234.scala:18:57 ---------------------------------------------------------------------------------
218+
18 |def func1badArgAndUsageDoesNotThrowWarning(goodArg: Int, bad$Arg: Int) = bad$Arg // error
219+
| ^
220+
| identifiers should not include dollar sign
221+
-- Error: tests/neg/i18234.scala:19:31 ---------------------------------------------------------------------------------
222+
19 |def func2badArgs(goodArg: Int, bad$Arg: Int, bad$arg2: String) = 5 // error // error
223+
| ^
224+
| identifiers should not include dollar sign
225+
-- Error: tests/neg/i18234.scala:19:45 ---------------------------------------------------------------------------------
226+
19 |def func2badArgs(goodArg: Int, bad$Arg: Int, bad$arg2: String) = 5 // error // error
227+
| ^
228+
| identifiers should not include dollar sign
229+
-- Error: tests/neg/i18234.scala:22:2 ----------------------------------------------------------------------------------
230+
22 | badAr$g: Int // error
231+
| ^
232+
| identifiers should not include dollar sign
233+
-- Error: tests/neg/i18234.scala:30:5 ----------------------------------------------------------------------------------
234+
30 |type $StartType = Int // error
235+
| ^
236+
| identifiers should not include dollar sign
237+
-- Error: tests/neg/i18234.scala:31:5 ----------------------------------------------------------------------------------
238+
31 |type Middle$Type = Int // error
239+
| ^
240+
| identifiers should not include dollar sign
241+
-- Error: tests/neg/i18234.scala:32:5 ----------------------------------------------------------------------------------
242+
32 |type EndType$ = Int // error
243+
| ^
244+
| identifiers should not include dollar sign

0 commit comments

Comments
 (0)