org.codehaus.groovy.tools.shell.util.ScriptVariableAnalyzer.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of driver-cql-shaded Show documentation
Show all versions of driver-cql-shaded Show documentation
A Shaded CQL ActivityType driver for http://nosqlbench.io/
/*
* 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.tools.shell.util
import groovy.transform.TypeChecked
import org.codehaus.groovy.ast.ClassCodeVisitorSupport
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.DynamicVariable
import org.codehaus.groovy.ast.GroovyClassVisitor
import org.codehaus.groovy.ast.expr.VariableExpression
import org.codehaus.groovy.classgen.GeneratorContext
import org.codehaus.groovy.control.CompilationFailedException
import org.codehaus.groovy.control.CompilationUnit
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.Phases
import org.codehaus.groovy.control.SourceUnit
import java.security.CodeSource
/**
* Class to Class parsing a script to detect all bound and unbound variables.
* Based on http://glaforge.appspot.com/article/knowing-which-variables-are-bound-or-not-in-a-groovy-script
*/
@TypeChecked
class ScriptVariableAnalyzer {
/**
* define a visitor that visits all variable expressions
*/
static class VariableVisitor extends ClassCodeVisitorSupport implements GroovyClassVisitor {
Set bound = new HashSet()
Set unbound = new HashSet()
@Override
void visitVariableExpression(VariableExpression expression) {
// we're not interested in some special implicit variables
if (!(expression.variable in ['args', 'context', 'this', 'super'])) {
// thanks to this instanceof
// we know if the variable is bound or not
if (expression.accessedVariable instanceof DynamicVariable) {
unbound << expression.variable
} else {
bound << expression.variable
}
}
super.visitVariableExpression(expression)
}
@Override
protected SourceUnit getSourceUnit() {
return null
}
}
/**
* custom PrimaryClassNodeOperation
* to be able to hook our code visitor
*/
static class VisitorSourceOperation extends CompilationUnit.PrimaryClassNodeOperation {
final GroovyClassVisitor visitor
VisitorSourceOperation(final GroovyClassVisitor visitor) {
this.visitor = visitor
}
@Override
void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode)
throws CompilationFailedException {
classNode.visitContents(visitor)
}
}
/**
* class loader to add our phase operation
*/
static class VisitorClassLoader extends GroovyClassLoader {
final GroovyClassVisitor visitor
VisitorClassLoader(final GroovyClassVisitor visitor, ClassLoader parent) {
super(parent == null ? Thread.currentThread().getContextClassLoader() : parent)
this.visitor = visitor
}
@Override
protected CompilationUnit createCompilationUnit(final CompilerConfiguration config, final CodeSource source) {
CompilationUnit cu = super.createCompilationUnit(config, source)
cu.addPhaseOperation(new VisitorSourceOperation(visitor), Phases.CLASS_GENERATION)
return cu
}
}
static Set getBoundVars(final String scriptText, ClassLoader parent) {
assert scriptText != null
GroovyClassVisitor visitor = new VariableVisitor()
VisitorClassLoader myCL = new VisitorClassLoader(visitor, parent)
// simply by parsing the script with our classloader
// our visitor will be called and will visit all the variables
myCL.parseClass(scriptText)
return visitor.bound
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy