This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push: new 6953697ca2 node meta data 6953697ca2 is described below commit 6953697ca27d69bf03271c83cd22348dfc58ea5f Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Tue Aug 29 12:17:15 2023 -0500 node meta data --- .../apache/groovy/parser/antlr4/AstBuilder.java | 100 ++++++++------------- .../codehaus/groovy/ast/NodeMetaDataHandler.java | 24 +++-- .../java/org/codehaus/groovy/util/ListHashMap.java | 27 +++--- 3 files changed, 71 insertions(+), 80 deletions(-) diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java index d1e71e9805..62c08cd53c 100644 --- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java +++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java @@ -502,7 +502,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { throw createParsingFailedException("Unsupported for control: " + ctx.getText(), ctx); } - @Override @SuppressWarnings("unchecked") + @Override public Expression visitForInit(final ForInitContext ctx) { if (!asBoolean(ctx)) { return EmptyExpression.INSTANCE; @@ -548,9 +548,9 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { @Override public Tuple2<Parameter, Expression> visitEnhancedForControl(final EnhancedForControlContext ctx) { Parameter parameter = new Parameter(this.visitType(ctx.type()), this.visitVariableDeclaratorId(ctx.variableDeclaratorId()).getName()); - configureAST(parameter, ctx.variableDeclaratorId()); ModifierManager modifierManager = new ModifierManager(this, this.visitVariableModifiersOpt(ctx.variableModifiersOpt())); modifierManager.processParameter(parameter); + configureAST(parameter, ctx.variableDeclaratorId()); return tuple(parameter, (Expression) this.visit(ctx.expression())); } @@ -693,16 +693,9 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { */ @Override public List<CatchStatement> visitCatchClause(final CatchClauseContext ctx) { - // FIXME Groovy will ignore variableModifier of parameter in the catch clause - // In order to make the new parser behave same with the old one, we do not process variableModifier* - return this.visitCatchType(ctx.catchType()).stream() .map(e -> configureAST( new CatchStatement( - // FIXME The old parser does not set location info for the parameter of the catch clause. - // we could make it better - //this.configureAST(new Parameter(e, this.visitIdentifier(ctx.identifier())), ctx.Identifier()), - new Parameter(e, this.visitIdentifier(ctx.identifier())), this.visitBlock(ctx.block())), ctx)) @@ -777,7 +770,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { } } - @Override @SuppressWarnings("unchecked") + @Override public List<Statement> visitSwitchBlockStatementGroup(final SwitchBlockStatementGroupContext ctx) { int labelCount = ctx.switchLabel().size(); List<Token> firstLabelHolder = new ArrayList<>(1); @@ -800,7 +793,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { ); statementList.add(configureAST(statement, firstLabelHolder.get(0))); break; - case DEFAULT: statement = this.visitBlockStatements(ctx.blockStatements()); statement.putNodeMetaData(IS_SWITCH_DEFAULT, Boolean.TRUE); @@ -1005,7 +997,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { } private int switchExpressionVariableSeq; - @Override @SuppressWarnings("unchecked") + @Override public Tuple3<List<Statement>, Boolean, Boolean> visitSwitchBlockStatementExpressionGroup(SwitchBlockStatementExpressionGroupContext ctx) { int labelCnt = ctx.switchExpressionLabel().size(); List<Token> firstLabelHolder = new ArrayList<>(1); @@ -1098,14 +1090,12 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { } switch (tuple.getV1().getType()) { - case CASE: { + case CASE: if (!asBoolean(statementList)) { firstLabelHolder.add(tuple.getV1()); } - - for (int i = 0, n = tuple.getV2().size(); i < n; i++) { + for (int i = 0, n = tuple.getV2().size(); i < n; i += 1) { Expression expr = tuple.getV2().get(i); - statementList.add( configureAST( new CaseStatement( @@ -1117,19 +1107,11 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { ), firstLabelHolder.get(0))); } - break; - } - case DEFAULT: { - codeBlock.putNodeMetaData(IS_SWITCH_DEFAULT, true); - - statementList.add( - // this.configureAST(codeBlock, tuple.getKey()) - codeBlock - ); - + case DEFAULT: + codeBlock.putNodeMetaData(IS_SWITCH_DEFAULT, Boolean.TRUE); + statementList.add(codeBlock); break; - } } return statementList; @@ -1325,7 +1307,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { .collect(Collectors.toList())); sealedAnnotationNode.setMember("permittedSubclasses", permittedSubclassesListExpression); configureAST(sealedAnnotationNode, ctx.PERMITS()); - sealedAnnotationNode.setNodeMetaData("permits", true); + sealedAnnotationNode.setNodeMetaData("permits", Boolean.TRUE); } classNode.addAnnotation(sealedAnnotationNode); } else if (isNonSealed) { @@ -1423,7 +1405,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { } } - @SuppressWarnings("unchecked") private boolean containsDefaultMethods(final ClassDeclarationContext ctx) { List<MethodDeclarationContext> methodDeclarationContextList = (List<MethodDeclarationContext>) ctx.classBody().classBodyDeclaration().stream() @@ -2480,13 +2461,13 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { GenericsType[] genericsTypes = this.visitNonWildcardTypeArguments(ctx.nonWildcardTypeArguments()); if (asBoolean(ctx.DOT())) { - boolean isSafeChain = this.isTrue(baseExpr, PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN); + boolean isSafeChain = isTrue(baseExpr, PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN); return this.createDotExpression(ctx, baseExpr, namePartExpr, genericsTypes, isSafeChain); } else if (asBoolean(ctx.SAFE_DOT())) { return this.createDotExpression(ctx, baseExpr, namePartExpr, genericsTypes, true); } else if (asBoolean(ctx.SAFE_CHAIN_DOT())) { // e.g. obj??.a OR obj??.@a Expression expression = createDotExpression(ctx, baseExpr, namePartExpr, genericsTypes, true); - expression.putNodeMetaData(PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN, true); + expression.putNodeMetaData(PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN, Boolean.TRUE); return expression; } else if (asBoolean(ctx.METHOD_POINTER())) { // e.g. obj.&m return configureAST(new MethodPointerExpression(baseExpr, namePartExpr), ctx); @@ -2510,7 +2491,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { return configureAST(this.visitCreator(creatorContext), ctx); } else if (asBoolean(ctx.indexPropertyArgs())) { // e.g. list[1, 3, 5] Tuple2<Token, Expression> tuple = this.visitIndexPropertyArgs(ctx.indexPropertyArgs()); - boolean isSafeChain = this.isTrue(baseExpr, PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN); + boolean isSafeChain = isTrue(baseExpr, PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN); return configureAST( new BinaryExpression(baseExpr, createGroovyToken(tuple.getV1()), tuple.getV2(), isSafeChain || asBoolean(ctx.indexPropertyArgs().SAFE_INDEX())), ctx); @@ -2582,7 +2563,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { if (baseExpr instanceof VariableExpression // e.g. m() || baseExpr instanceof GStringExpression // e.g. "$m"() - || (baseExpr instanceof ConstantExpression && this.isTrue(baseExpr, IS_STRING))) { // e.g. "m"() + || (baseExpr instanceof ConstantExpression && isTrue(baseExpr, IS_STRING))) { // e.g. "m"() String baseExprText = baseExpr.getText(); if (THIS_STR.equals(baseExprText) || SUPER_STR.equals(baseExprText)) { // e.g. this(...), super(...) // class declaration is not allowed in the closure, @@ -2675,7 +2656,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { if (baseExpr instanceof VariableExpression // e.g. m { } || baseExpr instanceof GStringExpression // e.g. "$m" { } - || (baseExpr instanceof ConstantExpression && this.isTrue(baseExpr, IS_STRING))) { // e.g. "m" { } + || (baseExpr instanceof ConstantExpression && isTrue(baseExpr, IS_STRING))) { // e.g. "m" { } MethodCallExpression methodCallExpression = this.createMethodCallExpression( baseExpr, @@ -3158,7 +3139,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { @Override public Expression visitConditionalExprAlt(final ConditionalExprAltContext ctx) { - ctx.fb.putNodeMetaData(IS_INSIDE_CONDITIONAL_EXPRESSION, true); + ctx.fb.putNodeMetaData(IS_INSIDE_CONDITIONAL_EXPRESSION, Boolean.TRUE); if (asBoolean(ctx.ELVIS())) { // e.g. a == 6 ?: 0 return configureAST( @@ -3166,7 +3147,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { ctx); } - ctx.tb.putNodeMetaData(IS_INSIDE_CONDITIONAL_EXPRESSION, true); + ctx.tb.putNodeMetaData(IS_INSIDE_CONDITIONAL_EXPRESSION, Boolean.TRUE); return configureAST( new TernaryExpression( @@ -3603,15 +3584,13 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { } private void validateExpressionListElement(final ExpressionListElementContext ctx, final Expression expression) { - if (!(expression instanceof MethodCallExpression && isTrue(expression, IS_COMMAND_EXPRESSION))) { - return; - } - - // statements like `foo(String a)` is invalid - MethodCallExpression methodCallExpression = (MethodCallExpression) expression; - String methodName = methodCallExpression.getMethodAsString(); - if (methodCallExpression.isImplicitThis() && Character.isUpperCase(methodName.codePointAt(0)) || isPrimitiveType(methodName)) { - throw createParsingFailedException("Invalid method declaration", ctx); + if (expression instanceof MethodCallExpression && isTrue(expression, IS_COMMAND_EXPRESSION)) { + // statements like `foo(String a)` is invalid + MethodCallExpression methodCallExpression = (MethodCallExpression) expression; + String methodName = methodCallExpression.getMethodAsString(); + if (methodCallExpression.isImplicitThis() && Character.isUpperCase(methodName.codePointAt(0)) || isPrimitiveType(methodName)) { + throw createParsingFailedException("Invalid method declaration", ctx); + } } } @@ -3905,16 +3884,14 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { private void validateParameterList(final List<Parameter> parameterList) { for (int n = parameterList.size(), i = n - 1; i >= 0; i -= 1) { Parameter parameter = parameterList.get(i); - String name = parameter.getName(); - if (name.equals("_")) { + if ("_".equals(name)) { continue; // check this later } for (Parameter otherParameter : parameterList) { if (otherParameter == parameter) { continue; } - if (otherParameter.getName().equals(name)) { throw createParsingFailedException("Duplicated parameter '" + name + "' found.", parameter); } @@ -4051,7 +4028,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { ClassNode classNode = null; if (asBoolean(ctx.classOrInterfaceType())) { - ctx.classOrInterfaceType().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, ctx.getNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR)); + if (isTrue(ctx, IS_INSIDE_INSTANCEOF_EXPR)) + ctx.classOrInterfaceType().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, Boolean.TRUE); classNode = this.visitClassOrInterfaceType(ctx.classOrInterfaceType()); } else if (asBoolean(ctx.primitiveType())) { classNode = this.visitPrimitiveType(ctx.primitiveType()); @@ -4078,10 +4056,12 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { public ClassNode visitClassOrInterfaceType(final ClassOrInterfaceTypeContext ctx) { ClassNode classNode; if (asBoolean(ctx.qualifiedClassName())) { - ctx.qualifiedClassName().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, ctx.getNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR)); + if (isTrue(ctx, IS_INSIDE_INSTANCEOF_EXPR)) + ctx.qualifiedClassName().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, Boolean.TRUE); classNode = this.visitQualifiedClassName(ctx.qualifiedClassName()); } else { - ctx.qualifiedStandardClassName().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, ctx.getNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR)); + if (isTrue(ctx, IS_INSIDE_INSTANCEOF_EXPR)) + ctx.qualifiedStandardClassName().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, Boolean.TRUE); classNode = this.visitQualifiedStandardClassName(ctx.qualifiedStandardClassName()); } @@ -4379,11 +4359,11 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { private ClassNode createClassNode(final GroovyParserRuleContext ctx) { ClassNode result = makeClassNode(ctx.getText()); - - if (!isTrue(ctx, IS_INSIDE_INSTANCEOF_EXPR)) { // type in the "instanceof" expression should not have proxy to redirect to it + if (isTrue(ctx, IS_INSIDE_INSTANCEOF_EXPR)) { + // type in the "instanceof" expression shouldn't have redirect + } else { result = this.proxyClassNode(result); } - return configureAST(result, ctx); } @@ -4394,7 +4374,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { ClassNode cn = ClassHelper.makeWithoutCaching(classNode.getName()); cn.setRedirect(classNode); - return cn; } @@ -4499,12 +4478,9 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { PathElementContext pathElementContext = (PathElementContext) e; pathElementContext.putNodeMetaData(PATH_EXPRESSION_BASE_EXPR, r); Expression expression = this.visitPathElement(pathElementContext); - - boolean isSafeChain = isTrue((Expression) r, PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN); - if (isSafeChain) { - expression.putNodeMetaData(PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN, true); + if (isTrue((Expression) r, PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN)) { + expression.putNodeMetaData(PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN, Boolean.TRUE); } - return expression; } ); @@ -4691,8 +4667,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> { return lexer.getInputStream().getText(Interval.of(context.getStart().getStartIndex(), context.getStop().getStopIndex())); } - private boolean isTrue(final NodeMetaDataHandler nodeMetaDataHandler, final String key) { - return Boolean.TRUE.equals(nodeMetaDataHandler.getNodeMetaData(key)); + private static boolean isTrue(final NodeMetaDataHandler obj, final String key) { + return Boolean.TRUE.equals(obj.getNodeMetaData(key)); } private CompilationFailedException createParsingFailedException(final String msg, final GroovyParserRuleContext ctx) { diff --git a/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java b/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java index 95aa7a3a44..ddb485d4f1 100644 --- a/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java +++ b/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java @@ -27,9 +27,12 @@ import java.util.function.Function; /** * An interface to mark a node being able to handle metadata. + * + * @since 3.0.0 */ @SuppressWarnings({"unchecked", "rawtypes"}) public interface NodeMetaDataHandler { + /** * Gets the node metadata. * @@ -56,7 +59,7 @@ public interface NodeMetaDataHandler { Map metaDataMap = this.getMetaDataMap(); if (metaDataMap == null) { - metaDataMap = new ListHashMap(); + metaDataMap = this.newMetaDataMap(); this.setMetaDataMap(metaDataMap); } return (T) metaDataMap.computeIfAbsent(key, valFn); @@ -74,7 +77,7 @@ public interface NodeMetaDataHandler { } Map metaDataMap = this.getMetaDataMap(); if (metaDataMap == null) { - metaDataMap = new ListHashMap(); + metaDataMap = this.newMetaDataMap(); this.setMetaDataMap(metaDataMap); } @@ -86,8 +89,7 @@ public interface NodeMetaDataHandler { * * @param key the metadata key * @param value the metadata value - * @throws GroovyBugError if key is null or there is already meta - * data under that key + * @throws GroovyBugError if key is null or there is already metadata for key */ default void setNodeMetaData(Object key, Object value) { Object old = putNodeMetaData(key, value); @@ -107,8 +109,11 @@ public interface NodeMetaDataHandler { Map metaDataMap = this.getMetaDataMap(); if (metaDataMap == null) { - metaDataMap = new ListHashMap(); + if (value == null) return null; + metaDataMap = newMetaDataMap(); this.setMetaDataMap(metaDataMap); + } else if (value == null) { + return metaDataMap.remove(key); } return metaDataMap.put(key, value); } @@ -142,7 +147,16 @@ public interface NodeMetaDataHandler { return Collections.unmodifiableMap(metaDataMap); } + //-------------------------------------------------------------------------- + Map<?, ?> getMetaDataMap(); + /** + * @since 5.0.0 + */ + default Map<?, ?> newMetaDataMap() { + return new ListHashMap(); + } + void setMetaDataMap(Map<?, ?> metaDataMap); } diff --git a/src/main/java/org/codehaus/groovy/util/ListHashMap.java b/src/main/java/org/codehaus/groovy/util/ListHashMap.java index 8fe48a18d8..d40bf1df5e 100644 --- a/src/main/java/org/codehaus/groovy/util/ListHashMap.java +++ b/src/main/java/org/codehaus/groovy/util/ListHashMap.java @@ -127,7 +127,7 @@ public class ListHashMap<K,V> implements Map<K,V> { } if (innerMap != null) { V old = innerMap.put(key, value); - size = innerMap.size(); + if (old == null) size += 1; return old; } for (int i = 0; i < size; i += 1) { @@ -138,15 +138,16 @@ public class ListHashMap<K,V> implements Map<K,V> { } } if (size < keys.length) { - values[size] = value; - keys[size] = key; + int i = (size ++); + values[i] = value; + keys[i] = key; } else { // evolve Map<K,V> map = toMap(); map.put(key, value); innerMap = map; clearArrays(); + size += 1; } - size += 1; } return null; } @@ -168,9 +169,9 @@ public class ListHashMap<K,V> implements Map<K,V> { if (size <= keys.length) { // devolve size = 0; Set<Entry<K,V>> entries = innerMap.entrySet(); innerMap = null; for (Entry<? extends K, ? extends V> entry : entries) { - values[size] = entry.getValue(); - keys[size] = entry.getKey(); - size += 1; + int i = size++; // not atomic + values[i] = entry.getValue(); + keys[i] = entry.getKey(); } } } @@ -179,14 +180,14 @@ public class ListHashMap<K,V> implements Map<K,V> { for (int i = 0; i < size; i += 1) { if (key.equals(keys[i])) { V value = values[i]; - size -= 1; + int j = (size -= 1); // if last element is not being removed, shift the last element into this slot - if (i < size) { - values[i] = values[size]; - keys[i] = keys[size]; + if (i < j) { + values[i] = values[j]; + keys[i] = keys[j]; } - values[size] = null; - keys[size] = null; + values[j] = null; + keys[j] = null; return value; } }