📄 findhemismatch.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.detect;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.bcel.Repository;import org.apache.bcel.classfile.Code;import org.apache.bcel.classfile.Field;import org.apache.bcel.classfile.JavaClass;import org.apache.bcel.classfile.Method;import org.apache.bcel.classfile.Signature;import edu.umd.cs.findbugs.BugInstance;import edu.umd.cs.findbugs.BugReporter;import edu.umd.cs.findbugs.BytecodeScanningDetector;import edu.umd.cs.findbugs.Lookup;import edu.umd.cs.findbugs.MethodAnnotation;import edu.umd.cs.findbugs.OpcodeStack;import edu.umd.cs.findbugs.Priorities;import edu.umd.cs.findbugs.StatelessDetector;import edu.umd.cs.findbugs.TypeAnnotation;import edu.umd.cs.findbugs.annotations.CheckForNull;import edu.umd.cs.findbugs.ba.AnalysisContext;public class FindHEmismatch extends BytecodeScanningDetector implements StatelessDetector { boolean hasFields = false; boolean visibleOutsidePackage = false; boolean hasHashCode = false; boolean hasEqualsObject = false; boolean hashCodeIsAbstract = false; boolean equalsObjectIsAbstract = false; boolean equalsMethodIsInstanceOfEquals = false; boolean hasCompareToObject = false; boolean hasEqualsSelf = false; boolean hasCompareToSelf = false; boolean extendsObject = false; MethodAnnotation equalsMethod = null; MethodAnnotation compareToMethod = null; MethodAnnotation compareToObjectMethod = null; MethodAnnotation compareToSelfMethod = null; MethodAnnotation hashCodeMethod = null; HashSet<String> nonHashableClasses = new HashSet<String>(); OpcodeStack stack = new OpcodeStack(); public boolean isHashableClassName(String dottedClassName) { return !nonHashableClasses.contains(dottedClassName); } Map<String, BugInstance> potentialBugs = new HashMap<String, BugInstance>(); private BugReporter bugReporter; public FindHEmismatch(BugReporter bugReporter) { this.bugReporter = bugReporter; } @Override public void visitAfter(JavaClass obj) { if (!obj.isClass()) return; if (getDottedClassName().equals("java.lang.Object")) return; int accessFlags = obj.getAccessFlags(); if ((accessFlags & ACC_INTERFACE) != 0) return; visibleOutsidePackage = obj.isPublic() || obj.isProtected(); String whereEqual = getDottedClassName(); boolean classThatDefinesEqualsIsAbstract = false; boolean inheritedHashCodeIsFinal = false; boolean inheritedEqualsIsFinal = false; boolean inheritedEqualsIsAbstract = false; if (!hasEqualsObject) { JavaClass we = Lookup.findSuperImplementor(obj, "equals", "(Ljava/lang/Object;)Z", bugReporter); if (we == null) { whereEqual = "java.lang.Object"; } else { whereEqual = we.getClassName(); classThatDefinesEqualsIsAbstract = we.isAbstract(); Method m = findMethod(we, "equals", "(Ljava/lang/Object;)Z"); if (m != null && m.isFinal()) inheritedEqualsIsFinal = true; if (m != null && m.isAbstract()) inheritedEqualsIsAbstract = true; } } boolean usesDefaultEquals = whereEqual.equals("java.lang.Object"); String whereHashCode = getDottedClassName(); if (!hasHashCode) { JavaClass wh = Lookup.findSuperImplementor(obj, "hashCode", "()I", bugReporter); if (wh == null) { whereHashCode = "java.lang.Object"; } else { whereHashCode = wh.getClassName(); Method m = findMethod(wh, "hashCode", "()I"); if (m != null && m.isFinal()) inheritedHashCodeIsFinal = true; } } boolean usesDefaultHashCode = whereHashCode.equals("java.lang.Object"); if (false && (usesDefaultEquals || usesDefaultHashCode)) { try { if (Repository.implementationOf(obj, "java/util/Set") || Repository.implementationOf(obj, "java/util/List") || Repository.implementationOf(obj, "java/util/Map")) { // System.out.println(getDottedClassName() + " uses default // hashCode or equals"); } } catch (ClassNotFoundException e) { // e.printStackTrace(); } } if (!hasEqualsObject && hasEqualsSelf) { if (usesDefaultEquals) { int priority = HIGH_PRIORITY; if (usesDefaultHashCode || obj.isAbstract()) priority++; if (!visibleOutsidePackage) priority++; String bugPattern = "EQ_SELF_USE_OBJECT"; BugInstance bug = new BugInstance(this, bugPattern, priority).addClass(getDottedClassName()); if (equalsMethod != null) bug.addMethod(equalsMethod); bugReporter.reportBug(bug); } else { int priority = NORMAL_PRIORITY; if (hasFields) priority--; if (obj.isAbstract()) priority++; String bugPattern = "EQ_SELF_NO_OBJECT"; String superclassName = obj.getSuperclassName(); if (superclassName.equals("java.lang.Enum")) { bugPattern = "EQ_DONT_DEFINE_EQUALS_FOR_ENUM"; priority = HIGH_PRIORITY; } BugInstance bug = new BugInstance(this, bugPattern, priority).addClass(getDottedClassName()); if (equalsMethod != null) bug.addMethod(equalsMethod); bugReporter.reportBug(bug); } }// System.out.println("Class " + getDottedClassName());// System.out.println("usesDefaultEquals: " + usesDefaultEquals);// System.out.println("hasHashCode: : " + hasHashCode);// System.out.println("usesDefaultHashCode: " + usesDefaultHashCode);// System.out.println("hasEquals: : " + hasEqualsObject);// System.out.println("hasCompareToObject: : " + hasCompareToObject);// System.out.println("hasCompareToSelf: : " + hasCompareToSelf); if ((hasCompareToObject || hasCompareToSelf) && usesDefaultEquals) { BugInstance bug = new BugInstance(this, "EQ_COMPARETO_USE_OBJECT_EQUALS", obj.isAbstract() ? Priorities.LOW_PRIORITY : Priorities.NORMAL_PRIORITY).addClass(this); if (compareToSelfMethod != null) bug.addMethod(compareToSelfMethod); else bug.addMethod(compareToObjectMethod); bugReporter.reportBug(bug); } if (!hasCompareToObject && hasCompareToSelf) { if (!extendsObject) bugReporter.reportBug(new BugInstance(this, "CO_SELF_NO_OBJECT", NORMAL_PRIORITY).addClass( getDottedClassName()).addMethod(compareToMethod)); } // if (!hasFields) return; if (hasHashCode && !hashCodeIsAbstract && !(hasEqualsObject || hasEqualsSelf)) { int priority = LOW_PRIORITY; if (usesDefaultEquals) bugReporter.reportBug(new BugInstance(this, "HE_HASHCODE_USE_OBJECT_EQUALS", priority).addClass( getDottedClassName()).addMethod(hashCodeMethod)); else if (!inheritedEqualsIsFinal) bugReporter.reportBug(new BugInstance(this, "HE_HASHCODE_NO_EQUALS", priority).addClass( getDottedClassName()).addMethod(hashCodeMethod)); } if (!hasHashCode && (hasEqualsObject && !equalsObjectIsAbstract || hasEqualsSelf)) { if (usesDefaultHashCode) { int priority = HIGH_PRIORITY; if (equalsMethodIsInstanceOfEquals) priority += 2; else if (obj.isAbstract() || !hasEqualsObject) priority++; if (priority == HIGH_PRIORITY) nonHashableClasses.add(getDottedClassName()); if (!visibleOutsidePackage) { priority++; } BugInstance bug = new BugInstance(this, "HE_EQUALS_USE_HASHCODE", priority) .addClass(getDottedClassName()); if (equalsMethod != null) bug.addMethod(equalsMethod); bugReporter.reportBug(bug); } else if (!inheritedHashCodeIsFinal && !whereHashCode.startsWith("java.util.Abstract")) { int priority = LOW_PRIORITY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -