Skip to content
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

Fix gathering inherited properties #2353

Closed

Conversation

BarkingBad
Copy link
Contributor

Enables gathering super fields/properties by PSI's. This PR depends on model changes introduced in #2326 so I leave it as a draft (it is rebased onto that branch in order to build correctly. Nonetheless, it can be reviewed as a single commit.

Copy link
Member

@vmishenev vmishenev left a comment

Choose a reason for hiding this comment

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

I have reviewed only 122c611 here.
Do you want to test InheritedMember in an extra?

@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch 2 times, most recently from 2f42d93 to 516ecaa Compare February 15, 2022 15:51
@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch from 516ecaa to c8f45ed Compare February 17, 2022 13:50
@BarkingBad BarkingBad marked this pull request as ready for review February 17, 2022 13:50
@IgnatBeresnev
Copy link
Member

I've merged the changes this PR is based on, can you resolve conflicts please?

@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch from c8f45ed to 925d45b Compare February 17, 2022 15:33
@BarkingBad
Copy link
Contributor Author

Rebased, should be good now

@BarkingBad
Copy link
Contributor Author

I've observed that the inhertited property is missing annotations, I will try to fix it that and include it in the tests

@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch 3 times, most recently from 19a1bb7 to 0bd5b63 Compare February 22, 2022 09:23
@BarkingBad
Copy link
Contributor Author

I know changes introduced in secondary commit are not directly coupled with the subject of the PR, but introduce small bugfixes that are related to the problem:

  • minor changes with parameters of functions transforming kotlin to java (context to logger, since it is more accurate)
  • fixed 2 smaller bugs with annotations and with names of accessors
  • fixed issue with top-level Property TagWrapper for java beans functions that inherit description from the kotlin property, since it doesn't make any sense

I can part it to smaller PRs if demanded

