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

@@ -1,61 +0,0 @@
/**
* Provides predicates for finding variable references and declarations
* in a given function or toplevel.
*/
import javascript
/**
* Classification of variable references; all references have kind `Ref`,
* but only declarations have kind `Decl`.
*
* Note that references that are not declarations are called accesses elsewhere,
* but they are not treated specially in this context.
*/
newtype RefKind =
Ref() or
Decl()
/**
* Gets a reference to `var` (if `kind` is `Ref()`) or declaration of
* `var` (if `kind` is `Decl()`) in `sc`.
*/
VarRef refInContainer(Variable var, RefKind kind, StmtContainer sc) {
result.getVariable() = var and
result.getContainer() = sc and
(kind = Decl() implies result instanceof VarDecl)
}
/**
* Gets the textually first reference to `var` (if `kind` is `Ref()`) or
* declaration of `var` (if `kind` is `Decl()`) in `sc`.
*/
VarRef firstRefInContainer(Variable var, RefKind kind, StmtContainer sc) {
result =
min(refInContainer(var, kind, sc) as ref
order by
ref.getLocation().getStartLine(), ref.getLocation().getStartColumn()
)
}
/**
* Gets a reference to `var` (if `kind` is `Ref()`) or declaration of
* `var` (if `kind` is `Decl()`) in `tl`.
*/
VarRef refInTopLevel(Variable var, RefKind kind, TopLevel tl) {
result.getVariable() = var and
result.getTopLevel() = tl and
(kind = Decl() implies result instanceof VarDecl)
}
/**
* Gets the textually first reference to `var` (if `kind` is `Ref()`) or
* declaration of `var` (if `kind` is `Decl()`) in `tl`.
*/
VarRef firstRefInTopLevel(Variable var, RefKind kind, TopLevel tl) {
result =
min(refInTopLevel(var, kind, tl) as ref
order by
ref.getLocation().getStartLine(), ref.getLocation().getStartColumn()
)
}

View File

@@ -1,22 +0,0 @@
/**
* 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("//", "/")
}

View File

@@ -1,13 +0,0 @@
/**
* @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 js/jump-to-definition
*/
import definitions
from Locatable e, AstNode def, string kind
where def = definitionOf(e, kind)
select e, def, kind

View File

