-
Notifications
You must be signed in to change notification settings - Fork 46
Add support for classes with hidden fields #563 #592
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
Changes from all commits
1e9587e
55bd35a
8e840ba
66761f6
f6419ee
2583bd8
fb6f19b
f080f49
eb7393b
94d8eca
78ed251
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,6 @@ import kotlinx.collections.immutable.toPersistentMap | |
import kotlinx.collections.immutable.toPersistentSet | ||
import org.utbot.common.WorkaroundReason.HACK | ||
import org.utbot.common.WorkaroundReason.REMOVE_ANONYMOUS_CLASSES | ||
import org.utbot.common.findField | ||
import org.utbot.common.unreachableBranch | ||
import org.utbot.common.withAccessibility | ||
import org.utbot.common.workaround | ||
|
@@ -90,8 +89,9 @@ import org.utbot.framework.plugin.api.MethodId | |
import org.utbot.framework.plugin.api.UtMethod | ||
import org.utbot.framework.plugin.api.classId | ||
import org.utbot.framework.plugin.api.id | ||
import org.utbot.framework.plugin.api.util.id | ||
import org.utbot.framework.plugin.api.util.field | ||
import org.utbot.framework.plugin.api.util.jClass | ||
import org.utbot.framework.plugin.api.util.id | ||
import org.utbot.framework.plugin.api.util.signature | ||
import org.utbot.framework.plugin.api.util.utContext | ||
import org.utbot.framework.util.executableId | ||
|
@@ -582,7 +582,7 @@ class Traverser( | |
declaringClass: SootClass, | ||
stmt: Stmt | ||
): SymbolicStateUpdate { | ||
val concreteValue = extractConcreteValue(field, declaringClass) | ||
val concreteValue = extractConcreteValue(field) | ||
val (symbolicResult, symbolicStateUpdate) = toMethodResult(concreteValue, field.type) | ||
val symbolicValue = (symbolicResult as SymbolicSuccess).value | ||
|
||
|
@@ -634,12 +634,12 @@ class Traverser( | |
// Some fields are inaccessible with reflection, so we have to instantiate it by ourselves. | ||
// Otherwise, extract it from the class. | ||
// TODO JIRA:1593 | ||
private fun extractConcreteValue(field: SootField, declaringClass: SootClass): Any? = | ||
private fun extractConcreteValue(field: SootField): Any? = | ||
when (field.signature) { | ||
SECURITY_FIELD_SIGNATURE -> SecurityManager() | ||
FIELD_FILTER_MAP_FIELD_SIGNATURE -> mapOf(Reflection::class to arrayOf("fieldFilterMap", "methodFilterMap")) | ||
METHOD_FILTER_MAP_FIELD_SIGNATURE -> emptyMap<Class<*>, Array<String>>() | ||
else -> declaringClass.id.jClass.findField(field.name).let { it.withAccessibility { it.get(null) } } | ||
else -> field.fieldId.field.let { it.withAccessibility { it.get(null) } } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Obviously, a problem with naming: Moreover, now we have unused There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just rewrote using UPD. Rolled back, problem still exists |
||
} | ||
|
||
private fun isStaticInstanceInMethodResult(id: ClassId, methodResult: MethodResult?) = | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,10 +15,8 @@ import org.utbot.framework.codegen.model.tree.CgAllocateInitializedArray | |
import org.utbot.framework.codegen.model.tree.CgDeclaration | ||
import org.utbot.framework.codegen.model.tree.CgEnumConstantAccess | ||
import org.utbot.framework.codegen.model.tree.CgExpression | ||
import org.utbot.framework.codegen.model.tree.CgFieldAccess | ||
import org.utbot.framework.codegen.model.tree.CgGetJavaClass | ||
import org.utbot.framework.codegen.model.tree.CgLiteral | ||
import org.utbot.framework.codegen.model.tree.CgNotNullAssertion | ||
import org.utbot.framework.codegen.model.tree.CgStaticFieldAccess | ||
import org.utbot.framework.codegen.model.tree.CgValue | ||
import org.utbot.framework.codegen.model.tree.CgVariable | ||
|
@@ -47,8 +45,7 @@ import org.utbot.framework.plugin.api.UtPrimitiveModel | |
import org.utbot.framework.plugin.api.UtReferenceModel | ||
import org.utbot.framework.plugin.api.UtVoidModel | ||
import org.utbot.framework.plugin.api.util.defaultValueModel | ||
import org.utbot.framework.plugin.api.util.field | ||
import org.utbot.framework.plugin.api.util.findFieldOrNull | ||
import org.utbot.framework.plugin.api.util.findFieldByIdOrNull | ||
import org.utbot.framework.plugin.api.util.id | ||
import org.utbot.framework.plugin.api.util.intClassId | ||
import org.utbot.framework.plugin.api.util.isArray | ||
|
@@ -128,21 +125,17 @@ internal class CgVariableConstructor(val context: CgContext) : | |
} | ||
|
||
for ((fieldId, fieldModel) in model.fields) { | ||
val field = fieldId.field | ||
val variableForField = getOrCreateVariable(fieldModel) | ||
val fieldFromVariableSpecifiedType = obj.type.findFieldOrNull(field.name) | ||
val field = obj.type.findFieldByIdOrNull(fieldId) | ||
|
||
// we cannot set field directly if variable declared type does not have such field | ||
// or we cannot directly create variable for field with the specified type (it is private, for example) | ||
// Example: | ||
// Object heapByteBuffer = createInstance("java.nio.HeapByteBuffer"); | ||
// branchRegisterRequest.byteBuffer = heapByteBuffer; | ||
// byteBuffer is field of type ByteBuffer and upper line is incorrect | ||
val canFieldBeDirectlySetByVariableAndFieldTypeRestrictions = | ||
fieldFromVariableSpecifiedType != null && fieldFromVariableSpecifiedType.type.id == variableForField.type | ||
if (canFieldBeDirectlySetByVariableAndFieldTypeRestrictions && fieldId.canBeSetIn(testClassPackageName)) { | ||
// TODO: check if it is correct to use declaringClass of a field here | ||
val fieldAccess = if (field.isStatic) CgStaticFieldAccess(fieldId) else CgFieldAccess(obj, fieldId) | ||
if (field != null && field.type.id == variableForField.type && fieldId.canBeSetIn(testClassPackageName)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Damtev or @EgorkaKulikov, please, look over these changes with code generation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no functional changes, but I am a bit confused with this |
||
val fieldAccess = if (field.isStatic) CgStaticFieldAccess(fieldId) else obj[fieldId] | ||
fieldAccess `=` variableForField | ||
} else { | ||
// composite models must not have info about static fields, hence only non-static fields are set here | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
package org.utbot.framework.codegen.model.util | ||
|
||
import org.utbot.common.findDirectAccessedFieldOrNull | ||
import org.utbot.framework.codegen.model.constructor.tree.CgCallableAccessManager | ||
import org.utbot.framework.codegen.model.tree.CgArrayElementAccess | ||
import org.utbot.framework.codegen.model.tree.CgDecrement | ||
|
@@ -16,6 +17,7 @@ import org.utbot.framework.codegen.model.tree.CgLessThan | |
import org.utbot.framework.codegen.model.tree.CgLiteral | ||
import org.utbot.framework.codegen.model.tree.CgStaticFieldAccess | ||
import org.utbot.framework.codegen.model.tree.CgThisInstance | ||
import org.utbot.framework.codegen.model.tree.CgTypeCast | ||
import org.utbot.framework.codegen.model.tree.CgVariable | ||
import org.utbot.framework.plugin.api.ClassId | ||
import org.utbot.framework.plugin.api.CodegenLanguage | ||
|
@@ -25,9 +27,11 @@ import org.utbot.framework.plugin.api.util.booleanClassId | |
import org.utbot.framework.plugin.api.util.byteClassId | ||
import org.utbot.framework.plugin.api.util.charClassId | ||
import org.utbot.framework.plugin.api.util.doubleClassId | ||
import org.utbot.framework.plugin.api.util.field | ||
import org.utbot.framework.plugin.api.util.floatClassId | ||
import org.utbot.framework.plugin.api.util.intClassId | ||
import org.utbot.framework.plugin.api.util.isArray | ||
import org.utbot.framework.plugin.api.util.jClass | ||
import org.utbot.framework.plugin.api.util.longClassId | ||
import org.utbot.framework.plugin.api.util.objectClassId | ||
import org.utbot.framework.plugin.api.util.shortClassId | ||
|
@@ -72,7 +76,11 @@ fun stringLiteral(string: String) = CgLiteral(stringClassId, string) | |
|
||
// non-static fields | ||
operator fun CgExpression.get(fieldId: FieldId): CgFieldAccess = | ||
CgFieldAccess(this, fieldId) | ||
if (type.jClass.findDirectAccessedFieldOrNull(fieldId.name) != fieldId.field) { | ||
CgFieldAccess(CgTypeCast(fieldId.declaringClass, this), fieldId) | ||
} else { | ||
CgFieldAccess(this, fieldId) | ||
} | ||
Comment on lines
-75
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This functionality was just a shortcut for a Also, this logic does not always work - there is no check that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the best place to move this logic to? Before calling this there are checks that Also, I believe that this logic should solve the removed TODO: it checks if we should use obj or declaring class as a caller. But maybe I misunderstood the TODO |
||
|
||
// static fields | ||
// TODO: unused receiver | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,7 +121,9 @@ internal class CgKotlinRenderer(context: CgContext, printer: CgPrinter = CgPrint | |
// Property access | ||
|
||
override fun visit(element: CgFieldAccess) { | ||
if (element.caller is CgTypeCast) print("(") | ||
element.caller.accept(this) | ||
if (element.caller is CgTypeCast) print(")") | ||
Comment on lines
+124
to
+126
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If lhs is typecast, we need brackets for correct priority. Without this, the generated code will be like This is a little bit of a hack, but I didn't find more general solution. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is definitely a hack, which is also not total - it does not cover similar cases for a method invocation and an array access. We need to find another solution. |
||
renderAccess(element.caller) | ||
print(element.fieldId.name) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure? Why?
Moreover, if it is true, do we write in this field in all other places in the wrapper? Not only in the resolver