/** * Returns the (non-static) fields that have the invariant annotation and are not yet initialized * in a given store. */ public List<VariableTree> getUninitializedInvariantFields( Store store, TreePath path, boolean isStatic, List<? extends AnnotationMirror> receiverAnnotations) { ClassTree currentClass = TreeUtils.enclosingClass(path); List<VariableTree> fields = InitializationChecker.getAllFields(currentClass); List<VariableTree> violatingFields = new ArrayList<>(); AnnotationMirror invariant = getFieldInvariantAnnotation(); for (VariableTree field : fields) { if (isUnused(field, receiverAnnotations)) { continue; // don't consider unused fields } VariableElement fieldElem = TreeUtils.elementFromDeclaration(field); if (ElementUtils.isStatic(fieldElem) == isStatic) { // Does this field need to satisfy the invariant? if (getAnnotatedType(field).hasEffectiveAnnotation(invariant)) { // Has the field been initialized? if (!store.isFieldInitialized(fieldElem)) { violatingFields.add(field); } } } } return violatingFields; }
@Override public Void visitMemberSelect(MemberSelectTree tree, AnnotatedTypeMirror type) { if (TreeUtils.isFieldAccess(tree) && isUnderlyingTypeAValue(type)) { VariableElement elem = (VariableElement) InternalUtils.symbol(tree); Object value = elem.getConstantValue(); if (value != null) { // compile time constant type.replaceAnnotation( resultAnnotationHandler( type.getUnderlyingType(), Collections.singletonList(value), tree)); return null; } if (ElementUtils.isStatic(elem) && ElementUtils.isFinal(elem)) { Element e = InternalUtils.symbol(tree.getExpression()); if (e != null) { String classname = ElementUtils.getQualifiedClassName(e).toString(); String fieldName = tree.getIdentifier().toString(); value = evalutator.evaluateStaticFieldAccess(classname, fieldName, tree); if (value != null) type.replaceAnnotation( resultAnnotationHandler( type.getUnderlyingType(), Collections.singletonList(value), tree)); return null; } } if (tree.getIdentifier().toString().equals("length")) { AnnotatedTypeMirror receiverType = getAnnotatedType(tree.getExpression()); if (receiverType.getKind() == TypeKind.ARRAY) { AnnotationMirror arrayAnno = receiverType.getAnnotation(ArrayLen.class); if (arrayAnno != null) { // array.length, where array : @ArrayLen(x) List<Integer> lengths = ValueAnnotatedTypeFactory.getArrayLength(arrayAnno); type.replaceAnnotation(createNumberAnnotationMirror(new ArrayList<Number>(lengths))); return null; } } } } return null; }
@Override public Void visitMethodInvocation(MethodInvocationTree tree, AnnotatedTypeMirror type) { if (isUnderlyingTypeAValue(type) && methodIsStaticallyExecutable(TreeUtils.elementFromUse(tree))) { // Get argument values List<? extends ExpressionTree> arguments = tree.getArguments(); ArrayList<List<?>> argValues; if (arguments.size() > 0) { argValues = new ArrayList<List<?>>(); for (ExpressionTree argument : arguments) { AnnotatedTypeMirror argType = getAnnotatedType(argument); List<?> values = getValues(argType, argType.getUnderlyingType()); if (values.isEmpty()) { // values aren't known, so don't try to evaluate the // method return null; } argValues.add(values); } } else { argValues = null; } // Get receiver values AnnotatedTypeMirror receiver = getReceiverType(tree); List<?> receiverValues; if (receiver != null && !ElementUtils.isStatic(TreeUtils.elementFromUse(tree))) { receiverValues = getValues(receiver, receiver.getUnderlyingType()); if (receiverValues.isEmpty()) { // values aren't known, so don't try to evaluate the // method return null; } } else { receiverValues = null; } // Evaluate method List<?> returnValues = evalutator.evaluteMethodCall(argValues, receiverValues, tree); AnnotationMirror returnType = resultAnnotationHandler(type.getUnderlyingType(), returnValues, tree); type.replaceAnnotation(returnType); } return null; }
/** * Returns the (non-static) fields that have the invariant annotation and are initialized in a * given store. */ public List<VariableTree> getInitializedInvariantFields(Store store, TreePath path) { // TODO: Instead of passing the TreePath around, can we use // getCurrentClassTree? ClassTree currentClass = TreeUtils.enclosingClass(path); List<VariableTree> fields = InitializationChecker.getAllFields(currentClass); List<VariableTree> initializedFields = new ArrayList<>(); AnnotationMirror invariant = getFieldInvariantAnnotation(); for (VariableTree field : fields) { VariableElement fieldElem = TreeUtils.elementFromDeclaration(field); if (!ElementUtils.isStatic(fieldElem)) { // Does this field need to satisfy the invariant? if (getAnnotatedType(field).hasEffectiveAnnotation(invariant)) { // Has the field been initialized? if (store.isFieldInitialized(fieldElem)) { initializedFields.add(field); } } } } return initializedFields; }
// TODO: These are special cases for isRegex(String, int) and asRegex(String, int). // They should be replaced by adding an @EnsuresQualifierIf annotation that supports // specifying attributes. @Override public TransferResult<CFValue, CFStore> visitMethodInvocation( MethodInvocationNode n, TransferInput<CFValue, CFStore> in) { RegexClassicAnnotatedTypeFactory factory = (RegexClassicAnnotatedTypeFactory) analysis.getTypeFactory(); TransferResult<CFValue, CFStore> result = super.visitMethodInvocation(n, in); // refine result for some helper methods MethodAccessNode target = n.getTarget(); ExecutableElement method = target.getMethod(); Node receiver = target.getReceiver(); if (!(receiver instanceof ClassNameNode)) { return result; } ClassNameNode cn = (ClassNameNode) receiver; String receiverName = cn.getElement().toString(); if (isRegexUtil(receiverName)) { if (ElementUtils.matchesElement(method, IS_REGEX_METHOD_NAME, String.class, int.class)) { // RegexUtil.isRegex(s, groups) method // (No special case is needed for isRegex(String) because of // the annotation on that method's definition.) CFStore thenStore = result.getRegularStore(); CFStore elseStore = thenStore.copy(); ConditionalTransferResult<CFValue, CFStore> newResult = new ConditionalTransferResult<>(result.getResultValue(), thenStore, elseStore); Receiver firstParam = FlowExpressions.internalReprOf( factory.getContext().getAnnotationProvider(), n.getArgument(0)); // add annotation with correct group count (if possible, // regex annotation without count otherwise) Node count = n.getArgument(1); if (count instanceof IntegerLiteralNode) { IntegerLiteralNode iln = (IntegerLiteralNode) count; Integer groupCount = iln.getValue(); AnnotationMirror regexAnnotation = factory.createRegexAnnotation(groupCount); thenStore.insertValue(firstParam, regexAnnotation); } else { AnnotationMirror regexAnnotation = AnnotationUtils.fromClass(factory.getElementUtils(), Regex.class); thenStore.insertValue(firstParam, regexAnnotation); } return newResult; } else if (ElementUtils.matchesElement( method, AS_REGEX_METHOD_NAME, String.class, int.class)) { // RegexUtil.asRegex(s, groups) method // (No special case is needed for asRegex(String) because of // the annotation on that method's definition.) // add annotation with correct group count (if possible, // regex annotation without count otherwise) AnnotationMirror regexAnnotation; Node count = n.getArgument(1); if (count instanceof IntegerLiteralNode) { IntegerLiteralNode iln = (IntegerLiteralNode) count; Integer groupCount = iln.getValue(); regexAnnotation = factory.createRegexAnnotation(groupCount); } else { regexAnnotation = AnnotationUtils.fromClass(factory.getElementUtils(), Regex.class); } CFValue newResultValue = analysis.createSingleAnnotationValue( regexAnnotation, result.getResultValue().getType().getUnderlyingType()); return new RegularTransferResult<>(newResultValue, result.getRegularStore()); } } return result; };