From 2927b89bf4d45257997178279f912231b31050ec Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Sat, 6 Apr 2024 14:02:50 -0500 Subject: [PATCH] GROOVY-11319 --- .../tests/xform/StaticCompilationTests.java | 36 +++++-------- .../stc/StaticTypeCheckingVisitor.java | 52 +++++++++++++++++-- 2 files changed, 62 insertions(+), 26 deletions(-) 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 b1c6218449..99592bb5aa 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 @@ -3682,17 +3682,13 @@ public void testCompileStatic9007or9043_enumConstToPrivate1() { }; //@formatter:on - if (!isAtLeastGroovy(40)) { - runConformTest(sources, "", "groovy.lang.MissingPropertyException: No such property: name for class: E"); - } else { - runNegativeTest(sources, - "----------\n" + - "1. ERROR in Main.groovy (at line 6)\n" + - "\tprint E.ONE.name\n" + - "\t ^^^^^^^^^^\n" + - "Groovy:[Static type checking] - No such property: name for class: E\n" + - "----------\n"); - } + runNegativeTest(sources, + "----------\n" + + "1. ERROR in Main.groovy (at line 6)\n" + + "\tprint E.ONE.name\n" + + "\t ^^^^^^^^^^\n" + + "Groovy:[Static type checking] - No such property: name for class: E\n" + + "----------\n"); } @Test @@ -3711,17 +3707,13 @@ public void testCompileStatic9007or9043_enumConstToPrivate2() { }; //@formatter:on - if (!isAtLeastGroovy(40)) { - runConformTest(sources, "", "groovy.lang.MissingPropertyException: No such property: ordinal for class: E"); - } else { - runNegativeTest(sources, - "----------\n" + - "1. ERROR in Main.groovy (at line 6)\n" + - "\tprint E.ONE.ordinal\n" + - "\t ^^^^^^^^^^^^^\n" + - "Groovy:[Static type checking] - No such property: ordinal for class: E\n" + - "----------\n"); - } + runNegativeTest(sources, + "----------\n" + + "1. ERROR in Main.groovy (at line 6)\n" + + "\tprint E.ONE.ordinal\n" + + "\t ^^^^^^^^^^^^^\n" + + "Groovy:[Static type checking] - No such property: ordinal for class: E\n" + + "----------\n"); } @Test 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 59d02513b2..cdadcffbbd 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 @@ -713,8 +713,15 @@ public void visitPropertyExpression(final PropertyExpression expression) { if (!extension.handleUnresolvedProperty(expression)) { Expression objectExpression = expression.getObjectExpression(); + /* GRECLIPSE edit addStaticTypeError("No such property: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(findCurrentInstanceOfClass(objectExpression, getType(objectExpression))), expression); + */ + ClassNode objectExpressionType = (objectExpression instanceof ClassExpression + ? objectExpression.getType() : wrapTypeIfNecessary(getType(objectExpression))); + objectExpressionType = findCurrentInstanceOfClass(objectExpression, objectExpressionType); + addStaticTypeError("No such property: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(objectExpressionType), expression); + // GRECLIPSE end } } @@ -724,8 +731,15 @@ public void visitAttributeExpression(final AttributeExpression expression) { if (!extension.handleUnresolvedAttribute(expression)) { Expression objectExpression = expression.getObjectExpression(); + /* GRECLIPSE edit addStaticTypeError("No such attribute: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(findCurrentInstanceOfClass(objectExpression, getType(objectExpression))), expression); + */ + ClassNode objectExpressionType = (objectExpression instanceof ClassExpression + ? objectExpression.getType() : wrapTypeIfNecessary(getType(objectExpression))); + objectExpressionType = findCurrentInstanceOfClass(objectExpression, objectExpressionType); + addStaticTypeError("No such attribute: " + expression.getPropertyAsString() + " for class: " + prettyPrintTypeName(objectExpressionType), expression); + // GRECLIPSE end } } @@ -1608,9 +1622,13 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re property = allowStaticAccessToMember(property, staticOnly); // prefer explicit getter or setter over property if receiver is not 'this' if (property == null || !enclosingTypes.contains(receiverType)) { + ClassNode enclosingType = enclosingTypes.iterator().next(); if (readMode) { - if (getter != null // GRECLIPSE add -- GROOVY-6277 - && hasAccessToMember(enclosingTypes.iterator().next(), getter.getDeclaringClass(), getter.getModifiers())) { + /* GRECLIPSE edit -- GROOVY-6277, GROOVY-11319 + if (getter != null) { + */ + if (getter != null && hasAccessToMember(enclosingType, getter.getDeclaringClass(), getter.getModifiers())) { + // GRECLIPSE end ClassNode returnType = inferReturnTypeGenerics(receiverType, getter, ArgumentListExpression.EMPTY_ARGUMENTS); storeInferredTypeForPropertyExpression(pexp, returnType); storeTargetMethod(pexp, getter); @@ -1620,8 +1638,15 @@ && hasAccessToMember(enclosingTypes.iterator().next(), getter.getDeclaringClass( } return true; } + // GRECLIPSE add + else getter = null; + // GRECLIPSE end } else { + /* GRECLIPSE edit if (!setters.isEmpty()) { + */ + if (setters.stream().anyMatch(setter -> hasAccessToMember(enclosingType, setter.getDeclaringClass(), setter.getModifiers()))) { + // GRECLIPSE and if (visitor != null) { for (MethodNode setter : setters) { // visiting setter will not infer the property type since return type is void, so visit a dummy field instead @@ -1641,9 +1666,16 @@ && hasAccessToMember(enclosingTypes.iterator().next(), getter.getDeclaringClass( } pexp.removeNodeMetaData(READONLY_PROPERTY); return true; + /* GRECLIPSE edit } else if (getter != null && field == null) { + */ + } else if (field == null && getter != null && hasAccessToMember(enclosingType, getter.getDeclaringClass(), getter.getModifiers())) { + // GRECLIPSE end pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE); // GROOVY-9127 } + // GRECLIPSE add + else setters.clear(); + // GRECLIPSE end } } @@ -1651,7 +1683,7 @@ && hasAccessToMember(enclosingTypes.iterator().next(), getter.getDeclaringClass( if (field != null && storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) return true; - foundGetterOrSetter = (foundGetterOrSetter || !setters.isEmpty() || getter != null); + foundGetterOrSetter = (foundGetterOrSetter || getter != null || !setters.isEmpty()); } // GROOVY-5568: the property may be defined by DGM @@ -1853,6 +1885,7 @@ private boolean isStaticInContext(final MethodNode method) { private boolean storeField(final FieldNode field, final PropertyExpression expressionToStoreOn, final ClassNode receiver, final ClassCodeVisitorSupport visitor, final String delegationData, final boolean lhsOfAssignment) { if (visitor != null) visitor.visitField(field); checkOrMarkPrivateAccess(expressionToStoreOn, field, lhsOfAssignment); + /* GRECLIPSE edit -- GROOVY-11319 boolean accessible = hasAccessToMember(isSuperExpression(expressionToStoreOn.getObjectExpression()) ? typeCheckingContext.getEnclosingClassNode() : receiver, field.getDeclaringClass(), field.getModifiers()); if (expressionToStoreOn instanceof AttributeExpression) { // TODO: expand to include PropertyExpression @@ -1860,7 +1893,18 @@ private boolean storeField(final FieldNode field, final PropertyExpression expre addStaticTypeError("The field " + field.getDeclaringClass().getNameWithoutPackage() + "." + field.getName() + " is not accessible", expressionToStoreOn.getProperty()); } } - + */ + boolean superField = isSuperExpression(expressionToStoreOn.getObjectExpression()); + boolean accessible = ( !superField && receiver.equals(field.getDeclaringClass()) ) // GROOVY-7300 + || hasAccessToMember(typeCheckingContext.getEnclosingClassNode(), field.getDeclaringClass(), field.getModifiers()); + if (!accessible) { + if (expressionToStoreOn instanceof AttributeExpression) { + addStaticTypeError("Cannot access field: " + field.getName() + " of class: " + prettyPrintTypeName(field.getDeclaringClass()), expressionToStoreOn.getProperty()); + } else if (field.isPrivate()) { + return false; + } + } + // GRECLIPSE end storeWithResolve(field.getOriginType(), receiver, field.getDeclaringClass(), field.isStatic(), expressionToStoreOn); if (delegationData != null) { expressionToStoreOn.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);