Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement some things #394

Merged
merged 16 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions autograder-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,23 @@
</exclusions>
</dependency>

<dependency>
<groupId>fr.inria.gforge.spoon</groupId>
<artifactId>spoon-javadoc</artifactId>
<version>${spoon.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<!-- exclude jdt, because spoon is not using the latest version -->
<exclusion>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
</exclusion>
</exclusions>
</dependency>


<!-- PMD -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ private static boolean isMathSqrt(CtInvocation<?> ctInvocation) {
&& SpoonUtil.isSignatureEqualTo(ctInvocation.getExecutable(), double.class, "sqrt", double.class);
}

private static boolean isPowSqrt(CtInvocation<?> ctInvocation) {
return isMathPow(ctInvocation)
&& ctInvocation.getArguments().size() == 2
&& SpoonUtil.resolveConstant(ctInvocation.getArguments().get(1)) instanceof CtLiteral<?> ctLiteral
&& ctLiteral.getValue() instanceof Double doubleValue
&& doubleValue == 0.5;
}

private static Optional<CtExpression<?>> getPow2(CtExpression<?> ctExpression) {
if (ctExpression instanceof CtBinaryOperator<?> ctBinaryOperator
&& ctBinaryOperator.getLeftHandOperand().equals(ctBinaryOperator.getRightHandOperand())
Expand All @@ -64,12 +72,12 @@ && isMathPow(ctInvocation)
return Optional.empty();
}

private void checkHypot(CtExpression<?> ctExpression) {
private boolean checkHypot(CtExpression<?> ctExpression) {
if (!(ctExpression instanceof CtInvocation<?> ctInvocation)
|| !isMathSqrt(ctInvocation)
|| (!isMathSqrt(ctInvocation) && !isPowSqrt(ctInvocation))
|| !(ctInvocation.getArguments().get(0) instanceof CtBinaryOperator<?> ctBinaryOperator)
|| ctBinaryOperator.getKind() != BinaryOperatorKind.PLUS) {
return;
return false;
}

Optional<CtExpression<?>> left = getPow2(ctBinaryOperator.getLeftHandOperand());
Expand All @@ -84,17 +92,19 @@ private void checkHypot(CtExpression<?> ctExpression) {
),
ProblemType.COMMON_REIMPLEMENTATION_HYPOT
);

return true;
}

return false;
}

private void checkSqrt(CtExpression<?> ctExpression) {
if (!(ctExpression instanceof CtInvocation<?> ctInvocation) || !isMathPow(ctInvocation)) {
return;
}

if (SpoonUtil.resolveCtExpression(ctInvocation.getArguments().get(1)) instanceof CtLiteral<?> ctLiteral
&& ctLiteral.getValue() instanceof Double doubleValue
&& doubleValue == 0.5) {
if (isPowSqrt(ctInvocation)) {
addLocalProblem(
ctExpression,
new LocalizedMessage(
Expand Down Expand Up @@ -155,6 +165,12 @@ private void checkMaxMin(CtIf ctIf) {
return;
}

// check that in `if (variable <op> max) { variable = assigned; }` the max is the same as the assigned value
if (!condition.getLeftHandOperand().equals(thenAssignment.getAssignment())
&& !condition.getRightHandOperand().equals(thenAssignment.getAssignment())) {
return;
}

// max looks like this:
// if (variable < max) {
// variable = max;
Expand Down Expand Up @@ -219,8 +235,10 @@ protected void enter(CtElement ctElement) {
if (ctElement instanceof CtExpression<?> ctExpression
&& !ctExpression.isImplicit()
&& ctExpression.getPosition().isValidPosition()) {
checkSqrt(ctExpression);
checkHypot(ctExpression);
// only check for sqrt if hypot is not applicable
if (!checkHypot(ctExpression)) {
checkSqrt(ctExpression);
}
}

super.enter(ctElement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,6 @@ public void process(CtExpression<String> ctExpression) {

@Override
public Optional<Integer> maximumProblems() {
return Optional.of(5);
return Optional.of(1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import de.firemage.autograder.core.check.ExecutableCheck;
import de.firemage.autograder.core.dynamic.DynamicAnalysis;
import de.firemage.autograder.core.integrated.IntegratedCheck;
import de.firemage.autograder.core.integrated.SpoonUtil;
import de.firemage.autograder.core.integrated.StaticAnalysis;
import spoon.processing.AbstractProcessor;
import spoon.reflect.code.CtExpression;
Expand All @@ -16,14 +17,16 @@
import java.util.Map;
import java.util.Optional;

@ExecutableCheck(reportedProblems = { ProblemType.USE_STRING_FORMATTED })
@ExecutableCheck(reportedProblems = {ProblemType.USE_STRING_FORMATTED})
public class UseStringFormatted extends IntegratedCheck {
private void checkCtInvocation(CtInvocation<?> ctInvocation) {
boolean hasInvokedStringFormat = ctInvocation.getTarget() instanceof CtTypeAccess<?> ctTypeAccess
// ensure the method is called on java.lang.String
&& ctInvocation.getFactory().Type().createReference(java.lang.String.class)
.equals(ctTypeAccess.getAccessedType())
&& ctInvocation.getExecutable().getSimpleName().equals("format");
// ensure the method is called on java.lang.String
&& SpoonUtil.isTypeEqualTo(ctTypeAccess.getAccessedType(), java.lang.String.class)
&& ctInvocation.getExecutable().getSimpleName().equals("format")
&& !ctInvocation.getArguments().isEmpty()
// ensure the first argument is a string (this ignores String.format(Locale, String, Object...))
&& SpoonUtil.isTypeEqualTo(ctInvocation.getArguments().get(0).getType(), java.lang.String.class);

if (!hasInvokedStringFormat) {
return;
Expand Down Expand Up @@ -59,6 +62,6 @@ public void process(CtInvocation<?> ctInvocation) {

@Override
public Optional<Integer> maximumProblems() {
return Optional.of(4);
return Optional.of(1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private void checkCtExecutable(CtExecutable<?> ctExecutable) {
CtJavaDoc ctJavaDoc = doc.get();

Set<String> documentedExceptions = ctJavaDoc.getTags().stream()
.filter(tag -> tag.getType() == CtJavaDocTag.TagType.THROWS && tag.getParam() != null)
.filter(tag -> (tag.getType() == CtJavaDocTag.TagType.THROWS || tag.getType() == CtJavaDocTag.TagType.EXCEPTION) && tag.getParam() != null)
.map(CtJavaDocTag::getParam)
.collect(Collectors.toSet());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import de.firemage.autograder.core.integrated.SpoonUtil;
import de.firemage.autograder.core.integrated.StaticAnalysis;
import spoon.reflect.code.CtComment;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtReturn;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtSwitchExpression;
import spoon.reflect.code.CtVariableRead;
import spoon.reflect.visitor.CtScanner;

Expand All @@ -29,6 +31,10 @@ private boolean isAllowedStatement(CtStatement ctStatement) {
return ctStatement instanceof CtComment;
}

private boolean isComplexExpression(CtExpression<?> ctExpression) {
return ctExpression instanceof CtSwitchExpression<?,?>;
}

private void checkVariableRead(CtStatement ctStatement, CtVariableRead<?> ctVariableRead) {
if (// the variable must be a local variable
!(ctVariableRead.getVariable().getDeclaration() instanceof CtLocalVariable<?> ctLocalVariable)
Expand All @@ -39,6 +45,11 @@ private void checkVariableRead(CtStatement ctStatement, CtVariableRead<?> ctVari
return;
}

if (ctLocalVariable.getDefaultExpression() != null
&& this.isComplexExpression(ctLocalVariable.getDefaultExpression())) {
return;
}

CtStatement previousStatement = SpoonUtil.getPreviousStatement(ctStatement).orElse(null);

while (!ctLocalVariable.equals(previousStatement) && this.isAllowedStatement(previousStatement)) {
Expand Down
Loading
Loading