use of edu.umd.cs.findbugs.ba.BasicBlock in project fb-contrib by mebigfatguy.
the class CyclomaticComplexity method visitMethod.
/**
* overrides the visitor to navigate the basic block list to count branches
*
* @param obj
* the method of the currently parsed method
*/
@Override
public void visitMethod(final Method obj) {
try {
if (obj.isSynthetic()) {
return;
}
Code code = obj.getCode();
if (code == null) {
return;
}
// bother
if (code.getCode().length < (2 * reportLimit)) {
return;
}
BitSet exceptionNodeTargets = new BitSet();
CFG cfg = classContext.getCFG(obj);
int branches = 0;
Iterator<BasicBlock> bbi = cfg.blockIterator();
while (bbi.hasNext()) {
BasicBlock bb = bbi.next();
Iterator<Edge> iei = cfg.outgoingEdgeIterator(bb);
int lastSwitchTargetBlockLabel = Integer.MIN_VALUE;
while (iei.hasNext()) {
Edge e = iei.next();
int edgeType = e.getType();
if ((edgeType != EdgeTypes.FALL_THROUGH_EDGE) && (edgeType != EdgeTypes.RETURN_EDGE) && (edgeType != EdgeTypes.UNKNOWN_EDGE)) {
if ((edgeType == EdgeTypes.UNHANDLED_EXCEPTION_EDGE) || (edgeType == EdgeTypes.HANDLED_EXCEPTION_EDGE)) {
int nodeTarget = e.getTarget().getLabel();
if (!exceptionNodeTargets.get(nodeTarget)) {
exceptionNodeTargets.set(nodeTarget);
branches++;
}
} else if ((edgeType == EdgeTypes.SWITCH_EDGE) || (edgeType == EdgeTypes.SWITCH_DEFAULT_EDGE)) {
int nodeTarget = e.getTarget().getLabel();
if (nodeTarget != lastSwitchTargetBlockLabel) {
branches++;
}
lastSwitchTargetBlockLabel = nodeTarget;
} else {
branches++;
}
}
}
}
if (branches > reportLimit) {
int priority = (branches > (reportLimit * 2) ? HIGH_PRIORITY : NORMAL_PRIORITY);
BugInstance bug = new BugInstance(this, BugType.CC_CYCLOMATIC_COMPLEXITY.name(), priority).addClass(this).addMethod(this).addSourceLine(classContext, this, 0).addInt(branches);
bugReporter.reportBug(bug);
}
} catch (CFGBuilderException cbe) {
bugReporter.logError("Failure examining basic blocks for method " + classContext.getJavaClass().getClassName() + '.' + obj.getName() + " in Cyclomatic Complexity detector", cbe);
}
}
use of edu.umd.cs.findbugs.ba.BasicBlock in project fb-contrib by mebigfatguy.
the class FieldCouldBeLocal method visitMethod.
/**
* overrides the visitor to navigate basic blocks looking for all first usages of fields, removing those that are read from first.
*
* @param obj
* the context object of the currently parsed method
*/
@Override
public void visitMethod(Method obj) {
if (localizableFields.isEmpty()) {
return;
}
try {
cfg = clsContext.getCFG(obj);
cpg = cfg.getMethodGen().getConstantPool();
BasicBlock bb = cfg.getEntry();
Set<String> uncheckedFields = new HashSet<>(localizableFields.keySet());
visitedBlocks.clear();
checkBlock(bb, uncheckedFields);
} catch (CFGBuilderException cbe) {
localizableFields.clear();
} finally {
cfg = null;
cpg = null;
}
}
use of edu.umd.cs.findbugs.ba.BasicBlock in project fb-contrib by mebigfatguy.
the class FieldCouldBeLocal method checkBlock.
/**
* looks in this basic block for the first access to the fields in uncheckedFields. Once found the item is removed from uncheckedFields, and removed from
* localizableFields if the access is a GETFIELD. If any unchecked fields remain, this method is recursively called on all outgoing edges of this basic
* block.
*
* @param startBB
* this basic block
* @param uncheckedFields
* the list of fields to look for
*/
private void checkBlock(BasicBlock startBB, Set<String> uncheckedFields) {
Deque<BlockState> toBeProcessed = new ArrayDeque<>();
toBeProcessed.addLast(new BlockState(startBB, uncheckedFields));
visitedBlocks.set(startBB.getLabel());
while (!toBeProcessed.isEmpty()) {
if (localizableFields.isEmpty()) {
return;
}
BlockState bState = toBeProcessed.removeFirst();
BasicBlock bb = bState.getBasicBlock();
InstructionIterator ii = bb.instructionIterator();
while ((bState.getUncheckedFieldSize() > 0) && ii.hasNext()) {
InstructionHandle ih = ii.next();
Instruction ins = ih.getInstruction();
if (ins instanceof FieldInstruction) {
FieldInstruction fi = (FieldInstruction) ins;
if (fi.getReferenceType(cpg).getSignature().equals(clsSig)) {
String fieldName = fi.getFieldName(cpg);
FieldInfo finfo = localizableFields.get(fieldName);
if ((finfo != null) && localizableFields.get(fieldName).hasAnnotation()) {
localizableFields.remove(fieldName);
} else {
boolean justRemoved = bState.removeUncheckedField(fieldName);
if (ins instanceof GETFIELD) {
if (justRemoved) {
localizableFields.remove(fieldName);
if (localizableFields.isEmpty()) {
return;
}
}
} else if (finfo != null) {
finfo.setSrcLineAnnotation(SourceLineAnnotation.fromVisitedInstruction(clsContext, this, ih.getPosition()));
}
}
}
} else if (ins instanceof INVOKESPECIAL) {
INVOKESPECIAL is = (INVOKESPECIAL) ins;
ReferenceType rt = is.getReferenceType(cpg);
if (Values.CONSTRUCTOR.equals(is.getMethodName(cpg))) {
if ((rt instanceof ObjectType) && ((ObjectType) rt).getClassName().startsWith(clsContext.getJavaClass().getClassName() + Values.INNER_CLASS_SEPARATOR)) {
localizableFields.clear();
}
} else {
localizableFields.clear();
}
} else if (ins instanceof INVOKEVIRTUAL) {
INVOKEVIRTUAL is = (INVOKEVIRTUAL) ins;
ReferenceType rt = is.getReferenceType(cpg);
if ((rt instanceof ObjectType) && ((ObjectType) rt).getClassName().equals(clsName)) {
String methodDesc = is.getName(cpg) + is.getSignature(cpg);
Set<String> fields = methodFieldModifiers.get(methodDesc);
if (fields != null) {
localizableFields.keySet().removeAll(fields);
}
}
}
}
if (bState.getUncheckedFieldSize() > 0) {
Iterator<Edge> oei = cfg.outgoingEdgeIterator(bb);
while (oei.hasNext()) {
Edge e = oei.next();
BasicBlock cb = e.getTarget();
int label = cb.getLabel();
if (!visitedBlocks.get(label)) {
toBeProcessed.addLast(new BlockState(cb, bState));
visitedBlocks.set(label);
}
}
}
}
}
Aggregations