mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
[java-decompiler] Avoid annotation duplication when annotation has multiple targets
Fixes a bug where type use annotations where duplicated when they were also applicable to other targets. GitOrigin-RevId: 8a2373a0423dd31691b83509128bb6065ff71905
This commit is contained in:
committed by
intellij-monorepo-bot
parent
999fe6d746
commit
f733e9c8fa
@@ -285,108 +285,6 @@ public class ClassWriter {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void packageInfoToJava(StructClass cl, TextBuffer buffer) {
|
||||
appendAnnotations(buffer, 0, cl);
|
||||
|
||||
int index = cl.qualifiedName.lastIndexOf('/');
|
||||
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
|
||||
buffer.append("package ").append(packageName).append(';').appendLineSeparator().appendLineSeparator();
|
||||
}
|
||||
|
||||
public static void moduleInfoToJava(StructClass cl, TextBuffer buffer) {
|
||||
appendAnnotations(buffer, 0, cl);
|
||||
|
||||
StructModuleAttribute moduleAttribute = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
|
||||
|
||||
if ((moduleAttribute.moduleFlags & CodeConstants.ACC_OPEN) != 0) {
|
||||
buffer.append("open ");
|
||||
}
|
||||
|
||||
buffer.append("module ").append(moduleAttribute.moduleName).append(" {").appendLineSeparator();
|
||||
|
||||
writeModuleInfoBody(buffer, moduleAttribute);
|
||||
|
||||
buffer.append('}').appendLineSeparator();
|
||||
}
|
||||
|
||||
private static void writeModuleInfoBody(TextBuffer buffer, StructModuleAttribute moduleAttribute) {
|
||||
boolean newLineNeeded = false;
|
||||
|
||||
List<StructModuleAttribute.RequiresEntry> requiresEntries = moduleAttribute.requires;
|
||||
if (!requiresEntries.isEmpty()) {
|
||||
for (StructModuleAttribute.RequiresEntry requires : requiresEntries) {
|
||||
if (!isGenerated(requires.flags)) {
|
||||
buffer.appendIndent(1).append("requires ").append(requires.moduleName.replace('/', '.')).append(';').appendLineSeparator();
|
||||
newLineNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<StructModuleAttribute.ExportsEntry> exportsEntries = moduleAttribute.exports;
|
||||
if (!exportsEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (StructModuleAttribute.ExportsEntry exports : exportsEntries) {
|
||||
if (!isGenerated(exports.flags)) {
|
||||
buffer.appendIndent(1).append("exports ").append(exports.packageName.replace('/', '.'));
|
||||
List<String> exportToModules = exports.exportToModules;
|
||||
if (exportToModules.size() > 0) {
|
||||
buffer.append(" to").appendLineSeparator();
|
||||
appendFQClassNames(buffer, exportToModules);
|
||||
}
|
||||
buffer.append(';').appendLineSeparator();
|
||||
newLineNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<StructModuleAttribute.OpensEntry> opensEntries = moduleAttribute.opens;
|
||||
if (!opensEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (StructModuleAttribute.OpensEntry opens : opensEntries) {
|
||||
if (!isGenerated(opens.flags)) {
|
||||
buffer.appendIndent(1).append("opens ").append(opens.packageName.replace('/', '.'));
|
||||
List<String> opensToModules = opens.opensToModules;
|
||||
if (opensToModules.size() > 0) {
|
||||
buffer.append(" to").appendLineSeparator();
|
||||
appendFQClassNames(buffer, opensToModules);
|
||||
}
|
||||
buffer.append(';').appendLineSeparator();
|
||||
newLineNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> usesEntries = moduleAttribute.uses;
|
||||
if (!usesEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (String uses : usesEntries) {
|
||||
buffer.appendIndent(1).append("uses ").append(ExprProcessor.buildJavaClassName(uses)).append(';').appendLineSeparator();
|
||||
}
|
||||
newLineNeeded = true;
|
||||
}
|
||||
|
||||
List<StructModuleAttribute.ProvidesEntry> providesEntries = moduleAttribute.provides;
|
||||
if (!providesEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (StructModuleAttribute.ProvidesEntry provides : providesEntries) {
|
||||
buffer.appendIndent(1).append("provides ").append(ExprProcessor.buildJavaClassName(provides.interfaceName)).append(" with").appendLineSeparator();
|
||||
appendFQClassNames(buffer, provides.implementationNames.stream().map(ExprProcessor::buildJavaClassName).collect(Collectors.toList()));
|
||||
buffer.append(';').appendLineSeparator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isGenerated(int flags) {
|
||||
return (flags & (CodeConstants.ACC_SYNTHETIC | CodeConstants.ACC_MANDATED)) != 0;
|
||||
}
|
||||
|
||||
private static void addTracer(StructClass cls, StructMethod method, BytecodeMappingTracer tracer) {
|
||||
StructLineNumberTableAttribute table = method.getAttribute(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
|
||||
tracer.setLineNumberTable(table);
|
||||
String key = InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor());
|
||||
DecompilerContext.getBytecodeSourceMapper().addTracer(cls.qualifiedName, key, tracer);
|
||||
}
|
||||
|
||||
private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) {
|
||||
if (node.type == ClassNode.CLASS_ANONYMOUS) {
|
||||
buffer.append(" {").appendLineSeparator();
|
||||
@@ -416,7 +314,7 @@ public class ClassWriter {
|
||||
appendComment(buffer, "synthetic class", indent);
|
||||
}
|
||||
|
||||
appendAnnotations(buffer, indent, cl);
|
||||
appendAnnotations(buffer, 0, indent, cl);
|
||||
|
||||
buffer.appendIndent(indent);
|
||||
|
||||
@@ -548,13 +446,6 @@ public class ClassWriter {
|
||||
buffer.append('{').appendLineSeparator();
|
||||
}
|
||||
|
||||
private static boolean isVarArgRecord(StructClass cl) {
|
||||
String canonicalConstructorDescriptor =
|
||||
cl.getRecordComponents().stream().map(StructField::getDescriptor).collect(Collectors.joining("", "(", ")V"));
|
||||
StructMethod init = cl.getMethod(CodeConstants.INIT_NAME, canonicalConstructorDescriptor);
|
||||
return init != null && init.hasModifier(CodeConstants.ACC_VARARGS);
|
||||
}
|
||||
|
||||
private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {
|
||||
int start = buffer.length();
|
||||
boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
|
||||
@@ -577,7 +468,7 @@ public class ClassWriter {
|
||||
Map.Entry<VarType, GenericFieldDescriptor> fieldTypeData = getFieldTypeData(fd);
|
||||
VarType fieldType = fieldTypeData.getKey();
|
||||
|
||||
appendAnnotations(buffer, indent, fd);
|
||||
appendAnnotations(buffer, fieldType.arrayDim, indent, fd);
|
||||
|
||||
buffer.appendIndent(indent);
|
||||
|
||||
@@ -642,138 +533,82 @@ public class ClassWriter {
|
||||
}
|
||||
}
|
||||
|
||||
private static void recordComponentToJava(StructRecordComponent cd, TextBuffer buffer, boolean varArgComponent) {
|
||||
appendAnnotations(buffer, -1, cd);
|
||||
private static void writeModuleInfoBody(TextBuffer buffer, StructModuleAttribute moduleAttribute) {
|
||||
boolean newLineNeeded = false;
|
||||
|
||||
Map.Entry<VarType, GenericFieldDescriptor> fieldTypeData = getFieldTypeData(cd);
|
||||
VarType fieldType = fieldTypeData.getKey();
|
||||
GenericFieldDescriptor descriptor = fieldTypeData.getValue();
|
||||
|
||||
final List<TypeAnnotationWriteHelper> typeAnnwriteHelper = createTypeAnnWriteHelper(cd);
|
||||
|
||||
if (descriptor != null) {
|
||||
buffer.append(GenericMain.getGenericCastTypeName(varArgComponent ? descriptor.type.decreaseArrayDim() : descriptor.type, typeAnnwriteHelper));
|
||||
}
|
||||
else {
|
||||
buffer.append(ExprProcessor.getCastTypeName(varArgComponent ? fieldType.decreaseArrayDim() : fieldType, typeAnnwriteHelper));
|
||||
}
|
||||
if (varArgComponent) {
|
||||
buffer.append("...");
|
||||
}
|
||||
buffer.append(' ');
|
||||
|
||||
buffer.append(cd.getName());
|
||||
}
|
||||
|
||||
private static void methodLambdaToJava(ClassNode lambdaNode,
|
||||
ClassWrapper classWrapper,
|
||||
StructMethod mt,
|
||||
TextBuffer buffer,
|
||||
int indent,
|
||||
boolean codeOnly, BytecodeMappingTracer tracer) {
|
||||
MethodWrapper methodWrapper = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
|
||||
|
||||
MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
|
||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);
|
||||
|
||||
try {
|
||||
String method_name = lambdaNode.lambdaInformation.method_name;
|
||||
MethodDescriptor md_content = MethodDescriptor.parseDescriptor(lambdaNode.lambdaInformation.content_method_descriptor);
|
||||
MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(lambdaNode.lambdaInformation.method_descriptor);
|
||||
|
||||
if (!codeOnly) {
|
||||
buffer.appendIndent(indent);
|
||||
buffer.append("public ");
|
||||
buffer.append(method_name);
|
||||
buffer.append("(");
|
||||
|
||||
boolean firstParameter = true;
|
||||
int index = lambdaNode.lambdaInformation.is_content_method_static ? 0 : 1;
|
||||
int start_index = md_content.params.length - md_lambda.params.length;
|
||||
|
||||
for (int i = 0; i < md_content.params.length; i++) {
|
||||
if (i >= start_index) {
|
||||
if (!firstParameter) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
|
||||
String typeName = ExprProcessor.getCastTypeName(md_content.params[i].copy(), Collections.emptyList());
|
||||
if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
|
||||
DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
|
||||
typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT, Collections.emptyList());
|
||||
}
|
||||
|
||||
buffer.append(typeName);
|
||||
buffer.append(" ");
|
||||
|
||||
String parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0));
|
||||
buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
|
||||
|
||||
firstParameter = false;
|
||||
}
|
||||
|
||||
index += md_content.params[i].stackSize;
|
||||
}
|
||||
|
||||
buffer.append(") {").appendLineSeparator();
|
||||
|
||||
indent += 1;
|
||||
}
|
||||
|
||||
RootStatement root = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
|
||||
if (!methodWrapper.decompiledWithErrors) {
|
||||
if (root != null) { // check for existence
|
||||
try {
|
||||
buffer.append(root.toJava(indent, tracer));
|
||||
}
|
||||
catch (Throwable t) {
|
||||
String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.";
|
||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN, t);
|
||||
methodWrapper.decompiledWithErrors = true;
|
||||
}
|
||||
List<StructModuleAttribute.RequiresEntry> requiresEntries = moduleAttribute.requires;
|
||||
if (!requiresEntries.isEmpty()) {
|
||||
for (StructModuleAttribute.RequiresEntry requires : requiresEntries) {
|
||||
if (!isGenerated(requires.flags)) {
|
||||
buffer.appendIndent(1).append("requires ").append(requires.moduleName.replace('/', '.')).append(';').appendLineSeparator();
|
||||
newLineNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (methodWrapper.decompiledWithErrors) {
|
||||
buffer.appendIndent(indent);
|
||||
buffer.append("// $FF: Couldn't be decompiled");
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
|
||||
if (root != null) {
|
||||
tracer.addMapping(root.getDummyExit().bytecode);
|
||||
}
|
||||
|
||||
if (!codeOnly) {
|
||||
indent -= 1;
|
||||
buffer.appendIndent(indent).append('}').appendLineSeparator();
|
||||
List<StructModuleAttribute.ExportsEntry> exportsEntries = moduleAttribute.exports;
|
||||
if (!exportsEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (StructModuleAttribute.ExportsEntry exports : exportsEntries) {
|
||||
if (!isGenerated(exports.flags)) {
|
||||
buffer.appendIndent(1).append("exports ").append(exports.packageName.replace('/', '.'));
|
||||
List<String> exportToModules = exports.exportToModules;
|
||||
if (exportToModules.size() > 0) {
|
||||
buffer.append(" to").appendLineSeparator();
|
||||
appendFQClassNames(buffer, exportToModules);
|
||||
}
|
||||
buffer.append(';').appendLineSeparator();
|
||||
newLineNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
|
||||
|
||||
List<StructModuleAttribute.OpensEntry> opensEntries = moduleAttribute.opens;
|
||||
if (!opensEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (StructModuleAttribute.OpensEntry opens : opensEntries) {
|
||||
if (!isGenerated(opens.flags)) {
|
||||
buffer.appendIndent(1).append("opens ").append(opens.packageName.replace('/', '.'));
|
||||
List<String> opensToModules = opens.opensToModules;
|
||||
if (opensToModules.size() > 0) {
|
||||
buffer.append(" to").appendLineSeparator();
|
||||
appendFQClassNames(buffer, opensToModules);
|
||||
}
|
||||
buffer.append(';').appendLineSeparator();
|
||||
newLineNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> usesEntries = moduleAttribute.uses;
|
||||
if (!usesEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (String uses : usesEntries) {
|
||||
buffer.appendIndent(1).append("uses ").append(ExprProcessor.buildJavaClassName(uses)).append(';').appendLineSeparator();
|
||||
}
|
||||
newLineNeeded = true;
|
||||
}
|
||||
|
||||
List<StructModuleAttribute.ProvidesEntry> providesEntries = moduleAttribute.provides;
|
||||
if (!providesEntries.isEmpty()) {
|
||||
if (newLineNeeded) buffer.appendLineSeparator();
|
||||
for (StructModuleAttribute.ProvidesEntry provides : providesEntries) {
|
||||
buffer.appendIndent(1).append("provides ").append(ExprProcessor.buildJavaClassName(provides.interfaceName)).append(" with").appendLineSeparator();
|
||||
appendFQClassNames(buffer, provides.implementationNames.stream().map(ExprProcessor::buildJavaClassName).collect(Collectors.toList()));
|
||||
buffer.append(';').appendLineSeparator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String toValidJavaIdentifier(String name) {
|
||||
if (name == null || name.isEmpty()) return name;
|
||||
private static boolean isGenerated(int flags) {
|
||||
return (flags & (CodeConstants.ACC_SYNTHETIC | CodeConstants.ACC_MANDATED)) != 0;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
StringBuilder res = new StringBuilder(name.length());
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if ((i == 0 && !Character.isJavaIdentifierStart(c))
|
||||
|| (i > 0 && !Character.isJavaIdentifierPart(c))) {
|
||||
changed = true;
|
||||
res.append("_");
|
||||
}
|
||||
else {
|
||||
res.append(c);
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
return name;
|
||||
}
|
||||
return res.append("/* $FF was: ").append(name).append("*/").toString();
|
||||
private static void addTracer(StructClass cls, StructMethod method, BytecodeMappingTracer tracer) {
|
||||
StructLineNumberTableAttribute table = method.getAttribute(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
|
||||
tracer.setLineNumberTable(table);
|
||||
String key = InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor());
|
||||
DecompilerContext.getBytecodeSourceMapper().addTracer(cls.qualifiedName, key, tracer);
|
||||
}
|
||||
|
||||
private boolean methodToJava(ClassNode node, StructMethod mt, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {
|
||||
@@ -822,7 +657,31 @@ public class ClassWriter {
|
||||
appendComment(buffer, "bridge method", indent);
|
||||
}
|
||||
|
||||
appendAnnotations(buffer, indent, mt);
|
||||
GenericMethodDescriptor descriptor = null;
|
||||
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
|
||||
StructGenericSignatureAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE);
|
||||
if (attr != null) {
|
||||
descriptor = GenericMain.parseMethodSignature(attr.getSignature());
|
||||
if (descriptor != null) {
|
||||
long actualParams = md.params.length;
|
||||
List<VarVersionPair> mask = methodWrapper.synthParameters;
|
||||
if (mask != null) {
|
||||
actualParams = mask.stream().filter(Objects::isNull).count();
|
||||
}
|
||||
else if (isEnum && init) {
|
||||
actualParams -= 2;
|
||||
}
|
||||
if (actualParams != descriptor.parameterTypes.size()) {
|
||||
String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor() + " in " + cl.qualifiedName;
|
||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||
descriptor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int arrayDim = 0;
|
||||
if (descriptor != null) arrayDim = descriptor.returnType.arrayDim;
|
||||
appendAnnotations(buffer, arrayDim, indent, mt);
|
||||
|
||||
buffer.appendIndent(indent);
|
||||
|
||||
@@ -849,29 +708,6 @@ public class ClassWriter {
|
||||
clInit = true;
|
||||
}
|
||||
|
||||
GenericMethodDescriptor descriptor = null;
|
||||
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
|
||||
StructGenericSignatureAttribute attr = mt.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE);
|
||||
if (attr != null) {
|
||||
descriptor = GenericMain.parseMethodSignature(attr.getSignature());
|
||||
if (descriptor != null) {
|
||||
long actualParams = md.params.length;
|
||||
List<VarVersionPair> mask = methodWrapper.synthParameters;
|
||||
if (mask != null) {
|
||||
actualParams = mask.stream().filter(Objects::isNull).count();
|
||||
}
|
||||
else if (isEnum && init) {
|
||||
actualParams -= 2;
|
||||
}
|
||||
if (actualParams != descriptor.parameterTypes.size()) {
|
||||
String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor() + " in " + cl.qualifiedName;
|
||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
|
||||
descriptor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean throwsExceptions = false;
|
||||
int paramCount = 0;
|
||||
final List<TypeAnnotationWriteHelper> typeAnnwriteHelper = createTypeAnnWriteHelper(mt);
|
||||
@@ -1076,6 +912,171 @@ public class ClassWriter {
|
||||
return !hideMethod;
|
||||
}
|
||||
|
||||
private static boolean isVarArgRecord(StructClass cl) {
|
||||
String canonicalConstructorDescriptor =
|
||||
cl.getRecordComponents().stream().map(StructField::getDescriptor).collect(Collectors.joining("", "(", ")V"));
|
||||
StructMethod init = cl.getMethod(CodeConstants.INIT_NAME, canonicalConstructorDescriptor);
|
||||
return init != null && init.hasModifier(CodeConstants.ACC_VARARGS);
|
||||
}
|
||||
|
||||
public static void packageInfoToJava(StructClass cl, TextBuffer buffer) {
|
||||
appendAnnotations(buffer, 0, 0, cl);
|
||||
|
||||
int index = cl.qualifiedName.lastIndexOf('/');
|
||||
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
|
||||
buffer.append("package ").append(packageName).append(';').appendLineSeparator().appendLineSeparator();
|
||||
}
|
||||
|
||||
public static void moduleInfoToJava(StructClass cl, TextBuffer buffer) {
|
||||
appendAnnotations(buffer, 0, 0, cl);
|
||||
|
||||
StructModuleAttribute moduleAttribute = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
|
||||
|
||||
if ((moduleAttribute.moduleFlags & CodeConstants.ACC_OPEN) != 0) {
|
||||
buffer.append("open ");
|
||||
}
|
||||
|
||||
buffer.append("module ").append(moduleAttribute.moduleName).append(" {").appendLineSeparator();
|
||||
|
||||
writeModuleInfoBody(buffer, moduleAttribute);
|
||||
|
||||
buffer.append('}').appendLineSeparator();
|
||||
}
|
||||
|
||||
private static void methodLambdaToJava(ClassNode lambdaNode,
|
||||
ClassWrapper classWrapper,
|
||||
StructMethod mt,
|
||||
TextBuffer buffer,
|
||||
int indent,
|
||||
boolean codeOnly, BytecodeMappingTracer tracer) {
|
||||
MethodWrapper methodWrapper = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
|
||||
|
||||
MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
|
||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);
|
||||
|
||||
try {
|
||||
String method_name = lambdaNode.lambdaInformation.method_name;
|
||||
MethodDescriptor md_content = MethodDescriptor.parseDescriptor(lambdaNode.lambdaInformation.content_method_descriptor);
|
||||
MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(lambdaNode.lambdaInformation.method_descriptor);
|
||||
|
||||
if (!codeOnly) {
|
||||
buffer.appendIndent(indent);
|
||||
buffer.append("public ");
|
||||
buffer.append(method_name);
|
||||
buffer.append("(");
|
||||
|
||||
boolean firstParameter = true;
|
||||
int index = lambdaNode.lambdaInformation.is_content_method_static ? 0 : 1;
|
||||
int start_index = md_content.params.length - md_lambda.params.length;
|
||||
|
||||
for (int i = 0; i < md_content.params.length; i++) {
|
||||
if (i >= start_index) {
|
||||
if (!firstParameter) {
|
||||
buffer.append(", ");
|
||||
}
|
||||
|
||||
String typeName = ExprProcessor.getCastTypeName(md_content.params[i].copy(), Collections.emptyList());
|
||||
if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
|
||||
DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
|
||||
typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT, Collections.emptyList());
|
||||
}
|
||||
|
||||
buffer.append(typeName);
|
||||
buffer.append(" ");
|
||||
|
||||
String parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0));
|
||||
buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
|
||||
|
||||
firstParameter = false;
|
||||
}
|
||||
|
||||
index += md_content.params[i].stackSize;
|
||||
}
|
||||
|
||||
buffer.append(") {").appendLineSeparator();
|
||||
|
||||
indent += 1;
|
||||
}
|
||||
|
||||
RootStatement root = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
|
||||
if (!methodWrapper.decompiledWithErrors) {
|
||||
if (root != null) { // check for existence
|
||||
try {
|
||||
buffer.append(root.toJava(indent, tracer));
|
||||
}
|
||||
catch (Throwable t) {
|
||||
String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.";
|
||||
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN, t);
|
||||
methodWrapper.decompiledWithErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (methodWrapper.decompiledWithErrors) {
|
||||
buffer.appendIndent(indent);
|
||||
buffer.append("// $FF: Couldn't be decompiled");
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
|
||||
if (root != null) {
|
||||
tracer.addMapping(root.getDummyExit().bytecode);
|
||||
}
|
||||
|
||||
if (!codeOnly) {
|
||||
indent -= 1;
|
||||
buffer.appendIndent(indent).append('}').appendLineSeparator();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
private static String toValidJavaIdentifier(String name) {
|
||||
if (name == null || name.isEmpty()) return name;
|
||||
|
||||
boolean changed = false;
|
||||
StringBuilder res = new StringBuilder(name.length());
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if ((i == 0 && !Character.isJavaIdentifierStart(c))
|
||||
|| (i > 0 && !Character.isJavaIdentifierPart(c))) {
|
||||
changed = true;
|
||||
res.append("_");
|
||||
}
|
||||
else {
|
||||
res.append(c);
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
return name;
|
||||
}
|
||||
return res.append("/* $FF was: ").append(name).append("*/").toString();
|
||||
}
|
||||
|
||||
private static void recordComponentToJava(StructRecordComponent cd, TextBuffer buffer, boolean varArgComponent) {
|
||||
Map.Entry<VarType, GenericFieldDescriptor> fieldTypeData = getFieldTypeData(cd);
|
||||
VarType fieldType = fieldTypeData.getKey();
|
||||
GenericFieldDescriptor descriptor = fieldTypeData.getValue();
|
||||
|
||||
appendAnnotations(buffer, fieldType.arrayDim, -1, cd);
|
||||
|
||||
final List<TypeAnnotationWriteHelper> typeAnnwriteHelper = createTypeAnnWriteHelper(cd);
|
||||
|
||||
if (descriptor != null) {
|
||||
buffer.append(GenericMain.getGenericCastTypeName(varArgComponent ? descriptor.type.decreaseArrayDim() : descriptor.type, typeAnnwriteHelper));
|
||||
}
|
||||
else {
|
||||
buffer.append(ExprProcessor.getCastTypeName(varArgComponent ? fieldType.decreaseArrayDim() : fieldType, typeAnnwriteHelper));
|
||||
}
|
||||
if (varArgComponent) {
|
||||
buffer.append("...");
|
||||
}
|
||||
buffer.append(' ');
|
||||
|
||||
buffer.append(cd.getName());
|
||||
}
|
||||
|
||||
private static boolean hideConstructor(
|
||||
ClassNode node,
|
||||
boolean hasAnnotation,
|
||||
@@ -1194,11 +1195,32 @@ public class ClassWriter {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb) {
|
||||
private static void appendAnnotations(TextBuffer buffer, int arrayDim, int indent, StructMember mb) {
|
||||
// Check whether annotation will already be written as a type annotation to avoid duplication
|
||||
final var firstTypeAnnotation = Arrays.stream(StructGeneralAttribute.TYPE_ANNOTATION_ATTRIBUTES)
|
||||
.flatMap(attrKey -> {
|
||||
StructTypeAnnotationAttribute attribute = (StructTypeAnnotationAttribute)mb.getAttribute(attrKey);
|
||||
if (attribute == null) {
|
||||
return Stream.empty();
|
||||
} else {
|
||||
return attribute.getAnnotations().stream();
|
||||
}
|
||||
}).filter(typeAnnotation -> {
|
||||
StructTypePathEntry pathEntry = typeAnnotation.getPaths().stream().findFirst().orElse(null);
|
||||
if (pathEntry == null && arrayDim == 0) return true;
|
||||
if (pathEntry != null && pathEntry.getTypePathEntryKind() == StructTypePathEntry.Kind.ARRAY.getOpcode() &&
|
||||
typeAnnotation.getPaths().size() == arrayDim
|
||||
) return true;
|
||||
return false;
|
||||
}).findFirst();
|
||||
|
||||
for (StructGeneralAttribute.Key<?> key : StructGeneralAttribute.ANNOTATION_ATTRIBUTES) {
|
||||
StructAnnotationAttribute attribute = (StructAnnotationAttribute)mb.getAttribute(key);
|
||||
if (attribute != null) {
|
||||
for (AnnotationExprent annotation : attribute.getAnnotations()) {
|
||||
if (firstTypeAnnotation.isPresent() &&
|
||||
firstTypeAnnotation.get().getAnnotationExpr().getClassName().equals(annotation.getClassName())
|
||||
) continue;
|
||||
String text = annotation.toJava(indent, BytecodeMappingTracer.DUMMY).toString();
|
||||
buffer.append(text);
|
||||
if (indent < 0) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,5 +6,6 @@ public class ArrayNestedTypeAnnotations {
|
||||
Z.Y.@C X.W @F [] @A [] @B [] w3;
|
||||
Z.Y.X.@D W @D [] w4;
|
||||
@A Z.@B Y.@C X.@D W[][] w5;
|
||||
@L Z.Y.X.@L W[] @L [] w6;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ public class ArrayTypeAnnotations implements ParentInterface {
|
||||
@A String @B [] @C [] @D [] s7() {
|
||||
return null;// 10
|
||||
}
|
||||
|
||||
@L String @L [][] @L [] s8() {
|
||||
return null;// 11
|
||||
}
|
||||
}
|
||||
|
||||
class 'typeAnnotations/ArrayTypeAnnotations' {
|
||||
@@ -34,9 +38,15 @@ class 'typeAnnotations/ArrayTypeAnnotations' {
|
||||
0 17
|
||||
1 17
|
||||
}
|
||||
|
||||
method 's8 ()[[[Ljava/lang/String;' {
|
||||
0 21
|
||||
1 21
|
||||
}
|
||||
}
|
||||
|
||||
Lines mapping:
|
||||
8 <-> 10
|
||||
9 <-> 14
|
||||
10 <-> 18
|
||||
11 <-> 22
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package typeAnnotations;
|
||||
|
||||
public class ClassSuperTypeAnnotations extends @A Foo implements @B Bar, @B BarGeneric<@F String, @A String @B []> {
|
||||
public class ClassSuperTypeAnnotations extends @L @A Foo implements @B Bar, @B BarGeneric<@F String, @L @A String @B []> {
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,6 @@ public class GenericArrayNestedTypeAnnotations {
|
||||
V.U<String>.@C T<Boolean, Integer, Float> @B [] @D [] t3;
|
||||
V.U<@D String>.T<Boolean, Integer, Float> @F [] t4;
|
||||
@B V.@A U<@A String>.@A T<@E Boolean, @F Integer, Float>[] t5;
|
||||
@L V.U<String>.T<Boolean, Integer, Float>[][] t6;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ public class GenericArrayTypeAnnotations {
|
||||
@A List<@B Object @C [] @D []> @E [] @F [] l2() {
|
||||
return null;// 28
|
||||
}
|
||||
|
||||
@L List<Object[][]>[] @L [] l3() {
|
||||
return null;// 32
|
||||
}
|
||||
}
|
||||
|
||||
class 'typeAnnotations/GenericArrayTypeAnnotations' {
|
||||
@@ -44,9 +48,15 @@ class 'typeAnnotations/GenericArrayTypeAnnotations' {
|
||||
0 27
|
||||
1 27
|
||||
}
|
||||
|
||||
method 'l3 ()[[Ljava/util/List;' {
|
||||
0 31
|
||||
1 31
|
||||
}
|
||||
}
|
||||
|
||||
Lines mapping:
|
||||
20 <-> 20
|
||||
24 <-> 24
|
||||
28 <-> 28
|
||||
32 <-> 32
|
||||
|
||||
@@ -6,5 +6,6 @@ public class GenericNestedTypeAnnotations {
|
||||
V.U<String>.@C T<Boolean, Integer, Float> t3;
|
||||
V.U<@D String>.T<Boolean, Integer, Float> t4;
|
||||
V.U<String>.T<@E Boolean, @F Integer, Float> t5;
|
||||
@L V.U<String>.T<@L Boolean, @F Integer, Float> t6;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ public class GenericTypeAnnotations {
|
||||
Map<? extends @C @D String, List<Object>> m8;
|
||||
Map<? extends String, @D @E List<Object>> m9;
|
||||
Map<? extends String, List<@E @F Object>> m10;
|
||||
@A Map<@B ? extends @C String, @D List<@E Object>> m11;
|
||||
@A Map<@B ? extends @C String, @L @D List<@E Object>> m11;
|
||||
@L Map<? extends String, List<Object>> m13;
|
||||
|
||||
@A Map<@A Object, @B List<@C Object>> m12() {
|
||||
return null;// 18
|
||||
@@ -27,16 +28,16 @@ public class GenericTypeAnnotations {
|
||||
|
||||
class 'typeAnnotations/GenericTypeAnnotations' {
|
||||
method 'm12 ()Ljava/util/Map;' {
|
||||
0 19
|
||||
1 19
|
||||
0 20
|
||||
1 20
|
||||
}
|
||||
|
||||
method 'l1 ()Ljava/util/List;' {
|
||||
0 23
|
||||
1 23
|
||||
0 24
|
||||
1 24
|
||||
}
|
||||
}
|
||||
|
||||
Lines mapping:
|
||||
18 <-> 20
|
||||
19 <-> 24
|
||||
18 <-> 21
|
||||
19 <-> 25
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package typeAnnotations;
|
||||
|
||||
public interface InterfaceSuperTypeAnnotations extends @B Bar, @B BarGeneric<@F String, @A String @B []> {
|
||||
public interface InterfaceSuperTypeAnnotations extends @B Bar, @L @B BarGeneric<@F String, @L @A String @B []> {
|
||||
}
|
||||
|
||||
|
||||
@@ -4,45 +4,47 @@ import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MemberDeclarationTypeAnnotations<@A P extends @B Number & @F Serializable> {
|
||||
@L String s1 = "";
|
||||
@B int f1 = 0;
|
||||
|
||||
@K
|
||||
public @A MemberDeclarationTypeAnnotations() {
|
||||
}// 11
|
||||
public @L @A MemberDeclarationTypeAnnotations() {
|
||||
}// 13
|
||||
|
||||
@K
|
||||
public <@A T extends @B Number & @F Serializable> @C Number foo(@D T @E [] a) {
|
||||
return 0;// 15
|
||||
public <@A T extends @B Number & @F Serializable> @L @C Number foo(@D T @E [] a) {
|
||||
return 0;// 17
|
||||
}
|
||||
|
||||
@K
|
||||
public <T> @C Number bar(@D T @E [] a) throws @A IOException, @B IllegalStateException {
|
||||
return 0;// 20
|
||||
return 0;// 22
|
||||
}
|
||||
}
|
||||
|
||||
class 'typeAnnotations/MemberDeclarationTypeAnnotations' {
|
||||
method '<init> ()V' {
|
||||
9 10
|
||||
f 11
|
||||
}
|
||||
|
||||
method 'foo ([Ljava/lang/Number;)Ljava/lang/Number;' {
|
||||
0 14
|
||||
1 14
|
||||
4 14
|
||||
0 15
|
||||
1 15
|
||||
4 15
|
||||
}
|
||||
|
||||
method 'bar ([Ljava/lang/Object;)Ljava/lang/Number;' {
|
||||
0 19
|
||||
1 19
|
||||
4 19
|
||||
0 20
|
||||
1 20
|
||||
4 20
|
||||
}
|
||||
}
|
||||
|
||||
Lines mapping:
|
||||
11 <-> 11
|
||||
15 <-> 15
|
||||
20 <-> 20
|
||||
13 <-> 12
|
||||
17 <-> 16
|
||||
22 <-> 21
|
||||
Not mapped:
|
||||
7
|
||||
10
|
||||
9
|
||||
12
|
||||
|
||||
@@ -6,5 +6,6 @@ public class NestedTypeAnnotations {
|
||||
Z.Y.@C X.W w3;
|
||||
Z.Y.X.@D W w4;
|
||||
@A Z.@B Y.@C X.@D W w5;
|
||||
@L Z.Y.X.W w6;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,4 +6,5 @@ public class ArrayNestedTypeAnnotations {
|
||||
Z.Y.@C X.W @F [] @A [] @B [] w3;
|
||||
Z.Y.X.@D W @D [] w4;
|
||||
@A Z.@B Y.@C X.@D W[][] w5;
|
||||
@L Z. Y.X.@L W[] @L [] w6;
|
||||
}
|
||||
|
||||
@@ -8,4 +8,5 @@ public class ArrayTypeAnnotations implements ParentInterface {
|
||||
@A String[] s5() { return null; }
|
||||
String @B [] s6() { return null; }
|
||||
@A String @B [] @C [] @D [] s7() { return null; }
|
||||
@L String @L [][] @L [] s8() { return null; }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package typeAnnotations;
|
||||
|
||||
public class ClassSuperTypeAnnotations extends @A Foo implements @B Bar, @B BarGeneric<@F String, @A String @B []> {
|
||||
public class ClassSuperTypeAnnotations extends @L @A Foo implements @B Bar, @B BarGeneric<@F String, @L @A String @B []> {
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ public class GenericArrayNestedTypeAnnotations {
|
||||
V.U<String>.@C T<Boolean, Integer, Float> @B [] @D [] t3;
|
||||
V.U<@D String>.T<Boolean, Integer, Float> @F [] t4;
|
||||
@B V.@A U<@A String>.@A T<@E Boolean, @F Integer, Float>[] t5;
|
||||
@L V.U<String>.T<Boolean, Integer, Float>[][] t6;
|
||||
}
|
||||
|
||||
@@ -27,4 +27,8 @@ public class GenericArrayTypeAnnotations {
|
||||
@A List<@B Object @C [] @D []> @E [] @F [] l2() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@L List<Object[][]>[] @L [] l3() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ public class GenericNestedTypeAnnotations {
|
||||
V.U<String>.@C T<Boolean, Integer, Float> t3;
|
||||
V.U<@D String>.T<Boolean, Integer, Float> t4;
|
||||
V.U<String>.T<@E Boolean, @F Integer, Float> t5;
|
||||
@L V.U<String>.T<@L Boolean, @F Integer, Float> t6;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ public class GenericTypeAnnotations {
|
||||
Map<? extends @C @D String, List<Object>> m8;
|
||||
Map<? extends String, @D @E List<Object>> m9;
|
||||
Map<? extends String, List<@E @F Object>> m10;
|
||||
@A Map<@B ? extends @C String, @D List<@E Object>> m11;
|
||||
@A Map<@B ? extends @C String, @L @D List<@E Object>> m11;
|
||||
@A Map<@A Object, @B List<@C Object>> m12() { return null; }
|
||||
@A @B List<@C Object> l1() { return null; }
|
||||
@L Map<? extends String, List<Object>> m13;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package typeAnnotations;
|
||||
|
||||
public interface InterfaceSuperTypeAnnotations extends @B Bar, @B BarGeneric<@F String, @A String @B []> {
|
||||
public interface InterfaceSuperTypeAnnotations extends @B Bar, @L @B BarGeneric<@F String, @L @A String @B []> {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package typeAnnotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.FIELD})
|
||||
public @interface L {
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package typeAnnotations;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class LocalTypeAnnotations {
|
||||
// void simple() {
|
||||
// @A String hello = "Hello";
|
||||
// @B String space = " ";
|
||||
// @C String world = "World";
|
||||
// }
|
||||
//
|
||||
// void instanceOf() {
|
||||
// boolean isobj = "Hello world!" instanceof @B Object;
|
||||
// }
|
||||
//
|
||||
// void newArray() {
|
||||
// @A String @B [] hw = new @C String @D [0];
|
||||
// }
|
||||
//
|
||||
// void methodRef() {
|
||||
// BiFunction<String, Integer, Character> stringIntegerCharacterBiFunction = @C String::charAt;
|
||||
// }
|
||||
//
|
||||
// void typeArg() {
|
||||
// BiFunction<@D String, @E Integer, @F Character> stringIntegerCharacterBiFunction = String::charAt;
|
||||
// }
|
||||
//
|
||||
// void tryWithResources() {
|
||||
// try (@A BufferedReader br = new @B BufferedReader(new @C FileReader("test"))) {
|
||||
// } catch (@A FileNotFoundException e) {
|
||||
// e.printStackTrace();
|
||||
// } catch (@B IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
|
||||
void combined() {
|
||||
@A String hello = "Hello!";
|
||||
boolean isobj = hello instanceof @B Object;
|
||||
@C String world = " World!";
|
||||
BiFunction<String, Integer, Character> stringIntegerCharacterBiFunction = @D String::charAt;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader("test"))) {
|
||||
} catch (@E IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@F String test = " Test!";
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,16 @@ import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MemberDeclarationTypeAnnotations<@A P extends @B Number & @F Serializable> {
|
||||
@L String s1 = "";
|
||||
|
||||
@B int f1 = 0;
|
||||
|
||||
@K
|
||||
public @A MemberDeclarationTypeAnnotations() {
|
||||
public @L @A MemberDeclarationTypeAnnotations() {
|
||||
}
|
||||
|
||||
@K
|
||||
public <@A T extends @B Number & @F Serializable> @C Number foo(@D T @E [] a) {
|
||||
public <@A T extends @B Number & @F Serializable> @L @C Number foo(@D T @E [] a) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,4 +6,5 @@ public class NestedTypeAnnotations {
|
||||
Z.Y.@C X.W w3;
|
||||
Z.Y.X.@D W w4;
|
||||
@A Z.@B Y.@C X.@D W w5;
|
||||
@L Z.Y.X.W w6;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user