Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
60baec6
unified: Add test showing problem with literal getValue()
asgerf Aug 6, 2026
51fe273
unified: Fix extraction of literals
asgerf Aug 6, 2026
b71ff8f
unified: Factor some code into CommentUtil.qll
asgerf Aug 6, 2026
c9fc793
unified: Fix mapping for compound type names
asgerf Aug 6, 2026
f50c80a
unified: Initial static name binding pass
asgerf Aug 6, 2026
375924e
unified: Track through aliases
asgerf Aug 6, 2026
db8b97a
unified: Add inheritance steps
asgerf Aug 6, 2026
6341bba
unified: Support unqualified access
asgerf Aug 6, 2026
ee8753b
unified: Allow numbers in key=value comments
asgerf Aug 6, 2026
7e3a4e3
unified: Cross-file name binding
asgerf Aug 6, 2026
574a5c9
unified: Handle bracketed generic array constructors
asgerf Aug 7, 2026
55b96f1
unified: Handle bracketed generic array metatypes
asgerf Aug 7, 2026
171aa7a
unified: Use '.' as location for inferred_type_expr
asgerf Aug 7, 2026
a9792e5
unified: Fix handling of exprPattern
asgerf Aug 7, 2026
8080bac
unified: Add newlines at EOF
asgerf Aug 7, 2026
0cf2871
unified: Update comment
asgerf Aug 7, 2026
a3f21a5
unified: Support scoped imports
asgerf Aug 7, 2026
50f934b
unified: Don't track trivial name aliasse
asgerf Aug 7, 2026
a79c32a
unified: Bulk imports
asgerf Aug 7, 2026
05fe395
unified: Fix access level in test case
asgerf Aug 7, 2026
659da08
unified: Fix incorrect expectation
asgerf Aug 7, 2026
35c54b1
unified: Fix toString and getLocation for TLocalNamespace
asgerf Aug 7, 2026
af2f5a2
unified: Remove location of TModuleRoot
asgerf Aug 7, 2026
970e4c6
unified: Fix handling of unscoped imports
asgerf Aug 7, 2026
f596a67
unified: Fix Swift source folder documentation
asgerf Aug 10, 2026
d6164c3
unified: Preserve array constructor trailing closures
asgerf Aug 10, 2026
a658c77
unified: Add test showing AST mapping error
asgerf Aug 11, 2026
c58a096
unified: Fix translation of callee in constructor pattern
asgerf Aug 11, 2026
3999894
unified: Clarify description of derivedStoreReadStep
asgerf Aug 13, 2026
e88dde7
unified: Make debug graph subset more configurable
asgerf Aug 13, 2026
d30b7a0
unified: Simplify uncertain scopes
asgerf Aug 13, 2026
e23f3e4
unified: Don't step into declaration sites
asgerf Aug 13, 2026
bec213b
shared: Factor out declInScope(name, scope)
asgerf Aug 13, 2026
4eade9e
shared: Rephrase a qldoc
asgerf Aug 13, 2026
828816c
unified: QLdoc fix
asgerf Aug 13, 2026
78671cd
unified: Prefer 'and' instead of '|'
asgerf Aug 13, 2026
5d7e64e
unified: Add test with @_exported import
asgerf Aug 13, 2026
61b3720
unified: Support @_exported imports
asgerf Aug 13, 2026
811932f
unified: Add test for spurious re-export
asgerf Aug 13, 2026
1f380d2
unified: Fix spurious resolution by refining isPrivateToLocalScope
asgerf Aug 13, 2026
719e8b4
unified: Prefer instanceof
asgerf Aug 13, 2026
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
29 changes: 29 additions & 0 deletions shared/namebinding/codeql/namebinding/LocalNameBinding.qll
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ signature module LocalNameBindingInputSig<LocationSig Location> {
* full control of scope resolution for specific types of references.
*/
default predicate lookupStartsAt(AstNode n, AstNode scope) { none() }

/**
* Holds if the set of names available in `scope` is not known ahead of time,
* and thus any lookup chain that goes through `scope` may need to be reconciled at a later stage.
*/
default predicate uncertainScope(AstNode scope) { none() }
}

/**
Expand All @@ -154,6 +160,8 @@ module LocalNameBinding<LocationSig Location, LocalNameBindingInputSig<Location>
implicitDeclInScope(_, this)
or
isTopScope(this)
or
uncertainScope(this)
}
}

Expand Down Expand Up @@ -353,6 +361,27 @@ module LocalNameBinding<LocationSig Location, LocalNameBindingInputSig<Location>
)
}

/**
* Holds if `name`, when resolved from `lookup`, may resolve to one of the uncertain members of `scope`.
*/
pragma[nomagic]
private predicate lookupInUncertainScope(string name, Scope lookup, Scope scope) {
lookupInScope(name, lookup, scope) and
uncertainScope(scope) and
not declInScope(_, name, scope) and
not implicitDeclInScope(name, scope)
Comment thread
hvitved marked this conversation as resolved.
Outdated
}

/**
* Gets an uncertain scope that the given `accessCand` pair may resolve to.
Comment thread
hvitved marked this conversation as resolved.
Outdated
*/
AstNode getAnUncertainScope(AstNode access, string name) {
exists(Scope lookup |
accessCandInLookupScope(access, name, lookup) and
lookupInUncertainScope(name, lookup, result)
)
}

