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 whitespace check capability and ParenPadQuickFix #298

Open
wants to merge 20 commits into
base: master
Choose a base branch
from

Conversation

karlvr
Copy link
Contributor

@karlvr karlvr commented Jan 14, 2021

I've had to introduce a new quick fix type. I've tried to minimise the changes, but perhaps BaseQuickFix should be renamed to BaseASTQuickFix.

(I've also implemented this for the fix all, but I'll add that if / when we merge fix all)

@karlvr
Copy link
Contributor Author

karlvr commented Jan 14, 2021

@jdneo I've made a few more improvements to the application of these edit quick fixes, so that we don't apply more than one to a line... because they can conflict a little! I might try to merge those improvements into this PR without adding the additional checks, but I can't PR the additional checks until we land the actual introduction of this different type of quick fix! So if you have a moment to check this out and comment that would make my branch juggling a little easier ;-)

@jdneo
Copy link
Owner

jdneo commented Jan 15, 2021

@karlvr Ok, I'll review this PR first. Thanks.

@karlvr
Copy link
Contributor Author

karlvr commented Jan 15, 2021

@jdneo thank you; I've just checked. My aforementioned improvements to the application of these edit quick fixes actually only applies (of course) to the "fix all" support. Without meaning to be super cheeky, once / if you're happy with the "fix all" then I'll land that piece! This one is good to go as is 🤞

