mirror of
https://github.com/github/codeql.git
synced 2026-01-07 19:50:22 +01:00
JavaScript: Remove obsolete Rhino interface classes.
This commit is contained in:
@@ -1,196 +0,0 @@
|
||||
package com.semmle.js.parser;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mozilla.javascript.NativeArray;
|
||||
import org.mozilla.javascript.NativeObject;
|
||||
import org.mozilla.javascript.UniqueTag;
|
||||
|
||||
import com.semmle.js.ast.Position;
|
||||
import com.semmle.js.ast.SourceElement;
|
||||
import com.semmle.js.ast.SourceLocation;
|
||||
import com.semmle.util.exception.CatastrophicError;
|
||||
|
||||
/**
|
||||
* Decode SpiderMonkey AST objects into their Java equivalents.
|
||||
*
|
||||
* We assume that every AST node has a <code>type</code> property uniquely identifying its
|
||||
* type, which is also the name of the corresponding Java class.
|
||||
*
|
||||
* For each Java class, a list of properties to read from the SpiderMonkey AST object has to be provided.
|
||||
* It is assumed that the Java class has a single constructor which takes exactly those
|
||||
* properties as arguments.
|
||||
*/
|
||||
public class JSObjectDecoder<T extends SourceElement> {
|
||||
private final ScriptLoader loader;
|
||||
private final String source;
|
||||
private final String pkg;
|
||||
private final Map<Class<? extends T>, List<String>> spec;
|
||||
|
||||
/**
|
||||
* Construct a new object decoder.
|
||||
*
|
||||
* @param source the source code from which the AST was parsed
|
||||
* @param loader the Rhino instance to use
|
||||
* @param pkg the package in which to look for Java classes
|
||||
* @param spec a mapping from Java classes to properties
|
||||
*/
|
||||
public JSObjectDecoder(String source, ScriptLoader loader, String pkg, Map<Class<? extends T>, List<String>> spec) {
|
||||
this.source = source;
|
||||
this.loader = loader;
|
||||
this.pkg = pkg;
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a given SpiderMonkey AST object.
|
||||
*
|
||||
* Any exceptions that occur during conversion are caught and re-thrown as {@link CatastrophicError},
|
||||
* except for {@link ClassNotFoundException}s resulting from unsupported AST node types, which are
|
||||
* re-thrown as {@link ParseError}s.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T decodeObject(NativeObject object) throws ParseError {
|
||||
String type = (String) loader.readProperty(object, "type");
|
||||
try {
|
||||
Class<? extends T> clazz = (Class<? extends T>)Class.forName(pkg + "." + type);
|
||||
return decodeObject(object, clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ParseError("Unexpected node type " + e, decodeLocation(object).getStart());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a given SpiderMonkey AST object as an instance of a given class.
|
||||
*
|
||||
* Any exceptions that occur during conversion are caught and re-thrown as {@link CatastrophicError},
|
||||
* except for {@link ClassNotFoundException}s resulting from unsupported AST node types, which are
|
||||
* re-thrown as {@link ParseError}s.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> V decodeObject(NativeObject object, Class<V> clazz) throws ParseError {
|
||||
SourceLocation loc = decodeLocation(object);
|
||||
Object[] ctorArgs = null;
|
||||
try {
|
||||
List<String> props = spec.get(clazz);
|
||||
if (props == null)
|
||||
throw new CatastrophicError("Unsupported node type " + clazz.getName());
|
||||
ctorArgs = new Object[props.size()+1];
|
||||
ctorArgs[0] = loc;
|
||||
for (int i=1; i<ctorArgs.length; ++i) {
|
||||
String argName = props.get(i-1);
|
||||
Object arg = loader.readProperty(object, argName);
|
||||
if (arg instanceof NativeObject) {
|
||||
ctorArgs[i] = decodeObject((NativeObject)arg);
|
||||
} else if (arg instanceof NativeArray) {
|
||||
ctorArgs[i] = decodeObjects((NativeArray)arg);
|
||||
} else if (arg == UniqueTag.NOT_FOUND) {
|
||||
ctorArgs[i] = null;
|
||||
} else if (arg instanceof CharSequence) {
|
||||
// Rhino has its own funny string types; normalise
|
||||
ctorArgs[i] = arg.toString();
|
||||
} else {
|
||||
ctorArgs[i] = arg;
|
||||
}
|
||||
}
|
||||
return (V)clazz.getConstructors()[0].newInstance(ctorArgs);
|
||||
} catch (InstantiationException e) {
|
||||
throw new CatastrophicError(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new CatastrophicError(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new CatastrophicError(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new CatastrophicError(e);
|
||||
} catch (SecurityException e) {
|
||||
throw new CatastrophicError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an array of SpiderMonkey AST objects.
|
||||
*/
|
||||
public List<T> decodeObjects(NativeArray objects) throws ParseError {
|
||||
List<T> result = new ArrayList<T>(objects.size());
|
||||
for (Object object : objects) {
|
||||
if (object == null)
|
||||
result.add(null);
|
||||
else
|
||||
result.add(decodeObject((NativeObject)object));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an array of SpiderMonkey AST objects as instances of a given class.
|
||||
*/
|
||||
public <V> List<V> decodeObjects(Class<V> clazz, NativeArray objects) throws ParseError {
|
||||
List<V> result = new ArrayList<V>(objects.size());
|
||||
for (Object object : objects) {
|
||||
if (object == null)
|
||||
result.add(null);
|
||||
else
|
||||
result.add(decodeObject((NativeObject)object, clazz));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bound <code>x</code> between <code>lo</code> and <code>hi</code>, inclusive.
|
||||
*/
|
||||
private int bound(int x, int lo, int hi) {
|
||||
if (x < lo)
|
||||
return lo;
|
||||
if (x > hi)
|
||||
return hi;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a SpiderMonkey location object into a {@link SourceLocation}.
|
||||
*/
|
||||
public SourceLocation decodeLocation(NativeObject object) {
|
||||
Integer startOffset, endOffset;
|
||||
Position start, end;
|
||||
Object loc = loader.readProperty(object, "loc");
|
||||
|
||||
if (loc == null) {
|
||||
// no 'loc' property; check whether we have 'range'
|
||||
Object range = loader.readProperty(object, "range");
|
||||
if (range instanceof NativeArray) {
|
||||
// good; make up a source location on line 0
|
||||
startOffset = loader.readIntProperty(range, 0);
|
||||
endOffset = loader.readIntProperty(range, 1);
|
||||
start = new Position(1, startOffset, startOffset);
|
||||
end = new Position(1, endOffset, endOffset);
|
||||
return new SourceLocation(getSource(startOffset, endOffset), start, end);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
startOffset = loader.readIntProperty(object, "start");
|
||||
endOffset = loader.readIntProperty(object, "end");
|
||||
start = decodePosition((NativeObject)loader.readProperty(loc, "start"), startOffset);
|
||||
end = decodePosition((NativeObject)loader.readProperty(loc, "end"), endOffset);
|
||||
return new SourceLocation(getSource(startOffset, endOffset), start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the source code between a given start and end offset.
|
||||
*/
|
||||
public String getSource(Integer startOffset, Integer endOffset) {
|
||||
if (startOffset == null || endOffset == null || startOffset > endOffset)
|
||||
return "";
|
||||
return source.substring(bound(startOffset, 0, source.length()), bound(endOffset, 0, source.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a SpiderMonkey position object into a {@link SourceLocation}.
|
||||
*/
|
||||
private Position decodePosition(NativeObject object, int offset) {
|
||||
return new Position(loader.readIntProperty(object, "line"), loader.readIntProperty(object, "column"), offset);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package com.semmle.js.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Function;
|
||||
import org.mozilla.javascript.NativeArray;
|
||||
import org.mozilla.javascript.NativeJSON;
|
||||
import org.mozilla.javascript.NativeObject;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.mozilla.javascript.Undefined;
|
||||
import org.mozilla.javascript.UniqueTag;
|
||||
|
||||
import com.semmle.util.exception.CatastrophicError;
|
||||
import com.semmle.util.files.FileUtil;
|
||||
|
||||
/**
|
||||
* Helper class for executing JavaScript programs through Rhino and reading out values from the
|
||||
* resulting environment.
|
||||
*/
|
||||
public class ScriptLoader {
|
||||
private final Context cx;
|
||||
private final ScriptableObject scope;
|
||||
|
||||
public ScriptLoader(String scriptPath) {
|
||||
InputStreamReader inputStreamReader = null;
|
||||
|
||||
this.cx = Context.enter();
|
||||
this.scope = cx.initStandardObjects();
|
||||
try {
|
||||
URL script = ScriptLoader.class.getResource(scriptPath);
|
||||
if (script == null)
|
||||
throw new IOException();
|
||||
InputStream scriptStream = script.openStream();
|
||||
inputStreamReader = new InputStreamReader(scriptStream, FileUtil.UTF8);
|
||||
cx.evaluateReader(scope, inputStreamReader, scriptPath, 1, null);
|
||||
} catch (IOException e) {
|
||||
throw new CatastrophicError("Could not load script " + scriptPath + ".", e);
|
||||
} finally {
|
||||
if (inputStreamReader != null)
|
||||
FileUtil.close(inputStreamReader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a global variable.
|
||||
*/
|
||||
public Object readGlobal(String name) {
|
||||
return scope.get(name, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an object property; the property name may be a path of several individual
|
||||
* names separated by dots.
|
||||
*
|
||||
* @return The value of the property, or {@literal null} if it could not be found.
|
||||
*/
|
||||
public Object readProperty(Object obj, String prop) {
|
||||
Object res = obj;
|
||||
for (String p : prop.split("\\."))
|
||||
res = ScriptableObject.getProperty((ScriptableObject)res, p);
|
||||
if (res == UniqueTag.NOT_FOUND)
|
||||
return null;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an array element.
|
||||
*
|
||||
* @return The value of the element, or {@literal null} if it could not be found.
|
||||
*/
|
||||
public Object readProperty(Object obj, int idx) {
|
||||
Object res = ((ScriptableObject)obj).get(idx, scope);
|
||||
if (res == UniqueTag.NOT_FOUND)
|
||||
return null;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an object property and return its value cast to an integer.
|
||||
*/
|
||||
public Integer readIntProperty(Object obj, String prop) {
|
||||
Object res = readProperty(obj, prop);
|
||||
if (res == null || res == Undefined.instance)
|
||||
return null;
|
||||
return ((Number)res).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an array element and return its value cast to an integer.
|
||||
*/
|
||||
public Integer readIntProperty(Object obj, int idx) {
|
||||
Object res = readProperty(obj, idx);
|
||||
if (res == null || res == Undefined.instance)
|
||||
return null;
|
||||
return ((Number)res).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an object property and return its value cast to a string.
|
||||
*/
|
||||
public String readStringProperty(Object obj, String prop) {
|
||||
Object val = readProperty(obj, prop);
|
||||
if (val == null || val == Undefined.instance)
|
||||
return null;
|
||||
return String.valueOf(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty JavaScript array.
|
||||
*/
|
||||
public NativeArray mkArray() {
|
||||
return (NativeArray)cx.newArray(scope, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JavaScript object.
|
||||
*
|
||||
* @param properties a list of alternating keys and values to populate the object with
|
||||
*/
|
||||
public NativeObject mkObject(Object... properties) {
|
||||
NativeObject obj = new NativeObject();
|
||||
for (int i=0; i+1<properties.length; i += 2)
|
||||
obj.defineProperty((String)properties[i], properties[i+1], 0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a method on an object.
|
||||
*/
|
||||
public Object callMethod(ScriptableObject obj, String method, Object... args) {
|
||||
Function f = (Function)readProperty(obj, method);
|
||||
return f.call(cx, scope, obj, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of a JavaScript constructor function.
|
||||
*/
|
||||
public ScriptableObject construct(Function ctor, Object... args) {
|
||||
return (ScriptableObject)ctor.construct(cx, scope, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty-print an object as JSON.
|
||||
*/
|
||||
public String stringify(Object obj) {
|
||||
return (String) NativeJSON.stringify(cx, scope, obj, null, 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user