use of com.mebigfatguy.fbcontrib.collect.MethodInfo in project fb-contrib by mebigfatguy.
the class PossiblyRedundantMethodCalls method sawOpcode.
/**
* implements the visitor to look for repetitive calls to the same method on the same object using the same constant parameters. These methods must return a
* value.
*
* @param seen
* the opcode of the currently parsed instruction
*/
@Override
public void sawOpcode(int seen) {
String userValue = null;
try {
stack.precomputation(this);
int pc = getPC();
if (branchTargets.get(pc)) {
localMethodCalls.clear();
fieldMethodCalls.clear();
branchTargets.clear(pc);
}
if (((seen >= Const.IFEQ) && (seen <= Const.GOTO)) || ((seen >= Const.IFNULL) && (seen <= Const.GOTO_W))) {
branchTargets.set(getBranchTarget());
} else if ((seen == Const.TABLESWITCH) || (seen == Const.LOOKUPSWITCH)) {
int[] offsets = getSwitchOffsets();
for (int offset : offsets) {
branchTargets.set(offset + pc);
}
branchTargets.set(getDefaultSwitchOffset() + pc);
} else if (OpcodeUtils.isAStore(seen)) {
localMethodCalls.remove(Integer.valueOf(RegisterUtils.getAStoreReg(this, seen)));
} else if (seen == Const.PUTFIELD) {
String fieldSource = "";
if (stack.getStackDepth() > 0) {
OpcodeStack.Item item = stack.getStackItem(0);
fieldSource = (String) item.getUserValue();
if (fieldSource == null) {
fieldSource = "";
}
}
fieldMethodCalls.remove(new FieldInfo(fieldSource, getNameConstantOperand()));
} else if (seen == Const.GETFIELD) {
if (stack.getStackDepth() > 0) {
OpcodeStack.Item item = stack.getStackItem(0);
userValue = (String) item.getUserValue();
if (userValue == null) {
int reg = item.getRegisterNumber();
if (reg >= 0) {
userValue = String.valueOf(reg);
} else {
XField xf = item.getXField();
if (xf != null) {
userValue = xf.getName();
}
}
}
}
} else if ((seen == Const.INVOKEVIRTUAL) || (seen == Const.INVOKEINTERFACE) || (seen == Const.INVOKESTATIC)) {
String className = getClassConstantOperand();
String methodName = getNameConstantOperand();
String signature = getSigConstantOperand();
int parmCount = SignatureUtils.getNumParameters(signature);
int reg = -1;
XField field = null;
MethodCall mc = null;
String fieldSource = null;
if (seen == Const.INVOKESTATIC) {
XMethod xm = XFactory.createXMethod(getDottedClassConstantOperand(), methodName, signature, true);
String genericSignature = xm.getSourceSignature();
if ((genericSignature != null) && genericSignature.endsWith(">;")) {
return;
}
} else if (stack.getStackDepth() > parmCount) {
OpcodeStack.Item obj = stack.getStackItem(parmCount);
reg = obj.getRegisterNumber();
field = obj.getXField();
if (reg >= 0) {
mc = localMethodCalls.get(Integer.valueOf(reg));
MethodInfo mi = Statistics.getStatistics().getMethodStatistics(className, getNameConstantOperand(), signature);
if ((mi != null) && mi.getModifiesState()) {
clearFieldMethods(String.valueOf(reg));
return;
}
} else if (field != null) {
fieldSource = (String) obj.getUserValue();
if (fieldSource == null) {
fieldSource = "";
}
mc = fieldMethodCalls.get(new FieldInfo(fieldSource, field.getName()));
MethodInfo mi = Statistics.getStatistics().getMethodStatistics(className, getNameConstantOperand(), signature);
if ((mi != null) && mi.getModifiesState()) {
clearFieldMethods(fieldSource);
return;
}
}
}
int neededStackSize = parmCount + ((seen == Const.INVOKESTATIC) ? 0 : 1);
if (stack.getStackDepth() >= neededStackSize) {
Object[] parmConstants = new Object[parmCount];
for (int i = 0; i < parmCount; i++) {
OpcodeStack.Item parm = stack.getStackItem(i);
parmConstants[i] = parm.getConstant();
if (parm.getSignature().startsWith(Values.SIG_ARRAY_PREFIX)) {
if (!Values.ZERO.equals(parm.getConstant())) {
return;
}
XField f = parm.getXField();
if (f != null) {
// Two different fields holding a 0 length array should be considered different
parmConstants[i] = f.getName() + ':' + parmConstants[i];
}
}
if (parmConstants[i] == null) {
return;
}
}
if (seen == Const.INVOKESTATIC) {
mc = staticMethodCalls.get(className);
} else if ((reg < 0) && (field == null)) {
return;
}
if (mc != null) {
if (!signature.endsWith(Values.SIG_VOID) && methodName.equals(mc.getName()) && signature.equals(mc.getSignature()) && !isRiskyName(className, methodName) && !commonMethods.contains(new FQMethod(getClassConstantOperand(), methodName, signature))) {
Object[] parms = mc.getParms();
if (Arrays.equals(parms, parmConstants)) {
int ln = getLineNumber(pc);
if ((ln != mc.getLineNumber()) || (Math.abs(pc - mc.getPC()) < 10)) {
Statistics statistics = Statistics.getStatistics();
MethodInfo mi = statistics.getMethodStatistics(getClassConstantOperand(), methodName, signature);
bugReporter.reportBug(new BugInstance(this, BugType.PRMC_POSSIBLY_REDUNDANT_METHOD_CALLS.name(), getBugPriority(methodName, mi)).addClass(this).addMethod(this).addSourceLine(this).addString(methodName + signature));
}
}
}
if (seen == Const.INVOKESTATIC) {
staticMethodCalls.remove(className);
} else {
if (reg >= 0) {
localMethodCalls.remove(Integer.valueOf(reg));
} else if (fieldSource != null) {
fieldMethodCalls.remove(new FieldInfo(fieldSource, field.getName()));
}
}
} else {
int ln = getLineNumber(pc);
if (seen == Const.INVOKESTATIC) {
staticMethodCalls.put(className, new MethodCall(methodName, signature, parmConstants, pc, ln));
} else {
if (reg >= 0) {
localMethodCalls.put(Integer.valueOf(reg), new MethodCall(methodName, signature, parmConstants, pc, ln));
} else if (field != null) {
OpcodeStack.Item obj = stack.getStackItem(parmCount);
fieldSource = (String) obj.getUserValue();
if (fieldSource == null) {
fieldSource = "";
}
fieldMethodCalls.put(new FieldInfo(fieldSource, field.getName()), new MethodCall(methodName, signature, parmConstants, pc, ln));
}
}
}
}
} else if (OpcodeUtils.isReturn(seen)) {
localMethodCalls.clear();
fieldMethodCalls.clear();
branchTargets.clear(pc);
}
} finally {
stack.sawOpcode(this, seen);
if ((userValue != null) && (stack.getStackDepth() > 0)) {
OpcodeStack.Item item = stack.getStackItem(0);
item.setUserValue(userValue);
}
}
}
use of com.mebigfatguy.fbcontrib.collect.MethodInfo in project fb-contrib by mebigfatguy.
the class ModifyingUnmodifiableCollection method sawOpcode.
/**
* overrides the visitor to find method mutations on collections that have previously been determined to have been created as immutable collections
*
* @param seen
* the currently parsed opcode
*/
@Override
public void sawOpcode(int seen) {
ImmutabilityType imType = null;
try {
stack.precomputation(this);
switch(seen) {
case INVOKESTATIC:
case INVOKEINTERFACE:
case INVOKESPECIAL:
case INVOKEVIRTUAL:
{
String className = getClassConstantOperand();
String methodName = getNameConstantOperand();
String signature = getSigConstantOperand();
MethodInfo mi = Statistics.getStatistics().getMethodStatistics(className, methodName, signature);
imType = mi.getImmutabilityType();
if (seen == INVOKEINTERFACE) {
Integer collectionOffset = MODIFYING_METHODS.get(new QMethod(methodName, signature));
if ((collectionOffset != null) && CollectionUtils.isListSetMap(className) && (stack.getStackDepth() > collectionOffset.intValue())) {
OpcodeStack.Item item = stack.getStackItem(collectionOffset.intValue());
ImmutabilityType type = (ImmutabilityType) item.getUserValue();
if ((type == ImmutabilityType.IMMUTABLE) || ((type == ImmutabilityType.POSSIBLY_IMMUTABLE) && (reportedType != ImmutabilityType.POSSIBLY_IMMUTABLE))) {
bugReporter.reportBug(new BugInstance(this, BugType.MUC_MODIFYING_UNMODIFIABLE_COLLECTION.name(), (type == ImmutabilityType.IMMUTABLE) ? HIGH_PRIORITY : NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
if (type == ImmutabilityType.IMMUTABLE) {
throw new StopOpcodeParsingException();
}
reportedType = type;
}
}
}
}
break;
default:
break;
}
} catch (ClassNotFoundException cnfe) {
bugReporter.reportMissingClass(cnfe);
} finally {
stack.sawOpcode(this, seen);
if ((imType != null) && (stack.getStackDepth() > 0)) {
OpcodeStack.Item item = stack.getStackItem(0);
item.setUserValue(imType);
}
}
}
use of com.mebigfatguy.fbcontrib.collect.MethodInfo in project fb-contrib by mebigfatguy.
the class AnnotationIssues method visitCode.
@Override
public void visitCode(Code obj) {
Method method = getMethod();
String sig = method.getSignature();
String returnType = sig.substring(sig.indexOf(')') + 1);
char returnTypeChar = returnType.charAt(0);
if ((returnTypeChar != 'L') && (returnTypeChar != '[')) {
return;
}
if (method.isSynthetic() && !isCollecting()) {
return;
}
if (Values.SIG_JAVA_LANG_VOID.equals(returnType)) {
return;
}
if (methodHasNullableAnnotation(method)) {
if (isCollecting()) {
MethodInfo methodInfo = Statistics.getStatistics().getMethodStatistics(getClassName(), method.getName(), method.getSignature());
methodInfo.setCanReturnNull(true);
}
return;
}
MethodInfo methodInfo = Statistics.getStatistics().getMethodStatistics(getClassName(), method.getName(), method.getSignature());
if (!isCollecting() && methodInfo.getCanReturnNull()) {
bugReporter.reportBug(new BugInstance(this, BugType.AI_ANNOTATION_ISSUES_NEEDS_NULLABLE.name(), LOW_PRIORITY).addClass(this).addMethod(this));
} else {
methodIsNullable = false;
stack.resetForMethodEntry(this);
assumedNullTill.clear();
assumedNonNullTill.clear();
noAssumptionsPossible.clear();
super.visitCode(obj);
if (methodIsNullable) {
if (isCollecting()) {
methodInfo.setCanReturnNull(true);
} else {
bugReporter.reportBug(new BugInstance(this, BugType.AI_ANNOTATION_ISSUES_NEEDS_NULLABLE.name(), LOW_PRIORITY).addClass(this).addMethod(this));
}
}
}
}
use of com.mebigfatguy.fbcontrib.collect.MethodInfo in project fb-contrib by mebigfatguy.
the class BloatedAssignmentScope method sawInstanceCall.
/**
* processes a instance method call to see if that call is modifies state or is otherwise'risky', if so mark the variable(s) associated with the caller as
* not reportable
*
* @param pc
* the current program counter
*
* @return a user object to place on the return value's OpcodeStack item
*/
@Nullable
private UserObject sawInstanceCall(int pc) {
String signature = getSigConstantOperand();
String name = getNameConstantOperand();
// this is kind of a wart. there should be a more seamless way to check this
if ("wasNull".equals(getNameConstantOperand()) && SignatureBuilder.SIG_VOID_TO_BOOLEAN.equals(signature)) {
dontReport = true;
}
if (signature.endsWith(Values.SIG_VOID)) {
return null;
}
MethodInfo mi = Statistics.getStatistics().getMethodStatistics(getClassConstantOperand(), name, signature);
UserObject uo = new UserObject(getCallingObject(), mi.getModifiesState() || isRiskyMethodCall());
if (uo.caller != null) {
ScopeBlock sb = findScopeBlock(rootScopeBlock, pc);
if (sb != null) {
sb.removeByAssoc(uo.caller);
}
}
return uo;
}
use of com.mebigfatguy.fbcontrib.collect.MethodInfo in project fb-contrib by mebigfatguy.
the class BloatedSynchronizedBlock method sawOpcode.
/**
* implement the visitor to find bloated sync blocks. This implementation only checks the outer most block
*
* @param seen
* the opcode of the currently parsed instruction
*/
@Override
public void sawOpcode(int seen) {
try {
stack.precomputation(this);
if (unsafeCallOccurred && OpcodeUtils.isAStore(seen)) {
int storeReg = RegisterUtils.getAStoreReg(this, seen);
if (storeReg >= 0) {
unsafeAliases.set(storeReg);
}
}
if ((seen == Const.INVOKEVIRTUAL) || (seen == Const.INVOKESPECIAL) || (seen == Const.INVOKEINTERFACE) || (seen == Const.INVOKEDYNAMIC)) {
String methodSig = getSigConstantOperand();
MethodInfo mi = Statistics.getStatistics().getMethodStatistics(getClassConstantOperand(), getNameConstantOperand(), methodSig);
if (mi.getModifiesState()) {
unsafeCallOccurred = true;
} else {
if (!Values.SIG_VOID.equals(SignatureUtils.getReturnSignature(methodSig))) {
int parmCount = SignatureUtils.getNumParameters(methodSig);
if (stack.getStackDepth() > parmCount) {
OpcodeStack.Item itm = stack.getStackItem(parmCount);
unsafeCallOccurred = unsafeAliases.get(itm.getRegisterNumber());
} else {
unsafeCallOccurred = false;
}
} else {
unsafeCallOccurred = false;
}
}
} else if (seen == Const.INVOKESTATIC) {
unsafeCallOccurred = getDottedClassConstantOperand().equals(this.getClassContext().getJavaClass().getClassName());
} else if (((seen >= Const.IFEQ) && (seen <= Const.GOTO)) || (seen == Const.GOTO_W)) {
Integer from = Integer.valueOf(getPC());
Integer to = Integer.valueOf(getBranchTarget());
branchInfo.put(from, to);
unsafeCallOccurred = false;
} else {
unsafeCallOccurred = false;
}
if (seen == Const.MONITORENTER) {
if (syncPC < 0) {
syncPC = getPC();
if (stack.getStackDepth() > 0) {
OpcodeStack.Item itm = stack.getStackItem(0);
int monitorReg = itm.getRegisterNumber();
if (monitorReg >= 0) {
unsafeAliases.set(monitorReg);
}
}
}
} else if (seen == Const.MONITOREXIT) {
syncPC = -1;
} else if (syncPC >= 0) {
processSyncBlockInstruction(seen);
}
} finally {
stack.sawOpcode(this, seen);
}
}
Aggregations