Skip to content

Commit 741ee16

Browse files
authored
Merge pull request #2229 from dotty-staging/sync-classfile-parser
Port some ClassfileParser changes from scalac
2 parents 4b33e36 + cc4045f commit 741ee16

File tree

4 files changed

+57
-9
lines changed

4 files changed

+57
-9
lines changed

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._,
77
import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._
88
import NameKinds.{ModuleClassName, DefaultGetterName}
99
import ast.tpd._
10-
import java.io.{ File, IOException }
10+
import java.io.{ ByteArrayInputStream, DataInputStream, File, IOException }
1111
import java.lang.Integer.toHexString
1212
import scala.collection.{ mutable, immutable }
1313
import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
@@ -194,13 +194,21 @@ class ClassfileParser(
194194
val name = pool.getName(in.nextChar)
195195
val isConstructor = name eq nme.CONSTRUCTOR
196196

197-
/** Strip leading outer param from constructor.
198-
* Todo: Also strip trailing access tag for private inner constructors?
197+
/** Strip leading outer param from constructor and trailing access tag for
198+
* private inner constructors.
199199
*/
200-
def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match {
200+
def normalizeConstructorParams() = innerClasses.get(currentClassName) match {
201201
case Some(entry) if !isStatic(entry.jflags) =>
202202
val mt @ MethodTpe(paramNames, paramTypes, resultType) = denot.info
203-
denot.info = mt.derivedLambdaType(paramNames.tail, paramTypes.tail, resultType)
203+
var normalizedParamNames = paramNames.tail
204+
var normalizedParamTypes = paramTypes.tail
205+
if ((jflags & JAVA_ACC_SYNTHETIC) != 0) {
206+
// SI-7455 strip trailing dummy argument ("access constructor tag") from synthetic constructors which
207+
// are added when an inner class needs to access a private constructor.
208+
normalizedParamNames = paramNames.dropRight(1)
209+
normalizedParamTypes = paramTypes.dropRight(1)
210+
}
211+
denot.info = mt.derivedLambdaType(normalizedParamNames, normalizedParamTypes, resultType)
204212
case _ =>
205213
}
206214

@@ -216,7 +224,7 @@ class ClassfileParser(
216224

217225
denot.info = pool.getType(in.nextChar)
218226
if (isEnum) denot.info = ConstantType(Constant(sym))
219-
if (isConstructor) stripOuterParamFromConstructor()
227+
if (isConstructor) normalizeConstructorParams()
220228
setPrivateWithin(denot, jflags)
221229
denot.info = translateTempPoly(parseAttributes(sym, denot.info))
222230
if (isConstructor) normalizeConstructorInfo()
@@ -227,8 +235,12 @@ class ClassfileParser(
227235
// seal java enums
228236
if (isEnum) {
229237
val enumClass = sym.owner.linkedClass
230-
if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed)
231-
enumClass.addAnnotation(Annotation.makeChild(sym))
238+
if (!enumClass.exists)
239+
ctx.warning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.")
240+
else {
241+
if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed)
242+
enumClass.addAnnotation(Annotation.makeChild(sym))
243+
}
232244
}
233245
} finally {
234246
in.bp = oldbp
@@ -923,12 +935,16 @@ class ClassfileParser(
923935
case null =>
924936
val start = starts(index)
925937
if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start)
926-
val name = termName(in.buf, start + 3, in.getChar(start + 1))
938+
val len = in.getChar(start + 1).toInt
939+
val name = termName(fromMUTF8(in.buf, start + 1, len + 2))
927940
values(index) = name
928941
name
929942
}
930943
}
931944

945+
private def fromMUTF8(bytes: Array[Byte], offset: Int, len: Int): String =
946+
new DataInputStream(new ByteArrayInputStream(bytes, offset, len)).readUTF
947+
932948
/** Return the name found at given index in the constant pool, with '/' replaced by '.'. */
933949
def getExternalName(index: Int): SimpleTermName = {
934950
if (index <= 0 || len <= index)
File renamed without changes.

tests/run/t9915/C_1.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* javac: -encoding UTF-8
3+
*/
4+
public class C_1 {
5+
public static final String NULLED = "X\000ABC";
6+
public static final String SUPPED = "𐒈𐒝𐒑𐒛𐒐𐒘𐒕𐒖";
7+
8+
public String nulled() {
9+
return C_1.NULLED;
10+
}
11+
public String supped() {
12+
return C_1.SUPPED;
13+
}
14+
public int nulledSize() {
15+
return C_1.NULLED.length();
16+
}
17+
public int suppedSize() {
18+
return C_1.SUPPED.length();
19+
}
20+
}

tests/run/t9915/Test_2.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
object Test extends App {
3+
val c = new C_1
4+
assert(c.nulled == "X\u0000ABC") // "X\000ABC"
5+
assert(c.supped == "𐒈𐒝𐒑𐒛𐒐𐒘𐒕𐒖")
6+
7+
assert(C_1.NULLED == "X\u0000ABC") // "X\000ABC"
8+
assert(C_1.SUPPED == "𐒈𐒝𐒑𐒛𐒐𐒘𐒕𐒖")
9+
10+
assert(C_1.NULLED.size == "XYABC".size)
11+
assert(C_1.SUPPED.codePointCount(0, C_1.SUPPED.length) == 8)
12+
}

0 commit comments

Comments
 (0)