Skip to content

Commit 9e7e49c

Browse files
committed
Fix for issue #286: type inferencing of inner class map constructor args
1 parent 0426dfb commit 9e7e49c

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/TypeInferencingVisitorWithRequestor.java

+9-10
Original file line numberDiff line numberDiff line change
@@ -1083,14 +1083,14 @@ public void visitConstructorCallExpression(ConstructorCallExpression node) {
10831083
boolean shouldContinue = handleSimpleExpression(node);
10841084
if (shouldContinue) {
10851085
visitClassReference(node.getType());
1086-
if (node.getArguments() instanceof TupleExpression
1087-
&& ((TupleExpression) node.getArguments()).getExpressions().size() == 1) {
1088-
Expression arg = ((TupleExpression) node.getArguments()).getExpressions().get(0);
1089-
if (arg instanceof MapExpression) {
1090-
// this is a constructor call that is instantiated by a map.
1091-
// remember this, so that when visiting the map, we can
1092-
// infer field names
1093-
enclosingConstructorCall = node;
1086+
if (node.getArguments() instanceof TupleExpression) {
1087+
TupleExpression tuple = (TupleExpression) node.getArguments();
1088+
if (isNotEmpty(tuple.getExpressions())) {
1089+
if ((tuple.getExpressions().size() == 1 && tuple.getExpressions().get(0) instanceof MapExpression) ||
1090+
tuple.getExpression(tuple.getExpressions().size() - 1) instanceof NamedArgumentListExpression) {
1091+
// remember this is a map ctor call, so that field names can be inferred when visiting the map
1092+
enclosingConstructorCall = node;
1093+
}
10941094
}
10951095
}
10961096
super.visitConstructorCallExpression(node);
@@ -1671,8 +1671,7 @@ public void visitTupleExpression(TupleExpression node) {
16711671
boolean shouldContinue = handleSimpleExpression(node);
16721672
if (shouldContinue && isNotEmpty(node.getExpressions())) {
16731673
// prevent revisit of statically-compiled chained assignment nodes
1674-
if (node instanceof ArgumentListExpression ||
1675-
node.getExpression(0) instanceof NamedArgumentListExpression) {
1674+
if (node instanceof ArgumentListExpression || node.getExpression(node.getExpressions().size() - 1) instanceof NamedArgumentListExpression) {
16761675
super.visitTupleExpression(node);
16771676
}
16781677
}

ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/ui/SemanticHighlightingTests.groovy

+30
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,36 @@ final class SemanticHighlightingTests extends GroovyEclipseTestSuite {
742742
new HighlightedTypedPosition(contents.lastIndexOf('X'), 1, CTOR_CALL))
743743
}
744744

745+
@Test
746+
void testInnerClassCtorCalls() {
747+
String contents = '''\
748+
class X {
749+
class Y {
750+
String foo
751+
Integer bar
752+
}
753+
def baz() {
754+
def y = new Y()
755+
def why = new Y(foo: '1', bar: 2) // non-static inner class causes an AST variation
756+
}
757+
}
758+
'''.stripIndent()
759+
760+
assertHighlighting(contents,
761+
new HighlightedTypedPosition(contents.indexOf('foo'), 3, FIELD),
762+
new HighlightedTypedPosition(contents.indexOf('bar'), 3, FIELD),
763+
new HighlightedTypedPosition(contents.indexOf('baz'), 3, METHOD),
764+
new HighlightedTypedPosition(contents.indexOf('y ='), 1, VARIABLE),
765+
new HighlightedTypedPosition(contents.indexOf('Y()'), 1, CTOR_CALL),
766+
new HighlightedTypedPosition(contents.indexOf('why'), 3, VARIABLE),
767+
new HighlightedTypedPosition(contents.lastIndexOf('Y'), 1, CTOR_CALL),
768+
new HighlightedTypedPosition(contents.lastIndexOf('foo'), 3, FIELD),
769+
new HighlightedTypedPosition(contents.lastIndexOf('foo'), 3, MAP_KEY),
770+
new HighlightedTypedPosition(contents.lastIndexOf('bar'), 3, FIELD),
771+
new HighlightedTypedPosition(contents.lastIndexOf('bar'), 3, MAP_KEY),
772+
new HighlightedTypedPosition(contents.lastIndexOf('2'), 1, NUMBER))
773+
}
774+
745775
@Test
746776
void testEnumDefs() {
747777
String contents = '''\

0 commit comments

Comments
 (0)