private boolean isLocalVariableAnnotationFound(List<Annotation> annotationRules, MethodNode methodNode) { boolean annotationFound = true; List<AnnotationNode> allLocalVariableAnnotations = new ArrayList<>(); List<LocalVariableAnnotationNode> invisibleVariableAnnotations = methodNode.invisibleLocalVariableAnnotations; if (invisibleVariableAnnotations != null) { allLocalVariableAnnotations.addAll(invisibleVariableAnnotations); } List<LocalVariableAnnotationNode> visibleVariableAnnotations = methodNode.visibleLocalVariableAnnotations; if (visibleVariableAnnotations != null) { allLocalVariableAnnotations.addAll(visibleVariableAnnotations); } for (Annotation annotationRule : annotationRules) { annotationFound &= RuleHelper.containsAnnotation(annotationRule, allLocalVariableAnnotations); } return annotationFound; }
void checkCallSites() { final List<LocalVariableAnnotationNode> varAnnotations = new ArrayList<>(); final Map<Integer, List<AnnotationNode>> paramAnnotations = new HashMap<>(); varAnnotations.addAll(CallSiteFinder.annotationsList(visibleLocalVariableAnnotations)); varAnnotations.addAll(CallSiteFinder.annotationsList(invisibleLocalVariableAnnotations)); paramAnnotations.putAll(CallSiteFinder.annotationsList(visibleParameterAnnotations)); paramAnnotations.putAll(CallSiteFinder.annotationsList(invisibleParameterAnnotations)); final List<CallSiteFinder.Result> results = new CallSiteFinder().findMatchingCallSites(instructions, varAnnotations, paramAnnotations); for (final CallSiteFinder.Result result : results) { if (!nodes.contains(result.methodCall) && checkContinuableAnnotation(result.annotations)) { final Label label = new Label(); instructions.insertBefore(result.methodCall, getLabelNode(label)); final int insertionIndex = findCallSiteInvocationInsertionIndex(result.methodCall); if (insertionIndex < 0) { labels.add(label); nodes.add(result.methodCall); } else { labels.add(insertionIndex, label); nodes.add(insertionIndex, result.methodCall); } } } }
List<Result> findMatchingCallSites(final InsnList instructions, final List<LocalVariableAnnotationNode> varAnnotations, final Map<Integer, List<AnnotationNode>> paramAnnotations) { final List<Result> result = new ArrayList<>(); for (@SuppressWarnings("unchecked") Iterator<AbstractInsnNode> i = instructions.iterator(); i.hasNext(); ) { final AbstractInsnNode ins = i.next(); if (ins instanceof MethodInsnNode) { final MethodInsnNode mins = (MethodInsnNode)ins; final Result entry = findMatchingCallSite(mins, varAnnotations, paramAnnotations); if (entry != null) { result.add(entry); } } } return result; }
protected Result findMatchingCallSite(final MethodInsnNode m, final List<LocalVariableAnnotationNode> varAnnotations, final Map<Integer, List<AnnotationNode>> paramAnnotations) { final int opcode = m.getOpcode(); if (INVOKEVIRTUAL != opcode && INVOKEINTERFACE != opcode ) { return null; } int size = Type.getArgumentsAndReturnSizes(m.desc) >> 2; int argCount = Type.getArgumentTypes(m.desc).length; assert size >= 1; for (AbstractInsnNode n = m.getPrevious(); n != null; n = n.getPrevious()) { size -= getStackSizeChange(n); if (size == 0) { if (n instanceof VarInsnNode) { // Local variable (incl. this) or parameter final VarInsnNode v = (VarInsnNode)n; final Set<String> annotations; if (v.var > argCount) { // 0 -- this, 1..argCount-1 -- params annotations = getVarAnnotations(varAnnotations, v); } else { annotations = getParamAnnotations(paramAnnotations, v.var - 1); // -1 while instance method } return new Result(v, m, annotations); } else if (n instanceof FieldInsnNode) { // static/instance field return new Result(n, m, Collections.emptySet()); } else { // Not interested in other types like directly reused return value from chained calls break; } } else if (size <= 0) { throw new RuntimeException(); } } return null; }
protected Set<String> getVarAnnotations(final List<LocalVariableAnnotationNode> varAnnotations, final VarInsnNode v) { final Set<String> result = new TreeSet<>(); for (final LocalVariableAnnotationNode n : varAnnotations) { final int idx = n.index.indexOf(v.var); if (idx < 0) { continue; } final LabelNode start = (LabelNode) n.start.get(idx); final LabelNode end = (LabelNode) n.end.get(idx); if (isVarBetweenBounds(v, start, end)) { result.add(n.desc); } } return result; }
@SuppressWarnings("unchecked") static List<LocalVariableAnnotationNode> annotationsList(final List<?> v) { return null == v ? Collections.emptyList() : (List<LocalVariableAnnotationNode>)v; }