@@ -1,181 +0,0 @@
/**
* Provides classes and predicates related to jump-to-definition links
* in the code viewer.
*/
import javascript
import IDEContextual
private import Declarations.Declarations
/**
* Gets the kind of reference that `r` represents.
*
* References in callee position have kind `"M"` (for "method"), all
* others have kind `"V"` (for "variable").
*
* For example, in the expression `f(x)`, `f` has kind `"M"` while
* `x` has kind `"V"`.
*/
private string refKind(RefExpr r) {
if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference())
then result = "M"
else result = "V"
}
/**
* Gets a class, function or object literal `va` may refer to.
*/
private AstNode lookupDef(VarAccess va) {
exists(AbstractValue av | av = va.analyze().getAValue() |
result = av.(AbstractClass).getClass() or
result = av.(AbstractFunction).getFunction() or
result = av.(AbstractObjectLiteral).getObjectExpr()
)
}
/**
* Holds if `va` is of kind `kind` and `def` is the unique class,
* function or object literal it refers to.
*/
private predicate variableDefLookup(VarAccess va, AstNode def, string kind) {
count(lookupDef(va)) = 1 and
def = lookupDef(va) and
kind = refKind(va)
}
/**
* Holds if variable access `va` is of kind `kind` and refers to the
* variable declaration.
*
* For example, in the statement `var x = 42, y = x;`, the initializing
* expression of `y` is a variable access `x` of kind `"V"` that refers to
* the declaration `x = 42`.
*/
private predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) {
// restrict to declarations in same file to avoid accidentally picking up
// unrelated global definitions
decl = firstRefInTopLevel(va.getVariable(), Decl(), va.getTopLevel()) and
kind = refKind(va)
}
/**
* Holds if path expression `path`, which appears in a CommonJS `require`
* call or an ES 2015 import statement, imports module `target`; `kind`
* is always "I" (for "import").
*
* For example, in the statement `var a = require("./a")`, the path expression
* `"./a"` imports a module `a` in the same folder.
*/
private predicate importLookup(AstNode path, Module target, string kind) {
kind = "I" and
(
exists(Import i |
path = i.getImportedPath() and
target = i.getImportedModule()
)
or
exists(ReExportDeclaration red |
path = red.getImportedPath() and
target = red.getReExportedModule()
)
)
}
/**
* Gets a node that may write the property read by `prn`.
*/
private AstNode getAWrite(DataFlow::PropRead prn) {
exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName |
base = prn.getBase() and
propName = prn.getPropertyName() and
baseVal = base.getAValue().getAPrototype*()
|
// write to a property on baseVal
exists(AnalyzedPropertyWrite apw |
result = apw.getAstNode() and
apw.writes(baseVal, propName, _)
)
or
// non-static class members aren't covered by `AnalyzedPropWrite`, so have to be handled
// separately
exists(ClassDefinition c, MemberDefinition m |
m = c.getMember(propName) and
baseVal.(AbstractInstance).getConstructor().(AbstractClass).getClass() = c and
result = m.getNameExpr()
)
)
}
/**
* Holds if `prop` is the property name expression of a property read that
* may read the property written by `write`. Furthermore, `write` must be the
* only such property write. Parameter `kind` is always bound to `"M"`
* at the moment.
*/
private predicate propertyLookup(Expr prop, AstNode write, string kind) {
exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() |
count(getAWrite(prn)) = 1 and
write = getAWrite(prn) and
kind = "M"
)
}
/**
* Holds if `ref` is an identifier that refers to a type declared at `decl`.
*/
private predicate typeLookup(AstNode ref, AstNode decl, string kind) {
exists(TypeAccess typeAccess |
ref = typeAccess.getIdentifier() and
decl = typeAccess.getTypeName().getADefinition() and
kind = "T"
)
}
/**
* Holds if `ref` is the callee name of an invocation of `decl`.
*/
private predicate typedInvokeLookup(AstNode ref, AstNode decl, string kind) {
not variableDefLookup(ref, decl, _) and
not propertyLookup(ref, decl, _) and
exists(InvokeExpr invoke, Expr callee |
callee = invoke.getCallee().getUnderlyingReference() and
(ref = callee.(Identifier) or ref = callee.(DotExpr).getPropertyNameExpr()) and
decl = invoke.getResolvedCallee() and
kind = "M"
)
}
/**
* Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`.
*/
private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, AstNode decl, string kind) {
decl = ref.getClass().getAstNode() and
kind = "T"
}
/**
* 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 imports
*/
cached
AstNode definitionOf(Locatable e, string kind) {
variableDefLookup(e, result, kind)
or
// prefer definitions over declarations
not variableDefLookup(e, _, _) and variableDeclLookup(e, result, kind)
or
importLookup(e, result, kind)
or
propertyLookup(e, result, kind)
or
typeLookup(e, result, kind)
or
typedInvokeLookup(e, result, kind)
or
jsdocTypeLookup(e, result, kind)
}

View File

@@ -1,16 +0,0 @@
/**
* @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 js/ide-jump-to-definition
* @tags ide-contextual-queries/local-definitions
*/
import definitions
external string selectedSourceFile();
from Locatable e, AstNode def, string kind
where def = definitionOf(e, kind) and e.getFile() = getFileBySourceArchiveName(selectedSourceFile())
select e, def, kind

View File

@@ -1,17 +0,0 @@
/**
* @name Find-references links
* @description Generates use-definition pairs that provide the data
* for find-references in the code viewer.
* @kind definitions
* @id js/ide-find-references
* @tags ide-contextual-queries/local-references
*/
import definitions
external string selectedSourceFile();
from Locatable e, AstNode def, string kind
where
def = definitionOf(e, kind) and def.getFile() = getFileBySourceArchiveName(selectedSourceFile())
select e, def, kind

View File

@@ -1,28 +0,0 @@
/**
* @name Print AST
* @description Outputs a representation of a file's Abstract Syntax Tree. This
* query is used by the VS Code extension.
* @id js/print-ast
* @kind graph
* @tags ide-contextual-queries/print-ast
*/
import javascript
import semmle.javascript.PrintAst
import definitions
/**
* Gets 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 not a synthetic constructor.
*/
override predicate shouldPrint(Locatable e, Location l) {
super.shouldPrint(e, l) and
l.getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
}