/** Provides classes for modeling program variables. */ import javascript /** A scope in which variables can be declared. */ class Scope extends @scope { /** Gets a textual representation of this element. */ string toString() { none() } /** Gets the scope in which this scope is nested, if any. */ Scope getOuterScope() { scopenesting(this, result) } /** Gets a scope nested in this one, if any. */ Scope getAnInnerScope() { result.getOuterScope() = this } /** Gets the program element this scope is associated with, if any. */ AstNode getScopeElement() { scopenodes(result, this) } /** Gets the location of the program element this scope is associated with, if any. */ Location getLocation() { result = this.getScopeElement().getLocation() } /** Gets a variable declared in this scope. */ Variable getAVariable() { result.getScope() = this } /** Gets the variable with the given name declared in this scope. */ Variable getVariable(string name) { result = this.getAVariable() and result.getName() = name } } /** * A program element that induces a scope. */ class ScopeElement extends AstNode { Scope s; ScopeElement() { this = s.getScopeElement() } /** Gets the scope induced by this element. */ Scope getScope() { result = s } } /** The global scope. */ class GlobalScope extends Scope, @global_scope { override string toString() { result = "global scope" } } /** A local scope, that is, a scope that is not the global scope. */ class LocalScope extends Scope { LocalScope() { not this instanceof GlobalScope } } /** * A scope induced by a Node.js or ES2015 module */ class ModuleScope extends Scope, @module_scope { /** Gets the module that induces this scope. */ Module getModule() { result = this.getScopeElement() } override string toString() { result = "module scope" } } /** A scope induced by a function. */ class FunctionScope extends Scope, @function_scope { /** Gets the function that induces this scope. */ Function getFunction() { result = this.getScopeElement() } override string toString() { result = "function scope" } } /** A scope induced by a catch clause. */ class CatchScope extends Scope, @catch_scope { /** Gets the catch clause that induces this scope. */ CatchClause getCatchClause() { result = this.getScopeElement() } override string toString() { result = "catch scope" } } /** A scope induced by a block of statements. */ class BlockScope extends Scope, @block_scope { /** Gets the block of statements that induces this scope. */ BlockStmt getBlock() { result = this.getScopeElement() } override string toString() { result = "block scope" } } /** A scope induced by a `for` statement. */ class ForScope extends Scope, @for_scope { /** Gets the `for` statement that induces this scope. */ ForStmt getLoop() { result = this.getScopeElement() } override string toString() { result = "for scope" } } /** A scope induced by a `for`-`in` or `for`-`of` statement. */ class ForInScope extends Scope, @for_in_scope { /** Gets the `for`-`in` or `for`-`of` statement that induces this scope. */ EnhancedForLoop getLoop() { result = this.getScopeElement() } override string toString() { result = "for-in scope" } } /** A scope induced by a comprehension block. */ class ComprehensionBlockScope extends Scope, @comprehension_block_scope { /** Gets the comprehension block that induces this scope. */ ComprehensionBlock getComprehensionBlock() { result = this.getScopeElement() } override string toString() { result = "comprehension block scope" } } /** * The lexical scope induced by a TypeScript namespace declaration. * * This scope is specific to a single syntactic declaration of a namespace, * and currently does not include variables exported from other declarations * of the same namespace. */ class NamespaceScope extends Scope, @namespace_scope { override string toString() { result = "namespace scope" } } /** A variable declared in a scope. */ class Variable extends @variable, LexicalName { /** Gets the name of this variable. */ override string getName() { variables(this, result, _) } /** Gets the scope this variable is declared in. */ override Scope getScope() { variables(this, _, result) } /** Holds if this is a global variable. */ predicate isGlobal() { this.getScope() instanceof GlobalScope } /** * Holds if this is a variable exported from a TypeScript namespace. * * Note that such variables are also considered local for the time being. */ predicate isNamespaceExport() { this.getScope() instanceof NamespaceScope and exists(ExportNamedDeclaration decl | decl.getADecl().getVariable() = this) } /** * Holds if this is a local variable. * * Parameters and `arguments` variables are considered to be local. */ predicate isLocal() { not this.isGlobal() } /** Holds if this variable is a parameter. */ predicate isParameter() { exists(Parameter p | p.getAVariable() = this) } /** Gets a reference to this variable. */ VarRef getAReference() { result.getVariable() = this } /** Gets an access to this variable. */ VarAccess getAnAccess() { result.getVariable() = this } /** Gets a declaration declaring this variable, if any. */ VarDecl getADeclaration() { result.getVariable() = this } /** Gets a declaration statement declaring this variable, if any. */ DeclStmt getADeclarationStatement() { result.getADecl().getBindingPattern().getAVariable() = this } /** Gets a definition for this variable. */ VarDef getADefinition() { result.getAVariable() = this } /** Gets an expression that is directly stored in this variable. */ Expr getAnAssignedExpr() { // result is an expression that this variable is initialized to exists(VariableDeclarator vd | vd.getBindingPattern().(VarDecl).getVariable() = this | result = vd.getInit() ) or // if this variable represents a function binding, return the function exists(FunctionExpr fn | fn.getVariable() = this | result = fn) or // there is an assignment to this variable exists(Assignment assgn | assgn.getLhs() = this.getAnAccess() and assgn.getRhs() = result) } /** * Holds if this variable is captured in the closure of a nested function. * * Global variables are always considered to be captured. */ predicate isCaptured() { this instanceof GlobalVariable or this.getAnAccess().getContainer().getFunctionBoundary() != this.(LocalVariable).getDeclaringContainer().getFunctionBoundary() } /** Holds if there is a declaration of this variable in `tl`. */ predicate declaredIn(TopLevel tl) { this.getADeclaration().getTopLevel() = tl } /** Gets a textual representation of this element. */ override string toString() { result = this.getName() } override DeclarationSpace getDeclarationSpace() { result = "variable" } } /** An `arguments` variable of a function. */ class ArgumentsVariable extends Variable { ArgumentsVariable() { is_arguments_object(this) } override FunctionScope getScope() { result = Variable.super.getScope() } /** Gets the function declaring this 'arguments' variable. */ Function getFunction() { result = this.getScope().getFunction() } } /** * An identifier that refers to a variable, either in a declaration or in a variable access. * * Examples: * * ``` * function f(o) { // `f` and `o` are variable references * var w = 0, { x : y, z } = o; // `w`, `y`, `z` and `o` are variable references; `x` is not * o = null; // `o` is a variable reference; `null` is not * } * ``` */ class VarRef extends @varref, Identifier, BindingPattern, LexicalRef { /** Gets the variable this identifier refers to. */ override Variable getVariable() { none() } // Overriden in VarAccess and VarDecl override string getName() { result = Identifier.super.getName() } override VarRef getABindingVarRef() { result = this } override predicate isImpure() { none() } override Expr getUnderlyingReference() { result = this } override string getAPrimaryQlClass() { result = "VarRef" } } /** * An identifier that refers to a variable in a non-declaring position. * * Examples: * * ``` * function f(o) { * var w = 0, { x : y, z } = o; // `o` is a variable access * o = null; // `o` is a variable access * } * ``` */ class VarAccess extends @varaccess, VarRef, LexicalAccess { /** * Gets the variable this identifier refers to. * * When analyzing TypeScript code, a variable may spuriously be resolved as a * global due to incomplete modeling of exported variables in namespaces. */ override Variable getVariable() { bind(this, result) } override predicate isLValue() { exists(Assignment assgn | assgn.getTarget() = this) or exists(UpdateExpr upd | upd.getOperand().getUnderlyingReference() = this) or exists(EnhancedForLoop efl | efl.getIterator() = this) or exists(BindingPattern p | this = p.getABindingVarRef() and p.isLValue()) } override Variable getAVariable() { result = this.getVariable() } } /** * An identifier that occurs in a named export declaration. * * Example: * * ``` * export { A }; * ``` * * Such an identifier may refer to a variable, type, or namespace, or a combination of these. */ class ExportVarAccess extends VarAccess, @export_varaccess { /** Gets the type being exported, if this identifier refers to a type. */ LocalTypeName getLocalTypeName() { result.getAnAccess() = this } /** Gets the namespace being exported, if this identifier refers to a namespace. */ LocalNamespaceName getLocalNamespaceName() { result.getAnAccess() = this } } /** A global variable. */ class GlobalVariable extends Variable { GlobalVariable() { this.isGlobal() } } /** A local variable or a parameter. */ class LocalVariable extends Variable { LocalVariable() { this.isLocal() } /** * Gets the function or toplevel in which this variable is declared; * `arguments` variables are taken to be implicitly declared in the function * to which they belong. * * Note that for a function expression `function f() { ... }` the variable * `f` is declared in the function itself, while for a function statement * it is declared in the enclosing container. */ StmtContainer getDeclaringContainer() { this = result.getScope().getAVariable() or exists(VarDecl d | d = this.getADeclaration() | if d = any(FunctionDeclStmt fds).getIdentifier() then exists(FunctionDeclStmt fds | d = fds.getIdentifier() | result = fds.getEnclosingContainer() ) else result = d.getContainer() ) } /** * Gets the location of a declaration of this variable. * * If the variable has one or more declarations, the location of the first declaration is used. * If the variable has no declaration, the entry point of its declaring container is used. */ Location getLocation() { result = min(Location loc | loc = this.getADeclaration().getLocation() | loc order by loc.getStartLine(), loc.getStartColumn() ) or not exists(this.getADeclaration()) and result = this.getDeclaringContainer().getEntry().getLocation() } } /** A local variable that is not captured. */ class PurelyLocalVariable extends LocalVariable { PurelyLocalVariable() { not this.isCaptured() } } /** * An identifier that refers to a global variable. * * Examples: * * ``` * NaN * undefined * ``` */ class GlobalVarAccess extends VarAccess { GlobalVarAccess() { this.getVariable().isGlobal() } } /** * A binding pattern, that is, either an identifier or a destructuring pattern. * * Examples: * * ``` * function f(x, { y: z }, ...rest) { // `x`, `{ y: z }`, `z` and `rest` are binding patterns * var [ a, b ] = rest; // `[ a, b ]`, `a` and `b` are binding patterns * var c; // `c` is a binding pattern * } * ``` * * Binding patterns can appear on the left hand side of assignments or in * variable or parameter declarations. */ class BindingPattern extends @pattern, Expr { /** Gets the name of this binding pattern if it is an identifier. */ string getName() { none() } /** Gets the variable this binding pattern refers to if it is an identifier. */ Variable getVariable() { none() } /** Gets a variable reference in binding position within this pattern. */ VarRef getABindingVarRef() { none() } /** Gets a variable bound by this pattern. */ Variable getAVariable() { result = this.getABindingVarRef().getVariable() } /** Holds if this pattern appears in an l-value position. */ predicate isLValue() { any() } /** * Returns the type annotation for this variable or pattern, if any. * * Only the outermost part of a binding pattern can have a type annotation. * For instance, in the declaration, *
   * var {x}: Point
   * 
* the variable `x` has no type annotation, whereas the pattern `{x}` has the type * annotation `Point`. */ TypeAnnotation getTypeAnnotation() { exists(VariableDeclarator decl | decl.getBindingPattern() = this | result = decl.getTypeAnnotation() ) // note: Parameter overrides this to handle the parameter case } } private class TDestructuringPattern = @array_pattern or @object_pattern; /** * A destructuring pattern, that is, either an array pattern or an object pattern. * * Examples: * * ``` * function f(x, { y: z }, ...rest) { // `{ y: z }` is a destructuring pattern * var [ a, b ] = rest; // `[ a, b ]` is a destructuring pattern * var c; * } * ``` */ class DestructuringPattern extends TDestructuringPattern, BindingPattern { /** Gets the rest pattern of this destructuring pattern, if any. */ Expr getRest() { none() } // Overridden in subtypes. } /** * An identifier that declares a variable. * * Examples: * * ``` * function f(o) { // `f` and `o` are variable declarations * var w = 0, { x : y, z } = o; // `w`, `y` and `z` are variable declarations * o = null; * } */ class VarDecl extends @var_decl, VarRef, LexicalDecl { override Variable getVariable() { decl(this, result) } override predicate isLValue() { exists(VariableDeclarator vd | vd.getBindingPattern() = this | exists(vd.getInit()) or exists(EnhancedForLoop efl | this = efl.getIterator()) ) or exists(BindingPattern p | this = p.getABindingVarRef() and p.isLValue()) } override string getAPrimaryQlClass() { result = "VarDecl" } } /** * An identifier that declares a global variable. * * Example: * * ``` * var m; // `m` is a global variable declaration if this is a top-level statement * // (and not in a module) * ``` */ class GlobalVarDecl extends VarDecl { GlobalVarDecl() { this.getVariable() instanceof GlobalVariable } } /** * An array pattern. * * Example: * * ``` * function f(x, { y: z }, ...rest) { * var [ a, b ] = rest; // `[ a, b ]` is an array pattern * var c; * } * ``` */ class ArrayPattern extends DestructuringPattern, @array_pattern { /** Gets the `i`th element of this array pattern. */ Expr getElement(int i) { i >= 0 and result = this.getChildExpr(i) } /** Gets an element of this array pattern. */ Expr getAnElement() { exists(int i | i >= -1 | result = this.getChildExpr(i)) } /** Gets the default expression for the `i`th element of this array pattern, if any. */ Expr getDefault(int i) { i in [0 .. this.getSize() - 1] and result = this.getChildExpr(-2 - i) } /** Holds if the `i`th element of this array pattern has a default expression. */ predicate hasDefault(int i) { exists(this.getDefault(i)) } /** Gets the rest pattern of this array pattern, if any. */ override Expr getRest() { result = this.getChildExpr(-1) } /** Holds if this array pattern has a rest pattern. */ predicate hasRest() { exists(this.getRest()) } /** Gets the number of elements in this array pattern, not including any rest pattern. */ int getSize() { array_size(this, result) } /** Holds if the `i`th element of this array pattern is omitted. */ predicate elementIsOmitted(int i) { i in [0 .. this.getSize() - 1] and not exists(this.getElement(i)) } /** Holds if this array pattern has an omitted element. */ predicate hasOmittedElement() { this.elementIsOmitted(_) } override predicate isImpure() { this.getAnElement().isImpure() } override VarRef getABindingVarRef() { result = this.getAnElement().(BindingPattern).getABindingVarRef() } override string getAPrimaryQlClass() { result = "ArrayPattern" } } /** * An object pattern. * * Example: * * ``` * function f(x, { y: z }, ...rest) { // `{ y: z }` is an object pattern * var [ a, b ] = rest; * var c; * } * ``` */ class ObjectPattern extends DestructuringPattern, @object_pattern { /** Gets the `i`th property pattern in this object pattern. */ PropertyPattern getPropertyPattern(int i) { properties(result, this, i, _, _) } /** Gets a property pattern in this object pattern. */ PropertyPattern getAPropertyPattern() { result = this.getPropertyPattern(_) } /** Gets the number of property patterns in this object pattern. */ int getNumProperty() { result = count(this.getAPropertyPattern()) } /** Gets the property pattern with the given name, if any. */ PropertyPattern getPropertyPatternByName(string name) { result = this.getAPropertyPattern() and result.getName() = name } /** Gets the rest property pattern of this object pattern, if any. */ override Expr getRest() { result = this.getChildExpr(-1) } override predicate isImpure() { this.getAPropertyPattern().isImpure() } override VarRef getABindingVarRef() { result = this.getAPropertyPattern().getValuePattern().(BindingPattern).getABindingVarRef() or result = this.getRest().(BindingPattern).getABindingVarRef() } override string getAPrimaryQlClass() { result = "ObjectPattern" } } /** * A property pattern in an object pattern. * * Examples: * * ``` * function f(x, { y: z }, ...rest) { // `y: z` is a property pattern * var [ a, b ] = rest; * var c; * } * ``` */ class PropertyPattern extends @property, AstNode { PropertyPattern() { // filter out ordinary properties exists(ObjectPattern obj | properties(this, obj, _, _, _)) } /** Holds if the name of this property pattern is computed. */ predicate isComputed() { is_computed(this) } /** Gets the expression specifying the name of the matched property. */ Expr getNameExpr() { result = this.getChildExpr(0) } /** Gets the expression the matched property value is assigned to. */ Expr getValuePattern() { result = this.getChildExpr(1) } /** Gets the default value of this property pattern, if any. */ Expr getDefault() { result = this.getChildExpr(2) } /** Holds if this property pattern is a shorthand pattern. */ predicate isShorthand() { this.getNameExpr().getLocation() = this.getValuePattern().getLocation() } /** Gets the name of the property matched by this pattern. */ string getName() { not this.isComputed() and result = this.getNameExpr().(Identifier).getName() or result = this.getNameExpr().(Literal).getValue() } /** Gets the object pattern this property pattern belongs to. */ ObjectPattern getObjectPattern() { properties(this, result, _, _, _) } /** Holds if this pattern is impure, that is, if its evaluation could have side effects. */ predicate isImpure() { this.isComputed() and this.getNameExpr().isImpure() or this.getValuePattern().isImpure() } override string toString() { properties(this, _, _, _, result) } override ControlFlowNode getFirstControlFlowNode() { result = this.getNameExpr().getFirstControlFlowNode() } override string getAPrimaryQlClass() { result = "PropertyPattern" } } /** * A variable declarator declaring a local or global variable. * * Examples: * * ``` * var * x, // variable declarator * y = z; // variable declarator * ``` */ class VariableDeclarator extends Expr, @var_declarator { /** Gets the pattern specifying the declared variable(s). */ BindingPattern getBindingPattern() { result = this.getChildExpr(0) } /** Gets the expression specifying the initial value of the declared variable(s), if any. */ Expr getInit() { result = this.getChildExpr(1) } /** Gets the type annotation for the declared variable or binding pattern. */ TypeAnnotation getTypeAnnotation() { result = this.getChildTypeExpr(2) or result = this.getDeclStmt().getDocumentation().getATagByTitle("type").getType() } /** Holds if this is a TypeScript variable marked as definitely assigned with the `!` operator. */ predicate hasDefiniteAssignmentAssertion() { has_definite_assignment_assertion(this) } /** Gets the declaration statement this declarator belongs to, if any. */ DeclStmt getDeclStmt() { this = result.getADecl() } override ControlFlowNode getFirstControlFlowNode() { result = this.getBindingPattern().getFirstControlFlowNode() } override string getAPrimaryQlClass() { result = "VariableDeclarator" } } /** * For internal use, holding the decorators of a function parameter. */ private class DecoratorList extends Expr, @decorator_list { Decorator getDecorator(int i) { result = this.getChildExpr(i) } override ControlFlowNode getFirstControlFlowNode() { if exists(this.getDecorator(0)) then result = this.getDecorator(0).getFirstControlFlowNode() else result = this } } /** * A program element that declares parameters, that is, either a function or * a catch clause. * * Examples: * * ``` * function f(x, y) { // a parameterized element * try { * g(); * } catch(e) { // a parameterized element * } * } * ``` */ class Parameterized extends @parameterized, Documentable { /** Gets a parameter declared by this element. */ Parameter getAParameter() { this = result.getParent() } /** Gets the number of parameters declared by this element. */ int getNumParameter() { result = count(this.getAParameter()) } /** Gets a variable of the given name that is a parameter of this element. */ Variable getParameterVariable(string name) { result = this.getAParameter().getAVariable() and result.getName() = name } } /** * A parameter declaration in a function or catch clause. * * Examples: * * ``` * function f(x, { y: z }, ...rest) { // `x`, `{ y: z }` and `rest` are parameter declarations * var [ a, b ] = rest; * var c; * try { * x.m(); * } catch(e) {} // `e` is a parameter declaration * } * ``` */ class Parameter extends BindingPattern { Parameter() { exists(Parameterized p, int n | this = p.getChildExpr(n) and n >= 0 ) } /** * Gets the index of this parameter within the parameter list of its * declaring entity. */ int getIndex() { exists(Parameterized p | this = p.getChildExpr(result)) } /** Gets the element declaring this parameter. */ override Parameterized getParent() { result = super.getParent() } /** Gets the default expression for this parameter, if any. */ Expr getDefault() { exists(Function f, int n | this = f.getParameter(n) | result = f.getChildExpr(-(4 * n + 5))) } /** Gets the type annotation for this parameter, if any. */ override TypeAnnotation getTypeAnnotation() { exists(Function f, int n | this = f.getParameter(n) | result = f.getChildTypeExpr(-(4 * n + 6))) or result = this.getJSDocTag().getType() } /** Holds if this parameter is a rest parameter. */ predicate isRestParameter() { exists(Function f, int n | this = f.getParameter(n) | n = f.getNumParameter() - 1 and f.hasRestParameter() ) } private DecoratorList getDecoratorList() { exists(Function f, int n | this = f.getParameter(n) | result = f.getChildExpr(-(4 * n + 8))) } /** Gets the `i`th decorator applied to this parameter. */ Decorator getDecorator(int i) { result = this.getDecoratorList().getDecorator(i) } /** Gets a decorator applied to this parameter. */ Decorator getADecorator() { result = this.getDecorator(_) } /** Gets the number of decorators applied to this parameter. */ int getNumDecorator() { result = count(this.getADecorator()) } override predicate isLValue() { any() } /** * Gets the JSDoc tag describing this parameter, if any. */ JSDocTag getJSDocTag() { none() // overridden in SimpleParameter } /** * Holds if this is a parameter declared optional with the `?` token. * * Note that this does not hold for rest parameters, and does not in general * hold for parameters with defaults. * * For example, `x`, is declared optional below: * ``` * function f(x?: number) {} * ``` */ predicate isDeclaredOptional() { is_optional_parameter_declaration(this) } override string getAPrimaryQlClass() { result = "Parameter" } } /** * A parameter declaration that is not an object or array pattern. * * Examples: * * ``` * function f(x, { y: z }, ...rest) { // `x` and `rest` are simple parameter declarations * var [ a, b ] = rest; * var c; * } * ``` */ class SimpleParameter extends Parameter, VarDecl { override predicate isLValue() { Parameter.super.isLValue() } /** * Gets a use of this parameter that refers to its initial value as * passed in from the caller. */ VarUse getAnInitialUse() { exists(SsaDefinition ssa | ssa.getAContributingVarDef() = this and result = ssa.getVariable().getAUse() ) } override JSDocParamTag getJSDocTag() { exists(Function fun | this = fun.getAParameter() and result = fun.getDocumentation().getATag() ) and // Avoid joining on name exists(string tagName, string paramName | tagName = result.getName() and paramName = this.getName() and tagName <= paramName and paramName <= tagName ) } override string getAPrimaryQlClass() { result = "SimpleParameter" } } /** * A constructor parameter that induces a field in its class. * * Example: * * ``` * class C { * constructor( * public x: number // constructor parameter * ) {} * } * ``` */ class FieldParameter extends SimpleParameter { FieldParameter() { exists(ParameterField field | field.getParameter() = this) } /** Gets the field induced by this parameter. */ ParameterField getField() { result.getParameter() = this } override string getAPrimaryQlClass() { result = "FieldParameter" } } /** * A string representing one of the three TypeScript declaration spaces: `variable`, `type`, or `namespace`. */ class DeclarationSpace extends string { DeclarationSpace() { this = "variable" or this = "type" or this = "namespace" } } /** * A name that is declared in a particular scope. * * This can be a variable or a local name for a TypeScript type or namespace. * * Examples: * * ``` * // `id`, `x` and `String` are lexical names * function id(x: String) : any { * return x; * } * ``` */ class LexicalName extends @lexical_name { /** Gets the scope in which this name was declared. */ abstract Scope getScope(); /** Gets the name of this variable, type or namespace. */ abstract string getName(); /** Gets a string representation of this element. */ abstract string toString(); /** * Gets the declaration space this name belongs to. * * This can be either `variable`, `type`, or `namespace`. */ abstract DeclarationSpace getDeclarationSpace(); } /** * An identifier that refers to a variable, type, or namespace, or a combination of these. * * Example: * * ``` * function id(x: String) : any { // `id`, `x` and `String` are lexical references * return x; // `x` is a lexical reference * } * ``` */ class LexicalRef extends Identifier, @lexical_ref { /** * Gets any of the names referenced by this identifier. * * Note that each identifier may reference up to one lexical name per declaration space. * For example, a class name declares both a type and a variable. */ LexicalName getALexicalName() { bind(this, result) or decl(this, result) or typebind(this, result) or typedecl(this, result) or namespacebind(this, result) or namespacedecl(this, result) } } /** * An identifier that declares a variable, type, or namespace, or a combination of these. * * Example: * * ``` * function id(x: number) : any { // `id` and `x` are lexical declarations * return x; * } * ``` */ class LexicalDecl extends LexicalRef, @lexical_decl { } /** * An identifier that refers to a variable, type, or namespace, or a combination of these, * in a non-declaring position. * * Example: * * ``` * function id(x: String) : any { // `String` is a lexical access * return x; // `x` is a lexical access * } * ``` */ class LexicalAccess extends LexicalRef, @lexical_access { }