diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 6e0607621ae..47b65310df4 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -350,6 +350,12 @@ class A { } sortedByPosition.computeIfAbsent(pos(field), i -> new ArrayList<>()).add(field); } + for (ConstructorNode ctor : clazz.getDeclaredConstructors()) { + if (!appearsInSource(ctor)) { + continue; + } + sortedByPosition.computeIfAbsent(pos(ctor), i -> new ArrayList<>()).add(ctor); + } Iterator innerClassIterator = clazz.getInnerClasses(); while (innerClassIterator.hasNext()) { InnerClassNode icn = innerClassIterator.next(); @@ -366,6 +372,8 @@ class A { .map(ast -> { if (ast instanceof FieldNode) { visitField((FieldNode) ast); + } else if (ast instanceof ConstructorNode) { + visitConstructor((ConstructorNode) ast); } else if (ast instanceof MethodNode) { visitMethod((MethodNode) ast); } else if (ast instanceof ClassNode) { @@ -595,6 +603,109 @@ null, emptyList(), )); } + @Override + public void visitConstructor(ConstructorNode ctor) { + Space fmt = whitespace(); + + List annotations = ctor.getAnnotations().stream() + .map(a -> { + visitAnnotation(a); + return (J.Annotation) pollQueue(); + }) + .collect(Collectors.toList()); + + List modifiers = visitModifiers(ctor.getModifiers()); + + // Constructor name might be in quotes + Space namePrefix = whitespace(); + String ctorName; + if (source.startsWith(ctor.getDeclaringClass().getName(), cursor)) { + ctorName = ctor.getDeclaringClass().getName(); + } else { + char openingQuote = source.charAt(cursor); + ctorName = openingQuote + ctor.getName() + openingQuote; + } + cursor += ctorName.length(); + J.Identifier name = new J.Identifier(randomId(), + namePrefix, + Markers.EMPTY, + emptyList(), + ctorName, + null, null); + + RewriteGroovyVisitor bodyVisitor = new RewriteGroovyVisitor(ctor, this); + + // Parameter has no visit implementation, so we've got to do this by hand + Space beforeParen = sourceBefore("("); + List> params = new ArrayList<>(ctor.getParameters().length); + Parameter[] unparsedParams = ctor.getParameters(); + for (int i = 0; i < unparsedParams.length; i++) { + Parameter param = unparsedParams[i]; + + List paramAnnotations = param.getAnnotations().stream() + .map(a -> { + visitAnnotation(a); + return (J.Annotation) pollQueue(); + }) + .collect(Collectors.toList()); + + TypeTree paramType; + if (param.isDynamicTyped()) { + paramType = new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), "", JavaType.ShallowClass.build("java.lang.Object"), null); + } else { + paramType = visitTypeTree(param.getOriginType()); + } + JRightPadded paramName = JRightPadded.build( + new J.VariableDeclarations.NamedVariable(randomId(), EMPTY, Markers.EMPTY, + new J.Identifier(randomId(), whitespace(), Markers.EMPTY, emptyList(), param.getName(), null, null), + emptyList(), null, null) + ); + cursor += param.getName().length(); + + org.codehaus.groovy.ast.expr.Expression defaultValue = param.getInitialExpression(); + if (defaultValue != null) { + paramName = paramName.withElement(paramName.getElement().getPadding() + .withInitializer(new JLeftPadded<>( + sourceBefore("="), + new RewriteGroovyVisitor(defaultValue, this).visit(defaultValue), + Markers.EMPTY))); + } + Space rightPad = sourceBefore(i == unparsedParams.length - 1 ? ")" : ","); + + params.add(JRightPadded.build((Statement) new J.VariableDeclarations(randomId(), EMPTY, + Markers.EMPTY, paramAnnotations, emptyList(), paramType, + null, emptyList(), + singletonList(paramName))).withAfter(rightPad)); + } + + if (unparsedParams.length == 0) { + params.add(JRightPadded.build(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY))); + } + + JContainer throws_ = ctor.getExceptions().length == 0 ? null : JContainer.build( + sourceBefore("throws"), + bodyVisitor.visitRightPadded(ctor.getExceptions(), null), + Markers.EMPTY + ); + + J.Block body = ctor.getCode() == null ? null : + bodyVisitor.visit(ctor.getCode()); + + queue.add(new J.MethodDeclaration( + randomId(), fmt, Markers.EMPTY, + annotations, + modifiers, + null, + null, + new J.MethodDeclaration.IdentifierWithAnnotations(name, emptyList()), + JContainer.build(beforeParen, params, Markers.EMPTY), + throws_, + body, + null, + typeMapping.methodType(ctor) + )); + } + @SuppressWarnings({"ConstantConditions", "unchecked"}) private T pollQueue() { return (T) queue.poll(); diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CompilationUnitTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CompilationUnitTest.java index 0e438eb6089..47ff7dd24eb 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CompilationUnitTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CompilationUnitTest.java @@ -16,7 +16,6 @@ package org.openrewrite.groovy.tree; import org.codehaus.groovy.control.customizers.ImportCustomizer; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openrewrite.Issue; import org.openrewrite.groovy.GroovyParser; @@ -125,7 +124,6 @@ void shouldNotFailWhenImportCannotBeResolved() { } @Issue("https://github.com/openrewrite/rewrite/issues/4704") - @Disabled @Test void addingToMaps() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ConstructorTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ConstructorTest.java index 802dc558882..16e575e0c96 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ConstructorTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ConstructorTest.java @@ -35,6 +35,24 @@ void inParens() { ); } + @Test + void declaration() { + rewriteRun( + groovy( + """ + class Pair { + String first + String second + Pair(String first, String second) { + this.first = first + this.second = second + } + } + """ + ) + ); + } + @Test void anonymousClassDeclarationClosedOverVariable() { rewriteRun(