mirror of
https://github.com/github/codeql.git
synced 2025-12-21 11:16:30 +01:00
This was always supposed to pick one of several candidate non-source locations (usually for a generic type instantiation), but since `getFile().toString()` just produces the basename of the class file actually the results would almost always tie and all of the candidate locations would be returned. Use the full class file path as a tiebreaker instead.
224 lines
7.2 KiB
Plaintext
224 lines
7.2 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.
|
|
*/
|
|
|
|
import FileSystem
|
|
import semmle.code.java.Element
|
|
private import semmle.code.SMAP
|
|
|
|
/** Holds if element `e` has name `name`. */
|
|
predicate hasName(Element e, string name) {
|
|
classes(e, name, _, _)
|
|
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, _, _, _, _)
|
|
}
|