Giter VIP home page Giter VIP logo

rewrite's People

Contributors

aegershman avatar ammachado avatar bananeweizen avatar boykoalex avatar gsmet avatar jbrisbin avatar jkschneider avatar jlleitschuh avatar kmccarp avatar knutwannheden avatar kunli2 avatar mike-solomon avatar murdos avatar natedanner avatar nmck257 avatar patrickviry avatar pstreef avatar pway99 avatar rmadamanchi avatar sambsnyd avatar shanman190 avatar sjungling avatar smehta23 avatar sofiabrittoschwartz avatar sullis avatar thomaszub avatar timtebeek avatar tkvangorder avatar traceyyoshima avatar yeikel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rewrite's Issues

Create a visitor+recipe which ensures all classes in a folder/package have the specified visibility

Inspired by forgetting to make a class intended to be part of our public API public:
We could create a visitor which is configured with one or more package names and a visibility modifier public/protected/package/private. It would then ensure that every class in that package always has the appropriate visibility modifier.

I mainly anticipate this being used in two ways:

  • Package is part of a public API, so all classes in it should always be public
  • Package is internal, so all classes should always have package level visibility

I'm not sure exactly where this visitor should live. Rewrite-java is probably fine.

rewrite.yml does not affect changes in java code

I am trying to reproduce this example: https://docs.openrewrite.org/java/refactoring-java-source-code/usestaticimport

I created single class in project:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;

class Sample {
  @Test
  void sample() {
    Assertions.assertEquals(42, 21*2);
  }
}

Then I created in the root of the project rewrite.yml:

---
type: specs.org.openrewrite.org/v1beta/visitor
name: io.moderne.UseStaticJUnitAsserts
visitors:
  - org.openrewrite.java.UseStaticImport:
    method: 'org.junit.jupiter.api.Assertions assert*(..)'

My pom also contains plugin:

    <build>
        <plugins>
            <plugin>
                <groupId>org.openrewrite.maven</groupId>
                <artifactId>rewrite-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <configLocation>rewrite.yml</configLocation>
                </configuration>
            </plugin>
        </plugins>
    </build>

But I don't get expected result when I run the command: ./mvnw rewrite:fix

// What I expected to see
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class Sample {
  @Test
  void sample() {
    assertEquals(42, 21*2);
  }
}

More over I noticed that when I remove rewrite.yml it doesn't affect anything. Build status is always "SUCCESS".

Also when I change rewrite.yml in https://github.com/openrewrite/spring-petclinic-migration it always applies the same changes(even when I remove rewrite.yml).

Did I miss something? Seems like I don't understand something...

RemoveAnnotation

I think this is something we need because it can help replace one annotation to another one using combination of RemoveAnnotation and AddAnnotation. I will try to implement this by myself

ExcludeDependency visitor for Maven.

By specifying a groupId and artifactId pair, ExcludeDependency should locate first order dependencies whose transitive dependency tree includes a dependency matching this pair and add excludes to them.

Add the exclude as the last item in <exclusions> if such a tag already exists.

Add <exclusions> to the dependency if it does not already exist.

Not possible for visitors to mark ASTs for deletion

The standard advice we've been giving is that for a visitor to delete a source file it should return null from the highest-level tree element (in the case of Java, this is CompilationUnit). But if you actually try to return null from any visit method SourceVisitor.reduce() will discard it.

So as it stands there is not currently a way for a visitor to delete a tree it encounters.

Classpath from MavenModel

How would I get the classpath of a Maven project with a help of OpenRewrite?

Currently we're performing the following:

        List<Maven.Pom> mavenPoms = MavenParser
                .builder()
                .resolveDependencies(true)
                .build()
                .parse(List.of(buildFilePath), null);

Then on the resultant Pom object we'd call getModel().getTransitiveDependenciesByScope() and get all scopes dependencies.

