Files
codeql/java/ql/lib/definitions.qll
2023-01-10 13:37:19 +01:00

202 lines
6.5 KiB
Plaintext

/**
* Provides classes and predicates related to jump-to-definition links
* in the code viewer.
*/
import java
import IDEContextual
/**
* Restricts the location of a method access to the method identifier only,
* excluding its qualifier, type arguments and arguments.
*
* If there is any whitespace between the method identifier and its first argument,
* or between the method identifier and its qualifier (or last type argument, if any),
* the location may be slightly inaccurate and include such whitespace,
* but it should suffice for the purpose of avoiding overlapping definitions.
*/
private class LocationOverridingMethodAccess extends MethodAccess {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(MemberRefExpr e | e.getReferencedCallable() = getMethod() |
exists(int elRef, int ecRef | e.hasLocationInfo(path, _, _, elRef, ecRef) |
sl = elRef and
sc = ecRef - getMethod().getName().length() + 1 and
el = elRef and
ec = ecRef
)
)
or
not exists(MemberRefExpr e | e.getReferencedCallable() = getMethod()) and
exists(int slSuper, int scSuper, int elSuper, int ecSuper |
super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper)
|
(
if exists(getTypeArgument(_))
then
exists(Location locTypeArg |
locTypeArg = getTypeArgument(count(getTypeArgument(_)) - 1).getLocation()
|
sl = locTypeArg.getEndLine() and
sc = locTypeArg.getEndColumn() + 2
)
else (
if exists(getQualifier())
then
// Note: this needs to be the original (full) location of the qualifier, not the modified one.
exists(Location locQual | locQual = getQualifier().getLocation() |
sl = locQual.getEndLine() and
sc = locQual.getEndColumn() + 2
)
else (
sl = slSuper and
sc = scSuper
)
)
) and
(
if getNumArgument() > 0
then
// Note: this needs to be the original (full) location of the first argument, not the modified one.
exists(Location locArg | locArg = getArgument(0).getLocation() |
el = locArg.getStartLine() and
ec = locArg.getStartColumn() - 2
)
else (
el = elSuper and
ec = ecSuper - 2
)
)
)
}
}
/**
* Restricts the location of a type access to exclude
* the type arguments and qualifier, if any.
*/
private class LocationOverridingTypeAccess extends TypeAccess {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(int slSuper, int scSuper, int elSuper, int ecSuper |
super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper)
|
(
if exists(getQualifier())
then
// Note: this needs to be the original (full) location of the qualifier, not the modified one.
exists(Location locQual | locQual = getQualifier().getLocation() |
sl = locQual.getEndLine() and
sc = locQual.getEndColumn() + 2
)
else (
sl = slSuper and
sc = scSuper
)
) and
(
if exists(getTypeArgument(_))
then
// Note: this needs to be the original (full) location of the first type argument, not the modified one.
exists(Location locArg | locArg = getTypeArgument(0).getLocation() |
el = locArg.getStartLine() and
ec = locArg.getStartColumn() - 2
)
else (
el = elSuper and
ec = ecSuper
)
)
)
}
}
/**
* Restricts the location of a field access to the name of the accessed field only,
* excluding its qualifier.
*/
private class LocationOverridingFieldAccess extends FieldAccess {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
super.hasLocationInfo(path, _, _, el, ec) and
sl = el and
sc = ec - getField().getName().length() + 1
}
}
/**
* Restricts the location of a single-type-import declaration to the name of the imported type only,
* excluding the `import` keyword and the package name.
*/
private class LocationOverridingImportType extends ImportType {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(int elSuper, int ecSuper | super.hasLocationInfo(path, _, _, elSuper, ecSuper) |
el = elSuper and
ec = ecSuper - 1 and
sl = el and
sc = ecSuper - getImportedType().getName().length()
)
}
}
/**
* Restricts the location of a single-static-import declaration to the name of the imported member(s) only,
* excluding the `import` keyword and the package name.
*/
private class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(int elSuper, int ecSuper | super.hasLocationInfo(path, _, _, elSuper, ecSuper) |
el = elSuper and
ec = ecSuper - 1 and
sl = el and
sc = ecSuper - getName().length()
)
}
}
private Element definition(Element e, string kind) {
e.(MethodAccess).getMethod().getSourceDeclaration() = result and
kind = "M" and
not result instanceof InitializerMethod
or
e.(TypeAccess).getType().(RefType).getSourceDeclaration() = result and kind = "T"
or
exists(Variable v | v = e.(VarAccess).getVariable() |
result = v.(Field).getSourceDeclaration() or
result = v.(Parameter).getSourceDeclaration() or
result = v.(LocalVariableDecl)
) and
kind = "V"
or
e.(ImportType).getImportedType() = result and kind = "I"
or
e.(ImportStaticTypeMember).getAMemberImport() = result and kind = "I"
}
private predicate dummyVarAccess(VarAccess va) {
exists(AssignExpr ae, InitializerMethod im |
ae.getDest() = va and
ae.getParent() = im.getBody().getAChild()
)
}
private predicate dummyTypeAccess(TypeAccess ta) {
exists(FunctionalExpr e |
e.getAnonymousClass().getClassInstanceExpr().getTypeName() = ta.getParent*()
)
}
/**
* Gets an element, of kind `kind`, that element `e` uses, if any.
*
* The `kind` is a string representing what kind of use it is:
* - `"M"` for function and method calls
* - `"T"` for uses of types
* - `"V"` for variable accesses
* - `"I"` for import directives
*/
Element definitionOf(Element e, string kind) {
result = definition(e, kind) and
result.fromSource() and
e.fromSource() and
not dummyVarAccess(e) and
not dummyTypeAccess(e)
}