mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
JS: Add DataFlow::Node.getLocation
This commit is contained in:
@@ -255,7 +255,6 @@
|
|||||||
"cpp/ql/lib/semmle/code/cpp/XML.qll",
|
"cpp/ql/lib/semmle/code/cpp/XML.qll",
|
||||||
"csharp/ql/lib/semmle/code/csharp/XML.qll",
|
"csharp/ql/lib/semmle/code/csharp/XML.qll",
|
||||||
"java/ql/lib/semmle/code/xml/XML.qll",
|
"java/ql/lib/semmle/code/xml/XML.qll",
|
||||||
"javascript/ql/lib/semmle/javascript/XML.qll",
|
|
||||||
"python/ql/lib/semmle/python/xml/XML.qll"
|
"python/ql/lib/semmle/python/xml/XML.qll"
|
||||||
],
|
],
|
||||||
"DuplicationProblems.inc.qhelp": [
|
"DuplicationProblems.inc.qhelp": [
|
||||||
@@ -372,4 +371,4 @@
|
|||||||
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
||||||
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -23,31 +23,27 @@ private import semmle.javascript.internal.CachedStages
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class AstNode extends @ast_node, NodeInStmtContainer {
|
class AstNode extends @ast_node, NodeInStmtContainer {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
override File getFile() {
|
override File getFile() {
|
||||||
result = this.getLocation().getFile() // Specialized for performance reasons
|
result = this.getLocation().getFile() // Specialized for performance reasons
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the first token belonging to this element. */
|
/** Gets the first token belonging to this element. */
|
||||||
Token getFirstToken() {
|
Token getFirstToken() {
|
||||||
exists(Location l1, Location l2 |
|
exists(DbLocation l1, DbLocation l2, string filepath, int startline, int startcolumn |
|
||||||
l1 = this.getLocation() and
|
l1 = this.getLocation() and
|
||||||
l2 = result.getLocation() and
|
l2 = result.getLocation() and
|
||||||
l1.getFile() = l2.getFile() and
|
l1.hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||||
l1.getStartLine() = l2.getStartLine() and
|
l2.hasLocationInfo(filepath, startline, startcolumn, _, _)
|
||||||
l1.getStartColumn() = l2.getStartColumn()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the last token belonging to this element. */
|
/** Gets the last token belonging to this element. */
|
||||||
Token getLastToken() {
|
Token getLastToken() {
|
||||||
exists(Location l1, Location l2 |
|
exists(DbLocation l1, DbLocation l2, string filepath, int endline, int endcolumn |
|
||||||
l1 = this.getLocation() and
|
l1 = this.getLocation() and
|
||||||
l2 = result.getLocation() and
|
l2 = result.getLocation() and
|
||||||
l1.getFile() = l2.getFile() and
|
l1.hasLocationInfo(filepath, _, _, endline, endcolumn) and
|
||||||
l1.getEndLine() = l2.getEndLine() and
|
l2.hasLocationInfo(filepath, _, _, endline, endcolumn)
|
||||||
l1.getEndColumn() = l2.getEndColumn()
|
|
||||||
) and
|
) and
|
||||||
// exclude empty EOF token
|
// exclude empty EOF token
|
||||||
not result instanceof EOFToken
|
not result instanceof EOFToken
|
||||||
|
|||||||
@@ -356,9 +356,7 @@ class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer {
|
|||||||
* A synthetic CFG node that does not correspond to a statement or expression;
|
* A synthetic CFG node that does not correspond to a statement or expression;
|
||||||
* examples include guard nodes and entry/exit nodes.
|
* examples include guard nodes and entry/exit nodes.
|
||||||
*/
|
*/
|
||||||
class SyntheticControlFlowNode extends @synthetic_cfg_node, ControlFlowNode {
|
class SyntheticControlFlowNode extends @synthetic_cfg_node, ControlFlowNode { }
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A synthetic CFG node marking the entry point of a function or toplevel script. */
|
/** A synthetic CFG node marking the entry point of a function or toplevel script. */
|
||||||
class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node {
|
class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node {
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import javascript
|
|||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
class Comment extends @comment, Locatable {
|
class Comment extends @comment, Locatable {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
/** Gets the toplevel element this comment belongs to. */
|
/** Gets the toplevel element this comment belongs to. */
|
||||||
TopLevel getTopLevel() { comments(this, _, result, _, _) }
|
TopLevel getTopLevel() { comments(this, _, result, _, _) }
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import javascript
|
|||||||
|
|
||||||
/** An error encountered during extraction. */
|
/** An error encountered during extraction. */
|
||||||
abstract class Error extends Locatable {
|
abstract class Error extends Locatable {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
/** Gets the message associated with this error. */
|
/** Gets the message associated with this error. */
|
||||||
abstract string getMessage();
|
abstract string getMessage();
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import javascript
|
import javascript
|
||||||
private import NodeModuleResolutionImpl
|
private import NodeModuleResolutionImpl
|
||||||
private import codeql.util.FileSystem
|
private import codeql.util.FileSystem
|
||||||
|
private import internal.Locations
|
||||||
|
|
||||||
private module FsInput implements InputSig {
|
private module FsInput implements InputSig {
|
||||||
abstract class ContainerBase extends @container {
|
abstract class ContainerBase extends @container {
|
||||||
@@ -83,7 +84,7 @@ class File extends Container, Impl::File {
|
|||||||
*
|
*
|
||||||
* Note that files have special locations starting and ending at line zero, column zero.
|
* Note that files have special locations starting and ending at line zero, column zero.
|
||||||
*/
|
*/
|
||||||
Location getLocation() { hasLocation(this, result) }
|
DbLocation getLocation() { result = getLocatableLocation(this) }
|
||||||
|
|
||||||
/** Gets the number of lines in this file. */
|
/** Gets the number of lines in this file. */
|
||||||
int getNumberOfLines() { result = sum(int loc | numlines(this, loc, _, _) | loc) }
|
int getNumberOfLines() { result = sum(int loc | numlines(this, loc, _, _) | loc) }
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ module HTML {
|
|||||||
class Element extends Locatable, @xmlelement {
|
class Element extends Locatable, @xmlelement {
|
||||||
Element() { exists(FileContainingHtml f | xmlElements(this, _, _, _, f)) }
|
Element() { exists(FileContainingHtml f | xmlElements(this, _, _, _, f)) }
|
||||||
|
|
||||||
override Location getLocation() { xmllocations(this, result) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of this HTML element.
|
* Gets the name of this HTML element.
|
||||||
*
|
*
|
||||||
@@ -122,8 +120,6 @@ module HTML {
|
|||||||
class Attribute extends Locatable, @xmlattribute {
|
class Attribute extends Locatable, @xmlattribute {
|
||||||
Attribute() { exists(FileContainingHtml f | xmlAttrs(this, _, _, _, _, f)) }
|
Attribute() { exists(FileContainingHtml f | xmlAttrs(this, _, _, _, _, f)) }
|
||||||
|
|
||||||
override Location getLocation() { xmllocations(this, result) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the inline script of this attribute, if any.
|
* Gets the inline script of this attribute, if any.
|
||||||
*/
|
*/
|
||||||
@@ -326,8 +322,6 @@ module HTML {
|
|||||||
* Holds if this text node is inside a `CDATA` tag.
|
* Holds if this text node is inside a `CDATA` tag.
|
||||||
*/
|
*/
|
||||||
predicate isCData() { xmlChars(this, _, _, _, 1, _) }
|
predicate isCData() { xmlChars(this, _, _, _, 1, _) }
|
||||||
|
|
||||||
override Location getLocation() { xmllocations(this, result) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -349,7 +343,5 @@ module HTML {
|
|||||||
string getText() { result = this.toString().regexpCapture("(?s)<!--(.*)-->", 1) }
|
string getText() { result = this.toString().regexpCapture("(?s)<!--(.*)-->", 1) }
|
||||||
|
|
||||||
override string toString() { xmlComments(this, result, _, _) }
|
override string toString() { xmlComments(this, result, _, _) }
|
||||||
|
|
||||||
override Location getLocation() { xmllocations(this, result) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ private import semmle.javascript.internal.CachedStages
|
|||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
class JSDoc extends @jsdoc, Locatable {
|
class JSDoc extends @jsdoc, Locatable {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
/** Gets the description text of this JSDoc comment. */
|
/** Gets the description text of this JSDoc comment. */
|
||||||
string getDescription() { jsdoc(this, result, _) }
|
string getDescription() { jsdoc(this, result, _) }
|
||||||
|
|
||||||
@@ -75,8 +73,6 @@ abstract class Documentable extends AstNode {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class JSDocTypeExprParent extends @jsdoc_type_expr_parent, Locatable {
|
class JSDocTypeExprParent extends @jsdoc_type_expr_parent, Locatable {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
/** Gets the JSDoc comment to which this element belongs. */
|
/** Gets the JSDoc comment to which this element belongs. */
|
||||||
JSDoc getJSDocComment() { none() }
|
JSDoc getJSDocComment() { none() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
private import semmle.javascript.internal.Locations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JSON-encoded value, which may be a primitive value, an array or an object.
|
* A JSON-encoded value, which may be a primitive value, an array or an object.
|
||||||
@@ -20,8 +21,6 @@ import javascript
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class JsonValue extends @json_value, Locatable {
|
class JsonValue extends @json_value, Locatable {
|
||||||
override Location getLocation() { json_locations(this, result) }
|
|
||||||
|
|
||||||
/** Gets the parent value to which this value belongs, if any. */
|
/** Gets the parent value to which this value belongs, if any. */
|
||||||
JsonValue getParent() { json(this, _, result, _, _) }
|
JsonValue getParent() { json(this, _, result, _, _) }
|
||||||
|
|
||||||
@@ -34,12 +33,7 @@ class JsonValue extends @json_value, Locatable {
|
|||||||
override string toString() { json(this, _, _, _, result) }
|
override string toString() { json(this, _, _, _, result) }
|
||||||
|
|
||||||
/** Gets the JSON file containing this value. */
|
/** Gets the JSON file containing this value. */
|
||||||
File getJsonFile() {
|
File getJsonFile() { result = getLocatableLocation(this).getFile() }
|
||||||
exists(Location loc |
|
|
||||||
json_locations(this, loc) and
|
|
||||||
result = loc.getFile()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** If this is an object, gets the value of property `name`. */
|
/** If this is an object, gets the value of property `name`. */
|
||||||
JsonValue getPropValue(string name) { json_properties(this, name, result) }
|
JsonValue getPropValue(string name) { json_properties(this, name, result) }
|
||||||
@@ -172,7 +166,5 @@ class JsonObject extends @json_object, JsonValue {
|
|||||||
* An error reported by the JSON parser.
|
* An error reported by the JSON parser.
|
||||||
*/
|
*/
|
||||||
class JsonParseError extends @json_parse_error, Error {
|
class JsonParseError extends @json_parse_error, Error {
|
||||||
override Location getLocation() { json_locations(this, result) }
|
|
||||||
|
|
||||||
override string getMessage() { json_errors(this, result) }
|
override string getMessage() { json_errors(this, result) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import javascript
|
|||||||
* extracted with the `--extract-program-text` flag.
|
* extracted with the `--extract-program-text` flag.
|
||||||
*/
|
*/
|
||||||
class Line extends @line, Locatable {
|
class Line extends @line, Locatable {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
/** Gets the toplevel element this line belongs to. */
|
/** Gets the toplevel element this line belongs to. */
|
||||||
TopLevel getTopLevel() { lines(this, result, _, _) }
|
TopLevel getTopLevel() { lines(this, result, _, _) }
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,41 @@
|
|||||||
/** Provides classes for working with locations and program elements that have locations. */
|
/** Provides classes for working with locations and program elements that have locations. */
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
private import internal.Locations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A location as given by a file, a start line, a start column,
|
* A location as given by a file, a start line, a start column,
|
||||||
* an end line, and an end column.
|
* an end line, and an end column.
|
||||||
*
|
*
|
||||||
|
* This class is restricted to locations created by the extractor.
|
||||||
|
*
|
||||||
* For more information about locations see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
* For more information about locations see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
class Location extends @location {
|
class DbLocation extends TDbLocation {
|
||||||
/** Gets the file for this location. */
|
/** Gets the file for this location. */
|
||||||
File getFile() { locations_default(this, result, _, _, _, _) }
|
File getFile() { dbLocationInfo(this, result, _, _, _, _) }
|
||||||
|
|
||||||
/** Gets the 1-based line number (inclusive) where this location starts. */
|
/** Gets the 1-based line number (inclusive) where this location starts. */
|
||||||
int getStartLine() { locations_default(this, _, result, _, _, _) }
|
int getStartLine() { dbLocationInfo(this, _, result, _, _, _) }
|
||||||
|
|
||||||
/** Gets the 1-based column number (inclusive) where this location starts. */
|
/** Gets the 1-based column number (inclusive) where this location starts. */
|
||||||
int getStartColumn() { locations_default(this, _, _, result, _, _) }
|
int getStartColumn() { dbLocationInfo(this, _, _, result, _, _) }
|
||||||
|
|
||||||
/** Gets the 1-based line number (inclusive) where this location ends. */
|
/** Gets the 1-based line number (inclusive) where this location ends. */
|
||||||
int getEndLine() { locations_default(this, _, _, _, result, _) }
|
int getEndLine() { dbLocationInfo(this, _, _, _, result, _) }
|
||||||
|
|
||||||
/** Gets the 1-based column number (inclusive) where this location ends. */
|
/** Gets the 1-based column number (inclusive) where this location ends. */
|
||||||
int getEndColumn() { locations_default(this, _, _, _, _, result) }
|
int getEndColumn() { dbLocationInfo(this, _, _, _, _, result) }
|
||||||
|
|
||||||
/** Gets the number of lines covered by this location. */
|
/** Gets the number of lines covered by this location. */
|
||||||
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
|
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
|
||||||
|
|
||||||
/** Holds if this location starts before location `that`. */
|
/** Holds if this location starts before location `that`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate startsBefore(Location that) {
|
predicate startsBefore(DbLocation that) {
|
||||||
exists(File f, int sl1, int sc1, int sl2, int sc2 |
|
exists(File f, int sl1, int sc1, int sl2, int sc2 |
|
||||||
locations_default(this, f, sl1, sc1, _, _) and
|
dbLocationInfo(this, f, sl1, sc1, _, _) and
|
||||||
locations_default(that, f, sl2, sc2, _, _)
|
dbLocationInfo(that, f, sl2, sc2, _, _)
|
||||||
|
|
|
|
||||||
sl1 < sl2
|
sl1 < sl2
|
||||||
or
|
or
|
||||||
@@ -42,10 +45,10 @@ class Location extends @location {
|
|||||||
|
|
||||||
/** Holds if this location ends after location `that`. */
|
/** Holds if this location ends after location `that`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate endsAfter(Location that) {
|
predicate endsAfter(DbLocation that) {
|
||||||
exists(File f, int el1, int ec1, int el2, int ec2 |
|
exists(File f, int el1, int ec1, int el2, int ec2 |
|
||||||
locations_default(this, f, _, _, el1, ec1) and
|
dbLocationInfo(this, f, _, _, el1, ec1) and
|
||||||
locations_default(that, f, _, _, el2, ec2)
|
dbLocationInfo(that, f, _, _, el2, ec2)
|
||||||
|
|
|
|
||||||
el1 > el2
|
el1 > el2
|
||||||
or
|
or
|
||||||
@@ -57,10 +60,10 @@ class Location extends @location {
|
|||||||
* Holds if this location contains location `that`, meaning that it starts
|
* Holds if this location contains location `that`, meaning that it starts
|
||||||
* before and ends after it.
|
* before and ends after it.
|
||||||
*/
|
*/
|
||||||
predicate contains(Location that) { this.startsBefore(that) and this.endsAfter(that) }
|
predicate contains(DbLocation that) { this.startsBefore(that) and this.endsAfter(that) }
|
||||||
|
|
||||||
/** Holds if this location is empty. */
|
/** Holds if this location is empty. */
|
||||||
predicate isEmpty() { exists(int l, int c | locations_default(this, _, l, c, l, c - 1)) }
|
predicate isEmpty() { exists(int l, int c | dbLocationInfo(this, _, l, c, l, c - 1)) }
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
string toString() { result = this.getFile().getBaseName() + ":" + this.getStartLine().toString() }
|
string toString() { result = this.getFile().getBaseName() + ":" + this.getStartLine().toString() }
|
||||||
@@ -76,22 +79,21 @@ class Location extends @location {
|
|||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
) {
|
) {
|
||||||
exists(File f |
|
exists(File f |
|
||||||
locations_default(this, f, startline, startcolumn, endline, endcolumn) and
|
dbLocationInfo(this, f, startline, startcolumn, endline, endcolumn) and
|
||||||
filepath = f.getAbsolutePath()
|
filepath = f.getAbsolutePath()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class Location = LocationImpl;
|
||||||
|
|
||||||
/** A program element with a location. */
|
/** A program element with a location. */
|
||||||
class Locatable extends @locatable {
|
class Locatable extends @locatable {
|
||||||
/** Gets the file this program element comes from. */
|
/** Gets the file this program element comes from. */
|
||||||
File getFile() { result = this.getLocation().getFile() }
|
File getFile() { result = this.getLocation().getFile() }
|
||||||
|
|
||||||
/** Gets this element's location. */
|
/** Gets this element's location. */
|
||||||
Location getLocation() {
|
final DbLocation getLocation() { result = getLocatableLocation(this) }
|
||||||
// overridden by subclasses
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the line on which this element starts.
|
* Gets the line on which this element starts.
|
||||||
@@ -142,16 +144,3 @@ class Locatable extends @locatable {
|
|||||||
*/
|
*/
|
||||||
string getAPrimaryQlClass() { result = "???" }
|
string getAPrimaryQlClass() { result = "???" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A `File`, considered as a `Locatable`.
|
|
||||||
*
|
|
||||||
* For reasons of backwards compatibility, @file is a subtype of @locatable. This class exists to
|
|
||||||
* provide an override of `Locatable.getLocation()` for @files, since it would otherwise default
|
|
||||||
* to `none()`, which is unhelpful.
|
|
||||||
*/
|
|
||||||
private class FileLocatable extends File, Locatable {
|
|
||||||
override Location getLocation() { result = File.super.getLocation() }
|
|
||||||
|
|
||||||
override string toString() { result = File.super.toString() }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ class RegExpParent extends Locatable, @regexpparent { }
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class RegExpTerm extends Locatable, @regexpterm {
|
class RegExpTerm extends Locatable, @regexpterm {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
/** Gets the `i`th child term of this term. */
|
/** Gets the `i`th child term of this term. */
|
||||||
RegExpTerm getChild(int i) { regexpterm(result, _, this, i, _) }
|
RegExpTerm getChild(int i) { regexpterm(result, _, this, i, _) }
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class FirstLineOf extends Locatable {
|
|||||||
then endcolumn = xc
|
then endcolumn = xc
|
||||||
else
|
else
|
||||||
endcolumn =
|
endcolumn =
|
||||||
max(int c | any(Location l).hasLocationInfo(filepath, startline, _, startline, c))
|
max(int c | any(DbLocation l).hasLocationInfo(filepath, startline, _, startline, c))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import javascript
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class Token extends Locatable, @token {
|
class Token extends Locatable, @token {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
/** Gets the toplevel syntactic structure to which this token belongs. */
|
/** Gets the toplevel syntactic structure to which this token belongs. */
|
||||||
TopLevel getTopLevel() { tokeninfo(this, _, result, _, _) }
|
TopLevel getTopLevel() { tokeninfo(this, _, result, _, _) }
|
||||||
|
|
||||||
|
|||||||
@@ -329,9 +329,9 @@ class LocalVariable extends Variable {
|
|||||||
* If the variable has one or more declarations, the location of the first declaration is used.
|
* If the variable has one or more declarations, the location of the first declaration is used.
|
||||||
* If the variable has no declaration, the entry point of its declaring container is used.
|
* If the variable has no declaration, the entry point of its declaring container is used.
|
||||||
*/
|
*/
|
||||||
Location getLocation() {
|
DbLocation getLocation() {
|
||||||
result =
|
result =
|
||||||
min(Location loc |
|
min(DbLocation loc |
|
||||||
loc = this.getADeclaration().getLocation()
|
loc = this.getADeclaration().getLocation()
|
||||||
|
|
|
|
||||||
loc order by loc.getStartLine(), loc.getStartColumn()
|
loc order by loc.getStartLine(), loc.getStartColumn()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.files.FileSystem
|
import semmle.files.FileSystem
|
||||||
|
private import semmle.javascript.internal.Locations
|
||||||
|
|
||||||
private class TXmlLocatable =
|
private class TXmlLocatable =
|
||||||
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
||||||
@@ -10,7 +11,7 @@ private class TXmlLocatable =
|
|||||||
/** An XML element that has a location. */
|
/** An XML element that has a location. */
|
||||||
class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
||||||
/** Gets the source location for this element. */
|
/** Gets the source location for this element. */
|
||||||
Location getLocation() { xmllocations(this, result) }
|
DbLocation getLocation() { result = getLocatableLocation(this) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this element is at the specified location.
|
* Holds if this element is at the specified location.
|
||||||
@@ -22,10 +23,7 @@ class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
|||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
) {
|
) {
|
||||||
exists(File f, Location l | l = this.getLocation() |
|
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
|
|
||||||
filepath = f.getAbsolutePath()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import javascript
|
|||||||
private import codeql.yaml.Yaml as LibYaml
|
private import codeql.yaml.Yaml as LibYaml
|
||||||
|
|
||||||
private module YamlSig implements LibYaml::InputSig {
|
private module YamlSig implements LibYaml::InputSig {
|
||||||
class LocatableBase extends @yaml_locatable, Locatable {
|
class Location = DbLocation;
|
||||||
override Location getLocation() { yaml_locations(this, result) }
|
|
||||||
}
|
class LocatableBase extends @yaml_locatable, Locatable { }
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -52,8 +52,6 @@ import LibYaml::Make<YamlSig>
|
|||||||
private class MyYmlNode extends Locatable instanceof YamlNode {
|
private class MyYmlNode extends Locatable instanceof YamlNode {
|
||||||
override string getAPrimaryQlClass() { result = YamlNode.super.getAPrimaryQlClass() }
|
override string getAPrimaryQlClass() { result = YamlNode.super.getAPrimaryQlClass() }
|
||||||
|
|
||||||
override Location getLocation() { result = YamlNode.super.getLocation() }
|
|
||||||
|
|
||||||
override string toString() { result = YamlNode.super.toString() }
|
override string toString() { result = YamlNode.super.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,14 @@ module DataFlow {
|
|||||||
none()
|
none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the location of this node. */
|
||||||
|
Location getLocation() {
|
||||||
|
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||||
|
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
|
||||||
|
result.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the file this data flow node comes from. */
|
/** Gets the file this data flow node comes from. */
|
||||||
File getFile() { none() } // overridden in subclasses
|
File getFile() { none() } // overridden in subclasses
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ module Templating {
|
|||||||
|
|
||||||
/** A placeholder tag for a templating engine. */
|
/** A placeholder tag for a templating engine. */
|
||||||
class TemplatePlaceholderTag extends @template_placeholder_tag, Locatable {
|
class TemplatePlaceholderTag extends @template_placeholder_tag, Locatable {
|
||||||
override Location getLocation() { hasLocation(this, result) }
|
|
||||||
|
|
||||||
override string toString() { template_placeholder_tag_info(this, _, result) }
|
override string toString() { template_placeholder_tag_info(this, _, result) }
|
||||||
|
|
||||||
/** Gets the full text of the template tag, including delimiters. */
|
/** Gets the full text of the template tag, including delimiters. */
|
||||||
@@ -107,7 +105,12 @@ module Templating {
|
|||||||
* Gets the innermost JavaScript expression containing this template tag, if any.
|
* Gets the innermost JavaScript expression containing this template tag, if any.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
Expr getEnclosingExpr() { expr_contains_template_tag_location(result, this.getLocation()) }
|
Expr getEnclosingExpr() {
|
||||||
|
exists(@location loc |
|
||||||
|
hasLocation(this, loc) and
|
||||||
|
expr_contains_template_tag_location(result, loc)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ module Stages {
|
|||||||
or
|
or
|
||||||
any(DataFlow::Node node).hasLocationInfo(_, _, _, _, _)
|
any(DataFlow::Node node).hasLocationInfo(_, _, _, _, _)
|
||||||
or
|
or
|
||||||
|
exists(any(DataFlow::Node node).getLocation())
|
||||||
|
or
|
||||||
exists(any(DataFlow::Node node).toString())
|
exists(any(DataFlow::Node node).toString())
|
||||||
or
|
or
|
||||||
exists(any(AccessPath a).getAnInstanceIn(_))
|
exists(any(AccessPath a).getAnInstanceIn(_))
|
||||||
|
|||||||
171
javascript/ql/lib/semmle/javascript/internal/Locations.qll
Normal file
171
javascript/ql/lib/semmle/javascript/internal/Locations.qll
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/** Provides classes for working with locations and program elements that have locations. */
|
||||||
|
|
||||||
|
import javascript
|
||||||
|
|
||||||
|
// Should _not_ be cached, as that would require the data flow stage to be evaluated
|
||||||
|
// in order to evaluate the AST stage. Ideally, we would cache each injector separately,
|
||||||
|
// but that's not possible. Instead, we cache all predicates that need the injectors
|
||||||
|
// to be tuple numbered.
|
||||||
|
newtype TLocation =
|
||||||
|
TDbLocation(@location loc) or
|
||||||
|
TSynthLocation(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||||
|
any(DataFlow::Node n).hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
|
||||||
|
// avoid overlap with existing DB locations
|
||||||
|
not exists(File f |
|
||||||
|
locations_default(_, f, startline, startcolumn, endline, endcolumn) and
|
||||||
|
f.getAbsolutePath() = filepath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A location as given by a file, a start line, a start column,
|
||||||
|
* an end line, and an end column.
|
||||||
|
*
|
||||||
|
* For more information about locations see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
|
*/
|
||||||
|
abstract class LocationImpl extends TLocation {
|
||||||
|
/** Gets the file for this location. */
|
||||||
|
abstract File getFile();
|
||||||
|
|
||||||
|
/** Gets the 1-based line number (inclusive) where this location starts. */
|
||||||
|
abstract int getStartLine();
|
||||||
|
|
||||||
|
/** Gets the 1-based column number (inclusive) where this location starts. */
|
||||||
|
abstract int getStartColumn();
|
||||||
|
|
||||||
|
/** Gets the 1-based line number (inclusive) where this location ends. */
|
||||||
|
abstract int getEndLine();
|
||||||
|
|
||||||
|
/** Gets the 1-based column number (inclusive) where this location ends. */
|
||||||
|
abstract int getEndColumn();
|
||||||
|
|
||||||
|
/** Gets the number of lines covered by this location. */
|
||||||
|
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
|
||||||
|
|
||||||
|
/** Holds if this location starts before location `that`. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate startsBefore(Location that) {
|
||||||
|
exists(string f, int sl1, int sc1, int sl2, int sc2 |
|
||||||
|
this.hasLocationInfo(f, sl1, sc1, _, _) and
|
||||||
|
that.hasLocationInfo(f, sl2, sc2, _, _)
|
||||||
|
|
|
||||||
|
sl1 < sl2
|
||||||
|
or
|
||||||
|
sl1 = sl2 and sc1 < sc2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if this location ends after location `that`. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate endsAfter(Location that) {
|
||||||
|
exists(string f, int el1, int ec1, int el2, int ec2 |
|
||||||
|
this.hasLocationInfo(f, _, _, el1, ec1) and
|
||||||
|
that.hasLocationInfo(f, _, _, el2, ec2)
|
||||||
|
|
|
||||||
|
el1 > el2
|
||||||
|
or
|
||||||
|
el1 = el2 and ec1 > ec2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this location contains location `that`, meaning that it starts
|
||||||
|
* before and ends after it.
|
||||||
|
*/
|
||||||
|
predicate contains(Location that) { this.startsBefore(that) and this.endsAfter(that) }
|
||||||
|
|
||||||
|
/** Holds if this location is empty. */
|
||||||
|
predicate isEmpty() { exists(int l, int c | this.hasLocationInfo(_, l, c, l, c - 1)) }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this element. */
|
||||||
|
string toString() { result = this.getFile().getBaseName() + ":" + this.getStartLine().toString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this element is at the specified location.
|
||||||
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
|
* For more information, see
|
||||||
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
|
*/
|
||||||
|
abstract predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DbLocationImpl extends LocationImpl instanceof DbLocation {
|
||||||
|
override File getFile() { result = DbLocation.super.getFile() }
|
||||||
|
|
||||||
|
override int getStartLine() { result = DbLocation.super.getStartLine() }
|
||||||
|
|
||||||
|
override int getStartColumn() { result = DbLocation.super.getStartColumn() }
|
||||||
|
|
||||||
|
override int getEndLine() { result = DbLocation.super.getEndLine() }
|
||||||
|
|
||||||
|
override int getEndColumn() { result = DbLocation.super.getEndColumn() }
|
||||||
|
|
||||||
|
override predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
DbLocation.super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SynthLocationImpl extends LocationImpl, TSynthLocation {
|
||||||
|
override File getFile() { synthLocationInfo(this, result.getAbsolutePath(), _, _, _, _) }
|
||||||
|
|
||||||
|
override int getStartLine() { synthLocationInfo(this, _, result, _, _, _) }
|
||||||
|
|
||||||
|
override int getStartColumn() { synthLocationInfo(this, _, _, result, _, _) }
|
||||||
|
|
||||||
|
override int getEndLine() { synthLocationInfo(this, _, _, _, result, _) }
|
||||||
|
|
||||||
|
override int getEndColumn() { synthLocationInfo(this, _, _, _, _, result) }
|
||||||
|
|
||||||
|
override predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
synthLocationInfo(this, filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
private module Cached {
|
||||||
|
cached
|
||||||
|
DbLocation getLocatableLocation(@locatable l) {
|
||||||
|
exists(@location loc |
|
||||||
|
hasLocation(l, loc) or
|
||||||
|
xmllocations(l, loc) or
|
||||||
|
json_locations(l, loc) or
|
||||||
|
yaml_locations(l, loc)
|
||||||
|
|
|
||||||
|
result = TDbLocation(loc)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate dbLocationInfo(
|
||||||
|
DbLocation l, File f, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
exists(@location loc |
|
||||||
|
l = TDbLocation(loc) and
|
||||||
|
locations_default(loc, f, startline, startcolumn, endline, endcolumn)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import Cached
|
||||||
|
|
||||||
|
cached
|
||||||
|
private module CachedInDataFlowStage {
|
||||||
|
private import semmle.javascript.internal.CachedStages
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate synthLocationInfo(
|
||||||
|
SynthLocationImpl l, string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
Stages::DataFlowStage::ref() and
|
||||||
|
l = TSynthLocation(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private import CachedInDataFlowStage
|
||||||
@@ -4,8 +4,13 @@ private import codeql.util.test.InlineExpectationsTest
|
|||||||
module Impl implements InlineExpectationsTestSig {
|
module Impl implements InlineExpectationsTestSig {
|
||||||
private import javascript
|
private import javascript
|
||||||
|
|
||||||
class ExpectationComment extends LineComment {
|
final private class LineCommentFinal = LineComment;
|
||||||
|
|
||||||
|
class ExpectationComment extends LineCommentFinal {
|
||||||
string getContents() { result = this.getText() }
|
string getContents() { result = this.getText() }
|
||||||
|
|
||||||
|
/** Gets this element's location. */
|
||||||
|
Location getLocation() { result = super.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Location = JS::Location;
|
class Location = JS::Location;
|
||||||
|
|||||||
Reference in New Issue
Block a user