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.checkNotNull; import static java.lang.String.format; import java.util.Collection; import java.util.Collections; import javax.annotation.concurrent.ThreadSafe; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.MethodNode; /** * * @author Juergen Fickel (jufickel@htwg-konstanz.de) * @version 05.03.2013 */ @ThreadSafe final class InitialisersFinder implements Finder<CandidatesInitialisersMapping> { private final Collection<MethodNode> methods; private final CandidatesInitialisersMapping candidatesInitialisersMapping; private volatile boolean areMethodsAlreadyExamined; private InitialisersFinder(final Collection<MethodNode> theMethods, final CandidatesInitialisersMapping theVariableInitialisersMapping) { methods = Collections.unmodifiableCollection(theMethods); candidatesInitialisersMapping = theVariableInitialisersMapping; areMethodsAlreadyExamined = false; } /** * Creates a new instance of this class. None of the arguments must be * {@code null}. * * @param methodsOfAnalysedClass * {@link Collection} containing all methods ({@code MethodNode}) * of the class under examination. * @param candidatesInitialisersMapping * an instance of * {@link VariableInitialiserAssociation} which * contains all candidates for lazy variables of * {@code classNode}. This object should be obtained by * {@link CandidatesFinder#find()} * . * @return a new instance of this class. */ public static InitialisersFinder newInstance(final Collection<MethodNode> methodsOfAnalysedClass, final CandidatesInitialisersMapping candidatesInitialisersMapping) { final String msgTemplate = "Argument '%s' must not be null!"; checkNotNull(methodsOfAnalysedClass, format(msgTemplate, "methodsOfAnalysedClass")); checkNotNull(candidatesInitialisersMapping, format(msgTemplate, "variableInitialiserMapping")); return new InitialisersFinder(methodsOfAnalysedClass, candidatesInitialisersMapping); } @Override public CandidatesInitialisersMapping find() { if (areMethodsToBeExamined()) { collectAllInitialisingMethodsForAllLazyVariableCandidates(); areMethodsAlreadyExamined = true; } return candidatesInitialisersMapping; } private boolean areMethodsToBeExamined() { return !areMethodsAlreadyExamined; } private void collectAllInitialisingMethodsForAllLazyVariableCandidates() { for (final MethodNode methodNode : methods) { addMethodNodeIfIsInitialiserForVariable(methodNode); } } private void addMethodNodeIfIsInitialiserForVariable(final MethodNode methodNode) { for (final AbstractInsnNode insn : methodNode.instructions.toArray()) { if (isInitialiserForAVariable(insn)) { final FieldInsnNode assignmentInstruction = (FieldInsnNode) insn; candidatesInitialisersMapping.addInitialiserForCandidate(assignmentInstruction.name, methodNode); } } } private static boolean isInitialiserForAVariable(final AbstractInsnNode insn) { return isPutfieldInstruction(insn) || isPutstaticInstruction(insn); } private static boolean isPutfieldInstruction(final AbstractInsnNode insn) { return Opcodes.PUTFIELD == insn.getOpcode(); } private static boolean isPutstaticInstruction(final AbstractInsnNode insn) { return Opcodes.PUTSTATIC == insn.getOpcode(); } @Override public String toString() { final StringBuilder b = new StringBuilder(); b.append(getClass().getSimpleName()).append(" [methods=").append(methods); b.append(", variableSetterMapping=").append(candidatesInitialisersMapping); b.append(", areMethodsAlreadyExamined=").append(areMethodsAlreadyExamined).append(']'); return b.toString(); } }