@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch 4 times, most recently from ac524d9 to f240e59 Compare February 23, 2022 18:35
return regularMethods.toList() to accessors.map { (dProperty, dFunctions) ->
if (dProperty.visibility.values.all { it is KotlinVisibility.Private }) {
dFunctions.flatMap { it.visibility.values }.toSet().singleOrNull()?.takeIf {
it in listOf(KotlinVisibility.Public, KotlinVisibility.Protected)
Copy link
Member

@IgnatBeresnev IgnatBeresnev Mar 1, 2022

Choose a reason for hiding this comment

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

I think this can be extracted into a variable with a name that explains intention (something like overridableVisibilities if I got the idea right), plus will avoid unnecessary allocation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will look into that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not necesarily overridability that we put emphasis on here, but rather we struggle with the proper visibility for property. The problem is, the java field will most likely be private and its accessors will be public/protected. We have to replace the visibility of the DProperty as it would be not visible in Kotlin. On the other hand I am now thinking about situation where we have public getter and private setter. That way we would like to have our DProperty to be public, yet be presented as val. Probably will have to rewrite the logic here...
I am also curious how dokka is handling private setter vars, is it rendering it like vals? I have to double check that

Copy link
Member

Choose a reason for hiding this comment

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

Do you need time to investigate it before we merge this PR? Can what you're talking about break something or introduce bugs?

nice comments btw, thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we should hardcode the configurations like these manually... I don't know if I have time to do it this week.

@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch from 13b1ab0 to bba621b Compare March 2, 2022 11:13
@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch from bba621b to bb746c9 Compare March 2, 2022 11:29
return regularMethods.toList() to accessors.map { (dProperty, dFunctions) ->
if (dProperty.visibility.values.all { it is KotlinVisibility.Private }) {
dFunctions.flatMap { it.visibility.values }.toSet().singleOrNull()?.takeIf {
it in listOf(KotlinVisibility.Public, KotlinVisibility.Protected)
Copy link
Member

Choose a reason for hiding this comment

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

Do you need time to investigate it before we merge this PR? Can what you're talking about break something or introduce bugs?

nice comments btw, thanks


/**
* This transformer is used to merge the backing fields and accessors (getters and setters)
* obtained from Java sources. This way, we could generate more coherent documentation,
Copy link
Member

@IgnatBeresnev IgnatBeresnev Mar 9, 2022

Choose a reason for hiding this comment

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

Is this transformer only applicable to java sources? If so:

  1. what do you think about renaming it to JavaPropertiesMergerTransformer?
  2. Can we somehow filter processed items and avoid processing kotlin classes? Does it make sense? Although I don't know if we have the ability to extract that info from DClass. Or maybe you already have that filter somewhere, e.g via KotlinVisibility?

My main concern is that if we don't limit it, then kotlin classes might satisfy the same conditions as Java and it'll introduce bugs (i.e not display getters/setters of a kotlin class for explicit declarations). If it's only java classes that are processed (somehow), should be safer.

But maybe this can never happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Technically it can happen, I am not sure how I could limit it to only Java classes. Do you have any idea?

Copy link
Member

Choose a reason for hiding this comment

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

@BarkingBad
Copy link
Contributor Author

I'll take a look tomorrow on that

Copy link
Member

@vmishenev vmishenev left a comment

Choose a reason for hiding this comment

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

I have discovered the same logic to merge accessors with fields in the different places: PropertiesMergerTransformer and DefaultPsiToDocumentableTranslator. What do you about extraction this logic from DefaultPsiToDocumentableTranslator into PropertiesMergerTransformer?

* declared and inheritedFrom as the same DRI but truncated callable part.
* Therefore, we set callable to null and take the DRI only if it is indeed coming from different class.
*/
val inheritedFrom = dri.copy(callable = null).takeIf { parent.dri.classNames != dri.classNames }
Copy link
Member

Choose a reason for hiding this comment

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

What is about classes with the same name but from the different packages?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Should it be parent.dri.classNames != dri.classNames || parent.dri.packageName != dri.packageName? If the classnames are equal we check if the package is different.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it should.

*
* Actually, the problem impacts more of these tags, yet this particular tag was blocker for
* some opens-source plugin creators.
* TODO: Should rethink if we could fix it globally in dokka or in compiler itself.
Copy link
Member

Choose a reason for hiding this comment

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

What solution do you suggest?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It could be fixed in the compiler. On the other hand, the compiler returns corresponding KDoc for some property etc. that is based on the positions of the original KDoc string, and therefore it is wrapped in the Property section, which is somehow correct. There could be some service in dokka to translate all of these, though one should rethink all the possibilities and cover them manually. Probably it won't be so hard afterall

@BarkingBad
Copy link
Contributor Author

BarkingBad commented Mar 14, 2022

I have discovered the same logic to merge accessors with fields in the different places: PropertiesMergerTransformer and DefaultPsiToDocumentableTranslator. What do you about extraction this logic from DefaultPsiToDocumentableTranslator into PropertiesMergerTransformer?

I honestly don't remember why I copied it (I know it is redundant, I warned about that), but don't remember the case when the properties won't be merged in PSI translator already.|

EDIT: At least, it is flipping the visibility of the property basing on its accessors, though I don't remember why I have to do it here, not in PSI translator.

EDIT 2: Ah, I finally recalled it! It is for things we inherit from Java but are from Kotlin class. The problem is, we get things from Descriptors but Java properties are not merged/processed. This transformer is for merging such properties. It also answers @IgnatBeresnev question about limiting this transformer to only Java sources. We cannot, since it is mainly for Kotlin sources, apparently.

@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch from fed49b3 to fecb1c2 Compare March 14, 2022 13:42
@BarkingBad BarkingBad force-pushed the fix-gathering-inherited-properties branch from fecb1c2 to 255925b Compare March 14, 2022 13:42
@vmishenev
Copy link
Member

So are there some blockers to merge accessors with fields only in PropertiesMergerTransformer?
I do not like we have the same code in the different places.
I suggested keeping all the fields and methods in DefaultPsiToDocumentableTranslator as is. Then PropertiesMergerTransformer can process them to merge accessors with properties.

It also answers @IgnatBeresnev question about limiting this transformer to only Java sources.

We need to merge properties only inside a Java class. Is it right? So is it possible to limit the transformer to only Java class?

@BarkingBad
Copy link
Contributor Author

Yes, we could limit it to be only in transformer and remove it from PSIs I think.

We need to merge properties only inside a Java class. Is it right? So is it possible to limit the transformer to only Java class?

Yes, we want to merge Java properties, but these can be coming from Descriptors, by inheriting from Java class in Kotlin. We cannot determine afaik from where the Documentable is coming, and if so, we should do it in DescriptorsToDocumentableTransformer then when we are on PSI / Descriptors layer of abstraction.

@BarkingBad
Copy link
Contributor Author

The reason I didn't refactor it was because I was short on time. I don't know if I will manage to fix it soon, so if you have time to remove the merging mechanisms from PSI please feel welcomed. It should not be that hard after all.

@vmishenev vmishenev self-requested a review March 15, 2022 15:19
@IgnatBeresnev
Copy link
Member

Hi!

The PR is starting to rot a little, there are some conflicts and new build errors. I've checked out your changes locally and rebased onto latest master, and I'm planning to remove duplicated code as we discussed above -- I know it's hard to find time for this, so we don't want to burden you too much with this :)

I'm closing this PR to preserve history (don't want to force-push over your commits and comments), but your changes have migrated to #2481 and will be merged after some additional changes. Thanks for your work!

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.

3 participants