Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ public void visitClass(final ClassNode node) {
classNode = node;
thisField = null;

if (node.isEnum() || node.isInterface() || isTrait(node.getOuterClass())) return;
// GROOVY-8587: trait helpers must not get the standard MOP methods, but
// GROOVY-12226: classes declared within a trait are ordinary inner classes
if (node.isEnum() || node.isInterface() || isTraitHelper(node)) return;

// if the class has an inner class, add methods to support private member access
if (node.getInnerClasses().hasNext()) {
Expand Down Expand Up @@ -149,6 +151,17 @@ public void visitConstructor(final ConstructorNode node) {
}
}

/**
* Tests for one of the classes generated for a trait, i.e. the helper, the
* field helper or the static field helper. Classes declared within a trait
* are not included.
*/
private static boolean isTraitHelper(final ClassNode node) {
ClassNode outerClass = node.getOuterClass();
return isTrait(outerClass) && (node.getModifiers() & ACC_SYNTHETIC) != 0
&& node.getName().startsWith(outerClass.getName() + "$Trait$");
}

private static void makeBridgeConstructor(final ClassNode c, final Parameter[] p) {
Parameter[] newP = new Parameter[p.length + 1];
for (int i = 0; i < p.length; i += 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,54 @@ final class TraitASTTransformationTest {
'''
}

// GROOVY-12226
@Test
void testStaticInnerClassInTrait2() {
assertScript shell, '''
trait T {
static class Outer {
def outerMethod() { 'foo' }
def outerProperty = 'bar'
class Inner {
def callOuter() { outerMethod() }
def readOuter() { outerProperty }
}
def viaInner() {
def inner = new Inner()
inner.callOuter() + inner.readOuter()
}
}
}
class Foo implements T {
}
assert new T.Outer().viaInner() == 'foobar'
'''
}

// GROOVY-12226: class name collides with the trait helper prefix
@Test
void testStaticInnerClassInTrait3() {
assertScript shell, '''
trait T {
static class Trait$Outer {
def outerMethod() { 'foo' }
def outerProperty = 'bar'
class Inner {
def callOuter() { outerMethod() }
def readOuter() { outerProperty }
}
def viaInner() {
def inner = new Inner()
inner.callOuter() + inner.readOuter()
}
}
}
class Foo implements T {
}
assert new T.Trait$Outer().viaInner() == 'foobar'
'''
}

@Test
void testNonStaticInnerClassInTrait() {
shouldFail shell, '''
Expand Down
Loading