You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2017/12/14 21:57:03 UTC
[38/57] [abbrv] [partial] groovy git commit: Move Java source set
into `src/main/java`
http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java b/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
new file mode 100644
index 0000000..c493299
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Represents an annotation which can be attached to interfaces, classes, methods and fields.
+ */
+public class AnnotationNode extends ASTNode {
+ public static final int CONSTRUCTOR_TARGET = 1 << 1;
+ public static final int METHOD_TARGET = 1 << 2;
+ public static final int FIELD_TARGET = 1 << 3;
+ public static final int PARAMETER_TARGET = 1 << 4;
+ public static final int LOCAL_VARIABLE_TARGET = 1 << 5;
+ public static final int ANNOTATION_TARGET = 1 << 6;
+ public static final int PACKAGE_TARGET = 1 << 7;
+ public static final int TYPE_PARAMETER_TARGET = 1 << 8;
+ public static final int TYPE_USE_TARGET = 1 << 9;
+ public static final int TYPE_TARGET = 1 + ANNOTATION_TARGET; //GROOVY-7151
+ private static final int ALL_TARGETS = TYPE_TARGET | CONSTRUCTOR_TARGET | METHOD_TARGET
+ | FIELD_TARGET | PARAMETER_TARGET | LOCAL_VARIABLE_TARGET | ANNOTATION_TARGET
+ | PACKAGE_TARGET | TYPE_PARAMETER_TARGET | TYPE_USE_TARGET;
+
+ private final ClassNode classNode;
+ private Map<String, Expression> members;
+ private boolean runtimeRetention= false, sourceRetention= false, classRetention = false;
+ private int allowedTargets = ALL_TARGETS;
+
+ public AnnotationNode(ClassNode classNode) {
+ this.classNode = classNode;
+ }
+
+ public ClassNode getClassNode() {
+ return classNode;
+ }
+
+ public Map<String, Expression> getMembers() {
+ if (members == null) {
+ return Collections.emptyMap();
+ }
+ return members;
+ }
+
+ public Expression getMember(String name) {
+ if (members == null) {
+ return null;
+ }
+ return members.get(name);
+ }
+
+ private void assertMembers() {
+ if (members == null) {
+ members = new LinkedHashMap<String, Expression>();
+ }
+ }
+
+ public void addMember(String name, Expression value) {
+ assertMembers();
+ Expression oldValue = members.get(name);
+ if (oldValue == null) {
+ members.put(name, value);
+ }
+ else {
+ throw new GroovyBugError(String.format("Annotation member %s has already been added", name));
+ }
+ }
+
+ public void setMember(String name, Expression value) {
+ assertMembers();
+ members.put(name, value);
+ }
+
+ public boolean isBuiltIn(){
+ return false;
+ }
+
+ /**
+ * Flag corresponding to <code>RetentionPolicy</code>.
+ * @return <tt>true</tt> if the annotation should be visible at runtime,
+ * <tt>false</tt> otherwise
+ */
+ public boolean hasRuntimeRetention() {
+ return this.runtimeRetention;
+ }
+
+ /**
+ * Sets the internal flag of this annotation runtime retention policy.
+ * If the current annotation has
+ * <code>RetentionPolicy.RUNTIME</code> or if <tt>false</tt>
+ * if the <code>RetentionPolicy.CLASS</code>.
+ * @param flag if <tt>true</tt> then current annotation is marked as having
+ * <code>RetentionPolicy.RUNTIME</code>. If <tt>false</tt> then
+ * the annotation has <code>RetentionPolicy.CLASS</code>.
+ */
+ public void setRuntimeRetention(boolean flag) {
+ this.runtimeRetention = flag;
+ }
+
+ /**
+ * Flag corresponding to <code>RetentionPolicy.SOURCE</code>.
+ * @return <tt>true</tt> if the annotation is only allowed in sources
+ * <tt>false</tt> otherwise
+ */
+ public boolean hasSourceRetention() {
+ if (!runtimeRetention && !classRetention) return true;
+ return this.sourceRetention;
+ }
+
+ /** Sets the internal flag if the current annotation has
+ * <code>RetentionPolicy.SOURCE</code>.
+ */
+ public void setSourceRetention(boolean flag) {
+ this.sourceRetention = flag;
+ }
+
+ /**
+ * Flag corresponding to <code>RetentionPolicy.CLASS</code>.
+ * @return <tt>true</tt> if the annotation is recorded by the compiler,
+ * but not visible at runtime *
+ * <tt>false</tt> otherwise
+ */
+ public boolean hasClassRetention() {
+ return this.classRetention;
+ }
+
+ /** Sets the internal flag if the current annotation has
+ * <code>RetentionPolicy.CLASS</code>.
+ */
+ public void setClassRetention(boolean flag) {
+ this.classRetention = flag;
+ }
+
+ public void setAllowedTargets(int bitmap) {
+ this.allowedTargets = bitmap;
+ }
+
+ public boolean isTargetAllowed(int target) {
+ return (this.allowedTargets & target) == target;
+ }
+
+ public static String targetToName(int target) {
+ switch(target) {
+ case TYPE_TARGET:
+ return "TYPE";
+ case CONSTRUCTOR_TARGET:
+ return "CONSTRUCTOR";
+ case METHOD_TARGET:
+ return "METHOD";
+ case FIELD_TARGET:
+ return "FIELD";
+ case PARAMETER_TARGET:
+ return "PARAMETER";
+ case LOCAL_VARIABLE_TARGET:
+ return "LOCAL_VARIABLE";
+ case ANNOTATION_TARGET:
+ return "ANNOTATION";
+ case PACKAGE_TARGET:
+ return "PACKAGE";
+ case TYPE_PARAMETER_TARGET:
+ return "TYPE_PARAMETER";
+ case TYPE_USE_TARGET:
+ return "TYPE_USE";
+ default:
+ return "unknown target";
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java b/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
new file mode 100644
index 0000000..3599fbf
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.ast;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Helper class for converting AST into text.
+ * @author Hamlet D'Arcy
+ */
+public class AstToTextHelper {
+
+ public static String getClassText(ClassNode node) {
+ if (node == null) return "<unknown>";
+ if (node.getName() == null) return "<unknown>";
+ return node.getName();
+ }
+
+ public static String getParameterText(Parameter node) {
+ if (node == null) return "<unknown>";
+
+ String name = node.getName() == null ? "<unknown>" : node.getName();
+ String type = getClassText(node.getType());
+ if (node.getInitialExpression() != null) {
+ return type + " " + name + " = " + node.getInitialExpression().getText();
+ }
+ return type + " " + name;
+ }
+
+ public static String getParametersText(Parameter[] parameters) {
+ if (parameters == null) return "";
+ if (parameters.length == 0) return "";
+ StringBuilder result = new StringBuilder();
+ int max = parameters.length;
+ for (int x = 0; x < max; x++) {
+ result.append(getParameterText(parameters[x]));
+ if (x < (max - 1)) {
+ result.append(", ");
+ }
+ }
+ return result.toString();
+ }
+
+ public static String getThrowsClauseText(ClassNode[] exceptions) {
+ if (exceptions == null) return "";
+ if (exceptions.length == 0) return "";
+ StringBuilder result = new StringBuilder("throws ");
+ int max = exceptions.length;
+ for (int x = 0; x < max; x++) {
+ result.append(getClassText(exceptions[x]));
+ if (x < (max - 1)) {
+ result.append(", ");
+ }
+ }
+ return result.toString();
+ }
+
+ public static String getModifiersText(int modifiers) {
+ StringBuilder result = new StringBuilder();
+ if (Modifier.isPrivate(modifiers)) {
+ result.append("private ");
+ }
+ if (Modifier.isProtected(modifiers)) {
+ result.append("protected ");
+ }
+ if (Modifier.isPublic(modifiers)) {
+ result.append("public ");
+ }
+ if (Modifier.isStatic(modifiers)) {
+ result.append("static ");
+ }
+ if (Modifier.isAbstract(modifiers)) {
+ result.append("abstract ");
+ }
+ if (Modifier.isFinal(modifiers)) {
+ result.append("final ");
+ }
+ if (Modifier.isInterface(modifiers)) {
+ result.append("interface ");
+ }
+ if (Modifier.isNative(modifiers)) {
+ result.append("native ");
+ }
+ if (Modifier.isSynchronized(modifiers)) {
+ result.append("synchronized ");
+ }
+ if (Modifier.isTransient(modifiers)) {
+ result.append("transient ");
+ }
+ if (Modifier.isVolatile(modifiers)) {
+ result.append("volatile ");
+ }
+ return result.toString().trim();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java b/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java
new file mode 100644
index 0000000..06ef44d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Visitor to transform expressions in a whole class.
+ * Transformed Expressions are usually not visited.
+ *
+ * @author Jochen Theodorou
+ */
+public abstract class ClassCodeExpressionTransformer extends ClassCodeVisitorSupport implements ExpressionTransformer {
+
+ protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+ for (Parameter p : node.getParameters()) {
+ if (p.hasInitialExpression()) {
+ Expression init = p.getInitialExpression();
+ p.setInitialExpression(transform(init));
+ }
+ }
+ super.visitConstructorOrMethod(node, isConstructor);
+ }
+
+ public void visitSwitch(SwitchStatement statement) {
+ Expression exp = statement.getExpression();
+ statement.setExpression(transform(exp));
+ for (CaseStatement caseStatement : statement.getCaseStatements()) {
+ caseStatement.visit(this);
+ }
+ statement.getDefaultStatement().visit(this);
+ }
+
+ public void visitField(FieldNode node) {
+ visitAnnotations(node);
+ Expression init = node.getInitialExpression();
+ node.setInitialValueExpression(transform(init));
+ }
+
+ public void visitProperty(PropertyNode node) {
+ visitAnnotations(node);
+ Statement statement = node.getGetterBlock();
+ visitClassCodeContainer(statement);
+
+ statement = node.getSetterBlock();
+ visitClassCodeContainer(statement);
+ }
+
+ public void visitIfElse(IfStatement ifElse) {
+ ifElse.setBooleanExpression((BooleanExpression) (transform(ifElse.getBooleanExpression())));
+ ifElse.getIfBlock().visit(this);
+ ifElse.getElseBlock().visit(this);
+ }
+
+ public Expression transform(Expression exp) {
+ if (exp == null) return null;
+ return exp.transformExpression(this);
+ }
+
+ public void visitAnnotations(AnnotatedNode node) {
+ List<AnnotationNode> annotations = node.getAnnotations();
+ if (annotations.isEmpty()) return;
+ for (AnnotationNode an : annotations) {
+ // skip built-in properties
+ if (an.isBuiltIn()) continue;
+ for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+ member.setValue(transform(member.getValue()));
+ }
+ }
+ }
+
+ public void visitReturnStatement(ReturnStatement statement) {
+ statement.setExpression(transform(statement.getExpression()));
+ }
+
+ public void visitAssertStatement(AssertStatement as) {
+ as.setBooleanExpression((BooleanExpression) (transform(as.getBooleanExpression())));
+ as.setMessageExpression(transform(as.getMessageExpression()));
+ }
+
+ public void visitCaseStatement(CaseStatement statement) {
+ statement.setExpression(transform(statement.getExpression()));
+ statement.getCode().visit(this);
+ }
+
+ public void visitDoWhileLoop(DoWhileStatement loop) {
+ loop.setBooleanExpression((BooleanExpression) (transform(loop.getBooleanExpression())));
+ super.visitDoWhileLoop(loop);
+ }
+
+ public void visitForLoop(ForStatement forLoop) {
+ forLoop.setCollectionExpression(transform(forLoop.getCollectionExpression()));
+ super.visitForLoop(forLoop);
+ }
+
+ public void visitSynchronizedStatement(SynchronizedStatement sync) {
+ sync.setExpression(transform(sync.getExpression()));
+ super.visitSynchronizedStatement(sync);
+ }
+
+ public void visitThrowStatement(ThrowStatement ts) {
+ ts.setExpression(transform(ts.getExpression()));
+ }
+
+ public void visitWhileLoop(WhileStatement loop) {
+ loop.setBooleanExpression((BooleanExpression) transform(loop.getBooleanExpression()));
+ super.visitWhileLoop(loop);
+ }
+
+ public void visitExpressionStatement(ExpressionStatement es) {
+ es.setExpression(transform(es.getExpression()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java b/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
new file mode 100644
index 0000000..378d2be
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.transform.ErrorCollecting;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class ClassCodeVisitorSupport extends CodeVisitorSupport implements ErrorCollecting, GroovyClassVisitor {
+
+ public void visitClass(ClassNode node) {
+ visitAnnotations(node);
+ visitPackage(node.getPackage());
+ visitImports(node.getModule());
+ node.visitContents(this);
+ visitObjectInitializerStatements(node);
+ }
+
+ protected void visitObjectInitializerStatements(ClassNode node) {
+ for (Statement element : node.getObjectInitializerStatements()) {
+ element.visit(this);
+ }
+ }
+
+ public void visitPackage(PackageNode node) {
+ if (node != null) {
+ visitAnnotations(node);
+ node.visit(this);
+ }
+ }
+
+ public void visitImports(ModuleNode node) {
+ if (node != null) {
+ for (ImportNode importNode : node.getImports()) {
+ visitAnnotations(importNode);
+ importNode.visit(this);
+ }
+ for (ImportNode importStarNode : node.getStarImports()) {
+ visitAnnotations(importStarNode);
+ importStarNode.visit(this);
+ }
+ for (ImportNode importStaticNode : node.getStaticImports().values()) {
+ visitAnnotations(importStaticNode);
+ importStaticNode.visit(this);
+ }
+ for (ImportNode importStaticStarNode : node.getStaticStarImports().values()) {
+ visitAnnotations(importStaticStarNode);
+ importStaticStarNode.visit(this);
+ }
+ }
+ }
+
+ public void visitAnnotations(AnnotatedNode node) {
+ List<AnnotationNode> annotations = node.getAnnotations();
+ if (annotations.isEmpty()) return;
+ for (AnnotationNode an : annotations) {
+ // skip built-in properties
+ if (an.isBuiltIn()) continue;
+ for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+ member.getValue().visit(this);
+ }
+ }
+ }
+
+ public void visitBlockStatement(BlockStatement block) {
+ visitStatement(block);
+ super.visitBlockStatement(block);
+ }
+
+ protected void visitClassCodeContainer(Statement code) {
+ if (code != null) code.visit(this);
+ }
+
+ @Override
+ public void visitDeclarationExpression(DeclarationExpression expression) {
+ visitAnnotations(expression);
+ super.visitDeclarationExpression(expression);
+ }
+
+ protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+ visitAnnotations(node);
+ visitClassCodeContainer(node.getCode());
+ for (Parameter param : node.getParameters()) {
+ visitAnnotations(param);
+ }
+ }
+
+ public void visitConstructor(ConstructorNode node) {
+ visitConstructorOrMethod(node, true);
+ }
+
+ public void visitMethod(MethodNode node) {
+ visitConstructorOrMethod(node, false);
+ }
+
+ public void visitField(FieldNode node) {
+ visitAnnotations(node);
+ Expression init = node.getInitialExpression();
+ if (init != null) init.visit(this);
+ }
+
+ public void visitProperty(PropertyNode node) {
+ visitAnnotations(node);
+ Statement statement = node.getGetterBlock();
+ visitClassCodeContainer(statement);
+
+ statement = node.getSetterBlock();
+ visitClassCodeContainer(statement);
+
+ Expression init = node.getInitialExpression();
+ if (init != null) init.visit(this);
+ }
+
+ public void addError(String msg, ASTNode expr) {
+ SourceUnit source = getSourceUnit();
+ source.getErrorCollector().addErrorAndContinue(
+ new SyntaxErrorMessage(new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), source)
+ );
+ }
+
+ protected abstract SourceUnit getSourceUnit();
+
+ protected void visitStatement(Statement statement) {
+ }
+
+ public void visitAssertStatement(AssertStatement statement) {
+ visitStatement(statement);
+ super.visitAssertStatement(statement);
+ }
+
+ public void visitBreakStatement(BreakStatement statement) {
+ visitStatement(statement);
+ super.visitBreakStatement(statement);
+ }
+
+ public void visitCaseStatement(CaseStatement statement) {
+ visitStatement(statement);
+ super.visitCaseStatement(statement);
+ }
+
+ public void visitCatchStatement(CatchStatement statement) {
+ visitStatement(statement);
+ super.visitCatchStatement(statement);
+ }
+
+ public void visitContinueStatement(ContinueStatement statement) {
+ visitStatement(statement);
+ super.visitContinueStatement(statement);
+ }
+
+ public void visitDoWhileLoop(DoWhileStatement loop) {
+ visitStatement(loop);
+ super.visitDoWhileLoop(loop);
+ }
+
+ public void visitExpressionStatement(ExpressionStatement statement) {
+ visitStatement(statement);
+ super.visitExpressionStatement(statement);
+ }
+
+ public void visitForLoop(ForStatement forLoop) {
+ visitStatement(forLoop);
+ super.visitForLoop(forLoop);
+ }
+
+ public void visitIfElse(IfStatement ifElse) {
+ visitStatement(ifElse);
+ super.visitIfElse(ifElse);
+ }
+
+ public void visitReturnStatement(ReturnStatement statement) {
+ visitStatement(statement);
+ super.visitReturnStatement(statement);
+ }
+
+ public void visitSwitch(SwitchStatement statement) {
+ visitStatement(statement);
+ super.visitSwitch(statement);
+ }
+
+ public void visitSynchronizedStatement(SynchronizedStatement statement) {
+ visitStatement(statement);
+ super.visitSynchronizedStatement(statement);
+ }
+
+ public void visitThrowStatement(ThrowStatement statement) {
+ visitStatement(statement);
+ super.visitThrowStatement(statement);
+ }
+
+ public void visitTryCatchFinally(TryCatchStatement statement) {
+ visitStatement(statement);
+ super.visitTryCatchFinally(statement);
+ }
+
+ public void visitWhileLoop(WhileStatement loop) {
+ visitStatement(loop);
+ super.visitWhileLoop(loop);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b25d0e55/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
new file mode 100644
index 0000000..60eaa47
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -0,0 +1,481 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.ast;
+
+import groovy.lang.Binding;
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.GroovyInterceptable;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.MetaClass;
+import groovy.lang.Range;
+import groovy.lang.Reference;
+import groovy.lang.Script;
+import org.codehaus.groovy.runtime.GeneratedClosure;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+import org.codehaus.groovy.transform.trait.Traits;
+import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ReferenceBundle;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * This class is a Helper for ClassNode and classes handling ClassNodes.
+ * It does contain a set of predefined ClassNodes for the most used
+ * types and some code for cached ClassNode creation and basic
+ * ClassNode handling
+ */
+public class ClassHelper {
+
+ private static final Class[] classes = new Class[]{
+ Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
+ Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
+ Closure.class, GString.class, List.class, Map.class, Range.class,
+ Pattern.class, Script.class, String.class, Boolean.class,
+ Character.class, Byte.class, Short.class, Integer.class, Long.class,
+ Double.class, Float.class, BigDecimal.class, BigInteger.class,
+ Number.class, Void.class, Reference.class, Class.class, MetaClass.class,
+ Iterator.class, GeneratedClosure.class, GroovyObjectSupport.class
+ };
+
+ private static final String[] primitiveClassNames = new String[]{
+ "", "boolean", "char", "byte", "short",
+ "int", "long", "double", "float", "void"
+ };
+
+ public static final ClassNode
+ DYNAMIC_TYPE = makeCached(Object.class), OBJECT_TYPE = DYNAMIC_TYPE,
+ VOID_TYPE = makeCached(Void.TYPE), CLOSURE_TYPE = makeCached(Closure.class),
+ GSTRING_TYPE = makeCached(GString.class), LIST_TYPE = makeWithoutCaching(List.class),
+ MAP_TYPE = makeWithoutCaching(Map.class), RANGE_TYPE = makeCached(Range.class),
+ PATTERN_TYPE = makeCached(Pattern.class), STRING_TYPE = makeCached(String.class),
+ SCRIPT_TYPE = makeCached(Script.class), REFERENCE_TYPE = makeWithoutCaching(Reference.class),
+ BINDING_TYPE = makeCached(Binding.class),
+
+ boolean_TYPE = makeCached(boolean.class), char_TYPE = makeCached(char.class),
+ byte_TYPE = makeCached(byte.class), int_TYPE = makeCached(int.class),
+ long_TYPE = makeCached(long.class), short_TYPE = makeCached(short.class),
+ double_TYPE = makeCached(double.class), float_TYPE = makeCached(float.class),
+ Byte_TYPE = makeCached(Byte.class), Short_TYPE = makeCached(Short.class),
+ Integer_TYPE = makeCached(Integer.class), Long_TYPE = makeCached(Long.class),
+ Character_TYPE = makeCached(Character.class), Float_TYPE = makeCached(Float.class),
+ Double_TYPE = makeCached(Double.class), Boolean_TYPE = makeCached(Boolean.class),
+ BigInteger_TYPE = makeCached(java.math.BigInteger.class),
+ BigDecimal_TYPE = makeCached(java.math.BigDecimal.class),
+ Number_TYPE = makeCached(Number.class),
+
+ void_WRAPPER_TYPE = makeCached(Void.class), METACLASS_TYPE = makeCached(MetaClass.class),
+ Iterator_TYPE = makeCached(Iterator.class),
+
+ Enum_Type = makeWithoutCaching(Enum.class),
+ Annotation_TYPE = makeCached(Annotation.class),
+ ELEMENT_TYPE_TYPE = makeCached(ElementType.class),
+
+ // uncached constants.
+ CLASS_Type = makeWithoutCaching(Class.class), COMPARABLE_TYPE = makeWithoutCaching(Comparable.class),
+ GENERATED_CLOSURE_Type = makeWithoutCaching(GeneratedClosure.class),
+ GROOVY_OBJECT_SUPPORT_TYPE = makeWithoutCaching(GroovyObjectSupport.class),
+ GROOVY_OBJECT_TYPE = makeWithoutCaching(GroovyObject.class),
+ GROOVY_INTERCEPTABLE_TYPE = makeWithoutCaching(GroovyInterceptable.class);
+
+ private static final ClassNode[] types = new ClassNode[]{
+ OBJECT_TYPE,
+ boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
+ int_TYPE, long_TYPE, double_TYPE, float_TYPE,
+ VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
+ LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
+ SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
+ Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
+ Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE,
+ Number_TYPE,
+ void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE,
+ Iterator_TYPE, GENERATED_CLOSURE_Type, GROOVY_OBJECT_SUPPORT_TYPE,
+ GROOVY_OBJECT_TYPE, GROOVY_INTERCEPTABLE_TYPE, Enum_Type, Annotation_TYPE
+ };
+
+ private static final int ABSTRACT_STATIC_PRIVATE =
+ Modifier.ABSTRACT | Modifier.PRIVATE | Modifier.STATIC;
+ private static final int VISIBILITY = 5; // public|protected
+
+ protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
+
+ public static final String OBJECT = "java.lang.Object";
+
+ public static ClassNode makeCached(Class c) {
+ final SoftReference<ClassNode> classNodeSoftReference = ClassHelperCache.classCache.get(c);
+ ClassNode classNode;
+ if (classNodeSoftReference == null || (classNode = classNodeSoftReference.get()) == null) {
+ classNode = new ClassNode(c);
+ ClassHelperCache.classCache.put(c, new SoftReference<ClassNode>(classNode));
+
+ VMPluginFactory.getPlugin().setAdditionalClassInformation(classNode);
+ }
+
+ return classNode;
+ }
+
+ /**
+ * Creates an array of ClassNodes using an array of classes.
+ * For each of the given classes a new ClassNode will be
+ * created
+ *
+ * @param classes an array of classes used to create the ClassNodes
+ * @return an array of ClassNodes
+ * @see #make(Class)
+ */
+ public static ClassNode[] make(Class[] classes) {
+ ClassNode[] cns = new ClassNode[classes.length];
+ for (int i = 0; i < cns.length; i++) {
+ cns[i] = make(classes[i]);
+ }
+
+ return cns;
+ }
+
+ /**
+ * Creates a ClassNode using a given class.
+ * A new ClassNode object is only created if the class
+ * is not one of the predefined ones
+ *
+ * @param c class used to created the ClassNode
+ * @return ClassNode instance created from the given class
+ */
+ public static ClassNode make(Class c) {
+ return make(c, true);
+ }
+
+ public static ClassNode make(Class c, boolean includeGenerics) {
+ for (int i = 0; i < classes.length; i++) {
+ if (c == classes[i]) return types[i];
+ }
+ if (c.isArray()) {
+ ClassNode cn = make(c.getComponentType(), includeGenerics);
+ return cn.makeArray();
+ }
+ return makeWithoutCaching(c, includeGenerics);
+ }
+
+ public static ClassNode makeWithoutCaching(Class c) {
+ return makeWithoutCaching(c, true);
+ }
+
+ public static ClassNode makeWithoutCaching(Class c, boolean includeGenerics) {
+ if (c.isArray()) {
+ ClassNode cn = makeWithoutCaching(c.getComponentType(), includeGenerics);
+ return cn.makeArray();
+ }
+
+ final ClassNode cached = makeCached(c);
+ if (includeGenerics) {
+ return cached;
+ } else {
+ ClassNode t = makeWithoutCaching(c.getName());
+ t.setRedirect(cached);
+ return t;
+ }
+ }
+
+
+ /**
+ * Creates a ClassNode using a given class.
+ * Unlike make(String) this method will not use the cache
+ * to create the ClassNode. This means the ClassNode created
+ * from this method using the same name will have a different
+ * reference
+ *
+ * @param name of the class the ClassNode is representing
+ * @see #make(String)
+ */
+ public static ClassNode makeWithoutCaching(String name) {
+ ClassNode cn = new ClassNode(name, Opcodes.ACC_PUBLIC, OBJECT_TYPE);
+ cn.isPrimaryNode = false;
+ return cn;
+ }
+
+ /**
+ * Creates a ClassNode using a given class.
+ * If the name is one of the predefined ClassNodes then the
+ * corresponding ClassNode instance will be returned. If the
+ * name is null or of length 0 the dynamic type is returned
+ *
+ * @param name of the class the ClassNode is representing
+ */
+ public static ClassNode make(String name) {
+ if (name == null || name.length() == 0) return DYNAMIC_TYPE;
+
+ for (int i = 0; i < primitiveClassNames.length; i++) {
+ if (primitiveClassNames[i].equals(name)) return types[i];
+ }
+
+ for (int i = 0; i < classes.length; i++) {
+ String cname = classes[i].getName();
+ if (name.equals(cname)) return types[i];
+ }
+ return makeWithoutCaching(name);
+ }
+
+ /**
+ * Creates a ClassNode containing the wrapper of a ClassNode
+ * of primitive type. Any ClassNode representing a primitive
+ * type should be created using the predefined types used in
+ * class. The method will check the parameter for known
+ * references of ClassNode representing a primitive type. If
+ * Reference is found, then a ClassNode will be contained that
+ * represents the wrapper class. For example for boolean, the
+ * wrapper class is java.lang.Boolean.
+ * <p>
+ * If the parameter is no primitive type, the redirected
+ * ClassNode will be returned
+ *
+ * @param cn the ClassNode containing a possible primitive type
+ * @see #make(Class)
+ * @see #make(String)
+ */
+ public static ClassNode getWrapper(ClassNode cn) {
+ cn = cn.redirect();
+ if (!isPrimitiveType(cn)) return cn;
+ if (cn == boolean_TYPE) {
+ return Boolean_TYPE;
+ } else if (cn == byte_TYPE) {
+ return Byte_TYPE;
+ } else if (cn == char_TYPE) {
+ return Character_TYPE;
+ } else if (cn == short_TYPE) {
+ return Short_TYPE;
+ } else if (cn == int_TYPE) {
+ return Integer_TYPE;
+ } else if (cn == long_TYPE) {
+ return Long_TYPE;
+ } else if (cn == float_TYPE) {
+ return Float_TYPE;
+ } else if (cn == double_TYPE) {
+ return Double_TYPE;
+ } else if (cn == VOID_TYPE) {
+ return void_WRAPPER_TYPE;
+ } else {
+ return cn;
+ }
+ }
+
+ public static ClassNode getUnwrapper(ClassNode cn) {
+ cn = cn.redirect();
+ if (isPrimitiveType(cn)) return cn;
+ if (cn == Boolean_TYPE) {
+ return boolean_TYPE;
+ } else if (cn == Byte_TYPE) {
+ return byte_TYPE;
+ } else if (cn == Character_TYPE) {
+ return char_TYPE;
+ } else if (cn == Short_TYPE) {
+ return short_TYPE;
+ } else if (cn == Integer_TYPE) {
+ return int_TYPE;
+ } else if (cn == Long_TYPE) {
+ return long_TYPE;
+ } else if (cn == Float_TYPE) {
+ return float_TYPE;
+ } else if (cn == Double_TYPE) {
+ return double_TYPE;
+ } else {
+ return cn;
+ }
+ }
+
+
+ /**
+ * Test to determine if a ClassNode is a primitive type.
+ * Note: this only works for ClassNodes created using a
+ * predefined ClassNode
+ *
+ * @param cn the ClassNode containing a possible primitive type
+ * @return true if the ClassNode is a primitive type
+ * @see #make(Class)
+ * @see #make(String)
+ */
+ public static boolean isPrimitiveType(ClassNode cn) {
+ return cn == boolean_TYPE ||
+ cn == char_TYPE ||
+ cn == byte_TYPE ||
+ cn == short_TYPE ||
+ cn == int_TYPE ||
+ cn == long_TYPE ||
+ cn == float_TYPE ||
+ cn == double_TYPE ||
+ cn == VOID_TYPE;
+ }
+
+ /**
+ * Test to determine if a ClassNode is a type belongs to the list of types which
+ * are allowed to initialize constants directly in bytecode instead of using <cinit>
+ * <p>
+ * Note: this only works for ClassNodes created using a
+ * predefined ClassNode
+ *
+ * @param cn the ClassNode to be tested
+ * @return true if the ClassNode is of int, float, long, double or String type
+ * @see #make(Class)
+ * @see #make(String)
+ */
+ public static boolean isStaticConstantInitializerType(ClassNode cn) {
+ return cn == int_TYPE ||
+ cn == float_TYPE ||
+ cn == long_TYPE ||
+ cn == double_TYPE ||
+ cn == STRING_TYPE ||
+ // the next items require conversion to int when initializing
+ cn == byte_TYPE ||
+ cn == char_TYPE ||
+ cn == short_TYPE;
+ }
+
+ public static boolean isNumberType(ClassNode cn) {
+ return cn == Byte_TYPE ||
+ cn == Short_TYPE ||
+ cn == Integer_TYPE ||
+ cn == Long_TYPE ||
+ cn == Float_TYPE ||
+ cn == Double_TYPE ||
+ cn == byte_TYPE ||
+ cn == short_TYPE ||
+ cn == int_TYPE ||
+ cn == long_TYPE ||
+ cn == float_TYPE ||
+ cn == double_TYPE;
+ }
+
+ public static ClassNode makeReference() {
+ return REFERENCE_TYPE.getPlainNodeReference();
+ }
+
+ public static boolean isCachedType(ClassNode type) {
+ for (ClassNode cachedType : types) {
+ if (cachedType == type) return true;
+ }
+ return false;
+ }
+
+ static class ClassHelperCache {
+ static ManagedConcurrentMap<Class, SoftReference<ClassNode>> classCache = new ManagedConcurrentMap<Class, SoftReference<ClassNode>>(ReferenceBundle.getWeakBundle());
+ }
+
+ public static boolean isSAMType(ClassNode type) {
+ return findSAM(type) != null;
+ }
+
+ /**
+ * Returns the single abstract method of a class node, if it is a SAM type, or null otherwise.
+ *
+ * @param type a type for which to search for a single abstract method
+ * @return the method node if type is a SAM type, null otherwise
+ */
+ public static MethodNode findSAM(ClassNode type) {
+ if (!Modifier.isAbstract(type.getModifiers())) return null;
+ if (type.isInterface()) {
+ List<MethodNode> methods = type.getMethods();
+ MethodNode found = null;
+ for (MethodNode mi : methods) {
+ // ignore methods, that are not abstract and from Object
+ if (!Modifier.isAbstract(mi.getModifiers())) continue;
+ // ignore trait methods which have a default implementation
+ if (Traits.hasDefaultImplementation(mi)) continue;
+ if (mi.getDeclaringClass().equals(OBJECT_TYPE)) continue;
+ if (OBJECT_TYPE.getDeclaredMethod(mi.getName(), mi.getParameters()) != null) continue;
+
+ // we have two methods, so no SAM
+ if (found != null) return null;
+ found = mi;
+ }
+ return found;
+
+ } else {
+
+ List<MethodNode> methods = type.getAbstractMethods();
+ MethodNode found = null;
+ if (methods != null) {
+ for (MethodNode mi : methods) {
+ if (!hasUsableImplementation(type, mi)) {
+ if (found != null) return null;
+ found = mi;
+ }
+ }
+ }
+ return found;
+ }
+ }
+
+ private static boolean hasUsableImplementation(ClassNode c, MethodNode m) {
+ if (c == m.getDeclaringClass()) return false;
+ MethodNode found = c.getDeclaredMethod(m.getName(), m.getParameters());
+ if (found == null) return false;
+ int asp = found.getModifiers() & ABSTRACT_STATIC_PRIVATE;
+ int visible = found.getModifiers() & VISIBILITY;
+ if (visible != 0 && asp == 0) return true;
+ if (c.equals(OBJECT_TYPE)) return false;
+ return hasUsableImplementation(c.getSuperClass(), m);
+ }
+
+ /**
+ * Returns a super class or interface for a given class depending on a given target.
+ * If the target is no super class or interface, then null will be returned.
+ * For a non-primitive array type, returns an array of the componentType's super class
+ * or interface if the target is also an array.
+ *
+ * @param clazz the start class
+ * @param goalClazz the goal class
+ * @return the next super class or interface
+ */
+ public static ClassNode getNextSuperClass(ClassNode clazz, ClassNode goalClazz) {
+ if (clazz.isArray()) {
+ if (!goalClazz.isArray()) return null;
+ ClassNode cn = getNextSuperClass(clazz.getComponentType(), goalClazz.getComponentType());
+ if (cn != null) cn = cn.makeArray();
+ return cn;
+ }
+
+ if (!goalClazz.isInterface()) {
+ if (clazz.isInterface()) {
+ if (OBJECT_TYPE.equals(clazz)) return null;
+ return OBJECT_TYPE;
+ } else {
+ return clazz.getUnresolvedSuperClass();
+ }
+ }
+
+ ClassNode[] interfaces = clazz.getUnresolvedInterfaces();
+ for (ClassNode anInterface : interfaces) {
+ if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(anInterface, goalClazz)) {
+ return anInterface;
+ }
+ }
+ //none of the interfaces here match, so continue with super class
+ return clazz.getUnresolvedSuperClass();
+ }
+}