mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
JS: Implement getAnUnderlyingType().
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import Customizations
|
||||
|
||||
import semmle.javascript.Aliases
|
||||
import semmle.javascript.AMD
|
||||
import semmle.javascript.AST
|
||||
|
||||
@@ -173,24 +173,24 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
result = getAReturnStmt().getExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Gets a return from a function which has undefined value (that is, implicit
|
||||
* returns and returns without expressions).
|
||||
*
|
||||
* Functions can have undefined returns in a few different ways:
|
||||
*
|
||||
*
|
||||
* 1. An explicit return statement with no expression (the statement `return;`)
|
||||
*
|
||||
*
|
||||
* 2. An implicit return resulting from an expression executing as the last thing
|
||||
* in the function. For example, the test in a final `if` statement:
|
||||
*
|
||||
*
|
||||
* ```
|
||||
* function foo() {
|
||||
* ...
|
||||
* if (test) { return 1; }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* Some things look like they might return undefined but actually don't because
|
||||
* the containing functioning doesn't return at all. For instance, `throw`
|
||||
* statements prevent the containing function from returning, so they don't count
|
||||
@@ -199,13 +199,12 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
* exclude yields entirely. Likewise, we exclude generator functions from
|
||||
* consideration, as well as asynchronous functions, since calls to both produce
|
||||
* something distinct from what's explicitly returned by the function.
|
||||
*
|
||||
*
|
||||
* Despite the fact that yield expressions are invalid outside of generators, we
|
||||
* include them anyway just to ensure that we're not relying on a perfect analysis
|
||||
* of a function to be a generator, and instead are looking also explicitly at the
|
||||
* return sites.
|
||||
*/
|
||||
|
||||
ConcreteControlFlowNode getAnUndefinedReturn() {
|
||||
not this.getBody() instanceof Expr and
|
||||
not this.isGenerator() and
|
||||
@@ -216,7 +215,7 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
result.getContainer() = this and
|
||||
result.isAFinalNode()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the function whose `this` binding a `this` expression in this function refers to,
|
||||
* which is the nearest enclosing non-arrow function.
|
||||
|
||||
@@ -154,21 +154,17 @@ class JSDocVoidTypeExpr extends @jsdoc_void_type_expr, JSDocTypeExpr {
|
||||
class JSDocNamedTypeExpr extends @jsdoc_named_type_expr, JSDocTypeExpr {
|
||||
/** Gets the name of the type the expression refers to. */
|
||||
string getName() { result = toString() }
|
||||
|
||||
override predicate isString() {
|
||||
getName() = "string"
|
||||
}
|
||||
|
||||
|
||||
override predicate isString() { getName() = "string" }
|
||||
|
||||
override predicate isStringy() {
|
||||
exists(string name | name = getName() |
|
||||
name = "string" or
|
||||
name = "String"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isNumber() {
|
||||
getName() = "number"
|
||||
}
|
||||
|
||||
override predicate isNumber() { getName() = "number" }
|
||||
|
||||
override predicate isNumbery() {
|
||||
exists(string name | name = getName() |
|
||||
@@ -182,9 +178,7 @@ class JSDocNamedTypeExpr extends @jsdoc_named_type_expr, JSDocTypeExpr {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBoolean() {
|
||||
getName() = "boolean"
|
||||
}
|
||||
override predicate isBoolean() { getName() = "boolean" }
|
||||
|
||||
override predicate isBooleany() {
|
||||
getName() = "boolean" or
|
||||
@@ -192,9 +186,7 @@ class JSDocNamedTypeExpr extends @jsdoc_named_type_expr, JSDocTypeExpr {
|
||||
getName() = "bool"
|
||||
}
|
||||
|
||||
override predicate isRawFunction() {
|
||||
getName() = "Function"
|
||||
}
|
||||
override predicate isRawFunction() { getName() = "Function" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +220,8 @@ class JSDocNullableTypeExpr extends @jsdoc_nullable_type_expr, JSDocTypeExpr {
|
||||
|
||||
/** Holds if the `?` operator of this type expression is written in prefix notation. */
|
||||
predicate isPrefix() { jsdoc_prefix_qualifier(this) }
|
||||
|
||||
override JSDocTypeExpr getAnUnderlyingType() { result = getTypeExpr().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,6 +233,8 @@ class JSDocNonNullableTypeExpr extends @jsdoc_non_nullable_type_expr, JSDocTypeE
|
||||
|
||||
/** Holds if the `!` operator of this type expression is written in prefix notation. */
|
||||
predicate isPrefix() { jsdoc_prefix_qualifier(this) }
|
||||
|
||||
override JSDocTypeExpr getAnUnderlyingType() { result = getTypeExpr().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,6 +273,8 @@ class JSDocArrayTypeExpr extends @jsdoc_array_type_expr, JSDocTypeExpr {
|
||||
class JSDocUnionTypeExpr extends @jsdoc_union_type_expr, JSDocTypeExpr {
|
||||
/** Gets one of the type alternatives of this union type. */
|
||||
JSDocTypeExpr getAnAlternative() { result = getChild(_) }
|
||||
|
||||
override JSDocTypeExpr getAnUnderlyingType() { result = getAnAlternative().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,6 +303,8 @@ class JSDocFunctionTypeExpr extends @jsdoc_function_type_expr, JSDocTypeExpr {
|
||||
class JSDocOptionalParameterTypeExpr extends @jsdoc_optional_type_expr, JSDocTypeExpr {
|
||||
/** Gets the underlying type of this optional type. */
|
||||
JSDocTypeExpr getUnderlyingType() { result = getChild(0) }
|
||||
|
||||
override JSDocTypeExpr getAnUnderlyingType() { result = getUnderlyingType().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,4 +67,12 @@ class TypeAnnotation extends @type_annotation {
|
||||
|
||||
/** Holds if this is the `const` keyword, occurring in a type assertion such as `x as const`. */
|
||||
predicate isConstKeyword() { none() }
|
||||
|
||||
/**
|
||||
* Repeatedly unfolds unions, intersections, parentheses, and nullability/readonly modifiers and gets any of the underlying types,
|
||||
* or this type itself if it cannot be unfolded.
|
||||
*
|
||||
* Note that this only unfolds the syntax of the type annotation. Type aliases are not followed to their definition.
|
||||
*/
|
||||
TypeAnnotation getAnUnderlyingType() { result = this }
|
||||
}
|
||||
|
||||
@@ -786,6 +786,8 @@ class UnionTypeExpr extends @uniontypeexpr, TypeExpr {
|
||||
|
||||
/** Gets the number of types in the union. This is always at least two. */
|
||||
int getNumElementType() { result = count(getAnElementType()) }
|
||||
|
||||
override TypeExpr getAnUnderlyingType() { result = getAnElementType().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -813,6 +815,8 @@ class IntersectionTypeExpr extends @intersectiontypeexpr, TypeExpr {
|
||||
|
||||
/** Gets the number of operands to the intersection type. This is always at least two. */
|
||||
int getNumElementType() { result = count(getAnElementType()) }
|
||||
|
||||
override TypeExpr getAnUnderlyingType() { result = getAnElementType().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -823,6 +827,8 @@ class ParenthesizedTypeExpr extends @parenthesizedtypeexpr, TypeExpr {
|
||||
TypeExpr getElementType() { result = getChildTypeExpr(0) }
|
||||
|
||||
override TypeExpr stripParens() { result = getElementType().stripParens() }
|
||||
|
||||
override TypeExpr getAnUnderlyingType() { result = getElementType().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -902,6 +908,8 @@ class IsTypeExpr extends @istypeexpr, TypeExpr {
|
||||
class OptionalTypeExpr extends @optionaltypeexpr, TypeExpr {
|
||||
/** Gets the type `T` in `T?` */
|
||||
TypeExpr getElementType() { result = getChildTypeExpr(0) }
|
||||
|
||||
override TypeExpr getAnUnderlyingType() { result = getElementType().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -921,6 +929,8 @@ class RestTypeExpr extends @resttypeexpr, TypeExpr {
|
||||
class ReadonlyTypeExpr extends @readonlytypeexpr, TypeExpr {
|
||||
/** Gets the type `T` in `readonly T`. */
|
||||
TypeExpr getElementType() { result = getChildTypeExpr(0) }
|
||||
|
||||
override TypeExpr getAnUnderlyingType() { result = getElementType().getAnUnderlyingType() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user