These however seem to be more than project's classpath and computation of transitive dependencies (with resolveDependencies flag on) takes ~20s for the project attached below. Transitive dependencies number is huge. Note that all jars are in the local maven repo and are not downloaded.

Whenever, I try to use https://github.com/shrinkwrap/resolver to compute the classpath of the project below it takes less than a second or around a second and return much less dependencies (but their are the same as M2Es in Eclipse).

What is the purpose of transitive dependencies on the MavenModel in OpenRewrite? Is it the classpath or is meant for something else?

jboss.zip

ChangeMethodName works only with static methods

In this test project https://github.com/Guseyn/rewrite-java-definitions, I've created following class with regular and static methods:

package org.openrewrite.classes;

public class ClassWithMethods {
    public void foo() {}
    public void bar() {}

    public static void fooStatic() {}
    public static void barStatic() {}
}

I decided to include package names since I think it can be important.

Then I've created following test class E that contains the class above:

package org.openrewrite.before;

import org.openrewrite.classes.ClassWithMethods;

public class E  {
    void foo() {
        new ClassWithMethods().foo();
        ClassWithMethods.fooStatic();
    }
}

My Java Definition for E class:

        ChangeMethodName cmn = new ChangeMethodName();
        cmn.setMethod("org.openrewrite.classes.ClassWithMethods foo()");
        cmn.setName("bar");
        ChangeMethodName cmnStatic = new ChangeMethodName();
        cmnStatic.setMethod("org.openrewrite.classes.ClassWithMethods fooStatic()");
        cmnStatic.setName("barStatic");
        ChangePackageName cpn = new ChangePackageName();
        cpn.setNewPackageName("org.openrewrite.after");
        List<RefactorVisitor<?>> visitors = new ArrayList<>(){{
            add(cmn);
            add(cmnStatic);
            add(cpn);
        }};
        RefactorProcessor.run(visitors, "E.java");

I explain how RefactorProcessor in readme of the project: https://github.com/Guseyn/rewrite-java-definitions

When I run the this Java Definition, I get error:

Exception in thread "main" java.lang.NoSuchMethodError: org.openrewrite.java.tree.J$NewClass.<init>(Ljava/util/UUID;Lorg/openrewrite/java/tree/J$Ident;Lorg/openrewrite/java/tree/J$NewClass$New;Lorg/openrewrite/java/tree/TypeTree;Lorg/openrewrite/java/tree/J$NewClass$Arguments;Lorg/openrewrite/java/tree/J$Block;Lorg/openrewrite/java/tree/JavaType;Lorg/openrewrite/Formatting;)V
	at org.openrewrite.java.Java11ParserVisitor.visitNewClass(Java11ParserVisitor.java:945)
	at org.openrewrite.java.Java11ParserVisitor.visitNewClass(Java11ParserVisitor.java:56)
	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1711)
	at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
	at org.openrewrite.java.Java11ParserVisitor.convert(Java11ParserVisitor.java:1278)
	at org.openrewrite.java.Java11ParserVisitor.visitMethodInvocation(Java11ParserVisitor.java:734)

When I comment regular method:

package org.openrewrite.before;

import org.openrewrite.classes.ClassWithMethods;

public class E  {
    void foo() {
        // new ClassWithMethods().foo();
        ClassWithMethods.fooStatic();
    }
}

and run the definition again, I get expected result:

package org.openrewrite.after;

import org.openrewrite.classes.ClassWithMethods;

public class E  {
    void foo() {
        // new ClassWithMethods().foo();
        ClassWithMethods.barStatic();
    }
}

It seems to me that this visitor works only with static method, otherwise I get weird parsing error.

AddField accepts a String initilization expression, likely to come out lacking type-attribution

As can be seen in our documented example for AddField it accepts a String which is parsed into the initialization expression for the field. When this string is parsed into an AST, it is unlikely to come out type-attributed. This leads to subtle problems running subsequent visitors which might be looking for that type.

