/*
 * FindBugs - Find bugs in Java programs
 * Copyright (C) 2003,2004 University of Maryland
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs;

import java.util.Iterator;

import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.MethodGen;

import edu.umd.cs.findbugs.ba.CFGBuilderException;
import edu.umd.cs.findbugs.ba.ClassContext;
import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
import edu.umd.cs.findbugs.ba.bcp.ByteCodePattern;
import edu.umd.cs.findbugs.ba.bcp.ByteCodePatternMatch;
import edu.umd.cs.findbugs.ba.bcp.PatternElementMatch;
import edu.umd.cs.findbugs.ba.bcp.PatternMatcher;

A base class for bug detectors that are based on a ByteCodePattern. ByteCodePatterns provide an easy way to detect patterns of bytecode instructions, taking into account control flow and uses of fields and values.
See Also:
  • ByteCodePattern
/** * A base class for bug detectors that are based on a ByteCodePattern. * ByteCodePatterns provide an easy way to detect patterns of bytecode * instructions, taking into account control flow and uses of fields and values. * * @see ByteCodePattern */
public abstract class ByteCodePatternDetector implements Detector { private static final boolean DEBUG = SystemProperties.getBoolean("bcpd.debug"); private static final String METHOD = SystemProperties.getProperty("bcpd.method"); protected abstract BugReporter getBugReporter(); @Override public void visitClassContext(ClassContext classContext) { try { ByteCodePattern pattern = getPattern(); JavaClass jclass = classContext.getJavaClass(); Method[] methodList = jclass.getMethods(); for (Method method : methodList) { if (method.isAbstract() || method.isNative()) { continue; } if (METHOD != null && !method.getName().equals(METHOD)) { continue; } if (DEBUG) { System.out.print("=====================================================================\n" + "Method " + jclass.getClassName() + "." + method.getName() + "\n" + "=====================================================================\n"); } if (!prescreen(method, classContext)) { continue; } MethodGen methodGen = classContext.getMethodGen(method); if (methodGen == null) { continue; } PatternMatcher matcher = new PatternMatcher(pattern, classContext, method); matcher.execute(); Iterator<ByteCodePatternMatch> j = matcher.byteCodePatternMatchIterator(); while (j.hasNext()) { ByteCodePatternMatch match = j.next(); if (DEBUG) { System.out.println("Pattern match:"); Iterator<PatternElementMatch> pemIter = match.patternElementMatchIterator(); while (pemIter.hasNext()) { PatternElementMatch pem = pemIter.next(); System.out.println("\t" + pem.toString()); } } reportMatch(classContext, method, match); } } } catch (DataflowAnalysisException e) { getBugReporter().logError(getDetectorName() + " caught exception", e); } catch (CFGBuilderException e) { getBugReporter().logError(getDetectorName() + " caught exception", e); } } private String getDetectorName() { String className = this.getClass().getName(); int lastDot = className.lastIndexOf('.'); if (lastDot >= 0) { className = className.substring(lastDot + 1); } return className; } @Override public void report() { }
Get the ByteCodePattern for this detector.
/** * Get the ByteCodePattern for this detector. */
public abstract ByteCodePattern getPattern();
Prescreen a method. It is a valid, but dumb, implementation simply to return true unconditionally. A better implementation is to call ClassContext.getBytecodeSet() to check whether the method actually contains the bytecode instructions that the pattern will look for. The theory is that checking the bytecode set is very fast, while building the MethodGen, CFG, ValueNumberAnalysis, etc. objects required to match ByteCodePatterns is slow, and the bytecode pattern matching algorithm is also not particularly fast.

As a datapoint, prescreening speeds up the BCPDoubleCheck detector by a factor of 5 with no loss of generality and only a dozen or so extra lines of code.

Params:
  • method – the method
  • classContext – the ClassContext for the method
Returns:true if the method should be analyzed for instances of the ByteCodePattern
/** * Prescreen a method. It is a valid, but dumb, implementation simply to * return true unconditionally. A better implementation is to call * ClassContext.getBytecodeSet() to check whether the method actually * contains the bytecode instructions that the pattern will look for. The * theory is that checking the bytecode set is very fast, while building the * MethodGen, CFG, ValueNumberAnalysis, etc. objects required to match * ByteCodePatterns is slow, and the bytecode pattern matching algorithm is * also not particularly fast. * <p/> * <p> * As a datapoint, prescreening speeds up the BCPDoubleCheck detector <b>by * a factor of 5</b> with no loss of generality and only a dozen or so extra * lines of code. * * @param method * the method * @param classContext * the ClassContext for the method * @return true if the method should be analyzed for instances of the * ByteCodePattern */
public abstract boolean prescreen(Method method, ClassContext classContext);
Called to report an instance of the ByteCodePattern.
Params:
  • classContext – the ClassContext for the analyzed class
  • method – the method to instance appears in
  • match – the ByteCodePatternMatch object representing the match of the ByteCodePattern against actual instructions in the method
/** * Called to report an instance of the ByteCodePattern. * * @param classContext * the ClassContext for the analyzed class * @param method * the method to instance appears in * @param match * the ByteCodePatternMatch object representing the match of the * ByteCodePattern against actual instructions in the method */
public abstract void reportMatch(ClassContext classContext, Method method, ByteCodePatternMatch match) throws CFGBuilderException, DataflowAnalysisException; }