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 java completion sort for not-imported items. #7631

Merged
merged 1 commit into from
Aug 6, 2024

Conversation

mbien
Copy link
Member

@mbien mbien commented Aug 2, 2024

LazySortText implements CharSequence but misses a toString() method.

Without it, it would use Object#toString(), and since it is used as comparator input, it would lead to undesired results.

This was the case with 'List.of' for example. ('List' must not have an import yet)

before
completion-sort-issue_before

after
completion-sort-issue_fixed

test

public class Mavenproject1 {
    public static void main(String[] args) {
        // use completion after 'of'
        java.util.Set.of; // sort works
        List.of;          // sort fails
    }
}

assignment (enclSortText can be of type String or LazySortText):

if (this.autoImportEnclosingType) {
this.enclSortText = new LazySortText(elem.getEnclosingElement().getSimpleName().toString(), null, ElementHandle.create((TypeElement)elem.getEnclosingElement()), referencesCount);
} else {
this.enclSortText = ""; //NOI18N
}

search token:

sortText = simpleName + "#" + enclSortText + "#" + ((cnt < 10 ? "0" : "") + cnt) + "#" + sortParams.toString(); //NOI18N

comparator:

int alphabeticalDiff = compareText(i1.getSortText(), i2.getSortText());
return alphabeticalDiff;

@mbien mbien added Java [ci] enable extra Java tests (java.completion, java.source.base, java.hints, refactoring.java, form) ci:dev-build [ci] produce a dev-build zip artifact (7 days expiration, see link on workflow summary page) labels Aug 2, 2024
@mbien mbien added this to the NB23 milestone Aug 2, 2024
@mbien
Copy link
Member Author

mbien commented Aug 2, 2024

i checked if I could add a test but couldn't find existing tests which verify full completion results. They seem to typically implement one result only.

Copy link
Contributor

@matthiasblaesing matthiasblaesing left a comment

Choose a reason for hiding this comment

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

I think this need review from @dbalek. Looking at the charAt method I have to conclude, that string concatenation was deemed expensive, else this whole class makes no sense and that raises the question how often the new codepath is actually hit.

If I see this correctly this codepath will be hit by FieldItem and MethodItem, which both modify the sortText with the enclosing element, while ClassItem, LazyJavaCompletionItem and StaticMemberItem.

Looking at LazySortText further I see enclName as parameter. It is unclear ,why it FieldItem and MethodItem don't use that.

In general I see why this change is done, I can reproduce the problem and verified it fixes the problem, so I'm leaning to a +1.

@mbien
Copy link
Member Author

mbien commented Aug 3, 2024

I believe it is safe to say (given the name) that the purpose of the class is delayed evaluation of the full char sequence. My hypothesis is that charAt was only implemented since it was required by the interface, toString has been overlooked though - since Object has a default impl - so this would be plausible.

I could be wrong but my guess is that charAt is a red hering - the main purpose of this is lazy init. (even if the original idea was to sort by partially evaluate the char sequence via charAt, it doesn't seem to be used that way now - it only cares about the full string)

regarding performance,

the value is cached, so toString should only be called once per item - i am pretty sure I checked this by setting a breakpoint.

Looking at LazySortText further I see enclName as parameter. It is unclear ,why it FieldItem and MethodItem don't use that.

yes I did wonder about this too

@mbien
Copy link
Member Author

mbien commented Aug 3, 2024

but this shows again that impls need documentation, a single comment on top of that class would have made this much easier!

Copy link
Contributor

@matthiasblaesing matthiasblaesing left a comment

Choose a reason for hiding this comment

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

Ok - lets get this in - it fixes a real problem.

@mbien mbien force-pushed the java-completion-sort-fix_delivery branch from 9d7183d to 4b9ac49 Compare August 3, 2024 22:41
@mbien
Copy link
Member Author

mbien commented Aug 3, 2024

made a small change since the sortText value for FieldItem wasn't cached like in MethodItem.

I did also take another look at this and LazySortText#charAt was never called before this change here, due to the fact that the CharSequence got concatenated to other Strings using its default toString() method.

Now its called while toString() is building the String, which happens once per item.

LazySortText implements CharSequence but missed a toString() method.

It would use Object#toString() and since it is used as
comparator input, it lead to undesired results.

This was the case with 'List.of' for example. ('List' must not have an
import yet)

This commit introduces utility methods which allow the linking
of CharSequences like LazySortText without toString() concatenation.
@mbien mbien force-pushed the java-completion-sort-fix_delivery branch from 4b9ac49 to 08d86f1 Compare August 4, 2024 01:43
@mbien
Copy link
Member Author

mbien commented Aug 4, 2024

I implemented it properly with a utility class which can link CharSequences. This comes close to the original performance while also sorting correctly and fixing this issue. Tested with some synthetic files which had 10k fields and methods.

Copy link
Contributor

@matthiasblaesing matthiasblaesing left a comment

Choose a reason for hiding this comment

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

Looks sane to me and the new solution looks elegant.

@ebarboni ebarboni merged commit 1e7ab53 into apache:delivery Aug 6, 2024
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci:dev-build [ci] produce a dev-build zip artifact (7 days expiration, see link on workflow summary page) Java [ci] enable extra Java tests (java.completion, java.source.base, java.hints, refactoring.java, form)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants