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

Add setting to make fields created via code action final #2371

Merged
merged 1 commit into from Apr 18, 2024

Conversation

mfussenegger
Copy link
Contributor

Adds a new codeGeneration.newFieldsFinal boolean setting which changes
the behavior of the "Assign parameter to new field" code action to
declare the new field as final.

In many applications it's preferred to make classes immutable if
possible. In such cases making fields final by default saves some
tedious editing.

Comment on lines 268 to 271
Preferences prefs = PreferenceManager.getPrefs(compilationUnit.getResource());
if (isParamToField && prefs.getCodeGenerationNewFieldsFinal()) {
modifiers |= Modifier.FINAL;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this also used in other contexts where adding final wouldn't make sense?

Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at Eclipse's final cleanup (which was recently added as a cleanup action in https://github.com/eclipse/eclipse.jdt.ls/pull/2350/files#diff-c1fc3fbd7efda0e6e347dfc818586804aa68547c02b7c9abd75794e7a7481fadR46 .

eclipse-cleanup-final-prefs

So you could apply it to local variables, and even parameters. In this file I do see doAddparam, doAddLocal, but not sure how easy it is to accomplish that.

Another place this might go is in https://github.com/eclipse/eclipse.jdt.ls/blob/3400ec33d2b05e6ee639d90e2d3e1ed509c4b495/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/NewVariableCorrectionProposal.java#L391-L393

@mfussenegger mfussenegger marked this pull request as ready for review December 9, 2022 16:49
Copy link
Contributor

@rgrunber rgrunber left a comment

Choose a reason for hiding this comment

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

@fbricon , thoughts on having certain quick fixes / assists that create fields/parameters/locals add final by default (if possible) ?

@@ -435,6 +435,9 @@ public class Preferences {
// A named preference that defines the location to insert the code generated by source actions.
public static final String JAVA_CODEGENERATION_INSERTIONLOCATION = "java.codeGeneration.insertionLocation";

// A named preference that defines that fields created via code generation should be declared final
public static final String JAVA_CODEGENERATION_NEW_FIELDS_FINAL = "java.codeGeneration.newFieldsFinal";
Copy link
Contributor

Choose a reason for hiding this comment

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

It almost seems to me like we should just make adding final (if possible) the default, and not bother with a setting, since it's just too small of a case. If we did it in more places, then maybe we could have a general setting for "Add final to declarations whenever possible`.

Comment on lines 268 to 271
Preferences prefs = PreferenceManager.getPrefs(compilationUnit.getResource());
if (isParamToField && prefs.getCodeGenerationNewFieldsFinal()) {
modifiers |= Modifier.FINAL;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at Eclipse's final cleanup (which was recently added as a cleanup action in https://github.com/eclipse/eclipse.jdt.ls/pull/2350/files#diff-c1fc3fbd7efda0e6e347dfc818586804aa68547c02b7c9abd75794e7a7481fadR46 .

eclipse-cleanup-final-prefs

So you could apply it to local variables, and even parameters. In this file I do see doAddparam, doAddLocal, but not sure how easy it is to accomplish that.

Another place this might go is in https://github.com/eclipse/eclipse.jdt.ls/blob/3400ec33d2b05e6ee639d90e2d3e1ed509c4b495/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/corrections/proposals/NewVariableCorrectionProposal.java#L391-L393

@mfussenegger
Copy link
Contributor Author

thoughts on having certain quick fixes / assists that create fields/parameters/locals add final by default

Making it final by default sounds good to me, but I'd keep it limited to fields. Marking local variables as final is much more controversial and the benefit of doing that is more questionable.

@mfussenegger
Copy link
Contributor Author

Any other inputs on this? Should I change it to make fields (but not local variables) final by default?

@rgrunber
Copy link
Contributor

rgrunber commented Mar 20, 2024

Just as an update, this change now requires the work be done upstream because we de-duplicated a lot of the classes. If we can't get the work accepted so that Eclipse itself makes the modifier final, we can always change the API so it allows us to make customizations on our side.

These should handle Assign statement to new (local variable|field) & Create (local variable|field) ...

https://github.com/eclipse-jdt/eclipse.jdt.ui/blob/c7ecdcae923fcbd2b7333e2de0c8c7cf7bc28eae/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/proposals/AssignToVariableAssistProposalCore.java#L227

https://github.com/eclipse-jdt/eclipse.jdt.ui/blob/c7ecdcae923fcbd2b7333e2de0c8c7cf7bc28eae/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/proposals/AssignToVariableAssistProposalCore.java#L232

(for the above 2, we need to add varValue.modifiers().addAll(ast.newModifiers(Modifier.FINAL));

https://github.com/eclipse-jdt/eclipse.jdt.ui/blob/c7ecdcae923fcbd2b7333e2de0c8c7cf7bc28eae/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/proposals/NewVariableCorrectionProposalCore.java#L259

(in each of the if blocks, we need to make sure the new declaration has a line for : newDecl.modifiers().addAll(ast.newModifiers(Modifier.FINAL))

https://github.com/eclipse-jdt/eclipse.jdt.ui/blob/c7ecdcae923fcbd2b7333e2de0c8c7cf7bc28eae/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/proposals/AssignToVariableAssistProposalCore.java#L391

https://github.com/eclipse-jdt/eclipse.jdt.ui/blob/c7ecdcae923fcbd2b7333e2de0c8c7cf7bc28eae/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/proposals/NewVariableCorrectionProposalCore.java#L549

Update: I have a basic PR for jdt.core.manipulation that will introduce API that will allow us to set this on by default. I should have it merged soon, then this PR will become simpler.

@rgrunber
Copy link
Contributor

Based on discussion from #3111 (comment) , I guess we should have a setting.

@rgrunber
Copy link
Contributor

rgrunber commented Apr 4, 2024

@mfussenegger , let me know if this works for your needs. It should cover quite a few quick assists. Setting is java.codeGeneration.addFinalForNewDeclaration, with values none, variables, fields, all .

I might add a few more testcases.

@mfussenegger
Copy link
Contributor Author

@mfussenegger , let me know if this works for your needs. It should cover quite a few quick assists. Setting is java.codeGeneration.addFinalForNewDeclaration, with values none, variables, fields, all .

I might add a few more testcases.

Did a quick test and it seems to work as expected. Thanks for picking this up

@rgrunber
Copy link
Contributor

Just noticed that the "Create (local variable|field)" doesn't actually work because we have no way to override the false value that the underlying API sets when calling the constructor to create the proposal (I was trying to avoid having addFinal be the default upstream). The proposal gets passed to JDT-LS so we can modify it, if the API just had some simple NewVariableCorrectionProposalCore.setAddFinal(boolean).

@rgrunber rgrunber force-pushed the new-fields-final branch 2 times, most recently from c9e4853 to 60b34e7 Compare April 18, 2024 14:23
- Adds `java.codeGeneration.addFinalForNewDeclaration` setting
which changes the behavior of the "Assign statement to new (local
variable|field)", "Create (local variable|field)", "Assign parameter to
new field", "Assign all parameters to new fields".
- Possible values are  "none", "variables", "fields", "all"
- Fix up some test cases for ease of understanding
- Update target platform to 4.32-I-builds/I20240417-1800

Signed-off-by: Roland Grunberg <rgrunber@redhat.com>
@rgrunber rgrunber self-assigned this Apr 18, 2024
@rgrunber rgrunber merged commit b090203 into eclipse-jdtls:master Apr 18, 2024
7 checks passed
@rgrunber
Copy link
Contributor

Thanks for proposing this. I think I could have probably made some constants for "all", "variables", "fields" but let's see if this needs to evolve / include more cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants