Java tutorial
package org.mutabilitydetector.checkers.settermethod; /* * #%L * MutabilityDetector * %% * Copyright (C) 2008 - 2014 Graham Allan * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.objectweb.asm.Opcodes.ASTORE; import static org.objectweb.asm.Opcodes.DSTORE; import static org.objectweb.asm.Opcodes.FSTORE; import static org.objectweb.asm.Opcodes.ISTORE; import static org.objectweb.asm.Opcodes.LSTORE; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.concurrent.Immutable; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.VarInsnNode; /** * @author Juergen Fickel (jufickel@htwg-konstanz.de) * @version 27.02.2013 */ @Immutable final class AliasFinder implements Finder<Alias> { private final Set<ControlFlowBlock> alreadyVisited; private final String variableName; private final ControlFlowBlock controlFlowBlockToExamine; private AliasFinder(final String theVariableName, final ControlFlowBlock theControlFlowBlockToExamine) { alreadyVisited = new HashSet<ControlFlowBlock>(); variableName = theVariableName; controlFlowBlockToExamine = theControlFlowBlockToExamine; } /** * Creates a new instance of this class. * * @param variableName * name of the instance variable to search aliases for. Must * neither be {@code null} nor empty. * @param controlFlowBlockToExamine * a {@link ControlFlowBlock} which possibly contains the setup * of an alias for a lazy variable. This method thereby examines * predecessors of {@code block}, too. This parameter must not be * {@code null}. * @return a new instance of this class. */ public static AliasFinder newInstance(final String variableName, final ControlFlowBlock controlFlowBlockToExamine) { checkArgument(!variableName.isEmpty()); return new AliasFinder(variableName, checkNotNull(controlFlowBlockToExamine)); } /** * @return an {@link Alias}. This is never {@code null}. If {@code block} * does not contain an alias, the following is being returned: * {@code Alias [doesExist=false, localVariable=Integer.MIN_VALUE]}. */ @Override public Alias find() { return searchForAliasInBlock(controlFlowBlockToExamine); } /* * Uses method argument as this method works recursively. */ private Alias searchForAliasInBlock(final ControlFlowBlock block) { checkNotNull(block); Alias result = Alias.newInstance(false, Integer.MIN_VALUE); if (alreadyVisited.contains(block)) { return result; } alreadyVisited.add(block); final List<AbstractInsnNode> insns = block.getBlockInstructions(); final int indexOfGetfield = findIndexOfGetfieldForVariable(insns); if (indexOfGetfieldFound(indexOfGetfield)) { final AbstractInsnNode successorInsnOfGetfieldForVariable = insns.get(indexOfGetfield + 1); if (isStoreInstruction(successorInsnOfGetfieldForVariable)) { final VarInsnNode storeInstruction = (VarInsnNode) successorInsnOfGetfieldForVariable; result = Alias.newInstance(true, storeInstruction.var); } } if (!result.doesExist) { for (final ControlFlowBlock predecessor : block.getPredecessors()) { return searchForAliasInBlock(predecessor); } } return result; } private int findIndexOfGetfieldForVariable(final List<AbstractInsnNode> instructions) { int result = -1; int i = 0; for (final AbstractInsnNode instruction : instructions) { if (isGetfieldForVariable(instruction)) { result = i; break; } i++; } return result; } private boolean isGetfieldForVariable(final AbstractInsnNode insn) { boolean result = false; if (Opcodes.GETFIELD == insn.getOpcode()) { final FieldInsnNode getfield = (FieldInsnNode) insn; result = variableName.equals(getfield.name); } return result; } private static boolean indexOfGetfieldFound(final int index) { return -1 < index; } private static boolean isStoreInstruction(final AbstractInsnNode insn) { switch (insn.getOpcode()) { case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: return true; default: return false; } } @Override public String toString() { final StringBuilder builder = new StringBuilder(); builder.append("AliasFinder [").append("variableName=").append(variableName); builder.append(", controlFlowBlockToExamine=").append(controlFlowBlockToExamine); builder.append(", alreadyVisited=").append(alreadyVisited).append("]"); return builder.toString(); } }