use of org.sonar.java.se.ProgramState in project sonar-java by SonarSource.
the class MethodYieldTest method constraints_on_varargs.
@Test
public void constraints_on_varargs() throws Exception {
ActionParser<Tree> p = JavaParser.createParser();
CompilationUnitTree cut = (CompilationUnitTree) p.parse(new File("src/test/files/se/VarArgsYields.java"));
SemanticModel semanticModel = SemanticModel.createFor(cut, new SquidClassLoader(new ArrayList<>()));
SymbolicExecutionVisitor sev = new SymbolicExecutionVisitor(Lists.newArrayList(new SECheck[] {}), new BehaviorCache(new SquidClassLoader(new ArrayList<>())));
JavaFileScannerContext context = mock(JavaFileScannerContext.class);
when(context.getTree()).thenReturn(cut);
when(context.getSemanticModel()).thenReturn(semanticModel);
sev.scanFile(context);
MethodSymbol methodSymbol = ((MethodTree) ((ClassTree) cut.types().get(0)).members().get(0)).symbol();
MethodBehavior mb = getMethodBehavior(sev, "varArgMethod");
List<MethodYield> yields = mb.yields();
assertThat(yields).hasSize(5);
assertThat(mb.exceptionalPathYields()).hasSize(4);
MethodYield yield = mb.happyPathYields().findFirst().get();
// check that we have NOT_NULL constraint on the first argument
assertThat(yield.parametersConstraints.get(0).get(ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
// check that we have NOT_NULL constraint on the variadic argument
assertThat(yield.parametersConstraints.get(1).get(ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
List<IdentifierTree> usages = methodSymbol.usages();
assertThat(usages).hasSize(6);
List<List<Type>> arguments = usages.stream().map(MethodYieldTest::getMethodIncoationArgumentsTypes).collect(Collectors.toList());
ProgramState ps = ProgramState.EMPTY_STATE;
ProgramState psResult;
SymbolicValue svFirstArg = new SymbolicValue();
SymbolicValue svVarArg1 = new SymbolicValue();
SymbolicValue svVarArg2 = new SymbolicValue();
SymbolicValue svResult = new SymbolicValue();
// apply constraint NotNull to parameter
Collection<ProgramState> arrayOfA = yield.statesAfterInvocation(Lists.newArrayList(svFirstArg, svVarArg1), arguments.get(0), ps, () -> svResult).collect(Collectors.toList());
assertThat(arrayOfA).hasSize(1);
psResult = arrayOfA.iterator().next();
assertThat(psResult.getConstraint(svFirstArg, ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
assertThat(psResult.getConstraint(svVarArg1, ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
// apply constraint NotNull to parameter (B[] is a subtype of A[])
Collection<ProgramState> arrayOfB = yield.statesAfterInvocation(Lists.newArrayList(svFirstArg, svVarArg1), arguments.get(1), ps, () -> svResult).collect(Collectors.toList());
assertThat(arrayOfB).hasSize(1);
psResult = arrayOfB.iterator().next();
assertThat(psResult.getConstraint(svFirstArg, ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
assertThat(psResult.getConstraint(svVarArg1, ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
// no constraint, as 'a' is not an array
Collection<ProgramState> objectA = yield.statesAfterInvocation(Lists.newArrayList(svFirstArg, svVarArg1), arguments.get(2), ps, () -> svResult).collect(Collectors.toList());
assertThat(objectA).hasSize(1);
psResult = objectA.iterator().next();
assertThat(psResult.getConstraint(svFirstArg, ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
assertThat(psResult.getConstraint(svVarArg1, ObjectConstraint.class)).isNull();
// no constraint, as 'a' and 'b' can not receive the constraint of the array
Collection<ProgramState> objectsAandB = yield.statesAfterInvocation(Lists.newArrayList(svFirstArg, svVarArg1, svVarArg2), arguments.get(3), ps, () -> svResult).collect(Collectors.toList());
assertThat(objectsAandB).hasSize(1);
psResult = objectsAandB.iterator().next();
assertThat(psResult.getConstraint(svFirstArg, ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
assertThat(psResult.getConstraint(svVarArg1, ObjectConstraint.class)).isNull();
assertThat(psResult.getConstraint(svVarArg2, ObjectConstraint.class)).isNull();
// no param, we only learn something about the argument which is not variadic
Collection<ProgramState> noParam = yield.statesAfterInvocation(Lists.newArrayList(svFirstArg), arguments.get(4), ps, () -> svResult).collect(Collectors.toList());
assertThat(noParam).hasSize(1);
psResult = noParam.iterator().next();
assertThat(psResult.getConstraint(svFirstArg, ObjectConstraint.class)).isEqualTo(ObjectConstraint.NOT_NULL);
// null param, contradiction, no resulting program state
ps = ProgramState.EMPTY_STATE.addConstraint(svFirstArg, ObjectConstraint.NULL);
Collection<ProgramState> nullParam = yield.statesAfterInvocation(Lists.newArrayList(svFirstArg, svVarArg1), arguments.get(5), ps, () -> svResult).collect(Collectors.toList());
assertThat(nullParam).isEmpty();
}
use of org.sonar.java.se.ProgramState in project sonar-java by SonarSource.
the class MapComputeIfAbsentOrPresentCheck method checkPreStatement.
@Override
public ProgramState checkPreStatement(CheckerContext context, Tree syntaxNode) {
if (syntaxNode.is(Tree.Kind.METHOD_INVOCATION)) {
MethodInvocationTree mit = (MethodInvocationTree) syntaxNode;
if (MAP_PUT.matches(mit) && !isMethodInvocationThrowingCheckedException(mit.arguments().get(1))) {
ProgramState ps = context.getState();
SymbolicValue keySV = ps.peekValue(1);
SymbolicValue mapSV = ps.peekValue(2);
mapGetInvocations.get(mapSV).stream().filter(getOnSameMap -> getOnSameMap.withSameKey(keySV)).findAny().ifPresent(getOnSameMap -> {
ObjectConstraint constraint = ps.getConstraint(getOnSameMap.value, ObjectConstraint.class);
if (constraint != null && isInsideIfStatementWithNullCheckWithoutElse(mit)) {
checkIssues.add(new CheckIssue(context.getNode(), getOnSameMap.mit, mit, getOnSameMap.value, constraint));
}
});
}
}
return super.checkPreStatement(context, syntaxNode);
}
use of org.sonar.java.se.ProgramState in project sonar-java by SonarSource.
the class OptionalGetBeforeIsPresentCheck method setOptionalConstraint.
private static List<ProgramState> setOptionalConstraint(CheckerContext context, Tree syntaxNode) {
ProgramState programState = context.getState();
if (!syntaxNode.is(Tree.Kind.METHOD_INVOCATION)) {
return Collections.singletonList(programState);
}
MethodInvocationTree mit = (MethodInvocationTree) syntaxNode;
SymbolicValue peekValue = programState.peekValue();
Preconditions.checkNotNull(peekValue);
if (OPTIONAL_EMPTY.matches(mit)) {
return peekValue.setConstraint(programState, OptionalConstraint.NOT_PRESENT);
}
if (OPTIONAL_OF.matches(mit)) {
return peekValue.setConstraint(programState, OptionalConstraint.PRESENT);
}
if (OPTIONAL_OF_NULLABLE.matches(mit)) {
ProgramState psPriorMethodInvocation = context.getNode().programState;
SymbolicValue paramSV = psPriorMethodInvocation.peekValue(0);
ObjectConstraint paramConstraint = psPriorMethodInvocation.getConstraint(paramSV, ObjectConstraint.class);
if (paramConstraint != null) {
// Optional.ofNullable(null) returns an empty Optional
return peekValue.setConstraint(programState, paramConstraint == ObjectConstraint.NULL ? OptionalConstraint.NOT_PRESENT : OptionalConstraint.PRESENT);
}
}
return Collections.singletonList(programState);
}
use of org.sonar.java.se.ProgramState in project sonar-java by SonarSource.
the class RedundantAssignmentsCheck method handleAssignment.
private void handleAssignment(CheckerContext context, AssignmentExpressionTree assignmentExpressionTree) {
SymbolicValueSymbol assignedVariable = context.getState().peekValueSymbol();
Symbol assignedSymbol = assignedVariable.symbol();
if (assignedSymbol == null || // meaning that 'stream = stream.map(...);' would be detected as redundant assignment if not explicitly excluded
STREAM_TYPES.stream().anyMatch(assignedSymbol.type()::is)) {
return;
}
ExplodedGraph.Node node = context.getNode();
ProgramState previousState = node.programState;
SymbolicValue oldValue = previousState.getValue(assignedSymbol);
SymbolicValue newValue = assignedVariable.symbolicValue();
Symbol fromSymbol = previousState.peekValueSymbol().symbol();
assignmentsByMethod.peek().put(assignmentExpressionTree, new AssignmentDataHolder(assignedSymbol, oldValue, newValue, fromSymbol, node));
}
use of org.sonar.java.se.ProgramState in project sonar-java by SonarSource.
the class NullDereferenceCheck method checkConstraint.
private ProgramState checkConstraint(CheckerContext context, Tree syntaxNode, SymbolicValue currentVal) {
ProgramState programState = context.getState();
ObjectConstraint constraint = programState.getConstraint(currentVal, ObjectConstraint.class);
if (constraint != null && constraint.isNull()) {
NullDereferenceIssue issue = new NullDereferenceIssue(context.getNode(), currentVal, syntaxNode);
detectedIssues.peek().add(issue);
// we reported the issue and stopped the exploration, but we still need to create a yield for x-procedural calls
context.addExceptionalYield(currentVal, programState, JAVA_LANG_NPE, this);
return null;
}
constraint = programState.getConstraint(currentVal, ObjectConstraint.class);
if (constraint == null) {
// a NPE will be triggered if the current value would have been null
context.addExceptionalYield(currentVal, programState.addConstraint(currentVal, ObjectConstraint.NULL), JAVA_LANG_NPE, this);
// We dereferenced the target value for the member select, so we can assume it is not null when not already known
return programState.addConstraint(currentVal, ObjectConstraint.NOT_NULL);
}
return programState;
}
Aggregations