Search in sources :

Example 1 with GroovyCodeVisitor

use of org.codehaus.groovy.ast.GroovyCodeVisitor in project groovy by apache.

the class Verifier method addDefaultParameterConstructors.

/**
 * Creates a new constructor for each combination of default parameter expressions.
 */
protected void addDefaultParameterConstructors(final ClassNode type) {
    List<ConstructorNode> constructors = new ArrayList<>(type.getDeclaredConstructors());
    addDefaultParameters(constructors, (arguments, params, method) -> {
        // GROOVY-9151: check for references to parameters that have been removed
        for (ListIterator<Expression> it = arguments.getExpressions().listIterator(); it.hasNext(); ) {
            Expression argument = it.next();
            if (argument instanceof CastExpression) {
                argument = ((CastExpression) argument).getExpression();
            }
            if (argument instanceof VariableExpression) {
                VariableExpression v = (VariableExpression) argument;
                if (v.getAccessedVariable() instanceof Parameter) {
                    Parameter p = (Parameter) v.getAccessedVariable();
                    if (p.hasInitialExpression() && !Arrays.asList(params).contains(p) && p.getInitialExpression() instanceof ConstantExpression) {
                        // replace argument "(Type) param" with "(Type) <param's default>" for simple default value
                        it.set(castX(method.getParameters()[it.nextIndex() - 1].getType(), p.getInitialExpression()));
                    }
                }
            }
        }
        GroovyCodeVisitor visitor = new CodeVisitorSupport() {

            @Override
            public void visitVariableExpression(final VariableExpression e) {
                if (e.getAccessedVariable() instanceof Parameter) {
                    Parameter p = (Parameter) e.getAccessedVariable();
                    if (p.hasInitialExpression() && !Arrays.asList(params).contains(p)) {
                        String error = String.format("The generated constructor \"%s(%s)\" references parameter '%s' which has been replaced by a default value expression.", type.getNameWithoutPackage(), Arrays.stream(params).map(Parameter::getType).map(ClassNodeUtils::formatTypeName).collect(joining(",")), p.getName());
                        throw new RuntimeParserException(error, sourceOf(method));
                    }
                }
            }
        };
        visitor.visitArgumentlistExpression(arguments);
        // delegate to original constructor using arguments derived from defaults
        Statement code = new ExpressionStatement(new ConstructorCallExpression(ClassNode.THIS, arguments));
        addConstructor(params, (ConstructorNode) method, code, type);
    });
}
Also used : ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) ArrayList(java.util.ArrayList) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) CodeVisitorSupport(org.codehaus.groovy.ast.CodeVisitorSupport) ClassNodeUtils(org.apache.groovy.ast.tools.ClassNodeUtils) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) CastExpression(org.codehaus.groovy.ast.expr.CastExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) FieldExpression(org.codehaus.groovy.ast.expr.FieldExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) Parameter(org.codehaus.groovy.ast.Parameter) GroovyCodeVisitor(org.codehaus.groovy.ast.GroovyCodeVisitor) CastExpression(org.codehaus.groovy.ast.expr.CastExpression) RuntimeParserException(org.codehaus.groovy.syntax.RuntimeParserException)

Example 2 with GroovyCodeVisitor

use of org.codehaus.groovy.ast.GroovyCodeVisitor in project groovy by apache.

the class SecureASTCustomizer method call.

