From 2e38fd8bbe38d3a206b97ba7988e6e8e3d718367 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Thu, 24 Nov 2022 14:16:21 -0600 Subject: [PATCH] GROOVY-10177 --- .../groovy/ast/ImmutableClassNode.java | 10 +++++- .../groovy/ast/ImmutableClassNode.java | 10 +++++- .../groovy/ast/ImmutableClassNode.java | 10 +++++- .../internal/compiler/ast/JDTClassNode.java | 34 +++++++++++++++++-- .../jdt/groovy/search/VariableScope.java | 23 +++---------- 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/ImmutableClassNode.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/ImmutableClassNode.java index df26380648..8cd9f15ae0 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/ImmutableClassNode.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/ImmutableClassNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 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. @@ -83,6 +83,14 @@ public void setSynthetic(boolean b) {} // ClassNode overrides: + @Override + public void addProperty(PropertyNode pn) {} + + @Override + public List getProperties() { + return Collections.emptyList(); + } + @Override public List getDeclaredMethods(String name) { if (lazyInitDone && !writeProtected) { diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/ImmutableClassNode.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/ImmutableClassNode.java index df26380648..8cd9f15ae0 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/ImmutableClassNode.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/ImmutableClassNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 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. @@ -83,6 +83,14 @@ public void setSynthetic(boolean b) {} // ClassNode overrides: + @Override + public void addProperty(PropertyNode pn) {} + + @Override + public List getProperties() { + return Collections.emptyList(); + } + @Override public List getDeclaredMethods(String name) { if (lazyInitDone && !writeProtected) { diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/ast/ImmutableClassNode.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/ast/ImmutableClassNode.java index 3c056ecb6c..2cd1363a88 100644 --- a/base/org.codehaus.groovy40/src/org/codehaus/groovy/ast/ImmutableClassNode.java +++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/ast/ImmutableClassNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 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. @@ -83,6 +83,9 @@ public void setSynthetic(boolean b) {} // ClassNode overrides: + @Override + public void addProperty(PropertyNode pn) {} + @Override public void addTypeAnnotation(AnnotationNode an) {} @@ -119,6 +122,11 @@ public List getDeclaredMethods(String name) { return super.getDeclaredMethods(name); } + @Override + public List getProperties() { + return Collections.emptyList(); + } + @Override public void setAnnotated(boolean b) {} 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 5abdcc73d0..136bdf58a7 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 @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 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. @@ -15,6 +15,9 @@ */ package org.codehaus.jdt.groovy.internal.compiler.ast; +import static org.eclipse.jdt.groovy.search.AccessorSupport.isGetter; + +import java.beans.Introspector; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -581,13 +584,13 @@ void setUpGenerics() { @Override public void addProperty(final PropertyNode node) { - throw new UnsupportedOperationException("JDTClassNode is immutable, should not be called to add property: " + node.getName()); + throw new UnsupportedOperationException("JDTClassNode cannot accept property: " + node.getName()); } @Override public PropertyNode addProperty(final String name, final int modifiers, final ClassNode type, final Expression initialValueExpression, final Statement getterBlock, final Statement setterBlock) { - throw new UnsupportedOperationException("JDTClassNode is immutable, should not be called to add property: " + name); + throw new UnsupportedOperationException("JDTClassNode cannot accept property: " + name); } @Override @@ -616,6 +619,22 @@ public List getProperties() { nodes.add(clone); } + } else { + // hydrate properties from getters + for (MethodNode mn : getMethods()) { + if (mn.isPublic() && isGetter(mn) && isGenerated(mn) && !"getMetaClass".equals(mn.getName())) { + String propertyName = Introspector.decapitalize(mn.getName().substring(mn.getName().startsWith("is") ? 2 : 3)); + // check for field with same name/type + FieldNode fn = getField(propertyName); + if (fn != null && fn.isPrivate() && fn.getType().equals(mn.getReturnType())) { + PropertyNode pn = new PropertyNode(fn, fn.getModifiers() & (Flags.AccFinal | Flags.AccStatic), null, null); + pn.addAnnotations(fn.getAnnotations()); + pn.setDeclaringClass(this); + + super.getProperties().add(pn); + } + } + } } bits |= PROPERTIES_INITIALIZED; } @@ -625,6 +644,15 @@ public List getProperties() { return Collections.unmodifiableList(super.getProperties()); } + private static boolean isGenerated(MethodNode mn) { + for (AnnotationNode an : mn.getAnnotations()) { + if (an.getClassNode().getName().equals("groovy.transform.Generated")) { + return true; + } + } + return false; + } + @Override public Iterator getInnerClasses() { if ((bits & INNER_TYPES_INITIALIZED) == 0) { diff --git a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/VariableScope.java b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/VariableScope.java index ff89205348..25650b9858 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/VariableScope.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/search/VariableScope.java @@ -19,7 +19,6 @@ import static org.codehaus.groovy.ast.tools.GenericsUtils.parseClassNodesFromString; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.evaluateExpression; -import java.beans.Introspector; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -61,7 +60,6 @@ import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.ModuleNode; import org.codehaus.groovy.ast.Parameter; -import org.codehaus.groovy.ast.PropertyNode; import org.codehaus.groovy.ast.Variable; import org.codehaus.groovy.ast.expr.BinaryExpression; import org.codehaus.groovy.ast.expr.ClassExpression; @@ -97,10 +95,10 @@ public class VariableScope implements Iterable { public static final ClassNode VOID_CLASS_NODE = ClassHelper.VOID_TYPE; // void.class public static final ClassNode VOID_WRAPPER_CLASS_NODE = ClassHelper.void_WRAPPER_TYPE; // Void.class + public static final ClassNode CLASS_CLASS_NODE = ClassHelper.CLASS_Type; public static final ClassNode OBJECT_CLASS_NODE = ClassHelper.OBJECT_TYPE; public static final ClassNode GROOVY_OBJECT_CLASS_NODE = ClassHelper.GROOVY_OBJECT_TYPE; public static final ClassNode GROOVY_SUPPORT_CLASS_NODE = ClassHelper.GROOVY_OBJECT_SUPPORT_TYPE; - public static final ClassNode CLOSURE_CLASS_NODE = ClassHelper.CLOSURE_TYPE; public static final ClassNode ENUMERATION_CLASS_NODE = ClassHelper.make(Enumeration.class); public static final ClassNode COLLECTION_CLASS_NODE = ClassHelper.make(Collection.class); public static final ClassNode ITERABLE_CLASS_NODE = ClassHelper.make(Iterable.class); @@ -110,11 +108,12 @@ public class VariableScope implements Iterable { public static final ClassNode ENTRY_CLASS_NODE = ClassHelper.make(Map.Entry.class); public static final ClassNode RANGE_CLASS_NODE = ClassHelper.RANGE_TYPE; public static final ClassNode TUPLE_CLASS_NODE = ClassHelper.make(Tuple.class); - public static final ClassNode STRING_CLASS_NODE = ClassHelper.STRING_TYPE; - public static final ClassNode GSTRING_CLASS_NODE = ClassHelper.GSTRING_TYPE; - public static final ClassNode NUMBER_CLASS_NODE = ClassHelper.Number_TYPE; public static final ClassNode BIG_DECIMAL_CLASS = ClassHelper.BigDecimal_TYPE; public static final ClassNode BIG_INTEGER_CLASS = ClassHelper.BigInteger_TYPE; + public static final ClassNode NUMBER_CLASS_NODE = ClassHelper.Number_TYPE; + public static final ClassNode STRING_CLASS_NODE = ClassHelper.STRING_TYPE; + public static final ClassNode GSTRING_CLASS_NODE = ClassHelper.GSTRING_TYPE; + public static final ClassNode CLOSURE_CLASS_NODE = ClassHelper.CLOSURE_TYPE; public static final ClassNode PATTERN_CLASS_NODE = ClassHelper.PATTERN_TYPE; public static final ClassNode MATCHER_CLASS_NODE = ClassHelper.make(Matcher.class); @@ -144,18 +143,6 @@ public class VariableScope implements Iterable { public static final ClassNode FLOAT_CLASS_NODE = ClassHelper.Float_TYPE; public static final ClassNode DOUBLE_CLASS_NODE = ClassHelper.Double_TYPE; - // don't cache because we have to add properties - public static final ClassNode CLASS_CLASS_NODE = initializeProperties(ClassHelper.makeWithoutCaching(Class.class)); - - // NOTE: JDTClassNode contains very similar method - private static ClassNode initializeProperties(ClassNode node) { - node.getMethods().stream().filter(AccessorSupport::isGetter).forEach(methodNode -> { - String propertyName = Introspector.decapitalize(methodNode.getName().substring(methodNode.getName().startsWith("is") ? 2 : 3)); - node.addProperty(new PropertyNode(propertyName, methodNode.getModifiers(), methodNode.getReturnType(), null, null, null, null)); - }); - return node; - } - //-------------------------------------------------------------------------- /**