📄 findhemismatch.java
字号:
if (hasEqualsObject && inheritedEqualsIsAbstract) priority++; if (hasFields) priority--; if (equalsMethodIsInstanceOfEquals || !hasEqualsObject) priority += 2; else if (obj.isAbstract()) priority++; BugInstance bug = new BugInstance(this, "HE_EQUALS_NO_HASHCODE", priority) .addClass(getDottedClassName()); if (equalsMethod != null) bug.addMethod(equalsMethod); bugReporter.reportBug(bug); } } if (!hasHashCode && !hasEqualsObject && !hasEqualsSelf && !usesDefaultEquals && usesDefaultHashCode && !obj.isAbstract() && classThatDefinesEqualsIsAbstract) { BugInstance bug = new BugInstance(this, "HE_INHERITS_EQUALS_USE_HASHCODE", NORMAL_PRIORITY) .addClass(getDottedClassName()); if (equalsMethod != null) bug.addMethod(equalsMethod); bugReporter.reportBug(bug); } } @Override public void visit(JavaClass obj) { extendsObject = getDottedSuperclassName().equals("java.lang.Object"); hasFields = false; hasHashCode = false; hasCompareToObject = false; hasCompareToSelf = false; hasEqualsObject = false; hasEqualsSelf = false; hashCodeIsAbstract = false; equalsObjectIsAbstract = false; equalsMethodIsInstanceOfEquals = false; equalsMethod = null; compareToMethod = null; compareToSelfMethod = null; compareToObjectMethod = null; hashCodeMethod = null; } @Override public void visit(Field obj) { int accessFlags = obj.getAccessFlags(); if ((accessFlags & ACC_STATIC) != 0) return; if (!obj.getName().startsWith("this$")) hasFields = true; } @Override public void visit(Method obj) { stack.resetForMethodEntry(this); int accessFlags = obj.getAccessFlags(); if ((accessFlags & ACC_STATIC) != 0) return; String name = obj.getName(); String sig = obj.getSignature(); if ((accessFlags & ACC_ABSTRACT) != 0) { if (name.equals("equals") && sig.equals("(L" + getClassName() + ";)Z")) { bugReporter.reportBug(new BugInstance(this, "EQ_ABSTRACT_SELF", LOW_PRIORITY).addClass(getDottedClassName())); return; } else if (name.equals("compareTo") && sig.equals("(L" + getClassName() + ";)I")) { bugReporter.reportBug(new BugInstance(this, "CO_ABSTRACT_SELF", LOW_PRIORITY).addClass(getDottedClassName())); return; } } boolean sigIsObject = sig.equals("(Ljava/lang/Object;)Z"); if (name.equals("hashCode") && sig.equals("()I")) { hasHashCode = true; if (obj.isAbstract()) hashCodeIsAbstract = true; hashCodeMethod = MethodAnnotation.fromVisitedMethod(this); // System.out.println("Found hashCode for " + betterClassName); } else if (name.equals("equals")) { if (sigIsObject) { equalsMethod = MethodAnnotation.fromVisitedMethod(this); hasEqualsObject = true; if (obj.isAbstract()) equalsObjectIsAbstract = true; else if (!obj.isNative()) { Code code = obj.getCode(); byte[] codeBytes = code.getCode(); if ((codeBytes.length == 5 && (codeBytes[1] & 0xff) == INSTANCEOF) || (codeBytes.length == 15 && (codeBytes[1] & 0xff) == INSTANCEOF && (codeBytes[11] & 0xff) == INVOKESPECIAL)) { equalsMethodIsInstanceOfEquals = true; } } } else if (sig.equals("(L" + getClassName() + ";)Z")) { hasEqualsSelf = true; if (equalsMethod == null) equalsMethod = MethodAnnotation.fromVisitedMethod(this); } } else if (name.equals("compareTo")) { MethodAnnotation tmp = MethodAnnotation.fromVisitedMethod(this); if (sig.equals("(Ljava/lang/Object;)I")) { hasCompareToObject = true; compareToObjectMethod = compareToMethod = tmp; } else if (sig.equals("(L" + getClassName() + ";)I")) { hasCompareToSelf = true; compareToSelfMethod = compareToMethod = tmp; } } } Method findMethod(JavaClass clazz, String name, String sig) { Method[] m = clazz.getMethods(); for (Method aM : m) if (aM.getName().equals(name) && aM.getSignature().equals(sig)) return aM; return null; } @Override public void sawOpcode(int seen) { stack.mergeJumps(this); if (seen == INVOKEVIRTUAL) { String className = getClassConstantOperand(); if (className.equals("java/util/Map") || className.equals("java/util/HashMap") || className.equals("java/util/LinkedHashMap") || className.equals("java/util/concurrent/ConcurrentHashMap") ) { if (getNameConstantOperand().equals("put") && getSigConstantOperand() .equals("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") && stack.getStackDepth() >= 3) check(1); else if ((getNameConstantOperand().equals("get") || getNameConstantOperand().equals("remove")) && getSigConstantOperand() .equals("(Ljava/lang/Object;)Ljava/lang/Object;") && stack.getStackDepth() >= 2) check(0); } else if (className.equals("java/util/Set") || className.equals("java/util/HashSet") ) { if (getNameConstantOperand().equals("add") || getNameConstantOperand().equals("contains") || getNameConstantOperand().equals("remove") && getSigConstantOperand() .equals("(Ljava/lang/Object;)Z") && stack.getStackDepth() >= 2) check(0); } } stack.sawOpcode(this, seen); } private void check(int pos) { OpcodeStack.Item item = stack.getStackItem(pos); JavaClass type = null; try { type = item.getJavaClass(); } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } if (type == null) return; int priority = NORMAL_PRIORITY; if (getClassConstantOperand().indexOf("Hash") >= 0) priority--; if (!AnalysisContext.currentAnalysisContext().getSubtypes().isApplicationClass(type)) priority++; if (type.isAbstract() || type.isInterface()) priority++; potentialBugs.put(type.getClassName(), new BugInstance(this, "HE_USE_OF_UNHASHABLE_CLASS",priority) .addClassAndMethod(this) .addTypeOfNamedClass(type.getClassName()).describe(TypeAnnotation.UNHASHABLE_ROLE) .addTypeOfNamedClass(getClassConstantOperand()) .addSourceLine(this)); } static final Pattern mapPattern = Pattern.compile("HashMap<L([^;<]*);"); static final Pattern hashTablePattern = Pattern.compile("Hashtable<L([^;<]*);"); static final Pattern setPattern = Pattern.compile("HashSet<L([^;<]*);"); @CheckForNull String findHashedClassInSignature(String sig) { Matcher m = mapPattern.matcher(sig); if (m.find()) return m.group(1).replace('/','.'); m = hashTablePattern.matcher(sig); if (m.find()) return m.group(1).replace('/','.'); m = setPattern.matcher(sig); if (m.find()) return m.group(1).replace('/','.');; return null; } @Override public void visit(Signature obj) { String sig = obj.getSignature(); String className = findHashedClassInSignature(sig); if (className == null) return; JavaClass type = null; try { type = Repository.lookupClass(className); } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } if (type == null) return; int priority = NORMAL_PRIORITY; if (sig.indexOf("Hash") >= 0) priority--; if (type.isAbstract() || type.isInterface()) priority++; if (!AnalysisContext.currentAnalysisContext().getSubtypes().isApplicationClass(type)) priority++; BugInstance bug = null; if (visitingField()) bug = new BugInstance(this, "HE_USE_OF_UNHASHABLE_CLASS", priority).addClass(this).addVisitedField( this).addTypeOfNamedClass(className).describe(TypeAnnotation.UNHASHABLE_ROLE); else if (visitingMethod()) bug = new BugInstance(this, "HE_USE_OF_UNHASHABLE_CLASS", priority).addClassAndMethod(this).addTypeOfNamedClass(className).describe(TypeAnnotation.UNHASHABLE_ROLE); else bug = new BugInstance(this, "HE_USE_OF_UNHASHABLE_CLASS", priority).addClass(this).addClass(this).addTypeOfNamedClass(className).describe(TypeAnnotation.UNHASHABLE_ROLE); potentialBugs.put(className, bug); } @Override public void report() { for(Map.Entry<String, BugInstance> e : potentialBugs.entrySet()) { if (!isHashableClassName(e.getKey())) { BugInstance bug = e.getValue(); bugReporter.reportBug(bug); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -