Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import org.utbot.framework.plugin.api.CodegenLanguage
import kotlin.math.min
import org.junit.jupiter.api.Test
import org.utbot.testcheckers.eq
import org.utbot.testcheckers.withoutConcrete
import org.utbot.testing.CodeGeneration
import org.utbot.testing.DoNotCalculate
import org.utbot.testing.FullWithAssumptions
import org.utbot.testing.UtValueTestCaseChecker
import org.utbot.testing.ignoreExecutionsNumber

Expand All @@ -19,6 +21,31 @@ internal class ListIteratorsTest : UtValueTestCaseChecker(
TestLastStage(CodegenLanguage.KOTLIN, CodeGeneration)
)
) {
@Test
fun testReturnIterator() {
withoutConcrete { // We need to check that a real class is returned but not `Ut` one
check(
ListIterators::returnIterator,
ignoreExecutionsNumber,
{ l, r -> l.isEmpty() && r!!.asSequence().toList().isEmpty() },
{ l, r -> l.isNotEmpty() && r!!.asSequence().toList() == l },
coverage = FullWithAssumptions(assumeCallsNumber = 1)
)
}
}

@Test
fun testReturnListIterator() {
withoutConcrete { // We need to check that a real class is returned but not `Ut` one
check(
ListIterators::returnListIterator,
ignoreExecutionsNumber,
{ l, r -> l.isEmpty() && r!!.asSequence().toList().isEmpty() },
{ l, r -> l.isNotEmpty() && r!!.asSequence().toList() == l },
coverage = FullWithAssumptions(assumeCallsNumber = 1)
)
}
}

@Test
fun testIterate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package org.utbot.examples.collections
import org.utbot.framework.plugin.api.CodegenLanguage
import org.junit.jupiter.api.Test
import org.utbot.testcheckers.ge
import org.utbot.testcheckers.withoutConcrete
import org.utbot.testing.CodeGeneration
import org.utbot.testing.FullWithAssumptions
import org.utbot.testing.UtValueTestCaseChecker
import org.utbot.testing.between
import org.utbot.testing.ignoreExecutionsNumber
Expand All @@ -18,6 +20,19 @@ class SetIteratorsTest : UtValueTestCaseChecker(
TestLastStage(CodegenLanguage.KOTLIN, CodeGeneration)
)
) {
@Test
fun testReturnIterator() {
withoutConcrete { // We need to check that a real class is returned but not `Ut` one
check(
SetIterators::returnIterator,
ignoreExecutionsNumber,
{ s, r -> s.isEmpty() && r!!.asSequence().toSet().isEmpty() },
{ s, r -> s.isNotEmpty() && r!!.asSequence().toSet() == s },
coverage = FullWithAssumptions(assumeCallsNumber = 1)
)
}
}

@Test
fun testIteratorHasNext() {
check(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ public int lastIndexOf(Object o) {
@Override
public Iterator<E> iterator() {
preconditionCheck();
return new UtArrayListIterator(0);
return new UtArrayListSimpleIterator(0);
}

@NotNull
Expand Down Expand Up @@ -405,6 +405,43 @@ public List<E> subList(int fromIndex, int toIndex) {
return this.toList().subList(fromIndex, toIndex);
}

public class UtArrayListSimpleIterator implements Iterator<E> {
int index;
int prevIndex = -1;

UtArrayListSimpleIterator(int index) {
rangeCheckForAdd(index);
this.index = index;
}

@Override
public boolean hasNext() {
preconditionCheck();
return index != elementData.end;
}

@Override
public E next() {
preconditionCheck();
if (index == elementData.end) {
throw new NoSuchElementException();
}
prevIndex = index;
return elementData.get(index++);
}

@Override
public void remove() {
preconditionCheck();
if (prevIndex == -1) {
throw new IllegalStateException();
}
elementData.end--;
elementData.remove(prevIndex);
prevIndex = -1;
}
}

public class UtArrayListIterator implements ListIterator<E> {
int index;
int prevIndex = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,8 @@ public List<E> subList(int fromIndex, int toIndex) {
@Override
public Iterator<E> iterator() {
preconditionCheck();

// Some implementations of `iterator` return an instance of ListIterator
return new UtLinkedListIterator(elementData.begin);
}

Expand All @@ -449,7 +451,7 @@ public ListIterator<E> listIterator() {
@Override
public Iterator<E> descendingIterator() {
preconditionCheck();
return new ReverseIteratorWrapper(elementData.end);
return new UtReverseIterator(elementData.end);
}

@Override
Expand All @@ -467,12 +469,12 @@ public Stream<E> parallelStream() {
return stream();
}

public class ReverseIteratorWrapper implements ListIterator<E> {
public class UtReverseIterator implements ListIterator<E> {

int index;
int prevIndex = -1;

ReverseIteratorWrapper(int index) {
UtReverseIterator(int index) {
this.index = index;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.utbot.engine

import org.utbot.engine.overrides.collections.UtArrayList.UtArrayListIterator
import org.utbot.engine.overrides.collections.UtArrayList.UtArrayListSimpleIterator
import org.utbot.engine.overrides.collections.UtHashSet.UtHashSetIterator
import org.utbot.engine.overrides.collections.UtLinkedList.UtReverseIterator
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.FieldId
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.UtAssembleModel
import org.utbot.framework.plugin.api.UtExecutableCallModel
import org.utbot.framework.plugin.api.UtModel
import org.utbot.framework.plugin.api.UtReferenceModel
import org.utbot.framework.plugin.api.util.id
import org.utbot.framework.plugin.api.util.methodId
import soot.SootClass
import soot.SootMethod
import kotlin.reflect.KClass
import kotlin.reflect.jvm.jvmName

/**
* Abstract wrapper for iterator of [java.util.Collection].
*/
abstract class CollectionIteratorWrapper(overriddenClass: KClass<*>) : BaseOverriddenWrapper(overriddenClass.jvmName) {
protected abstract val modelName: String
protected abstract val javaCollectionClassId: ClassId
protected abstract val iteratorMethodId: MethodId
protected abstract val iteratorClassId: ClassId

override fun Traverser.overrideInvoke(
wrapper: ObjectValue,
method: SootMethod,
parameters: List<SymbolicValue>
): List<InvokeResult>? = null

override fun value(resolver: Resolver, wrapper: ObjectValue): UtModel = resolver.run {
val addr = holder.concreteAddr(wrapper.addr)
val fieldModels = collectFieldModels(wrapper.addr, overriddenClass.type)

val containerFieldId = overriddenClass.enclosingClassField
val containerFieldModel = fieldModels[containerFieldId] as UtReferenceModel

val instantiationCall = UtExecutableCallModel(
instance = containerFieldModel,
executable = iteratorMethodId,
params = emptyList()
)

UtAssembleModel(addr, iteratorClassId, modelName, instantiationCall)
}
}

class IteratorOfListWrapper : CollectionIteratorWrapper(UtArrayListSimpleIterator::class) {
override val modelName: String = "iteratorOfList"
override val javaCollectionClassId: ClassId = java.util.List::class.id
override val iteratorClassId: ClassId = java.util.Iterator::class.id
override val iteratorMethodId: MethodId = methodId(
classId = javaCollectionClassId,
name = "iterator",
returnType = iteratorClassId,
arguments = emptyArray()
)
}

class ListIteratorOfListWrapper : CollectionIteratorWrapper(UtArrayListIterator::class) {
override val modelName: String = "listIteratorOfList"
override val javaCollectionClassId: ClassId = java.util.List::class.id
override val iteratorClassId: ClassId = java.util.ListIterator::class.id
override val iteratorMethodId: MethodId = methodId(
classId = javaCollectionClassId,
name = "listIterator",
returnType = iteratorClassId,
arguments = emptyArray()
)
}

class IteratorOfSetWrapper : CollectionIteratorWrapper(UtHashSetIterator::class) {
override val modelName: String = "iteratorOfSet"
override val javaCollectionClassId: ClassId = java.util.Set::class.id
override val iteratorClassId: ClassId = java.util.Iterator::class.id
override val iteratorMethodId: MethodId = methodId(
classId = javaCollectionClassId,
name = "iterator",
returnType = iteratorClassId,
arguments = emptyArray()
)
}

class ReverseIteratorWrapper :CollectionIteratorWrapper(UtReverseIterator::class) {
override val modelName: String = "reverseIterator"
override val javaCollectionClassId: ClassId = java.util.Deque::class.id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is ReverseIteratorWrapper corresponds to Deque?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because descendingIterator is a method of java.util.Deque

override val iteratorClassId: ClassId = java.util.Iterator::class.id
override val iteratorMethodId: MethodId = methodId(
classId = javaCollectionClassId,
name = "descendingIterator",
returnType = iteratorClassId,
arguments = emptyArray()
)
}

internal val SootClass.enclosingClassField: FieldId
get() {
require(isInnerClass) {
"Cannot get field for enclosing class of non-inner class $this"
}

return getFieldByName("this$0").fieldId
}
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,11 @@ val LINKED_HASH_MAP_TYPE: RefType
val HASH_MAP_TYPE: RefType
get() = Scene.v().getSootClass(java.util.HashMap::class.java.canonicalName).type

val ITERATOR_TYPE: RefType
get() = Scene.v().getSootClass(java.util.Iterator::class.java.canonicalName).type
val LIST_ITERATOR_TYPE: RefType
get() = Scene.v().getSootClass(java.util.ListIterator::class.java.canonicalName).type

val STREAM_TYPE: RefType
get() = Scene.v().getSootClass(java.util.stream.Stream::class.java.canonicalName).type

Expand Down
27 changes: 25 additions & 2 deletions utbot-framework/src/main/kotlin/org/utbot/engine/ObjectWrappers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ import org.utbot.engine.UtStreamClass.UT_STREAM
import org.utbot.engine.overrides.collections.AssociativeArray
import org.utbot.engine.overrides.collections.RangeModifiableUnlimitedArray
import org.utbot.engine.overrides.collections.UtArrayList
import org.utbot.engine.overrides.collections.UtArrayList.UtArrayListIterator
import org.utbot.engine.overrides.collections.UtArrayList.UtArrayListSimpleIterator
import org.utbot.engine.overrides.collections.UtHashMap
import org.utbot.engine.overrides.collections.UtHashSet
import org.utbot.engine.overrides.collections.UtHashSet.UtHashSetIterator
import org.utbot.engine.overrides.collections.UtLinkedList
import org.utbot.engine.overrides.collections.UtLinkedList.UtLinkedListIterator
import org.utbot.engine.overrides.collections.UtLinkedList.UtReverseIterator
import org.utbot.engine.overrides.collections.UtLinkedListWithNullableCheck
import org.utbot.engine.overrides.collections.UtOptional
import org.utbot.engine.overrides.collections.UtOptionalDouble
Expand Down Expand Up @@ -67,6 +72,7 @@ import soot.Scene
import soot.SootClass
import soot.SootMethod
import kotlin.reflect.KClass
import kotlin.reflect.jvm.jvmName

typealias TypeToBeWrapped = RefType
typealias WrapperType = RefType
Expand Down Expand Up @@ -123,6 +129,13 @@ val classToWrapper: MutableMap<TypeToBeWrapped, WrapperType> =
putSootClass(java.util.HashMap::class, UtHashMap::class)
putSootClass(java.util.concurrent.ConcurrentHashMap::class, UtHashMap::class)

// Iterators
putSootClass(java.util.Iterator::class, UtArrayListSimpleIterator::class)
putSootClass(java.util.ListIterator::class, UtArrayListIterator::class)
putSootClass(UtLinkedListIterator::class, UtLinkedListIterator::class)
putSootClass(UtReverseIterator::class, UtReverseIterator::class)
putSootClass(UtHashSetIterator::class, UtHashSetIterator::class)

putSootClass(java.util.stream.BaseStream::class, UT_STREAM.className)
putSootClass(java.util.stream.Stream::class, UT_STREAM.className)
putSootClass(java.util.stream.IntStream::class, UT_INT_STREAM.className)
Expand Down Expand Up @@ -158,7 +171,7 @@ val wrapperToClass: Map<WrapperType, Set<TypeToBeWrapped>> =
private fun MutableMap<TypeToBeWrapped, WrapperType>.putSootClass(
key: KClass<*>,
value: KClass<*>
) = putSootClass(key, Scene.v().getSootClass(value.java.canonicalName).type)
) = putSootClass(key, Scene.v().getSootClass(value.jvmName).type) // It is important to use `jvmName` because `canonicalName` replaces `$` for nested classes to `.`

private fun MutableMap<TypeToBeWrapped, WrapperType>.putSootClass(
key: KClass<*>,
Expand All @@ -173,7 +186,7 @@ private fun MutableMap<TypeToBeWrapped, WrapperType>.putSootClass(
private fun MutableMap<TypeToBeWrapped, WrapperType>.putSootClass(
key: KClass<*>,
value: RefType
) = put(Scene.v().getSootClass(key.java.canonicalName).type, value)
) = put(Scene.v().getSootClass(key.jvmName).type, value) // It is important to use `jvmName` because `canonicalName` replaces `$` for nested classes to `.`

private val wrappers: Map<ClassId, (RefType, UtAddrExpression) -> ObjectValue> = mutableMapOf(
wrap(java.lang.StringBuilder::class) { type, addr -> objectValue(type, addr, UtStringBuilderWrapper()) },
Expand Down Expand Up @@ -235,6 +248,10 @@ private val wrappers: Map<ClassId, (RefType, UtAddrExpression) -> ObjectValue> =
wrap(java.util.HashMap::class) { _, addr -> objectValue(HASH_MAP_TYPE, addr, MapWrapper()) },
wrap(java.util.concurrent.ConcurrentHashMap::class) { _, addr -> objectValue(HASH_MAP_TYPE, addr, MapWrapper()) },

// iterator wrappers
wrap(java.util.Iterator::class) { _, addr -> objectValue(ITERATOR_TYPE, addr, IteratorOfListWrapper()) },
wrap(java.util.ListIterator::class) { _, addr -> objectValue(LIST_ITERATOR_TYPE, addr, ListIteratorOfListWrapper()) },

// stream wrappers
wrap(java.util.stream.BaseStream::class) { _, addr -> objectValue(STREAM_TYPE, addr, CommonStreamWrapper()) },
wrap(java.util.stream.Stream::class) { _, addr -> objectValue(STREAM_TYPE, addr, CommonStreamWrapper()) },
Expand Down Expand Up @@ -272,6 +289,12 @@ private val wrappers: Map<ClassId, (RefType, UtAddrExpression) -> ObjectValue> =

wrap(UtHashMap::class) { _, addr -> objectValue(HASH_MAP_TYPE, addr, MapWrapper()) },

wrap(UtArrayListSimpleIterator::class) { _, addr -> objectValue(ITERATOR_TYPE, addr, IteratorOfListWrapper()) },
wrap(UtArrayListIterator::class) { _, addr -> objectValue(LIST_ITERATOR_TYPE, addr, ListIteratorOfListWrapper()) },
wrap(UtLinkedListIterator::class) { _, addr -> objectValue(LIST_ITERATOR_TYPE, addr, ListIteratorOfListWrapper()) }, // use ListIterator instead of simple Iterator because java.util.LinkedList may return ListIterator for `iterator`
wrap(UtReverseIterator::class) { _, addr -> objectValue(ITERATOR_TYPE, addr, ReverseIteratorWrapper()) },
wrap(UtHashSetIterator::class) { _, addr -> objectValue(ITERATOR_TYPE, addr, IteratorOfSetWrapper()) },

wrap(UtStream::class) { _, addr -> objectValue(STREAM_TYPE, addr, CommonStreamWrapper()) },
wrap(UtIntStream::class) { _, addr -> objectValue(INT_STREAM_TYPE, addr, IntStreamWrapper()) },
wrap(UtLongStream::class) { _, addr -> objectValue(LONG_STREAM_TYPE, addr, LongStreamWrapper()) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.utbot.framework.util

import org.utbot.common.FileUtil
import org.utbot.engine.jimpleBody
import org.utbot.engine.overrides.collections.UtLinkedList
import org.utbot.engine.pureJavaSignature
import org.utbot.framework.UtSettings
import org.utbot.framework.plugin.api.ExecutableId
Expand Down Expand Up @@ -159,11 +160,12 @@ private val classesToLoad = arrayOf(
org.utbot.engine.overrides.collections.UtOptionalLong::class,
org.utbot.engine.overrides.collections.UtOptionalDouble::class,
org.utbot.engine.overrides.collections.UtArrayList::class,
org.utbot.engine.overrides.collections.UtArrayList.UtArrayListSimpleIterator::class,
org.utbot.engine.overrides.collections.UtArrayList.UtArrayListIterator::class,
org.utbot.engine.overrides.collections.UtLinkedList::class,
org.utbot.engine.overrides.collections.UtLinkedListWithNullableCheck::class,
org.utbot.engine.overrides.collections.UtLinkedList.UtLinkedListIterator::class,
org.utbot.engine.overrides.collections.UtLinkedList.ReverseIteratorWrapper::class,
org.utbot.engine.overrides.collections.UtLinkedList.UtReverseIterator::class,
org.utbot.engine.overrides.collections.UtHashSet::class,
org.utbot.engine.overrides.collections.UtHashSet.UtHashSetIterator::class,
org.utbot.engine.overrides.collections.UtHashMap::class,
Expand Down
Loading