Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Remove usages of getPsi() #2901
base: master
Are you sure you want to change the base?
Remove usages of getPsi() #2901
Changes from 16 commits
7f8984c
2562354
a05595f
1b76046
546dfca
5f0f4a8
7e2f282
bd1596b
d0c798e
0058330
a10fd38
94624ba
e962b64
c8d1a54
efd32be
6094819
e2846c1
fe71a48
d92140d
ffda19b
3efbf7a
cb757a9
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
Function
getPrevSiblingIgnoringWhitespaceAndComments
is duplicate ofprevCodeSibling
. Note that Psi is a java interface, and as of that is using theget
prefix. For theASTNodeExtensions
we should prefer kotlin naming style withoutget
prefix.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.
Good point. Deleted
getPrevSiblingIgnoringWhitespaceAndComments
.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.
In
SpacingBetweenDeclarationsWithCommentsRule
the PSI version ofgetPrevSiblingIgnoringWhitespaceAndComments
is used. I was trying to see whether I could refactor the code below, to not usepsi
:I could not (easily) find an angle how to replace
KtDeclaration
with anASTNode
implementation. Can you give me a pointer how to approach that? You don't need to implement it, but I would learn to know for myself how I could do that.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 all very trial and error for me, but I was able to implement a solution for
SpacingBetweenDeclarationsWithCommentsRule
. It involvesKtTokenSets.DECLARATION_TYPES
, which is probably the key for getting rid of theis
checking ofKtDeclaration
.I won't commit the implementation since you asked to try it yourself. But here it is for your reference:
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.
The question was indeed, how should I have gotten the idea to use
KtTokenSets.DECLARATION_TYPES
instead ofis KtDeclaration
? Could you derive that somehow from the Psi library, or did you find this accidentally while exploring the lib?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 essentially found it accidentally. I either searched for the term "declaration" in the kotlin repository or I found it while reading through the members of
KtTokenSets
. I am making the assumption that the word "declaration" is used consistently in the Psi class hierarchy and inKtTokenSets
to define the same set of node types. I then checked all the ktlint tests still passed.If we wanted to be even more sure, I have at least one idea:
KtTokenSets.DECLARATION_TYPES
, navigate to its associated Psi type. For example, looking atKtStubElementTypes.CLASS
, we see it is aKtClassElementType
. Looking at theKtClassElementType.kt
we can see it is assocaited with the Psi typeKtClass
, which we can figure out implementsKtDeclaration
.KtTokenSets.DECLARATION_TYPES
.This would obviously be a lot of work. Here are my follow up thoughts about it.
KtDeclaration
.KtTokenSets.DECLARATION_TYPES
andKtDeclaration
, then I suppose we will find out when someone makes a bug report and we could react accordingly.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 those token sets based on information from the Psi Interface? If so, please add comment with references/links. If tokes are added or removed in the future from the Psi Interface, this makes it easier to keep our token sets in sync with Psi.
Also, I prefer to keep the elements in such collection sorted alphabetically.
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.
No, I didn't get this from a specific source unfortunately. When I mentioned that there might be bugs, these token sets are one of my biggest worries. Like
EXPRESSIONS
, I'm afraid it could be missing something that didn't get covered by a test.I alphabetized the lines.
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.
The kotlin compiler has some like
KtTokenSets
but I am not sure if I've seen one with all expressions.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 rather concerning.
https://kotlinlang.org/docs/reference/grammar.html#expression gives some insights, but it can not be simply match to the tokens either.
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 did some more searching, and found a lot more examples of public TokenSet instances in the kotlin repository. I regret not looking harder before. I'm going to try to see if I can replace my token sets with established ones from the kotlin repistory.
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.
Here is what I did:
COMMENTS
, I was able to use one from the kotlin compiler directlyCONTROL_FLOW_KEYWORDS
, I was able to copy and paste a subset ofKotlinExpressionParsing.EXPRESSION_FIRST
. This added a few, but still all tests pass. Should be more maintainable.EXPRESSIONS
, I could not find anything even close that could serve as a reference. So instead, I asked "why do we need this anyway if aparently nobody else has ever needed it?". I found the one usage (inNoUnusedImportsRule
), removed it, checked all tests pass, and then removedTokenSets.EXPRESSIONS
.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.
While I was editing
NoUnusedImportsRule
I tried to pick up a conceptual understanding of why this token set was being used inparentCallExpressionOrNull
, but I could not figure it out.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 do you think of adding:
so that this can be written as:
which nicely aligns with the
findChildByType(ElementType)
function of the embedded Kotlin compiler?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 agree, I was thinking of adding a function like this.
Can we leave it without a kdoc since the name is self explanatory? I feel like a kdoc would say "Finds a child with type
elementType
recursively", which is pretty redundant with the name of the function.I notice a bunch of other public functions in this file don't have a kdoc.
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 a test 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.
True, I was aware of the latter. For Ktlint contributors it would suffice, to not document. But those extensions are also meant to be used by external rule providers which might not be familiar with ktlint that much. By providing the API docs, we make it slightly better for them.
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 is now a kdoc for
findChildByTypeRecursively
.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 this token set based on information from the Psi Interface? If so, please add comment with references/links. If tokes are added or removed in the future from the Psi Interface, this makes it easier to keep our token sets in sync with Psi.
What would be your policy for creating such token sets inside the
TokenSets.kt
or within a class as long as there is only one usage? When this token set is derived from Psi, I am inclined to define it insideTokenSets.kt
.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.
No, as with the other token sets I created I do not think that this was based on another source such as psi. I basically figured it out by adding element types until all tests passed. Sorry I did not say this earlier, as this is the biggest weak spot of this PR in terms of possible bugs and maintainability.
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.
Personally, I would lean towards centralizing all token sets into
TokenSets.kt
. Based on the times I have tried to skim Psi for token sets, I don't think I found much of use. So I am not sure if "being derived from psi" would be a realistic standard as many or even most of ktlint's token sets might have to be original.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.
But we may need to give psi a closer look. I only skimmed it lightly and could be wrong.
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.
As said before, this is indeed concerning. In order to test this we would need some big code bases that do not use ktlint. Next we could format both code bases with ktlint version without your changeset, and once more with another version including your changeset. Both versions should provide the same results. Doing this with code bases which are already formatted with ktlint might not reveal all problems.
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 an interesting idea. Maybe this should be integrated into the project as a test in general? A single "integration" test that does what you describe might be heavy but probably worthwhile so that refactorings like this are safer.
I'm imagining a full large, unformatted kotlin project sitting inside of a test resources folder. Another file adjacent to the root of that folder could be a csv where one column is the relative path of each file and another file is the hash of the expected file contents after formatting. I think you might see where I'm going with 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.
I'd personally like to avoid having to imlpement such a test though, only because it might take an uncomfortably long time to develop (though I think it could be a great addition to this project, if you feel you have the time). Instead, I have explored a different solution to making this safer and more maintainble. See my commit "alternative to token set" where I do something a bit hacky, but that actually might be more safe and maintainable. That is, to create dummy psi elements from ASTNode and then using
is
checking as before (likeis KtAnnotated
). I'm not 100% sure this is performant, but I would think it likely is since the dummy elements can be cached. If you like this strategy, it might be generalizable to other places as well as an alternative to making customTokenSet
instances.