From f99dc7b26668072840455432595a6720af894bdd Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 27 May 2021 20:59:10 +0200 Subject: [PATCH] Variable resolution --- ql/consistency-queries/VariableResolution.ql | 1 + ql/src/codeql_ql/ast/Ast.qll | 11 ++++++ ql/src/codeql_ql/ast/internal/Variable.qll | 41 ++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 ql/consistency-queries/VariableResolution.ql create mode 100644 ql/src/codeql_ql/ast/internal/Variable.qll diff --git a/ql/consistency-queries/VariableResolution.ql b/ql/consistency-queries/VariableResolution.ql new file mode 100644 index 00000000000..8fc944d5363 --- /dev/null +++ b/ql/consistency-queries/VariableResolution.ql @@ -0,0 +1 @@ +import codeql_ql.ast.internal.Variable::VarConsistency diff --git a/ql/src/codeql_ql/ast/Ast.qll b/ql/src/codeql_ql/ast/Ast.qll index cf6116ce26c..87a24731fa7 100644 --- a/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/src/codeql_ql/ast/Ast.qll @@ -3,6 +3,7 @@ private import codeql_ql.ast.internal.AstNodes private import codeql_ql.ast.internal.Module private import codeql_ql.ast.internal.Predicate private import codeql_ql.ast.internal.Type +private import codeql_ql.ast.internal.Variable bindingset[name, i] private string indexedMember(string name, int i) { result = name + "(" + i.toString() + ")" } @@ -1172,6 +1173,16 @@ class Identifier extends TIdentifier, Expr { override string getAPrimaryQlClass() { result = "Identifier" } } +/** An access to a variable. */ +class VarAccess extends Identifier { + private VarDecl decl; + + VarAccess() { resolveVariable(this, decl) } + + /** Gets the accessed variable. */ + VarDecl getDeclaration() { result = decl } +} + /** A `not` formula. */ class Negation extends TNegation, Formula { Generated::Negation neg; diff --git a/ql/src/codeql_ql/ast/internal/Variable.qll b/ql/src/codeql_ql/ast/internal/Variable.qll new file mode 100644 index 00000000000..ec471585217 --- /dev/null +++ b/ql/src/codeql_ql/ast/internal/Variable.qll @@ -0,0 +1,41 @@ +import ql +import codeql_ql.ast.internal.AstNodes + +private class TScope = + TClass or TAggregate or TQuantifier or TSelect or TPredicate or TNewTypeBranch; + +/** A variable scope. */ +class VariableScope extends TScope, AstNode { + /** Gets the outer scope, if any. */ + VariableScope getOuterScope() { result = scopeOf(this) } + + /** Gets a variable declared directly in this scope. */ + VarDecl getADeclaration() { result.getParent() = this } + + /** Holds if this scope contains declaration `decl`, either directly or inherited. */ + predicate contains(VarDecl decl) { + decl = this.getADeclaration() + or + this.getOuterScope().contains(decl) and + not this.getADeclaration().getName() = decl.getName() + } +} + +private AstNode parent(AstNode child) { + result = child.getParent() and + not child instanceof VariableScope +} + +VariableScope scopeOf(AstNode n) { result = parent*(n.getParent()) } + +predicate resolveVariable(Identifier i, VarDecl decl) { + scopeOf(i).contains(decl) and + decl.getName() = i.getName() +} + +module VarConsistency { + query predicate multipleVarDecls(VarAccess v, VarDecl decl) { + decl = v.getDeclaration() and + strictcount(v.getDeclaration()) > 1 + } +}