mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +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:
@@ -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()
|
||||
)
|
||||
}
|
||||
@@ -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("//", "/")
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user