for (XField f : data.assumedNonNull.keySet()) {
System.out.println(" " + f);
}
}
Set<XField> declaredFields = new HashSet<XField>();
AnalysisContext currentAnalysisContext = AnalysisContext.currentAnalysisContext();
XFactory xFactory = AnalysisContext.currentXFactory();
for (XField f : AnalysisContext.currentXFactory().allFields()) {
ClassDescriptor classDescriptor = f.getClassDescriptor();
if (currentAnalysisContext.isApplicationClass(classDescriptor) && !currentAnalysisContext.isTooBig(classDescriptor)
&& !xFactory.isReflectiveClass(classDescriptor)) {
declaredFields.add(f);
}
}
// Don't report anything about ejb3Fields
HashSet<XField> unknownAnotationAndUnwritten = new HashSet<XField>(data.unknownAnnotation.keySet());
unknownAnotationAndUnwritten.removeAll(data.writtenFields);
declaredFields.removeAll(unknownAnotationAndUnwritten);
declaredFields.removeAll(data.containerFields);
declaredFields.removeAll(data.reflectiveFields);
for (Iterator<XField> i = declaredFields.iterator(); i.hasNext();) {
XField f = i.next();
if (f.isSynthetic() && !f.getName().startsWith("this$") || f.getName().startsWith("_")) {
i.remove();
}
}
TreeSet<XField> notInitializedInConstructors = new TreeSet<XField>(declaredFields);
notInitializedInConstructors.retainAll(data.readFields);
notInitializedInConstructors.retainAll(data.writtenNonNullFields);
notInitializedInConstructors.retainAll(data.assumedNonNull.keySet());
notInitializedInConstructors.removeAll(data.writtenInConstructorFields);
notInitializedInConstructors.removeAll(data.writtenInInitializationFields);
for (Iterator<XField> i = notInitializedInConstructors.iterator(); i.hasNext();) {
if (i.next().isStatic()) {
i.remove();
}
}
TreeSet<XField> readOnlyFields = new TreeSet<XField>(declaredFields);
readOnlyFields.removeAll(data.writtenFields);
readOnlyFields.retainAll(data.readFields);
TreeSet<XField> nullOnlyFields = new TreeSet<XField>(declaredFields);
nullOnlyFields.removeAll(data.writtenNonNullFields);
nullOnlyFields.retainAll(data.readFields);
Set<XField> writeOnlyFields = declaredFields;
writeOnlyFields.removeAll(data.readFields);
Map<String, Integer> count = new HashMap<String, Integer>();
Bag<String> nullOnlyFieldNames = new Bag<String>();
Bag<ClassDescriptor> classContainingNullOnlyFields = new Bag<ClassDescriptor>();
for (XField f : nullOnlyFields) {
nullOnlyFieldNames.add(f.getName());
classContainingNullOnlyFields.add(f.getClassDescriptor());
int increment = 3;
Collection<ProgramPoint> assumedNonNullAt = data.assumedNonNull.get(f);
if (assumedNonNullAt != null) {
increment += assumedNonNullAt.size();
}
for (String s : data.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 : data.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);
} else if (nullOnlyFieldNames.getCount(f.getName()) > 8) {
assumeReflective.add(f);
} else if (classContainingNullOnlyFields.getCount(f.getClassDescriptor()) > 4) {
assumeReflective.add(f);
} else if (classContainingNullOnlyFields.getCount(f.getClassDescriptor()) > 2 && f.getName().length() == 1) {
assumeReflective.add(f);
}
}
readOnlyFields.removeAll(assumeReflective);
nullOnlyFields.removeAll(assumeReflective);
notInitializedInConstructors.removeAll(assumeReflective);
Bag<String> notInitializedUses = new Bag<String>();
for (XField f : notInitializedInConstructors) {
String className = f.getClassName();
Set<ProgramPoint> assumedNonnullAt = data.assumedNonNull.get(f);
notInitializedUses.add(className, assumedNonnullAt.size());
}
for (XField f : notInitializedInConstructors) {
String className = f.getClassName();
if (notInitializedUses.getCount(className) >= 8) {
continue;
}
String fieldSignature = f.getSignature();
if (f.isResolved() && !data.fieldsOfNativeClasses.contains(f)
&& (fieldSignature.charAt(0) == 'L' || fieldSignature.charAt(0) == '[')) {
int priority = LOW_PRIORITY;
Set<ProgramPoint> assumedNonnullAt = data.assumedNonNull.get(f);
if (assumedNonnullAt.size() < 4) {
for (ProgramPoint p : assumedNonnullAt) {
BugInstance bug = new BugInstance(this, "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", priority)
.addClass(className).addField(f).addMethod(p.getMethodAnnotation());
bugAccumulator.accumulateBug(bug, p.getSourceLineAnnotation());
}
}
}
}
for (XField f : readOnlyFields) {
// String fieldName = f.getName();
// String className = f.getClassName();
String fieldSignature = f.getSignature();
if (f.isResolved() && !data.fieldsOfNativeClasses.contains(f)) {
int priority = NORMAL_PRIORITY;
if (!(fieldSignature.charAt(0) == 'L' || fieldSignature.charAt(0) == '[')) {
priority++;
}
if (maxCount.containsKey(f)) {
priority++;
}
String pattern = "UWF_UNWRITTEN_FIELD";
if (f.isProtected() || f.isPublic()) {
pattern = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD";
}
bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this, pattern, 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(" : " + data.assumedNonNull.containsKey(f));
System.out.println(" : " + data.fieldsOfSerializableOrNativeClassed.contains(f));
System.out.println(" : " + fieldNamesSet.contains(f.getName()));
System.out.println(" : " + data.abstractClasses.contains(f.getClassName()));
System.out.println(" : " + data.hasNonAbstractSubClass.contains(f.getClassName()));
System.out.println(" : " + f.isResolved());
}
if (!f.isResolved()) {
continue;
}
if (data.fieldsOfNativeClasses.contains(f)) {
continue;
}
if (DEBUG) {
System.out.println("Ready to report");
}
int priority = NORMAL_PRIORITY;
if (maxCount.containsKey(f)) {
priority++;
}
if (data.abstractClasses.contains(f.getClassName())) {
priority++;
if (!data.hasNonAbstractSubClass.contains(f.getClassName())) {
priority++;
}
}
// if (fieldNamesSet.contains(f.getName())) priority++;
if (data.assumedNonNull.containsKey(f)) {
int npPriority = priority;
Set<ProgramPoint> assumedNonNullAt = data.assumedNonNull.get(f);
if (assumedNonNullAt.size() > 14) {
npPriority += 2;
} else if (assumedNonNullAt.size() > 6) {
npPriority++;
} else {
priority--;
}
String pattern = (f.isPublic() || f.isProtected()) ? "NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD"
: "NP_UNWRITTEN_FIELD";
for (ProgramPoint p : assumedNonNullAt) {
bugAccumulator.accumulateBug(
new BugInstance(this, pattern, npPriority).addClassAndMethod(p.method).addField(f),
p.getSourceLineAnnotation());
}
} else {
if (f.isStatic()) {
priority++;
}
if (f.isFinal()) {
priority++;
}
if (data.fieldsOfSerializableOrNativeClassed.contains(f)) {
priority++;
}
}
if (!readOnlyFields.contains(f)) {
bugReporter.reportBug(addClassFieldAndAccess(new BugInstance(this, "UWF_NULL_FIELD", priority), f)
.lowerPriorityIfDeprecated());
}
}
writeOnlyFields: 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" + data.constantFields.contains(f)
+ "\t" + f.isStatic());
}
if (!f.isResolved()) {
continue;
}
if (dontComplainAbout.matcher(fieldName).find()) {
continue;
}
if (lastDollar >= 0 && (fieldName.startsWith("this$") || fieldName.startsWith("this+"))) {
String outerClassName = className.substring(0, lastDollar);
try {
XClass thisClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, f.getClassDescriptor());
if (isAnonymousInnerClass) {
for (XField f2 : thisClass.getXFields()) {
if (f2 != f && f2.isPrivate() && f2.isSynthetic() && !f2.getName().startsWith("this$")
&& f2.getName().contains("$")) {
continue writeOnlyFields;
}
}
}
JavaClass outerClass = Repository.lookupClass(outerClassName);
if (classHasParameter(outerClass)) {
continue;
}
ClassDescriptor cDesc = DescriptorFactory.createClassDescriptorFromDottedClassName(outerClassName);
XClass outerXClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, cDesc);
AnalysisContext analysisContext = AnalysisContext.currentAnalysisContext();
Subtypes2 subtypes2 = analysisContext.getSubtypes2();
for (XField of : outerXClass.getXFields()) {
if (!of.isStatic()) {
String sourceSignature = of.getSourceSignature();
if (sourceSignature != null && of.getSignature().equals("Ljava/lang/ThreadLocal;")) {