AddField, and any other older visitors which accept a String that gets parsed into AST elements, should be updated to instead accept AST elements. The expectation then is that users would then use TreeBuilder to construct type-attributed ASTs.

As part of fixing this, the docs for AddField should be updated and other visitors in rewrite-java should be spot checked to see if they have similar issues.

Finalize parsing of license types in Pom.License.fromName(..)

Currently we recognize a few license name texts, like "Apache License, Version 2.0" and "GPL", but there is much more variety in the wild west of Maven Central. Any unrecognized name is mapped to Unknown .

Also, remove Other since it is redundant with Unknown.

AutoFormat doesn't separate statements out onto their own lines

Given input like:

public class D {public String foo() {String foo = "foo";foo = foo + foo;return foo;}}

I expect AutoFormat to produce output like:

public class D {

    public String foo() {
        String foo = "foo";
        foo = foo + foo;
        return foo;
    }
}

Instead its actual output is:

public class D {

    public String foo() {String foo = "foo"; foo = foo + foo;return foo;}}

Run AutoFormatTest.separatesStatementsWithEmptyFormatting() to reproduce this issue

Kotlin support

Is there any plan to add support to kotlin method usage search and refactor?

"RequiresManualIntervention" Marker implementation

When generating PRs, the PR should represent a set of file changes for those pieces of a refactoring operation that we can do automatically plus review comments on lines that require manual intervention. So it is enough to define a refactoring visitor that paints an AST element that requires manual intervention with RequiresManualIntervention.

