Skip to content

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

Closed

Conversation

volivan239
Copy link
Collaborator

@volivan239 volivan239 commented Jul 26, 2022

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.

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

Automated Testing

Switched org.utbot.examples.objects.HiddenFieldExampleTest#testCheckSuccField to enabled, added org.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

  • The change followed the style guidelines of the UTBot project
  • Self-review of the code is passed
  • The change contains enough commentaries, particularly in hard-to-understand areas
  • New documentation is provided or existed one is altered
  • No new warnings
  • New tests have been added
  • All tests pass locally with my changes

@volivan239 volivan239 changed the title Add support for classes with hidden fields Add support for classes with hidden fields #563 Jul 26, 2022
@volivan239 volivan239 marked this pull request as ready for review July 28, 2022 07:27
}
}
.firstOrNull()
fun Class<*>.findDirectAccessedField(fieldName: String): Field? = generateSequence(this) { it.superclass }
Copy link
Member

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

Copy link
Collaborator Author

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()
Copy link
Member

Choose a reason for hiding this comment

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

Why not findField anymore?

Copy link
Collaborator Author

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

Comment on lines 289 to 290
if (this.isNotSubtypeOf(fieldId.declaringClass))
return null
Copy link
Member

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

Copy link
Collaborator Author

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
Copy link
Member

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

Copy link
Collaborator Author

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 }
Copy link
Member

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?

Copy link
Collaborator Author

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)) {
Copy link
Member

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

Copy link
Member

@Damtev Damtev Jul 29, 2022

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?

Comment on lines 79 to 82
if (type.jClass.findDirectAccessedField(fieldId.name) != fieldId.field)
CgFieldAccess(CgTypeCast(fieldId.declaringClass, this), fieldId)
else
CgFieldAccess(this, fieldId)
Copy link
Member

Choose a reason for hiding this comment

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

brackets

Copy link
Collaborator Author

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 =
Copy link
Member

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?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

replaced with declaring

Comment on lines 6 to 9
@Override
public String toString() {
return b + ". Super b: " + super.b;
}
Copy link
Member

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?

Copy link
Collaborator Author

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
Copy link
Member

Choose a reason for hiding this comment

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

Why?

Copy link
Collaborator Author

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

@volivan239 volivan239 requested a review from CaelmBleidd July 29, 2022 14:26
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)) {
Copy link
Member

@Damtev Damtev Jul 29, 2022

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?

Comment on lines -75 to +83
CgFieldAccess(this, fieldId)
if (type.jClass.findDirectAccessedFieldOrNull(fieldId.name) != fieldId.field) {
CgFieldAccess(CgTypeCast(fieldId.declaringClass, this), fieldId)
} else {
CgFieldAccess(this, fieldId)
}
Copy link
Member

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.

Copy link
Collaborator Author

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

Comment on lines +124 to +126
if (element.caller is CgTypeCast) print("(")
element.caller.accept(this)
if (element.caller is CgTypeCast) print(")")
Copy link
Member

Choose a reason for hiding this comment

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

Why?

Copy link
Collaborator Author

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.

Copy link
Member

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.

@volivan239 volivan239 removed the request for review from EgorkaKulikov August 1, 2022 11:49
@volivan239
Copy link
Collaborator Author

After discussion with @Damtev and @ArsenHD it was decided to merge into main only changes concerning engine (#627) so far. It was also decided to leave codegen untouched until @ArsenHD finishes his changes in codegen so we would have more rational ways of dealing with field hiding there.

@volivan239
Copy link
Collaborator Author

volivan239 commented Sep 7, 2022

Corresponding issue was finally solved in #763, closing this PR therefore.

@volivan239 volivan239 closed this Sep 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Errors in test generation when there is variable hiding in src code
3 participants