Skip to content

Commit

Permalink
SONARJAVA-4513 FN S2060 (ExternalizableClassConstructorCheck) if no-a…
Browse files Browse the repository at this point in the history
…rgument constructor is not public (#4562)
  • Loading branch information
kaufco authored Nov 21, 2023
1 parent 1b25ff2 commit e36419e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,40 @@ public S2060_E(String color, int weight) {}
class S2060_F { // Compliant
public S2060_F(String color, int weight) {}
}

class CtorVisibility_A implements Externalizable {
public CtorVisibility_A() {} // Compliant
@Override public void writeExternal(ObjectOutput out) throws IOException { }
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }
}

class CtorVisibility_B implements Externalizable { // Compliant
protected CtorVisibility_B() {} // Noncompliant [[sc=13;ec=29]] {{Declare this no-arg constructor public.}}
@Override public void writeExternal(ObjectOutput out) throws IOException { }
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }
}

class CtorVisibility_C implements Externalizable { // Compliant
CtorVisibility_C() {} // Noncompliant [[sc=3;ec=19]]
@Override public void writeExternal(ObjectOutput out) throws IOException { }
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }
}

class CtorVisibility_D implements Externalizable { // Compliant
private CtorVisibility_D() {} // Noncompliant [[sc=11;ec=27]]
@Override public void writeExternal(ObjectOutput out) throws IOException { }
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }
}

class OuterClass {

private static class CtorVisibility_E implements Externalizable { // Compliant, no-arg constructor is private, but implicit
@Override public void writeExternal(ObjectOutput out) throws IOException { }
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }
}

public static class CtorVisibilita_F implements Externalizable { // Compliant, implicit no-arg constructor is public
@Override public void writeExternal(ObjectOutput out) throws IOException { }
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@
*/
package org.sonar.java.checks.serialization;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.sonar.check.Rule;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.tree.ClassTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.Tree;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

@Rule(key = "S2060")
public class ExternalizableClassConstructorCheck extends IssuableSubscriptionVisitor {

Expand All @@ -42,16 +43,17 @@ public void visitNode(Tree tree) {
ClassTree classTree = (ClassTree) tree;
if (!isAnonymous(classTree) && implementsExternalizable(classTree)) {
Collection<Symbol> constructors = classTree.symbol().lookupSymbols("<init>");
boolean hasNoArgConstructor = constructors.isEmpty();
for (Symbol constructor : constructors) {
if (isNoArgConstructor(constructor)) {
hasNoArgConstructor = true;
break;
var noArgConstructor = constructors.stream().filter(ExternalizableClassConstructorCheck::isNoArgConstructor).findFirst();

if (noArgConstructor.isEmpty()) {
reportIssue(Objects.requireNonNull(classTree.simpleName()), "Add a no-arg constructor to this class.");
} else if (!noArgConstructor.get().isPublic()) {
// Implicit no-arg constructors have no declaration and same visibility as class. Can be below "public". Ignore them.
var declaration = noArgConstructor.get().declaration();
if (declaration != null) {
reportIssue(((MethodTree) declaration).simpleName(), "Declare this no-arg constructor public.");
}
}
if (!hasNoArgConstructor) {
reportIssue(classTree.simpleName(), "Add a no-arg constructor to this class.");
}
}
}

Expand Down

0 comments on commit e36419e

Please sign in to comment.