Merge branch 'pull-request__typeannotations' of https://github.com/joana-team/WALA
This commit is contained in:
commit
db65c16863
|
@ -167,7 +167,7 @@
|
|||
<param name="destdir" value="${temp.folder}/dalvik/@dot"/>
|
||||
<param name="jsv" value="1.6"/>
|
||||
<param name="jtv" value="1.6"/>
|
||||
<param name="excludes" value="**/bak/,**/SortingExample.java,defaultMethods/*.java,special/A.java"/>
|
||||
<param name="excludes" value="**/bak/,**/SortingExample.java,defaultMethods/*.java,special/A.java,annotations/TypeAnnotatedClass*.java, annotations/TypeAnnotationTypeUse.java"/>
|
||||
</antcall>
|
||||
</target>
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Hecker, KIT - initial implementation
|
||||
*******************************************************************************/
|
||||
package annotations;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TypeAnnotatedClass1 extends @TypeAnnotationTypeUse Object {
|
||||
|
||||
|
||||
@TypeAnnotationTypeUse
|
||||
List<Set<@TypeAnnotationTypeUse TypeAnnotatedClass1>> field;
|
||||
|
||||
@TypeAnnotationTypeUse Integer foo(@TypeAnnotationTypeUse int a, @TypeAnnotationTypeUse Object b) {
|
||||
|
||||
@TypeAnnotationTypeUse
|
||||
int x = 3;
|
||||
|
||||
@TypeAnnotationTypeUse
|
||||
Object y = new Object();
|
||||
|
||||
if (y instanceof @TypeAnnotationTypeUse(someKey = "lul") String) {
|
||||
x = 7;
|
||||
}
|
||||
|
||||
try {
|
||||
throw new NullPointerException();
|
||||
} catch (@TypeAnnotationTypeUse RuntimeException e) {
|
||||
x = 911;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Hecker, KIT - initial implementation
|
||||
*******************************************************************************/
|
||||
package annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TypeAnnotatedClass2 extends @TypeAnnotationTypeUse Object {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface A {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface B {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface C {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface D {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface E {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface F {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface G {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface H {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface I {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface J {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface K {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface L {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
@interface M {}
|
||||
|
||||
@A Map<@B ? extends @C String, @D List<@E Object>> field1;
|
||||
@I String @F [] @G [] @H [] field2;
|
||||
@A List<@B Comparable<@F Object @C [] @D [] @E []>> field3;
|
||||
@C Outer . @B Middle . @A Inner field4;
|
||||
Outer2 . Middle<@D Foo . @C Bar> . Inner<@B String @A []> field5;
|
||||
}
|
||||
|
||||
class Outer {
|
||||
class Middle {
|
||||
class Inner {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Outer2 {
|
||||
class Middle<S> {
|
||||
class Inner<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
class Bar {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Joana IFC project,
|
||||
* Programming Paradigms Group,
|
||||
* Karlsruhe Institute of Technology (KIT).
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* martin.hecker@kit.edu, KIT -
|
||||
*******************************************************************************/
|
||||
package annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.TYPE_USE})
|
||||
public @interface TypeAnnotationTypeUse {
|
||||
String someKey() default "lol";
|
||||
}
|
|
@ -27,6 +27,7 @@ import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil;
|
|||
import com.ibm.wala.core.tests.util.TestConstants;
|
||||
import com.ibm.wala.core.tests.util.WalaTestCase;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
|
@ -36,6 +37,7 @@ import com.ibm.wala.ipa.callgraph.Entrypoint;
|
|||
import com.ibm.wala.ipa.callgraph.impl.Util;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
|
||||
|
@ -65,12 +67,12 @@ public class NullPointerExceptionInterTest extends WalaTestCase {
|
|||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
cache = new AnalysisCache();
|
||||
cache = new AnalysisCacheImpl();
|
||||
scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
|
||||
(new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), NullPointerExceptionInterTest.class.getClassLoader());
|
||||
ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions());
|
||||
try {
|
||||
cha = ClassHierarchy.make(scope, factory);
|
||||
cha = ClassHierarchyFactory.make(scope, factory);
|
||||
Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, "Lcfg/exc/inter/CallFieldAccess");
|
||||
AnalysisOptions options = new AnalysisOptions(scope, entrypoints);
|
||||
|
||||
|
|
|
@ -31,10 +31,11 @@ import com.ibm.wala.classLoader.ClassLoaderFactoryImpl;
|
|||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.core.tests.util.TestConstants;
|
||||
import com.ibm.wala.core.tests.util.WalaTestCase;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ssa.ISSABasicBlock;
|
||||
import com.ibm.wala.ssa.SSACFG;
|
||||
|
@ -68,7 +69,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
ClassLoaderFactory factory = new ClassLoaderFactoryImpl(scope.getExclusions());
|
||||
|
||||
try {
|
||||
cha = ClassHierarchy.make(scope, factory);
|
||||
cha = ClassHierarchyFactory.make(scope, factory);
|
||||
} catch (ClassHierarchyException e) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testParam(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -124,7 +125,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testParam(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -158,7 +159,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testParam2(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -191,7 +192,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testDynamicParam2(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -226,7 +227,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testIf(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -260,7 +261,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testIf(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -294,7 +295,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testIf2(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -330,7 +331,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testIf2(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -367,7 +368,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testIfContinued(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -403,7 +404,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testIfContinued(ZLcfg/exc/intra/B;Lcfg/exc/intra/B;Lcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -439,7 +440,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testIf3(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -476,7 +477,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testIf3(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -513,7 +514,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testWhile(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -549,7 +550,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testWhile(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -585,7 +586,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testWhile2(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -619,7 +620,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testWhile2(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -653,7 +654,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccess.testGet(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
@ -689,7 +690,7 @@ public class NullPointerExceptionIntraTest extends WalaTestCase {
|
|||
MethodReference mr = StringStuff.makeMethodReference("cfg.exc.intra.FieldAccessDynamic.testGet(ZLcfg/exc/intra/B;)Lcfg/exc/intra/B");
|
||||
|
||||
IMethod m = cha.resolveMethod(mr);
|
||||
AnalysisCache cache = new AnalysisCache();
|
||||
AnalysisCacheImpl cache = new AnalysisCacheImpl();
|
||||
IR ir = cache.getIR(m);
|
||||
final ISSABasicBlock returnNode = returnNode(ir.getControlFlowGraph());
|
||||
final int returnVal = returnVal(returnNode);
|
||||
|
|
|
@ -0,0 +1,301 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2013,2016 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Martin Hecker, KIT - adaptation to type annotations
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.core.tests.ir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ibm.wala.classLoader.FieldImpl;
|
||||
import com.ibm.wala.classLoader.IClass;
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.classLoader.ShrikeCTMethod;
|
||||
import com.ibm.wala.classLoader.ShrikeClass;
|
||||
import com.ibm.wala.core.tests.util.JVMLTestAssertions;
|
||||
import com.ibm.wala.core.tests.util.TestAssertions;
|
||||
import com.ibm.wala.core.tests.util.WalaTestCase;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.ConstantElementValue;
|
||||
import com.ibm.wala.shrikeCT.AnnotationsReader.ElementValue;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.shrikeCT.TypeAnnotationsReader;
|
||||
import com.ibm.wala.shrikeCT.TypeAnnotationsReader.TargetType;
|
||||
import com.ibm.wala.shrikeCT.TypeAnnotationsReader.TypePathKind;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
import com.ibm.wala.types.MethodReference;
|
||||
import com.ibm.wala.types.Selector;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.types.annotations.TypeAnnotation;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
import com.ibm.wala.util.strings.Atom;
|
||||
|
||||
public class TypeAnnotationTest extends WalaTestCase {
|
||||
|
||||
private final IClassHierarchy cha;
|
||||
|
||||
private final TestAssertions harness;
|
||||
|
||||
protected TypeAnnotationTest(TestAssertions harness, IClassHierarchy cha) {
|
||||
this.cha = cha;
|
||||
this.harness = harness;
|
||||
}
|
||||
|
||||
public TypeAnnotationTest() throws ClassHierarchyException, IOException {
|
||||
this(new JVMLTestAssertions(), WalaTestCase.makeCHA());
|
||||
}
|
||||
|
||||
private final String typeAnnotatedClass1 = "Lannotations/TypeAnnotatedClass1";
|
||||
private final String typeAnnotatedClass2 = "Lannotations/TypeAnnotatedClass2";
|
||||
|
||||
@Test
|
||||
public void testClassAnnotations5() throws Exception {
|
||||
TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, typeAnnotatedClass1);
|
||||
|
||||
Collection<TypeAnnotation> expectedRuntimeInvisibleAnnotations = HashSetFactory.make();
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
// TODO: currently, annotations will reference class loaders from which they were loaded, even if the type
|
||||
// comes from, e.g., primordial (e.g.: Application instead of Primordial).
|
||||
// See {@link TypeAnnotation#fromString(ClassLoaderReference, String)}
|
||||
new TypeAnnotation.SuperTypeTarget(TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/Object")),
|
||||
TargetType.CLASS_EXTENDS
|
||||
)
|
||||
);
|
||||
|
||||
Collection<TypeAnnotation> expectedRuntimeVisibleAnnotations = HashSetFactory.make();
|
||||
|
||||
testClassAnnotations(typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassAnnotations5Foo() throws Exception {
|
||||
// TODO: the catchIIndex is obviously somewhat unstable wrt change in generated bytecode (and changes in Decoder).
|
||||
// Just change it whenever a test starts to fail
|
||||
final int catchIIndex = 16;
|
||||
|
||||
// TODO: the instanceOfIIndex is obviously somewhat unstable wrt change in generated bytecode (and changes in Decoder).
|
||||
// This is even more so true since apparently, some compilers generate (for an instanceof test) the bytecode index
|
||||
// not of the instanceof instruction (as required per spec:
|
||||
// "The value of the offset item specifies the code array offset of either the instanceof bytecode instruction
|
||||
// corresponding to the instanceof expression, ..."
|
||||
// ), but instead of the preceding aload instruction.
|
||||
//
|
||||
// Just change it whenever a test starts to fail
|
||||
final int instanceOfIIndex = 6;
|
||||
|
||||
TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, typeAnnotatedClass1);
|
||||
|
||||
MethodReference methodRefUnderTest = MethodReference.findOrCreate(typeUnderTest, Selector.make("foo(ILjava/lang/Object;)Ljava/lang/Integer;"));
|
||||
|
||||
Collection<TypeAnnotation> expectedRuntimeInvisibleAnnotations = HashSetFactory.make();
|
||||
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
new TypeAnnotation.LocalVarTarget(3, "x"),
|
||||
TargetType.LOCAL_VARIABLE
|
||||
)
|
||||
);
|
||||
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
new TypeAnnotation.LocalVarTarget(4, "y"),
|
||||
TargetType.LOCAL_VARIABLE
|
||||
)
|
||||
);
|
||||
|
||||
// TODO: comment wrt. ClassLoaderReference in testClassAnnotations5() also applies here
|
||||
final TypeReference runtimeExceptionRef = TypeReference.findOrCreate(ClassLoaderReference.Application, "Ljava/lang/RuntimeException");
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
new TypeAnnotation.CatchTarget(catchIIndex, runtimeExceptionRef),
|
||||
TargetType.EXCEPTION_PARAMETER
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
final Map<String,ElementValue> values = HashMapFactory.make();
|
||||
values.put("someKey", new ConstantElementValue("lul"));
|
||||
// TODO: comment wrt. ClassLoaderReference in testClassAnnotations5() also applies here
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.makeWithNamed(
|
||||
TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse"),
|
||||
values
|
||||
),
|
||||
new TypeAnnotation.OffsetTarget(instanceOfIIndex),
|
||||
TargetType.INSTANCEOF
|
||||
)
|
||||
);
|
||||
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
new TypeAnnotation.EmptyTarget(),
|
||||
TargetType.METHOD_RETURN
|
||||
)
|
||||
);
|
||||
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
new TypeAnnotation.FormalParameterTarget(0),
|
||||
TargetType.METHOD_FORMAL_PARAMETER
|
||||
)
|
||||
);
|
||||
|
||||
expectedRuntimeInvisibleAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
new TypeAnnotation.FormalParameterTarget(1),
|
||||
TargetType.METHOD_FORMAL_PARAMETER
|
||||
)
|
||||
);
|
||||
|
||||
Collection<TypeAnnotation> expectedRuntimeVisibleAnnotations = HashSetFactory.make();
|
||||
|
||||
testMethodAnnotations(methodRefUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassAnnotations5field() throws Exception {
|
||||
TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, typeAnnotatedClass1);
|
||||
|
||||
|
||||
Collection<TypeAnnotation> expectedAnnotations = HashSetFactory.make();
|
||||
expectedAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
TypeAnnotationsReader.TYPEPATH_EMPTY,
|
||||
new TypeAnnotation.EmptyTarget(),
|
||||
TargetType.FIELD
|
||||
)
|
||||
);
|
||||
|
||||
final List<Pair<TypePathKind, Integer>> path = new LinkedList<Pair<TypePathKind,Integer>>();
|
||||
path.add(Pair.make(TypeAnnotationsReader.TypePathKind.TYPE_ARGUMENT, 0));
|
||||
path.add(Pair.make(TypeAnnotationsReader.TypePathKind.TYPE_ARGUMENT, 0));
|
||||
|
||||
expectedAnnotations.add(
|
||||
TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, "Lannotations/TypeAnnotationTypeUse")),
|
||||
path,
|
||||
new TypeAnnotation.EmptyTarget(),
|
||||
TargetType.FIELD
|
||||
)
|
||||
);
|
||||
|
||||
testFieldAnnotations("field", typeUnderTest, expectedAnnotations);
|
||||
}
|
||||
|
||||
private TypeAnnotation makeForAnnotations6(String annotation, List<Pair<TypePathKind, Integer>> path) {
|
||||
return TypeAnnotation.make(
|
||||
Annotation.make(TypeReference.findOrCreate(ClassLoaderReference.Application, typeAnnotatedClass2 + "$" + annotation)),
|
||||
path,
|
||||
new TypeAnnotation.EmptyTarget(),
|
||||
TargetType.FIELD
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassAnnotations6field1() throws Exception {
|
||||
TypeReference typeUnderTest = TypeReference.findOrCreate(ClassLoaderReference.Application, typeAnnotatedClass2);
|
||||
|
||||
Collection<TypeAnnotation> expectedAnnotations = HashSetFactory.make();
|
||||
{
|
||||
final List<Pair<TypePathKind, Integer>> pathA = new LinkedList<Pair<TypePathKind,Integer>>();
|
||||
expectedAnnotations.add(makeForAnnotations6("A", pathA));
|
||||
}
|
||||
{
|
||||
final List<Pair<TypePathKind, Integer>> pathB = new LinkedList<Pair<TypePathKind,Integer>>();
|
||||
pathB.add(Pair.make(TypeAnnotationsReader.TypePathKind.TYPE_ARGUMENT, 0));
|
||||
expectedAnnotations.add(makeForAnnotations6("B", pathB));
|
||||
}
|
||||
{
|
||||
final List<Pair<TypePathKind, Integer>> pathC = new LinkedList<Pair<TypePathKind,Integer>>();
|
||||
pathC.add(Pair.make(TypeAnnotationsReader.TypePathKind.TYPE_ARGUMENT, 0));
|
||||
pathC.add(Pair.make(TypeAnnotationsReader.TypePathKind.WILDCARD_BOUND, 0));
|
||||
expectedAnnotations.add(makeForAnnotations6("C", pathC));
|
||||
}
|
||||
{
|
||||
final List<Pair<TypePathKind, Integer>> pathD = new LinkedList<Pair<TypePathKind,Integer>>();
|
||||
pathD.add(Pair.make(TypeAnnotationsReader.TypePathKind.TYPE_ARGUMENT, 1));
|
||||
expectedAnnotations.add(makeForAnnotations6("D", pathD));
|
||||
}
|
||||
{
|
||||
final List<Pair<TypePathKind, Integer>> pathE = new LinkedList<Pair<TypePathKind,Integer>>();
|
||||
pathE.add(Pair.make(TypeAnnotationsReader.TypePathKind.TYPE_ARGUMENT, 1));
|
||||
pathE.add(Pair.make(TypeAnnotationsReader.TypePathKind.TYPE_ARGUMENT, 0));
|
||||
expectedAnnotations.add(makeForAnnotations6("E", pathE));
|
||||
}
|
||||
testFieldAnnotations("field1", typeUnderTest, expectedAnnotations);
|
||||
}
|
||||
|
||||
private void testClassAnnotations(TypeReference typeUnderTest, Collection<TypeAnnotation> expectedRuntimeInvisibleAnnotations,
|
||||
Collection<TypeAnnotation> expectedRuntimeVisibleAnnotations) throws IOException, ClassHierarchyException,
|
||||
InvalidClassFileException {
|
||||
IClass classUnderTest = cha.lookupClass(typeUnderTest);
|
||||
harness.assertNotNull(typeUnderTest.toString() + " not found", classUnderTest);
|
||||
harness.assertTrue(classUnderTest + " must be BytecodeClass", classUnderTest instanceof ShrikeClass);
|
||||
ShrikeClass bcClassUnderTest = (ShrikeClass) classUnderTest;
|
||||
|
||||
Collection<TypeAnnotation> runtimeInvisibleAnnotations = bcClassUnderTest.getTypeAnnotations(true);
|
||||
harness.assertEqualCollections(expectedRuntimeInvisibleAnnotations, runtimeInvisibleAnnotations);
|
||||
|
||||
Collection<TypeAnnotation> runtimeVisibleAnnotations = bcClassUnderTest.getTypeAnnotations(false);
|
||||
harness.assertEqualCollections(expectedRuntimeVisibleAnnotations, runtimeVisibleAnnotations);
|
||||
}
|
||||
|
||||
private void testMethodAnnotations(MethodReference methodRefUnderTest, Collection<TypeAnnotation> expectedRuntimeInvisibleAnnotations,
|
||||
Collection<TypeAnnotation> expectedRuntimeVisibleAnnotations) throws IOException, ClassHierarchyException,
|
||||
InvalidClassFileException {
|
||||
IMethod methodUnderTest = cha.resolveMethod(methodRefUnderTest);
|
||||
harness.assertNotNull(methodRefUnderTest.toString() + " not found", methodUnderTest);
|
||||
harness.assertTrue(methodUnderTest + " must be ShrikeCTMethod", methodUnderTest instanceof ShrikeCTMethod);
|
||||
ShrikeCTMethod bcMethodUnderTest = (ShrikeCTMethod) methodUnderTest;
|
||||
|
||||
Collection<TypeAnnotation> runtimeInvisibleAnnotations = HashSetFactory.make();
|
||||
runtimeInvisibleAnnotations.addAll(bcMethodUnderTest.getTypeAnnotationsAtCode(true));
|
||||
runtimeInvisibleAnnotations.addAll(bcMethodUnderTest.getTypeAnnotationsAtMethodInfo(true));
|
||||
harness.assertEqualCollections(expectedRuntimeInvisibleAnnotations, runtimeInvisibleAnnotations);
|
||||
|
||||
Collection<TypeAnnotation> runtimeVisibleAnnotations = HashSetFactory.make();
|
||||
runtimeVisibleAnnotations.addAll(bcMethodUnderTest.getTypeAnnotationsAtCode(false));
|
||||
runtimeVisibleAnnotations.addAll(bcMethodUnderTest.getTypeAnnotationsAtMethodInfo(false));
|
||||
harness.assertEqualCollections(expectedRuntimeVisibleAnnotations, runtimeVisibleAnnotations);
|
||||
}
|
||||
|
||||
|
||||
private void testFieldAnnotations(String fieldNameStr, TypeReference typeUnderTest, Collection<TypeAnnotation> expectedAnnotations) throws IOException, ClassHierarchyException,
|
||||
InvalidClassFileException {
|
||||
IClass classUnderTest = cha.lookupClass(typeUnderTest);
|
||||
harness.assertNotNull(typeUnderTest.toString() + " not found", classUnderTest);
|
||||
harness.assertTrue(classUnderTest + " must be BytecodeClass", classUnderTest instanceof ShrikeClass);
|
||||
ShrikeClass bcClassUnderTest = (ShrikeClass) classUnderTest;
|
||||
|
||||
final Atom fieldName = Atom.findOrCreateUnicodeAtom(fieldNameStr);
|
||||
FieldImpl field = (FieldImpl) bcClassUnderTest.getField(fieldName);
|
||||
Collection<TypeAnnotation> annotations = field.getTypeAnnotations();
|
||||
harness.assertEqualCollections(expectedAnnotations, annotations);
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import com.ibm.wala.types.Selector;
|
|||
import com.ibm.wala.types.TypeName;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.types.annotations.TypeAnnotation;
|
||||
import com.ibm.wala.types.generics.TypeSignature;
|
||||
import com.ibm.wala.util.collections.BimodalMap;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
|
@ -568,7 +569,7 @@ public abstract class BytecodeClass<T extends IClassLoader> implements IClass {
|
|||
}
|
||||
|
||||
protected void addFieldToList(List<FieldImpl> L, Atom name, ImmutableByteArray fieldType, int accessFlags,
|
||||
Collection<Annotation> annotations, TypeSignature sig) {
|
||||
Collection<Annotation> annotations, Collection<TypeAnnotation> typeAnnotations, TypeSignature sig) {
|
||||
TypeName T = null;
|
||||
if (fieldType.get(fieldType.length() - 1) == ';') {
|
||||
T = TypeName.findOrCreate(fieldType, 0, fieldType.length() - 1);
|
||||
|
@ -577,7 +578,7 @@ public abstract class BytecodeClass<T extends IClassLoader> implements IClass {
|
|||
}
|
||||
TypeReference type = TypeReference.findOrCreate(getClassLoader().getReference(), T);
|
||||
FieldReference fr = FieldReference.findOrCreate(getReference(), name, type);
|
||||
FieldImpl f = new FieldImpl(this, fr, accessFlags, annotations, sig);
|
||||
FieldImpl f = new FieldImpl(this, fr, accessFlags, annotations, typeAnnotations, sig);
|
||||
L.add(f);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.ibm.wala.shrikeCT.ClassConstants;
|
|||
import com.ibm.wala.types.FieldReference;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.types.annotations.TypeAnnotation;
|
||||
import com.ibm.wala.types.generics.TypeSignature;
|
||||
import com.ibm.wala.util.strings.Atom;
|
||||
|
||||
|
@ -34,14 +35,22 @@ public final class FieldImpl implements IField {
|
|||
private final int accessFlags;
|
||||
|
||||
private final Collection<Annotation> annotations;
|
||||
|
||||
private final Collection<TypeAnnotation> typeAnnotations;
|
||||
|
||||
private final TypeSignature genericSignature;
|
||||
|
||||
public FieldImpl(IClass declaringClass, FieldReference canonicalRef, int accessFlags, Collection<Annotation> annotations, TypeSignature sig) {
|
||||
this(declaringClass, canonicalRef, accessFlags, annotations, null, sig);
|
||||
}
|
||||
|
||||
public FieldImpl(IClass declaringClass, FieldReference canonicalRef, int accessFlags, Collection<Annotation> annotations,
|
||||
Collection<TypeAnnotation> typeAnnotations, TypeSignature sig) {
|
||||
this.declaringClass = declaringClass;
|
||||
this.fieldRef = canonicalRef;
|
||||
this.accessFlags = accessFlags;
|
||||
this.annotations = annotations;
|
||||
this.typeAnnotations = typeAnnotations;
|
||||
this.genericSignature = sig;
|
||||
if (declaringClass == null) {
|
||||
throw new IllegalArgumentException("null declaringClass");
|
||||
|
@ -156,5 +165,7 @@ public final class FieldImpl implements IField {
|
|||
return annotations == null ? null : Collections.unmodifiableCollection(annotations);
|
||||
}
|
||||
|
||||
|
||||
public Collection<TypeAnnotation> getTypeAnnotations() {
|
||||
return typeAnnotations == null ? null : Collections.unmodifiableCollection(typeAnnotations);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@ public interface IBytecodeMethod extends IMethod {
|
|||
*/
|
||||
int getBytecodeIndex(int i) throws InvalidClassFileException;
|
||||
|
||||
/**
|
||||
* @return the instuction index i in the getInstructions() array corresponding to the bytecode index bcIndex
|
||||
*/
|
||||
int getInstructionIndex(int bcIndex) throws InvalidClassFileException;
|
||||
|
||||
/**
|
||||
* @return the Shrike representation of the exception handlers
|
||||
*/
|
||||
|
|
|
@ -159,6 +159,41 @@ public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants {
|
|||
return getBCInfo().pcMap[instructionIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Shrike instruction index for a particular valid program counter (bytecode index), or -1 if
|
||||
* the Shrike instriction index could not be determined.
|
||||
*
|
||||
* This ShrikeBTMethod must not be native.
|
||||
*
|
||||
* @throws InvalidClassFileException, {@link UnsupportedOperationException}
|
||||
*/
|
||||
public int getInstructionIndex(int bcIndex) throws InvalidClassFileException {
|
||||
if (isNative()) {
|
||||
throw new UnsupportedOperationException("getInstructionIndex(int bcIndex) is only supported for non-native bytecode");
|
||||
}
|
||||
|
||||
final BytecodeInfo info = getBCInfo();
|
||||
if (info.decoder.containsSubroutines()) return -1;
|
||||
|
||||
final int[] pcMap = info.pcMap;
|
||||
assert isSorted(pcMap);
|
||||
|
||||
int iindex = Arrays.binarySearch(pcMap, bcIndex);
|
||||
if (iindex < 0) return -1;
|
||||
|
||||
// Unfortunately, pcMap is not always *strictly* sorted: given bcIndex, there may be multiple adjacent indices
|
||||
// i,j such that pcMap[i] == bcIndex == pcMap[j]. We pick the least such index.
|
||||
while (iindex > 0 && pcMap[iindex - 1] == bcIndex) iindex--;
|
||||
return iindex;
|
||||
}
|
||||
|
||||
private static boolean isSorted(int[] a) {
|
||||
for (int i = 0; i < a.length - 1; i++) {
|
||||
if (a[i+1] < a[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of Shrike instructions for this method.
|
||||
*
|
||||
|
|
|
@ -31,9 +31,11 @@ import com.ibm.wala.shrikeCT.SignatureReader;
|
|||
import com.ibm.wala.shrikeCT.SourceFileReader;
|
||||
import com.ibm.wala.shrikeCT.SourcePositionTableReader;
|
||||
import com.ibm.wala.shrikeCT.SourcePositionTableReader.Position;
|
||||
import com.ibm.wala.shrikeCT.TypeAnnotationsReader;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.types.annotations.TypeAnnotation;
|
||||
import com.ibm.wala.types.generics.MethodTypeSignature;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
|
@ -377,6 +379,22 @@ public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMet
|
|||
|
||||
return AnnotationsReader.getReaderForAnnotation(type, iter);
|
||||
}
|
||||
|
||||
private TypeAnnotationsReader getTypeAnnotationsReaderAtMethodInfo(TypeAnnotationsReader.AnnotationType type) {
|
||||
ClassReader.AttrIterator iter = new AttrIterator();
|
||||
getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter);
|
||||
|
||||
return TypeAnnotationsReader.getReaderForAnnotationAtMethodInfo(type, iter, getExceptionReader(), getSignatureReader());
|
||||
}
|
||||
|
||||
private TypeAnnotationsReader getTypeAnnotationsReaderAtCode(TypeAnnotationsReader.AnnotationType type) {
|
||||
final CodeReader codeReader = getCodeReader();
|
||||
if (codeReader == null) return null;
|
||||
|
||||
ClassReader.AttrIterator iter = new ClassReader.AttrIterator();
|
||||
codeReader.initAttributeIterator(iter);
|
||||
return TypeAnnotationsReader.getReaderForAnnotationAtCode(type, iter, getCodeReader());
|
||||
}
|
||||
|
||||
private String computeGenericsSignature() throws InvalidClassFileException {
|
||||
SignatureReader reader = getSignatureReader();
|
||||
|
@ -437,6 +455,32 @@ public final class ShrikeCTMethod extends ShrikeBTMethod implements IBytecodeMet
|
|||
: AnnotationType.RuntimeVisibleAnnotations);
|
||||
return Annotation.getAnnotationsFromReader(r, getDeclaringClass().getClassLoader().getReference());
|
||||
}
|
||||
|
||||
public Collection<TypeAnnotation> getTypeAnnotationsAtMethodInfo(boolean runtimeInvisible) throws InvalidClassFileException {
|
||||
TypeAnnotationsReader r = getTypeAnnotationsReaderAtMethodInfo(
|
||||
runtimeInvisible ? TypeAnnotationsReader.AnnotationType.RuntimeInvisibleTypeAnnotations
|
||||
: TypeAnnotationsReader.AnnotationType.RuntimeVisibleTypeAnnotations
|
||||
);
|
||||
final ClassLoaderReference clRef = getDeclaringClass().getClassLoader().getReference();
|
||||
return TypeAnnotation.getTypeAnnotationsFromReader(
|
||||
r,
|
||||
TypeAnnotation.targetConverterAtMethodInfo(clRef, this),
|
||||
clRef
|
||||
);
|
||||
}
|
||||
|
||||
public Collection<TypeAnnotation> getTypeAnnotationsAtCode(boolean runtimeInvisible) throws InvalidClassFileException {
|
||||
TypeAnnotationsReader r = getTypeAnnotationsReaderAtCode(
|
||||
runtimeInvisible ? TypeAnnotationsReader.AnnotationType.RuntimeInvisibleTypeAnnotations
|
||||
: TypeAnnotationsReader.AnnotationType.RuntimeVisibleTypeAnnotations
|
||||
);
|
||||
final ClassLoaderReference clRef = getDeclaringClass().getClassLoader().getReference();
|
||||
return TypeAnnotation.getTypeAnnotationsFromReader(
|
||||
r,
|
||||
TypeAnnotation.targetConverterAtCode(clRef, this),
|
||||
clRef
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Annotation> getAnnotations() {
|
||||
|
|
|
@ -26,9 +26,12 @@ import com.ibm.wala.shrikeCT.InnerClassesReader;
|
|||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.shrikeCT.SignatureReader;
|
||||
import com.ibm.wala.shrikeCT.SourceFileReader;
|
||||
import com.ibm.wala.shrikeCT.TypeAnnotationsReader;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
import com.ibm.wala.types.TypeName;
|
||||
import com.ibm.wala.types.TypeReference;
|
||||
import com.ibm.wala.types.annotations.Annotation;
|
||||
import com.ibm.wala.types.annotations.TypeAnnotation;
|
||||
import com.ibm.wala.types.generics.ClassSignature;
|
||||
import com.ibm.wala.types.generics.TypeSignature;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
|
@ -90,6 +93,11 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
annotations.addAll(getRuntimeVisibleAnnotations(i));
|
||||
annotations = annotations.isEmpty() ? null : annotations;
|
||||
|
||||
Collection<TypeAnnotation> typeAnnotations = HashSetFactory.make();
|
||||
typeAnnotations.addAll(getRuntimeInvisibleTypeAnnotations(i));
|
||||
typeAnnotations.addAll(getRuntimeVisibleTypeAnnotations(i));
|
||||
typeAnnotations = typeAnnotations.isEmpty() ? null : typeAnnotations;
|
||||
|
||||
TypeSignature sig = null;
|
||||
SignatureReader signatureReader = getSignatureReader(i);
|
||||
if (signatureReader != null) {
|
||||
|
@ -100,9 +108,9 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
}
|
||||
|
||||
if ((accessFlags & ClassConstants.ACC_STATIC) == 0) {
|
||||
addFieldToList(instanceList, name, b, accessFlags, annotations, sig);
|
||||
addFieldToList(instanceList, name, b, accessFlags, annotations, typeAnnotations, sig);
|
||||
} else {
|
||||
addFieldToList(staticList, name, b, accessFlags, annotations, sig);
|
||||
addFieldToList(staticList, name, b, accessFlags, annotations, typeAnnotations, sig);
|
||||
}
|
||||
}
|
||||
instanceFields = new IField[instanceList.size()];
|
||||
|
@ -269,6 +277,29 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
return AnnotationsReader.getReaderForAnnotation(runtimeInvisable ? AnnotationType.RuntimeInvisibleAnnotations
|
||||
: AnnotationType.RuntimeVisibleAnnotations, attrs);
|
||||
}
|
||||
|
||||
public Collection<TypeAnnotation> getTypeAnnotations(boolean runtimeInvisible) throws InvalidClassFileException {
|
||||
TypeAnnotationsReader r = getTypeAnnotationsReader(runtimeInvisible);
|
||||
final ClassLoaderReference clRef = getClassLoader().getReference();
|
||||
return TypeAnnotation.getTypeAnnotationsFromReader(
|
||||
r,
|
||||
TypeAnnotation.targetConverterAtClassFile(clRef),
|
||||
clRef
|
||||
);
|
||||
}
|
||||
|
||||
private TypeAnnotationsReader getTypeAnnotationsReader(boolean runtimeInvisible) throws InvalidClassFileException {
|
||||
ClassReader r = reader.get();
|
||||
ClassReader.AttrIterator attrs = new ClassReader.AttrIterator();
|
||||
r.initClassAttributeIterator(attrs);
|
||||
|
||||
return TypeAnnotationsReader.getReaderForAnnotationAtClassfile(
|
||||
runtimeInvisible ? TypeAnnotationsReader.AnnotationType.RuntimeInvisibleTypeAnnotations
|
||||
: TypeAnnotationsReader.AnnotationType.RuntimeVisibleTypeAnnotations,
|
||||
attrs,
|
||||
getSignatureReader(-1)
|
||||
);
|
||||
}
|
||||
|
||||
interface GetReader<T> {
|
||||
T getReader(ClassReader.AttrIterator iter) throws InvalidClassFileException;
|
||||
|
@ -346,6 +377,43 @@ public final class ShrikeClass extends JVMClass<IClassLoader> {
|
|||
AnnotationsReader r = getFieldAnnotationsReader(runtimeInvisible, fieldIndex);
|
||||
return Annotation.getAnnotationsFromReader(r, getClassLoader().getReference());
|
||||
}
|
||||
|
||||
|
||||
|
||||
private TypeAnnotationsReader getFieldTypeAnnotationsReader(boolean runtimeInvisible, int fieldIndex) throws InvalidClassFileException {
|
||||
ClassReader.AttrIterator iter = new AttrIterator();
|
||||
reader.get().initFieldAttributeIterator(fieldIndex, iter);
|
||||
|
||||
return TypeAnnotationsReader.getReaderForAnnotationAtFieldInfo(
|
||||
runtimeInvisible ? TypeAnnotationsReader.AnnotationType.RuntimeInvisibleTypeAnnotations
|
||||
: TypeAnnotationsReader.AnnotationType.RuntimeVisibleTypeAnnotations,
|
||||
iter
|
||||
);
|
||||
|
||||
}
|
||||
/**
|
||||
* read the runtime-invisible type annotations from the class file
|
||||
*/
|
||||
public Collection<TypeAnnotation> getRuntimeInvisibleTypeAnnotations(int fieldIndex) throws InvalidClassFileException {
|
||||
return getFieldTypeAnnotations(fieldIndex, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* read the runtime-visible type annotations from the class file
|
||||
*/
|
||||
public Collection<TypeAnnotation> getRuntimeVisibleTypeAnnotations(int fieldIndex) throws InvalidClassFileException {
|
||||
return getFieldTypeAnnotations(fieldIndex, false);
|
||||
}
|
||||
|
||||
protected Collection<TypeAnnotation> getFieldTypeAnnotations(int fieldIndex, boolean runtimeInvisible) throws InvalidClassFileException {
|
||||
TypeAnnotationsReader r = getFieldTypeAnnotationsReader(runtimeInvisible, fieldIndex);
|
||||
final ClassLoaderReference clRef = getClassLoader().getReference();
|
||||
return TypeAnnotation.getTypeAnnotationsFromReader(
|
||||
r,
|
||||
TypeAnnotation.targetConverterAtFieldInfo(clRef),
|
||||
clRef
|
||||
);
|
||||
}
|
||||
|
||||
private SignatureReader getSignatureReader(int index) throws InvalidClassFileException {
|
||||
ClassReader r = reader.get();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3164,6 +3164,7 @@ public class DexIMethod implements IBytecodeMethod {
|
|||
return instructions().getPcFromIndex(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstructionIndex(int bytecodeindex) {
|
||||
return instructions().getIndexFromPc(bytecodeindex);
|
||||
}
|
||||
|
|
|
@ -1101,4 +1101,14 @@ public abstract class Decoder implements Constants {
|
|||
}
|
||||
return instructionsToBytecodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true iff the method decoded by this Decoder contains subroutines (JSRs)
|
||||
*/
|
||||
final public boolean containsSubroutines() {
|
||||
if (instructions == null) {
|
||||
throw new Error("Call decode() before calling containsSubroutines()");
|
||||
}
|
||||
return JSRs != null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public class AnnotationsReader extends AttributeReader {
|
|||
/**
|
||||
* offset in class file where this attribute begins
|
||||
*/
|
||||
private final int beginOffset;
|
||||
protected final int beginOffset;
|
||||
|
||||
public AnnotationsReader(ClassReader.AttrIterator iter, String label) throws InvalidClassFileException {
|
||||
super(iter, label);
|
||||
|
@ -63,7 +63,7 @@ public class AnnotationsReader extends AttributeReader {
|
|||
* offset in the class file at which the constant pool offset is
|
||||
* given
|
||||
*/
|
||||
private String getUtf8ConstantPoolValue(int offset) throws InvalidClassFileException {
|
||||
protected String getUtf8ConstantPoolValue(int offset) throws InvalidClassFileException {
|
||||
checkSize(offset, 2);
|
||||
int cpOffset = cr.getUShort(offset);
|
||||
return cr.getCP().getCPUtf8(cpOffset);
|
||||
|
@ -154,8 +154,17 @@ public class AnnotationsReader extends AttributeReader {
|
|||
|
||||
/**
|
||||
* get all the annotations declared in this attribute.
|
||||
* <pre>
|
||||
* RuntimeVisibleAnnotations_attribute {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
* u2 num_annotations;
|
||||
* annotation annotations[num_annotations];
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @throws InvalidClassFileException
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16"> JLS (SE8), 4.7.16</a>
|
||||
*/
|
||||
public AnnotationAttribute[] getAllAnnotations() throws InvalidClassFileException {
|
||||
AnnotationAttribute[] result = new AnnotationAttribute[getAnnotationCount()];
|
||||
|
@ -168,7 +177,7 @@ public class AnnotationsReader extends AttributeReader {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* param_annotations {
|
||||
|
@ -200,6 +209,9 @@ public class AnnotationsReader extends AttributeReader {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* annotation {
|
||||
|
@ -212,7 +224,7 @@ public class AnnotationsReader extends AttributeReader {
|
|||
*
|
||||
* @throws InvalidClassFileException
|
||||
*/
|
||||
private Pair<AnnotationAttribute, Integer> getAttributeAndSize(int begin) throws InvalidClassFileException {
|
||||
protected Pair<AnnotationAttribute, Integer> getAttributeAndSize(int begin) throws InvalidClassFileException {
|
||||
String type = getUtf8ConstantPoolValue(begin);
|
||||
int numElementValuePairs = cr.getUShort(begin + 2);
|
||||
int size = 4;
|
||||
|
@ -297,7 +309,7 @@ public class AnnotationsReader extends AttributeReader {
|
|||
* @throws InvalidClassFileException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
private Pair<ElementValue, Integer> readElementValueAndSize(int offset) throws IllegalArgumentException,
|
||||
protected Pair<ElementValue, Integer> readElementValueAndSize(int offset) throws IllegalArgumentException,
|
||||
InvalidClassFileException {
|
||||
char tag = (char) cr.getByte(offset);
|
||||
// meaning of this short depends on the tag
|
||||
|
@ -351,6 +363,7 @@ public class AnnotationsReader extends AttributeReader {
|
|||
public static enum AnnotationType {
|
||||
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations,RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations
|
||||
}
|
||||
|
||||
|
||||
public static boolean isKnownAnnotation(String name) {
|
||||
for (AnnotationType t : AnnotationType.values()) {
|
||||
|
|
|
@ -325,6 +325,13 @@ public final class ClassReader implements ClassConstants {
|
|||
public byte getByte(int i) {
|
||||
return bytes[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the unsigned 8-bit value at offset i in the class data
|
||||
*/
|
||||
public int getUnsignedByte(int i) {
|
||||
return ((int) bytes[i]) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of fields in the class
|
||||
|
|
|
@ -0,0 +1,809 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Martin Hecker, KIT - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.shrikeCT;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
|
||||
/**
|
||||
* This class reads TypeAnnotations attributes, i.e.: RuntimeInvisibleTypeAnnotations and RuntimeVisibleTypeAnnotations
|
||||
*
|
||||
* @author Martin Hecker martin.hecker@kit.edu
|
||||
*/
|
||||
public class TypeAnnotationsReader extends AnnotationsReader {
|
||||
|
||||
/**
|
||||
* required for {@link TypeAnnotationLocation#method_info} readers
|
||||
*/
|
||||
private final ExceptionsReader exceptionReader;
|
||||
|
||||
|
||||
/**
|
||||
* required for {@link TypeAnnotationLocation#Code} readers
|
||||
*/
|
||||
private final CodeReader codeReader;
|
||||
|
||||
/**
|
||||
* required for {@link TypeAnnotationLocation#method_info}
|
||||
* and for {@link TypeAnnotationLocation#ClassFile} readers
|
||||
*/
|
||||
private final SignatureReader signatureReader;
|
||||
|
||||
private final TypeAnnotationLocation location;
|
||||
|
||||
protected TypeAnnotationsReader(
|
||||
ClassReader.AttrIterator iter,
|
||||
String label,
|
||||
ExceptionsReader exceptionReader,
|
||||
CodeReader codeReader,
|
||||
SignatureReader signatureReader,
|
||||
TypeAnnotationLocation location
|
||||
) throws InvalidClassFileException {
|
||||
super(iter, label);
|
||||
this.exceptionReader = exceptionReader;
|
||||
this.codeReader = codeReader;
|
||||
this.signatureReader = signatureReader;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return a TypeAnnotationReader for reading type annotations in the attributes table of a ClassFile structure
|
||||
*/
|
||||
public static TypeAnnotationsReader getTypeAnnotationReaderAtClassfile(
|
||||
ClassReader.AttrIterator iter,
|
||||
String label,
|
||||
SignatureReader signatureReader
|
||||
) throws InvalidClassFileException {
|
||||
return new TypeAnnotationsReader(iter, label, null, null, signatureReader, TypeAnnotationLocation.ClassFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a TypeAnnotationReader for reading type annotations in the attributes table of a method_info structure
|
||||
*/
|
||||
public static TypeAnnotationsReader getTypeAnnotationReaderAtMethodInfo(
|
||||
ClassReader.AttrIterator iter,
|
||||
String label,
|
||||
ExceptionsReader exceptionReader,
|
||||
SignatureReader signatureReader
|
||||
) throws InvalidClassFileException {
|
||||
return new TypeAnnotationsReader(iter, label, exceptionReader, null, signatureReader, TypeAnnotationLocation.method_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a TypeAnnotationReader for reading type annotations in the attributes table of a field_info structure
|
||||
*/
|
||||
public static TypeAnnotationsReader getTypeAnnotationReaderAtFieldInfo(
|
||||
ClassReader.AttrIterator iter,
|
||||
String label
|
||||
) throws InvalidClassFileException {
|
||||
return new TypeAnnotationsReader(iter, label, null, null, null, TypeAnnotationLocation.field_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a TypeAnnotationReader for reading type annotations in the attributes table of a Code attribute
|
||||
*/
|
||||
public static TypeAnnotationsReader getTypeAnnotationReaderAtCode(
|
||||
ClassReader.AttrIterator iter,
|
||||
String label,
|
||||
CodeReader codeReader
|
||||
) throws InvalidClassFileException {
|
||||
return new TypeAnnotationsReader(iter, label, null, codeReader, null, TypeAnnotationLocation.Code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return an array TypeAnnotationAttribute[] corresponding to the annotations[num_annotations] table
|
||||
* specified as:
|
||||
* <pre>
|
||||
* {@code
|
||||
* RuntimeVisibleTypeAnnotations_attribute {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
* u2 num_annotations;
|
||||
* type_annotation annotations[num_annotations];
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20"> JLS (SE8), 4.7.20</a>
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
public TypeAnnotationAttribute[] getAllTypeAnnotations() throws InvalidClassFileException {
|
||||
TypeAnnotationAttribute[] result = new TypeAnnotationAttribute[getAnnotationCount()];
|
||||
int offset = beginOffset + 8; // skip attribute_name_index,
|
||||
// attribute_length, and num_annotations
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
Pair<TypeAnnotationAttribute, Integer> attributeAndSize = getTypeAttributeAndSize(offset);
|
||||
result[i] = attributeAndSize.fst;
|
||||
offset += attributeAndSize.snd;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param begin the offset from which to read a type annotation
|
||||
* @return a Pair (a,i) such that "i" is the number of bytes read in order to construct "a", which is
|
||||
* the {@link TypeAnnotationAttribute} that corresponds to the type_annotation structure at offset begin specified as:
|
||||
* <pre>
|
||||
* {@code
|
||||
* type_annotation {
|
||||
* u1 target_type;
|
||||
* union {
|
||||
* type_parameter_target;
|
||||
* supertype_target;
|
||||
* type_parameter_bound_target;
|
||||
* empty_target;
|
||||
* method_formal_parameter_target;
|
||||
* throws_target;
|
||||
* localvar_target;
|
||||
* catch_target;
|
||||
* offset_target;
|
||||
* type_argument_target;
|
||||
* } target_info;
|
||||
* type_path target_path;
|
||||
* u2 type_index;
|
||||
* u2 num_element_value_pairs;
|
||||
* { u2 element_name_index;
|
||||
* element_value value;
|
||||
* } element_value_pairs[num_element_value_pairs];
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
private Pair<TypeAnnotationAttribute, Integer> getTypeAttributeAndSize(int begin) throws InvalidClassFileException {
|
||||
TargetType target_type = TargetType.fromValue(cr.getUnsignedByte(begin));
|
||||
|
||||
if (target_type == null) {
|
||||
throw new InvalidClassFileException(begin, "Unknown target_type: " + cr.getUnsignedByte(begin));
|
||||
}
|
||||
|
||||
if (target_type.location != this.location) {
|
||||
throw new InvalidClassFileException(
|
||||
begin,
|
||||
target_type + " annotation found while reading " + this.location + " annotations."
|
||||
+ " Only valid at " + target_type.location
|
||||
);
|
||||
}
|
||||
|
||||
final Pair<TypeAnnotationTarget, Integer> pAnnotationTargetAndSize =
|
||||
getTypeAnnotationTargetAndSize(begin+1, target_type.target_info);
|
||||
|
||||
final int type_path_offset = begin + 1 + pAnnotationTargetAndSize.snd;
|
||||
checkSize(type_path_offset, 1);
|
||||
final int path_length = cr.getUnsignedByte(type_path_offset);
|
||||
checkSize(type_path_offset + 1, 2 * path_length);
|
||||
|
||||
ArrayList<Pair<TypePathKind, Integer>> type_path = new ArrayList<Pair<TypePathKind, Integer>>(path_length);
|
||||
int current_path_element = type_path_offset + 1;
|
||||
for (int i = 0; i < path_length; i++) {
|
||||
TypePathKind type_path_kind = TypePathKind.fromValue(cr.getUnsignedByte(current_path_element));
|
||||
int type_argument_index = cr.getUnsignedByte(current_path_element + 1);
|
||||
type_path.add(i, Pair.make(type_path_kind, type_argument_index));
|
||||
current_path_element += 2;
|
||||
}
|
||||
|
||||
final int annotation_begin = type_path_offset + 1 + 2*path_length;
|
||||
|
||||
Pair<AnnotationAttribute, Integer> pAttributeAndSize = getAttributeAndSize(annotation_begin);
|
||||
|
||||
|
||||
return Pair.make(
|
||||
new TypeAnnotationAttribute(
|
||||
pAnnotationTargetAndSize.fst,
|
||||
pAttributeAndSize.fst,
|
||||
type_path,
|
||||
target_type
|
||||
),
|
||||
1 + pAnnotationTargetAndSize.snd + 1 + 2*path_length + pAttributeAndSize.snd
|
||||
);
|
||||
}
|
||||
|
||||
private Pair<TypeAnnotationTarget, Integer> getTypeAnnotationTargetAndSize(int begin, TargetInfo target_info) throws InvalidClassFileException {
|
||||
switch (target_info) {
|
||||
case type_parameter_target: {
|
||||
checkSize(begin, 1);
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new TypeParameterTarget(cr.getUnsignedByte(begin)), 1);
|
||||
}
|
||||
case supertype_target: {
|
||||
checkSize(begin, 2);
|
||||
final int interfaceIndex = cr.getUShort(begin);
|
||||
final String superType;
|
||||
if (interfaceIndex == 65535) {
|
||||
superType = cr.getSuperName();
|
||||
} else {
|
||||
superType = cr.getInterfaceName(interfaceIndex);
|
||||
}
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new SuperTypeTarget(superType), 2);
|
||||
}
|
||||
case type_parameter_bound_target: {
|
||||
checkSize(begin, 2);
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new TypeParameterBoundTarget(
|
||||
cr.getUnsignedByte(begin),
|
||||
cr.getUnsignedByte(begin+1),
|
||||
signatureReader.getSignature()
|
||||
), 2);
|
||||
}
|
||||
case empty_target: {
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new EmptyTarget(), 0);
|
||||
}
|
||||
case formal_parameter_target: {
|
||||
checkSize(begin, 1);
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new FormalParameterTarget(cr.getUnsignedByte(begin)), 1);
|
||||
}
|
||||
case throws_target: {
|
||||
assert exceptionReader != null;
|
||||
checkSize(begin, 2);
|
||||
final int throwsIndex = cr.getUShort(begin);
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new ThrowsTarget(exceptionReader.getClasses()[throwsIndex]), 2);
|
||||
}
|
||||
/*
|
||||
* localvar_target {
|
||||
* u2 table_length;
|
||||
* { u2 start_pc;
|
||||
u2 length;
|
||||
u2 index;
|
||||
* } table[table_length];
|
||||
* }
|
||||
*/
|
||||
case localvar_target: {
|
||||
checkSize(begin, 2);
|
||||
final int table_length = cr.getUShort(begin);
|
||||
final int offset = begin+2;
|
||||
checkSize(offset, (2+2+2)*table_length);
|
||||
int[] start_pc = new int[table_length];
|
||||
int[] length = new int[table_length];
|
||||
int[] index = new int[table_length];
|
||||
|
||||
for (int i = 0; i < table_length; i++) {
|
||||
start_pc[i] = cr.getUShort(offset + (2+2+2)*i);
|
||||
length[i] = cr.getUShort(offset + 2 + (2+2+2)*i);
|
||||
index[i] = cr.getUShort(offset + 4 + (2+2+2)*i);
|
||||
}
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new LocalVarTarget(start_pc, length, index), 2 + (2+2+2)*table_length);
|
||||
}
|
||||
case catch_target: {
|
||||
assert codeReader != null;
|
||||
checkSize(begin, 2);
|
||||
int exception_table_index = cr.getUShort(begin);
|
||||
int[] rawHandler = new int[4];
|
||||
System.arraycopy(codeReader.getRawHandlers(), exception_table_index*4, rawHandler, 0, 4);
|
||||
final String catchType =
|
||||
rawHandler[3] == 0 ? CatchTarget.ALL_EXCEPTIONS
|
||||
: cr.getCP().getCPClass(rawHandler[3]);
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new CatchTarget(rawHandler, catchType), 2);
|
||||
}
|
||||
case offset_target: {
|
||||
checkSize(begin, 2);
|
||||
int offset = cr.getUShort(begin);
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new OffsetTarget(offset), 2);
|
||||
}
|
||||
case type_argument_target: {
|
||||
checkSize(begin, 3);
|
||||
int offset = cr.getUShort(begin);
|
||||
int type_argument_index = cr.getUnsignedByte(begin);
|
||||
return Pair.<TypeAnnotationTarget, Integer>make(new TypeArgumentTarget(offset, type_argument_index), 3);
|
||||
}
|
||||
default:
|
||||
Assertions.UNREACHABLE();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of those Bytecode locations where type annotation may appear (in the corresponding attribute table).
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20"> JLS (SE8), 4.7.20</a>
|
||||
*/
|
||||
public static enum TypeAnnotationLocation {
|
||||
ClassFile, method_info, field_info, Code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible target_type items.
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20"> JLS (SE8), 4.7.20</a>
|
||||
*/
|
||||
public static enum TargetInfo {
|
||||
type_parameter_target, supertype_target, type_parameter_bound_target, empty_target, formal_parameter_target, throws_target,
|
||||
localvar_target, catch_target, offset_target, type_argument_target
|
||||
}
|
||||
|
||||
/**
|
||||
* Known target_types for JSR 308 Type-Annotation.
|
||||
*
|
||||
* Constant names taken from <a href="http://types.cs.washington.edu/jsr308/">http://types.cs.washington.edu/jsr308/</a>
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20"> JLS (SE8), 4.7.20</a>
|
||||
*/
|
||||
// TODO: This somewhat mirrors com.sun.tools.javac.code.TargetType, maybe just use that instead?
|
||||
public static enum TargetType {
|
||||
CLASS_TYPE_PARAMETER( 0x00, TargetInfo.type_parameter_target, TypeAnnotationLocation.ClassFile),
|
||||
METHOD_TYPE_PARAMETER( 0x01, TargetInfo.type_parameter_target, TypeAnnotationLocation.method_info),
|
||||
|
||||
CLASS_EXTENDS( 0x10, TargetInfo.supertype_target, TypeAnnotationLocation.ClassFile),
|
||||
CLASS_TYPE_PARAMETER_BOUND( 0x11, TargetInfo.type_parameter_bound_target, TypeAnnotationLocation.ClassFile),
|
||||
METHOD_TYPE_PARAMETER_BOUND( 0x12, TargetInfo.type_parameter_bound_target, TypeAnnotationLocation.method_info),
|
||||
FIELD( 0x13, TargetInfo.empty_target, TypeAnnotationLocation.field_info),
|
||||
METHOD_RETURN( 0x14, TargetInfo.empty_target, TypeAnnotationLocation.method_info),
|
||||
METHOD_RECEIVER( 0x15, TargetInfo.empty_target, TypeAnnotationLocation.method_info),
|
||||
METHOD_FORMAL_PARAMETER( 0x16, TargetInfo.formal_parameter_target, TypeAnnotationLocation.method_info),
|
||||
THROWS( 0x17, TargetInfo.throws_target, TypeAnnotationLocation.method_info),
|
||||
|
||||
LOCAL_VARIABLE( 0x40, TargetInfo.localvar_target, TypeAnnotationLocation.Code),
|
||||
RESOURCE_VARIABLE( 0x41, TargetInfo.localvar_target, TypeAnnotationLocation.Code),
|
||||
EXCEPTION_PARAMETER( 0x42, TargetInfo.catch_target, TypeAnnotationLocation.Code),
|
||||
INSTANCEOF( 0x43, TargetInfo.offset_target, TypeAnnotationLocation.Code),
|
||||
NEW( 0x44, TargetInfo.offset_target, TypeAnnotationLocation.Code),
|
||||
CONSTRUCTOR_REFERENCE( 0x45, TargetInfo.offset_target, TypeAnnotationLocation.Code),
|
||||
METHOD_REFERENCE( 0x46, TargetInfo.offset_target, TypeAnnotationLocation.Code),
|
||||
CAST( 0x47, TargetInfo.type_argument_target, TypeAnnotationLocation.Code),
|
||||
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, TargetInfo.type_argument_target, TypeAnnotationLocation.Code),
|
||||
METHOD_INVOCATION_TYPE_ARGUMENT( 0x49, TargetInfo.type_argument_target, TypeAnnotationLocation.Code),
|
||||
CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT( 0x4A, TargetInfo.type_argument_target, TypeAnnotationLocation.Code),
|
||||
METHOD_REFERENCE_TYPE_ARGUMENT( 0x4B, TargetInfo.type_argument_target, TypeAnnotationLocation.Code);
|
||||
|
||||
private static final Map<Integer, TargetType> fromValue;
|
||||
|
||||
static {
|
||||
final TargetType[] targetTypes = TargetType.values();
|
||||
fromValue = HashMapFactory.make(targetTypes.length);
|
||||
for (int i = 0; i < targetTypes.length; i++) {
|
||||
fromValue.put(targetTypes[i].target_type, targetTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static TargetType fromValue(int value) {
|
||||
return fromValue.get(value);
|
||||
}
|
||||
|
||||
public final int target_type;
|
||||
public final TargetInfo target_info;
|
||||
public final TypeAnnotationLocation location;
|
||||
TargetType(int target_type, TargetInfo target_info, TypeAnnotationLocation location) {
|
||||
if (!(0 <= target_type && target_type <= Byte.MAX_VALUE)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Code may break for target_type that does not fit in a Java (signed!) byte"
|
||||
);
|
||||
}
|
||||
|
||||
this.target_type = target_type;
|
||||
this.target_info = target_info;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link TypeAnnotationTarget} represents one of the possible target_info structure
|
||||
* <pre>
|
||||
* {@code
|
||||
* union {
|
||||
* type_parameter_target;
|
||||
* supertype_target;
|
||||
* type_parameter_bound_target;
|
||||
* empty_target;
|
||||
* method_formal_parameter_target;
|
||||
* throws_target;
|
||||
* localvar_target;
|
||||
* catch_target;
|
||||
* offset_target;
|
||||
* type_argument_target;
|
||||
* } target_info;
|
||||
* }
|
||||
* </pre>
|
||||
* @author Martin Hecker martin.hecker@kit.edu
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
public static abstract class TypeAnnotationTarget {
|
||||
private final TargetInfo targetInfo;
|
||||
protected TypeAnnotationTarget(TargetInfo targetInfo) {
|
||||
this.targetInfo = targetInfo;
|
||||
}
|
||||
public TargetInfo getTargetInfo() {
|
||||
return targetInfo;
|
||||
}
|
||||
|
||||
public abstract <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor);
|
||||
}
|
||||
|
||||
public static interface TypeAnnotationTargetVisitor<R> {
|
||||
R visitTypeParameterTarget(TypeParameterTarget target);
|
||||
R visitSuperTypeTarget(SuperTypeTarget target );
|
||||
R visitTypeParameterBoundTarget(TypeParameterBoundTarget target);
|
||||
R visitEmptyTarget(EmptyTarget target);
|
||||
R visitFormalParameterTarget(FormalParameterTarget target);
|
||||
R visitThrowsTarget(ThrowsTarget target);
|
||||
R visitLocalVarTarget(LocalVarTarget target);
|
||||
R visitCatchTarget(CatchTarget target);
|
||||
R visitOffsetTarget(OffsetTarget target);
|
||||
R visitTypeArgumentTarget(TypeArgumentTarget target);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-A.1"> JLS (SE8), 4.7.20.1 A</a>
|
||||
*/
|
||||
public static class TypeParameterTarget extends TypeAnnotationTarget {
|
||||
private final int type_parameter_index;
|
||||
public TypeParameterTarget(int type_parameter_index) {
|
||||
super(TargetInfo.type_parameter_target);
|
||||
this.type_parameter_index = type_parameter_index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return type_parameter_index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitTypeParameterTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-B.1"> JLS (SE8), 4.7.20.1 B</a>
|
||||
*/
|
||||
public static class SuperTypeTarget extends TypeAnnotationTarget {
|
||||
private final String superType;
|
||||
public SuperTypeTarget(String superType) {
|
||||
super(TargetInfo.supertype_target);
|
||||
this.superType = superType;
|
||||
}
|
||||
|
||||
public String getSuperType() {
|
||||
return superType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitSuperTypeTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-C.1"> JLS (SE8), 4.7.20.1 C</a>
|
||||
*/
|
||||
public static class TypeParameterBoundTarget extends TypeAnnotationTarget {
|
||||
private final int type_parameter_index;
|
||||
private final int bound_index;
|
||||
private final String boundSignature;
|
||||
|
||||
public TypeParameterBoundTarget(int type_parameter_index, int bound_index, String boundSignature) {
|
||||
super(TargetInfo.type_parameter_bound_target);
|
||||
this.type_parameter_index = type_parameter_index;
|
||||
this.bound_index = bound_index;
|
||||
this.boundSignature = boundSignature;
|
||||
}
|
||||
|
||||
public int getParameterIndex() {
|
||||
return type_parameter_index;
|
||||
}
|
||||
|
||||
public int getBoundIndex() {
|
||||
return bound_index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitTypeParameterBoundTarget(this);
|
||||
}
|
||||
|
||||
public String getBoundSignature() {
|
||||
return boundSignature;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-D.1"> JLS (SE8), 4.7.20.1 D</a>
|
||||
*/
|
||||
public static class EmptyTarget extends TypeAnnotationTarget {
|
||||
public EmptyTarget() {
|
||||
super(TargetInfo.empty_target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitEmptyTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-E.1"> JLS (SE8), 4.7.20.1 E</a>
|
||||
*/
|
||||
public static class FormalParameterTarget extends TypeAnnotationTarget {
|
||||
private final int formal_parameter_index;
|
||||
public FormalParameterTarget(int index) {
|
||||
super(TargetInfo.formal_parameter_target);
|
||||
this.formal_parameter_index = index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return formal_parameter_index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitFormalParameterTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-F.1"> JLS (SE8), 4.7.20.1 F</a>
|
||||
*/
|
||||
public static class ThrowsTarget extends TypeAnnotationTarget {
|
||||
private final String throwType;
|
||||
public ThrowsTarget(String throwType) {
|
||||
super(TargetInfo.supertype_target);
|
||||
this.throwType = throwType;
|
||||
}
|
||||
|
||||
public String getThrowType() {
|
||||
return throwType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitThrowsTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-G.1"> JLS (SE8), 4.7.20.1 G</a>
|
||||
*/
|
||||
public static class LocalVarTarget extends TypeAnnotationTarget {
|
||||
private final int[] start_pc;
|
||||
private final int[] length;
|
||||
private final int[] index;
|
||||
public LocalVarTarget(int[] start_pc, int[] length, int[] index) {
|
||||
super(TargetInfo.localvar_target);
|
||||
if (!(start_pc.length == length.length && length.length == index.length)) throw new IllegalArgumentException();
|
||||
// TODO: do we really need to copy here? Can't we trust callees not to change arrays after the fact?
|
||||
this.start_pc = Arrays.copyOf(start_pc, start_pc.length);
|
||||
this.length = Arrays.copyOf(length, length.length);
|
||||
this.index = Arrays.copyOf(index, index.length);
|
||||
}
|
||||
|
||||
public int getNrOfRanges() {
|
||||
return start_pc.length;
|
||||
}
|
||||
|
||||
public int getStartPc(int range) {
|
||||
return start_pc[range];
|
||||
}
|
||||
|
||||
public int getLength(int range) {
|
||||
return length[range];
|
||||
}
|
||||
|
||||
public int getIndex(int range) {
|
||||
return index[range];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitLocalVarTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-H.1"> JLS (SE8), 4.7.20.1 H</a>
|
||||
*/
|
||||
public static class CatchTarget extends TypeAnnotationTarget {
|
||||
private final int[] rawHandler;
|
||||
private final String catchType;
|
||||
|
||||
public static final String ALL_EXCEPTIONS = null;
|
||||
|
||||
public CatchTarget(int[] rawHandler, String catchType) {
|
||||
super(TargetInfo.catch_target);
|
||||
this.rawHandler = rawHandler;
|
||||
this.catchType = catchType;
|
||||
}
|
||||
/**
|
||||
* @return The type-annotations targets raw handler, i.e.: a 4 tuple (startPC, endPC, catchPC, catchClassIndex)
|
||||
* @see CodeReader
|
||||
*/
|
||||
public int[] getRawHandler() {
|
||||
// TODO: do we really need to copy here? Can't we trust callees not to change arrays after the fact?
|
||||
return Arrays.copyOf(rawHandler, rawHandler.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitCatchTarget(this);
|
||||
}
|
||||
|
||||
public String getCatchType() {
|
||||
return catchType;
|
||||
}
|
||||
|
||||
public int getStartPC() {
|
||||
return rawHandler[0];
|
||||
}
|
||||
|
||||
public int getEndPC() {
|
||||
return rawHandler[1];
|
||||
}
|
||||
|
||||
public int getCatchPC() {
|
||||
return rawHandler[2];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-I.1"> JLS (SE8), 4.7.20.1 I</a>
|
||||
*/
|
||||
public static class OffsetTarget extends TypeAnnotationTarget {
|
||||
private final int offset;
|
||||
|
||||
public OffsetTarget(int offset) {
|
||||
super(TargetInfo.offset_target);
|
||||
this.offset = offset;
|
||||
}
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitOffsetTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1-100-J.1"> JLS (SE8), 4.7.20.1 J</a>
|
||||
*/
|
||||
public static class TypeArgumentTarget extends TypeAnnotationTarget {
|
||||
private final int offset;
|
||||
private final int type_argument_index;
|
||||
|
||||
public TypeArgumentTarget(int offset, int type_argument_index) {
|
||||
super(TargetInfo.type_argument_target);
|
||||
this.offset = offset;
|
||||
this.type_argument_index = type_argument_index;
|
||||
}
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
public int getTypeArgumentIndex() {
|
||||
return type_argument_index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R acceptVisitor(TypeAnnotationTargetVisitor<R> visitor) {
|
||||
return visitor.visitTypeArgumentTarget(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static enum AnnotationType {
|
||||
RuntimeInvisibleTypeAnnotations, RuntimeVisibleTypeAnnotations
|
||||
}
|
||||
|
||||
public static enum TypePathKind {
|
||||
DEEPER_IN_ARRAY(0),
|
||||
DEEPER_IN_NESTED(1),
|
||||
WILDCARD_BOUND(2),
|
||||
TYPE_ARGUMENT(3);
|
||||
|
||||
private final int type_path_kind;
|
||||
private TypePathKind(int type_path_kind) {
|
||||
this.type_path_kind = type_path_kind;
|
||||
}
|
||||
|
||||
private static final Map<Integer, TypePathKind> fromValue;
|
||||
|
||||
static {
|
||||
final TypePathKind[] typePathKinds = TypePathKind.values();
|
||||
fromValue = HashMapFactory.make(typePathKinds.length);
|
||||
for (int i = 0; i < typePathKinds.length; i++) {
|
||||
fromValue.put(typePathKinds[i].type_path_kind, typePathKinds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static TypePathKind fromValue(int value) {
|
||||
return fromValue.get(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static final List<Pair<TypePathKind, Integer>> TYPEPATH_EMPTY = Collections.emptyList();
|
||||
|
||||
public static class TypeAnnotationAttribute {
|
||||
public final TypeAnnotationTarget annotationTarget;
|
||||
public final AnnotationAttribute annotationAttribute;
|
||||
public final List<Pair<TypePathKind, Integer>> typePath;
|
||||
public final TargetType targetType;
|
||||
|
||||
public TypeAnnotationAttribute(
|
||||
TypeAnnotationTarget annotationTarget,
|
||||
AnnotationAttribute annotationAttribute,
|
||||
List<Pair<TypePathKind, Integer>> typePath,
|
||||
TargetType targetType
|
||||
) {
|
||||
this.annotationTarget = annotationTarget;
|
||||
this.annotationAttribute = annotationAttribute;
|
||||
this.typePath = Collections.unmodifiableList(typePath);
|
||||
this.targetType = targetType;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isKnownAnnotation(String name) {
|
||||
for (AnnotationType t : AnnotationType.values()) {
|
||||
if (t.name().equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static interface Action {
|
||||
TypeAnnotationsReader apply() throws InvalidClassFileException;
|
||||
}
|
||||
public static TypeAnnotationsReader getReaderForAnnotationAtClassfile(final AnnotationType type, final ClassReader.AttrIterator iter, final SignatureReader signatureReader) {
|
||||
return advanceIter(type, iter, new Action() {
|
||||
@Override
|
||||
public TypeAnnotationsReader apply() throws InvalidClassFileException {
|
||||
return getTypeAnnotationReaderAtClassfile(iter, type.toString(), signatureReader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static TypeAnnotationsReader getReaderForAnnotationAtMethodInfo(final AnnotationType type, final ClassReader.AttrIterator iter, final ExceptionsReader exceptionReader, final SignatureReader signatureReader) {
|
||||
return advanceIter(type, iter, new Action() {
|
||||
@Override
|
||||
public TypeAnnotationsReader apply() throws InvalidClassFileException {
|
||||
return getTypeAnnotationReaderAtMethodInfo(iter, type.toString(), exceptionReader, signatureReader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static TypeAnnotationsReader getReaderForAnnotationAtFieldInfo(final AnnotationType type, final ClassReader.AttrIterator iter) {
|
||||
return advanceIter(type, iter, new Action() {
|
||||
@Override
|
||||
public TypeAnnotationsReader apply() throws InvalidClassFileException {
|
||||
return getTypeAnnotationReaderAtFieldInfo(iter, type.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static TypeAnnotationsReader getReaderForAnnotationAtCode(final AnnotationType type, final ClassReader.AttrIterator iter, final CodeReader codereader) {
|
||||
return advanceIter(type, iter, new Action() {
|
||||
@Override
|
||||
public TypeAnnotationsReader apply() throws InvalidClassFileException {
|
||||
return getTypeAnnotationReaderAtCode(iter, type.toString(), codereader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static TypeAnnotationsReader advanceIter(AnnotationType type, ClassReader.AttrIterator iter, Action newReader){
|
||||
// search for the desired attribute
|
||||
final String attrName = type.toString();
|
||||
try {
|
||||
for (; iter.isValid(); iter.advance()) {
|
||||
if (iter.getName().equals(attrName)) return newReader.apply();
|
||||
}
|
||||
} catch (InvalidClassFileException e) {
|
||||
Assertions.UNREACHABLE();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue