Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions unified/extractor/ast_types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ supertypes:
- switch_expr
- unresolved_operator_sequence
- unsupported_node
- unhandled_node
- or_pattern
- conditional_pattern
- bulk_importing_pattern
Expand Down Expand Up @@ -84,6 +85,7 @@ supertypes:
- type_alias_declaration
- associated_type_declaration
- unsupported_node
- unhandled_node
type_constraint:
- equality_type_constraint
- bound_type_constraint
Expand Down Expand Up @@ -421,6 +423,9 @@ named:
# A node that we don't yet translate
unsupported_node:

# A node kind that has no explicit translation or unsupported classification
unhandled_node:

infix_operator:

prefix_operator:
Expand Down
130 changes: 85 additions & 45 deletions unified/extractor/src/languages/swift/swift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
vec![
// ---- Top-level ----
// These rules translate the swift-syntax AST (camelCase kind names),
// produced by the sibling `adapter` module from the `swift-syntax-parse`
// binary's JSON. Anything unmatched falls through to the
// `unsupported_node` fallback at the end.
// produced by the sibling `adapter` module from swift-syntax JSON.
// Known kinds without dedicated rules become `unsupported_node`;
// genuinely unknown kinds become `unhandled_node`.
//
// `sourceFile` holds its top-level statements in an (elided)
// `statements` collection; each element is a `codeBlockItem` wrapping
Expand Down Expand Up @@ -198,13 +198,13 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
=>
(unsupported_node)
),
rule!((declReferenceExpr baseName: (identifier) @name) => expr {
rule!((declReferenceExpr baseName: (identifier) @@name) => expr {
tree!((identifier #{name}))
}),
// A bare name reference (`x`), and an operator used as a value (`+` in
// `reduce(0, +)`), are both `declReferenceExpr`; its `baseName` is the
// referenced identifier / operator symbol.
rule!((declReferenceExpr baseName: @name) => (identifier #{name})),
rule!((declReferenceExpr baseName: @@name) => (identifier #{name})),
// A discard `_` used as an expression — e.g. the target of a discarding
// assignment `_ = x`. swift-syntax models it as a `discardAssignmentExpr`.
rule!((discardAssignmentExpr wildcard: @@w) => (ignore_pattern #{w})),
Expand All @@ -215,7 +215,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// `generic_type_expr`, so we map it directly to that shape.
rule!(
(genericSpecializationExpr
expression: (declReferenceExpr baseName: @name)
expression: (declReferenceExpr baseName: @@name)
genericArgumentClause: (genericArgumentClause arguments: (genericArgument argument: @args)*))
=>
(generic_type_expr
Expand All @@ -230,7 +230,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// A `binaryOperatorExpr` wraps the operator token; unwrap it to the
// operator leaf. Used by `infixOperatorExpr` (folded) and `sequenceExpr`
// (unresolved).
rule!((binaryOperatorExpr operator: @op) => (infix_operator #{op})),
rule!((binaryOperatorExpr operator: @@op) => (infix_operator #{op})),
// A `binaryOperator`-based `infixOperatorExpr` represents both ordinary
// binary applications (`a + b`) and compound assignments (`x += y`).
// Both have the same target AST shape; the QL library distinguishes
Expand Down Expand Up @@ -276,7 +276,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// infix operators, rather than guessing a structure.
rule!((sequenceExpr elements: _* @els) => (unresolved_operator_sequence element: {els})),
// Prefix unary operators (`!a`, `-x`).
rule!((prefixOperatorExpr operator: @op expression: @operand) => (unary_expr operator: (prefix_operator #{op}) operand: {operand})),
rule!((prefixOperatorExpr operator: @@op expression: @operand) => (unary_expr operator: (prefix_operator #{op}) operand: {operand})),
// A parenthesised expression has a single tuple element; elide the
// grouping and preserve the expression itself. Actual tuple literals
// retain their translated labeled elements as `argument` children.
Expand Down Expand Up @@ -468,7 +468,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// `chained_declaration` tag.
rule!(
(enumCaseElement
name: @name
name: @@name
parameterClause: (enumCaseParameterClause parameters: _* @params) @@clause)
=>
class_like_declaration {
Expand All @@ -486,7 +486,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
}
),
rule!(
(enumCaseElement name: @name rawValue: (initializerClause value: @val))
(enumCaseElement name: @@name rawValue: (initializerClause value: @val))
=>
(variable_declaration
modifier: {ctx.outer_modifiers.clone()}
Expand All @@ -496,7 +496,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
value: {val})
),
rule!(
(enumCaseElement name: @name)
(enumCaseElement name: @@name)
=>
(variable_declaration
modifier: {ctx.outer_modifiers.clone()}
Expand Down Expand Up @@ -526,7 +526,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
),
// `identifierPattern` wraps a single identifier token.
rule!(
(identifierPattern identifier: @name)
(identifierPattern identifier: @@name)
=>
(identifier #{name})
),
Expand Down Expand Up @@ -574,7 +574,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!(
(functionDecl
modifiers: _* @mods
name: @name
name: @@name
genericParameterClause: (genericParameterClause parameters: _* @type_params)?
signature: (functionSignature
parameterClause: (functionParameterClause parameters: _* @params)
Expand All @@ -592,7 +592,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!(
(functionDecl
modifiers: _* @mods
name: @name
name: @@name
genericParameterClause: (genericParameterClause parameters: _* @type_params)?
signature: (functionSignature
parameterClause: (functionParameterClause parameters: _* @params)
Expand Down Expand Up @@ -715,7 +715,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
(memberAccessExpr
base: (arrayExpr
elements: (arrayElement expression: (genericSpecializationExpr) @element)) @@array
declName: (declReferenceExpr baseName: @member))
declName: (declReferenceExpr baseName: @@member))
=>
member_access_expr {
let base = tree_at!(
Expand All @@ -731,12 +731,12 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
}
),
rule!(
(memberAccessExpr base: @base declName: (declReferenceExpr baseName: @member))
(memberAccessExpr base: @base declName: (declReferenceExpr baseName: @@member))
=>
(member_access_expr base: {base} member_name_node: (identifier #{member}))
),
rule!(
(memberAccessExpr period: @dot declName: (declReferenceExpr baseName: @member))
(memberAccessExpr period: @@dot declName: (declReferenceExpr baseName: @@member))
=>
(member_access_expr base: (inferred_type_expr #{dot}) member_name_node: (identifier #{member}))
),
Expand Down Expand Up @@ -790,14 +790,14 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// A closure parameter (`x: Int`, or just `x`). Unlike a function
// parameter it has no external label; the type is optional.
rule!(
(closureParameter firstName: @name type: _? @ty)
(closureParameter firstName: @@name type: _? @ty)
=>
(parameter pattern: (identifier #{name}) type: {ty})
),
// A shorthand closure parameter (`x` in `{ x, y in … }`): a bare name
// with no parentheses and no type.
rule!(
(closureShorthandParameter name: @name)
(closureShorthandParameter name: @@name)
=>
(parameter pattern: (identifier #{name}))
),
Expand Down Expand Up @@ -872,7 +872,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!(
(optionalBindingCondition
bindingSpecifier: @@spec
pattern: (identifierPattern identifier: @name)
pattern: (identifierPattern identifier: @@name)
initializer: (initializerClause value: @val))
=>
(pattern_guard_expr
Expand All @@ -886,7 +886,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!(
(optionalBindingCondition
bindingSpecifier: @@spec
pattern: (identifierPattern identifier: @name))
pattern: (identifierPattern identifier: @@name))
=>
(pattern_guard_expr
value: (identifier #{name})
Expand Down Expand Up @@ -1091,7 +1091,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!((declModifier) @m => (modifier #{m})),
// Preserve the `super` keyword as a dedicated expression, normally used
// as the base of a member access (`super.foo`).
rule!((superExpr superKeyword: @keyword) => (super_expr #{keyword})),
rule!((superExpr superKeyword: @@keyword) => (super_expr #{keyword})),
// Type expressions. A generic type applied with explicit arguments
// (`Set<Int>`) becomes a `generic_type_expr` whose `base` is the type
// name and whose `type_argument`s are the (structured) arguments — the
Expand Down Expand Up @@ -1213,9 +1213,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// Class declaration with body containing members
rule!(
(classDecl
classKeyword: @kind
classKeyword: @@kind
modifiers: _* @mods
name: @name
name: @@name
genericParameterClause: (genericParameterClause
parameters: _* @params
genericWhereClause: (genericWhereClause requirements: _* @parameter_constraints)?)?
Expand All @@ -1236,9 +1236,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// Enum class declaration: same as a regular class but with an enum body.
rule!(
(enumDecl
enumKeyword: @kind
enumKeyword: @@kind
modifiers: _* @mods
name: @name
name: @@name
genericParameterClause: (genericParameterClause
parameters: _* @params
genericWhereClause: (genericWhereClause requirements: _* @parameter_constraints)?)?
Expand All @@ -1259,9 +1259,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// A `struct` declaration.
rule!(
(structDecl
structKeyword: @kind
structKeyword: @@kind
modifiers: _* @mods
name: @name
name: @@name
genericParameterClause: (genericParameterClause
parameters: _* @params
genericWhereClause: (genericWhereClause requirements: _* @parameter_constraints)?)?
Expand All @@ -1282,9 +1282,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// Protocol declaration
rule!(
(protocolDecl
protocolKeyword: @kind
protocolKeyword: @@kind
modifiers: _* @mods
name: @name
name: @@name
genericParameterClause: (genericParameterClause parameters: _* @params)?
inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)?
genericWhereClause: (genericWhereClause requirements: _* @declaration_constraints)?
Expand All @@ -1302,7 +1302,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// An `extension Foo.Bar { … }` is likewise a `class_like_declaration`.
rule!(
(extensionDecl
extensionKeyword: @kind
extensionKeyword: @@kind
modifiers: _* @mods
extendedType: @extendedType
inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)?
Expand All @@ -1322,7 +1322,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// nest under `signature` (as for `functionDecl`).
rule!(
(initializerDecl
initKeyword: @initK
initKeyword: @@initK
modifiers: _* @mods
signature: (functionSignature
parameterClause: (functionParameterClause parameters: _* @params))
Expand All @@ -1336,7 +1336,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
),
rule!(
(initializerDecl
initKeyword: @initK
initKeyword: @@initK
modifiers: _* @mods
signature: (functionSignature
parameterClause: (functionParameterClause parameters: _* @params)))
Expand Down Expand Up @@ -1383,18 +1383,58 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
name_node: (identifier #{name})
bound: {bound})
),
// ---- Fallbacks ----
// Bare `_` (rather than `(_)`) so this matches both named nodes
// and unnamed tokens. Any unnamed token that escapes the
// input-schema-specific rules (e.g. captured operators in
// `additive_expression op: @op`) has its auto-translated value
// replaced with an `unsupported_node` whose source range is
// inherited from the original token, so `#{op}` still reads the
// original text.
rule!(
_
=>
(unsupported_node)
// ---- Explicitly unsupported roots ----
// These kinds can reach translation independently, but we do not
// currently map them to the unified AST. Syntax nested inside one of
// these roots is discarded with its parent and needs no separate rule.
rule!((actorDecl) => (unsupported_node)),
rule!((attributedType) => (unsupported_node)),
rule!((borrowExpr) => (unsupported_node)),
rule!((classRestrictionType) => (unsupported_node)),
rule!((compositionType) => (unsupported_node)),
rule!((consumeExpr) => (unsupported_node)),
rule!((copyExpr) => (unsupported_node)),
rule!((deferStmt) => (unsupported_node)),
rule!((discardStmt) => (unsupported_node)),
rule!((fallThroughStmt) => (unsupported_node)),
rule!((ifConfigDecl) => (unsupported_node)),
rule!((implicitlyUnwrappedOptionalType) => (unsupported_node)),
rule!((inOutExpr) => (unsupported_node)),
rule!((inlineArrayType) => (unsupported_node)),
rule!((keyPathExpr) => (unsupported_node)),
rule!((macroDecl) => (unsupported_node)),
rule!((metatypeType) => (unsupported_node)),
rule!((namedOpaqueReturnType) => (unsupported_node)),
rule!((operatorDecl) => (unsupported_node)),
rule!((packElementExpr) => (unsupported_node)),
rule!((packElementType) => (unsupported_node)),
rule!((packExpansionExpr) => (unsupported_node)),
rule!((packExpansionType) => (unsupported_node)),
rule!((postfixIfConfigExpr) => (unsupported_node)),
rule!((postfixOperatorExpr) => (unsupported_node)),
rule!((poundSourceLocation) => (unsupported_node)),
rule!((precedenceGroupDecl) => (unsupported_node)),
rule!((someOrAnyType) => (unsupported_node)),
rule!((subscriptDecl) => (unsupported_node)),
rule!((suppressedType) => (unsupported_node)),
rule!((typeExpr) => (unsupported_node)),
rule!((unsafeExpr) => (unsupported_node)),
rule!((yieldStmt) => (unsupported_node)),
// Anything reaching this final generic handler has neither a
// dedicated rule nor an explicit unsupported entry.
rule!(
_ @@node
=>
unhandled_node {
let input = ctx.ast.get_node(node).expect("matched node must exist");
tracing::error!(
target: "unified_extractor",
node_kind = input.kind_name(),
source_range = ?input.source_range(),
"Unhandled Swift syntax node reached translation"
);
tree!((unhandled_node))
}
),
]
}
Expand Down
8 changes: 8 additions & 0 deletions unified/ql/lib/codeql/unified/internal/Ast.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,12 @@ module Unified {
}
}

/** A class representing `unhandled_node` tokens. */
class UnhandledNode extends @unified_token_unhandled_node, F::Expr, F::Member, F::Token {
/** Gets the name of the primary QL class for this element. */
final override string getAPrimaryQlClass() { result = "UnhandledNode" }
}

/** A class representing `unresolved_operator_sequence` nodes. */
class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, F::Expr {
/** Gets the name of the primary QL class for this element. */
Expand Down Expand Up @@ -1976,6 +1982,8 @@ module UnifiedFinal {

final class UnaryExpr = F::UnaryExpr;

final class UnhandledNode = F::UnhandledNode;

final class UnresolvedOperatorSequence = F::UnresolvedOperatorSequence;

final class UnsupportedNode = F::UnsupportedNode;
Expand Down
Loading
Loading