Skip to content

Commit

Permalink
filter all returns of unmodifiable wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
henry committed Feb 12, 2024
1 parent 3794506 commit e80f824
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,19 @@ public static Match<AbstractInsnNode> methodDescEquals(final String desc) {
}

public static Match<AbstractInsnNode> methodCallTo(final ClassName owner, final String name) {
return methodCallTo(owner, c -> c.equals(name));
}

public static Match<AbstractInsnNode> methodCallTo(final ClassName owner, Predicate<String> name) {
return (c, t) -> {
if ( t instanceof MethodInsnNode ) {
final MethodInsnNode call = (MethodInsnNode) t;
return result( call.name.equals(name) && call.owner.equals(owner.asInternalName()), c);
return result( name.test(call.name) && call.owner.equals(owner.asInternalName()), c);
}
return result(false, c);
};
}


public static Match<AbstractInsnNode> isInstruction(final SlotRead<AbstractInsnNode> target) {
return (c, t) -> result(c.retrieve(target).get() == t, c);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@

public class ReturnUnmodifiableCollection extends RegionInterceptor {

private static final ClassName COLLECTIONS = ClassName.fromClass(Collections.class);

static final Slot<AbstractInsnNode> MUTATED_INSTRUCTION = Slot.create(AbstractInsnNode.class);

static final SequenceMatcher<AbstractInsnNode> DEFENSIVE_RETURN = QueryStart
.any(AbstractInsnNode.class)
.then(INVOKESTATIC.and(methodCallTo(COLLECTIONS, "unmodifiableSet")).and(store(MUTATED_INSTRUCTION.write())))
.then(INVOKESTATIC.and(methodCallTo(ClassName.fromClass(Collections.class), n -> n.startsWith("unmodifiable"))).and(store(MUTATED_INSTRUCTION.write())))
.then(ARETURN)
.zeroOrMore(QueryStart.match(anyInstruction()))
.compile(QueryParams.params(AbstractInsnNode.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
import org.pitest.verifier.interceptors.InterceptorVerifier;
import org.pitest.verifier.interceptors.VerifierStart;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.pitest.bytecode.analysis.OpcodeMatchers.INVOKESTATIC;
Expand Down Expand Up @@ -53,6 +56,22 @@ public void filtersMutationsToReturnUnmodifiableSet() {
.verify();
}

@Test
public void filtersMutationsToReturnUnmodifiableList() {
v.forClass(HasUnmodifiableListReturn.class)
.forCodeMatching(INVOKESTATIC.asPredicate())
.allMutantsAreFiltered()
.verify();
}

@Test
public void filtersMutationsToReturnUnmodifiableMap() {
v.forClass(HasUnmodifiableMapReturn.class)
.forCodeMatching(INVOKESTATIC.asPredicate())
.allMutantsAreFiltered()
.verify();
}

@Test
public void doesNotFilterOtherCode() {
v.forClass(HasUnmodifiableSetReturn.class)
Expand Down Expand Up @@ -82,6 +101,25 @@ public Set<String> mutateMe(int i) {
}
}

class HasUnmodifiableListReturn {
private final List<String> s = new ArrayList<>();

public List<String> mutateMe(int i) {
if (i != 1) {
return Collections.unmodifiableList(s);
}

return s;
}
}

class HasUnmodifiableMapReturn {

public Map<String,String> mutateMe(Map<String,String> m) {
return Collections.unmodifiableMap(m);
}
}

class HasUnmodifiableSetNonReturn {
private final Set<String> s = new HashSet<>();
private Set<String> copy;
Expand Down

0 comments on commit e80f824

Please sign in to comment.