/** Is the annotation {@code anno} an initialization qualifier? */ protected boolean isInitializationAnnotation(AnnotationMirror anno) { assert anno != null; return AnnotationUtils.areSameIgnoringValues(anno, UNCLASSIFIED) || AnnotationUtils.areSameIgnoringValues(anno, FREE) || AnnotationUtils.areSameIgnoringValues(anno, COMMITTED) || AnnotationUtils.areSameIgnoringValues(anno, FBCBOTTOM); }
/** * 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); } } }
/** * Recursive method to handle array initializations. Recursively descends the initializer to * find each dimension's size and create the appropriate annotation for it. * * @param dimensions a list of ExpressionTrees where each ExpressionTree is a specifier of the * size of that dimension (should be an IntVal). * @param type the AnnotatedTypeMirror of the array */ private void handleDimensions( List<? extends ExpressionTree> dimensions, AnnotatedArrayType type) { if (dimensions.size() > 1) { handleDimensions( dimensions.subList(1, dimensions.size()), (AnnotatedArrayType) type.getComponentType()); } AnnotationMirror dimType = getAnnotatedType(dimensions.get(0)).getAnnotationInHierarchy(UNKNOWNVAL); if (!AnnotationUtils.areSameIgnoringValues(dimType, UNKNOWNVAL)) { List<Long> longLengths = getIntValues(dimType); HashSet<Integer> lengths = new HashSet<Integer>(longLengths.size()); for (Long l : longLengths) { lengths.add(l.intValue()); } AnnotationMirror newQual = createArrayLenAnnotation(new ArrayList<>(lengths)); type.replaceAnnotation(newQual); } }
/** * 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; }