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