📄 unreadfields.java
字号:
if (selfCall && getMethodName().equals("<init>")) { sawSelfCallInConstructor = true; if (DEBUG) System.out.println("Saw self call in " + getFullyQualifiedMethodName() + " to " + invokedClassName + "." + getNameConstantOperand() ); } } } if ((seen == IFNULL || seen == IFNONNULL) && opcodeStack.getStackDepth() > 0) { OpcodeStack.Item item = opcodeStack.getStackItem(0); XField f = item.getXField(); if (f != null) { nullTested.add(f); if (DEBUG) System.out.println(f + " null checked in " + getFullyQualifiedMethodName()); } } if (seen == GETFIELD || seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE || seen == INVOKESPECIAL || seen == PUTFIELD || seen == IALOAD || seen == AALOAD || seen == BALOAD || seen == CALOAD || seen == SALOAD || seen == IASTORE || seen == AASTORE || seen == BASTORE || seen == CASTORE || seen == SASTORE || seen == ARRAYLENGTH) { int pos = 0; switch(seen) { case ARRAYLENGTH: case GETFIELD : pos = 0; break; case INVOKEVIRTUAL : case INVOKEINTERFACE: case INVOKESPECIAL: String sig = getSigConstantOperand(); pos = PreorderVisitor.getNumberArguments(sig); break; case PUTFIELD : case IALOAD : case AALOAD: case BALOAD: case CALOAD: case SALOAD: pos = 1; break; case IASTORE : case AASTORE: case BASTORE: case CASTORE: case SASTORE: pos = 2; break; default: throw new RuntimeException("Impossible"); } if (opcodeStack.getStackDepth() >= pos) { OpcodeStack.Item item = opcodeStack.getStackItem(pos); XField f = item.getXField(); if (DEBUG) System.out.println("RRR: " + f + " " + nullTested.contains(f) + " " + writtenInConstructorFields.contains(f) + " " + writtenNonNullFields.contains(f)); if (f != null && !nullTested.contains(f) && ! (writtenInConstructorFields.contains(f) && writtenNonNullFields.contains(f)) ) { ProgramPoint p = new ProgramPoint(this); HashSet <ProgramPoint> s = assumedNonNull.get(f); if (s == null) { s = new HashSet<ProgramPoint>(); assumedNonNull.put(f,s); } s.add(p); if (DEBUG) System.out.println(f + " assumed non-null in " + getFullyQualifiedMethodName()); } } } if (seen == ALOAD_1) { count_aload_1++; } else if (seen == GETFIELD || seen == GETSTATIC) { XField f = XFactory.createReferencedXField(this); pendingGetField = f; if (getMethodName().equals("readResolve") && seen == GETFIELD ) { writtenFields.add(f); writtenNonNullFields.add(f); } if (DEBUG) System.out.println("get: " + f); // readFields.add(f); if (!fieldAccess.containsKey(f)) fieldAccess.put(f, SourceLineAnnotation.fromVisitedInstruction(this)); } else if ((seen == PUTFIELD || seen == PUTSTATIC) && !selfAssignment) { XField f = XFactory.createReferencedXField(this); OpcodeStack.Item item = null; if (opcodeStack.getStackDepth() > 0) { item = opcodeStack.getStackItem(0); if (!item.isNull()) nullTested.add(f); } writtenFields.add(f); if (!fieldAccess.containsKey(f)) fieldAccess.put(f, SourceLineAnnotation.fromVisitedInstruction(this)); if (previousOpcode != ACONST_NULL || previousPreviousOpcode == GOTO ) { writtenNonNullFields.add(f); if (DEBUG) System.out.println("put nn: " + f); } else if (DEBUG) System.out.println("put: " + f); if ( getMethod().isStatic() == f.isStatic() && ( calledFromConstructors.contains(getMethodName()+":"+getMethodSig()) || getMethodName().equals("<init>") || getMethodName().equals("init") || getMethodName().equals("init") || getMethodName().equals("initialize") || getMethodName().equals("<clinit>") || getMethod().isPrivate())) { writtenInConstructorFields.add(f); if (previousOpcode != ACONST_NULL || previousPreviousOpcode == GOTO ) assumedNonNull.remove(f); } else { writtenOutsideOfConstructorFields.add(f); } } opcodeStack.sawOpcode(this, seen); previousPreviousOpcode = previousOpcode; previousOpcode = seen; if (false && DEBUG) { System.out.println("After " + OPCODE_NAMES[seen] + " opcode stack is"); System.out.println(opcodeStack); } } static Pattern dontComplainAbout = Pattern.compile("class[$]"); static Pattern withinAnonymousClass = Pattern.compile("[$][0-9].*[$]"); @Override public void report() { Set<String> fieldNamesSet = new HashSet<String>(); for(XField f : writtenNonNullFields) fieldNamesSet.add(f.getName()); if (DEBUG) { System.out.println("read fields:" ); for(XField f : readFields) System.out.println(" " + f); if (!containerFields.isEmpty()) { System.out.println("ejb3 fields:" ); for(XField f : containerFields) System.out.println(" " + f); } if (!reflectiveFields.isEmpty()) { System.out.println("reflective fields:" ); for(XField f : reflectiveFields) System.out.println(" " + f); } System.out.println("written fields:" ); for (XField f : writtenFields) System.out.println(" " + f); System.out.println("written nonnull fields:" ); for (XField f : writtenNonNullFields) System.out.println(" " + f); System.out.println("assumed nonnull fields:" ); for (XField f : assumedNonNull.keySet()) System.out.println(" " + f); } // Don't report anything about ejb3Fields declaredFields.removeAll(containerFields); declaredFields.removeAll(reflectiveFields); TreeSet<XField> notInitializedInConstructors = new TreeSet<XField>(declaredFields); notInitializedInConstructors.retainAll(readFields); notInitializedInConstructors.retainAll(writtenFields); notInitializedInConstructors.retainAll(assumedNonNull.keySet()); notInitializedInConstructors.removeAll(staticFields); notInitializedInConstructors.removeAll(writtenInConstructorFields); // notInitializedInConstructors.removeAll(staticFields); TreeSet<XField> readOnlyFields = new TreeSet<XField>(declaredFields); readOnlyFields.removeAll(writtenFields); readOnlyFields.retainAll(readFields); TreeSet<XField> nullOnlyFields = new TreeSet<XField>(declaredFields); nullOnlyFields.removeAll(writtenNonNullFields); nullOnlyFields.retainAll(readFields); Set<XField> writeOnlyFields = declaredFields; writeOnlyFields.removeAll(readFields); Map<String, Integer> count = new HashMap<String, Integer>(); for (XField f : nullOnlyFields) { int increment = 3; Collection<ProgramPoint> assumedNonNullAt = assumedNonNull.get(f); if (assumedNonNullAt != null) increment += assumedNonNullAt.size(); for(String s : unknownAnnotation.get(f)) { Integer value = count.get(s); if (value == null) count.put(s,increment); else count.put(s,value+increment); } } Map<XField, Integer> maxCount = new HashMap<XField, Integer>(); LinkedList<XField> assumeReflective = new LinkedList<XField>(); for (XField f : nullOnlyFields) { int myMaxCount = 0; for(String s : unknownAnnotation.get(f)) { Integer value = count.get(s); if (value != null && myMaxCount < value) myMaxCount = value; } if (myMaxCount > 0) maxCount.put(f, myMaxCount); if (myMaxCount > 15) assumeReflective.add(f); } readOnlyFields.removeAll(assumeReflective); nullOnlyFields.removeAll(assumeReflective); notInitializedInConstructors.removeAll(assumeReflective); for (XField f : notInitializedInConstructors) { String fieldName = f.getName(); String className = f.getClassName(); String fieldSignature = f.getSignature(); if (f.isResolved() && !fieldsOfNativeClasses.contains(f) && (fieldSignature.charAt(0) == 'L' || fieldSignature.charAt(0) == '[') ) { int priority = LOW_PRIORITY; if (assumedNonNull.containsKey(f)) bugReporter.reportBug(new BugInstance(this, "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", priority) .addClass(className) .addField(f)); } } for (XField f : readOnlyFields) { String fieldName = f.getName(); String className = f.getClassName(); String fieldSignature = f.getSignature(); if (f.isResolved() && !fieldsOfNativeClasses.contains(f)) { int priority = NORMAL_PRIORITY; if (!(fieldSignature.charAt(0) == 'L' || fieldSignature.charAt(0) == '[')) priority++; if (maxCount.containsKey(f)) priority++; bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this, "UWF_UNWRITTEN_FIELD", priority),f)); } } for (XField f : nullOnlyFields) { String fieldName = f.getName(); String className = f.getClassName(); String fieldSignature = f.getSignature(); if (DEBUG) { System.out.println("Null only: " + f); System.out.println(" : " + assumedNonNull.containsKey(f)); System.out.println(" : " + fieldsOfSerializableOrNativeClassed.contains(f)); System.out.println(" : " + fieldNamesSet.contains(f.getName())); System.out.println(" : " + abstractClasses.contains(f.getClassName())); System.out.println(" : " + hasNonAbstractSubClass.contains(f.getClassName())); System.out.println(" : " + f.isResolved()); } if (!f.isResolved()) continue; if (fieldsOfNativeClasses.contains(f)) continue; if (DEBUG) { System.out.println("Ready to report"); } int priority = NORMAL_PRIORITY; if (maxCount.containsKey(f)) priority++; if (abstractClasses.contains(f.getClassName())) { priority++; if (! hasNonAbstractSubClass.contains(f.getClassName())) priority++; } // if (fieldNamesSet.contains(f.getName())) priority++; if (assumedNonNull.containsKey(f)) { int npPriority = priority; HashSet<ProgramPoint> assumedNonNullAt = assumedNonNull.get(f); if (assumedNonNullAt.size() > 14) { npPriority+=2; } else if (assumedNonNullAt.size() > 6) { npPriority++; } else { priority--; } for (ProgramPoint p : assumedNonNullAt) bugReporter.reportBug(new BugInstance(this, "NP_UNWRITTEN_FIELD", npPriority) .addClassAndMethod(p.method) .addField(f) .addSourceLine(p.sourceLine) ); } else { if (f.isStatic()) priority++; if (finalFields.contains(f)) priority++; if (fieldsOfSerializableOrNativeClassed.contains(f)) priority++; } if (!readOnlyFields.contains(f)) bugReporter.reportBug( addClassFieldAndAccess(new BugInstance(this,"UWF_NULL_FIELD",priority), f).lowerPriorityIfDeprecated() ); } for (XField f : writeOnlyFields) { String fieldName = f.getName(); String className = f.getClassName(); int lastDollar = Math.max(className.lastIndexOf('$'), className.lastIndexOf('+')); boolean isAnonymousInnerClass = (lastDollar > 0) && (lastDollar < className.length() - 1) && Character.isDigit(className.charAt(lastDollar+1)); if (DEBUG) { System.out.println("Checking write only field " + className + "." + fieldName + "\t" + constantFields.contains(f) + "\t" + f.isStatic() ); } if (!f.isResolved()) continue; if (dontComplainAbout.matcher(fieldName).find()) continue; if (fieldName.startsWith("this$") || fieldName.startsWith("this+")) { String outerClassName = className.substring(0, lastDollar); try { JavaClass outerClass = Repository.lookupClass(outerClassName); if (classHasParameter(outerClass)) continue; } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); } if (!innerClassCannotBeStatic.contains(className)) { boolean easyChange = !needsOuterObjectInConstructor.contains(className); if (easyChange || !isAnonymousInnerClass) { // easyChange isAnonymousInnerClass // true false medium, SIC // true true low, SIC_ANON // false true not reported // false false low, SIC_THIS int priority = LOW_PRIORITY; if (easyChange && !isAnonymousInnerClass) priority = NORMAL_PRIORITY; boolean b = withinAnonymousClass.matcher(getDottedClassName()).find(); String bug = "SIC_INNER_SHOULD_BE_STATIC"; if (isAnonymousInnerClass) bug = "SIC_INNER_SHOULD_BE_STATIC_ANON"; else if (!easyChange) bug = "SIC_INNER_SHOULD_BE_STATIC_NEEDS_THIS"; bugReporter.reportBug(new BugInstance(this, bug, priority) .addClass(className)); } } } else { if (constantFields.contains(f)) { if (!f.isStatic()) bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this, "SS_SHOULD_BE_STATIC", NORMAL_PRIORITY), f)); } else if (fieldsOfSerializableOrNativeClassed.contains(f)) { // ignore it } else if (!writtenFields.contains(f) && f.isResolved()) bugReporter.reportBug(new BugInstance(this, "UUF_UNUSED_FIELD", NORMAL_PRIORITY) .addClass(className) .addField(f).lowerPriorityIfDeprecated()); else if (f.getName().toLowerCase().indexOf("guardian") < 0) { int priority = NORMAL_PRIORITY; if (f.isStatic()) priority++; if (finalFields.contains(f)) priority++; bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this, "URF_UNREAD_FIELD", priority),f)); } } } } /** * @param instance * @return */ private BugInstance addClassFieldAndAccess(BugInstance instance, XField f) { instance.addClass(f.getClassName()).addField(f); if (fieldAccess.containsKey(f)) instance.add(fieldAccess.get(f)); return instance; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -