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);
});
}
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);
}
}
}
}
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);
});
}
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;
}
Aggregations