From 6e9855afa784646abcbf0cc72dac2311e8fc4517 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Sat, 16 May 2020 09:09:13 -0500 Subject: [PATCH] Fix for #1113: open declaration (F3) on accessor should go to property --- .../internal/compiler/ast/JDTClassNode.java | 20 ++++- .../tests/CodeSelectFieldsTests.groovy | 24 +++++- .../tests/CodeSelectMethodsTests.groovy | 78 ++++++++++++++++++- .../requestor/CodeSelectRequestor.java | 4 + 4 files changed, 115 insertions(+), 11 deletions(-) diff --git a/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/JDTClassNode.java b/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/JDTClassNode.java index a479503443..5ac54ec1dd 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/JDTClassNode.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/JDTClassNode.java @@ -289,21 +289,31 @@ private void initializeMembers() { if (ClassHelper.boolean_TYPE.equals(pNode.getType())) { MethodNode mNode = addMethod("is" + capitalizedName, mMods, pNode.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null); if (!(mNode instanceof JDTNode)) { + mNode.setNameStart(pNode.getField().getNameStart()); + mNode.setNameEnd(pNode.getField().getNameEnd()); mNode.setSynthetic(true); - mNode = addMethod("get" + capitalizedName, mMods, pNode.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null); - if (!(mNode instanceof JDTNode)) { - mNode.setSynthetic(true); - } + + // GROOVY-9382: include "getter" if "isser" was not declared + mNode = addMethod("get" + capitalizedName, mMods, pNode.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null); + if (!(mNode instanceof JDTNode)) { + mNode.setNameStart(pNode.getField().getNameStart()); + mNode.setNameEnd(pNode.getField().getNameEnd()); + mNode.setSynthetic(true); + } } } else { MethodNode mNode = addMethod("get" + capitalizedName, mMods, pNode.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null); if (!(mNode instanceof JDTNode)) { + mNode.setNameStart(pNode.getField().getNameStart()); + mNode.setNameEnd(pNode.getField().getNameEnd()); mNode.setSynthetic(true); } } if (!Flags.isFinal(pNode.getModifiers())) { MethodNode mNode = addMethod("set" + capitalizedName, mMods, ClassHelper.VOID_TYPE, new Parameter[] {new Parameter(pNode.getType(), pName)}, ClassNode.EMPTY_ARRAY, null); if (!(mNode instanceof JDTNode)) { + mNode.setNameStart(pNode.getField().getNameStart()); + mNode.setNameEnd(pNode.getField().getNameEnd()); mNode.setSynthetic(true); } } @@ -575,11 +585,13 @@ public List getProperties() { if (synth) { field = new FieldNode(node.getName(), Flags.AccPrivate | (node.getModifiers() & Flags.AccStatic), resolver.resolve(node.getType().getName()), this, null); field.setDeclaringClass(this); + field.setSourcePosition(node.getField()); field.setSynthetic(true); } PropertyNode clone = new PropertyNode(field, node.getModifiers(), null, null); clone.setDeclaringClass(this); + clone.setSourcePosition(node); clone.setSynthetic(synth); nodes.add(clone); diff --git a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy index 54f2ae81ff..7955aa2db5 100644 --- a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy +++ b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectFieldsTests.groovy @@ -188,7 +188,7 @@ final class CodeSelectFieldsTests extends BrowsingTestSuite { | } |} |'''.stripMargin()], 'T__f', 'f') - assert elem.inferredElement.declaringClass.nameWithoutPackage == 'T' + assert elem.declaringType.fullyQualifiedName == 'T' } @Test // https://github.com/groovy/groovy-eclipse/issues/756 @@ -203,7 +203,7 @@ final class CodeSelectFieldsTests extends BrowsingTestSuite { | } |} |'''.stripMargin()], 'T__f', 'f') - assert elem.inferredElement.declaringClass.nameWithoutPackage == 'T' + assert elem.declaringType.fullyQualifiedName == 'T' } @Test // https://github.com/groovy/groovy-eclipse/issues/756 @@ -218,6 +218,24 @@ final class CodeSelectFieldsTests extends BrowsingTestSuite { | } |} |'''.stripMargin()], 'T__f', 'f') - assert elem.inferredElement.declaringClass.nameWithoutPackage == 'T' + assert elem.declaringType.fullyQualifiedName == 'T' + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/1113 + void testCodeSelectFieldFromTrait4() { + addGroovySource('''\ + |trait T { + | String f + |} + |'''.stripMargin()) + def elem = assertCodeSelect(['''\ + |class C implements T { + | def m() { + | f + | } + |} + |'''.stripMargin()], 'f') + assert elem.declaringType.fullyQualifiedName == 'T' + assert elem.elementInfo.nameSourceStart == 19 } } diff --git a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy index b45b183c20..da5e8c8742 100644 --- a/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy +++ b/ide-test/org.codehaus.groovy.eclipse.codebrowsing.test/src/org/codehaus/groovy/eclipse/codebrowsing/tests/CodeSelectMethodsTests.groovy @@ -126,7 +126,7 @@ final class CodeSelectMethodsTests extends BrowsingTestSuite { |'''.stripMargin() IJavaElement elem = assertCodeSelect([contents1, contents2], 'redirect') - assert elem.inferredElement.declaringClass.nameWithoutPackage == 'PlantController' + assert elem.declaringType.fullyQualifiedName == 'PlantController' } @Test // GRECLIPSE-1755 @@ -157,7 +157,7 @@ final class CodeSelectMethodsTests extends BrowsingTestSuite { |'''.stripMargin() IJavaElement elem = assertCodeSelect([contents1, contents2, contents3, contents4], 'foo') - assert elem.inferredElement.declaringClass.nameWithoutPackage == 'SuperInterface' + assert elem.declaringType.fullyQualifiedName == 'SuperInterface' } @Test @@ -276,7 +276,77 @@ final class CodeSelectMethodsTests extends BrowsingTestSuite { |} |'''.stripMargin() IJavaElement elem = assertCodeSelect([contents], 'x') - assert elem.inferredElement.declaringClass.nameWithoutPackage == 'T' + assert elem.declaringType.fullyQualifiedName == 'T' + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/960 + void testCodeSelectStaticMethodFromTrait4() { + String contents = '''\ + |trait T { + | Number number + |} + |class C implements T { + | def m() { + | getNumber() + | } + |} + |'''.stripMargin() + IJavaElement elem = assertCodeSelect([contents], 'getNumber') + assert elem.declaringType.fullyQualifiedName == 'T' + assert elem.elementInfo.nameSourceStart == contents.indexOf('number') + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/960 + void testCodeSelectStaticMethodFromTrait5() { + String contents = '''\ + |trait T { + | Number number + |} + |class C implements T { + | def m() { + | setNumber(42) + | } + |} + |'''.stripMargin() + IJavaElement elem = assertCodeSelect([contents], 'setNumber') + assert elem.declaringType.fullyQualifiedName == 'T' + assert elem.elementInfo.nameSourceStart == contents.indexOf('number') + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/960 + void testCodeSelectStaticMethodFromTrait6() { + String contents = '''\ + |trait T { + | boolean condition + |} + |class C implements T { + | def m() { + | isCondition() + | } + |} + |'''.stripMargin() + IJavaElement elem = assertCodeSelect([contents], 'isCondition') + assert elem.declaringType.fullyQualifiedName == 'T' + assert elem.elementInfo.nameSourceStart == contents.indexOf('condition') + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/1113 + void testCodeSelectStaticMethodFromTrait7() { + addGroovySource'''\ + |trait T { + | String foo + |} + |'''.stripMargin() + String contents = '''\ + |class C implements T { + | def m() { + | getFoo() + | } + |} + |'''.stripMargin() + IJavaElement elem = assertCodeSelect([contents], 'getFoo') + assert elem.declaringType.fullyQualifiedName == 'T' + assert elem.elementInfo.nameSourceStart == 19 } @Test @@ -372,7 +442,7 @@ final class CodeSelectMethodsTests extends BrowsingTestSuite { void testCodeSelectStaticMethod4() { String contents = 'List empty = Collections.&emptyList' IJavaElement elem = assertCodeSelect([contents], 'emptyList') - assert elem.inferredElement.returnType.toString(false) == 'java.util.List ' // want T to be java.lang.String + assert elem.inferredElement.returnType.toString(false) == 'java.util.List ' // TODO: want T to be java.lang.String } @Test diff --git a/ide/org.codehaus.groovy.eclipse.codebrowsing/src/org/codehaus/groovy/eclipse/codebrowsing/requestor/CodeSelectRequestor.java b/ide/org.codehaus.groovy.eclipse.codebrowsing/src/org/codehaus/groovy/eclipse/codebrowsing/requestor/CodeSelectRequestor.java index e6bd8b6f52..7fead88444 100644 --- a/ide/org.codehaus.groovy.eclipse.codebrowsing/src/org/codehaus/groovy/eclipse/codebrowsing/requestor/CodeSelectRequestor.java +++ b/ide/org.codehaus.groovy.eclipse.codebrowsing/src/org/codehaus/groovy/eclipse/codebrowsing/requestor/CodeSelectRequestor.java @@ -49,6 +49,7 @@ import org.codehaus.groovy.eclipse.codebrowsing.elements.GroovyResolvedSourceMethod; import org.codehaus.groovy.eclipse.codebrowsing.elements.GroovyResolvedSourceType; import org.codehaus.groovy.eclipse.core.GroovyCore; +import org.codehaus.groovy.transform.trait.Traits; import org.codehaus.jdt.groovy.internal.compiler.ast.JDTFieldNode; import org.codehaus.jdt.groovy.internal.compiler.ast.JDTMethodNode; import org.codehaus.jdt.groovy.model.GroovyCompilationUnit; @@ -523,6 +524,9 @@ private boolean existsOnlyInGroovyModel(final FieldNode node, final String name, return true; } // check for @Trait field + if (!node.isFinal() && !node.isStatic() && Traits.isTrait(node.getDeclaringClass())) { + return true; + } List traitFields = declaringType.redirect().getNodeMetaData("trait.fields"); if (traitFields != null) { for (FieldNode traitField : traitFields) {