[java, java-decompiler] type annotations in class files

Step 1: add top-level field/method/parameter annotations to stubs; include them in decompiled text.
This commit is contained in:
Roman Shevchenko
2016-04-21 21:22:36 +02:00
parent a8403429ef
commit 52b31bf325
13 changed files with 316 additions and 241 deletions

View File

@@ -23,10 +23,7 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
@@ -43,9 +40,7 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.gen.generics.*;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class ClassWriter {
private final PoolInterceptor interceptor;
@@ -311,7 +306,7 @@ public class ClassWriter {
appendComment(buffer, "synthetic class", indent);
}
appendAnnotations(buffer, cl, indent);
appendAnnotations(buffer, indent, cl, -1);
buffer.appendIndent(indent);
@@ -407,7 +402,7 @@ public class ClassWriter {
appendComment(buffer, "synthetic field", indent);
}
appendAnnotations(buffer, fd, indent);
appendAnnotations(buffer, indent, fd, TypeAnnotation.FIELD);
buffer.appendIndent(indent);
@@ -630,7 +625,7 @@ public class ClassWriter {
appendComment(buffer, "bridge method", indent);
}
appendAnnotations(buffer, mt, indent);
appendAnnotations(buffer, indent, mt, TypeAnnotation.METHOD_RETURN_TYPE);
buffer.appendIndent(indent);
@@ -816,7 +811,7 @@ public class ClassWriter {
StructAnnDefaultAttribute attr = (StructAnnDefaultAttribute)mt.getAttributes().getWithKey("AnnotationDefault");
if (attr != null) {
buffer.append(" default ");
buffer.append(attr.getDefaultValue().toJava(0, new BytecodeMappingTracer())); // dummy tracer
buffer.append(attr.getDefaultValue().toJava(0, BytecodeMappingTracer.DUMMY));
}
}
@@ -951,26 +946,30 @@ public class ClassWriter {
private static final String[] ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
private static final String[] PARAMETER_ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
private static final String[] TYPE_ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS};
private static void appendAnnotations(TextBuffer buffer, StructMember mb, int indent) {
BytecodeMappingTracer tracer_dummy = new BytecodeMappingTracer(); // FIXME: replace with a real one
private static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, int targetType) {
Set<String> filter = new HashSet<>();
for (String name : ANNOTATION_ATTRIBUTES) {
StructAnnotationAttribute attribute = (StructAnnotationAttribute)mb.getAttributes().getWithKey(name);
if (attribute != null) {
for (AnnotationExprent annotation : attribute.getAnnotations()) {
buffer.append(annotation.toJava(indent, tracer_dummy)).appendLineSeparator();
String text = annotation.toJava(indent, BytecodeMappingTracer.DUMMY).toString();
filter.add(text);
buffer.append(text).appendLineSeparator();
}
}
}
appendTypeAnnotations(buffer, indent, mb, targetType, -1, filter);
}
private static final String[] PARAMETER_ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
private static void appendParameterAnnotations(TextBuffer buffer, StructMethod mt, int param) {
BytecodeMappingTracer tracer_dummy = new BytecodeMappingTracer(); // FIXME: replace with a real one
Set<String> filter = new HashSet<>();
for (String name : PARAMETER_ANNOTATION_ATTRIBUTES) {
StructAnnotationParameterAttribute attribute = (StructAnnotationParameterAttribute)mt.getAttributes().getWithKey(name);
@@ -978,7 +977,33 @@ public class ClassWriter {
List<List<AnnotationExprent>> annotations = attribute.getParamAnnotations();
if (param < annotations.size()) {
for (AnnotationExprent annotation : annotations.get(param)) {
buffer.append(annotation.toJava(0, tracer_dummy)).append(' ');
String text = annotation.toJava(-1, BytecodeMappingTracer.DUMMY).toString();
filter.add(text);
buffer.append(text).append(' ');
}
}
}
}
appendTypeAnnotations(buffer, -1, mt, TypeAnnotation.METHOD_PARAMETER, param, filter);
}
private static void appendTypeAnnotations(TextBuffer buffer, int indent, StructMember mb, int targetType, int index, Set<String> filter) {
for (String name : TYPE_ANNOTATION_ATTRIBUTES) {
StructTypeAnnotationAttribute attribute = (StructTypeAnnotationAttribute)mb.getAttributes().getWithKey(name);
if (attribute != null) {
for (TypeAnnotation annotation : attribute.getAnnotations()) {
if (annotation.isTopLevel() && annotation.getTargetType() == targetType && (index < 0 || annotation.getIndex() == index)) {
String text = annotation.getAnnotation().toJava(indent, BytecodeMappingTracer.DUMMY).toString();
if (!filter.contains(text)) {
buffer.append(text);
if (indent < 0) {
buffer.append(' ');
}
else {
buffer.appendLineSeparator();
}
}
}
}
}