1 19 20 package edu.umd.cs.findbugs.detect; 21 22 23 import edu.umd.cs.findbugs.*; 24 25 import java.util.*; 26 import org.apache.bcel.classfile.Code; 27 28 public class InitializationChain extends BytecodeScanningDetector { 29 Set<String > requires = new TreeSet<String >(); 30 Map<String , Set<String >> classRequires = new TreeMap<String , Set<String >>(); 31 private BugReporter bugReporter; 32 private boolean instanceCreated; 33 private int instanceCreatedPC; 34 private boolean instanceCreatedWarningGiven; 35 36 private static final boolean DEBUG = SystemProperties.getBoolean("ic.debug"); 37 private static final boolean REPORT_CREATE_INSTANCE_BEFORE_FIELDS_ASSIGNED = 38 SystemProperties.getBoolean("ic.createInstance"); 39 40 public InitializationChain(BugReporter bugReporter) { 41 this.bugReporter = bugReporter; 42 } 43 44 @Override 45 public void visit(Code obj) { 46 instanceCreated = false; 47 instanceCreatedWarningGiven = false; 48 if (!getMethodName().equals("<clinit>")) return; 49 super.visit(obj); 50 requires.remove(getDottedClassName()); 51 if (getDottedClassName().equals("java.lang.System")) { 52 requires.add("java.io.FileInputStream"); 53 requires.add("java.io.FileOutputStream"); 54 requires.add("java.io.BufferedInputStream"); 55 requires.add("java.io.BufferedOutputStream"); 56 requires.add("java.io.PrintStream"); 57 } 58 if (!requires.isEmpty()) { 59 classRequires.put(getDottedClassName(), requires); 60 requires = new TreeSet<String >(); 61 } 62 } 63 64 65 @Override 66 public void sawOpcode(int seen) { 67 68 69 if (seen == PUTSTATIC && getClassConstantOperand().equals(getClassName())) { 70 if (REPORT_CREATE_INSTANCE_BEFORE_FIELDS_ASSIGNED && 74 instanceCreated && !instanceCreatedWarningGiven) { 75 String okSig = "L" + getClassName() + ";"; 76 if (!okSig.equals(getSigConstantOperand())) { 77 bugReporter.reportBug(new BugInstance(this, "SI_INSTANCE_BEFORE_FINALS_ASSIGNED", NORMAL_PRIORITY) 78 .addClassAndMethod(this) 79 .addSourceLine(this, instanceCreatedPC)); 80 instanceCreatedWarningGiven = true; 81 } 82 } 83 } else if (seen == NEW && getClassConstantOperand().equals(getClassName())) { 84 instanceCreated = true; 85 instanceCreatedPC = getPC(); 86 } else if (seen == PUTSTATIC || seen == GETSTATIC || seen == INVOKESTATIC 87 || seen == NEW) 88 if (getPC() + 6 < codeBytes.length) 89 requires.add(getDottedClassConstantOperand()); 90 } 91 92 public void compute() { 93 Set<String > allClasses = classRequires.keySet(); 94 Set<String > emptyClasses = new TreeSet<String >(); 95 for (String c : allClasses) { 96 Set<String > needs = classRequires.get(c); 97 needs.retainAll(allClasses); 98 Set<String > extra = new TreeSet<String >(); 99 for (String need : needs) 100 extra.addAll(classRequires.get(need)); 101 needs.addAll(extra); 102 needs.retainAll(allClasses); 103 classRequires.put(c, needs); 104 if (needs.isEmpty()) emptyClasses.add(c); 105 } 106 for (String c : emptyClasses) { 107 classRequires.remove(c); 108 } 109 } 110 111 @Override 112 public void report() { 113 114 if (DEBUG) System.out.println("Finishing computation"); 115 compute(); 116 compute(); 117 compute(); 118 compute(); 119 compute(); 120 compute(); 121 compute(); 122 compute(); 123 Set<String > allClasses = classRequires.keySet(); 124 125 for (String c : allClasses) { 126 if (DEBUG) System.out.println("Class " + c + " requires:"); 127 for (String needs : (classRequires.get(c))) { 128 if (DEBUG) System.out.println(" " + needs); 129 Set<String > s = classRequires.get(needs); 130 if (s != null && s.contains(c) && c.compareTo(needs) < 0) 131 bugReporter.reportBug(new BugInstance(this, "IC_INIT_CIRCULARITY", NORMAL_PRIORITY) 132 .addClass(c) 133 .addClass(needs)); 134 } 135 } 136 } 137 138 } 139 | Popular Tags |