Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.checkerframework.common.reflection;
import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.reflection.qual.ClassBound;
import org.checkerframework.common.reflection.qual.ClassVal;
import org.checkerframework.common.reflection.qual.GetConstructor;
import org.checkerframework.common.reflection.qual.GetMethod;
import org.checkerframework.common.reflection.qual.MethodVal;
import org.checkerframework.common.reflection.qual.MethodValBottom;
import org.checkerframework.common.reflection.qual.UnknownMethod;
import org.checkerframework.common.value.ValueAnnotatedTypeFactory;
import org.checkerframework.common.value.ValueChecker;
import org.checkerframework.common.value.qual.ArrayLen;
import org.checkerframework.common.value.qual.BottomVal;
import org.checkerframework.common.value.qual.StringVal;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.QualifierHierarchy;
import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator;
import org.checkerframework.framework.type.treeannotator.TreeAnnotator;
import org.checkerframework.framework.util.AnnotationBuilder;
import org.checkerframework.framework.util.MultiGraphQualifierHierarchy;
import org.checkerframework.framework.util.MultiGraphQualifierHierarchy.MultiGraphFactory;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.InternalUtils;
import org.checkerframework.javacutil.TreeUtils;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
public class MethodValAnnotatedTypeFactory extends BaseAnnotatedTypeFactory {
private final AnnotationMirror METHODVAL_BOTTOM = AnnotationUtils
.fromClass(elements, MethodValBottom.class);
private final AnnotationMirror UNKNOWN_METHOD = AnnotationUtils.fromClass(
elements, UnknownMethod.class);
private static final int UNKNOWN_PARAM_LENGTH = -1;
public MethodValAnnotatedTypeFactory(BaseTypeChecker checker) {
super(checker);
if (this.getClass().equals(MethodValAnnotatedTypeFactory.class)) {
this.postInit();
}
}
@Override
protected Set> createSupportedTypeQualifiers() {
return Collections.unmodifiableSet(
new HashSet>(
Arrays.asList(MethodVal.class, MethodValBottom.class, UnknownMethod.class)));
}
@Override
protected void initilizeReflectionResolution() {
boolean debug = "debug".equals(checker.getOption("resolveReflection"));
reflectionResolver = new DefaultReflectionResolver(checker, this,
debug);
}
static List getListOfMethodSignatures(AnnotationMirror anno) {
List list = new ArrayList<>();
List methodNames = AnnotationUtils.getElementValueArray(anno,
"methodName", String.class, true);
List classNames = AnnotationUtils.getElementValueArray(anno,
"className", String.class, true);
List params = AnnotationUtils.getElementValueArray(anno,
"params", Integer.class, true);
for (int i = 0; i < methodNames.size(); i++) {
list.add(new MethodSignature(classNames.get(i),
methodNames.get(i),
params.get(i)));
}
return list;
}
private AnnotationMirror createMethodVal(Set sigs) {
List classNames = new ArrayList<>();
List methodNames = new ArrayList<>();
List params = new ArrayList<>();
for (MethodSignature sig:sigs) {
classNames.add(sig.className);
methodNames.add(sig.methodName);
params.add(sig.params);
}
AnnotationBuilder builder = new AnnotationBuilder(processingEnv,
MethodVal.class.getCanonicalName());
builder.setValue("className", classNames);
builder.setValue("methodName", methodNames);
builder.setValue("params", params);
return builder.build();
}
/**
* Returns a list of class names for the given tree using the Class Val Checker
* @param tree ExpressionTree whose class names are requested
* @param mustBeExact whether @ClassBound may be used
* @return list of class names or the empty list if no class names were found
*/
private List getClassNamesFromClassValChecker(ExpressionTree tree, boolean mustBeExact) {
ClassValAnnotatedTypeFactory classValATF = getTypeFactoryOfSubchecker(ClassValChecker.class);
AnnotatedTypeMirror classAnno = classValATF.getAnnotatedType(tree);
List classNames = new ArrayList<>();
AnnotationMirror annotation = classAnno.getAnnotation(ClassVal.class);
if (annotation != null) {
classNames = AnnotationUtils.getElementValueArray(annotation,
"value", String.class, true);
} else if (!mustBeExact) {
// Could be ClassBound instead of ClassVal
annotation = classAnno.getAnnotation(ClassBound.class);
if (annotation != null) {
classNames = AnnotationUtils.getElementValueArray(annotation,
"value", String.class, true);
}
}
return classNames;
}
/**
* Returns the string values for the argument passed. The String Values
* are estimated using the Value Checker.
* @param arg ExpressionTree whose string values are sought
* @return string values of arg or the empty list if no values were found
*/
private List getMethodNamesFromStringArg(ExpressionTree arg) {
List methodNames = new ArrayList<>();
ValueAnnotatedTypeFactory valueATF = getTypeFactoryOfSubchecker(ValueChecker.class);
AnnotatedTypeMirror valueAnno = valueATF.getAnnotatedType(arg);
AnnotationMirror annotation = valueAnno.getAnnotation(StringVal.class);
if (annotation != null) {
methodNames = AnnotationUtils.getElementValueArray(annotation,
"value", String.class, true);
}
return methodNames;
}
@Override
public QualifierHierarchy createQualifierHierarchy(MultiGraphFactory factory) {
return new MethodValQualifierHierarchy(factory, METHODVAL_BOTTOM);
}
protected class MethodValQualifierHierarchy extends
MultiGraphQualifierHierarchy {
protected MethodValQualifierHierarchy(
MultiGraphQualifierHierarchy.MultiGraphFactory factory,
AnnotationMirror bottom) {
super(factory, bottom);
}
/*
* Determines the least upper bound of a1 and a2. If both are MethodVal
* annotations, then the least upper bound is the result of
* concatenating all value lists of a1 and a2.
*/
@Override
public AnnotationMirror leastUpperBound(AnnotationMirror a1,
AnnotationMirror a2) {
if (!AnnotationUtils.areSameIgnoringValues(getTopAnnotation(a1),
getTopAnnotation(a2))) {
return null;
} else if (isSubtype(a1, a2)) {
return a2;
} else if (isSubtype(a2, a1)) {
return a1;
} else if (AnnotationUtils.areSameIgnoringValues(a1, a2)) {
List a1Sigs = getListOfMethodSignatures(a1);
List a2Sigs = getListOfMethodSignatures(a2);
Set lubSigs = new HashSet(a1Sigs);
lubSigs.addAll(a2Sigs);
AnnotationMirror result = createMethodVal(lubSigs);
return result;
}
return null;
}
@Override
public boolean isSubtype(AnnotationMirror sub, AnnotationMirror sup) {
if (AnnotationUtils.areSame(sub, sup)
|| AnnotationUtils.areSameByClass(sup, UnknownMethod.class)
|| AnnotationUtils.areSameByClass(sub,
MethodValBottom.class)) {
return true;
}
if (AnnotationUtils.areSameByClass(sub, UnknownMethod.class)
|| AnnotationUtils.areSameByClass(sup, MethodValBottom.class)) {
return false;
}
assert AnnotationUtils.areSameByClass(sub, MethodVal.class)
&& AnnotationUtils.areSameByClass(sup, MethodVal.class) : "Unexpected annotation in MethodVal";
List subSignatures = getListOfMethodSignatures(sub);
List superSignatures = getListOfMethodSignatures(sup);
for (MethodSignature sig : subSignatures) {
if (!superSignatures.contains(sig)) {
return false;
}
}
return true;
}
}
@Override
protected TreeAnnotator createTreeAnnotator() {
return new ListTreeAnnotator(new MethodValTreeAnnotator(this),
super.createTreeAnnotator());
}
/**
* TreeAnnotator with the visitMethodInvocation method overridden
*/
protected class MethodValTreeAnnotator extends TreeAnnotator {
protected MethodValTreeAnnotator(MethodValAnnotatedTypeFactory factory) {
super(factory);
}
/*
* Special handling of getMethod and getDeclaredMethod calls. Attempts
* to get the annotation on the Class object receiver to get the
* className, the annotation on the String argument to get the
* methodName, and the parameters argument to get the param, and then
* builds a new MethodVal annotation from these
*/
@Override
public Void visitMethodInvocation(MethodInvocationTree tree,
AnnotatedTypeMirror type) {
List methodNames;
List params;
List classNames;
if (isGetConstructorMethodInovaction(tree)) {
// method name for constructors is always
methodNames = Arrays.asList(ReflectionResolver.INIT);
params = getConstructorParamsLen(tree.getArguments());
classNames = getClassNamesFromClassValChecker(TreeUtils.getReceiverTree(tree),
true);
} else if (isGetMethodMethodInovaction(tree)) {
ExpressionTree methodNameArg = tree.getArguments().get(0);
methodNames = getMethodNamesFromStringArg(methodNameArg);
params = getMethodParamsLen(tree.getArguments());
classNames = getClassNamesFromClassValChecker(TreeUtils.getReceiverTree(tree),
false);
} else {
// Not a covered method invocation
return null;
}
// Create MethodVal
if (methodNames.isEmpty() || classNames.isEmpty()) {
// No method name or classname is found, it could be any
// class or method, so, return @UnknownMethod.
type.replaceAnnotation(UNKNOWN_METHOD);
return null;
}
Set methodSigs = new HashSet<>();
// The possible method signatures are the Cartesian product of all
// found class, method, and parameter lengths
for (String methodName : methodNames) {
for (String className : classNames) {
for (Integer param : params) {
methodSigs.add(new MethodSignature(className,
methodName, param));
}
}
}
AnnotationMirror newQual = createMethodVal(methodSigs);
type.replaceAnnotation(newQual);
return null;
}
private boolean isGetConstructorMethodInovaction(MethodInvocationTree tree) {
if (getDeclAnnotation(InternalUtils.symbol(tree),
GetConstructor.class) != null) {
return true;
}
return false;
}
private boolean isGetMethodMethodInovaction(MethodInvocationTree tree) {
if (getDeclAnnotation(InternalUtils.symbol(tree),
GetMethod.class) != null) {
return true;
}
return false;
}
private List getMethodParamsLen(
List args) {
assert args.size() > 0 : "getMethod must have at least one parameter";
// Number of parameters in the created method object
int numParams = args.size() - 1;
if (numParams == 1) {
return getNumberOfParameterOneArg(args.get(1));
}
return Collections.singletonList(numParams);
}
private List getConstructorParamsLen(
List args) {
// Number of parameters in the created method object
int numParams = args.size();
if (numParams == 1) {
return getNumberOfParameterOneArg(args.get(0));
}
return Collections.singletonList(numParams);
}
/**
* if getMethod(Object receiver, Object... params) or
* getConstrutor(Object... params) have one argument for params, then
* the number of parameters in the underlying method or constructor must
* be:
*
* 0: if the argument is null
* x: if the argument is an array with @ArrayLen(x)
* UNKNOWN_PARAM_LENGTH: if the argument is an array with @UnknownVal
* 1: otherwise
*/
private List getNumberOfParameterOneArg(ExpressionTree argument) {
AnnotatedTypeMirror atm = atypeFactory.getAnnotatedType(argument);
switch (atm.getKind()) {
case ARRAY:
ValueAnnotatedTypeFactory valueATF = getTypeFactoryOfSubchecker(ValueChecker.class);
AnnotatedTypeMirror valueAnno = valueATF.getAnnotatedType(argument);
if (valueAnno.getAnnotation(ArrayLen.class) != null) {
AnnotationMirror annotation = valueAnno
.getAnnotation(ArrayLen.class);
return AnnotationUtils.getElementValueArray(annotation, "value",
Integer.class, true);
} else if (valueAnno.getAnnotation(BottomVal.class) != null) {
// happens in this case: (Class[]) null
return Collections.singletonList(0);
}
// the argument is an array with unknown array length
return Collections.singletonList(UNKNOWN_PARAM_LENGTH);
case NULL:
// null is treated as the empty list of parameters, so size
// is 0
return Collections.singletonList(0);
default:
// The argument is not an array or null,
// so it must be a class.
return Collections.singletonList(1);
}
}
}
}
/**
* An object that represents a the tuple that identifies a method signature:
* (fully qualified class name, method name, number of parameters)
* @author smillst
*
*/
class MethodSignature {
String className;
String methodName;
int params;
public MethodSignature(String className, String methodName, int params) {
this.className = className;
this.methodName = methodName;
this.params = params;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((className == null) ? 0 : className.hashCode());
result = prime * result
+ ((methodName == null) ? 0 : methodName.hashCode());
result = prime * result + params;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
MethodSignature other = (MethodSignature) obj;
if (className == null) {
if (other.className != null) {
return false;
}
} else if (!className.equals(other.className)) {
return false;
}
if (methodName == null) {
if (other.methodName != null) {
return false;
}
} else if (!methodName.equals(other.methodName)) {
return false;
}
if (params != other.params) {
return false;
}
return true;
}
@Override
public String toString() {
return "MethodSignature [className=" + className + ", methodName="
+ methodName + ", params=" + params + "]";
}
}