📄 buginstance.java
字号:
/* * FindBugs - Find bugs in Java programs * Copyright (C) 2003-2005 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.io.IOException;import java.io.Serializable;import java.math.BigInteger;import java.security.MessageDigest;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.HashSet;import java.util.Iterator;import java.util.NoSuchElementException;import java.util.Set;import java.util.StringTokenizer;import org.apache.bcel.Constants;import org.apache.bcel.classfile.JavaClass;import org.apache.bcel.classfile.Method;import org.apache.bcel.classfile.Field;import org.apache.bcel.generic.ConstantPoolGen;import org.apache.bcel.generic.InstructionHandle;import org.apache.bcel.generic.InvokeInstruction;import org.apache.bcel.generic.MethodGen;import org.objectweb.asm.tree.ClassNode;import edu.umd.cs.findbugs.annotations.NonNull;import edu.umd.cs.findbugs.annotations.Nullable;import edu.umd.cs.findbugs.annotations.CheckForNull;import edu.umd.cs.findbugs.ba.AnalysisContext;import edu.umd.cs.findbugs.ba.ClassContext;import edu.umd.cs.findbugs.ba.JavaClassAndMethod;import edu.umd.cs.findbugs.ba.Location;import edu.umd.cs.findbugs.ba.XFactory;import edu.umd.cs.findbugs.ba.XField;import edu.umd.cs.findbugs.ba.XMethod;import edu.umd.cs.findbugs.ba.bcp.FieldVariable;import edu.umd.cs.findbugs.classfile.ClassDescriptor;import edu.umd.cs.findbugs.classfile.FieldDescriptor;import edu.umd.cs.findbugs.classfile.MethodDescriptor;import edu.umd.cs.findbugs.util.ClassName;import edu.umd.cs.findbugs.visitclass.DismantleBytecode;import edu.umd.cs.findbugs.visitclass.PreorderVisitor;import edu.umd.cs.findbugs.xml.XMLAttributeList;import edu.umd.cs.findbugs.xml.XMLOutput;/** * An instance of a bug pattern. * A BugInstance consists of several parts: * <p/> * <ul> * <li> the type, which is a string indicating what kind of bug it is; * used as a key for the FindBugsMessages resource bundle * <li> the priority; how likely this instance is to actually be a bug * <li> a list of <em>annotations</em> * </ul> * <p/> * The annotations describe classes, methods, fields, source locations, * and other relevant context information about the bug instance. * Every BugInstance must have at least one ClassAnnotation, which * describes the class in which the instance was found. This is the * "primary class annotation". * <p/> * <p> BugInstance objects are built up by calling a string of <code>add</code> * methods. (These methods all "return this", so they can be chained). * Some of the add methods are specialized to get information automatically from * a BetterVisitor or DismantleBytecode object. * * @author David Hovemeyer * @see BugAnnotation */public class BugInstance implements Comparable<BugInstance>, XMLWriteableWithMessages, Serializable, Cloneable { private static final long serialVersionUID = 1L; private String type; private int priority; private ArrayList<BugAnnotation> annotationList; private int cachedHashCode; private @CheckForNull BugDesignation userDesignation; private BugProperty propertyListHead, propertyListTail; private String uniqueId; private String oldInstanceHash; private String instanceHash; private int instanceOccurrenceNum; private int instanceOccurrenceMax; /* * The following fields are used for tracking Bug instances across multiple versions of software. * They are meaningless in a BugCollection for just one version of software. */ private long firstVersion = 0; private long lastVersion = -1; private boolean introducedByChangeOfExistingClass; private boolean removedByChangeOfPersistingClass; /** * This value is used to indicate that the cached hashcode * is invalid, and should be recomputed. */ private static final int INVALID_HASH_CODE = 0; /** * This value is used to indicate whether BugInstances should be reprioritized very low, * when the BugPattern is marked as experimental */ private static boolean adjustExperimental = false; private static Set<String> bugTypes = Collections.synchronizedSet(new HashSet<String>()); /** * Constructor. * * @param type the bug type * @param priority the bug priority */ public BugInstance(String type, int priority) { this.type = type; this.priority = priority; annotationList = new ArrayList<BugAnnotation>(4); cachedHashCode = INVALID_HASH_CODE; if (bugTypes.add(type)) { BugPattern p = I18N.instance().lookupBugPattern(type); if (p == null) { String msg = "Can't find definition of bug type " + type; AnalysisContext.logError(msg, new IllegalArgumentException(msg)); } } if (adjustExperimental && isExperimental()) this.priority = Detector.EXP_PRIORITY; boundPriority(); } private void boundPriority() { priority = boundedPriority(priority); } @Override public Object clone() { BugInstance dup; try { dup = (BugInstance) super.clone(); // Do deep copying of mutable objects for (int i = 0; i < dup.annotationList.size(); ++i) { dup.annotationList.set(i, (BugAnnotation) dup.annotationList.get(i).clone()); } dup.propertyListHead = dup.propertyListTail = null; for (Iterator<BugProperty> i = propertyIterator(); i.hasNext(); ) { dup.addProperty((BugProperty) i.next().clone()); } return dup; } catch (CloneNotSupportedException e) { throw new AssertionError(e); } } /** * Create a new BugInstance. * This is the constructor that should be used by Detectors. * * @param detector the Detector that is reporting the BugInstance * @param type the bug type * @param priority the bug priority */ public BugInstance(Detector detector, String type, int priority) { this(type, priority); if (detector != null) { // Adjust priority if required DetectorFactory factory = DetectorFactoryCollection.instance().getFactoryByClassName(detector.getClass().getName()); if (factory != null) { this.priority += factory.getPriorityAdjustment(); boundPriority(); } } } /** * Create a new BugInstance. * This is the constructor that should be used by Detectors. * * @param detector the Detector2 that is reporting the BugInstance * @param type the bug type * @param priority the bug priority */ public BugInstance(Detector2 detector, String type, int priority) { this(type, priority); if (detector != null) { // Adjust priority if required DetectorFactory factory = DetectorFactoryCollection.instance().getFactoryByClassName(detector.getDetectorClassName()); if (factory != null) { this.priority += factory.getPriorityAdjustment(); boundPriority(); } } } public static void setAdjustExperimental(boolean adjust) { adjustExperimental = adjust; } /* ---------------------------------------------------------------------- * Accessors * ---------------------------------------------------------------------- */ /** * Get the bug type. */ public String getType() { return type; } /** * Get the BugPattern. */ public @NonNull BugPattern getBugPattern() { BugPattern result = I18N.instance().lookupBugPattern(getType()); if (result != null) return result; AnalysisContext.logError("Unable to find description of bug pattern " + getType()); result = I18N.instance().lookupBugPattern("UNKNOWN"); if (result != null) return result; return BugPattern.REALLY_UNKNOWN; } /** * Get the bug priority. */ public int getPriority() { return priority; } /** * Get a string describing the bug priority and type. * e.g. "High Priority Correctness" * @return a string describing the bug priority and type */ public String getPriorityTypeString() { String priorityString = getPriorityString(); BugPattern bugPattern = this.getBugPattern(); //then get the category and put everything together String categoryString; if (bugPattern == null) categoryString = "Unknown category for " + getType(); else categoryString = I18N.instance().getBugCategoryDescription(bugPattern.getCategory()); return priorityString + " Priority " + categoryString; //TODO: internationalize the word "Priority" } public String getPriorityTypeAbbreviation() { String priorityString = getPriorityAbbreviation(); return priorityString + " " + getCategoryAbbrev(); } public String getCategoryAbbrev() { BugPattern bugPattern = getBugPattern(); if (bugPattern == null) return "?"; return bugPattern.getCategoryAbbrev(); } public String getPriorityString() { //first, get the priority int value = this.getPriority(); String priorityString; if (value == Detector.HIGH_PRIORITY) priorityString = edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_high", "High"); else if (value == Detector.NORMAL_PRIORITY) priorityString = edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_normal", "Medium"); else if (value == Detector.LOW_PRIORITY) priorityString = edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_low", "Low"); else if (value == Detector.EXP_PRIORITY) priorityString = edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_experimental", "Experimental"); else priorityString = edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_ignore", "Ignore"); // This probably shouldn't ever happen, but what the hell, let's be complete return priorityString; } public String getPriorityAbbreviation() { return getPriorityString().substring(0,1); } /** * Set the bug priority. */ public void setPriority(int p) { priority = boundedPriority(p); } private int boundedPriority(int p) { return Math.max(Detector.HIGH_PRIORITY, Math.min(Detector.IGNORE_PRIORITY, p)); } public void raisePriority() { priority = boundedPriority(priority-1); } public void lowerPriority() { priority = boundedPriority(priority+1); } public void lowerPriorityALot() { priority = boundedPriority(priority+2); } /** * Is this bug instance the result of an experimental detector? */ public boolean isExperimental() { BugPattern pattern = getBugPattern(); return (pattern != null) && pattern.isExperimental(); } /** * Get the primary class annotation, which indicates where the bug occurs. */ public ClassAnnotation getPrimaryClass() { return (ClassAnnotation) findAnnotationOfType(ClassAnnotation.class); } /** * Get the primary method annotation, which indicates where the bug occurs. */ public MethodAnnotation getPrimaryMethod() { return (MethodAnnotation) findAnnotationOfType(MethodAnnotation.class); } /** * Get the primary method annotation, which indicates where the bug occurs. */ public FieldAnnotation getPrimaryField() { return (FieldAnnotation) findAnnotationOfType(FieldAnnotation.class); } public BugInstance lowerPriorityIfDeprecated() { MethodAnnotation m = getPrimaryMethod(); if (m != null && AnalysisContext.currentXFactory().getDeprecated().contains(XFactory.createXMethod(m))) lowerPriority(); FieldAnnotation f = getPrimaryField(); if (f != null && AnalysisContext.currentXFactory().getDeprecated().contains(XFactory.createXField(f))) lowerPriority(); return this; } /** * Find the first BugAnnotation in the list of annotations * that is the same type or a subtype as the given Class parameter. * * @param cls the Class parameter * @return the first matching BugAnnotation of the given type, * or null if there is no such BugAnnotation */ private BugAnnotation findAnnotationOfType(Class<? extends BugAnnotation> cls) { for (Iterator<BugAnnotation> i = annotationIterator(); i.hasNext();) { BugAnnotation annotation = i.next(); if (cls.isAssignableFrom(annotation.getClass())) return annotation; } return null; } public LocalVariableAnnotation getPrimaryLocalVariableAnnotation() { for (BugAnnotation annotation : annotationList) if (annotation instanceof LocalVariableAnnotation) return (LocalVariableAnnotation) annotation; return null; } /** * Get the primary source line annotation. * There is guaranteed to be one (unless some Detector constructed * an invalid BugInstance). * * @return the source line annotation */ public SourceLineAnnotation getPrimarySourceLineAnnotation() { // Highest priority: return the first top level source line annotation for (BugAnnotation annotation : annotationList) { if (annotation instanceof SourceLineAnnotation) return (SourceLineAnnotation) annotation; } // Next: Try primary method, primary field, primary class SourceLineAnnotation srcLine; if ((srcLine = inspectPackageMemberSourceLines(getPrimaryMethod())) != null) return srcLine; if ((srcLine = inspectPackageMemberSourceLines(getPrimaryField())) != null) return srcLine; if ((srcLine = inspectPackageMemberSourceLines(getPrimaryClass())) != null) return srcLine; // Last resort: throw exception throw new IllegalStateException("BugInstance must contain at least one class, method, or field annotation"); } public String getInstanceKey() { StringBuffer buf = new StringBuffer(type); for (BugAnnotation annotation : annotationList) { if (annotation instanceof SourceLineAnnotation || annotation instanceof MethodAnnotation && !annotation.isSignificant()) { // do nothing } else { buf.append(":"); buf.append(annotation.format("hash", null)); } } return buf.toString(); } /** * If given PackageMemberAnnotation is non-null, return its * SourceLineAnnotation. * * @param packageMember * a PackageMemberAnnotation * @return the PackageMemberAnnotation's SourceLineAnnotation, or null if * there is no SourceLineAnnotation */ private SourceLineAnnotation inspectPackageMemberSourceLines(PackageMemberAnnotation packageMember) { return (packageMember != null) ? packageMember.getSourceLines() : null; } /** * Get an Iterator over all bug annotations. */ public Iterator<BugAnnotation> annotationIterator() { return annotationList.iterator(); } /** * Get the abbreviation of this bug instance's BugPattern. * This is the same abbreviation used by the BugCode which * the BugPattern is a particular species of. */ public String getAbbrev() { BugPattern pattern = getBugPattern(); return pattern != null ? pattern.getAbbrev() : "<unknown bug pattern>"; } /** set the user designation object. This will clobber any * existing annotationText (or any other BugDesignation field). */ public void setUserDesignation(BugDesignation bd) { userDesignation = bd; } /** return the user designation object, which may be null. * * A previous calls to getSafeUserDesignation(), setAnnotationText(), * or setUserDesignation() will ensure it will be non-null
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -