diff --git a/autograder-core/src/main/java/de/firemage/autograder/core/check/api/CommonReimplementation.java b/autograder-core/src/main/java/de/firemage/autograder/core/check/api/CommonReimplementation.java index 6387a588..a7acee16 100644 --- a/autograder-core/src/main/java/de/firemage/autograder/core/check/api/CommonReimplementation.java +++ b/autograder-core/src/main/java/de/firemage/autograder/core/check/api/CommonReimplementation.java @@ -25,6 +25,7 @@ import spoon.reflect.code.CtInvocation; import spoon.reflect.code.CtLiteral; import spoon.reflect.code.CtNewArray; +import spoon.reflect.code.CtNewClass; import spoon.reflect.code.CtOperatorAssignment; import spoon.reflect.code.CtStatement; import spoon.reflect.code.CtVariableAccess; @@ -161,6 +162,11 @@ private void checkArraysFill(CtFor ctFor) { return; } + // ignore new array or new class assignments + if (ctAssignment.getAssignment() instanceof CtNewClass || ctAssignment.getAssignment() instanceof CtNewArray) { + return; + } + CtExpression rhs = ctAssignment.getAssignment(); if (!SpoonUtil.isImmutable(rhs.getType())) { return; diff --git a/autograder-core/src/main/java/de/firemage/autograder/core/check/api/UseFormatString.java b/autograder-core/src/main/java/de/firemage/autograder/core/check/api/UseFormatString.java index a5bf052c..8a22fa99 100644 --- a/autograder-core/src/main/java/de/firemage/autograder/core/check/api/UseFormatString.java +++ b/autograder-core/src/main/java/de/firemage/autograder/core/check/api/UseFormatString.java @@ -90,6 +90,11 @@ private String buildFormattedString(Iterable> ctExpres } else { formatString.append(value); } + + // if the string ends with a %, the concatenation is likely used to build a format string + if (value.endsWith("%")) { + return null; + } } else if (ctTypeInformation.isPrimitive() && !ctTypeInformation.isArray()) { // inline literals: formatString.append(ctLiteral.getValue()); diff --git a/autograder-core/src/main/java/de/firemage/autograder/core/check/complexity/RedundantVariable.java b/autograder-core/src/main/java/de/firemage/autograder/core/check/complexity/RedundantVariable.java index e90e9e46..243d1318 100644 --- a/autograder-core/src/main/java/de/firemage/autograder/core/check/complexity/RedundantVariable.java +++ b/autograder-core/src/main/java/de/firemage/autograder/core/check/complexity/RedundantVariable.java @@ -21,6 +21,8 @@ @ExecutableCheck(reportedProblems = {ProblemType.REDUNDANT_VARIABLE}) public class RedundantVariable extends IntegratedCheck { + private static final int MAX_EXPRESSION_SIZE = 40; + /** * Checks if the given statement does not influence the variable returned by the return statement. * @@ -32,7 +34,7 @@ private boolean isAllowedStatement(CtStatement ctStatement) { } private boolean isComplexExpression(CtExpression ctExpression) { - return ctExpression instanceof CtSwitchExpression; + return ctExpression instanceof CtSwitchExpression || ctExpression.toString().length() > MAX_EXPRESSION_SIZE; } private void checkVariableRead(CtStatement ctStatement, CtVariableRead ctVariableRead) { diff --git a/autograder-core/src/main/java/de/firemage/autograder/core/check/naming/LinguisticNamingCheck.java b/autograder-core/src/main/java/de/firemage/autograder/core/check/naming/LinguisticNamingCheck.java index 86088d4f..5dccb2e4 100644 --- a/autograder-core/src/main/java/de/firemage/autograder/core/check/naming/LinguisticNamingCheck.java +++ b/autograder-core/src/main/java/de/firemage/autograder/core/check/naming/LinguisticNamingCheck.java @@ -94,7 +94,7 @@ private void checkCtMethod(CtMethod ctMethod) { return; } - if (prefix.equals("set") && isInvalidSetterReturnType(ctMethod)) { + if (prefix.equals("set") && isInvalidSetterReturnType(ctMethod) && SpoonUtil.getEffectiveStatements(ctMethod.getBody()).size() <= 3) { // it is expected that a setter returns nothing (void) this.reportProblem( "linguistic-naming-setter", diff --git a/autograder-core/src/main/java/de/firemage/autograder/core/check/oop/InheritanceBadPractices.java b/autograder-core/src/main/java/de/firemage/autograder/core/check/oop/InheritanceBadPractices.java index 2d9b9644..132fb6c9 100644 --- a/autograder-core/src/main/java/de/firemage/autograder/core/check/oop/InheritanceBadPractices.java +++ b/autograder-core/src/main/java/de/firemage/autograder/core/check/oop/InheritanceBadPractices.java @@ -48,14 +48,14 @@ public void process(CtClass ctClass) { } // check if the class can be an interface: - if (fields.isEmpty()) { + if (fields.isEmpty() && ctClass.getSuperclass() == null) { addLocalProblem( ctClass, new LocalizedMessage("should-be-interface"), ProblemType.SHOULD_BE_INTERFACE ); // check if the class has only fields (data class) - } else if (methods.isEmpty()) { + } else if (methods.isEmpty() && ctClass.getSuperclass() == null) { String methodName = IdentifierNameUtils.toLowerCamelCase(ctClass.getSimpleName()); addLocalProblem( ctClass, diff --git a/autograder-core/src/test/java/de/firemage/autograder/core/check/api/TestUseFormatString.java b/autograder-core/src/test/java/de/firemage/autograder/core/check/api/TestUseFormatString.java index 6a51ce94..695cdf33 100644 --- a/autograder-core/src/test/java/de/firemage/autograder/core/check/api/TestUseFormatString.java +++ b/autograder-core/src/test/java/de/firemage/autograder/core/check/api/TestUseFormatString.java @@ -126,4 +126,26 @@ public String toString() { problems.assertExhausted(); } + + @Test + void testBuildFormatString() throws LinterException, IOException { + ProblemIterator problems = this.checkIterator(StringSourceInfo.fromSourceString( + JavaVersion.JAVA_17, + "Field", + """ + public class Field { + private String left; + private int number; + private String right; + + @Override + public String toString() { + return String.format("output: " + "%" + this.number + "d", this.number); + } + } + """ + ), PROBLEM_TYPES); + + problems.assertExhausted(); + } }