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

review: fix: do not remove constructor parameters from inner classes #4734

Merged
merged 7 commits into from
Jun 4, 2022

Conversation

SirYwell
Copy link
Collaborator

@SirYwell SirYwell commented May 21, 2022

Previously, one parameter was deleted for each nesting level. However, only one parameter exists for the direct enclosing class.

SirYwell and others added 3 commits May 21, 2022 18:03
Co-authored-by: I-Al-Istannen <i-al-istannen@users.noreply.github.com>
Co-authored-by: Martin Wittlinger <wittlinger.martin@gmail.com>
@SirYwell SirYwell marked this pull request as ready for review May 21, 2022 18:13
@SirYwell SirYwell changed the title wip: fix: do not remove constructor parameters from inner classes review: fix: do not remove constructor parameters from inner classes May 21, 2022
@SirYwell
Copy link
Collaborator Author

@monperrus @slarse could one of you review this? @MartinWitt co-authored the fix, therefore someone else should take a second look at it. Thanks!

@slarse
Copy link
Collaborator

slarse commented May 31, 2022

@monperrus @slarse could one of you review this? @MartinWitt co-authored the fix, therefore someone else should take a second look at it. Thanks!

I can have a look tonight.

Copy link
Collaborator

@slarse slarse left a comment

Choose a reason for hiding this comment

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

@SirYwell I'm a little bit confused about Parameter.isImplicit(), see question in code.

RtParameter[] parametersOf = RtParameter.parametersOf(constructor);
Parameter[] parameters = constructor.getParameters();
for (int i = 0; i < parametersOf.length; i++) {
if (parameters[i].isImplicit()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looking at the coverage, this branch is never taken by the tests. Yet I would expect the test added to execute this branch as the code is compiled with Java >8. Trying this locally with JDK 11 (both OpenJDK and Amazon Coretto), isImplicit() returns false for clearly implicit parameters.

@SirYwell can you explain this to me?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's complicated. Since Java 8, the JLS says that

  1. A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter declared implicitly in source code

(JLS 13.1)

However, javac only does this when compiling with the -parameters flag. See https://mail.openjdk.java.net/pipermail/compiler-dev/2022-May/019783.html for more context.

So ih theory, it's the best way to figure out if a parameter is implicit, but in practice, it would require the compiler to keep to the spec.

Copy link
Collaborator

@slarse slarse Jun 1, 2022

Choose a reason for hiding this comment

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

I see. Then I suggest extracting the implicitness check into a separate method and put all of the relevant information required to understand why it's so funky in the Javadoc (for example the stuff you wrote above). Something like this:

/**
 * Determine if the constructor parameter is is implicit.
 *
 * This is a great description of why this is so weird.
 */
private boolean isImplicitParameter(Parameter parameter, Constructor constructor, boolean isFirstParameter) {
    // do isImplicit() and "best guess" checks
}

It doesn't have to be exactly like that, but just provide any information required into the method such that it can perform the checks. The implementation of Constructor.getParameters() looks rather heavy so we probably don't want to call it multiple times.

There are a lot of places in Spoon where weird corner cases aren't adequately explained, so I'm trying to make a push for... explaining them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I extracted the relevant code into its own method now.

RtParameter[] parametersOf = RtParameter.parametersOf(constructor);
Parameter[] parameters = constructor.getParameters();
for (int i = 0; i < parametersOf.length; i++) {
if (parameters[i].isImplicit()) {
Copy link
Collaborator

@slarse slarse Jun 1, 2022

Choose a reason for hiding this comment

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

I see. Then I suggest extracting the implicitness check into a separate method and put all of the relevant information required to understand why it's so funky in the Javadoc (for example the stuff you wrote above). Something like this:

/**
 * Determine if the constructor parameter is is implicit.
 *
 * This is a great description of why this is so weird.
 */
private boolean isImplicitParameter(Parameter parameter, Constructor constructor, boolean isFirstParameter) {
    // do isImplicit() and "best guess" checks
}

It doesn't have to be exactly like that, but just provide any information required into the method such that it can perform the checks. The implementation of Constructor.getParameters() looks rather heavy so we probably don't want to call it multiple times.

There are a lot of places in Spoon where weird corner cases aren't adequately explained, so I'm trying to make a push for... explaining them.

Copy link
Collaborator

@slarse slarse left a comment

Choose a reason for hiding this comment

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

Thanks @SirYwell, looks good to me! I've left an optional comment that you can do something about if you'd like, but it's a tiny comment and I'm perfectly fine with merging this as-is if you disagree (but let me know which one you decide on).

Comment on lines 340 to 343
if (isFirstParameter && parameter.getType() == constructor.getDeclaringClass().getEnclosingClass()) {
return true;
}
return false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional comment: You could contract this into a single return statement.

Suggested change
if (isFirstParameter && parameter.getType() == constructor.getDeclaringClass().getEnclosingClass()) {
return true;
}
return false;
return isFirstParameter && parameter.getType() == constructor.getDeclaringClass().getEnclosingClass()

IMO it's better to just return like this, but I've met people who disagree so I'll leave it up to you if you want to change it or not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I applied the suggested change.

Copy link
Collaborator

@slarse slarse left a comment

Choose a reason for hiding this comment

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

Thanks @SirYwell. This was deceptively complicated.

@slarse slarse merged commit 10bf22e into INRIA:master Jun 4, 2022
@SirYwell SirYwell deleted the fix/inner-class-ctor-parameters branch June 5, 2022 07:40
@monperrus
Copy link
Collaborator

monperrus commented Jun 8, 2022 via email

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

Successfully merging this pull request may close these issues.

4 participants