mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
Move contextual queries from src to lib
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.
This commit is contained in:
22
java/ql/lib/IDEContextual.qll
Normal file
22
java/ql/lib/IDEContextual.qll
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Provides shared predicates related to contextual queries in the code viewer.
|
||||
*/
|
||||
|
||||
import semmle.files.FileSystem
|
||||
|
||||
/**
|
||||
* Returns the `File` matching the given source file name as encoded by the VS
|
||||
* Code extension.
|
||||
*/
|
||||
cached
|
||||
File getFileBySourceArchiveName(string name) {
|
||||
// The name provided for a file in the source archive by the VS Code extension
|
||||
// has some differences from the absolute path in the database:
|
||||
// 1. colons are replaced by underscores
|
||||
// 2. there's a leading slash, even for Windows paths: "C:/foo/bar" ->
|
||||
// "/C_/foo/bar"
|
||||
// 3. double slashes in UNC prefixes are replaced with a single slash
|
||||
// We can handle 2 and 3 together by unconditionally adding a leading slash
|
||||
// before replacing double slashes.
|
||||
name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/")
|
||||
}
|
||||
205
java/ql/lib/definitions.qll
Normal file
205
java/ql/lib/definitions.qll
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* 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 slSuper, int scSuper, int elSuper, int ecSuper |
|
||||
super.hasLocationInfo(path, slSuper, scSuper, 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 slSuper, int scSuper, int elSuper, int ecSuper |
|
||||
super.hasLocationInfo(path, slSuper, scSuper, 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)
|
||||
}
|
||||
16
java/ql/lib/localDefinitions.ql
Normal file
16
java/ql/lib/localDefinitions.ql
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Jump-to-definition links
|
||||
* @description Generates use-definition pairs that provide the data
|
||||
* for jump-to-definition in the code viewer.
|
||||
* @kind definitions
|
||||
* @id java/ide-jump-to-definition
|
||||
* @tags ide-contextual-queries/local-definitions
|
||||
*/
|
||||
|
||||
import definitions
|
||||
|
||||
external string selectedSourceFile();
|
||||
|
||||
from Element e, Element def, string kind
|
||||
where def = definitionOf(e, kind) and e.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select e, def, kind
|
||||
17
java/ql/lib/localReferences.ql
Normal file
17
java/ql/lib/localReferences.ql
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name Find-references links
|
||||
* @description Generates use-definition pairs that provide the data
|
||||
* for find-references in the code viewer.
|
||||
* @kind definitions
|
||||
* @id java/ide-find-references
|
||||
* @tags ide-contextual-queries/local-references
|
||||
*/
|
||||
|
||||
import definitions
|
||||
|
||||
external string selectedSourceFile();
|
||||
|
||||
from Element e, Element def, string kind
|
||||
where
|
||||
def = definitionOf(e, kind) and def.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
select e, def, kind
|
||||
28
java/ql/lib/printAst.ql
Normal file
28
java/ql/lib/printAst.ql
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @name Print AST
|
||||
* @description Outputs a representation of a file's Abstract Syntax Tree. This
|
||||
* query is used by the VS Code extension.
|
||||
* @id java/print-ast
|
||||
* @kind graph
|
||||
* @tags ide-contextual-queries/print-ast
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.PrintAst
|
||||
import definitions
|
||||
|
||||
/**
|
||||
* The source file to generate an AST from.
|
||||
*/
|
||||
external string selectedSourceFile();
|
||||
|
||||
class PrintAstConfigurationOverride extends PrintAstConfiguration {
|
||||
/**
|
||||
* Holds if the location matches the selected file in the VS Code extension and
|
||||
* the element is `fromSource`.
|
||||
*/
|
||||
override predicate shouldPrint(Element e, Location l) {
|
||||
super.shouldPrint(e, l) and
|
||||
l.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user