The PR generator can then use LineNumber to identify the line number of the source file to add a review comment to (see #81).

Determine what styling information should be mandatory for a rewrite configuration to be valid

Lots of Java recipes need to add/remove imports. But where in the list of imports should the new one go?
There are many different common answers.

To deal with this, some currently not-entirely-known set of style information must be provided.
For Java that definitely includes import ordering, but what else?
For Yaml? Maven poms?

We should try to clarify what is mandatory up-front as early as possible, since making a new piece of style information mandatory later would be one of the obnoxious breaking changes we're trying to save our industry from.

ChangeType doesn't use fully qualified names in import statements

Description/ Observed Behavior

When attempting to use the ChangeType recipe to swap org.mockito.Matchers (used in mockito 1) with org.mockito.ArgumentMatchers (used in mockito 2+) I observed that the import statements in the resulting code are missing the "org.mockito" bit.

Here's an example of the visitor:

@AutoConfigure
public class ReplaceMatchersWithArgumentMatchers extends JavaRefactorVisitor {
    private final ChangeType changeAny = new ChangeType();

    public ReplaceMatchersWithArgumentMatchers() {
        changeAny.setType("org.mockito.Matchers");
        changeAny.setTargetType("org.mockito.ArgumentMatchers");
    }

    @Override
    public J visitCompilationUnit(J.CompilationUnit cu) {
        return changeAny.visitCompilationUnit(cu);
    }
}

Operating on code with imports like these:

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;

Produces these invalid import statements:

import static ArgumentMatchers.any;
import static ArgumentMatchers.anyBoolean;

This isn't specific to the imports being static, all imports are affected.

Desired Behavior

This transformation should produce import statements like:

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;

Repro Steps

  1. Clone the rewrite-spring project
  2. Switch to the "mockito" branch
  3. Run the tests in ReplaceMatchersWithArgumentMatchersTest.kt

On org.openrewrite.java.tree.J interface, add a method String printAST() which prints the element and it's children

J.printAST() should operate similarly to the print() method in that it returns a String representation of the AST element which includes all of its children.
Unlike print(), printAST() is not expected to return Java source code, but instead directly transcribe the AST itself. The intended purpose of this is as a debugging tool for our own convenience as the developers of this software.
Implementing printAST() will likely involve creating a PrintJavaAST class that operates similarly to the existing org.openrewrite.java.internal.PrintJava class.

One thing I've grappled with trying to work on this codebase is thinking in terms of the AST, rather than in terms of the source code. I suspect that easily being able to interrogate any such AST element for both its source code representation and its AST representation will be a useful debugging and onboarding-to-the-concepts tool.

The output of this method may resemble JSON, yaml, or a similar data format.
So for java source like:

    package a;
    public class A {
       public void nonStatic() {}
    }

Example output of printAST(), in a pseudo-JSON-ish format, may resemble something along these lines:

{ CompilationUnit :
    sourcePath: "A.java"
    imports: []
    classes: [
        { ClassDecl:
            name: { Ident(A)}
            annotations: []
            modifiers: [ {Modifier.Public} ]
            typeParameters: null
            extendings: null
            body: { Block:
                statik: null
                statements: [
                    { MethodDecl:
                        annotations: []
                        modifiers: [ { Modifier.Public }]
                        typeParameters: null
                        returnTypeExpr: { Primitive:
                            type: { "Void" }
                        }
                        params: { MethodDecl.Parameters
                            params: [ Empty ]
                        }
                        throwz: null
                        defaultValue: null
                        body: {
                            statik: null
                            statements: []
                        }
                    }
                ]
            }
        }
    ]
}

Replace "Profile" terminology with "Recipe"

Should be updated in code, rewrite config files, documentation, and the projects that consume this one within openrewrite.

Optional Stretch goal: Include a "recipe" that operates on rewrite yaml configuration files and updates them to say "recipe" and "activeRecipes" instead of "profile" and "activeProfile".

Simplify the concept of a "Recipe": No inheritance. No assembling them from multiple pieces spread across many locations

Recipes are currently called "profiles" until #13 is complete

Remove any notion of recipes extending or inheriting from one another. This includes removing any mention of the "default" recipe, a concept which will no longer exist.
Remove any notion of recipes being defined in pieces across many places and merged together based on having the same name
No recipe should be executed unless the user has configured it as being among the active recipes via build tool plugin

Bug: Mistakenly adds the 'new' keyword

At instantiation of an inner classes, specifically when we have a . expression with the new keyword (e.g.,this.new B()), Java8Parser adds the new keyword at the beginning of the expression.

Consider the following as the original code,

class A {
  void bar(B b, C c) {}
  void foo() {
    bar(this.new B(), this.new C());
  }
  class B { }
  class C { }
}

And now just by parsing the above code without applying any change, I get the following output,

class A {
  void bar(B b, C c) {}
  void foo() {
    bar(newthis.new B(), newthis.new C());
  }
  class B { }
  class C { }
}

Here is the code I used to produce the above output,

JavaParser parser =
            Java8Parser.builder()
                    .relaxedClassTypeMatching(true)
                    .logCompilationWarningsAndErrors(false)
                    .build();


    String uri = "PATH_TO_FILE";
    ArrayList<Path> p = new ArrayList<>();
    p.add(Paths.get(uri));
    ArrayList<J.CompilationUnit> trees = (ArrayList<J.CompilationUnit>) parser.parse(p);
    J.CompilationUnit tree = trees.get(0);
    System.out.println(tree.print());

AutoFormat is adding unnecessary newlines

There are a couple of different situations where an unnecessary newline is being added to the name of the method and/or to the return type of the method. Only the first modifier, return type or name should have a prefix containing a newline, not multiple.

image

Reference AddAnnotationTest.addAnnotationToMethod() to recreate this behavior.

J.FieldAccess.isFullyQualifiedClassReference() doesn't work on MethodMatchers containing wildcards

Description/ Observed Behavior

J.FieldAccess.isFullyQualifiedClassReference(MethodMatcher) allows for comparison between a FieldAccess and a MethodMatcher to see if they are describing the same fully qualified type or not.

But MethodMatchers can contain patterns/wildcards like "com.*.Bar" instead of something concrete like "com.foo.Bar". Currently isFullyQualifiedFieldAccess will always return false when comparing such MethodMatchers.

Desired Behavior

If a FieldReference to something like "com.foo.Bar" is compared against a MethodMatcher that contains something like "com.*.Bar", isFullyQualifiedReference() should return true.

Remove a user's home directory as a valid place to discover Recipes, still allow Styles

Recipes are currently called "profiles" until #13 is complete

We've decided that the user home is a valid place to store style information, like preferred import ordering, but defining any recipes/visitors there should not be allowed.

At the time of writing this issue I'm not actually sure if we are actively checking a user's home directory for anything or if that was just the plan. If we don't currently actively check the home directory for recipes, then this issue can be closed for now and we'll revisit later when we have a somewhat more rigorous concept of what a "Style" is.

AddImport doesn't allow setting Layout

Hi there!

I'm using the AddImport java refactor visitor in a library refactoring I'm building. AddImport delegates to OrderImports in order to reorder the imports.

A few things:

  1. Would you all take a patch that adds a setting on AddImport to disable reordering imports after adding an import (just a setter on the AddImport object)?
  2. If we do want to order imports, should the Layout is be configurable from the AddImport call? Our company style prefers explict imports, rather than wildcarded imports, so we'd prefer to be able to disable wildcard importing if we do end up wanting to re-order imports.

Let me know what you think!

Thanks for openrewrite, we're just starting to use it for some large-scale library refactorings, and are enjoying it so far!

Create convenience methods for creating/updating/deleting AST elements

We are using annotations as an example, but this is being proposed for wherever there is a collection of elements in an AST to make creating, updating and deleting from these collections a better experience for the user.

Create

Old

J.Annotation newAnnot = buildAnnotation(formatting);
List<J.Annotation> annots = new ArrayList<>(c.getAnnotations());
annots.add(newAnnot);
c = c.withAnnotations(annots);

New

c = c.withNewAnnotation(newAnnot); // adds to the end
c = c.withNewAnnotation(newAnnot, 0); // adds to the start

Update/Replace

Old

public J.Annotation doSomethingWithAnnotation(J.Annotation annot) { ... }
public Stream<J.Annotation> returnsManyAnnotations(J.Annotation annot) { ... }

List<J.Annotation> annots = new ArrayList<>(c.getAnnotations());
annots = annots.stream()
    .map(annot -> doSomethingWithAnnotation(annot))
    .collect(toList());
c = c.withAnnotations(annots);

New

c = c.mapAnnotations(annot -> doSomethingWithAnnotation(annot));
c = c.flatMapAnnotations( annot -> Stream.of(doSomethingWithAnnotation(annot)));
c = c.flatMapAnnotations( annot -> returnsManyAnnotations(annot));

Remove

Old

List<J.Annotation> annots = new ArrayList<>(c.getAnnotations());
annots = annots.stream()
    .filter(annot -> annot == something)
    .collect(toList());
c = c.withAnnotations(annots);

New

c = c.filterAnnotations(annot -> annot == something)

OrderImports will remove some static imports even when removeUnused = false

Given these sources:

package com.foo;

public class A {
    public static int one() { return 1;}
    public static int plusOne(int n) { return n + 1; }
}
package com.foo;

public class B {
    public static int two() { return 2; }
    public static int multiply(int n, int n2) { return n * n2; }
}

And this class that uses them:

package org.bar;

import static com.foo.A.one;
import static com.foo.A.plusOne;
import static com.foo.B.two;
import static com.foo.B.multiply;

public class C {
    void c() {
        multiply(plusOne(one()), two());
    }
}

Visiting C with OrderImports should result in all four import statements still being present.
Instead this is the result:

package org.bar;

import static com.foo.A.one;

import static com.foo.A.plusOne;

public class C {
    void c() {
        multiply(plusOne(one()), two());
    }
}

This happens whether or not removeUnused is set to true or false.
I haven't fully debugged but, for some reason, none of the import "blocks" accept the imports from "B". It's also peculiar that the imports from "A" end up in different blocks.

OrderImportsTest.moreStaticImportFun() reproduces this issue

Require recipe names to be fully qualified & unique

Recipes are currently called "profiles" until #13 is complete

Right now recipes can have simple names like "mockito" or "spring".
With #16 removing the concept of recipes being assembled from multiple pieces based on their name, it becomes an error to have multiple recipes with the same name.
To save us all from runtime errors due to name collision, let's go ahead and require recipe names to be fully qualified with a package-prefix.

This applies to all existing recipes as well as all new ones. No special treatment for anything org.openrewrite.

MethodMatcher treats array arguments as if they were non-array arguments

When applying a MethodMatcher like new MethodMatcher("a.A foo(int[])") to methods like these:

package a;

class A {
    // Should match this, but does not
    void foo(int[] arg) { }
    // Should not match this, but does
    void foo(int arg)
}

It does not match the foo with argument of type int[], which it should.
And it does match the foo with argument of type int, which it should not.

To reproduce this issue, un-@Disable MethodMatcherTest.matchesPrimitiveArgument() test.

AddImport does not work while inserting method argument

In this test project (https://github.com/guseyn/rewrite-java-definitions), I've create following example:

public class InsertMethodArgumentExample {
    public static void main(String... args) throws IOException {
        InsertMethodArgument ima = new InsertMethodArgument();
        ima.setMethod("org.slf4j.Logger debug(String,..)");
        ima.setIndex(0);
        ima.setSource("MarkerFactory.getMarker(\"CONFIDENTIAL\")");
        ChangePackageName cpn = new ChangePackageName();
        cpn.setNewPackageName("org.openrewrite.after");
        AddImport adi = new AddImport();
        adi.setType("MarkerFactory");
        adi.setOnlyIfReferenced(false);
        RefactorProcessor.run(new ArrayList<RefactorVisitor<?>>(){{
            add(ima);
            add(adi);
            add(cpn);
        }}, "I.java");
    }
}

RefactorProcessor.run() takes file I.java from folder before, applies visitors which is in ArrayList(as first argument) and then puts updated I.java into after folder.

This is how I.java looks before:

package org.openrewrite.before;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class I {
    public void foo() {
        Logger logger = LoggerFactory.getLogger(G.class);
        logger.debug("message");
    }
}

And this is how it looks after:

package org.openrewrite.after;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class I {
    public void foo() {
        Logger logger = LoggerFactory.getLogger(G.class);
        logger.debug(MarkerFactory.getMarker("CONFIDENTIAL"), "message");
    }
}

As you can see, import org.slf4j.MarkerFactory; is missing although I've explicitly created new AddImport() visitor.

Create a subclass of JavaRefactorVisitor where the visit methods return the types they accept

Context

Anything extending from JavaRefactorVisitor has visit methods which return a J, the abstract type from which all Java AST elements extend.
This is a very flexible API, as it allows you to do things like visit a field and return a method declaration.
In practice, few visitors need this flexibility, and those that don't would be less verbose and easier to work with if they were constrained. Each visit method only returning the same type it accepts as an argument would make the API easier to work with and require less casting.

Desired Result

Create a new subtype of JavaRefactorVisitor where visitField only returns fields, visitMethod only returns methods, etc.
This new subtype of JavaRefactorVisitor can be called JavaIsomorphicRefactorVisitor (name not final).

Out of Scope

This issue does not include migrating all of the existing visitors that could be isomorphic visitors to the new class. That can be a separate issue.

No changes need to be made to JavaRefactorVisitor itself. There are visitors which do require its flexibility.

Update tests for visitors to take advantage of RefactorVisitorTest

Context

We created RefactorVisitorTest to provide a convenient, declarative syntax for writing tests of Rewrite Visitors. Many of the tests under rewrite-test predate RefactorVisitorTest and therefore don't take advantage of it and are written in an older style.

The task is to update all of the older style visitor tests to use the new form.

Before

Using AddImportTest.addNamedImport() as an example, currently it looks like this:

    @Test
    fun addNamedImport(jp: JavaParser) {
        "class A {}"
                .whenParsedBy(jp)
                .whenVisitedBy(AddImport().apply { setType("java.util.List"); setOnlyIfReferenced(false) })
                .isRefactoredTo("""
                    import java.util.List;
                    
                    class A {}
                """)
    }

After

Rewritten as a RefactorVisitorTest that same test case would look like:

    @Test
    fun addNamedImport2(jp: JavaParser) = assertRefactored(jp,
            visitors = listOf(AddImport().apply { setType("java.util.List"); setOnlyIfReferenced(false) }),
            before = """
                    class A {}
                """,
            after = """
                    import java.util.List;
                    
                    class A {}
                """
    )

SemanticallyEqual should consider annotation equal with "value =" present or omitted

The following annotations are semantically equal, but because the first would be an Ident and the second would be an Assign, they would not be considered equal. This edge case needs to be implemented in SemanticallyEqual.
Example 1:
@ExampleAnnotation("a value")

@ExampleAnnotation(value = "a value")

Example 2:
@ExampleAnnotation({"a value"})

@ExampleAnnotation(value = {"a value"})

J.NewClass doesn't expose the names of a constructor's parameters

Description/ Observed Behavior

J.NewClass represents the invocation of a constructor, e.g.: new String("foo"). This is understandable as at the call site the names of the arguments are not present.

But it would be useful for recipes which operate on constructors to have this information.

This can be worked around with TypeUtils.asClass(newClass.getType()).getConstructors()

Desired Behavior

J.NewClass should have an Arguments field the same as MethodInvocation does.

Swapping a constructor invocation with a static method leaves behind extra stuff

Description/ Observed Behavior

In Java static methods are often used to provide access to instance creation when directly using new is, for a variety of possible reasons, undesirable or impractical.
Implementing a JavaRefactorVisitor that overrides visitNewClass and returns a J.MethodInvocation instead of the J.NewClass that originally represented the constructor invocation had an unexpected result.

Input, attempting to swap "new A()" with a call to A.factory():

class B {
    public static void foo() {
        A a = new A();
    }
}

Output:

class B {
    public static void foo() {
        A a = A factory()();
    }
}

Desired Behavior

This replacement should instead result in:

class B {
    public static void foo() {
        A a = A.factory();
    }
}

Repro Steps

  1. Check out the constructor-to-static branch
  2. Run ChangeMethodTargetToStaticTest.refactorConstructorToStatic()

Rewrite type declarations should be of the format openrewrite.org/spec/<version>[beta]/<concept>

At some point openrewrite.org will be a real website and we will have formal specifications for concepts like "visitor" available there under openrewrite.org/spec//
This is conceptually similar to how xml documents provide URLs to their schema definitions.

Currently recipe types look like: beta.openrewrite.org/v1/visitor
Instead they should be: openrewrite.org/spec/v1beta/visitor

This includes having rewrite core reject rule types that include openrewrite.org but are missing /
No particular requirement is placed on non-openrewrite.org type urls

Change package name

I think we need a visitor that changes package name in classes, it's very useful and as I can see it's not implemented yet.

RemoveUnusedImports removes imports of static methods invoked from the argument lists of other method invocations

Given an static utility class like this one:

package com.foo;

public class A {
    public static void foo(String bar) {}
    public static String stringify(Integer baz) { return baz.toString(); }
    public static Integer numberOne() { return 1; }
}

And a usage like:

package org.bar;

import static com.foo.A.*;

class B {
    void bar() {
        foo(stringify(numberOne()));
    }
}

When visited by RemoveUnusedImports (or OrderImports with removeUnused = true) the result will be:

package org.bar;

import static com.foo.A.foo;

class B {
    void bar() {
        foo(stringify(numberOne()));
    }
}

Which will result in stringify() and numberOne() being unknown symbols.

OrderImportsTest.preservesStaticMethodArguments exercises this issue

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.