Step 1: add top-level field/method/parameter annotations to stubs; include them in decompiled text.master
parent
a8403429ef
commit
52b31bf325
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2000-2016 JetBrains s.r.o. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.jetbrains.java.decompiler.modules.decompiler.exps; |
||||||
|
|
||||||
|
public class TypeAnnotation { |
||||||
|
public static final int CLASS_TYPE_PARAMETER = 0x00; |
||||||
|
public static final int METHOD_TYPE_PARAMETER = 0x01; |
||||||
|
public static final int SUPER_TYPE_REFERENCE = 0x10; |
||||||
|
public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; |
||||||
|
public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; |
||||||
|
public static final int FIELD = 0x13; |
||||||
|
public static final int METHOD_RETURN_TYPE = 0x14; |
||||||
|
public static final int METHOD_RECEIVER = 0x15; |
||||||
|
public static final int METHOD_PARAMETER = 0x16; |
||||||
|
public static final int THROWS_REFERENCE = 0x17; |
||||||
|
public static final int LOCAL_VARIABLE = 0x40; |
||||||
|
public static final int RESOURCE_VARIABLE = 0x41; |
||||||
|
public static final int CATCH_CLAUSE = 0x42; |
||||||
|
public static final int EXPR_INSTANCEOF = 0x43; |
||||||
|
public static final int EXPR_NEW = 0x44; |
||||||
|
public static final int EXPR_CONSTRUCTOR_REF = 0x45; |
||||||
|
public static final int EXPR_METHOD_REF = 0x46; |
||||||
|
public static final int TYPE_ARG_CAST = 0x47; |
||||||
|
public static final int TYPE_ARG_CONSTRUCTOR_CALL = 0x48; |
||||||
|
public static final int TYPE_ARG_METHOD_CALL = 0x49; |
||||||
|
public static final int TYPE_ARG_CONSTRUCTOR_REF = 0x4A; |
||||||
|
public static final int TYPE_ARG_METHOD_REF = 0x4B; |
||||||
|
|
||||||
|
private final int target; |
||||||
|
private final byte[] path; |
||||||
|
private final AnnotationExprent annotation; |
||||||
|
|
||||||
|
public TypeAnnotation(int target, byte[] path, AnnotationExprent annotation) { |
||||||
|
this.target = target; |
||||||
|
this.path = path; |
||||||
|
this.annotation = annotation; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTargetType() { |
||||||
|
return target >> 24; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIndex() { |
||||||
|
return target & 0x0FFFF; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isTopLevel() { |
||||||
|
return path == null; |
||||||
|
} |
||||||
|
|
||||||
|
public AnnotationExprent getAnnotation() { |
||||||
|
return annotation; |
||||||
|
} |
||||||
|
} |
@ -1,194 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2000-2014 JetBrains s.r.o. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
package org.jetbrains.java.decompiler.struct.attr; |
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent; |
|
||||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; |
|
||||||
|
|
||||||
import java.io.DataInputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
public class StructAnnotationTypeAttribute extends StructGeneralAttribute { |
|
||||||
|
|
||||||
private static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS = 0x00; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD = 0x01; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS = 0x10; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND = 0x11; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND = 0x12; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_FIELD = 0x13; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_RETURN = 0x14; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_RECEIVER = 0x15; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_FORMAL = 0x16; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_THROWS = 0x17; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE = 0x40; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE = 0x41; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_EXCEPTION = 0x42; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_INSTANCEOF = 0x43; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_NEW = 0x44; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_DOUBLE_COLON_NEW = 0x45; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_DOUBLE_COLON_ID = 0x46; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_CAST = 0x47; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_INVOCATION_CONSTRUCTOR = 0x48; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_INVOCATION_METHOD = 0x49; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_NEW = 0x4A; |
|
||||||
private static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_ID = 0x4B; |
|
||||||
|
|
||||||
private static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER = 1; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_SUPERTYPE = 2; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND = 3; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_EMPTY = 4; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_FORMAL_PARAMETER = 5; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_THROWS = 6; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_LOCAL_VAR = 7; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_CATCH = 8; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_OFFSET = 9; |
|
||||||
private static final int ANNOTATION_TARGET_UNION_TYPE_ARGUMENT = 10; |
|
||||||
|
|
||||||
@SuppressWarnings("FieldCanBeLocal") private List<AnnotationLocation> locations; |
|
||||||
@SuppressWarnings("FieldCanBeLocal") private List<AnnotationExprent> annotations; |
|
||||||
|
|
||||||
@Override |
|
||||||
public void initContent(ConstantPool pool) throws IOException { |
|
||||||
DataInputStream data = stream(); |
|
||||||
|
|
||||||
int len = data.readUnsignedByte(); |
|
||||||
if (len > 0) { |
|
||||||
locations = new ArrayList<AnnotationLocation>(len); |
|
||||||
annotations = new ArrayList<AnnotationExprent>(len); |
|
||||||
for (int i = 0; i < len; i++) { |
|
||||||
locations.add(parseAnnotationLocation(data)); |
|
||||||
annotations.add(StructAnnotationAttribute.parseAnnotation(data, pool)); |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
locations = Collections.emptyList(); |
|
||||||
annotations = Collections.emptyList(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static AnnotationLocation parseAnnotationLocation(DataInputStream data) throws IOException { |
|
||||||
AnnotationLocation ann_location = new AnnotationLocation(); |
|
||||||
|
|
||||||
// target type
|
|
||||||
ann_location.target_type = data.readUnsignedByte(); |
|
||||||
|
|
||||||
// target union
|
|
||||||
switch (ann_location.target_type) { |
|
||||||
case ANNOTATION_TARGET_TYPE_GENERIC_CLASS: |
|
||||||
case ANNOTATION_TARGET_TYPE_GENERIC_METHOD: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_SUPERTYPE; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND: |
|
||||||
case ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_FIELD: |
|
||||||
case ANNOTATION_TARGET_TYPE_RETURN: |
|
||||||
case ANNOTATION_TARGET_TYPE_RECEIVER: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_EMPTY; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_FORMAL: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_FORMAL_PARAMETER; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_THROWS: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_THROWS; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE: |
|
||||||
case ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_LOCAL_VAR; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_EXCEPTION: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_CATCH; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_INSTANCEOF: |
|
||||||
case ANNOTATION_TARGET_TYPE_NEW: |
|
||||||
case ANNOTATION_TARGET_TYPE_DOUBLE_COLON_NEW: |
|
||||||
case ANNOTATION_TARGET_TYPE_DOUBLE_COLON_ID: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_OFFSET; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_TYPE_CAST: |
|
||||||
case ANNOTATION_TARGET_TYPE_INVOCATION_CONSTRUCTOR: |
|
||||||
case ANNOTATION_TARGET_TYPE_INVOCATION_METHOD: |
|
||||||
case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_NEW: |
|
||||||
case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_ID: |
|
||||||
ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_ARGUMENT; |
|
||||||
break; |
|
||||||
default: |
|
||||||
throw new RuntimeException("Unknown target type in a type annotation!"); |
|
||||||
} |
|
||||||
|
|
||||||
// target union data
|
|
||||||
|
|
||||||
switch (ann_location.target_union) { |
|
||||||
case ANNOTATION_TARGET_UNION_TYPE_PARAMETER: |
|
||||||
case ANNOTATION_TARGET_UNION_FORMAL_PARAMETER: |
|
||||||
ann_location.data = new int[]{data.readUnsignedByte()}; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_UNION_SUPERTYPE: |
|
||||||
case ANNOTATION_TARGET_UNION_THROWS: |
|
||||||
case ANNOTATION_TARGET_UNION_CATCH: |
|
||||||
case ANNOTATION_TARGET_UNION_OFFSET: |
|
||||||
ann_location.data = new int[]{data.readUnsignedShort()}; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND: |
|
||||||
ann_location.data = new int[]{data.readUnsignedByte(), data.readUnsignedByte()}; |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_UNION_EMPTY: |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_UNION_LOCAL_VAR: |
|
||||||
int table_length = data.readUnsignedShort(); |
|
||||||
|
|
||||||
ann_location.data = new int[table_length * 3 + 1]; |
|
||||||
ann_location.data[0] = table_length; |
|
||||||
|
|
||||||
for (int i = 0; i < table_length; ++i) { |
|
||||||
ann_location.data[3 * i + 1] = data.readUnsignedShort(); |
|
||||||
ann_location.data[3 * i + 2] = data.readUnsignedShort(); |
|
||||||
ann_location.data[3 * i + 3] = data.readUnsignedShort(); |
|
||||||
} |
|
||||||
break; |
|
||||||
case ANNOTATION_TARGET_UNION_TYPE_ARGUMENT: |
|
||||||
ann_location.data = new int[]{data.readUnsignedShort(), data.readUnsignedByte()}; |
|
||||||
} |
|
||||||
|
|
||||||
// target path
|
|
||||||
int path_length = data.readUnsignedByte(); |
|
||||||
|
|
||||||
ann_location.target_path_kind = new int[path_length]; |
|
||||||
ann_location.target_argument_index = new int[path_length]; |
|
||||||
|
|
||||||
for (int i = 0; i < path_length; ++i) { |
|
||||||
ann_location.target_path_kind[i] = data.readUnsignedByte(); |
|
||||||
ann_location.target_argument_index[i] = data.readUnsignedByte(); |
|
||||||
} |
|
||||||
|
|
||||||
return ann_location; |
|
||||||
} |
|
||||||
|
|
||||||
private static class AnnotationLocation { |
|
||||||
public int target_type; |
|
||||||
public int target_union; |
|
||||||
public int[] data; |
|
||||||
public int[] target_path_kind; |
|
||||||
public int[] target_argument_index; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,107 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2000-2016 JetBrains s.r.o. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.jetbrains.java.decompiler.struct.attr; |
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent; |
||||||
|
import org.jetbrains.java.decompiler.modules.decompiler.exps.TypeAnnotation; |
||||||
|
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; |
||||||
|
|
||||||
|
import java.io.DataInputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
public class StructTypeAnnotationAttribute extends StructGeneralAttribute { |
||||||
|
private List<TypeAnnotation> annotations = Collections.emptyList(); |
||||||
|
|
||||||
|
@Override |
||||||
|
public void initContent(ConstantPool pool) throws IOException { |
||||||
|
DataInputStream data = stream(); |
||||||
|
|
||||||
|
int len = data.readUnsignedShort(); |
||||||
|
if (len > 0) { |
||||||
|
annotations = new ArrayList<>(len); |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
annotations.add(parse(data, pool)); |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
annotations = Collections.emptyList(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static TypeAnnotation parse(DataInputStream data, ConstantPool pool) throws IOException { |
||||||
|
int targetType = data.readUnsignedByte(); |
||||||
|
int target = targetType << 24; |
||||||
|
|
||||||
|
switch (targetType) { |
||||||
|
case TypeAnnotation.CLASS_TYPE_PARAMETER: |
||||||
|
case TypeAnnotation.METHOD_TYPE_PARAMETER: |
||||||
|
case TypeAnnotation.METHOD_PARAMETER: |
||||||
|
target |= data.readUnsignedByte(); |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeAnnotation.SUPER_TYPE_REFERENCE: |
||||||
|
case TypeAnnotation.CLASS_TYPE_PARAMETER_BOUND: |
||||||
|
case TypeAnnotation.METHOD_TYPE_PARAMETER_BOUND: |
||||||
|
case TypeAnnotation.THROWS_REFERENCE: |
||||||
|
case TypeAnnotation.CATCH_CLAUSE: |
||||||
|
case TypeAnnotation.EXPR_INSTANCEOF: |
||||||
|
case TypeAnnotation.EXPR_NEW: |
||||||
|
case TypeAnnotation.EXPR_CONSTRUCTOR_REF: |
||||||
|
case TypeAnnotation.EXPR_METHOD_REF: |
||||||
|
target |= data.readUnsignedShort(); |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeAnnotation.TYPE_ARG_CAST: |
||||||
|
case TypeAnnotation.TYPE_ARG_CONSTRUCTOR_CALL: |
||||||
|
case TypeAnnotation.TYPE_ARG_METHOD_CALL: |
||||||
|
case TypeAnnotation.TYPE_ARG_CONSTRUCTOR_REF: |
||||||
|
case TypeAnnotation.TYPE_ARG_METHOD_REF: |
||||||
|
data.skipBytes(3); |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeAnnotation.LOCAL_VARIABLE: |
||||||
|
case TypeAnnotation.RESOURCE_VARIABLE: |
||||||
|
data.skipBytes(data.readUnsignedShort() * 6); |
||||||
|
break; |
||||||
|
|
||||||
|
case TypeAnnotation.FIELD: |
||||||
|
case TypeAnnotation.METHOD_RETURN_TYPE: |
||||||
|
case TypeAnnotation.METHOD_RECEIVER: |
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
throw new RuntimeException("unknown target type: " + targetType); |
||||||
|
} |
||||||
|
|
||||||
|
int pathLength = data.readUnsignedByte(); |
||||||
|
byte[] path = null; |
||||||
|
if (pathLength > 0) { |
||||||
|
path = new byte[2 * pathLength]; |
||||||
|
data.readFully(path); |
||||||
|
} |
||||||
|
|
||||||
|
AnnotationExprent annotation = StructAnnotationAttribute.parseAnnotation(data, pool); |
||||||
|
|
||||||
|
return new TypeAnnotation(target, path, annotation); |
||||||
|
} |
||||||
|
|
||||||
|
public List<TypeAnnotation> getAnnotations() { |
||||||
|
return annotations; |
||||||
|
} |
||||||
|
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,44 @@ |
|||||||
|
package pkg; |
||||||
|
|
||||||
|
import java.lang.annotation.ElementType; |
||||||
|
import java.lang.annotation.Target; |
||||||
|
|
||||||
|
class TypeAnnotations { |
||||||
|
@TypeAnnotations.TA("field type") |
||||||
|
private String f1; |
||||||
|
@TypeAnnotations.MixA("field and type") |
||||||
|
private String f2; |
||||||
|
|
||||||
|
@TypeAnnotations.TA("return type") |
||||||
|
int m1() { |
||||||
|
return 42;// 18 |
||||||
|
} |
||||||
|
|
||||||
|
void m2(@TypeAnnotations.TA("parameter") int var1) { |
||||||
|
}// 21 |
||||||
|
|
||||||
|
@Target({ElementType.FIELD, ElementType.TYPE_USE}) |
||||||
|
@interface MixA { |
||||||
|
String value(); |
||||||
|
} |
||||||
|
|
||||||
|
@Target({ElementType.TYPE_USE}) |
||||||
|
@interface TA { |
||||||
|
String value(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class 'pkg/TypeAnnotations' { |
||||||
|
method 'm1 ()I' { |
||||||
|
0 13 |
||||||
|
2 13 |
||||||
|
} |
||||||
|
|
||||||
|
method 'm2 (I)V' { |
||||||
|
0 17 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Lines mapping: |
||||||
|
18 <-> 14 |
||||||
|
21 <-> 18 |
@ -0,0 +1,22 @@ |
|||||||
|
package pkg; |
||||||
|
|
||||||
|
import java.lang.annotation.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
class TypeAnnotations { |
||||||
|
@Target(ElementType.TYPE_USE) |
||||||
|
@interface TA { String value(); } |
||||||
|
|
||||||
|
@Target({ElementType.FIELD, ElementType.TYPE_USE}) |
||||||
|
@interface MixA { String value(); } |
||||||
|
|
||||||
|
private @TA("field type") String f1; |
||||||
|
|
||||||
|
private @MixA("field and type") String f2; |
||||||
|
|
||||||
|
@TA("return type") int m1() { |
||||||
|
return 42; |
||||||
|
} |
||||||
|
|
||||||
|
void m2(@TA("parameter") int i) { } |
||||||
|
} |
Loading…
Reference in new issue