@Override
public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
    ModuleNode ast = source.getAST();
    if (!isPackageAllowed && ast.getPackage() != null) {
        throw new SecurityException("Package definitions are not allowed");
    }
    checkMethodDefinitionAllowed(classNode);
    // verify imports
    if (disallowedImports != null || allowedImports != null || disallowedStarImports != null || allowedStarImports != null) {
        for (ImportNode importNode : ast.getImports()) {
            assertImportIsAllowed(importNode.getClassName());
        }
        for (ImportNode importNode : ast.getStarImports()) {
            assertStarImportIsAllowed(importNode.getPackageName() + "*");
        }
    }
    // verify static imports
    if (disallowedStaticImports != null || allowedStaticImports != null || disallowedStaticStarImports != null || allowedStaticStarImports != null) {
        for (Map.Entry<String, ImportNode> entry : ast.getStaticImports().entrySet()) {
            final String className = entry.getValue().getClassName();
            assertStaticImportIsAllowed(entry.getKey(), className);
        }
        for (Map.Entry<String, ImportNode> entry : ast.getStaticStarImports().entrySet()) {
            final String className = entry.getValue().getClassName();
            assertStaticImportIsAllowed(entry.getKey(), className);
        }
    }
    GroovyCodeVisitor visitor = createGroovyCodeVisitor();
    ast.getStatementBlock().visit(visitor);
    for (ClassNode clNode : ast.getClasses()) {
        if (clNode != classNode) {
            checkMethodDefinitionAllowed(clNode);
            for (MethodNode methodNode : clNode.getMethods()) {
                if (!methodNode.isSynthetic() && methodNode.getCode() != null) {
                    methodNode.getCode().visit(visitor);
                }
            }
        }
    }
    List<MethodNode> methods = filterMethods(classNode);
    if (isMethodDefinitionAllowed) {
        for (MethodNode method : methods) {
            if (method.getDeclaringClass() == classNode && method.getCode() != null) {
                method.getCode().visit(visitor);
            }
        }
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) GroovyCodeVisitor(org.codehaus.groovy.ast.GroovyCodeVisitor) ImportNode(org.codehaus.groovy.ast.ImportNode) Map(java.util.Map) ModuleNode(org.codehaus.groovy.ast.ModuleNode)

Example 3 with GroovyCodeVisitor

use of org.codehaus.groovy.ast.GroovyCodeVisitor in project groovy by apache.

the class Verifier method addDefaultParameterMethods.

/**
 * Creates a new method for each combination of default parameter expressions.
 */
protected void addDefaultParameterMethods(final ClassNode type) {
    List<MethodNode> methods = new ArrayList<>(type.getMethods());
    addDefaultParameters(methods, (arguments, params, method) -> {
        BlockStatement code = new BlockStatement();
        MethodNode newMethod = new MethodNode(method.getName(), method.getModifiers(), method.getReturnType(), params, method.getExceptions(), code);
        MethodNode oldMethod = type.getDeclaredMethod(method.getName(), params);
        if (oldMethod != null) {
            throw new RuntimeParserException("The method with default parameters \"" + method.getTypeDescriptor() + "\" defines a method \"" + newMethod.getTypeDescriptor() + "\" that is already defined.", sourceOf(method));
        }
        List<AnnotationNode> annotations = method.getAnnotations();
        if (annotations != null && !annotations.isEmpty()) {
            newMethod.addAnnotations(annotations);
        }
        newMethod.setGenericsTypes(method.getGenericsTypes());
        // GROOVY-5632, GROOVY-9151: check for references to parameters that have been removed
        GroovyCodeVisitor visitor = new CodeVisitorSupport() {

            private boolean inClosure;

            @Override
            public void visitClosureExpression(final ClosureExpression e) {
                boolean prev = inClosure;
                inClosure = true;
                super.visitClosureExpression(e);
                inClosure = prev;
            }

            @Override
            public void visitVariableExpression(final VariableExpression e) {
                if (e.getAccessedVariable() instanceof Parameter) {
                    Parameter p = (Parameter) e.getAccessedVariable();
                    if (p.hasInitialExpression() && !Arrays.asList(params).contains(p)) {
                        VariableScope blockScope = code.getVariableScope();
                        VariableExpression localVariable = (VariableExpression) blockScope.getDeclaredVariable(p.getName());
                        if (localVariable == null) {
                            // create a variable declaration so that the name can be found in the new method
                            localVariable = localVarX(p.getName(), p.getType());
                            localVariable.setModifiers(p.getModifiers());
                            blockScope.putDeclaredVariable(localVariable);
                            localVariable.setInStaticContext(blockScope.isInStaticContext());
                            code.addStatement(declS(localVariable, p.getInitialExpression()));
                        }
                        if (!localVariable.isClosureSharedVariable()) {
                            localVariable.setClosureSharedVariable(inClosure);
                        }
                    }
                }
            }
        };
        visitor.visitArgumentlistExpression(arguments);
        // if variable was created to capture an initial value expression, reference it in arguments as well
        for (ListIterator<Expression> it = arguments.getExpressions().listIterator(); it.hasNext(); ) {
            Expression argument = it.next();
            if (argument instanceof CastExpression) {
                argument = ((CastExpression) argument).getExpression();
            }
            for (Parameter p : method.getParameters()) {
                if (p.hasInitialExpression() && p.getInitialExpression() == argument) {
                    if (code.getVariableScope().getDeclaredVariable(p.getName()) != null) {
                        it.set(varX(p.getName()));
                    }
                    break;
                }
            }
        }
        // delegate to original method using arguments derived from defaults
        MethodCallExpression call = callThisX(method.getName(), arguments);
        call.setMethodTarget(method);
        call.setImplicitThis(true);
        if (method.isVoidMethod()) {
            code.addStatement(new ExpressionStatement(call));
        } else {
            code.addStatement(new ReturnStatement(call));
        }
        // GROOVY-5681: set anon. inner enclosing method reference
        visitor = new CodeVisitorSupport() {

            @Override
            public void visitConstructorCallExpression(final ConstructorCallExpression call) {
                if (call.isUsingAnonymousInnerClass()) {
                    call.getType().setEnclosingMethod(newMethod);
                }
                super.visitConstructorCallExpression(call);
            }
        };
        visitor.visitBlockStatement(code);
        addPropertyMethod(newMethod);
        newMethod.putNodeMetaData(DEFAULT_PARAMETER_GENERATED, Boolean.TRUE);
    });
}
Also used : ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) ArrayList(java.util.ArrayList) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) CodeVisitorSupport(org.codehaus.groovy.ast.CodeVisitorSupport) MethodNode(org.codehaus.groovy.ast.MethodNode) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) AnnotationNode(org.codehaus.groovy.ast.AnnotationNode) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) CastExpression(org.codehaus.groovy.ast.expr.CastExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) FieldExpression(org.codehaus.groovy.ast.expr.FieldExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) GroovyCodeVisitor(org.codehaus.groovy.ast.GroovyCodeVisitor) Parameter(org.codehaus.groovy.ast.Parameter) RuntimeParserException(org.codehaus.groovy.syntax.RuntimeParserException) ClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression) CastExpression(org.codehaus.groovy.ast.expr.CastExpression) VariableScope(org.codehaus.groovy.ast.VariableScope)

