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:
Andrew Eisenberg
2022-06-28 14:36:07 -07:00
parent f97cc9e37c
commit a3f4d1bf66
29 changed files with 5 additions and 5 deletions

View 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
View 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)
}

View 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

View 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
View 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())
}
}