/** * Determines the least upper bound of a1 and a2. If a1 and a2 are both the same type of Value * annotation, then the LUB is the result of taking all values from both a1 and a2 and removing * duplicates. If a1 and a2 are not the same type of Value annotation they may still be * mergeable because some values can be implicitly cast as others. If a1 and a2 are both in * {DoubleVal, IntVal} then they will be converted upwards: IntVal → DoubleVal to arrive at * a common annotation type. * * @return the least upper bound 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; } // If both are the same type, determine the type and merge: else if (AnnotationUtils.areSameIgnoringValues(a1, a2)) { List<Object> a1Values = AnnotationUtils.getElementValueArray(a1, "value", Object.class, true); List<Object> a2Values = AnnotationUtils.getElementValueArray(a2, "value", Object.class, true); HashSet<Object> newValues = new HashSet<Object>(a1Values.size() + a2Values.size()); newValues.addAll(a1Values); newValues.addAll(a2Values); return createAnnotation(a1.getAnnotationType().toString(), newValues); } // Annotations are in this hierarchy, but they are not the same else { // If either is UNKNOWNVAL, ARRAYLEN, STRINGVAL, or BOOLEAN then // the LUB is // UnknownVal if (!(AnnotationUtils.areSameByClass(a1, IntVal.class) || AnnotationUtils.areSameByClass(a1, DoubleVal.class) || AnnotationUtils.areSameByClass(a2, IntVal.class) || AnnotationUtils.areSameByClass(a2, DoubleVal.class))) { return UNKNOWNVAL; } else { // At this point one of them must be a DoubleVal and one an // IntVal AnnotationMirror doubleAnno; AnnotationMirror intAnno; if (AnnotationUtils.areSameByClass(a2, DoubleVal.class)) { doubleAnno = a2; intAnno = a1; } else { doubleAnno = a1; intAnno = a2; } List<Long> intVals = getIntValues(intAnno); List<Double> doubleVals = getDoubleValues(doubleAnno); for (Long n : intVals) { doubleVals.add(n.doubleValue()); } return createDoubleValAnnotation(doubleVals); } } }
private boolean containsSameIgnoringValues( Set<Class<? extends Annotation>> quals, AnnotationMirror anno) { for (Class<? extends Annotation> q : quals) { if (AnnotationUtils.areSameByClass(anno, q)) { return true; } } return false; }
/** @inheritDoc */ @Override public Slot getSlot(final AnnotationMirror annotationMirror) { final int id; if (InferenceQualifierHierarchy.isVarAnnot(annotationMirror)) { if (annotationMirror.getElementValues().isEmpty()) { return null; // TODO: should we instead throw an exception? } else { final AnnotationValue annoValue = annotationMirror.getElementValues().values().iterator().next(); id = Integer.valueOf(annoValue.toString()); } return getVariable(id); } else { if (constantStore != null) { return constantStore.get(AnnotationUtils.annotationName(annotationMirror)); } else { for (Class<? extends Annotation> realAnno : realQualifiers) { if (AnnotationUtils.areSameByClass(annotationMirror, realAnno)) { return new ConstantSlot(annotationMirror, nextId()); } } } } if (InferenceMain.isHackMode()) { return new ConstantSlot( InferenceMain.getInstance() .getRealTypeFactory() .getQualifierHierarchy() .getTopAnnotations() .iterator() .next(), nextId()); } ErrorReporter.errorAbort( annotationMirror + " is a type of AnnotationMirror not handled by getVariableSlot."); return null; // Dead }
/** * Computes subtyping as per the subtyping in the qualifier hierarchy structure unless both * annotations are Value. In this case, rhs is a subtype of lhs iff lhs contains at least every * element of rhs * * @return true if rhs is a subtype of lhs, false otherwise */ @Override public boolean isSubtype(AnnotationMirror rhs, AnnotationMirror lhs) { if (AnnotationUtils.areSameByClass(lhs, UnknownVal.class) || AnnotationUtils.areSameByClass(rhs, BottomVal.class)) { return true; } else if (AnnotationUtils.areSameByClass(rhs, UnknownVal.class) || AnnotationUtils.areSameByClass(lhs, BottomVal.class)) { return false; } else if (AnnotationUtils.areSameIgnoringValues(lhs, rhs)) { // Same type, so might be subtype List<Object> lhsValues = AnnotationUtils.getElementValueArray(lhs, "value", Object.class, true); List<Object> rhsValues = AnnotationUtils.getElementValueArray(rhs, "value", Object.class, true); return lhsValues.containsAll(rhsValues); } else if (AnnotationUtils.areSameByClass(lhs, DoubleVal.class) && AnnotationUtils.areSameByClass(rhs, IntVal.class)) { List<Long> rhsValues; rhsValues = AnnotationUtils.getElementValueArray(rhs, "value", Long.class, true); List<Double> lhsValues = AnnotationUtils.getElementValueArray(lhs, "value", Double.class, true); boolean same = false; for (Long rhsLong : rhsValues) { for (Double lhsDbl : lhsValues) { if (lhsDbl.doubleValue() == rhsLong.doubleValue()) { same = true; break; } } if (!same) { return false; } } return same; } return false; }
/** * Is {@code anno} the {@link UnknownInitialization} annotation (with any type frame)? If {@code * useFbc} is false, then {@link Raw} is used in the comparison. */ public boolean isUnclassified(AnnotationMirror anno) { Class<? extends Annotation> clazz = useFbc ? UnknownInitialization.class : Raw.class; return AnnotationUtils.areSameByClass(anno, clazz); }
/** * Is {@code anno} the {@link UnderInitialization} annotation (with any type frame)? Always * returns false if {@code useFbc} is false. */ public boolean isFree(AnnotationMirror anno) { return useFbc && AnnotationUtils.areSameByClass(anno, UnderInitialization.class); }
/* * Provided that m is of a type that implements interface java.util.Map: * -Given a call m.containsKey(k), ensures that k is @KeyFor("m") in the thenStore of the transfer result. * -Given a call m.put(k, ...), ensures that k is @KeyFor("m") in the thenStore and elseStore of the transfer result. */ @Override public TransferResult<CFValue, CFStore> visitMethodInvocation( MethodInvocationNode node, TransferInput<CFValue, CFStore> in) { TransferResult<CFValue, CFStore> result = super.visitMethodInvocation(node, in); String methodName = node.getTarget().getMethod().toString(); // First verify if the method name is containsKey or put. This is an inexpensive check. boolean containsKey = methodName.startsWith("containsKey("); boolean put = methodName.startsWith("put("); if (containsKey || put) { // Now verify that the receiver of the method invocation is of a type // that extends that java.util.Map interface. This is a more expensive check. javax.lang.model.util.Types types = analysis.getTypes(); TypeMirror mapInterfaceTypeMirror = types.erasure( TypesUtils.typeFromClass(types, analysis.getEnv().getElementUtils(), Map.class)); TypeMirror receiverType = types.erasure(node.getTarget().getReceiver().getType()); if (types.isSubtype(receiverType, mapInterfaceTypeMirror)) { FlowExpressionContext flowExprContext = FlowExpressionParseUtil.buildFlowExprContextForUse(node, checker); String mapName = flowExprContext.receiver.toString(); Receiver keyReceiver = flowExprContext.arguments.get(0); KeyForAnnotatedTypeFactory atypeFactory = (KeyForAnnotatedTypeFactory) analysis.getTypeFactory(); LinkedHashSet<String> keyForMaps = new LinkedHashSet<>(); keyForMaps.add(mapName); final CFValue previousKeyValue = in.getValueOfSubNode(node.getArgument(0)); if (previousKeyValue != null) { final AnnotationMirror prevAm = previousKeyValue.getType().getAnnotationInHierarchy(KEYFOR); if (prevAm != null && AnnotationUtils.areSameByClass(prevAm, KeyFor.class)) { keyForMaps.addAll(getKeys(prevAm)); } } AnnotationMirror am = atypeFactory.createKeyForAnnotationMirrorWithValue(keyForMaps); if (containsKey) { ConditionalTransferResult<CFValue, CFStore> conditionalResult = (ConditionalTransferResult<CFValue, CFStore>) result; conditionalResult.getThenStore().insertValue(keyReceiver, am); } else if (put) { result.getThenStore().insertValue(keyReceiver, am); result.getElseStore().insertValue(keyReceiver, am); } } } return result; }