mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
238 lines
7.6 KiB
Plaintext
238 lines
7.6 KiB
Plaintext
/**
|
|
* Provides classes and predicates for working with locations.
|
|
*
|
|
* Locations represent parts of files and are used to map elements to their source location.
|
|
*/
|
|
overlay[local?]
|
|
module;
|
|
|
|
import FileSystem
|
|
import semmle.code.java.Element
|
|
private import semmle.code.java.Overlay
|
|
private import semmle.code.SMAP
|
|
|
|
/** Holds if element `e` has name `name`. */
|
|
predicate hasName(Element e, string name) {
|
|
classes_or_interfaces(e, name, _, _)
|
|
or
|
|
primitives(e, name)
|
|
or
|
|
constrs(e, name, _, _, _, _)
|
|
or
|
|
methods(e, name, _, _, _, _)
|
|
or
|
|
fields(e, name, _, _)
|
|
or
|
|
packages(e, name)
|
|
or
|
|
name = e.(File).getStem()
|
|
or
|
|
paramName(e, name)
|
|
or
|
|
exists(int pos |
|
|
params(e, _, pos, _, _) and
|
|
not paramName(e, _) and
|
|
name = "p" + pos
|
|
)
|
|
or
|
|
localvars(e, name, _, _)
|
|
or
|
|
typeVars(e, name, _, _)
|
|
or
|
|
wildcards(e, name, _)
|
|
or
|
|
arrays(e, name, _, _, _)
|
|
or
|
|
modifiers(e, name)
|
|
or
|
|
kt_type_alias(e, name, _)
|
|
or
|
|
ktProperties(e, name)
|
|
or
|
|
e instanceof ErrorType and name = "<CodeQL error type>"
|
|
}
|
|
|
|
/**
|
|
* Top is the root of the QL type hierarchy; it defines some default
|
|
* methods for obtaining locations and a standard `toString()` method.
|
|
*/
|
|
class Top extends @top {
|
|
/** Gets the source location for this element. */
|
|
Location getLocation() { fixedHasLocation(this, result, _) }
|
|
|
|
/**
|
|
* 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
|
|
) {
|
|
this.hasLocationInfoAux(filepath, startline, startcolumn, endline, endcolumn)
|
|
or
|
|
exists(string outFilepath, int outStartline, int outEndline |
|
|
this.hasLocationInfoAux(outFilepath, outStartline, _, outEndline, _) and
|
|
hasSmapLocationInfo(filepath, startline, startcolumn, endline, endcolumn, outFilepath,
|
|
outStartline, outEndline)
|
|
)
|
|
}
|
|
|
|
private predicate hasLocationInfoAux(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
exists(File f, Location l | fixedHasLocation(this, l, f) |
|
|
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
|
|
filepath = f.getAbsolutePath()
|
|
)
|
|
}
|
|
|
|
/** Gets the file associated with this element. */
|
|
File getFile() { fixedHasLocation(this, _, result) }
|
|
|
|
/**
|
|
* Gets the total number of lines that this element ranges over,
|
|
* including lines of code, comment and whitespace-only lines.
|
|
*/
|
|
int getTotalNumberOfLines() { numlines(this, result, _, _) }
|
|
|
|
/** Gets the number of lines of code that this element ranges over. */
|
|
int getNumberOfLinesOfCode() { numlines(this, _, result, _) }
|
|
|
|
/** Gets the number of comment lines that this element ranges over. */
|
|
int getNumberOfCommentLines() { numlines(this, _, _, result) }
|
|
|
|
/** Gets a textual representation of this element. */
|
|
cached
|
|
string toString() { hasName(this, result) }
|
|
|
|
/**
|
|
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
|
|
*/
|
|
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
|
|
|
|
/**
|
|
* Gets the name of a primary CodeQL class to which this element belongs.
|
|
*
|
|
* For most elements, this is simply the most precise syntactic category to
|
|
* which they belong; for example, `AddExpr` is a primary class, but
|
|
* `BinaryExpr` is not.
|
|
*
|
|
* This predicate always has a result. If no primary class can be
|
|
* determined, the result is `"???"`. If multiple primary classes match,
|
|
* this predicate can have multiple results.
|
|
*/
|
|
string getAPrimaryQlClass() { result = "???" }
|
|
}
|
|
|
|
/** A location maps language elements to positions in source files. */
|
|
class Location extends @location {
|
|
/** Gets the 1-based line number (inclusive) where this location starts. */
|
|
int getStartLine() { locations_default(this, _, result, _, _, _) }
|
|
|
|
/** Gets the 1-based column number (inclusive) where this location starts. */
|
|
int getStartColumn() { locations_default(this, _, _, result, _, _) }
|
|
|
|
/** Gets the 1-based line number (inclusive) where this location ends. */
|
|
int getEndLine() { locations_default(this, _, _, _, result, _) }
|
|
|
|
/** Gets the 1-based column number (inclusive) where this location ends. */
|
|
int getEndColumn() { locations_default(this, _, _, _, _, result) }
|
|
|
|
/**
|
|
* Gets the total number of lines that this location ranges over,
|
|
* including lines of code, comment and whitespace-only lines.
|
|
*/
|
|
int getNumberOfLines() {
|
|
exists(@sourceline s | hasLocation(s, this) |
|
|
numlines(s, result, _, _)
|
|
or
|
|
not numlines(s, _, _, _) and result = 0
|
|
)
|
|
}
|
|
|
|
/** Gets the number of lines of code that this location ranges over. */
|
|
int getNumberOfLinesOfCode() {
|
|
exists(@sourceline s | hasLocation(s, this) |
|
|
numlines(s, _, result, _)
|
|
or
|
|
not numlines(s, _, _, _) and result = 0
|
|
)
|
|
}
|
|
|
|
/** Gets the number of comment lines that this location ranges over. */
|
|
int getNumberOfCommentLines() {
|
|
exists(@sourceline s | hasLocation(s, this) |
|
|
numlines(s, _, _, result)
|
|
or
|
|
not numlines(s, _, _, _) and result = 0
|
|
)
|
|
}
|
|
|
|
/** Gets the file containing this location. */
|
|
File getFile() { locations_default(this, result, _, _, _, _) }
|
|
|
|
/** Gets a string representation containing the file and range for this location. */
|
|
string toString() {
|
|
exists(string filepath, int startLine, int startCol, int endLine, int endCol |
|
|
this.hasLocationInfo(filepath, startLine, startCol, endLine, endCol)
|
|
|
|
|
toUrl(filepath, startLine, startCol, endLine, endCol, result)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* 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 | locations_default(this, f, startline, startcolumn, endline, endcolumn) |
|
|
filepath = f.getAbsolutePath()
|
|
)
|
|
}
|
|
}
|
|
|
|
private predicate hasSourceLocation(Top l, Location loc, File f) {
|
|
hasLocation(l, loc) and f = loc.getFile() and f.isSourceFile()
|
|
}
|
|
|
|
cached
|
|
private predicate fixedHasLocation(Top l, Location loc, File f) {
|
|
hasSourceLocation(l, loc, f)
|
|
or
|
|
// When an entity has more than one location, as it might due to
|
|
// e.g. a parameterized generic being seen and extracted in several
|
|
// different directories or JAR files, select an arbitrary representative
|
|
// location to avoid needlessly duplicating alerts.
|
|
//
|
|
// Don't do this when the relevant location is in a source file, because
|
|
// that is much more unusual and we would rather notice the bug than mask it here.
|
|
loc =
|
|
min(Location candidateLoc |
|
|
hasLocation(l, candidateLoc)
|
|
|
|
|
candidateLoc order by candidateLoc.getFile().getAbsolutePath()
|
|
) and
|
|
not hasSourceLocation(l, _, _) and
|
|
locations_default(loc, f, _, _, _, _)
|
|
}
|
|
|
|
overlay[local]
|
|
private predicate discardableLocation(string file, @location l) {
|
|
not isOverlay() and
|
|
file = getRawFileForLoc(l) and
|
|
not exists(@file f | hasLocation(f, l))
|
|
}
|
|
|
|
/** Discard base locations in files fully extracted in the overlay. */
|
|
overlay[discard_entity]
|
|
private predicate discardLocation(@location l) {
|
|
exists(string file | discardableLocation(file, l) and overlayChangedFiles(file))
|
|
}
|