⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 findrefcomparison.java

📁 A static analysis tool to find bugs in Java programs
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* * 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.detect;import edu.umd.cs.findbugs.*;import edu.umd.cs.findbugs.ba.*;import edu.umd.cs.findbugs.ba.type.*;import edu.umd.cs.findbugs.props.*;import java.util.*;import org.apache.bcel.Constants;import org.apache.bcel.classfile.*;import org.apache.bcel.generic.*;/** * Find suspicious reference comparisons. * This includes: * <ul> * <li>Strings and other java.lang objects compared by reference equality</li> * <li>Calls to equals(Object) where the argument is a different type than *     the receiver object</li> * </ul> *  * @author David Hovemeyer * @author Bill Pugh */public class FindRefComparison implements Detector, ExtendedTypes {	private static final boolean DEBUG = SystemProperties.getBoolean("frc.debug");	private static final boolean REPORT_ALL_REF_COMPARISONS = SystemProperties.getBoolean("findbugs.refcomp.reportAll");	private static final int BASE_ES_PRIORITY = SystemProperties.getInteger("es.basePriority", NORMAL_PRIORITY);	/**	 * Classes that are suspicious if compared by reference.	 */	private static final HashSet<String> suspiciousSet = new HashSet<String>();	static {		suspiciousSet.add("java.lang.Boolean");		suspiciousSet.add("java.lang.Byte");		suspiciousSet.add("java.lang.Character");		suspiciousSet.add("java.lang.Double");		suspiciousSet.add("java.lang.Float");		suspiciousSet.add("java.lang.Integer");		suspiciousSet.add("java.lang.Long");		suspiciousSet.add("java.lang.Short");	}	/**	 * Set of opcodes that invoke instance methods on an object.	 */	private static final BitSet invokeInstanceSet = new BitSet();	static {		invokeInstanceSet.set(Constants.INVOKEVIRTUAL);		invokeInstanceSet.set(Constants.INVOKEINTERFACE);		invokeInstanceSet.set(Constants.INVOKESPECIAL);	}	/**	 * Set of bytecodes using for prescreening.	 */	private static final BitSet prescreenSet = new BitSet();	static {		prescreenSet.or(invokeInstanceSet);		prescreenSet.set(Constants.IF_ACMPEQ);		prescreenSet.set(Constants.IF_ACMPNE);	}	/* ----------------------------------------------------------------------	 * Helper classes	 * ---------------------------------------------------------------------- */	private static final byte T_DYNAMIC_STRING = T_AVAIL_TYPE + 0;	private static final byte T_STATIC_STRING = T_AVAIL_TYPE + 1;	private static final byte T_PARAMETER_STRING = T_AVAIL_TYPE + 2;	private static final String STRING_SIGNATURE = "Ljava/lang/String;";	/**	 * Type representing a dynamically created String.	 * This sort of String should never be compared using reference	 * equality.	 */	private static class DynamicStringType extends ObjectType {		private static final long serialVersionUID = 1L;		public DynamicStringType() {			super("java.lang.String");		}		@Override		public byte getType() {			return T_DYNAMIC_STRING;		}		@Override		public int hashCode() {			return System.identityHashCode(this);		}		@Override		public boolean equals(Object o) {			return o == this;		}		@Override		public String toString() {			return "<dynamic string>";		}	}	private static final Type dynamicStringTypeInstance = new DynamicStringType();	/**	 * Type representing a static String.	 * E.g., interned strings and constant strings.	 * It is generally OK to compare this sort of String	 * using reference equality.	 */	private static class StaticStringType extends ObjectType {		private static final long serialVersionUID = 1L;		public StaticStringType() {			super("java.lang.String");		}		@Override		public byte getType() {			return T_STATIC_STRING;		}		@Override		public int hashCode() {			return System.identityHashCode(this);		}		@Override		public boolean equals(Object o) {			return o == this;		}		@Override		public String toString() {			return "<static string>";		}	}	private static final Type staticStringTypeInstance = new StaticStringType();	/**	 * Type representing a String passed as a parameter.	 */	private static class ParameterStringType extends ObjectType {		private static final long serialVersionUID = 1L;		public ParameterStringType() {			super("java.lang.String");		}		@Override		public byte getType() {			return T_PARAMETER_STRING;		}		@Override		public int hashCode() {			return System.identityHashCode(this);		}		@Override		public boolean equals(Object o) {			return o == this;		}		@Override		public String toString() {			return "<parameter string>";		}	}	private static final Type parameterStringTypeInstance = new ParameterStringType();	private static class RefComparisonTypeFrameModelingVisitor extends TypeFrameModelingVisitor {		private RepositoryLookupFailureCallback lookupFailureCallback;		private boolean sawStringIntern;		public RefComparisonTypeFrameModelingVisitor(				ConstantPoolGen cpg,				RepositoryLookupFailureCallback lookupFailureCallback) {			super(cpg);			this.lookupFailureCallback = lookupFailureCallback;			this.sawStringIntern = false;		}		public boolean sawStringIntern() {			return sawStringIntern;		}		// Override handlers for bytecodes that may return String objects		// known to be dynamic or static.		@Override		public void visitINVOKESTATIC(INVOKESTATIC obj) {			consumeStack(obj);			if (returnsString(obj)) {				String className = obj.getClassName(getCPG());				if (className.equals("java.lang.String")) {					pushValue(dynamicStringTypeInstance);				} else {					pushReturnType(obj);				}			} else {				pushReturnType(obj);			}		}		@Override		public void visitINVOKESPECIAL(INVOKESPECIAL obj) {			handleInstanceMethod(obj);		}		@Override		public void visitINVOKEINTERFACE(INVOKEINTERFACE obj) {			handleInstanceMethod(obj);		}		@Override		public void visitINVOKEVIRTUAL(INVOKEVIRTUAL obj) {			handleInstanceMethod(obj);		}		private boolean returnsString(InvokeInstruction inv) {			String methodSig = inv.getSignature(getCPG());			return methodSig.endsWith(")Ljava/lang/String;");		}		private void handleInstanceMethod(InvokeInstruction obj) {			consumeStack(obj);			if (returnsString(obj)) {				String className = obj.getClassName(getCPG());				String methodName = obj.getName(getCPG());				// System.out.println(className + "." + methodName);				if (methodName.equals("intern") && className.equals("java.lang.String")) {					sawStringIntern = true;					pushValue(staticStringTypeInstance);				} else if (methodName.equals("toString")						|| className.equals("java.lang.String")) {					pushValue(dynamicStringTypeInstance);					// System.out.println("  dynamic");				} else					pushReturnType(obj);			} else				pushReturnType(obj);		}		@Override		public void visitLDC(LDC obj) {			Type type = obj.getType(getCPG());			pushValue(isString(type) ? staticStringTypeInstance : type);		}		@Override		public void visitLDC2_W(LDC2_W obj) {			Type type = obj.getType(getCPG());			pushValue(isString(type) ? staticStringTypeInstance : type);		}		private boolean isString(Type type) {			return type.getSignature().equals(STRING_SIGNATURE);		}		@Override		public void visitGETSTATIC(GETSTATIC obj) {			handleLoad(obj);		}		@Override		public void visitGETFIELD(GETFIELD obj) {			handleLoad(obj);		}		private void handleLoad(FieldInstruction obj) {			consumeStack(obj);			Type type = obj.getType(getCPG());			if (type.getSignature().equals(STRING_SIGNATURE)) {				try {					String className = obj.getClassName(getCPG());					String fieldName = obj.getName(getCPG());					Field field = Hierarchy.findField(className, fieldName);					if (field != null) {						// If the field is final, we'll assume that the String value						// is static.						if (field.isFinal())							pushValue(staticStringTypeInstance);						else							pushValue(type);						return;					}				} catch (ClassNotFoundException ex) {					lookupFailureCallback.reportMissingClass(ex);				}			}			pushValue(type);		}	}	/**	 * Type merger to use the extended String types.	 */	private static class RefComparisonTypeMerger extends StandardTypeMerger {		public RefComparisonTypeMerger(RepositoryLookupFailureCallback lookupFailureCallback,				ExceptionSetFactory exceptionSetFactory) {			super(lookupFailureCallback, exceptionSetFactory);		}		@Override		protected boolean isReferenceType(byte type) {			return super.isReferenceType(type) || type == T_STATIC_STRING || type == T_DYNAMIC_STRING;		}		@Override		protected Type mergeReferenceTypes(ReferenceType aRef, ReferenceType bRef) throws DataflowAnalysisException {			byte aType = aRef.getType();			byte bType = bRef.getType();			if (isExtendedStringType(aType) || isExtendedStringType(bType)) {				// If both types are the same extended String type,				// then the same type is returned.  Otherwise, extended				// types are downgraded to plain java.lang.String,				// and a standard merge is applied.				if (aType == bType)					return aRef;				if (isExtendedStringType(aType))					aRef = Type.STRING;				if (isExtendedStringType(bType))					bRef = Type.STRING;			}			return super.mergeReferenceTypes(aRef, bRef);		}		private boolean isExtendedStringType(byte type) {			return type == T_DYNAMIC_STRING || type == T_STATIC_STRING || type == T_PARAMETER_STRING;		}	}	/* ----------------------------------------------------------------------	 * Fields	 * ---------------------------------------------------------------------- */	private BugReporter bugReporter;	private ClassContext classContext;	/* ----------------------------------------------------------------------	 * Implementation	 * ---------------------------------------------------------------------- */	public FindRefComparison(BugReporter bugReporter) {		this.bugReporter = bugReporter;	}	public void visitClassContext(ClassContext classContext) {		this.classContext = classContext;		JavaClass jclass = classContext.getJavaClass();		Method[] methodList = jclass.getMethods();		for (Method method : methodList) {			MethodGen methodGen = classContext.getMethodGen(method);			if (methodGen == null)				continue;			// Prescreening - must have IF_ACMPEQ, IF_ACMPNE,			// or an invocation of an instance method			BitSet bytecodeSet = classContext.getBytecodeSet(method);			if (bytecodeSet == null || !bytecodeSet.intersects(prescreenSet))				continue;			if (DEBUG)				System.out.println("FindRefComparison: analyzing " +						SignatureConverter.convertMethodSignature(methodGen));			try {				analyzeMethod(classContext, method);			} catch (CFGBuilderException e) {				bugReporter.logError("Error analyzing " + method.toString(), e);			} catch (DataflowAnalysisException e) {				// bugReporter.logError("Error analyzing " + method.toString(), e);			}		}	}	/**	 * A BugInstance and its WarningPropertySet.	 */	private static class WarningWithProperties {		BugInstance instance;		WarningPropertySet propertySet;		Location location;		WarningWithProperties(BugInstance warning, WarningPropertySet propertySet, Location location) {			this.instance = warning;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -