Skip to content

Commit a7706c9

Browse files
authored
Merge pull request #22666 from hvitved/unified/local-variable-is-implicit-receiver
Unified: Add `LocalVariable.isImplicitReceiverParameter`
2 parents 9a54399 + 306d4b9 commit a7706c9

1 file changed

Lines changed: 41 additions & 19 deletions

File tree

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

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,26 @@ module Public {
395395
LocalName getLocalName() { result = this.(LocalNameBindingOutput::LocalAccess).getLocal() }
396396
}
397397

398+
final class LocalVariable = LocalVariableImpl;
399+
398400
/** A representative for a lexically scoped local variable. */
399-
class LocalVariable extends LocalName {
400-
LocalVariable() {
401+
abstract private class LocalVariableImpl extends LocalName {
402+
/** Gets the callable containing the declaration of this local variable. */
403+
abstract Callable getDeclaringCallable();
404+
405+
/** Holds if this local variable is captured, that is, it is accessed from another callable than the one declaring it. */
406+
predicate isCaptured() {
407+
this.getAnAccess().getEnclosingCallable() != this.getDeclaringCallable()
408+
}
409+
410+
/**
411+
* Holds if this local variable represents an implicit receiver parameter of the given callable.
412+
*/
413+
abstract predicate isImplicitReceiverParameter(Callable c);
414+
}
415+
416+
private class ExplicitLocalVariable extends LocalVariableImpl {
417+
ExplicitLocalVariable() {
401418
exists(AstNode decl |
402419
decl = this.getABinding().getDeclaration() and
403420
not isInstanceMember(decl) and
@@ -411,29 +428,34 @@ module Public {
411428
decl instanceof CatchClause or
412429
decl instanceof SwitchCase
413430
)
414-
or
431+
}
432+
433+
override Callable getDeclaringCallable() { result = this.getABinding().getEnclosingCallable() }
434+
435+
override predicate isImplicitReceiverParameter(Callable c) { none() }
436+
}
437+
438+
private class ImplicitLocalVariable extends LocalVariableImpl instanceof LocalNameBindingOutput::ImplicitLocal
439+
{
440+
AstNode scope;
441+
string name;
442+
443+
ImplicitLocalVariable() {
415444
// For implicitly-declared locals we can't expect to find a binding. Check 'implicitDeclInScope' directly.
416-
exists(AstNode scope, string name |
417-
this.(LocalNameBindingOutput::ImplicitLocal).hasNameAndScope(name, scope) and
418-
LocalNameBindingInput::implicitDeclInScope(name, scope, true)
419-
)
445+
super.hasNameAndScope(name, scope) and
446+
LocalNameBindingInput::implicitDeclInScope(name, scope, true)
420447
}
421448

422-
/** Gets the callable containing the declaration of this local variable. */
423-
Callable getDeclaringCallable() {
424-
result = this.getABinding().getEnclosingCallable()
449+
override Callable getDeclaringCallable() {
450+
result = scope
425451
or
426-
exists(AstNode scope | scope = this.(LocalNameBindingOutput::ImplicitLocal).getScope() |
427-
result = scope
428-
or
429-
not scope instanceof Callable and
430-
result = scope.getEnclosingCallable()
431-
)
452+
not scope instanceof Callable and
453+
result = scope.getEnclosingCallable()
432454
}
433455

434-
/** Holds if this local variable is captured, that is, it is accessed from another callable than the one declaring it. */
435-
predicate isCaptured() {
436-
this.getAnAccess().getEnclosingCallable() != this.getDeclaringCallable()
456+
override predicate isImplicitReceiverParameter(Callable c) {
457+
name = any(NameBindingPlugin p).getImplicitReceiverParameterName(scope) and
458+
scope = c
437459
}
438460
}
439461

0 commit comments

Comments
 (0)