Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 29 additions & 38 deletions go/ql/lib/semmle/go/Locations.qll
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@
import go
private import internal.Locations

private module DbLocationInput implements LocationClassInputSig {
class Base = TDbLocation;

predicate locationInfo(
Base b, string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f |
dbLocationInfo(b, f, startline, startcolumn, endline, endcolumn) and
filepath = f.getAbsolutePath()
)
}

File getFile(Base b) { dbLocationInfo(b, result, _, _, _, _) }
}

/**
* A location as given by a file, a start line, a start column,
* an end line, and an end column.
Expand All @@ -11,51 +26,27 @@ private import internal.Locations
*
* For more information about locations see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
class DbLocation extends TDbLocation {
/** Gets the file for this location. */
File getFile() { dbLocationInfo(this, result, _, _, _, _) }

/** Gets the 1-based line number (inclusive) where this location starts. */
int getStartLine() { dbLocationInfo(this, _, result, _, _, _) }

/** Gets the 1-based column number (inclusive) where this location starts. */
int getStartColumn() { dbLocationInfo(this, _, _, result, _, _) }

/** Gets the 1-based line number (inclusive) where this location ends. */
int getEndLine() { dbLocationInfo(this, _, _, _, result, _) }
class DbLocation = LocationClass<DbLocationInput>::Location;

/** Gets the 1-based column number (inclusive) where this location ends. */
int getEndColumn() { dbLocationInfo(this, _, _, _, _, result) }
private module LocationInput implements LocationClassInputSig {
class Base = TLocation;

/** Gets the number of lines covered by this location. */
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }

/** Gets a textual representation of this element. */
string toString() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
)
predicate locationInfo(
Base b, string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
DbLocationInput::locationInfo(b, filepath, startline, startcolumn, endline, endcolumn)
or
dataFlowNodeLocationInfo(b, filepath, startline, startcolumn, endline, endcolumn)
}

/**
* 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/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f |
dbLocationInfo(this, f, startline, startcolumn, endline, endcolumn) and
filepath = f.getAbsolutePath()
)
File getFile(Base b) {
result = DbLocationInput::getFile(b)
or
dataFlowNodeLocationInfo(b, result.getAbsolutePath(), _, _, _, _)
}
}

final class Location = LocationImpl;
class Location = LocationClass<LocationInput>::Location;

/** A program element with a location. */
class Locatable extends @locatable {
Expand Down
8 changes: 2 additions & 6 deletions go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ private import semmle.go.dataflow.FlowSummary
private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.go.dataflow.ExternalFlow
private import semmle.go.internal.Locations

cached
private newtype TNode =
Expand Down Expand Up @@ -158,12 +159,7 @@ module Public {
}

/** 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)
)
}
Location getLocation() { result = getDataFlowNodeLocation(this) }

/** Gets the file in which this node appears. */
File getFile() { this.hasLocationInfo(result.getAbsolutePath(), _, _, _, _) }
Expand Down
171 changes: 81 additions & 90 deletions go/ql/lib/semmle/go/internal/Locations.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,76 @@

import go

/** Provides the input to `LocationClass`. */
signature module LocationClassInputSig {
class Base;

predicate locationInfo(
Base b, string filepath, int startline, int startcolumn, int endline, int endcolumn
);

File getFile(Base b);
}

/** Provides a class layer for locations. */
module LocationClass<LocationClassInputSig Input> {
private import Input

/**
* 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/).
*/
final class Location instanceof Base {
/** Gets the file for this location. */
File getFile() { result = getFile(this) }

/** Gets the 1-based line number (inclusive) where this location starts. */
int getStartLine() { locationInfo(this, _, result, _, _, _) }

/** Gets the 1-based column number (inclusive) where this location starts. */
int getStartColumn() { locationInfo(this, _, _, result, _, _) }

/** Gets the 1-based line number (inclusive) where this location ends. */
int getEndLine() { locationInfo(this, _, _, _, result, _) }

/** Gets the 1-based column number (inclusive) where this location ends. */
int getEndColumn() { locationInfo(this, _, _, _, _, result) }

/** Gets the number of lines covered by this location. */
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }

/** Gets a textual representation of this element. */
string toString() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
)
}

/**
* 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/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
locationInfo(this, filepath, startline, startcolumn, endline, endcolumn)
}
}
}

// 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) {
TDataFlowNodeLocation(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 existingDBLocation(filepath, startline, startcolumn, endline, endcolumn)
Expand All @@ -24,91 +87,6 @@ private predicate existingDBLocation(
)
}

/**
* 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 }

/** Gets a textual representation of this element. */
string toString() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
)
}

/**
* 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 {
private @location loc;

DbLocationImpl() { this = TDbLocation(loc) }

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
Expand Down Expand Up @@ -143,8 +121,21 @@ private module Cached {
import Cached

cached
private predicate synthLocationInfo(
SynthLocationImpl l, string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
l = TSynthLocation(filepath, startline, startcolumn, endline, endcolumn)
private module DataFlowNodes {
cached
predicate dataFlowNodeLocationInfo(
Location l, string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
l = TDataFlowNodeLocation(filepath, startline, startcolumn, endline, endcolumn)
}

cached
Location getDataFlowNodeLocation(DataFlow::Node n) {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
result.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
}
}

import DataFlowNodes