cached
private newtype TLocal =
TExplicitLocal(AstNode definingNode, string name, AstNode scope) {
Expand Down
22 changes: 13 additions & 9 deletions unified/extractor/src/languages/swift/swift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,12 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// swift-syntax does not distinguish the lexical integer/string forms
// (hex/binary/octal, single- vs multi-line, raw): each is a single
// `*LiteralExpr` kind, so one rule per literal type suffices.
rule!((integerLiteralExpr) => (int_literal)),
rule!((floatLiteralExpr) => (float_literal)),
rule!((booleanLiteralExpr) => (boolean_literal)),
rule!((nilLiteralExpr) => (builtin_expr)),
rule!((stringLiteralExpr) => (string_literal)),
rule!((regexLiteralExpr) => (regex_literal)),
rule!((integerLiteralExpr) @@node => (int_literal #{node})),
rule!((floatLiteralExpr) @@node => (float_literal #{node})),
rule!((booleanLiteralExpr) @@node => (boolean_literal #{node})),
rule!((nilLiteralExpr) @@node => (builtin_expr #{node})),
rule!((stringLiteralExpr) @@node => (string_literal #{node})),
rule!((regexLiteralExpr) @@node => (regex_literal #{node})),
// ---- Names ----
// A function reference spelled with argument labels (`f(x:y:z:)`) is a
// `declReferenceExpr` carrying `argumentNames`. Mark it unsupported for
Expand Down Expand Up @@ -1014,9 +1014,13 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// A named type (`Int`). `identifierType.name` is the type-name token.
rule!((identifierType name: @@n) => (named_type_expr name: (identifier #{n}))),
// A qualified type (`Outer.Inner`, `NSString.CompareOptions`). swift-syntax
// nests these as `memberType` nodes; we keep the whole dotted path as the
// opaque `named_type_expr` name.
rule!((memberType) @ty => (named_type_expr name: (identifier #{ty}))),
// nests these as `memberType` nodes; preserve the nesting in the
// named_type_expr qualifier field.
rule!(
(memberType baseType: @base name: @@name)
=>
(named_type_expr qualifier: {base} name: (identifier #{name}))
),
// Sugared types desugar to `generic_type_expr`: `T?` -> Optional<T>,
// `[T]` -> Array<T>, `[K: V]` -> Dictionary<K, V>.
rule!(
Expand Down
139 changes: 139 additions & 0 deletions unified/extractor/tests/corpus/swift/types/qualified-type.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
struct Outer {
struct Inner {
struct Deep {}
}
}

let value: Outer.Inner
let nested: Outer.Inner.Deep

---

sourceFile
endOfFileToken: endOfFile
statements:
codeBlockItem
item:
structDecl
attributes:
name: identifier "Outer"
memberBlock:
memberBlock
leftBrace: {
rightBrace: }
members:
memberBlockItem
decl:
structDecl
attributes:
name: identifier "Inner"
memberBlock:
memberBlock
leftBrace: {
rightBrace: }
members:
memberBlockItem
decl:
structDecl
attributes:
name: identifier "Deep"
memberBlock:
memberBlock
leftBrace: {
rightBrace: }
members:
modifiers:
structKeyword: struct
modifiers:
structKeyword: struct
modifiers:
structKeyword: struct
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
pattern:
identifierPattern
identifier: identifier "value"
typeAnnotation:
typeAnnotation
colon: :
type:
memberType
name: identifier "Inner"
baseType:
identifierType
name: identifier "Outer"
period: .
codeBlockItem
item:
variableDecl
attributes:
modifiers:
bindingSpecifier: let
bindings:
patternBinding
pattern:
identifierPattern
identifier: identifier "nested"
typeAnnotation:
typeAnnotation
colon: :
type:
memberType
name: identifier "Deep"
baseType:
memberType
name: identifier "Inner"
baseType:
identifierType
name: identifier "Outer"
period: .
period: .

---

top_level
body:
block
stmt:
class_like_declaration
modifier: modifier "struct"
name: identifier "Outer"
member:
class_like_declaration
modifier: modifier "struct"
name: identifier "Inner"
member:
class_like_declaration
modifier: modifier "struct"
name: identifier "Deep"
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "value"
type:
named_type_expr
qualifier:
named_type_expr
name: identifier "Outer"
name: identifier "Inner"
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "nested"
type:
named_type_expr
qualifier:
named_type_expr
qualifier:
named_type_expr
name: identifier "Outer"
name: identifier "Inner"
name: identifier "Deep"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
struct Outer {
struct Inner {
struct Deep {}
}
}

let value: Outer.Inner
let nested: Outer.Inner.Deep
8 changes: 8 additions & 0 deletions unified/ql/lib/codeql/unified/internal/FacadeAst.qll
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ module Unified {
mod.getValue() = text
)
}

/** Gets the nearest enclosing class declaration, possibly this node itself. */
ClassLikeDeclaration getEnclosingClass() {
result = this
or
not this instanceof ClassLikeDeclaration and
result = this.getParent().getEnclosingClass()
}
}

/** The base class for all patterns. */
Expand Down
Loading