Skip to content

Commit d401b96

Browse files
committed
unified: Let bindingContext dictate resolution for name bindings
1 parent e31ab54 commit d401b96

3 files changed

Lines changed: 25 additions & 12 deletions

File tree

‎shared/namebinding/codeql/namebinding/LocalNameBinding.qll‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,12 @@ module LocalNameBinding<LocationSig Location, LocalNameBindingInputSig<Location>
449449

450450
/** Gets a textual representation of this local entity. */
451451
string toString() { result = this.getName() }
452+
453+
/** Holds if this variable has the given name and scope. */
454+
pragma[nomagic]
455+
predicate hasNameAndScope(string name, AstNode scope) {
456+
this = TExplicitLocal(_, name, scope) or this = TImplicitLocal(name, scope)
457+
}
452458
}
453459

454460
final class Local = LocalImpl;
@@ -484,10 +490,6 @@ module LocalNameBinding<LocationSig Location, LocalNameBindingInputSig<Location>
484490
override string getName() { result = name }
485491

486492
override Location getLocation() { result = scope.getLocation() }
487-
488-
/** Holds if this variable has the given name and scope. */
489-
pragma[nomagic]
490-
predicate hasNameAndScope(string name_, AstNode scope_) { name = name_ and scope = scope_ }
491493
}
492494

493495
/** A local access. */

‎unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,17 @@ predicate bindingContext = LocalNameBindingInput::bindingContext/3;
347347

348348
module LocalNameBindingOutput = LocalNameBinding<Location, LocalNameBindingInput>;
349349

350+
private LocalNameBindingOutput::Local resolveId(Identifier id) {
351+
// For names in binding position, always resolve to the scope set by the bindingContext predicate
352+
exists(AstNode scope |
353+
bindingContext(id, scope, _) and
354+
result.hasNameAndScope(id.getValue(), scope)
355+
)
356+
or
357+
not bindingContext(id, _, _) and
358+
result = id.(LocalNameBindingOutput::LocalAccess).getLocal()
359+
}
360+
350361
module Public {
351362
/**
352363
* A representative for a lexically scoped entity, such as a local variable, type name, or module name.
@@ -379,7 +390,7 @@ module Public {
379390
string getName() { result = this.getValue() }
380391

381392
/** Gets the representative for the local name introduced by this declaration. */
382-
LocalName getLocalName() { result = this.(LocalNameBindingOutput::LocalAccess).getLocal() }
393+
LocalName getLocalName() { result = resolveId(this) }
383394
}
384395

385396
final class LocalVariable = LocalVariableImpl;
@@ -495,7 +506,7 @@ module Public {
495506
*/
496507
class PotentialLocalNameAccess extends IdentifierExpr {
497508
/** Gets the representative for the local name being accessed. */
498-
LocalName getLocalName() { result = this.(LocalNameBindingOutput::LocalAccess).getLocal() }
509+
LocalName getLocalName() { result = resolveId(this) }
499510

500511
/** Gets the name being accessed. */
501512
string getName() { result = this.getValue() }

‎unified/ql/test/library-tests/local-name-binding/test.swift‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -385,23 +385,23 @@ func t39(value: Int) {
385385

386386
func t40() {
387387
// This function and its parameter have the same name
388-
func foo( // $ SPURIOUS: access=foo2 // name=foo1
389-
_ foo: String // $ SPURIOUS: access=foo2 captured=foo2 // name=foo2
388+
func foo( // name=foo1
389+
_ foo: String // name=foo2
390390
) {
391391
foo // $ access=foo2
392392
}
393-
foo() // $ MISSING: access=foo1
393+
foo() // $ access=foo1
394394
}
395395

396396
func t41() {
397397
// This function and its parameter have the same name
398398
// The parameter default value must resolve to the outer name (the function)
399399
// swift-format-ignore
400-
func foo( // $ SPURIOUS: access=foo2 // name=foo1
401-
_ foo: Any = // $ SPURIOUS: access=foo2 captured=foo2 // name=foo2
400+
func foo( // name=foo1
401+
_ foo: Any = // name=foo2
402402
foo // $ MISSING: access=foo1 SPURIOUS: access=foo2
403403
) {
404404
foo // $ access=foo2
405405
}
406-
foo() // $ MISSING: access=foo1
406+
foo() // $ access=foo1
407407
}

0 commit comments

Comments
 (0)