aload0pos, found); | aload0pos, found); | ||||
} | } | ||||
private boolean isFromSameDeclaringClass(CtClass outer, CtClass inner) { | |||||
try { | |||||
while (outer != null) { | |||||
if (isEnclosing(outer, inner)) | |||||
return true; | |||||
outer = outer.getDeclaringClass(); | |||||
} | |||||
} | |||||
catch (NotFoundException e) {} | |||||
return false; | |||||
} | |||||
private void atMethodCallCore2(CtClass targetClass, String mname, | private void atMethodCallCore2(CtClass targetClass, String mname, | ||||
boolean isStatic, boolean isSpecial, | boolean isStatic, boolean isSpecial, | ||||
int aload0pos, | int aload0pos, | ||||
throw new CompileError("no such constructor: " + targetClass.getName()); | throw new CompileError("no such constructor: " + targetClass.getName()); | ||||
if (declClass != thisClass && AccessFlag.isPrivate(acc)) { | if (declClass != thisClass && AccessFlag.isPrivate(acc)) { | ||||
boolean isNested = false; | |||||
if (declClass.getClassFile().getMajorVersion() >= ClassFile.JAVA_11) { | |||||
try { | |||||
CtClass[] nestedClasses = declClass.getNestedClasses(); | |||||
for (int i = 0; i < nestedClasses.length; i++) { | |||||
if (thisClass == nestedClasses[i]) { | |||||
isNested = true; | |||||
break; | |||||
} | |||||
} | |||||
} catch (NotFoundException ignored) { } | |||||
} | |||||
if (!isNested) { | |||||
if (declClass.getClassFile().getMajorVersion() < ClassFile.JAVA_11 | |||||
|| !isFromSameDeclaringClass(declClass, thisClass)) { | |||||
desc = getAccessibleConstructor(desc, declClass, minfo); | desc = getAccessibleConstructor(desc, declClass, minfo); | ||||
bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter | bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter | ||||
} | } |
} | } | ||||
} | } | ||||
public void testNestPrivateConstructor2() throws Exception { | |||||
CtClass cc = sloader.get("test5.NestHost4$InnerClass1"); | |||||
cc.instrument(new ExprEditor() { | |||||
public void edit(NewExpr e) throws CannotCompileException { | |||||
String code = "$_ = $proceed($$);"; | |||||
e.replace(code); | |||||
} | |||||
}); | |||||
cc.writeFile(); | |||||
cc = sloader.get("test5.NestHost4$InnerClass1$InnerClass5"); | |||||
cc.instrument(new ExprEditor() { | |||||
public void edit(NewExpr e) throws CannotCompileException { | |||||
String code = "$_ = $proceed($$);"; | |||||
e.replace(code); | |||||
} | |||||
}); | |||||
cc.writeFile(); | |||||
try { | |||||
Class<?> nestHost4Class = cloader.loadClass("test5.NestHost4"); | |||||
nestHost4Class.getDeclaredConstructor().newInstance(); | |||||
} catch (Exception ex) { | |||||
ex.printStackTrace(); | |||||
fail("it should be able to access the private constructor of the nest host"); | |||||
} | |||||
} | |||||
public void testSwitchCaseWithStringConstant2() throws Exception { | public void testSwitchCaseWithStringConstant2() throws Exception { | ||||
CtClass cc = sloader.makeClass("test5.SwitchCase2"); | CtClass cc = sloader.makeClass("test5.SwitchCase2"); | ||||
cc.addMethod(CtNewMethod.make( | cc.addMethod(CtNewMethod.make( |
package test5; | |||||
public class NestHost4 { | |||||
public void test() { | |||||
new InnerClass1().new InnerClass5(); | |||||
} | |||||
private class InnerClass1 { | |||||
private InnerClass1() { | |||||
new InnerClass2(); | |||||
} | |||||
private class InnerClass5 { | |||||
private InnerClass5() { | |||||
new InnerClass2().new InnerClass3(); | |||||
} | |||||
} | |||||
} | |||||
private class InnerClass2 { | |||||
private class InnerClass3 { | |||||
} | |||||
} | |||||
} |