mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
With this change, users are now able to run View AST command in vscode within vscode workspaces that do not include the core libraries. The relevant core library only needs to be installed in the package cache.
199 lines
6.4 KiB
Plaintext
199 lines
6.4 KiB
Plaintext
/**
|
|
* Provides classes and predicates related to jump-to-definition links
|
|
* in the code viewer.
|
|
*/
|
|
|
|
import csharp
|
|
import IDEContextual
|
|
|
|
/** 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://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(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 = this.getQualifiedDeclaration().getUnboundDeclaration()
|
|
}
|
|
|
|
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 access, 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().getUnboundDeclaration() }
|
|
|
|
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 predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, _) and
|
|
endcolumn =
|
|
startcolumn +
|
|
this.getType().(ConstructedType).getUnboundGeneric().getUndecoratedName().length() - 1
|
|
or
|
|
Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, _) and
|
|
endcolumn = startcolumn + this.getType().(UnboundGenericType).getUndecoratedName().length() - 1
|
|
or
|
|
not this.getType() instanceof ConstructedType and
|
|
not this.getType() instanceof UnboundGenericType and
|
|
Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override Type getDefinition() { result = this.getType().getUnboundDeclaration() }
|
|
|
|
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() and
|
|
// Some entities have many locations. This can arise for files that
|
|
// are duplicated multiple times in the database at different
|
|
// locations. Rather than letting the result set explode, we just
|
|
// exclude results that are "too ambiguous" -- we could also arbitrarily
|
|
// pick one location later on.
|
|
strictcount(result.getLocation()) < 10
|
|
}
|