mirror of
https://github.com/konsoletyper/teavm.git
synced 2025-01-06 10:15:18 +08:00
Add tests for annotation field types
This commit is contained in:
parent
8daba1f09f
commit
dbd2c3f6bc
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* 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.teavm.classlib.java.lang.annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public enum TElementType {
|
||||||
|
ANNOTATION_TYPE,
|
||||||
|
CONSTRUCTOR,
|
||||||
|
FIELD,
|
||||||
|
LOCAL_VARIABLE,
|
||||||
|
METHOD,
|
||||||
|
PACKAGE,
|
||||||
|
PARAMETER,
|
||||||
|
TYPE
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* 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.teavm.classlib.java.lang.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
public @interface TRetention {
|
||||||
|
TRetentionPolicy value();
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* 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.teavm.classlib.java.lang.annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public enum TRetentionPolicy {
|
||||||
|
CLASS,
|
||||||
|
RUNTIME,
|
||||||
|
SOURCE
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* 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.teavm.classlib.java.lang.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
public @interface TTarget {
|
||||||
|
TElementType[] value();
|
||||||
|
}
|
@ -128,6 +128,7 @@ public class AnnotationClassTransformer implements ClassHolderTransformer {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
case AnnotationValue.ENUM:
|
case AnnotationValue.ENUM:
|
||||||
|
pe.initClass(value.getEnumValue().getClassName());
|
||||||
return pe.getField(value.getEnumValue(), type);
|
return pe.getField(value.getEnumValue(), type);
|
||||||
case AnnotationValue.CLASS:
|
case AnnotationValue.CLASS:
|
||||||
return pe.constant(value.getJavaClass());
|
return pe.constant(value.getJavaClass());
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.teavm.callgraph;
|
package org.teavm.callgraph;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import org.teavm.model.InstructionLocation;
|
import org.teavm.model.InstructionLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,4 +47,23 @@ public class DefaultClassAccessSite implements ClassAccessSite {
|
|||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
return className;
|
return className;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(location, callee, className);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof DefaultClassAccessSite)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DefaultClassAccessSite other = (DefaultClassAccessSite)obj;
|
||||||
|
return Objects.equals(location, other.location) &&
|
||||||
|
Objects.equals(callee, other.callee) &&
|
||||||
|
Objects.equals(className, other.className);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||||||
|
|
||||||
private Set<String> classesAddedByRoot = new HashSet<>();
|
private Set<String> classesAddedByRoot = new HashSet<>();
|
||||||
|
|
||||||
public ClassDependency linkClass(String className, CallLocation callLocation) {
|
public ClassDependency linkClass(final String className, final CallLocation callLocation) {
|
||||||
ClassDependency dep = classCache.map(className);
|
ClassDependency dep = classCache.map(className);
|
||||||
boolean added = true;
|
boolean added = true;
|
||||||
if (callLocation != null && callLocation.getMethod() != null) {
|
if (callLocation != null && callLocation.getMethod() != null) {
|
||||||
@ -215,9 +215,14 @@ public class DependencyChecker implements DependencyInfo {
|
|||||||
added = classesAddedByRoot.add(className);
|
added = classesAddedByRoot.add(className);
|
||||||
}
|
}
|
||||||
if (!dep.isMissing() && added) {
|
if (!dep.isMissing() && added) {
|
||||||
for (DependencyListener listener : listeners) {
|
tasks.add(new Runnable() {
|
||||||
listener.classAchieved(agent, className, callLocation);
|
@Override
|
||||||
}
|
public void run() {
|
||||||
|
for (DependencyListener listener : listeners) {
|
||||||
|
listener.classAchieved(agent, className, callLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return dep;
|
return dep;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import org.teavm.model.instructions.DoubleConstantInstruction;
|
|||||||
import org.teavm.model.instructions.ExitInstruction;
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
import org.teavm.model.instructions.FloatConstantInstruction;
|
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
import org.teavm.model.instructions.GetFieldInstruction;
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.InitClassInstruction;
|
||||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
import org.teavm.model.instructions.InvocationType;
|
import org.teavm.model.instructions.InvocationType;
|
||||||
import org.teavm.model.instructions.InvokeInstruction;
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
@ -203,6 +204,12 @@ public final class ProgramEmitter {
|
|||||||
return constructArray(ValueType.parse(type), size);
|
return constructArray(ValueType.parse(type), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initClass(String className) {
|
||||||
|
InitClassInstruction insn = new InitClassInstruction();
|
||||||
|
insn.setClassName(className);
|
||||||
|
addInstruction(insn);
|
||||||
|
}
|
||||||
|
|
||||||
public ProgramEmitter jump(BasicBlock block) {
|
public ProgramEmitter jump(BasicBlock block) {
|
||||||
JumpInstruction insn = new JumpInstruction();
|
JumpInstruction insn = new JumpInstruction();
|
||||||
insn.setTarget(block);
|
insn.setTarget(block);
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.teavm.parsing;
|
package org.teavm.parsing;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
@ -197,7 +198,8 @@ public final class Parser {
|
|||||||
private static AnnotationValue parseAnnotationValue(Object value) {
|
private static AnnotationValue parseAnnotationValue(Object value) {
|
||||||
if (value instanceof String[]) {
|
if (value instanceof String[]) {
|
||||||
String[] enumInfo = (String[])value;
|
String[] enumInfo = (String[])value;
|
||||||
return new AnnotationValue(new FieldReference(enumInfo[0], enumInfo[1]));
|
ValueType.Object object = (ValueType.Object)ValueType.parse(enumInfo[0]);
|
||||||
|
return new AnnotationValue(new FieldReference(object.getClassName(), enumInfo[1]));
|
||||||
} else if (value instanceof Type) {
|
} else if (value instanceof Type) {
|
||||||
Type cls = (Type)value;
|
Type cls = (Type)value;
|
||||||
return new AnnotationValue(ValueType.parse(cls.getDescriptor()));
|
return new AnnotationValue(ValueType.parse(cls.getDescriptor()));
|
||||||
@ -210,7 +212,8 @@ public final class Parser {
|
|||||||
return new AnnotationValue(resultList);
|
return new AnnotationValue(resultList);
|
||||||
} else if (value instanceof AnnotationNode) {
|
} else if (value instanceof AnnotationNode) {
|
||||||
AnnotationNode annotNode = (AnnotationNode)value;
|
AnnotationNode annotNode = (AnnotationNode)value;
|
||||||
AnnotationHolder annotation = new AnnotationHolder(annotNode.desc.replace('.', '/'));
|
ValueType.Object object = (ValueType.Object)ValueType.parse(annotNode.desc);
|
||||||
|
AnnotationHolder annotation = new AnnotationHolder(object.getClassName());
|
||||||
parseAnnotationValues(annotation, annotNode.values);
|
parseAnnotationValues(annotation, annotNode.values);
|
||||||
return new AnnotationValue(annotation);
|
return new AnnotationValue(annotation);
|
||||||
} else if (value instanceof String) {
|
} else if (value instanceof String) {
|
||||||
@ -229,6 +232,14 @@ public final class Parser {
|
|||||||
return new AnnotationValue((Float)value);
|
return new AnnotationValue((Float)value);
|
||||||
} else if (value instanceof Double) {
|
} else if (value instanceof Double) {
|
||||||
return new AnnotationValue((Double)value);
|
return new AnnotationValue((Double)value);
|
||||||
|
} else if (value.getClass().isArray()) {
|
||||||
|
List<AnnotationValue> resultList = new ArrayList<>();
|
||||||
|
int size = Array.getLength(value);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
Object item = Array.get(value, i);
|
||||||
|
resultList.add(parseAnnotationValue(item));
|
||||||
|
}
|
||||||
|
return new AnnotationValue(resultList);
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.teavm.classlib.java.lang;
|
package org.teavm.classlib.java.lang;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
@ -127,6 +128,26 @@ public class ClassTest {
|
|||||||
assertEquals(3, annot.x());
|
assertEquals(3, annot.x());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void annotationFieldTypesSupported() {
|
||||||
|
AnnotWithVariousFields annot = D.class.getAnnotation(AnnotWithVariousFields.class);
|
||||||
|
assertEquals(true, annot.a());
|
||||||
|
assertEquals((byte)2, annot.b());
|
||||||
|
assertEquals((short)3, annot.c());
|
||||||
|
assertEquals(4, annot.d());
|
||||||
|
assertEquals(5L, annot.e());
|
||||||
|
assertEquals(6.5, annot.f(), 0.01);
|
||||||
|
assertEquals(7.2, annot.g(), 0.01);
|
||||||
|
assertArrayEquals(new int[] { 2, 3 }, annot.h());
|
||||||
|
assertEquals(RetentionPolicy.CLASS, annot.i());
|
||||||
|
assertEquals(Retention.class, annot.j().annotationType());
|
||||||
|
assertEquals(1, annot.k().length);
|
||||||
|
assertEquals(RetentionPolicy.RUNTIME, annot.k()[0].value());
|
||||||
|
assertEquals("foo", annot.l());
|
||||||
|
assertArrayEquals(new String[] { "bar" }, annot.m());
|
||||||
|
assertEquals(Integer.class, annot.n());
|
||||||
|
}
|
||||||
|
|
||||||
@TestAnnot
|
@TestAnnot
|
||||||
private static class A {
|
private static class A {
|
||||||
}
|
}
|
||||||
@ -139,6 +160,12 @@ public class ClassTest {
|
|||||||
private static class C {
|
private static class C {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AnnotWithVariousFields(a = true, b = 2, c = 3, d = 4, e = 5, f = 6.5f, g = 7.2, h = { 2, 3 },
|
||||||
|
i = RetentionPolicy.CLASS, j = @Retention(RetentionPolicy.SOURCE),
|
||||||
|
k = { @Retention(RetentionPolicy.RUNTIME) }, l = "foo", m = "bar", n = Integer.class)
|
||||||
|
private static class D {
|
||||||
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
static @interface TestAnnot {
|
static @interface TestAnnot {
|
||||||
}
|
}
|
||||||
@ -147,4 +174,35 @@ public class ClassTest {
|
|||||||
static @interface AnnotWithDefaultField {
|
static @interface AnnotWithDefaultField {
|
||||||
int x() default 2;
|
int x() default 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
static @interface AnnotWithVariousFields {
|
||||||
|
boolean a();
|
||||||
|
|
||||||
|
byte b();
|
||||||
|
|
||||||
|
short c();
|
||||||
|
|
||||||
|
int d();
|
||||||
|
|
||||||
|
long e();
|
||||||
|
|
||||||
|
float f();
|
||||||
|
|
||||||
|
double g();
|
||||||
|
|
||||||
|
int[] h();
|
||||||
|
|
||||||
|
RetentionPolicy i();
|
||||||
|
|
||||||
|
Retention j();
|
||||||
|
|
||||||
|
Retention[] k();
|
||||||
|
|
||||||
|
String l();
|
||||||
|
|
||||||
|
String[] m();
|
||||||
|
|
||||||
|
Class<?> n();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user