Example 4 with GroovyCodeVisitor

use of org.codehaus.groovy.ast.GroovyCodeVisitor in project groovy by apache.

the class InnerClassVisitor method isStatic.

private boolean isStatic(final ClassNode innerClass, final VariableScope scope, final ConstructorCallExpression call) {
    boolean isStatic = innerClass.isStaticClass();
    if (!isStatic) {
        if (currentMethod != null) {
            if (currentMethod instanceof ConstructorNode) {
                boolean[] precedesSuperOrThisCall = new boolean[1];
                ConstructorNode ctor = (ConstructorNode) currentMethod;
                GroovyCodeVisitor visitor = new CodeVisitorSupport() {

                    @Override
                    public void visitConstructorCallExpression(ConstructorCallExpression cce) {
                        if (cce == call) {
                            precedesSuperOrThisCall[0] = true;
                        } else {
                            super.visitConstructorCallExpression(cce);
                        }
                    }
                };
                if (ctor.firstStatementIsSpecialConstructorCall())
                    currentMethod.getFirstStatement().visit(visitor);
                Arrays.stream(ctor.getParameters()).filter(Parameter::hasInitialExpression).forEach(p -> p.getInitialExpression().visit(visitor));
                isStatic = precedesSuperOrThisCall[0];
            } else {
                isStatic = currentMethod.isStatic();
            }
        } else if (currentField != null) {
            isStatic = currentField.isStatic();
        }
    }
    // GROOVY-8433: Category transform implies static method
    isStatic = isStatic || innerClass.getOuterClass().getAnnotations().stream().anyMatch(a -> a.getClassNode().getName().equals("groovy.lang.Category"));
    return isStatic;
}
Also used : CodeVisitorSupport(org.codehaus.groovy.ast.CodeVisitorSupport) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) ConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression) GroovyCodeVisitor(org.codehaus.groovy.ast.GroovyCodeVisitor)

Aggregations

GroovyCodeVisitor (org.codehaus.groovy.ast.GroovyCodeVisitor)4 CodeVisitorSupport (org.codehaus.groovy.ast.CodeVisitorSupport)3 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)3 ArrayList (java.util.ArrayList)2 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)2 MethodNode (org.codehaus.groovy.ast.MethodNode)2 Parameter (org.codehaus.groovy.ast.Parameter)2 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)2 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)2 CastExpression (org.codehaus.groovy.ast.expr.CastExpression)2 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)2 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)2 Expression (org.codehaus.groovy.ast.expr.Expression)2 FieldExpression (org.codehaus.groovy.ast.expr.FieldExpression)2 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)2 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)2 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)2 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)2 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)2 RuntimeParserException (org.codehaus.groovy.syntax.RuntimeParserException)2