package com.crawljax.plugins.jsmodify.executionTracer;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import org.mozilla.javascript.Token;
import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.AstRoot;
import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.ast.Scope;
import org.mozilla.javascript.ast.Symbol;
import com.crawljax.plugins.jsmodify.JSASTModifier;
import com.crawljax.util.Helper;
/**
* This class is used to visit all JS nodes. When a node matches a certain condition, this class
* will add instrumentation code near this code.
*
*/
public abstract class AstInstrumenter extends JSASTModifier {
/**
* List with regular expressions that should not be instrumented.
*/
private List<String> excludeList = new ArrayList<String>();
String jsFileNameToAttach;
private boolean domModifications = false;
/**
* Construct without patterns.
*/
public AstInstrumenter(String jsFileNameToAttach) {
super();
this.jsFileNameToAttach=jsFileNameToAttach;
excludeList = new ArrayList<String>();
}
/**
* Constructor with patterns.
*
* @param excludes
* List with variable patterns to exclude.
*/
public AstInstrumenter(List<String> excludes) {
excludeList = excludes;
}
/**
* Return an AST of the variable logging functions.
*
* @return The AstNode which contains functions.
*/
private AstNode jsLoggingFunctions() {
String code;
File js = new File(this.getClass().getResource(jsFileNameToAttach).getFile());
code = Helper.getContent(js);
return parse(code);
}
@Override
public abstract AstNode createNodeInFunction(FunctionNode function, int lineNo);
@Override
public abstract AstNode createNode(AstNode...node);
/**
* Check if we should instrument this variable by matching it against the exclude variable
* regexps.
*
* @param name
* Name of the variable.
* @return True if we should add instrumentation code.
*/
protected boolean shouldInstrument(String name) {
if (name == null) {
return false;
}
/* is this an excluded variable? */
for (String regex : excludeList) {
if (name.matches(regex)) {
return false;
}
}
return true;
}
/**
* Returns all variables in scope.
*
* @param func
* The function.
* @return All variables in scope.
*/
protected String[] getVariablesNamesInScope(Scope scope) {
TreeSet<String> result = new TreeSet<String>();
do {
/* get the symboltable for the current scope */
Map<String, Symbol> t = scope.getSymbolTable();
if (t != null) {
for (String key : t.keySet()) {
/* read the symbol */
Symbol symbol = t.get(key);
/* only add variables and function parameters */
if (symbol.getDeclType() == Token.LP || symbol.getDeclType() == Token.VAR) {
result.add(symbol.getName());
}
}
}
/* get next scope (upwards) */
scope = scope.getEnclosingScope();
} while (scope != null);
/* return the result as a String array */
return result.toArray(new String[0]);
}
@Override
public void finish(AstRoot node) {
/* add initialization code for the function and logging array */
node.addChildToFront(jsLoggingFunctions());
}
@Override
public abstract void start();
@Override
public abstract AstNode createPointNode(String objectAndFunction, int lineNo);
protected boolean shouldInstrumentDOMModifications() {
return domModifications;
}
public void instrumentDOMModifications() {
domModifications = true;
}
}