diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java index 78ce09843a..033dd461fa 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java @@ -1581,6 +1581,46 @@ public void testCompileStatic7996d() { runConformTest(sources, "true"); } + @Test + public void testCompileStatic7996e() { + //@formatter:off + String[] sources = { + "Main.groovy", + "import groovy.transform.*\n" + + "import org.codehaus.groovy.ast.DynamicVariable\n" + + "import org.codehaus.groovy.ast.expr.VariableExpression\n" + + "import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE\n" + + "import static org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_TYPE\n" + + "import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.PROPERTY_OWNER\n" + + + "class JSON {\n" + + " def get(String name) {\n" + + " }\n" + + "}\n" + + "class POGO {\n" + + " Number getAnswer() {\n" + + " }\n" + + " @CompileStatic\n" + + " void usage() {\n" + + " new JSON().with {\n" + + " @ASTTest(phase=CLASS_GENERATION, value={\n" + + " def vexp = node.rightExpression\n" + + " assert vexp instanceof VariableExpression\n" + + " assert vexp.accessedVariable instanceof DynamicVariable\n" + + " assert vexp.getNodeMetaData(INFERRED_TYPE) == OBJECT_TYPE\n" + + " assert vexp.getNodeMetaData(PROPERTY_OWNER).name == 'JSON'\n" + + " })\n" + + " def result = answer\n" + // "answer" accessed from JSON; "getAnswer()" invoked from POGO + " }\n" + + " }\n" + + "}\n" + + "new POGO().usage()\n", + }; + //@formatter:on + + runConformTest(sources, ""); + } + @Test public void testCompileStatic8051() { //@formatter:off diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index f99defa143..1193dddd48 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -774,8 +774,10 @@ private boolean tryVariableExpressionAsProperty(final VariableExpression vexp, f storeType(vexp, type != null ? type: pexp.getType()); String receiver = vexp.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER); - // GROOVY-7701: correct false assumption made by VariableScopeVisitor - if (receiver != null && !receiver.endsWith("owner") && !(vexp.getAccessedVariable() instanceof DynamicVariable)) { + Boolean dynamic = pexp.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION); + // GROOVY-7701, GROOVY-7996: correct false assumption made by VariableScopeVisitor + if (((receiver != null && !receiver.endsWith("owner")) || Boolean.TRUE.equals(dynamic)) + && !(vexp.getAccessedVariable() instanceof DynamicVariable)) { vexp.setAccessedVariable(new DynamicVariable(dynName, false)); } return true; @@ -1694,10 +1696,11 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re } if (mopMethod == null) mopMethod = receiverType.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "propertyName")}); - if (mopMethod != null && !mopMethod.isSynthetic()) { + if (mopMethod != null && !mopMethod.isStatic() && !mopMethod.isSynthetic()) { pexp.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.removeNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE); pexp.removeNodeMetaData(StaticTypesMarker.INFERRED_TYPE); + visitor.visitMethod(mopMethod); return true; } } diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index d337e74887..0e79125fe6 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -685,8 +685,10 @@ private boolean tryVariableExpressionAsProperty(final VariableExpression vexp, f storeType(vexp, Optional.ofNullable(type).orElseGet(pexp::getType)); String receiver = vexp.getNodeMetaData(IMPLICIT_RECEIVER); - // GROOVY-7701: correct false assumption made by VariableScopeVisitor - if (receiver != null && !receiver.endsWith("owner") && !(vexp.getAccessedVariable() instanceof DynamicVariable)) { + Boolean dynamic = pexp.getNodeMetaData(DYNAMIC_RESOLUTION); + // GROOVY-7701, GROOVY-7996: correct false assumption made by VariableScopeVisitor + if (((receiver != null && !receiver.endsWith("owner")) || Boolean.TRUE.equals(dynamic)) + && !(vexp.getAccessedVariable() instanceof DynamicVariable)) { vexp.setAccessedVariable(new DynamicVariable(dynName, false)); } return true; @@ -1661,10 +1663,11 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re } if (mopMethod == null) mopMethod = receiverType.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "propertyName")}); - if (mopMethod != null && !mopMethod.isSynthetic()) { + if (mopMethod != null && !mopMethod.isStatic() && !mopMethod.isSynthetic()) { pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE); pexp.removeNodeMetaData(INFERRED_TYPE); + visitor.visitMethod(mopMethod); return true; } } diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 0e50551aeb..c2cae298ec 100644 --- a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -685,8 +685,10 @@ private boolean tryVariableExpressionAsProperty(final VariableExpression vexp, f storeType(vexp, Optional.ofNullable(type).orElseGet(pexp::getType)); String receiver = vexp.getNodeMetaData(IMPLICIT_RECEIVER); - // GROOVY-7701: correct false assumption made by VariableScopeVisitor - if (receiver != null && !receiver.endsWith("owner") && !(vexp.getAccessedVariable() instanceof DynamicVariable)) { + Boolean dynamic = pexp.getNodeMetaData(DYNAMIC_RESOLUTION); + // GROOVY-7701, GROOVY-7996: correct false assumption made by VariableScopeVisitor + if (((receiver != null && !receiver.endsWith("owner")) || Boolean.TRUE.equals(dynamic)) + && !(vexp.getAccessedVariable() instanceof DynamicVariable)) { vexp.setAccessedVariable(new DynamicVariable(dynName, false)); } return true; @@ -1653,10 +1655,11 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re } if (mopMethod == null) mopMethod = receiverType.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "propertyName")}); - if (mopMethod != null && !mopMethod.isSynthetic()) { + if (mopMethod != null && !mopMethod.isStatic() && !mopMethod.isSynthetic()) { pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE); pexp.removeNodeMetaData(INFERRED_TYPE); + visitor.visitMethod(mopMethod); return true; } }