-
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
Add support for classes with hidden fields #563 #592
Conversation
} | ||
} | ||
.firstOrNull() | ||
fun Class<*>.findDirectAccessedField(fieldName: String): Field? = generateSequence(this) { it.superclass } |
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.
Please, add documentation here. Especially about what 'directAccessed' means
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.
Added documentation for this method
@@ -855,7 +856,7 @@ open class FieldId(val declaringClass: ClassId, val name: String) { | |||
return result | |||
} | |||
|
|||
override fun toString() = declaringClass.findFieldOrNull(name).toString() | |||
override fun toString() = declaringClass.fieldOrNull(this).toString() |
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.
Why not findField
anymore?
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.
Previously it was a method that was finding Field
by its name. Now, when the FieldId
is passed as argument, it is not really finding -- it's more like checking that this field belongs to this class and returning Field
.
Renamed to fieldByIdOrNull
for greater clarity
if (this.isNotSubtypeOf(fieldId.declaringClass)) | ||
return null |
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.
Please, do not omit brackets for multiline constructions. Minor: redundant this
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.
fixed
return try { | ||
fieldId.field | ||
} catch (e: IllegalStateException) { | ||
null |
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.
I believe, it is exception-dependent logic. Why you can't do it without throwing an exception? It is not a cheap operation after all. Moreover, please, add an empty line before the return
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.
fixed, although it's a little bit copy-pasted now
} | ||
} | ||
.firstOrNull() | ||
fun Class<*>.findDirectAccessedField(fieldName: String): Field? = generateSequence(this) { it.superclass } |
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.
Why it is not orNull
anymore?
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.
Renamed to findDirectAccessedFieldOrNull
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 comment
The 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 comment
The 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 TODO
removing. Are you sure it is resolved?
if (type.jClass.findDirectAccessedField(fieldId.name) != fieldId.field) | ||
CgFieldAccess(CgTypeCast(fieldId.declaringClass, this), fieldId) | ||
else | ||
CgFieldAccess(this, fieldId) |
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.
brackets
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.
fixed here
@@ -167,8 +165,8 @@ internal abstract class UtModelTestCaseChecker( | |||
/** | |||
* Finds field model in [UtCompositeModel] and [UtAssembleModel]. For assemble model supports direct field access only. | |||
*/ | |||
protected fun UtModel.findField(fieldName: String): UtModel = | |||
findField(this.classId.jClass.findField(fieldName).fieldId) | |||
protected fun UtModel.findField(fieldName: String, declarationClass: ClassId = this.classId): UtModel = |
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.
is declaration
the right word?
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.
replaced with declaring
@Override | ||
public String toString() { | ||
return b + ". Super b: " + super.b; | ||
} |
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.
Isn't it a forgotten method implementation?
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.
This override really seems useless, removed it
{ o, _ -> o == null }, | ||
{ _, r -> r == true }, | ||
{ _, r -> r == false}, | ||
coverage = DoNotCalculate |
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.
Why?
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.
added coverage here and to org.utbot.examples.objects.HiddenFieldExampleTest#testCheckSuccField
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 comment
The 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 TODO
removing. Are you sure it is resolved?
CgFieldAccess(this, fieldId) | ||
if (type.jClass.findDirectAccessedFieldOrNull(fieldId.name) != fieldId.field) { | ||
CgFieldAccess(CgTypeCast(fieldId.declaringClass, this), fieldId) | ||
} else { | ||
CgFieldAccess(this, fieldId) | ||
} |
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.
This functionality was just a shortcut for a CgFieldAccess
constructor. I don't think we should use more complex logic with additional checks here.
Also, this logic does not always work - there is no check that fieldId.declaringClass
is accessible, so there is possible situation with cast to a private class.
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.
What is the best place to move this logic to? Before calling this there are checks that fieldId
is accessible, aren't they enough?
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
if (element.caller is CgTypeCast) print("(") | ||
element.caller.accept(this) | ||
if (element.caller is CgTypeCast) print(")") |
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.
Why?
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.
If lhs is typecast, we need brackets for correct priority. Without this, the generated code will be like Succ as Super.f
and not (Succ as Super).f
.
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 comment
The 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.
Corresponding issue was finally solved in #763, closing this PR therefore. |
Description
Now if class has hidden fields, they can be recognized by engine and correct code for instantiation of such classes will be generated.
Fixes #563
Type of Change
Please delete options that are not relevant.
How Has This Been Tested?
Automated Testing
Switched
org.utbot.examples.objects.HiddenFieldExampleTest#testCheckSuccField
to enabled, addedorg.utbot.examples.objects.HiddenFieldAccessModifiersTest
Manual Scenario
Tested plugin on examples from #563 -- generates tests the way as expected.
Checklist (remove irrelevant options):
This is the author self-check list