@@ -26,18 +26,43 @@ import ast.untpd
2626import ast .tpd
2727import transform .SymUtils ._
2828
29- /** Messages
30- * ========
31- * The role of messages is to provide the necessary details for a simple to
32- * understand diagnostic event. Each message can be turned into a message
33- * container (one of the above) by calling the appropriate method on them.
34- * For instance:
35- *
36- * ```scala
37- * EmptyCatchBlock(tree).error(pos) // res: Error
38- * EmptyCatchBlock(tree).warning(pos) // res: Warning
39- * ```
29+ /* Messages
30+ * ========
31+ * The role of messages is to provide the necessary details for a simple to
32+ * understand diagnostic event. Each message can be turned into a message
33+ * container (one of the above) by calling the appropriate method on them.
34+ * For instance:
35+ *
36+ * ```scala
37+ * EmptyCatchBlock(tree).error(pos) // res: Error
38+ * EmptyCatchBlock(tree).warning(pos) // res: Warning
39+ * ```
40+ */
41+
42+ /** A list of possible candidate options with their Levenstein distances
43+ * to the name of the missing member.
4044 */
45+ def closestNamed [T ](candidates : List [T ], missing : String , format : T => String , maxDist : Int = 3 ): List [(Int , T )] =
46+
47+ def levenshteinDistance (s1 : String , s2 : String ): Int =
48+ val dist = Array .ofDim[Int ](s2.length + 1 , s1.length + 1 )
49+ for
50+ j <- 0 to s2.length
51+ i <- 0 to s1.length
52+ do
53+ dist(j)(i) =
54+ if j == 0 then i
55+ else if i == 0 then j
56+ else if s2(j - 1 ) == s1(i - 1 ) then dist(j - 1 )(i - 1 )
57+ else (dist(j - 1 )(i) min dist(j)(i - 1 ) min dist(j - 1 )(i - 1 )) + 1
58+ dist(s2.length)(s1.length)
59+ end levenshteinDistance
60+
61+ candidates
62+ .map(candidate => (levenshteinDistance(format(candidate), missing), candidate))
63+ .filter((d, candidate) => d <= maxDist && d < missing.length && d < format(candidate).length)
64+ .sortBy((d, candidate) => (d, format(candidate))) // sort by distance first, alphabetically second
65+ end closestNamed
4166
4267 abstract class SyntaxMsg (errorId : ErrorMessageID ) extends Message (errorId):
4368 def kind = MessageKind .Syntax
@@ -318,27 +343,10 @@ import transform.SymUtils._
318343 && ! sym.flagsUNSAFE.isOneOf(Synthetic | Private ))
319344 yield sym
320345
321- // Calculate Levenshtein distance
322- def distance (s1 : String , s2 : String ): Int =
323- val dist = Array .ofDim[Int ](s2.length + 1 , s1.length + 1 )
324- for
325- j <- 0 to s2.length
326- i <- 0 to s1.length
327- do
328- dist(j)(i) =
329- if j == 0 then i
330- else if i == 0 then j
331- else if s2(j - 1 ) == s1(i - 1 ) then dist(j - 1 )(i - 1 )
332- else (dist(j - 1 )(i) min dist(j)(i - 1 ) min dist(j - 1 )(i - 1 )) + 1
333- dist(s2.length)(s1.length)
334-
335346 // A list of possible candidate symbols with their Levenstein distances
336347 // to the name of the missing member
337- def closest : List [(Int , Symbol )] = candidates
338- .toList
339- .map(sym => (distance(sym.name.show, missing), sym))
340- .filter((d, sym) => d <= maxDist && d < missing.length && d < sym.name.show.length)
341- .sortBy((d, sym) => (d, sym.name.show)) // sort by distance first, alphabetically second
348+ def closest : List [(Int , Symbol )] =
349+ closestNamed(candidates.toList, missing, format = _.name.show, maxDist)
342350
343351 val enumClause =
344352 if ((name eq nme.values) || (name eq nme.valueOf)) && site.classSymbol.companionClass.isEnumClass then
0 commit comments