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 CatchCauseOnlyRethrows onlyRethrows check for multi catch statements #355

Merged

Conversation

nielsdebruin
Copy link
Contributor

What's changed?

This pull request includes changes to the CatchClauseOnlyRethrows class and its corresponding test class to improve the handling of multi-catch blocks and simplify the code.

Improvements to CatchClauseOnlyRethrows class:

Enhancements to test coverage:

What's your motivation?

Consider the following input:

class A {
  void foo() throws IOException {
      try {
          new FileReader("").read();
      } catch (FileNotFoundException e) {
          throw e;
      } catch(IOException | ArrayIndexOutOfBoundsException e) {
          throw e;
      }
  }
}

Currently, no suggestions are provided to remove the redundant catch (FileNotFoundException e) block. The issue stems from the onlyRethrows method not functioning correctly with multi-catch statements. For a J.Try.Catch the onlyRethrows method will perform the following check:

  1. The catch body contains a single statement of type J.Throw.
  2. The J.Throw exception type matches the catch parameter type.
  3. The J.Throw statement contains an identifier that matches the catch parameter.

The problem lies with the second check. For catch (IOException e), the check passes since e is assigned to IOException. However, for catch (IOException | ArrayIndexOutOfBoundsException e), the type of e becomes Exception, causing the check to fail.

Fortunately, I believe the second check is unnecessary. If the throw contains only a single statement of type J.Throw (check 1), and this throws only contains a J.Identifier pointing to the catch parameter, there’s no chance of modifying e. Hence checking for type changes is not required. This change resolves the issue with multi-catch statements and improves method efficiency.

Anything in particular you'd like reviewers to focus on?

Anyone you would like to review specifically?

Have you considered any alternatives or workarounds?

Any additional context

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

github-actions[bot]

This comment was marked as off-topic.

@Laurens-W Laurens-W added the bug Something isn't working label Oct 7, 2024
@timtebeek timtebeek self-requested a review October 7, 2024 12:31
Comment on lines 113 to 116
JavaType.FullyQualified catchType = TypeUtils.asFullyQualified(aCatch.getParameter().getType());
if (catchType == null || !catchType.equals(exception.getType())) {
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of removing this check, I wonder if we should add an additional check with something like if (catchType instanceof JavaType.MultiCatch) { ... check if any of the thrown exceptions matches ... }. I'd feel slightly more secure with such an approach then dropping this requirement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi Tim, Thanks for the review! I am not sure how to implement this check....

In the base case e.g. catch(A ex) {throw ex} type A is assigned to ex in the body. Hence we can compare the type of the catch parameter ex that of the body. In the multicatch, catch (A | B ex) {throw ex} both ex in the body and parameter will be assigned type Exception, as it is not know if they will be of type A or B. Using JavaType.MultiCatch.getThrowableTypes I can retrieve the possible types the parameter ex can take, but the I can't compare them with the type of ex in the body as this will still be of type Exception.

Choose a reason for hiding this comment

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

If we can't determine it based on type then maybe in case of a MultiCatch we could check whether exception is an identifier and if it is whether it's the same identifier as aCatch.getParameter()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Isn't that already checked on line 114?

if (exception instanceof J.Identifier) {
    return ((J.Identifier) exception).getSimpleName().equals(aCatch.getParameter().getTree().getVariables().get(0).getSimpleName());
}

Choose a reason for hiding this comment

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

Ah yes, missed that part! Though checking by name is potentially more dangerous than checking by reference.
Not sure what direction to go here then

@timtebeek
Copy link
Contributor

@nielsdebruin & @Laurens-W would you agree with the change I pushed in 6b39457 ?

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Some suggestions could not be made:

  • src/main/java/org/openrewrite/staticanalysis/ChainStringBuilderAppendCalls.java
    • lines 35-35
  • src/main/java/org/openrewrite/staticanalysis/UseCollectionInterfaces.java
    • lines 28-28
    • lines 59-60

@nielsdebruin
Copy link
Contributor Author

@nielsdebruin & @Laurens-W would you agree with the change I pushed in 6b39457 ?

As mentioned in the PR description I don't think this extra check is required, however, it certainly cannot be harmful. So I agree with it.

@timtebeek
Copy link
Contributor

@nielsdebruin & @Laurens-W would you agree with the change I pushed in 6b39457 ?

As mentioned in the PR description I don't think this extra check is required, however, it certainly cannot be harmful. So I agree with it.

Yeah it's happened a few too many times that I thought "we don't need that" only to later realize we did indeed need that, we'd just lacked a test for it. So figured be slightly more conservative with the change for now. Thanks though!

@timtebeek timtebeek merged commit d24228b into openrewrite:main Oct 22, 2024
2 checks passed
@nielsdebruin nielsdebruin deleted the multi-catch-only-throws-support branch October 22, 2024 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants