Skip to content

Commit

Permalink
Merge pull request #8949 from som-snytt/improve/8928
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Dec 21, 2020
2 parents 5d8ded9 + 642d494 commit 54eab98
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 21 deletions.
32 changes: 28 additions & 4 deletions src/reflect/scala/reflect/internal/Names.scala
Expand Up @@ -214,7 +214,7 @@ trait Names extends api.Names {
/** The length of this name. */
final def length: Int = len
final def nonEmpty = !isEmpty
// This method is implements NameHasIsEmpty, and overrides CharSequence's isEmpty on JDK 15+
// This method implements NameHasIsEmpty, and overrides CharSequence's isEmpty on JDK 15+
override final def isEmpty = length == 0

def nameKind: String
Expand Down Expand Up @@ -413,11 +413,36 @@ trait Names extends api.Names {
false
}

def lastIndexOf(s: String): Int = if (s.isEmpty) length else {
val slength = s.length()
val lastIndex = slength - 1
val lastChar = s.charAt(lastIndex)
val contents = _chrs
val base = start
val min = base + lastIndex
var end = base + length - 1

while (end >= min) {
if (contents(end) == lastChar) {
var i = end - 1
val i0 = i - lastIndex
var at = lastIndex - 1
while (i > i0 && contents(i) == s.charAt(at)) {
i -= 1
at -= 1
}
if (i == i0) return i0 + 1 - base
}
end -= 1
}
-1
}

/** Some thoroughly self-explanatory convenience functions. They
* assume that what they're being asked to do is known to be valid.
*/
final def startChar: Char = this charAt 0
final def endChar: Char = this charAt len - 1
final def startChar: Char = charAt(0)
final def endChar: Char = charAt(len - 1)
final def startsWith(char: Char): Boolean = len > 0 && startChar == char
final def startsWith(name: String): Boolean = startsWith(name, 0)
final def endsWith(char: Char): Boolean = len > 0 && endChar == char
Expand All @@ -434,7 +459,6 @@ trait Names extends api.Names {

/** The lastPos methods already return -1 on failure. */
def lastIndexOf(ch: Char): Int = lastPos(ch)
def lastIndexOf(s: String): Int = toString lastIndexOf s

/** Replace all occurrences of `from` by `to` in
* name; result is always a term name.
Expand Down
8 changes: 3 additions & 5 deletions src/reflect/scala/reflect/internal/StdNames.scala
Expand Up @@ -456,9 +456,8 @@ trait StdNames {
* or $ followed by an operator that gets encoded, go directly to compiler
* crash. Do not pass go and don't even think about collecting any $$
*/
def unexpandedName(name: Name): Name = {
if (!name.containsChar('$')) name // lastIndexOf calls Name.toString, add a fast path to avoid that.
else name lastIndexOf "$$" match {
def unexpandedName(name: Name): Name =
name.lastIndexOf("$$") match {
case 0 | -1 => name
case idx0 =>
// Sketchville - We've found $$ but if it's part of $$$ or $$$$
Expand All @@ -467,9 +466,8 @@ trait StdNames {
var idx = idx0
while (idx > 0 && name.charAt(idx - 1) == '$')
idx -= 1
name drop idx + 2
name.drop(idx + 2)
}
}

@deprecated("use unexpandedName", "2.11.0") def originalName(name: Name): Name = unexpandedName(name)
@deprecated("use Name#dropModule", "2.11.0") def stripModuleSuffix(name: Name): Name = name.dropModule
Expand Down
47 changes: 35 additions & 12 deletions test/junit/scala/reflect/internal/NamesTest.scala
Expand Up @@ -12,15 +12,15 @@ class NamesTest {
object symbolTable extends SymbolTableForUnitTesting
import symbolTable._

val h1 = newTermName("hai")
val h2 = newTermName("hai")
val f = newTermName("fisch")
val h1 = TermName("hai")
val h2 = TermName("hai")
val f = TermName("fisch")

val h1y = h1.toTypeName
val h2y = newTypeName("hai")
val fy = newTypeName("fisch")
val h2y = TypeName("hai")
val fy = TypeName("fisch")

val uy = newTypeName("uhu")
val uy = TypeName("uhu")
val u = uy.toTermName // calling toTermName after constructing a typeName. This tests the fact
// that creating a typeName always also first creates a termName. There is
// an assertion for that in toTermName.
Expand Down Expand Up @@ -55,20 +55,20 @@ class NamesTest {
assertTrue(lookupTypeName("uhu".toCharArray) eq uy)

assertThrows[AssertionError](lookupTypeName("dog".toCharArray), _ contains "not yet created")
val d = newTermName("dog")
val d = TermName("dog")
assertThrows[AssertionError](lookupTypeName("dog".toCharArray), _ contains "not yet created")
val dy = d.toTypeName
assertTrue(lookupTypeName("dog".toCharArray) eq dy)
}

@Test
def emptyName(): Unit = {
val z = newTermName("")
val z = TermName("")
val zy = z.toTypeName
assertEquals(z.toString, "")
assertEquals(zy.toString, "")
assertTrue(z eq newTermName(""))
assertTrue(zy eq newTypeName(""))
assertTrue(z eq TermName(""))
assertTrue(zy eq TypeName(""))
}

@Test
Expand All @@ -81,8 +81,8 @@ class NamesTest {
assertTrue(iy.start == (fy.start + 1) && iy.length == (fy.length - 1))
assertTrue(fy.subName(0, fy.length) eq fy)

assertTrue(f.subName(1,1) eq newTermName(""))
assertTrue(f.subName(1, 0) eq newTermName(""))
assertTrue(f.subName(1,1) eq TermName(""))
assertTrue(f.subName(1, 0) eq TermName(""))

assertThrows[IllegalArgumentException](f.subName(0 - f.start - 1, 1))
}
Expand Down Expand Up @@ -117,4 +117,27 @@ class NamesTest {
check("", "x")
check("", "xy")
}

@Test
def `name.lastIndexOf is name.toString.lastIndexOf`(): Unit = {
def check(name: Name, sub: String): Unit = {
val javaResult = name.toString.lastIndexOf(sub)
val nameResult = name.lastIndexOf(sub)
assertEquals(s""""$name".lastIndexOf("$sub")""", javaResult, nameResult)
}
val d = TermName("x$default$42")
val e = TermName("")
check(f, "isch") // the isch in fisch
check(fy, "isch")
check(f, "")
check(e, "")
check(e, "abc")
check(f, "ischbiisch")
check(fy, "ischbiisch")
check(fy, "fyou")
check(f, "disch")
check(fy, "disch")
check(f, "hai") // happens to be earlier in name array
check(d, "$$") // likely to be earlier in name array
}
}

0 comments on commit 54eab98

Please sign in to comment.