// 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; };
/* * 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; }