Skip to content

Commit 31ddce3

Browse files
committed
Fix false-positive canBeSetIn result for private fields with getters in Kotlin
1 parent c45244f commit 31ddce3

File tree

8 files changed

+38
-29
lines changed

8 files changed

+38
-29
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import org.utbot.framework.codegen.model.tree.CgValue
3333
import org.utbot.framework.codegen.model.tree.CgVariable
3434
import org.utbot.framework.codegen.model.util.at
3535
import org.utbot.framework.codegen.model.util.isAccessibleFrom
36+
import org.utbot.framework.codegen.model.util.canBeReadFrom
3637
import org.utbot.framework.codegen.model.util.nullLiteral
3738
import org.utbot.framework.codegen.model.util.resolve
3839
import org.utbot.framework.plugin.api.BuiltinConstructorId
@@ -293,7 +294,7 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
293294

294295
private fun FieldId.accessSuitability(accessor: CgExpression?): FieldAccessorSuitability {
295296
// Check field accessibility.
296-
if (!isAccessibleFrom(context)) {
297+
if (!canBeReadFrom(context)) {
297298
return ReflectionOnly
298299
}
299300

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import org.utbot.framework.codegen.model.tree.CgValue
1818
import org.utbot.framework.codegen.model.tree.CgVariable
1919
import org.utbot.framework.codegen.model.util.at
2020
import org.utbot.framework.codegen.model.util.isAccessibleFrom
21+
import org.utbot.framework.codegen.model.util.canBeReadFrom
2122
import org.utbot.framework.codegen.model.util.stringLiteral
2223
import org.utbot.framework.fields.ArrayElementAccess
2324
import org.utbot.framework.fields.FieldAccess
@@ -182,7 +183,7 @@ internal class CgFieldStateManagerImpl(val context: CgContext)
182183
for ((index, fieldPathElement) in path.withIndex()) {
183184
when (fieldPathElement) {
184185
is FieldAccess -> {
185-
if (!fieldPathElement.field.isAccessibleFrom(context)) {
186+
if (!fieldPathElement.field.canBeReadFrom(context)) {
186187
lastAccessibleIndex = index - 1
187188
break
188189
}
@@ -246,7 +247,7 @@ internal class CgFieldStateManagerImpl(val context: CgContext)
246247

247248
private fun variableForStaticFieldState(owner: ClassId, fieldPath: FieldPath, customName: String?): CgVariable {
248249
val firstField = (fieldPath.elements.first() as FieldAccess).field
249-
val firstAccessor = if (owner.isAccessibleFrom(testClassPackageName) && firstField.isAccessibleFrom(context)) {
250+
val firstAccessor = if (owner.isAccessibleFrom(testClassPackageName) && firstField.canBeReadFrom(context)) {
250251
owner[firstField]
251252
} else {
252253
// TODO: there is a function getClassOf() for these purposes, but it is not accessible from here for now

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ import org.utbot.framework.codegen.model.tree.buildParameterizedTestDataProvider
6666
import org.utbot.framework.codegen.model.tree.buildTestMethod
6767
import org.utbot.framework.codegen.model.tree.convertDocToCg
6868
import org.utbot.framework.codegen.model.tree.toStatement
69-
import org.utbot.framework.codegen.model.util.canBeSetIn
69+
import org.utbot.framework.codegen.model.util.canBeSetFrom
7070
import org.utbot.framework.codegen.model.util.equalTo
7171
import org.utbot.framework.codegen.model.util.inc
72-
import org.utbot.framework.codegen.model.util.isAccessibleFrom
72+
import org.utbot.framework.codegen.model.util.canBeReadFrom
7373
import org.utbot.framework.codegen.model.util.length
7474
import org.utbot.framework.codegen.model.util.lessThan
7575
import org.utbot.framework.codegen.model.util.nullLiteral
@@ -218,7 +218,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
218218
val accessibleStaticFields = statics.accessibleFields()
219219
for ((field, _) in accessibleStaticFields) {
220220
val declaringClass = field.declaringClass
221-
val fieldAccessible = field.isAccessibleFrom(context)
221+
val fieldAccessible = field.canBeReadFrom(context)
222222

223223
// prevValue is nullable if not accessible because of getStaticFieldValue(..) : Any?
224224
val prevValue = newVar(
@@ -243,7 +243,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
243243
val accessibleStaticFields = statics.accessibleFields()
244244
for ((field, model) in accessibleStaticFields) {
245245
val declaringClass = field.declaringClass
246-
val fieldAccessible = field.canBeSetIn(context)
246+
val fieldAccessible = field.canBeSetFrom(context)
247247

248248
val fieldValue = if (isParametrized) {
249249
currentMethodParameters[CgParameterKind.Statics(model)]
@@ -264,7 +264,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
264264

265265
private fun recoverStaticFields() {
266266
for ((field, prevValue) in prevStaticFieldValues.accessibleFields()) {
267-
if (field.canBeSetIn(context)) {
267+
if (field.canBeSetFrom(context)) {
268268
field.declaringClass[field] `=` prevValue
269269
} else {
270270
val declaringClass = getClassOf(field.declaringClass)
@@ -1039,7 +1039,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
10391039
private fun FieldId.getAccessExpression(variable: CgVariable): CgExpression =
10401040
// Can directly access field only if it is declared in variable class (or in its ancestors)
10411041
// and is accessible from current package
1042-
if (variable.type.hasField(this) && isAccessibleFrom(context)) {
1042+
if (variable.type.hasField(this) && canBeReadFrom(context)) {
10431043
if (jField.isStatic) CgStaticFieldAccess(this) else CgFieldAccess(variable, this)
10441044
} else {
10451045
utilsClassId[getFieldValue](variable, this.declaringClass.name, this.name)

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import org.utbot.framework.codegen.model.tree.CgStaticFieldAccess
2828
import org.utbot.framework.codegen.model.tree.CgValue
2929
import org.utbot.framework.codegen.model.tree.CgVariable
3030
import org.utbot.framework.codegen.model.util.at
31-
import org.utbot.framework.codegen.model.util.canBeSetIn
31+
import org.utbot.framework.codegen.model.util.canBeSetFrom
3232
import org.utbot.framework.codegen.model.util.fieldThisIsGetterFor
3333
import org.utbot.framework.codegen.model.util.fieldThisIsSetterFor
3434
import org.utbot.framework.codegen.model.util.inc
@@ -193,7 +193,7 @@ internal class CgVariableConstructor(val context: CgContext) :
193193
// byteBuffer is field of type ByteBuffer and upper line is incorrect
194194
val canFieldBeDirectlySetByVariableAndFieldTypeRestrictions =
195195
fieldFromVariableSpecifiedType != null && fieldFromVariableSpecifiedType.type.id == variableForField.type
196-
if (canFieldBeDirectlySetByVariableAndFieldTypeRestrictions && fieldId.canBeSetIn(context)) {
196+
if (canFieldBeDirectlySetByVariableAndFieldTypeRestrictions && fieldId.canBeSetFrom(context)) {
197197
// TODO: check if it is correct to use declaringClass of a field here
198198
val fieldAccess = if (field.isStatic) CgStaticFieldAccess(fieldId) else CgFieldAccess(obj, fieldId)
199199
fieldAccess `=` variableForField

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/MockFrameworkManager.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import org.utbot.framework.codegen.model.constructor.builtin.anyLong
1313
import org.utbot.framework.codegen.model.constructor.builtin.anyOfClass
1414
import org.utbot.framework.codegen.model.constructor.builtin.anyShort
1515
import org.utbot.framework.codegen.model.constructor.builtin.argumentMatchersClassId
16-
import org.utbot.framework.codegen.model.constructor.builtin.forName
1716
import org.utbot.framework.codegen.model.constructor.builtin.mockMethodId
1817
import org.utbot.framework.codegen.model.constructor.builtin.mockedConstructionContextClassId
1918
import org.utbot.framework.codegen.model.constructor.builtin.mockitoClassId
@@ -24,7 +23,6 @@ import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
2423
import org.utbot.framework.codegen.model.constructor.util.CgComponents
2524
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor
2625
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructorImpl
27-
import org.utbot.framework.codegen.model.constructor.util.classCgClassId
2826
import org.utbot.framework.codegen.model.constructor.util.hasAmbiguousOverloadsOf
2927
import org.utbot.framework.codegen.model.tree.CgAnonymousFunction
3028
import org.utbot.framework.codegen.model.tree.CgAssignment
@@ -33,7 +31,6 @@ import org.utbot.framework.codegen.model.tree.CgConstructorCall
3331
import org.utbot.framework.codegen.model.tree.CgDeclaration
3432
import org.utbot.framework.codegen.model.tree.CgExecutableCall
3533
import org.utbot.framework.codegen.model.tree.CgExpression
36-
import org.utbot.framework.codegen.model.tree.CgGetJavaClass
3734
import org.utbot.framework.codegen.model.tree.CgLiteral
3835
import org.utbot.framework.codegen.model.tree.CgMethodCall
3936
import org.utbot.framework.codegen.model.tree.CgParameterDeclaration
@@ -63,7 +60,6 @@ import org.utbot.framework.plugin.api.util.byteClassId
6360
import org.utbot.framework.plugin.api.util.charClassId
6461
import org.utbot.framework.plugin.api.util.doubleClassId
6562
import org.utbot.framework.plugin.api.util.floatClassId
66-
import org.utbot.framework.plugin.api.util.id
6763
import org.utbot.framework.plugin.api.util.intClassId
6864
import org.utbot.framework.plugin.api.util.longClassId
6965
import org.utbot.framework.plugin.api.util.shortClassId

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import org.utbot.framework.codegen.StaticImport
55
import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
66
import org.utbot.framework.codegen.model.tree.CgClassId
77
import org.utbot.framework.codegen.model.tree.CgExpression
8-
import org.utbot.framework.codegen.model.tree.CgGetClass
9-
import org.utbot.framework.codegen.model.tree.CgGetJavaClass
108
import org.utbot.framework.codegen.model.tree.CgTypeCast
119
import org.utbot.framework.codegen.model.tree.CgValue
1210
import org.utbot.framework.codegen.model.tree.CgVariable

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/FieldIdUtil.kt

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import org.utbot.framework.plugin.api.util.voidClassId
1414
* @param context context in which code is generated (it is needed because the method needs to know package and language)
1515
*/
1616
// TODO: change parameter from packageName: String to context: CgContext in ClassId.isAccessibleFrom and ExecutableId.isAccessibleFrom ?
17-
internal infix fun FieldId.isAccessibleFrom(context: CgContext): Boolean {
18-
if (context.codegenLanguage == CodegenLanguage.KOTLIN) {
17+
private fun FieldId.isAccessibleFrom(context: CgContext): Boolean {
18+
/*if (context.codegenLanguage == CodegenLanguage.KOTLIN) {
1919
// Here we call field accessible iff its getter is accessible, checks for setter are made in FieldId.canBeSetIn
20-
if (!isStatic && declaringClass.allMethods.contains(getter) && getter.isAccessibleFrom(context.testClassPackageName))
20+
if (!isStatic && isAccessibleViaGetterFrom(context))
2121
return true
22-
}
22+
}*/
2323
val packageName = context.testClassPackageName
2424
val isClassAccessible = declaringClass.isAccessibleFrom(packageName)
2525
val isAccessibleByVisibility = isPublic || (declaringClass.packageName == packageName && (isPackagePrivate || isProtected))
@@ -28,21 +28,34 @@ internal infix fun FieldId.isAccessibleFrom(context: CgContext): Boolean {
2828
return isClassAccessible && isAccessibleFromPackageByModifiers
2929
}
3030

31+
private fun FieldId.canBeReadViaGetterFrom(context: CgContext): Boolean =
32+
declaringClass.allMethods.contains(getter) && getter.isAccessibleFrom(context.testClassPackageName)
33+
34+
internal infix fun FieldId.canBeReadFrom(context: CgContext): Boolean {
35+
if (context.codegenLanguage == CodegenLanguage.KOTLIN) {
36+
if (!isStatic && canBeReadViaGetterFrom(context))
37+
return true
38+
}
39+
40+
return isAccessibleFrom(context)
41+
}
42+
43+
private fun FieldId.canBeSetViaSetterFrom(context: CgContext): Boolean =
44+
declaringClass.allMethods.contains(setter) && setter.isAccessibleFrom(context.testClassPackageName)
45+
3146
/**
3247
* Whether or not a field can be set without reflection
3348
*/
34-
internal fun FieldId.canBeSetIn(context: CgContext): Boolean {
35-
if (!isAccessibleFrom(context)) {
36-
return false
37-
}
38-
49+
internal fun FieldId.canBeSetFrom(context: CgContext): Boolean {
3950
if (context.codegenLanguage == CodegenLanguage.KOTLIN) {
40-
if (!isStatic && declaringClass.allMethods.contains(setter) && setter.isAccessibleFrom(context.testClassPackageName)) {
51+
// Kotlin will allow direct write access if both getter and setter is defined (even if the field is final)
52+
// TODO: add comment about final public and final private fields
53+
if (!isAccessibleFrom(context) && !isStatic && canBeReadViaGetterFrom(context) && canBeSetViaSetterFrom(context)) {
4154
return true
4255
}
4356
}
4457

45-
return !isFinal
58+
return isAccessibleFrom(context) && !isFinal
4659
}
4760

4861
/**

utbot-sample/src/main/java/org/utbot/examples/annotations/ClassWithRefField.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static void setStaticBoxedInt(@NotNull Integer staticBoxedInt) {
2121
}
2222

2323
@SuppressWarnings("NullableProblems")
24-
public @NotNull Integer getBoxedInt() {
24+
public Integer getBoxedInt() {
2525
return boxedInt;
2626
}
2727
}

0 commit comments

Comments
 (0)