Skip to content

Commit af40b9d

Browse files
committed
Fix for #1308: add delegate or owner qualifier within closure/lambda
see #1288
1 parent dc9d5fc commit af40b9d

File tree

2 files changed

+57
-15
lines changed

2 files changed

+57
-15
lines changed

ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/actions/ConvertToPropertyActionTests.groovy

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2021 the original author or authors.
2+
* Copyright 2009-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -149,6 +149,20 @@ final class ConvertToPropertyActionTests extends GroovyEditorTestSuite {
149149
assertEditorContents 'def getX(){0}\n[x:1].with { this.x }'
150150
}
151151

152+
@Test // https://github.com/groovy/groovy-eclipse/issues/1308
153+
void testImplicitGetterToProperty3() {
154+
def pogo = 'class C {\n def getX(){0}\n}\n'
155+
convertToProperty pogo + "new C().with { get${CARET}X() }"
156+
assertEditorContents pogo + 'new C().with { x }' // no qualifier
157+
158+
convertToProperty pogo + "def x=1\nnew C().with { get${CARET}X() }"
159+
assertEditorContents pogo + 'def x=1\nnew C().with { delegate.x }'
160+
161+
def stc = { '@groovy.transform.TypeChecked void test(){\n' + it + '\n}' }
162+
convertToProperty pogo + stc("def x=1\nnew C().with { get${CARET}X() }")
163+
assertEditorContents pogo + stc('def x=1\nnew C().with { delegate.x }')
164+
}
165+
152166
@Test
153167
void testImplicitIsserToProperty() {
154168
addGroovySource 'class Foo { static void isSomething() {} }', 'Foo'
@@ -168,6 +182,20 @@ final class ConvertToPropertyActionTests extends GroovyEditorTestSuite {
168182
assertEditorContents 'void setX(x){}\n[x:1].with { this.x = 0 }'
169183
}
170184

185+
@Test // https://github.com/groovy/groovy-eclipse/issues/1308
186+
void testImplicitSetterToProperty3() {
187+
def pogo = 'class C {\n void setX(x){}\n}\n'
188+
convertToProperty pogo + "new C().with { set${CARET}X(0) }"
189+
assertEditorContents pogo + 'new C().with { x = 0 }' // no qualifier
190+
191+
convertToProperty pogo + "def x=1\nnew C().with { set${CARET}X(0) }"
192+
assertEditorContents pogo + 'def x=1\nnew C().with { delegate.x = 0 }'
193+
194+
def stc = { '@groovy.transform.TypeChecked void test(){\n' + it + '\n}' }
195+
convertToProperty pogo + stc("def x=1\nnew C().with { set${CARET}X(0) }")
196+
assertEditorContents pogo + stc('def x=1\nnew C().with { delegate.x = 0 }')
197+
}
198+
171199
@Test
172200
void testStaticGetterToProperty() {
173201
convertToProperty "import java.lang.management.*; ManagementFactory.getRun${CARET}timeMXBean()"

ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/refactoring/actions/ConvertToPropertyAction.java

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2021 the original author or authors.
2+
* Copyright 2009-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818
import static java.beans.Introspector.decapitalize;
1919
import static java.util.regex.Pattern.compile;
2020

21+
import static org.codehaus.groovy.transform.stc.StaticTypesMarker.IMPLICIT_RECEIVER;
2122
import static org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_ASSIGNMENT_OPERATOR;
2223
import static org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_ASSIGNMENT_OPERATOR;
2324

@@ -84,12 +85,12 @@ public void run() {
8485
}
8586
}
8687

87-
public static TextEdit createEdit(final GroovyCompilationUnit gcu, final int pos, final int len) {
88+
public static TextEdit createEdit(final GroovyCompilationUnit gcu, final int idx, final int len) {
8889
ModuleNodeInfo info = gcu.getModuleInfo(true);
8990
if (!info.isEmpty()) {
9091
MethodCall call = null;
9192

92-
ASTNode node = new ASTNodeFinder(new Region(pos, len)).doVisit(info.module);
93+
ASTNode node = new ASTNodeFinder(new Region(idx, len)).doVisit(info.module);
9394
if (node instanceof ConstantExpression) {
9495
IASTFragment fragment = new FindSurroundingNode(new Region(node)).doVisitSurroundingNode(info.module);
9596
if (fragment.kind() == ASTFragmentKind.METHOD_CALL) {
@@ -114,8 +115,8 @@ public static TextEdit createEdit(final GroovyCompilationUnit gcu, final int pos
114115
TextEdit edit = new ReplaceEdit(offset, length, decapitalize(propertyName));
115116

116117
// implicit-this call may require qualifier to retain its semantics
117-
if (call.getReceiver().getEnd() < 1 && isTypeChange(gcu, edit, node)) {
118-
edit = new ReplaceEdit(offset, length, call.getReceiver().getText() + "." + decapitalize(propertyName));
118+
if (call.getReceiver().getEnd() < 1 && isTypeChange(edit, node, gcu)) {
119+
edit = new ReplaceEdit(offset, length, getReceiver(call) + "." + decapitalize(propertyName));
119120
}
120121

121122
return edit;
@@ -149,9 +150,10 @@ public static TextEdit createEdit(final GroovyCompilationUnit gcu, final int pos
149150
}
150151

151152
// implicit-this call may require qualifier to retain its semantics
152-
if (call.getReceiver().getEnd() < 1 && isTypeChange(gcu, edit, node)) {
153-
edit.removeChild(0); // add qualifier to the property name
154-
replacement.insert(0, call.getReceiver().getText() + ".");
153+
if (call.getReceiver().getEnd() < 1 && isTypeChange(edit, node, gcu)) {
154+
edit.removeChild(0);
155+
// add qualifier to the property name
156+
replacement.insert(0, getReceiver(call) + ".");
155157
edit.addChild(new ReplaceEdit(offset, length, replacement.toString()));
156158
}
157159

@@ -164,14 +166,26 @@ public static TextEdit createEdit(final GroovyCompilationUnit gcu, final int pos
164166

165167
//--------------------------------------------------------------------------
166168

167-
private static boolean isTypeChange(final GroovyCompilationUnit gcu, final TextEdit edit, final ASTNode node) {
169+
private static String getReceiver(final MethodCall call) {
170+
String receiver = ((ASTNode) call).getNodeMetaData(IMPLICIT_RECEIVER);
171+
if (receiver == null) {
172+
receiver = call.getReceiver().getText();
173+
}
174+
return receiver;
175+
}
176+
177+
private static boolean isTypeChange(final TextEdit edit, final ASTNode node, final GroovyCompilationUnit unit) {
168178
try {
169-
TypeLookupResult before = inferNodeType(node, gcu);
170-
TextEdit undo = gcu.applyTextEdit(edit.copy(), null);
171-
TypeLookupResult after = inferNodeType(new ASTNodeFinder(new Region(node.getStart(), 0)).doVisit(gcu.getModuleNode()), gcu);
172-
gcu.applyTextEdit(undo, null);
179+
TypeLookupResult before = lookupNodeType(node, unit);
180+
TextEdit undo = unit.applyTextEdit(edit.copy(), null);
181+
TypeLookupResult after = lookupNodeType(new ASTNodeFinder(new Region(node.getStart(), 0)).doVisit(unit.getModuleNode()), unit);
182+
unit.applyTextEdit(undo, null);
173183

174184
if (!before.declaringType.equals(after.declaringType)) {
185+
if (!before.declaringType.equals(before.scope.getThis())) {
186+
ASTNode call = (node instanceof MethodCall ? node : before.scope.getEnclosingNode()); // TODO: refactor side-effect solution!
187+
call.getNodeMetaData(IMPLICIT_RECEIVER, x -> before.declaringType.equals(before.scope.getDelegate()) ? "delegate" : "owner");
188+
}
175189
return true;
176190
}
177191
} catch (Exception e) {
@@ -180,7 +194,7 @@ private static boolean isTypeChange(final GroovyCompilationUnit gcu, final TextE
180194
return false;
181195
}
182196

183-
private static TypeLookupResult inferNodeType(final ASTNode node, final GroovyCompilationUnit unit) {
197+
private static TypeLookupResult lookupNodeType(/* */ final ASTNode node, final GroovyCompilationUnit unit) {
184198
TypeLookupResult[] result = new TypeLookupResult[1];
185199
new TypeInferencingVisitorFactory().createVisitor(unit).visitCompilationUnit((n, r, x) -> {
186200
if (n == node) {

0 commit comments

Comments
 (0)