Skip to content

Commit

Permalink
Fix for #1542: create a @Generated annotation for each delegate method
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Feb 4, 2024
1 parent 9f3799e commit b61a5e4
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 234 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2023 the original author or authors.
* Copyright 2009-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,7 +15,9 @@
*/
package org.codehaus.jdt.groovy.internal.compiler.ast;

import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.isGenerated;
import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.plus;
import static org.codehaus.groovy.runtime.StringGroovyMethods.find;

import java.io.PrintWriter;
Expand Down Expand Up @@ -1523,10 +1525,10 @@ private void createConstructorDeclarations(ClassNode classNode, List<AbstractMet
if (!variables.isEmpty()) constructorDecl.statements = createStatements(variables.values());
}
if (constructorNode.hasDefaultValue()) {
Annotation[] generated = createAnnotations(ClassHelper.make(groovy.transform.Generated.class));
for (Argument[] variantArgs : getVariantsAllowingForDefaulting(constructorNode.getParameters(), constructorDecl.arguments)) {
ConstructorDeclaration variantDecl = new ConstructorDeclaration(unitDeclaration.compilationResult);
variantDecl.annotations = constructorDecl.annotations == null ? generated : ArrayUtils.concat(constructorDecl.annotations, generated);
variantDecl.annotations = createAnnotations(isGenerated(constructorNode) ? constructorNode.getAnnotations()
: plus(constructorNode.getAnnotations(), new AnnotationNode(ClassHelper.make(groovy.transform.Generated.class))));
variantDecl.arguments = variantArgs;
variantDecl.bits = constructorDecl.bits;
variantDecl.javadoc = constructorDecl.javadoc;
Expand Down Expand Up @@ -1601,10 +1603,11 @@ private void createMethodDeclarations(ClassNode classNode, GroovyTypeDeclaration
}

if (methodNode.hasDefaultValue()) {
Annotation[] generated = createAnnotations(ClassHelper.make(groovy.transform.Generated.class));
for (Argument[] variantArgs : getVariantsAllowingForDefaulting(methodNode.getParameters(), methodDecl.arguments)) {
AbstractMethodDeclaration variantDecl = createMethodDeclaration(classNode, methodNode);
variantDecl.annotations = variantDecl.annotations == null ? generated : ArrayUtils.concat(variantDecl.annotations, generated);
variantDecl.annotations = ArrayUtils.concat(
variantDecl.annotations != null ? variantDecl.annotations : new Annotation[0],
createAnnotations(ClassHelper.make(groovy.transform.Generated.class)));
variantDecl.arguments = variantArgs;

variantDecl.declarationSourceStart = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.codehaus.groovy.ast.Parameter;
import org.eclipse.core.expressions.PropertyTester;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.core.runtime.IAdaptable;

public class GroovyPropertyTester extends PropertyTester {

Expand All @@ -50,17 +49,15 @@ private static boolean oneStringArray(Parameter[] p) {

@Override
public boolean test(Object receiver, String property, Object[] arguments, Object expectedValue) {
if (receiver instanceof IAdaptable) {
ModuleNode node = Adapters.adapt(receiver, ModuleNode.class);
if (node != null && !Boolean.TRUE.equals(node.getNodeMetaData("ParseError"))) {
switch (property) {
case "hasMain":
return node.getClasses().stream().flatMap(cn -> cn.getDeclaredMethods("main").stream()).anyMatch(JAVA_MAIN);
case "isScript":
return !node.getStatementBlock().isEmpty() || (!node.getClasses().isEmpty() &&
node.getClasses().get(0).getNameEnd() < 1 /* un-named */ && getGroovyVersion().getMajor() >= 5 &&
node.getClasses().get(0).getDeclaredMethods("main").stream().anyMatch(JEP_445_MAIN.and(JAVA_MAIN.negate())));
}
ModuleNode node = Adapters.adapt(receiver, ModuleNode.class);
if (node != null && !node.encounteredUnrecoverableError()) {
switch (property) {
case "hasMain":
return node.getClasses().stream().flatMap(cn -> cn.getDeclaredMethods("main").stream()).anyMatch(JAVA_MAIN);
case "isScript":
return !node.getStatementBlock().isEmpty() || (!node.getClasses().isEmpty() &&
node.getClasses().get(0).getNameEnd() < 1 /* un-named */ && getGroovyVersion().getMajor() >= 5 &&
node.getClasses().get(0).getDeclaredMethods("main").stream().anyMatch(JEP_445_MAIN.and(JAVA_MAIN.negate())));
}
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
Expand Down Expand Up @@ -427,7 +428,7 @@ public static Expression getTraitFieldExpression(MethodCallExpression call) {
} else if (objType.equals(ClassHelper.CLASS_Type) && asBoolean(objType.getGenericsTypes())) {
objType = objType.getGenericsTypes()[0].getType(); // look for $static$self.T__name$get()
}
if (Traits.isTrait(objType)) {
if (Traits.isTrait(objType) && call.getMethod() instanceof ConstantExpression) {
Matcher m = Pattern.compile(".+__(\\p{javaJavaIdentifierPart}+)\\$[gs]et").matcher(call.getMethodAsString());
if (m.matches()) {
String fieldName = m.group(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2071,14 +2071,14 @@ private boolean handleSimpleExpression(final Expression node) {
primaryType = null; // implicit-this calls are handled like free variables
isStatic = scope.isStatic();
} else {
isStatic = mce.getObjectExpression() instanceof ClassExpression || primaryType.equals(VariableScope.CLASS_CLASS_NODE);
isStatic = mce.getObjectExpression() instanceof ClassExpression || VariableScope.CLASS_CLASS_NODE.equals(primaryType);
}
} else if (enclosingNode instanceof PropertyExpression) {
PropertyExpression pe = (PropertyExpression) enclosingNode;
isStatic = pe.getObjectExpression() instanceof ClassExpression || primaryType.equals(VariableScope.CLASS_CLASS_NODE);
isStatic = pe.getObjectExpression() instanceof ClassExpression || VariableScope.CLASS_CLASS_NODE.equals(primaryType);
} else if (enclosingNode instanceof MethodPointerExpression) {
MethodPointerExpression mpe = (MethodPointerExpression) enclosingNode;
isStatic = mpe.getExpression() instanceof ClassExpression || primaryType.equals(VariableScope.CLASS_CLASS_NODE);
isStatic = mpe.getExpression() instanceof ClassExpression || VariableScope.CLASS_CLASS_NODE.equals(primaryType);
} else /*if (enclosingNode instanceof ImportNode)*/ {
isStatic = true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2023 the original author or authors.
* Copyright 2009-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -94,6 +94,7 @@ import org.junit.runners.Suite
// org.codehaus.groovy.eclipse.junit.tests
org.codehaus.groovy.eclipse.junit.test.JUnit3TestFinderTests,
org.codehaus.groovy.eclipse.junit.test.JUnit4TestFinderTests,
org.codehaus.groovy.eclipse.junit.test.JUnit5TestFinderTests,
org.codehaus.groovy.eclipse.junit.test.MainMethodFinderTests,

// org.codehaus.groovy.eclipse.quickfix.tests
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2020 the original author or authors.
* Copyright 2009-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,87 +15,119 @@
*/
package org.codehaus.groovy.eclipse.junit.test

import org.codehaus.groovy.eclipse.test.GroovyEclipseTestSuite
import org.codehaus.groovy.eclipse.test.SynchronizationUtils
import org.eclipse.jdt.core.ICompilationUnit
import org.eclipse.jdt.core.IType
import org.eclipse.jdt.internal.junit.launcher.JUnit3TestFinder
import org.junit.Before
import org.junit.Test

final class JUnit3TestFinderTests extends JUnitTestSuite {
final class JUnit3TestFinderTests extends GroovyEclipseTestSuite {

private void assertTypeIsTest(boolean expected, ICompilationUnit unit, String typeName, String reasonText = '') {
@Before
void setUp() {
addJUnit(3)
}

private Set<IType> getAllTests() {
Set<IType> testTypes = []
SynchronizationUtils.waitForIndexingToComplete()
new JUnit3TestFinder().findTestsInContainer(packageFragmentRoot, testTypes, null)
return testTypes
}

private boolean isTest(ICompilationUnit unit, String typeName = unit.types[0].elementName) {
def type = unit.getType(typeName)
assert type.exists() : "Groovy type $typeName should exist"
assert new JUnit3TestFinder().isTest(type) == expected : "Groovy type $typeName should${expected ? '' : 'n\'t'} be a JUnit 3 test $reasonText"
return new JUnit3TestFinder().isTest(type)
}

//--------------------------------------------------------------------------

@Test
void testFinderWithSuite() {
def test = addGroovySource '''
class A {
static junit.framework.Test suite() throws Exception {}
void testIsTest0() {
def unit = addGroovySource '''
class C {
void test() { }
}
'''
''', 'C', 'p'
assert !isTest(unit)
}

assertTypeIsTest(true, test, 'A')
@Test
void testIsTest1() {
def unit = addGroovySource '''
class C extends junit.framework.TestCase {
void test() { }
}
''', 'C', 'p'
assert isTest(unit)
}

@Test
void testFinderOfSubclass() {
def base = addGroovySource '''
abstract class TestBase extends junit.framework.TestCase {
void testIsTest2() {
def unit = addGroovySource '''
class C {
static junit.framework.Test suite() { }
}
'''
''', 'C', 'p'
assert isTest(unit)
}

def test = addGroovySource '''
class B extends TestBase {
@Test
void testIsTest3() {
def unit = addGroovySource '''
abstract class TestBase extends junit.framework.TestCase {
}
'''
''', 'TestBase', 'p'
assert !isTest(unit)

assertTypeIsTest(false, base, 'TestBase', '(it is abstract)')
assertTypeIsTest(true, test, 'B')
unit = addGroovySource '''
class C extends TestBase {
}
''', 'C', 'p'
assert isTest(unit)
}

@Test
void testFinderOfNonPublicSubclass() {
def base = addGroovySource '''
void testIsTest4() {
def unit = addGroovySource '''
abstract class TestBase extends junit.framework.TestCase {
}
'''
''', 'TestBase', 'p'
assert !isTest(unit)

def test = addGroovySource '''
unit = addGroovySource '''
@groovy.transform.PackageScope class C extends TestBase {
}
'''

assertTypeIsTest(false, base, 'TestBase', '(it is abstract)')
assertTypeIsTest(true, test, 'C')
''', 'C', 'p'
assert isTest(unit)
}

//

@Test
void testFindAllTestSuites() {
void testFindTests() {
addGroovySource '''
abstract class TestBase extends junit.framework.TestCase {
}
'''

''', 'TestBase', 'p'
addGroovySource '''
class X extends TestBase {
}
'''

''', 'X', 'p'
addGroovySource '''
class Y extends junit.framework.TestCase {
}
'''

''', 'Y', 'p'
addGroovySource '''
class Z {
static junit.framework.Test suite() throws Exception {}
}
'''
''', 'Z', 'p'

Set<IType> testTypes = []
new JUnit3TestFinder().findTestsInContainer(packageFragmentRoot, testTypes, null)
Set<IType> testTypes = allTests

assert testTypes.any { it.elementName == 'X' } : 'X should be a test type'
assert testTypes.any { it.elementName == 'Y' } : 'Y should be a test type'
Expand Down

0 comments on commit b61a5e4

Please sign in to comment.