Add tests for annotation field types

This commit is contained in:
Alexey Andreev 2015-06-19 22:23:49 +03:00
parent 8daba1f09f
commit dbd2c3f6bc
10 changed files with 229 additions and 6 deletions

View File

@ -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
}

View File

@ -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();
}

View File

@ -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
}

View File

@ -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();
}

View File

@ -128,6 +128,7 @@ public class AnnotationClassTransformer implements ClassHolderTransformer {
return array;
}
case AnnotationValue.ENUM:
pe.initClass(value.getEnumValue().getClassName());
return pe.getField(value.getEnumValue(), type);
case AnnotationValue.CLASS:
return pe.constant(value.getJavaClass());

View File

@ -15,6 +15,7 @@
*/
package org.teavm.callgraph;
import java.util.Objects;
import org.teavm.model.InstructionLocation;
/**
@ -46,4 +47,23 @@ public class DefaultClassAccessSite implements ClassAccessSite {
public String getClassName() {
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);
}
}

View File

@ -203,7 +203,7 @@ public class DependencyChecker implements DependencyInfo {
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);
boolean added = true;
if (callLocation != null && callLocation.getMethod() != null) {
@ -215,9 +215,14 @@ public class DependencyChecker implements DependencyInfo {
added = classesAddedByRoot.add(className);
}
if (!dep.isMissing() && added) {
for (DependencyListener listener : listeners) {
listener.classAchieved(agent, className, callLocation);
}
tasks.add(new Runnable() {
@Override
public void run() {
for (DependencyListener listener : listeners) {
listener.classAchieved(agent, className, callLocation);
}
}
});
}
return dep;
}

View File

@ -23,6 +23,7 @@ import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
@ -203,6 +204,12 @@ public final class ProgramEmitter {
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) {
JumpInstruction insn = new JumpInstruction();
insn.setTarget(block);

View File

@ -15,6 +15,7 @@
*/
package org.teavm.parsing;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
@ -197,7 +198,8 @@ public final class Parser {
private static AnnotationValue parseAnnotationValue(Object value) {
if (value instanceof String[]) {
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) {
Type cls = (Type)value;
return new AnnotationValue(ValueType.parse(cls.getDescriptor()));
@ -210,7 +212,8 @@ public final class Parser {
return new AnnotationValue(resultList);
} else if (value instanceof AnnotationNode) {
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);
return new AnnotationValue(annotation);
} else if (value instanceof String) {
@ -229,6 +232,14 @@ public final class Parser {
return new AnnotationValue((Float)value);
} else if (value instanceof Double) {
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 {
throw new AssertionError();
}

View File

@ -15,6 +15,7 @@
*/
package org.teavm.classlib.java.lang;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@ -127,6 +128,26 @@ public class ClassTest {
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
private static class A {
}
@ -139,6 +160,12 @@ public class ClassTest {
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)
static @interface TestAnnot {
}
@ -147,4 +174,35 @@ public class ClassTest {
static @interface AnnotWithDefaultField {
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();
}
}