All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.groovy.transform.AbstractASTTransformation Maven / Gradle / Ivy

There is a newer version: 3.0.21
Show newest version
/*
 *  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.transform;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.tools.GeneralUtils;
import org.codehaus.groovy.ast.tools.GenericsUtils;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
import org.codehaus.groovy.runtime.StringGroovyMethods;
import org.codehaus.groovy.syntax.SyntaxException;
import org.objectweb.asm.Opcodes;

import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static groovy.transform.Undefined.isUndefined;

public abstract class AbstractASTTransformation implements Opcodes, ASTTransformation {
    public static final ClassNode RETENTION_CLASSNODE = ClassHelper.makeWithoutCaching(Retention.class);

    protected SourceUnit sourceUnit;

    /**
     * Copies all candidateAnnotations with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
     * and {@link java.lang.annotation.RetentionPolicy#CLASS}.
     * 

* Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported for now. */ protected List copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, String myTypeName) { final ArrayList copiedAnnotations = new ArrayList(); final ArrayList notCopied = new ArrayList(); GeneralUtils.copyAnnotatedNodeAnnotations(annotatedNode, copiedAnnotations, notCopied); for (AnnotationNode annotation : notCopied) { addError(myTypeName + " does not support keeping Closure annotation members.", annotation); } return copiedAnnotations; } protected void init(ASTNode[] nodes, SourceUnit sourceUnit) { if (nodes == null || nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) { throw new GroovyBugError("Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + (nodes == null ? null : Arrays.asList(nodes))); } this.sourceUnit = sourceUnit; } public boolean memberHasValue(AnnotationNode node, String name, Object value) { final Expression member = node.getMember(name); return member != null && member instanceof ConstantExpression && ((ConstantExpression) member).getValue().equals(value); } public Object getMemberValue(AnnotationNode node, String name) { final Expression member = node.getMember(name); if (member != null && member instanceof ConstantExpression) return ((ConstantExpression) member).getValue(); return null; } public static String getMemberStringValue(AnnotationNode node, String name, String defaultValue) { final Expression member = node.getMember(name); if (member != null && member instanceof ConstantExpression) { Object result = ((ConstantExpression) member).getValue(); if (result != null && result instanceof String && isUndefined((String) result)) result = null; if (result != null) return result.toString(); } return defaultValue; } public static String getMemberStringValue(AnnotationNode node, String name) { return getMemberStringValue(node, name, null); } public int getMemberIntValue(AnnotationNode node, String name) { Object value = getMemberValue(node, name); if (value != null && value instanceof Integer) { return (Integer) value; } return 0; } public ClassNode getMemberClassValue(AnnotationNode node, String name) { return getMemberClassValue(node, name, null); } public ClassNode getMemberClassValue(AnnotationNode node, String name, ClassNode defaultValue) { final Expression member = node.getMember(name); if (member != null) { if (member instanceof ClassExpression) { if (!isUndefined(member.getType())) return member.getType(); } else if (member instanceof VariableExpression) { addError("Error expecting to find class value for '" + name + "' but found variable: " + member.getText() + ". Missing import?", node); return null; } else if (member instanceof ConstantExpression) { addError("Error expecting to find class value for '" + name + "' but found constant: " + member.getText() + "!", node); return null; } } return defaultValue; } public static List getMemberList(AnnotationNode anno, String name) { List list; Expression expr = anno.getMember(name); if (expr != null && expr instanceof ListExpression) { list = new ArrayList(); final ListExpression listExpression = (ListExpression) expr; for (Expression itemExpr : listExpression.getExpressions()) { if (itemExpr != null && itemExpr instanceof ConstantExpression) { Object value = ((ConstantExpression) itemExpr).getValue(); if (value != null) list.add(value.toString()); } } } else { list = tokenize(getMemberStringValue(anno, name)); } return list; } public List getClassList(AnnotationNode anno, String name) { List list = new ArrayList(); Expression expr = anno.getMember(name); if (expr != null && expr instanceof ListExpression) { final ListExpression listExpression = (ListExpression) expr; for (Expression itemExpr : listExpression.getExpressions()) { if (itemExpr != null && itemExpr instanceof ClassExpression) { ClassNode cn = itemExpr.getType(); if (cn != null) list.add(cn); } } } else if (expr != null && expr instanceof ClassExpression) { ClassNode cn = expr.getType(); if (cn != null) list.add(cn); } return list; } public void addError(String msg, ASTNode expr) { sourceUnit.getErrorCollector().addErrorAndContinue(new SyntaxErrorMessage( new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), sourceUnit) ); } protected boolean checkNotInterface(ClassNode cNode, String annotationName) { if (cNode.isInterface()) { addError("Error processing interface '" + cNode.getName() + "'. " + annotationName + " not allowed for interfaces.", cNode); return false; } return true; } public boolean hasAnnotation(ClassNode cNode, ClassNode annotation) { List annots = cNode.getAnnotations(annotation); return (annots != null && !annots.isEmpty()); } public static List tokenize(String rawExcludes) { return rawExcludes == null ? new ArrayList() : StringGroovyMethods.tokenize(rawExcludes, ", "); } public static boolean deemedInternalName(String name) { return name.contains("$"); } public static boolean shouldSkip(String name, List excludes, List includes) { return (excludes != null && excludes.contains(name)) || deemedInternalName(name) || (includes != null && !includes.isEmpty() && !includes.contains(name)); } public static boolean shouldSkipOnDescriptor(boolean checkReturn, Map genericsSpec, MethodNode mNode, List excludeTypes, List includeTypes) { String descriptor = mNode.getTypeDescriptor(); String descriptorNoReturn = GeneralUtils.makeDescriptorWithoutReturnType(mNode); for (ClassNode cn : excludeTypes) { List remaining = new LinkedList(); remaining.add(cn); Map updatedGenericsSpec = new HashMap(genericsSpec); while (!remaining.isEmpty()) { ClassNode next = remaining.remove(0); if (!next.equals(ClassHelper.OBJECT_TYPE)) { updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec); for (MethodNode mn : next.getMethods()) { MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn); if (checkReturn) { String md = correctedMethodNode.getTypeDescriptor(); if (md.equals(descriptor)) return true; } else { String md = GeneralUtils.makeDescriptorWithoutReturnType(correctedMethodNode); if (md.equals(descriptorNoReturn)) return true; } } remaining.addAll(Arrays.asList(next.getInterfaces())); } } } if (includeTypes.isEmpty()) return false; for (ClassNode cn : includeTypes) { List remaining = new LinkedList(); remaining.add(cn); Map updatedGenericsSpec = new HashMap(genericsSpec); while (!remaining.isEmpty()) { ClassNode next = remaining.remove(0); if (!next.equals(ClassHelper.OBJECT_TYPE)) { updatedGenericsSpec = GenericsUtils.createGenericsSpec(next, updatedGenericsSpec); for (MethodNode mn : next.getMethods()) { MethodNode correctedMethodNode = GenericsUtils.correctToGenericsSpec(updatedGenericsSpec, mn); if (checkReturn) { String md = correctedMethodNode.getTypeDescriptor(); if (md.equals(descriptor)) return false; } else { String md = GeneralUtils.makeDescriptorWithoutReturnType(correctedMethodNode); if (md.equals(descriptorNoReturn)) return false; } } remaining.addAll(Arrays.asList(next.getInterfaces())); } } } return true; } protected boolean checkIncludeExclude(AnnotationNode node, List excludes, List includes, String typeName) { if (includes != null && !includes.isEmpty() && excludes != null && !excludes.isEmpty()) { addError("Error during " + typeName + " processing: Only one of 'includes' and 'excludes' should be supplied not both.", node); return false; } return true; } protected void checkIncludeExclude(AnnotationNode node, List excludes, List includes, List excludeTypes, List includeTypes, String typeName) { int found = 0; if (includes != null && !includes.isEmpty()) found++; if (excludes != null && !excludes.isEmpty()) found++; if (includeTypes != null && !includeTypes.isEmpty()) found++; if (excludeTypes != null && !excludeTypes.isEmpty()) found++; if (found > 1) { addError("Error during " + typeName + " processing: Only one of 'includes', 'excludes', 'includeTypes' and 'excludeTypes' should be supplied.", node); } } /** * @deprecated use GenericsUtils#nonGeneric */ @Deprecated public static ClassNode nonGeneric(ClassNode type) { return GenericsUtils.nonGeneric(type); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy