codeql/java/ql/lib/definitions.qll

202 строки
6.6 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 LocationOverridingMethodCall extends MethodCall {
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(MemberRefExpr e | e.getReferencedCallable() = this.getMethod() |
exists(int elRef, int ecRef | e.hasLocationInfo(path, _, _, elRef, ecRef) |
sl = elRef and
sc = ecRef - this.getMethod().getName().length() + 1 and
el = elRef and
ec = ecRef
)
)
or
not exists(MemberRefExpr e | e.getReferencedCallable() = this.getMethod()) and
exists(int slSuper, int scSuper, int elSuper, int ecSuper |
super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper)
|
(
if exists(this.getTypeArgument(_))
then
exists(Location locTypeArg |
locTypeArg = this.getTypeArgument(count(this.getTypeArgument(_)) - 1).getLocation()
|
sl = locTypeArg.getEndLine() and
sc = locTypeArg.getEndColumn() + 2
)
else (
if exists(this.getQualifier())
then
// Note: this needs to be the original (full) location of the qualifier, not the modified one.
exists(Location locQual | locQual = this.getQualifier().getLocation() |
sl = locQual.getEndLine() and
sc = locQual.getEndColumn() + 2
)
else (
sl = slSuper and
sc = scSuper
)
)
) and
(
if this.getNumArgument() > 0
then
// Note: this needs to be the original (full) location of the first argument, not the modified one.
exists(Location locArg | locArg = this.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(this.getQualifier())
then
// Note: this needs to be the original (full) location of the qualifier, not the modified one.
exists(Location locQual | locQual = this.getQualifier().getLocation() |
sl = locQual.getEndLine() and
sc = locQual.getEndColumn() + 2
)
else (
sl = slSuper and
sc = scSuper
)
) and
(
if exists(this.getTypeArgument(_))
then
// Note: this needs to be the original (full) location of the first type argument, not the modified one.
exists(Location locArg | locArg = this.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 - this.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 - this.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 - this.getName().length()
)
}
}
private Element definition(Element e, string kind) {
e.(MethodCall).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) 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)
}