Merge pull request #3297 from asger-semmle/js/isambient-refactor

Approved by esbena
This commit is contained in:
semmle-qlci
2020-04-21 09:36:14 +01:00
committed by GitHub
6 changed files with 50 additions and 47 deletions

View File

@@ -125,6 +125,42 @@ class ASTNode extends @ast_node, Locatable {
/** Holds if this syntactic entity belongs to an externs file. */ /** Holds if this syntactic entity belongs to an externs file. */
predicate inExternsFile() { getTopLevel().isExterns() } predicate inExternsFile() { getTopLevel().isExterns() }
/**
* Holds if this is an ambient node that is not a `TypeExpr` and is not inside a `.d.ts` file
*
* Since the overwhelming majority of ambient nodes are `TypeExpr` or inside `.d.ts` files,
* we avoid caching them.
*/
cached
private predicate isAmbientInternal() {
getParent().isAmbientInternal()
or
not isAmbientTopLevel(getTopLevel()) and
(
this instanceof ExternalModuleDeclaration
or
this instanceof GlobalAugmentationDeclaration
or
this instanceof ExportAsNamespaceDeclaration
or
this instanceof TypeAliasDeclaration
or
this instanceof InterfaceDeclaration
or
hasDeclareKeyword(this)
or
hasTypeKeyword(this)
or
// An export such as `export declare function f()` should be seen as ambient.
hasDeclareKeyword(this.(ExportNamedDeclaration).getOperand())
or
exists(Function f |
this = f and
not f.hasBody()
)
)
}
/** /**
* Holds if this is part of an ambient declaration or type annotation in a TypeScript file. * Holds if this is part of an ambient declaration or type annotation in a TypeScript file.
* *
@@ -134,8 +170,21 @@ class ASTNode extends @ast_node, Locatable {
* The TypeScript compiler emits no code for ambient declarations, but they * The TypeScript compiler emits no code for ambient declarations, but they
* can affect name resolution and type checking at compile-time. * can affect name resolution and type checking at compile-time.
*/ */
predicate isAmbient() { getParent().isAmbient() } pragma[inline]
predicate isAmbient() {
isAmbientInternal()
or
isAmbientTopLevel(getTopLevel())
or
this instanceof TypeExpr
} }
}
/**
* Holds if the given file is a `.d.ts` file.
*/
cached
private predicate isAmbientTopLevel(TopLevel tl) { tl.getFile().getBaseName().matches("%.d.ts") }
/** /**
* A toplevel syntactic unit; that is, a stand-alone script, an inline script * A toplevel syntactic unit; that is, a stand-alone script, an inline script
@@ -197,11 +246,6 @@ class TopLevel extends @toplevel, StmtContainer {
override ControlFlowNode getFirstControlFlowNode() { result = getEntry() } override ControlFlowNode getFirstControlFlowNode() { result = getEntry() }
override string toString() { result = "<toplevel>" } override string toString() { result = "<toplevel>" }
override predicate isAmbient() {
getFile().getFileType().isTypeScript() and
getFile().getBaseName().matches("%.d.ts")
}
} }
/** /**

View File

@@ -1059,12 +1059,6 @@ class FieldDeclaration extends MemberDeclaration, @field {
/** Holds if this is a TypeScript field marked as definitely assigned with the `!` operator. */ /** Holds if this is a TypeScript field marked as definitely assigned with the `!` operator. */
predicate hasDefiniteAssignmentAssertion() { hasDefiniteAssignmentAssertion(this) } predicate hasDefiniteAssignmentAssertion() { hasDefiniteAssignmentAssertion(this) }
override predicate isAmbient() {
hasDeclareKeyword(this)
or
getParent().isAmbient()
}
} }
/** /**

View File

@@ -79,11 +79,6 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration {
/** Holds if this is declared with the `type` keyword, so it only imports types. */ /** Holds if this is declared with the `type` keyword, so it only imports types. */
predicate isTypeOnly() { hasTypeKeyword(this) } predicate isTypeOnly() { hasTypeKeyword(this) }
override predicate isAmbient() {
Stmt.super.isAmbient() or
isTypeOnly()
}
} }
/** A literal path expression appearing in an `import` declaration. */ /** A literal path expression appearing in an `import` declaration. */
@@ -267,11 +262,6 @@ abstract class ExportDeclaration extends Stmt, @exportdeclaration {
/** Holds if is declared with the `type` keyword, so only types are exported. */ /** Holds if is declared with the `type` keyword, so only types are exported. */
predicate isTypeOnly() { hasTypeKeyword(this) } predicate isTypeOnly() { hasTypeKeyword(this) }
override predicate isAmbient() {
Stmt.super.isAmbient() or
isTypeOnly()
}
} }
/** /**
@@ -422,11 +412,6 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration
/** Gets an export specifier of this declaration. */ /** Gets an export specifier of this declaration. */
ExportSpecifier getASpecifier() { result = getSpecifier(_) } ExportSpecifier getASpecifier() { result = getSpecifier(_) }
override predicate isAmbient() {
// An export such as `export declare function f()` should be seen as ambient.
hasDeclareKeyword(getOperand()) or getParent().isAmbient()
}
} }
/** /**

View File

@@ -397,8 +397,6 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
*/ */
predicate isAbstract() { exists(MethodDeclaration md | this = md.getBody() | md.isAbstract()) } predicate isAbstract() { exists(MethodDeclaration md | this = md.getBody() | md.isAbstract()) }
override predicate isAmbient() { getParent().isAmbient() or not hasBody() }
/** /**
* Holds if this function cannot be invoked using `new` because it * Holds if this function cannot be invoked using `new` because it
* is of the given `kind`. * is of the given `kind`.

View File

@@ -54,8 +54,6 @@ class Stmt extends @stmt, ExprOrStmt, Documentable {
getContainer().(Expr).getEnclosingStmt().nestedIn(outer) getContainer().(Expr).getEnclosingStmt().nestedIn(outer)
} }
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
/** /**
* Gets the `try` statement with a catch block containing this statement without * Gets the `try` statement with a catch block containing this statement without
* crossing function boundaries or other `try ` statements with catch blocks. * crossing function boundaries or other `try ` statements with catch blocks.
@@ -931,8 +929,6 @@ class DebuggerStmt extends @debuggerstmt, Stmt {
*/ */
class FunctionDeclStmt extends @functiondeclstmt, Stmt, Function { class FunctionDeclStmt extends @functiondeclstmt, Stmt, Function {
override Stmt getEnclosingStmt() { result = this } override Stmt getEnclosingStmt() { result = this }
override predicate isAmbient() { Function.super.isAmbient() }
} }
/** /**

View File

@@ -155,8 +155,6 @@ class ExternalModuleDeclaration extends Stmt, StmtContainer, @externalmoduledecl
int getNumStmt() { result = count(getAStmt()) } int getNumStmt() { result = count(getAStmt()) }
override StmtContainer getEnclosingContainer() { result = this.getContainer() } override StmtContainer getEnclosingContainer() { result = this.getContainer() }
override predicate isAmbient() { any() }
} }
/** /**
@@ -176,8 +174,6 @@ class GlobalAugmentationDeclaration extends Stmt, StmtContainer, @globalaugmenta
int getNumStmt() { result = count(getAStmt()) } int getNumStmt() { result = count(getAStmt()) }
override StmtContainer getEnclosingContainer() { result = this.getContainer() } override StmtContainer getEnclosingContainer() { result = this.getContainer() }
override predicate isAmbient() { any() }
} }
/** A TypeScript "import-equals" declaration. */ /** A TypeScript "import-equals" declaration. */
@@ -237,8 +233,6 @@ class ExportAsNamespaceDeclaration extends Stmt, @exportasnamespacedeclaration {
* Gets the `X` in `export as namespace X`. * Gets the `X` in `export as namespace X`.
*/ */
Identifier getIdentifier() { result = getChildExpr(0) } Identifier getIdentifier() { result = getChildExpr(0) }
override predicate isAmbient() { any() }
} }
/** /**
@@ -259,8 +253,6 @@ class TypeAliasDeclaration extends @typealiasdeclaration, TypeParameterized, Stm
override string describe() { result = "type alias " + getName() } override string describe() { result = "type alias " + getName() }
override predicate isAmbient() { any() }
/** /**
* Gets the canonical name of the type being defined. * Gets the canonical name of the type being defined.
*/ */
@@ -286,8 +278,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat
override StmtContainer getContainer() { result = Stmt.super.getContainer() } override StmtContainer getContainer() { result = Stmt.super.getContainer() }
override predicate isAmbient() { any() }
override string describe() { result = "interface " + getName() } override string describe() { result = "interface " + getName() }
/** /**
@@ -533,8 +523,6 @@ class LocalNamespaceName extends @local_namespace_name, LexicalName {
class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation { class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
override string toString() { typeexprs(this, _, _, _, result) } override string toString() { typeexprs(this, _, _, _, result) }
override predicate isAmbient() { any() }
/** /**
* Gets the static type expressed by this type annotation. * Gets the static type expressed by this type annotation.
* *
@@ -1410,8 +1398,6 @@ class EnumDeclaration extends NamespaceDefinition, @enumdeclaration, AST::ValueN
/** Holds if this enumeration is declared with the `const` keyword. */ /** Holds if this enumeration is declared with the `const` keyword. */
predicate isConst() { isConstEnum(this) } predicate isConst() { isConstEnum(this) }
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
override ControlFlowNode getFirstControlFlowNode() { result = getIdentifier() } override ControlFlowNode getFirstControlFlowNode() { result = getIdentifier() }
} }