mirror of
https://github.com/github/codeql.git
synced 2026-01-04 02:00:18 +01:00
182 lines
5.6 KiB
Plaintext
182 lines
5.6 KiB
Plaintext
/**
|
|
* Provides classes and predicates related to jump-to-definition links
|
|
* in the code viewer.
|
|
*/
|
|
|
|
import csharp
|
|
|
|
/** An element with an associated definition. */
|
|
abstract class Use extends @type_mention_parent {
|
|
/**
|
|
* 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://help.semmle.com/QL/learn-ql/ql/locations.html).
|
|
*/
|
|
predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
exists(Location l |
|
|
l = this.(Element).getLocation() or
|
|
l = this.(TypeMention).getLocation()
|
|
|
|
|
filepath = l.getFile().getAbsolutePath() and
|
|
startline = l.getStartLine() and
|
|
startcolumn = l.getStartColumn() and
|
|
endline = l.getEndLine() and
|
|
endcolumn = l.getEndColumn()
|
|
)
|
|
}
|
|
|
|
/** Gets the definition associated with this element. */
|
|
abstract Declaration getDefinition();
|
|
|
|
/**
|
|
* Gets the type of use.
|
|
*
|
|
* - `"M"`: call.
|
|
* - `"V"`: variable use.
|
|
* - `"T"`: type reference.
|
|
*/
|
|
abstract string getUseType();
|
|
|
|
/** Gets a textual representation of this element. */
|
|
abstract string toString();
|
|
}
|
|
|
|
/** A method call/access. */
|
|
private class MethodUse extends Use, QualifiableExpr {
|
|
MethodUse() {
|
|
this instanceof MethodCall or
|
|
this instanceof MethodAccess
|
|
}
|
|
|
|
/** Gets the qualifier of this method use, if any. */
|
|
private Expr getFormatQualifier() {
|
|
(
|
|
if this.getQualifiedDeclaration().(Method).isExtensionMethod()
|
|
then result = this.(MethodCall).getArgument(0)
|
|
else result = this.getQualifier()
|
|
) and
|
|
not result.isImplicit()
|
|
}
|
|
|
|
override predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
Use.super.hasLocationInfo(filepath, _, _, _, _) and
|
|
endline = startline and
|
|
endcolumn = startcolumn + this.getQualifiedDeclaration().getName().length() - 1 and
|
|
(
|
|
exists(Location ql | ql = this.getFormatQualifier().getLocation() |
|
|
startline = ql.getEndLine() and
|
|
startcolumn = ql.getEndColumn() + 2
|
|
)
|
|
or
|
|
not exists(this.getFormatQualifier()) and
|
|
exists(Location l | l = this.getLocation() |
|
|
startline = l.getStartLine() and
|
|
startcolumn = l.getStartColumn()
|
|
)
|
|
)
|
|
}
|
|
|
|
override Method getDefinition() { result = getQualifiedDeclaration().getSourceDeclaration() }
|
|
|
|
override string getUseType() { result = "M" }
|
|
|
|
override string toString() { result = this.(Expr).toString() }
|
|
}
|
|
|
|
/** An access. */
|
|
private class AccessUse extends Access, Use {
|
|
AccessUse() {
|
|
not this.getTarget().(Parameter).getCallable() instanceof Accessor and
|
|
not this = any(LocalVariableDeclAndInitExpr d).getLValue() and
|
|
not this.isImplicit() and
|
|
not this instanceof MethodAccess and // handled by `MethodUse`
|
|
not this instanceof TypeAccess and // handled by `TypeMentionUse`
|
|
not this.(FieldAccess).getParent() instanceof Field and // Enum initializer
|
|
not this.(FieldAccess).getParent().getParent() instanceof Field and // Field initializer
|
|
not this.(PropertyAccess).getParent().getParent() instanceof Property // Property initializer
|
|
}
|
|
|
|
/** Gets the qualifier of this acccess, if any. */
|
|
private Expr getFormatQualifier() {
|
|
result = this.(QualifiableExpr).getQualifier() and
|
|
not result.isImplicit()
|
|
}
|
|
|
|
override predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
exists(Location ql | ql = this.getFormatQualifier().getLocation() |
|
|
startline = ql.getEndLine() and
|
|
startcolumn = ql.getEndColumn() + 2 and
|
|
Use.super.hasLocationInfo(filepath, _, _, endline, endcolumn)
|
|
)
|
|
or
|
|
not exists(this.getFormatQualifier()) and
|
|
Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override Declaration getDefinition() { result = this.getTarget().getSourceDeclaration() }
|
|
|
|
override string getUseType() {
|
|
if this instanceof Call or this instanceof LocalFunctionAccess
|
|
then result = "M"
|
|
else
|
|
if this instanceof BaseAccess or this instanceof ThisAccess
|
|
then result = "T"
|
|
else result = "V"
|
|
}
|
|
|
|
override string toString() { result = this.(Access).toString() }
|
|
}
|
|
|
|
/** A type mention. */
|
|
private class TypeMentionUse extends Use, TypeMention {
|
|
TypeMentionUse() {
|
|
// In type mentions such as `T[]`, `T?`, `T*`, and `(S, T)`, we only want
|
|
// uses for the nested type mentions
|
|
forall(TypeMention child, Type t |
|
|
child.getParent() = this and
|
|
t = this.getType()
|
|
|
|
|
not t instanceof ArrayType and
|
|
not t instanceof NullableType and
|
|
not t instanceof PointerType and
|
|
not t instanceof TupleType
|
|
)
|
|
}
|
|
|
|
override Type getDefinition() { result = this.getType().getSourceDeclaration() }
|
|
|
|
override string getUseType() {
|
|
if this.getTarget() instanceof ObjectCreation
|
|
then result = "M" // constructor call
|
|
else result = "T"
|
|
}
|
|
|
|
override string toString() { result = TypeMention.super.toString() }
|
|
}
|
|
|
|
/**
|
|
* Gets an element, of kind `kind`, that element `e` uses, if any.
|
|
*/
|
|
cached
|
|
Declaration definitionOf(Use use, string kind) {
|
|
result = use.getDefinition() and
|
|
result.fromSource() and
|
|
kind = use.getUseType()
|
|
}
|
|
|
|
/**
|
|
* Returns an appropriately encoded version of a filename `name`
|
|
* passed by the VS Code extension in order to coincide with the
|
|
* output of `.getFile()` on locatable entities.
|
|
*/
|
|
cached
|
|
File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name }
|