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

Refactor "Move Inner to Outer level" on record drops the record details #7044

Open
homberghp opened this issue Feb 8, 2024 · 3 comments · May be fixed by #8197
Open

Refactor "Move Inner to Outer level" on record drops the record details #7044

homberghp opened this issue Feb 8, 2024 · 3 comments · May be fixed by #8197
Labels
Editor Java [ci] enable extra Java tests (java.completion, java.source.base, java.hints, refactoring.java, form) kind:bug Bug report or fix

Comments

@homberghp
Copy link
Contributor

homberghp commented Feb 8, 2024

Apache NetBeans version

Apache NetBeans 20

What happened

When you have an inner record like so;

package example;
import java.time.LocalDate;
public class Example {
    public record Studentje(int id, String fullName, LocalDate dob){}
}

and for some reason you want it to be an outer class in its own file, then
refactor Move Inner to Outer level, then the result in the that file is

package example;
import java.time.LocalDate;
public class Studentje {
}

dropping all record details.

Language / Project Type / NetBeans Component

java editor

How to reproduce

make class as above with inner record and apply refactoring Move Inner to.
The resulting class is no longer a record, the record component parameters including parenthesis are dropped,
but the import (LocalDate) is handed over, but is useless because of the stripping.

Did this work correctly in an earlier version?

No / Don't know

Operating System

ubuntu 24.04, Windows 11

JDK

java 21, Java 17 at least

Apache NetBeans packaging

Apache NetBeans binary zip

Anything else

occurs always.

Are you willing to submit a pull request?

Yes, I am at it, but stuck on the steps from parsetree to java code and possibly templates.

@homberghp homberghp added kind:bug Bug report or fix needs:triage Requires attention from one of the committers labels Feb 8, 2024
@mbien mbien added Java [ci] enable extra Java tests (java.completion, java.source.base, java.hints, refactoring.java, form) Editor labels Feb 8, 2024
@mbien mbien removed the needs:triage Requires attention from one of the committers label Jul 23, 2024
@homberghp
Copy link
Contributor Author

Working on tests. Tests first. Then I might be able to resolve the issue, so answer to 'willing to submit a pull request is maybe'

@homberghp
Copy link
Contributor Author

homberghp commented Jan 6, 2025

Further investigation revealed the following.

After adding two times RECORD as case label in file java.source.base/org.netbeans.api.java.source.WorkingCopy.java,
and adding a non-null test in java.source.base/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java I am able to get nearer to a solution.

My tests now produces

/*                                                                              
* Refactoring License                                                           
*/                                                                              
package t;                                                                      
import java.time.LocalDate;                                                     
import java.util.Objects;                                                       
/**                                                                             
*                                                                               
* @author junit                                                                 
*/                                                                              
record F(private final int id, private final String name, private final LocalDate dob) { //<1>
  /**                                                                             
   * Validate stuff.                                                               
   */                                                                              
    public F(int id, String name, LocalDate dob) {  //<2>                                
          Objects.requireNonNull(id);                                                     
          Objects.requireNonNull(name);                                                   
          Objects.requireNonNull(dob);                                                    
          assert !name.isEmpty() && !name.isBlank();                                      
          assert dob.isAfter(LocalDate.EPOCH);                                            
      }                                                                                 
}                                                                               

from the following original inner/outer class text:

package t;

import java.time.LocalDate;
import java.util.Objects;

public class A {

      void useStudent() {
            F s = new F(42,"Jan Klaassen", LocalDate.now().minusDays(1));
             System.out.println("student = " + s);
        }

        record F(int id, String name, LocalDate dob) {

    /**
     * Validate stuff.
      */
    public F {
          Objects.requireNonNull(id);
          Objects.requireNonNull(name);
          Objects.requireNonNull(dob);
          assert !name.isEmpty() && !name.isBlank();
          assert dob.isAfter(LocalDate.EPOCH);
         }
    }
}

.

As can be seen:

  1. The record header has wrong RecordComponent declarations (they include private final)
  2. The constructor is not a compact constructor but a 'normal' one, but is not sufficient to be designated as the canonical constructor because it is missing the field assignments.

So I am stuck with finding how information from the AST parsetree (classtree) is written out as java code.

A simpler test with a record within a record shows that outer record is properly generated, but the inner record
is malformed to

record F(private final int x, private final int y) {} 

It might have to do with Templates, but I have no idea where I can find them.

homberghp added a commit to homberghp/netbeans that referenced this issue Jan 26, 2025
see issue apache#7044 for exact problem.

Start with adding tests.

Introduced RECORD and RECORD_COMPONENT case labels in multiple places.

Deal with method params for the record header in InnerOuterTransformer.
The given way of printing the 'method parameters' for the record header
include 'private final', producing illegal java code.
The solution found might not be the moset elegant, but since the tree
modifications will not persist into any real source code, it is
acceptable. The solution strips `private` and `final` from the VARIABLE
trees.

Delete file threw and unnecessary exception where a simple null test
 suffices.
@homberghp homberghp linked a pull request Jan 26, 2025 that will close this issue
@homberghp
Copy link
Contributor Author

homberghp commented Jan 26, 2025

Dropped earlier pull request and created a new one based on a branch: issue7044.

@mbien mbien linked a pull request Jan 31, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Editor Java [ci] enable extra Java tests (java.completion, java.source.base, java.hints, refactoring.java, form) kind:bug Bug report or fix
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants