From 61d5f4412c74df6e1eaec4b504417249a01be4cd Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 8 Oct 2024 14:44:05 +0100 Subject: [PATCH] PS: AST support for 'this'. --- .../lib/semmle/code/powershell/Function.qll | 16 ++++++++++++-- .../lib/semmle/code/powershell/Variable.qll | 21 +++++++++++++++++-- .../code/powershell/controlflow/CfgNodes.qll | 6 +++++- .../powershell/controlflow/internal/Scope.qll | 7 +++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/powershell/ql/lib/semmle/code/powershell/Function.qll b/powershell/ql/lib/semmle/code/powershell/Function.qll index 40222580881..eff18885ebf 100644 --- a/powershell/ql/lib/semmle/code/powershell/Function.qll +++ b/powershell/ql/lib/semmle/code/powershell/Function.qll @@ -33,16 +33,28 @@ abstract private class AbstractFunction extends Ast { /** Gets the number of function parameters. */ final int getNumberOfFunctionParameters() { result = count(this.getAFunctionParameter()) } - /** Gets the number of parameters (both function and block). */ + /** + * Gets the number of parameters (both function and block). + * Note: This excludes the `this` parameter. + */ final int getNumberOfParameters() { result = count(this.getAParameter()) } - /** Gets the i'th parameter of this function, if any. */ + /** + * Gets the i'th parameter of this function, if any. + * + * This does not include the `this` parameter. + */ final Parameter getParameter(int i) { result = this.getFunctionParameter(i) or result = this.getBody().getParamBlock().getParameter(i) } + final Parameter getThisParameter() { + result.isThis() and + result.getFunction() = this + } + /** Gets any parameter of this function. */ final Parameter getAParameter() { result = this.getParameter(_) } diff --git a/powershell/ql/lib/semmle/code/powershell/Variable.qll b/powershell/ql/lib/semmle/code/powershell/Variable.qll index bc87109fc92..c155a5f0977 100644 --- a/powershell/ql/lib/semmle/code/powershell/Variable.qll +++ b/powershell/ql/lib/semmle/code/powershell/Variable.qll @@ -42,7 +42,8 @@ private newtype TParameterImpl = TInternalParameter(Internal::Parameter p) or TUnderscore(Scope scope) { exists(VarAccess va | va.getUserPath() = "_" and scope = va.getEnclosingScope()) - } + } or + TThisParameter(Scope scope) { exists(scope.getEnclosingFunction().getDeclaringType()) } private class ParameterImpl extends TParameterImpl { abstract Location getLocation(); @@ -109,9 +110,22 @@ private class Underscore extends ParameterImpl, TUnderscore { final override Scope getEnclosingScope() { result = scope } } +private class ThisParameter extends ParameterImpl, TThisParameter { + Scope scope; + + ThisParameter() { this = TThisParameter(scope) } + + override Location getLocation() { result = scope.getLocation() } + + override string getName() { result = "this" } + + final override Scope getEnclosingScope() { result = scope } +} + private newtype TVariable = TLocalVariable(string name, Scope scope) { not isParameterImpl(name, scope) and + not name = "this" and // This is modeled as a parameter exists(VarAccess va | va.getUserPath() = name and scope = va.getEnclosingScope()) } or TParameter(ParameterImpl p) @@ -186,8 +200,11 @@ class Parameter extends AbstractLocalScopeVariable, TParameter { predicate hasDefaultValue() { exists(this.getDefaultValue()) } + /** Holds if this is the `this` parameter. */ + predicate isThis() { p instanceof ThisParameter } + /** - * Gets the index of this parameter. + * Gets the index of this parameter, if any. * * The parameter may be in a parameter block or a function parameter. */ diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index e5f6185702a..91c0ff01cd6 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -217,7 +217,11 @@ module ExprNodes { /** Gets the name of this argument, if any. */ string getName() { result = e.getName() } - StmtNodes::CmdCfgNode getCmd() { result.getAnArgument() = this } + /** Holds if `this` is a qualifier to a call. */ + predicate isQualifier() { e.isQualifier() } + + /** Gets the call for which this is an argument. */ + CallCfgNode getCall() { result.getAnArgument() = this or result.getQualifier() = this } } private class InvokeMemberChildMapping extends ExprChildMapping, InvokeMemberExpr { diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll index 84b794dbee8..c1c1fab1c97 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll @@ -36,4 +36,11 @@ class Scope extends Ast, @script_block { * This may be both function paramters and parameter block parameters. */ Parameter getAParameter() { result = this.getParameter(_) } + + Parameter getThisParameter() { + exists(Function func | + func.getBody() = this and + result = func.getThisParameter() + ) + } }