mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
888 lines
27 KiB
Plaintext
888 lines
27 KiB
Plaintext
/**
|
|
* Provides queries to pretty-print a JavaScript AST as a graph.
|
|
*
|
|
* By default, this will print the AST for all elements in the database. To change this behavior,
|
|
* extend `PrintAstConfiguration` and override `shouldPrint` to hold for only the elements
|
|
* you wish to view the AST for.
|
|
*/
|
|
|
|
import javascript
|
|
|
|
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
|
|
|
|
/**
|
|
* The query can extend this class to control which elements are printed.
|
|
*/
|
|
class PrintAstConfiguration extends TPrintAstConfiguration {
|
|
/**
|
|
* Gets a textual representation of this `PrintAstConfiguration`.
|
|
*/
|
|
string toString() { result = "PrintAstConfiguration" }
|
|
|
|
/**
|
|
* Controls whether the `Element` should be considered for AST printing.
|
|
* By default it checks whether the `Element` `e` belongs to `Location` `l`.
|
|
*/
|
|
predicate shouldPrint(Locatable e, Location l) { l = e.getLocation() }
|
|
}
|
|
|
|
private predicate shouldPrint(Locatable e, Location l) {
|
|
exists(PrintAstConfiguration config | config.shouldPrint(e, l))
|
|
}
|
|
|
|
/** Holds if the given element does not need to be rendered in the AST, due to being the `TopLevel` for a file. */
|
|
private predicate isNotNeeded(Locatable el) {
|
|
el instanceof TopLevel and
|
|
el.getLocation().getStartLine() = 0 and
|
|
el.getLocation().getStartColumn() = 0
|
|
or
|
|
// relaxing aggressive type inference.
|
|
none()
|
|
}
|
|
|
|
/**
|
|
* Retrieves the canonical QL class(es) for entity `el`
|
|
*/
|
|
private string getQlClass(Locatable el) {
|
|
result = "[" + el.getPrimaryQlClasses() + "] "
|
|
// Alternative implementation -- do not delete. It is useful for QL class discovery.
|
|
// not el.getAPrimaryQlClass() = "???" and result = "[" + getPrimaryQlClasses() + "] " or el.getAPrimaryQlClass() = "???" and result = "??[" + concat(el.getAQlClass(), ",") + "] "
|
|
}
|
|
|
|
/**
|
|
* Printed nodes for different file types.
|
|
*/
|
|
private newtype TPrintAstNode =
|
|
// JavaScript / TypeScript
|
|
TElementNode(AstNode el) { shouldPrint(el, _) and not isNotNeeded(el) } or
|
|
TParametersNode(Function f) { shouldPrint(f, _) and not isNotNeeded(f) } or
|
|
TTypeParametersNode(TypeParameterized f) { shouldPrint(f, _) and not isNotNeeded(f) } or
|
|
TJsxAttributesNode(JsxElement n) { shouldPrint(n, _) and not isNotNeeded(n) } or
|
|
TJsxBodyElementsNode(JsxNode n) { shouldPrint(n, _) and not isNotNeeded(n) } or
|
|
TInvokeArgumentsNode(InvokeExpr n) { shouldPrint(n, _) and not isNotNeeded(n) } or
|
|
TInvokeTypeArgumentsNode(InvokeExpr invk) { shouldPrint(invk, _) and not isNotNeeded(invk) } or
|
|
// JSON
|
|
TJsonNode(JsonValue value) { shouldPrint(value, _) and not isNotNeeded(value) } or
|
|
// YAML
|
|
TYamlNode(YamlNode n) { shouldPrint(n, _) and not isNotNeeded(n) } or
|
|
TYamlMappingNode(YamlMapping mapping, int i) {
|
|
shouldPrint(mapping, _) and not isNotNeeded(mapping) and exists(mapping.getKeyNode(i))
|
|
} or
|
|
// HTML
|
|
THtmlElementNode(HTML::Element e) { shouldPrint(e, _) and not isNotNeeded(e) } or
|
|
THtmlAttributesNodes(HTML::Element e) { shouldPrint(e, _) and not isNotNeeded(e) } or
|
|
THtmlAttributeNode(HTML::Attribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) } or
|
|
THtmlScript(Script script) { shouldPrint(script, _) and not isNotNeeded(script) } or
|
|
THtmlCodeInAttr(CodeInAttribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) } or
|
|
TRegExpTermNode(RegExpTerm term) {
|
|
shouldPrint(term, _) and
|
|
term.isUsedAsRegExp() and
|
|
any(RegExpLiteral lit).getRoot() = term.getRootTerm()
|
|
}
|
|
|
|
/**
|
|
* A node in the output tree.
|
|
*/
|
|
class PrintAstNode extends TPrintAstNode {
|
|
/**
|
|
* Gets a textual representation of this node in the PrintAst output tree.
|
|
*/
|
|
string toString() { none() }
|
|
|
|
/**
|
|
* Gets the child node at index `childIndex`. Child indices must be unique,
|
|
* but need not be contiguous.
|
|
*/
|
|
PrintAstNode getChild(int childIndex) { none() }
|
|
|
|
/**
|
|
* Gets a child of this node.
|
|
*/
|
|
final PrintAstNode getAChild() { result = this.getChild(_) }
|
|
|
|
/**
|
|
* Gets the parent of this node, if any.
|
|
*/
|
|
final PrintAstNode getParent() { result.getAChild() = this }
|
|
|
|
/**
|
|
* Gets the location of this node in the source code.
|
|
*/
|
|
Location getLocation() { none() }
|
|
|
|
/**
|
|
* Gets the value of the property of this node, where the name of the property
|
|
* is `key`.
|
|
*/
|
|
string getProperty(string key) {
|
|
key = "semmle.label" and
|
|
result = this.toString()
|
|
}
|
|
|
|
/**
|
|
* Gets the label for the edge from this node to the specified child. By
|
|
* default, this is just the index of the child, but subclasses can override
|
|
* this.
|
|
*/
|
|
string getChildEdgeLabel(int childIndex) {
|
|
exists(this.getChild(childIndex)) and
|
|
result = childIndex.toString()
|
|
}
|
|
}
|
|
|
|
/** A top-level AST node. */
|
|
class TopLevelPrintAstNode extends PrintAstNode {
|
|
TopLevelPrintAstNode() { not exists(this.getParent()) }
|
|
|
|
private int getOrder() {
|
|
this =
|
|
rank[result](TopLevelPrintAstNode n, Location l |
|
|
l = n.getLocation()
|
|
|
|
|
n
|
|
order by
|
|
l.getFile().getRelativePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
|
l.getEndColumn()
|
|
)
|
|
}
|
|
|
|
override string getProperty(string key) {
|
|
result = super.getProperty(key)
|
|
or
|
|
key = "semmle.order" and
|
|
result = this.getOrder().toString()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Classes for printing JavaScript AST.
|
|
*/
|
|
private module PrintJavaScript {
|
|
/**
|
|
* A print node representing an `ASTNode`.
|
|
*
|
|
* Provides a default implementation that works for some (but not all) ASTNode's.
|
|
* More specific subclasses can override this class to get more specific behavior.
|
|
*
|
|
* The more specific subclasses are mostly used aggregate the children of the `ASTNode`.
|
|
* For example by aggregating all the parameters of a function under a single child node.
|
|
*/
|
|
class ElementNode extends PrintAstNode, TElementNode {
|
|
AstNode element;
|
|
|
|
ElementNode() {
|
|
this = TElementNode(element) and
|
|
not element instanceof Script and // Handled in module `PrintHTML`
|
|
not element instanceof CodeInAttribute // Handled in module `PrintHTML`
|
|
}
|
|
|
|
override string toString() { result = getQlClass(element) + PrettyPrinting::print(element) }
|
|
|
|
override Location getLocation() { result = element.getLocation() }
|
|
|
|
/**
|
|
* Gets the `ASTNode` represented by this node.
|
|
*/
|
|
final AstNode getElement() { result = element }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
exists(AstNode el | result.(ElementNode).getElement() = el |
|
|
el = this.getChildNode(childIndex)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets the `i`th child of `element`.
|
|
* Can be overridden in subclasses to get more specific behavior for `getChild()`.
|
|
*/
|
|
AstNode getChildNode(int i) { result = getLocationSortedChild(element, i) }
|
|
}
|
|
|
|
/** Provides predicates for pretty printing `AstNode`s. */
|
|
private module PrettyPrinting {
|
|
/**
|
|
* Gets a pretty string representation of `element`.
|
|
* Either the result is `ASTNode::toString`, or a custom made string representation of `element`.
|
|
*/
|
|
string print(AstNode element) {
|
|
shouldPrint(element, _) and
|
|
(
|
|
result = element.toString().regexpReplaceAll("(\\\\n|\\\\r|\\\\t| )+", " ") and
|
|
not exists(repr(element))
|
|
or
|
|
result = repr(element)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets a string representing `a`.
|
|
*/
|
|
private string repr(AstNode a) {
|
|
shouldPrint(a, _) and
|
|
(
|
|
exists(DeclStmt decl | decl = a |
|
|
result =
|
|
getDeclarationKeyword(decl) + " " +
|
|
strictconcat(string name, int i |
|
|
name = decl.getDecl(i).getBindingPattern().getName()
|
|
|
|
|
name, ", " order by i
|
|
) + " = ..."
|
|
)
|
|
or
|
|
exists(ObjectExpr obj | obj = a | result = "{" + obj.getProperty(0).getName() + ": ...}")
|
|
or
|
|
result = a.(Property).getName() + ": " + repr(a.(Property).getInit())
|
|
or
|
|
result = a.(Literal).getRawValue()
|
|
or
|
|
result = a.(Identifier).getName()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets "var" or "const" or "let" depending on what type of declaration `decl` is.
|
|
*/
|
|
private string getDeclarationKeyword(DeclStmt decl) {
|
|
decl instanceof VarDeclStmt and result = "var"
|
|
or
|
|
decl instanceof ConstDeclStmt and result = "const"
|
|
or
|
|
decl instanceof LetStmt and result = "let"
|
|
}
|
|
}
|
|
|
|
private AstNode getLocationSortedChild(AstNode parent, int i) {
|
|
result =
|
|
rank[i](AstNode child, int childIndex |
|
|
child = parent.getChild(childIndex)
|
|
|
|
|
child
|
|
order by
|
|
child.getLocation().getStartLine(), child.getLocation().getStartColumn(), childIndex
|
|
)
|
|
}
|
|
|
|
/**
|
|
* A print node for function invocations.
|
|
*
|
|
* The children of this node are split into 3.
|
|
* 1: The callee.
|
|
* 2: An aggregate node for all the arguments.
|
|
* 3: An aggregate node for all the type argument.
|
|
*/
|
|
class InvokeNode extends ElementNode {
|
|
override InvokeExpr element;
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = 0 and result.(ElementNode).getElement() = element.getCallee()
|
|
or
|
|
childIndex = 1 and
|
|
exists(element.getAnArgument()) and
|
|
result.(InvokeArgumentsNode).getInvokeExpr() = element
|
|
or
|
|
childIndex = 2 and
|
|
exists(element.getATypeArgument()) and
|
|
result.(InvokeTypeArgumentsNode).getInvokeExpr() = element
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A print node for regexp literals.
|
|
*
|
|
* The single child of this node is the root `RegExpTerm`.
|
|
*/
|
|
class RegexpNode extends ElementNode {
|
|
override RegExpLiteral element;
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = 0 and
|
|
result.(RegExpTermNode).getTerm() = element.getRoot()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A print node for regexp terms.
|
|
*/
|
|
class RegExpTermNode extends PrintAstNode, TRegExpTermNode {
|
|
RegExpTerm term;
|
|
|
|
RegExpTermNode() { this = TRegExpTermNode(term) }
|
|
|
|
RegExpTerm getTerm() { result = term }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(RegExpTermNode).getTerm() = term.getChild(childIndex)
|
|
}
|
|
|
|
override string toString() { result = getQlClass(term) + term.toString() }
|
|
|
|
override Location getLocation() { result = term.getLocation() }
|
|
}
|
|
|
|
/**
|
|
* An aggregate node representing all the arguments for an function invocation.
|
|
*/
|
|
class InvokeArgumentsNode extends PrintAstNode, TInvokeArgumentsNode {
|
|
InvokeExpr invk;
|
|
|
|
InvokeArgumentsNode() { this = TInvokeArgumentsNode(invk) and exists(invk.getAnArgument()) }
|
|
|
|
override string toString() { result = "(Arguments)" }
|
|
|
|
/**
|
|
* Gets the `InvokeExpr` for which this node represents the arguments.
|
|
*/
|
|
InvokeExpr getInvokeExpr() { result = invk }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(ElementNode).getElement() = invk.getArgument(childIndex)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An aggregate node representing all the type-arguments for an function invocation.
|
|
*/
|
|
class InvokeTypeArgumentsNode extends PrintAstNode, TInvokeTypeArgumentsNode {
|
|
InvokeExpr invk;
|
|
|
|
InvokeTypeArgumentsNode() {
|
|
this = TInvokeTypeArgumentsNode(invk) and exists(invk.getATypeArgument())
|
|
}
|
|
|
|
override string toString() { result = "(TypeArguments)" }
|
|
|
|
/**
|
|
* Gets the `InvokeExpr` for which this node represents the type-arguments.
|
|
*/
|
|
InvokeExpr getInvokeExpr() { result = invk }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(ElementNode).getElement() = invk.getTypeArgument(childIndex)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A print node for JSX nodes.
|
|
*
|
|
* The children of this node are split into 3.
|
|
* 1: The name of the JSX node (for example `Name` in `<Name href={foo} />`).
|
|
* 2: An aggregate node for all the attributes (for example `href={foo}` in `<Name href={foo} />`).
|
|
* 3: An aggregate node for all the body element (for example `foo` in `<span>foo</span>`).
|
|
*/
|
|
class JsxNodeNode extends ElementNode {
|
|
override JsxNode element;
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = 0 and result.(ElementNode).getElement() = element.(JsxElement).getNameExpr()
|
|
or
|
|
childIndex = 1 and
|
|
exists(element.getABodyElement()) and
|
|
result.(JsxBodyElementsNode).getJsxNode() = element
|
|
or
|
|
childIndex = 2 and
|
|
exists(element.(JsxElement).getAttribute(_)) and
|
|
result.(JsxAttributesNode).getJsxElement() = element
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for JsxNodeNode */
|
|
deprecated class JSXNodeNode = JsxNodeNode;
|
|
|
|
/**
|
|
* An aggregate node representing all the attributes in a `JSXNode`.
|
|
*/
|
|
class JsxAttributesNode extends PrintAstNode, TJsxAttributesNode {
|
|
JsxElement n;
|
|
|
|
JsxAttributesNode() { this = TJsxAttributesNode(n) and exists(n.getAttribute(_)) }
|
|
|
|
override string toString() { result = "(Attributes)" }
|
|
|
|
/**
|
|
* Gets the `JSXElement` for which this node represents the attributes.
|
|
*/
|
|
JsxElement getJsxElement() { result = n }
|
|
|
|
/** DEPRECATED: Alias for getJsxElement */
|
|
deprecated JSXElement getJSXElement() { result = this.getJsxElement() }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(ElementNode).getElement() = n.getAttribute(childIndex)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for JsxAttributesNode */
|
|
deprecated class JSXAttributesNode = JsxAttributesNode;
|
|
|
|
/**
|
|
* An aggregate node representing all the body elements in a `JSXNode`.
|
|
*/
|
|
class JsxBodyElementsNode extends PrintAstNode, TJsxBodyElementsNode {
|
|
JsxNode n;
|
|
|
|
JsxBodyElementsNode() { this = TJsxBodyElementsNode(n) and exists(n.getBodyElement(_)) }
|
|
|
|
override string toString() { result = "(Body)" }
|
|
|
|
/**
|
|
* Gets the `JSXNode` for which this node represents the body elements.
|
|
*/
|
|
JsxNode getJsxNode() { result = n }
|
|
|
|
/** DEPRECATED: Alias for getJsxNode */
|
|
deprecated JSXNode getJSXNode() { result = this.getJsxNode() }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(ElementNode).getElement() = n.getBodyElement(childIndex)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for JsxBodyElementsNode */
|
|
deprecated class JSXBodyElementsNode = JsxBodyElementsNode;
|
|
|
|
/**
|
|
* A node representing any `ASTNode` that has type-parameters.
|
|
*
|
|
* The first child of this node is an aggregate node representing all the type-parameters.
|
|
*/
|
|
class TypeParameterizedNode extends ElementNode {
|
|
override TypeParameterized element;
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = -100 and result.(TypeParametersNode).getTypeParameterized() = element
|
|
or
|
|
result = super.getChild(childIndex) and
|
|
not result.(ElementNode).getElement() = element.getATypeParameter()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A `PrintAstNode` for functions.
|
|
*
|
|
* The children of this node is split into 6:
|
|
* - The identifier (name) of the function.
|
|
* - An aggregate node for all the parameters of the function.
|
|
* - An aggregate node for all the type parameters of the function.
|
|
* - The `this` type annotation.
|
|
* - The return type annotation.
|
|
* - The body
|
|
*/
|
|
class FunctionNode extends TypeParameterizedNode {
|
|
override Function element;
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = 0 and result.(ElementNode).getElement() = element.getIdentifier()
|
|
or
|
|
childIndex = 1 and
|
|
result.(ParametersNode).getFunction() = element and
|
|
exists(element.getAParameter())
|
|
or
|
|
childIndex = 2 and
|
|
result.(TypeParametersNode).getTypeParameterized() = element and
|
|
exists(element.getATypeParameter())
|
|
or
|
|
childIndex = 3 and result.(ElementNode).getElement() = element.getThisTypeAnnotation()
|
|
or
|
|
childIndex = 4 and result.(ElementNode).getElement() = element.getReturnTypeAnnotation()
|
|
or
|
|
childIndex = 5 and result.(ElementNode).getElement() = element.getBody()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A `PrintAstNode` for parameters.
|
|
*
|
|
* This node puts the type-annotation and default value of a parameter as children of the parameter itself.
|
|
* Instead of the default behavior (from `ElementNode`) where they would be children of the function.
|
|
*/
|
|
class ParameterNode extends ElementNode {
|
|
override Parameter element;
|
|
|
|
override AstNode getChildNode(int childIndex) {
|
|
childIndex = 0 and result = element.getTypeAnnotation()
|
|
or
|
|
childIndex = 1 and result = element.getDefault()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An aggregate node representing all the parameters in a function.
|
|
*/
|
|
class ParametersNode extends PrintAstNode, TParametersNode {
|
|
Function f;
|
|
|
|
ParametersNode() { this = TParametersNode(f) and exists(f.getAParameter()) }
|
|
|
|
override string toString() { result = "(Parameters)" }
|
|
|
|
/**
|
|
* Gets the `Function` for which this node represents the parameters.
|
|
*/
|
|
Function getFunction() { result = f }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(ElementNode).getElement() = f.getParameter(childIndex)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An aggregate node representing all the type parameters in a function.
|
|
*/
|
|
class TypeParametersNode extends PrintAstNode, TTypeParametersNode {
|
|
TypeParameterized f;
|
|
|
|
TypeParametersNode() { this = TTypeParametersNode(f) and exists(f.getATypeParameter()) }
|
|
|
|
override string toString() { result = "(TypeParameters)" }
|
|
|
|
/**
|
|
* Gets the `Function` for which this node represents the type-parameters.
|
|
*/
|
|
TypeParameterized getTypeParameterized() { result = f }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(ElementNode).getElement() = f.getTypeParameter(childIndex)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Classes for printing JSON AST.
|
|
*/
|
|
private module PrintJson {
|
|
/**
|
|
* A print node representing a JSON value in a .json file.
|
|
*/
|
|
class JsonNode extends PrintAstNode, TJsonNode {
|
|
JsonValue value;
|
|
|
|
JsonNode() { this = TJsonNode(value) }
|
|
|
|
override string toString() { result = getQlClass(value) + PrettyPrinting::print(value) }
|
|
|
|
override Location getLocation() { result = value.getLocation() }
|
|
|
|
/**
|
|
* Gets the `JSONValue` represented by this node.
|
|
*/
|
|
final JsonValue getValue() { result = value }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
exists(JsonValue child | result.(JsonNode).getValue() = child |
|
|
child = value.getChild(childIndex)
|
|
)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for JsonNode */
|
|
deprecated class JSONNode = JsonNode;
|
|
|
|
/** Provied predicates for pretty printing JSON. */
|
|
private module PrettyPrinting {
|
|
/**
|
|
* Gets a string representation of `n`.
|
|
* Either using the default `JSONValue::toString`, or a custom printing of the JSON value.
|
|
*/
|
|
string print(JsonValue n) {
|
|
shouldPrint(n, _) and
|
|
(
|
|
result = n.toString().regexpReplaceAll("(\\\\n|\\\\r|\\\\t| )+", " ") and
|
|
not exists(repr(n))
|
|
or
|
|
result = repr(n)
|
|
)
|
|
}
|
|
|
|
/** Gets a string representing `n`. */
|
|
private string repr(JsonValue n) {
|
|
shouldPrint(n, _) and
|
|
(
|
|
exists(JsonObject obj, string name, JsonValue prop | obj = n |
|
|
prop = obj.getPropValue(name) and
|
|
prop = obj.getChild(0) and
|
|
result = "{" + name + ": ...}"
|
|
)
|
|
or
|
|
n instanceof JsonObject and not exists(n.getChild(_)) and result = "{}"
|
|
or
|
|
result = n.(JsonPrimitiveValue).getRawValue()
|
|
or
|
|
exists(JsonArray arr | arr = n |
|
|
result = "[]" and not exists(arr.getChild(_))
|
|
or
|
|
result = "[" + repr(arr.getChild(0)) + "]" and not exists(arr.getChild(1))
|
|
or
|
|
result = "[" + repr(arr.getChild(0)) + ", ...]" and exists(arr.getChild(1))
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Classes for printing YAML AST.
|
|
*/
|
|
module PrintYaml {
|
|
/**
|
|
* A print node representing a YAML value in a .yml file.
|
|
*/
|
|
class YamlNodeNode extends PrintAstNode, TYamlNode {
|
|
YamlNode node;
|
|
|
|
YamlNodeNode() { this = TYamlNode(node) }
|
|
|
|
override string toString() { result = getQlClass(node) + node.toString() }
|
|
|
|
override Location getLocation() { result = node.getLocation() }
|
|
|
|
/**
|
|
* Gets the `YAMLNode` represented by this node.
|
|
*/
|
|
final YamlNode getValue() { result = node }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
exists(YamlNode child | result.(YamlNodeNode).getValue() = child |
|
|
child = node.getChildNode(childIndex)
|
|
)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for YamlNodeNode */
|
|
deprecated class YAMLNodeNode = YamlNodeNode;
|
|
|
|
/**
|
|
* A print node representing a `YAMLMapping`.
|
|
*
|
|
* Each child of this node aggregates the key and value of a mapping.
|
|
*/
|
|
class YamlMappingNode extends YamlNodeNode {
|
|
override YamlMapping node;
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
exists(YamlMappingMapNode map | map = result | map.maps(node, childIndex))
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for YamlMappingNode */
|
|
deprecated class YAMLMappingNode = YamlMappingNode;
|
|
|
|
/**
|
|
* A print node representing the `i`th mapping in `mapping`.
|
|
*/
|
|
class YamlMappingMapNode extends PrintAstNode, TYamlMappingNode {
|
|
YamlMapping mapping;
|
|
int i;
|
|
|
|
YamlMappingMapNode() { this = TYamlMappingNode(mapping, i) }
|
|
|
|
override string toString() {
|
|
result = "(Mapping " + i + ")" and not exists(mapping.getKeyNode(i).(YamlScalar).getValue())
|
|
or
|
|
result = "(Mapping " + i + ") " + mapping.getKeyNode(i).(YamlScalar).getValue() + ":"
|
|
}
|
|
|
|
/**
|
|
* Holds if this print node represents the `index`th mapping of `m`.
|
|
*/
|
|
predicate maps(YamlMapping m, int index) {
|
|
m = mapping and
|
|
index = i
|
|
}
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = 0 and result.(YamlNodeNode).getValue() = mapping.getKeyNode(i)
|
|
or
|
|
childIndex = 1 and result.(YamlNodeNode).getValue() = mapping.getValueNode(i)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for YamlMappingMapNode */
|
|
deprecated class YAMLMappingMapNode = YamlMappingMapNode;
|
|
}
|
|
|
|
/** DEPRECATED: Alias for PrintYaml */
|
|
deprecated module PrintYAML = PrintYaml;
|
|
|
|
/**
|
|
* Classes for printing HTML AST.
|
|
*/
|
|
module PrintHtml {
|
|
/**
|
|
* A print node representing an HTML node in a .html file.
|
|
*/
|
|
class HtmlElementNode extends PrintAstNode, THtmlElementNode {
|
|
HTML::Element element;
|
|
|
|
HtmlElementNode() { this = THtmlElementNode(element) }
|
|
|
|
override string toString() { result = getQlClass(element) + "<" + element.getName() + " ..." }
|
|
|
|
override Location getLocation() { result = element.getLocation() }
|
|
|
|
/**
|
|
* Gets the `HTML::Element` represented by this node.
|
|
*/
|
|
final HTML::Element getElement() { result = element }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = -1 and result.(HtmlAttributesNodes).getElement() = element
|
|
or
|
|
exists(HTML::Element child | result.(HtmlElementNode).getElement() = child |
|
|
child = element.getChild(childIndex)
|
|
)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for HtmlElementNode */
|
|
deprecated class HTMLElementNode = HtmlElementNode;
|
|
|
|
/**
|
|
* A print node representing an HTML node in a .html file.
|
|
*/
|
|
class HtmlScriptElementNode extends HtmlElementNode {
|
|
override HTML::ScriptElement element;
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = -200 and result.(HtmlScript).getScript() = element.getScript()
|
|
or
|
|
result = super.getChild(childIndex)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for HtmlScriptElementNode */
|
|
deprecated class HTMLScriptElementNode = HtmlScriptElementNode;
|
|
|
|
/**
|
|
* A print node representing the code inside a `<script>` element.
|
|
*/
|
|
class HtmlScript extends PrintAstNode, THtmlScript {
|
|
Script script;
|
|
|
|
HtmlScript() {
|
|
this = THtmlScript(script) and
|
|
any(HtmlScriptElementNode se).getElement().(HTML::ScriptElement).getScript() = script
|
|
}
|
|
|
|
override string toString() { result = "(Script)" }
|
|
|
|
override Location getLocation() { result = script.getLocation() }
|
|
|
|
/**
|
|
* Gets the `Script` for which this node represents code.
|
|
*/
|
|
Script getScript() { result = script }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(PrintJavaScript::ElementNode).getElement() = script.getChild(childIndex)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for HtmlScript */
|
|
deprecated class HTMLScript = HtmlScript;
|
|
|
|
/**
|
|
* A print node representing the code inside an attribute.
|
|
*/
|
|
class HtmlCodeInAttr extends PrintAstNode, THtmlCodeInAttr {
|
|
CodeInAttribute attr;
|
|
|
|
HtmlCodeInAttr() {
|
|
this = THtmlCodeInAttr(attr) and
|
|
any(HtmlAttributeNode an).getAttribute().getCodeInAttribute() = attr
|
|
}
|
|
|
|
override string toString() { result = "(Script)" }
|
|
|
|
override Location getLocation() { result = attr.getLocation() }
|
|
|
|
/**
|
|
* Gets the `CodeInAttribute` for which this node represents code.
|
|
*/
|
|
CodeInAttribute getCode() { result = attr }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(PrintJavaScript::ElementNode).getElement() = attr.getChild(childIndex)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for HtmlCodeInAttr */
|
|
deprecated class HTMLCodeInAttr = HtmlCodeInAttr;
|
|
|
|
/**
|
|
* An aggregate node representing all the attributes of an HTMLElement.
|
|
*/
|
|
class HtmlAttributesNodes extends PrintAstNode, THtmlAttributesNodes {
|
|
HTML::Element element;
|
|
|
|
HtmlAttributesNodes() {
|
|
this = THtmlAttributesNodes(element) and exists(element.getAttribute(_))
|
|
}
|
|
|
|
override string toString() { result = "(Attributes)" }
|
|
|
|
/**
|
|
* Gets the `HTMLElement` for which this node represents the attributes.
|
|
*/
|
|
HTML::Element getElement() { result = element }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
result.(HtmlAttributeNode).getAttribute() = element.getAttribute(childIndex)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for HtmlAttributesNodes */
|
|
deprecated class HTMLAttributesNodes = HtmlAttributesNodes;
|
|
|
|
/**
|
|
* A print node representing an HTML attribute in a .html file.
|
|
*/
|
|
class HtmlAttributeNode extends PrintAstNode, THtmlAttributeNode {
|
|
HTML::Attribute attr;
|
|
|
|
HtmlAttributeNode() { this = THtmlAttributeNode(attr) }
|
|
|
|
override string toString() { result = getQlClass(attr) + attr.toString() }
|
|
|
|
override Location getLocation() { result = attr.getLocation() }
|
|
|
|
/**
|
|
* Gets the `HTMLAttribute` represented by this node.
|
|
*/
|
|
final HTML::Attribute getAttribute() { result = attr }
|
|
|
|
override PrintAstNode getChild(int childIndex) {
|
|
childIndex = 0 and result.(HtmlCodeInAttr).getCode() = attr.getCodeInAttribute()
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for HtmlAttributeNode */
|
|
deprecated class HTMLAttributeNode = HtmlAttributeNode;
|
|
}
|
|
|
|
/** DEPRECATED: Alias for PrintHtml */
|
|
deprecated module PrintHTML = PrintHtml;
|
|
|
|
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
|
|
query predicate nodes(PrintAstNode node, string key, string value) { value = node.getProperty(key) }
|
|
|
|
/**
|
|
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
|
|
* given `value`.
|
|
*/
|
|
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
|
|
exists(int childIndex |
|
|
target = source.getChild(childIndex) and
|
|
(
|
|
key = "semmle.label" and value = source.getChildEdgeLabel(childIndex)
|
|
or
|
|
key = "semmle.order" and value = childIndex.toString()
|
|
)
|
|
)
|
|
}
|
|
|
|
/** Holds if property `key` of the graph has the given `value`. */
|
|
query predicate graphProperties(string key, string value) {
|
|
key = "semmle.graphKind" and value = "tree"
|
|
}
|