astRoot.accept(((BaseQuickFix) quickFix).getCorrectingASTVisitor(lineInfo, offset.intValue()));
final TextEdit edit = astRoot.rewrite(document, null);
return EditUtils.convertToWorkspaceEdit(unit, edit);
} else if (quickFix instanceof BaseEditQuickFix) {
Copy link
Owner

Choose a reason for hiding this comment

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

For simplicity, how about write the if block as

if (quickFix instanceof BaseQuickFix) {
    ...
} else if (quickFix instanceof BaseEditQuickFix) {
    final TextEdit edit = ((BaseEditQuickFix) quickFix).createTextEdit(lineInfo, offset.intValue(), document);
    if (edit != null) {
        return EditUtils.convertToWorkspaceEdit(unit, edit);
    }
}

return null;

@jdneo
Copy link
Owner

jdneo commented Jan 15, 2021

From the implementation, it looks like we are deleting spaces in the parentheses. For example: switch( n ) -> switch(n)

But according to the document: https://checkstyle.sourceforge.io/property_types.html#PadOption

The PadOption can be nospace,space, which means whether adding/deleting the spaces actually relies on how the rule is configured.

@karlvr I'm afraid that simply removing the spaces is not enough for this fix.

@karlvr
Copy link
Contributor Author

karlvr commented Jan 15, 2021

@jdneo yes! I would love to work out how to determine what the option to the check was! It doesn't appear that Checker provides a way to interrogate the checks it uses. Do you know of a way to do that? Alternatively we could perhaps inject the diagnostic message as well, and work out what to do based on the message to the user?

(Who are these people adding spaces inside the parentheses?!)__

@karlvr
Copy link
Contributor Author

karlvr commented Jan 19, 2021

I'm trying to figure out how to read the Checkstyle configuration to solve the above...

@karlvr karlvr force-pushed the quickfix-whitespace branch from 2369648 to 348c685 Compare January 20, 2021 05:50
@karlvr
Copy link
Contributor Author

karlvr commented Jan 20, 2021

@jdneo I haven't yet looked into how to read the Checkstyle configuration, but I have pushed changes to allow these edits to work in the "fix all" mode, and added a couple more whitespace-related quick fixes.

@karlvr
Copy link
Contributor Author

karlvr commented Jan 24, 2021

@jdneo It looks like we could use ConfigurationLoader.loadConfiguration to load the Checkstyle DefaultConfiguration and then explore it, looking for how things are configured in order to resolve #298 (comment) but I don't think that will work generally... there could be multiple configurations for a check, matching different files... I think it might get messy.

I'm exploring examining the diagnostic message to determine how to fix it. In the Checkstyle source I see this documentation on LocalizedMessage.getKey():

Returns the message key to locate the translation, can also be used in IDE plugins to map audit event messages to corrective actions.

So I think this is the right track.

This will provide more information to the quick fixes about exactly what the violation was, so the quick fix can respond to the configuration.
@karlvr
Copy link
Contributor Author

karlvr commented Jan 25, 2021

@jdneo I have resolved the issue that you raised about regarding PadOption in the ParenPadQuickFix.

I've noticed an issue, however, when an AST fix and a whitespace fix coincide:

public static void main(String[] args) {

becomes

public static void main(final  String[] args ) {

when ParenPadCheck is configured with space and FinalParametersCheck is included.

<module name="TreeWalker">
	<module name="FinalParameters" />
	<module name="ParenPad">
		<property name="option" value="space" />
	</module>
</module>

e.g.

public static void main(String[] args) {

becomes

public static void main(final  String[] args ) {

under

<module name="TreeWalker">
	<module name="FinalParameters" />
	<module name="ParenPad">
		<property name="option" value="space" />
	</module>
</module>
@karlvr
Copy link
Contributor Author

karlvr commented Jan 25, 2021

@jdneo OK, there are a bunch of whitespace-related quick fixes in here. It taking implementing a few to end up with a reasonable pattern I think. Please take it for a spin where you get a chance.

final IRegion lineInfo = document.getLineInformationOfOffset(offset);
astRoot.accept(quickFix.getCorrectingASTVisitor(lineInfo, offset));
final IRegion lineInfo = document.getLineInformationOfOffset(offset);
final IQuickFix quickFix = getQuickFix(sourceNames.get(i));
Copy link
Owner

Choose a reason for hiding this comment

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

resolve the quickFix at first and continue the loop if it's null to reduce unnecessary calculation?


if ("ws.illegalFollow".equals(violationKey)) {
return new InsertEdit(markerStartOffset + 1, " ");
} else if ("ws.notPreceded".equals(violationKey)) {
Copy link
Owner

Choose a reason for hiding this comment

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

It would be better if we can directly reference the static const defined in the Checkstyle lib, seems it's not easily achievable given the current OSGi framework. 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jdneo yes, I agree. I don't have experience with OSGi or how all of those dependencies are setup so I took the path of least resistance.

* Quick fix for
* https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/checks/whitespace/MethodParamPadCheck.html
*/
public class MethodParamPadQuickFix extends BaseEditQuickFix {
Copy link
Owner

Choose a reason for hiding this comment

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

Seems not handle well with:

<module name="MethodParamPad">
  <property name="tokens" value="METHOD_DEF"/>
  <property name="option" value="space"/>
  <property name="allowLineBreaks" value="true"/>
</module>

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jdneo when I test this, Checkstyle reports that the "(" is not preceded by whitespace, and the quick fix adds a space before the "(". That seems like it's doing the right thing to me?

final String lastChar = doc.getLength() > 0 ? doc.get(doc.getLength() - 1, 1) : "";

if (lastChar.isEmpty() || !"\n".equals(lastChar)) {
return new InsertEdit(doc.getLength(), "\n");
Copy link
Owner

Choose a reason for hiding this comment

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

\n might not be enough. Given this rule has the options:

<property name="lineSeparator" value="lf"/>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jdneo hmm, yes; given the error that is reported doesn't specify what it's looking for, I think the best we can do is assume the default (which looks for any of CR LF or CRLF) and then adds the platform-specific version.

Or we could simply add the platform specific version.

Is it handy enough to fix these things that it might be wrong sometimes? Or should we more actively pursue getting Checkstyle to expose its internal configuration? My forays into the code suggest that it doesn't want to.

@karlvr
Copy link
Contributor Author

karlvr commented Mar 2, 2021

@jdneo just a ping to see if you have bandwidth to pick this back up?

@jdneo
Copy link
Owner

jdneo commented Mar 3, 2021

@karlvr Sorry I was busy with some other stuffs, will try to take a look some time by the end of this week.

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.

2 participants