@@ -17,18 +17,12 @@ package scala.tools.nsc
17
17
package ast .parser
18
18
19
19
import scala .annotation .tailrec
20
- import scala .collection .mutable , mutable .ListBuffer
21
- import scala .reflect .internal .{ModifierFlags => Flags , Precedence }
22
- import scala .reflect .internal .util .{
23
- CodeAction ,
24
- FreshNameCreator ,
25
- ListOfNil ,
26
- Position ,
27
- SourceFile ,
28
- TextEdit ,
29
- }
30
- import Tokens ._
20
+ import scala .collection .mutable
21
+ import scala .collection .mutable .ListBuffer
22
+ import scala .reflect .internal .util .{CodeAction , FreshNameCreator , ListOfNil , Position , SourceFile }
23
+ import scala .reflect .internal .{Precedence , ModifierFlags => Flags }
31
24
import scala .tools .nsc .Reporting .WarningCategory
25
+ import scala .tools .nsc .ast .parser .Tokens ._
32
26
33
27
/** Historical note: JavaParsers started life as a direct copy of Parsers
34
28
* but at a time when that Parsers had been replaced by a different one.
@@ -329,7 +323,7 @@ self =>
329
323
def source = parser.source
330
324
}
331
325
val treeBuilder = new ParserTreeBuilder
332
- import treeBuilder .{global => _ , unit => _ , source => _ , fresh => _ , _ }
326
+ import treeBuilder .{fresh => _ , global => _ , source => _ , unit => _ , _ }
333
327
334
328
implicit def fresh : FreshNameCreator = unit.fresh
335
329
@@ -633,11 +627,11 @@ self =>
633
627
else deprecationWarning(offset, msg, since, actions)
634
628
635
629
// deprecation or migration under -Xsource:3, with different messages
636
- def hardMigrationWarning (offset : Offset , depr : => String , migr : => String , since : String , actions : List [CodeAction ]): Unit =
637
- if (currentRun.isScala3) warning(offset, migr, WarningCategory .Scala3Migration , actions)
638
- else deprecationWarning(offset, depr, since, actions)
630
+ def hardMigrationWarning (offset : Offset , depr : => String , migr : => String , since : String , actions : String => List [CodeAction ]): Unit =
631
+ if (currentRun.isScala3) warning(offset, migr, WarningCategory .Scala3Migration , actions(migr) )
632
+ else deprecationWarning(offset, depr, since, actions(depr) )
639
633
def hardMigrationWarning (offset : Offset , depr : => String , migr : => String , since : String ): Unit =
640
- hardMigrationWarning(offset, depr, migr, since, Nil )
634
+ hardMigrationWarning(offset, depr, migr, since, _ => Nil )
641
635
642
636
def expectedMsgTemplate (exp : String , fnd : String ) = s " $exp expected but $fnd found. "
643
637
def expectedMsg (token : Token ): String =
@@ -748,12 +742,18 @@ self =>
748
742
def isWildcardType = in.token == USCORE || isScala3WildcardType
749
743
def isScala3WildcardType = isRawIdent && in.name == raw.QMARK
750
744
def checkQMarkDefinition () =
751
- if (isScala3WildcardType)
752
- syntaxError(in.offset, " using `?` as a type name requires backticks." )
745
+ if (isScala3WildcardType) {
746
+ val msg = " using `?` as a type name requires backticks."
747
+ syntaxError(in.offset, msg,
748
+ runReporting.codeAction(" add backticks" , r2p(in.offset, in.offset, in.offset + 1 ), " `?`" , msg, expected = Some ((" ?" , unit))))
749
+ }
750
+
753
751
def checkKeywordDefinition () =
754
- if (isRawIdent && scala3Keywords.contains(in.name))
755
- deprecationWarning(in.offset,
756
- s " Wrap ` ${in.name}` in backticks to use it as an identifier, it will become a keyword in Scala 3. " , " 2.13.7" )
752
+ if (isRawIdent && scala3Keywords.contains(in.name)) {
753
+ val msg = s " Wrap ` ${in.name}` in backticks to use it as an identifier, it will become a keyword in Scala 3. "
754
+ deprecationWarning(in.offset, msg, " 2.13.7" ,
755
+ runReporting.codeAction(" add backticks" , r2p(in.offset, in.offset, in.offset + in.name.length), s " ` ${in.name}` " , msg, expected = Some ((in.name.toString, unit))))
756
+ }
757
757
758
758
def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT
759
759
def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw
@@ -816,8 +816,7 @@ self =>
816
816
val wrn = sm """ | $msg
817
817
|Use '-Wconf:msg=lambda-parens:s' to silence this warning. """
818
818
def actions =
819
- if (tree.pos.isRange)
820
- List (CodeAction (" lambda parameter" , Some (msg), List (TextEdit (tree.pos, s " ( ${unit.sourceAt(tree.pos)}) " ))))
819
+ if (tree.pos.isRange) runReporting.codeAction(" add parentheses" , tree.pos, s " ( ${unit.sourceAt(tree.pos)}) " , msg)
821
820
else Nil
822
821
migrationWarning(tree.pos.point, wrn, " 2.13.11" , actions)
823
822
List (convertToParam(tree))
@@ -1029,11 +1028,17 @@ self =>
1029
1028
1030
1029
def finishBinaryOp (isExpr : Boolean , opinfo : OpInfo , rhs : Tree ): Tree = {
1031
1030
import opinfo ._
1032
- if (targs.nonEmpty)
1033
- migrationWarning(offset, " type application is not allowed for infix operators" , " 2.13.11" )
1034
1031
val operatorPos : Position = Position .range(rhs.pos.source, offset, offset, offset + operator.length)
1035
1032
val pos = lhs.pos.union(rhs.pos).union(operatorPos).withEnd(in.lastOffset).withPoint(offset)
1036
1033
1034
+ if (targs.nonEmpty) {
1035
+ val qual = unit.sourceAt(lhs.pos)
1036
+ val fun = s " ${CodeAction .maybeWrapInParens(qual)}. ${unit.sourceAt(operatorPos.withEnd(rhs.pos.start))}" .trim
1037
+ val fix = s " $fun${CodeAction .wrapInParens(unit.sourceAt(rhs.pos))}"
1038
+ val msg = " type application is not allowed for infix operators"
1039
+ migrationWarning(offset, msg, " 2.13.11" ,
1040
+ runReporting.codeAction(" use selection" , pos, fix, msg))
1041
+ }
1037
1042
atPos(pos)(makeBinop(isExpr, lhs, operator, rhs, operatorPos, targs))
1038
1043
}
1039
1044
@@ -1090,7 +1095,9 @@ self =>
1090
1095
if (in.token == ARROW )
1091
1096
atPos(start, in.skipToken()) { makeSafeFunctionType(ts, typ()) }
1092
1097
else if (ts.isEmpty) {
1093
- syntaxError(start, " Illegal literal type (), use Unit instead" )
1098
+ val msg = " Illegal literal type (), use Unit instead"
1099
+ syntaxError(start, msg,
1100
+ runReporting.codeAction(" use `Unit`" , r2p(start, start, start + 2 ), " Unit" , msg, expected = Some ((" ()" , unit))))
1094
1101
EmptyTree
1095
1102
}
1096
1103
else {
@@ -1174,7 +1181,9 @@ self =>
1174
1181
if (lookingAhead(in.token == RPAREN )) {
1175
1182
in.nextToken()
1176
1183
in.nextToken()
1177
- syntaxError(start, " Illegal literal type (), use Unit instead" )
1184
+ val msg = " Illegal literal type (), use Unit instead"
1185
+ syntaxError(start, msg,
1186
+ runReporting.codeAction(" use `Unit`" , r2p(start, start, start + 2 ), " Unit" , msg, expected = Some ((" ()" , unit))))
1178
1187
EmptyTree
1179
1188
}
1180
1189
else
@@ -1475,9 +1484,9 @@ self =>
1475
1484
else withPlaceholders(interpolatedString(inPattern), isAny = true ) // interpolator params are Any* by definition
1476
1485
}
1477
1486
else if (in.token == SYMBOLLIT ) {
1478
- def msg ( what : String ) =
1479
- s """ symbol literal is $what ; use Symbol(" ${ in.strVal} ") instead """
1480
- deprecationWarning( in.offset, msg( " deprecated " ), " 2.13.0 " )
1487
+ val msg = s """ symbol literal is deprecated; use Symbol(" ${in.strVal} ") instead """
1488
+ deprecationWarning( in.offset, msg, " 2.13.0 " ,
1489
+ runReporting.codeAction( " replace symbol literal " , r2p( in.offset, in.offset, in.offset + 1 + in.strVal.length), s """ Symbol(" ${in.strVal} ") """ , msg, expected = Some (( s " ' ${in.strVal} " , unit))) )
1481
1490
Apply (scalaDot(nme.Symbol ), List (finish(in.strVal)))
1482
1491
}
1483
1492
else finish(in.token match {
@@ -2095,17 +2104,15 @@ self =>
2095
2104
val hasEq = in.token == EQUALS
2096
2105
2097
2106
if (hasVal) {
2098
- def actions = {
2099
- val pos = r2p(valOffset, valOffset, valOffset + 4 )
2100
- if (unit.sourceAt(pos) != " val " ) Nil else
2101
- List (CodeAction (" val in for comprehension" , None , List (TextEdit (pos, " " ))))
2102
- }
2107
+ def actions (msg : String ) = runReporting.codeAction(" remove `val` keyword" , r2p(valOffset, valOffset, valOffset + 4 ), " " , msg, expected = Some ((" val " , unit)))
2103
2108
def msg (what : String , instead : String ): String = s " `val` keyword in for comprehension is $what: $instead"
2104
2109
if (hasEq) {
2105
2110
val without = " instead, bind the value without `val`"
2106
2111
hardMigrationWarning(in.offset, msg(" deprecated" , without), msg(" unsupported" , without), " 2.10.0" , actions)
2112
+ } else {
2113
+ val m = msg(" unsupported" , " just remove `val`" )
2114
+ syntaxError(in.offset, m, actions(m))
2107
2115
}
2108
- else syntaxError(in.offset, msg(" unsupported" , " just remove `val`" ), actions)
2109
2116
}
2110
2117
2111
2118
if (hasEq && eqOK && ! hasCase) in.nextToken()
@@ -2969,7 +2976,11 @@ self =>
2969
2976
def funDefOrDcl (start : Int , mods : Modifiers ): Tree = {
2970
2977
in.nextToken()
2971
2978
if (in.token == THIS ) {
2972
- def missingEquals () = hardMigrationWarning(in.lastOffset, " procedure syntax is deprecated for constructors: add `=`, as in method definition" , " 2.13.2" )
2979
+ def missingEquals () = {
2980
+ val msg = " procedure syntax is deprecated for constructors: add `=`, as in method definition"
2981
+ hardMigrationWarning(in.lastOffset, msg, " 2.13.2" ,
2982
+ runReporting.codeAction(" replace procedure syntax" , o2p(in.lastOffset), " =" , msg))
2983
+ }
2973
2984
atPos(start, in.skipToken()) {
2974
2985
val vparamss = paramClauses(nme.CONSTRUCTOR , classContextBounds map (_.duplicate), ofCaseClass = false )
2975
2986
newLineOptWhenFollowedBy(LBRACE )
@@ -3006,8 +3017,8 @@ self =>
3006
3017
var restype = fromWithinReturnType(typedOpt())
3007
3018
def msg (what : String , instead : String ) =
3008
3019
s " procedure syntax is $what: instead, add ` $instead` to explicitly declare ` $name`'s return type "
3009
- def declActions = List ( CodeAction ( " procedure syntax (decl) " , None , List ( TextEdit ( o2p(in.lastOffset), " : Unit" ))) )
3010
- def defnActions = List ( CodeAction ( " procedure syntax (defn) " , None , List ( TextEdit ( o2p(in.lastOffset), " : Unit =" ))) )
3020
+ def declActions ( msg : String ) = runReporting.codeAction( " add result type " , o2p(in.lastOffset), " : Unit" , msg )
3021
+ def defnActions ( msg : String ) = runReporting.codeAction( " replace procedure syntax" , o2p(in.lastOffset), " : Unit =" , msg )
3011
3022
val rhs =
3012
3023
if (isStatSep || in.token == RBRACE ) {
3013
3024
if (restype.isEmpty) {
@@ -3035,7 +3046,11 @@ self =>
3035
3046
if (nme.isEncodedUnary(name) && vparamss.nonEmpty) {
3036
3047
def instead = DefDef (newmods, name.toTermName.decodedName, tparams, vparamss.drop(1 ), restype, rhs)
3037
3048
def unaryMsg (what : String ) = s " unary prefix operator definition with empty parameter list is $what: instead, remove () to declare as ` $instead` "
3038
- def warnNilary () = hardMigrationWarning(nameOffset, unaryMsg(" deprecated" ), unaryMsg(" unsupported" ), " 2.13.4" )
3049
+ def action (msg : String ) = {
3050
+ val o = nameOffset + name.decode.length
3051
+ runReporting.codeAction(" remove ()" , r2p(o, o, o + 2 ), " " , msg, expected = Some ((" ()" , unit)))
3052
+ }
3053
+ def warnNilary () = hardMigrationWarning(nameOffset, unaryMsg(" deprecated" ), unaryMsg(" unsupported" ), " 2.13.4" , action)
3039
3054
vparamss match {
3040
3055
case List (List ()) => warnNilary()
3041
3056
case List (List (), x :: xs) if x.mods.isImplicit => warnNilary()
@@ -3313,7 +3328,9 @@ self =>
3313
3328
*/
3314
3329
def templateOpt (mods : Modifiers , name : Name , constrMods : Modifiers , vparamss : List [List [ValDef ]], tstart : Offset ): Template = {
3315
3330
def deprecatedUsage (): Boolean = {
3316
- deprecationWarning(in.offset, " Using `<:` for `extends` is deprecated" , since = " 2.12.5" )
3331
+ val msg = " Using `<:` for `extends` is deprecated"
3332
+ deprecationWarning(in.offset, msg, since = " 2.12.5" ,
3333
+ runReporting.codeAction(" use `extends`" , r2p(in.offset, in.offset, in.offset + 2 ), " extends" , msg, expected = Some ((" <:" , unit))))
3317
3334
true
3318
3335
}
3319
3336
val (parents, self, body) =
0 commit comments