Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package io.shiftleft.codepropertygraph.schema
import io.shiftleft.codepropertygraph.schema.CpgSchema.PropertyDefaults
import flatgraph.schema.EdgeType.Cardinality
import flatgraph.schema.Property.ValueType
import flatgraph.schema.{Constant, NodeType, SchemaBuilder, SchemaInfo}
object Ast extends SchemaBase {
def docIndex: Int = 7
override def providedByFrontend: Boolean = true
override def description: String =
"""
|The Abstract Syntax Tree (AST) Layer provides syntax trees for all compilation units.
|All nodes of the tree inherit from the same base class (`AST_NODE`) and are connected
|to their child nodes via outgoing `AST` edges.
|
|Syntax trees are typed, that is, when possible, types for all expressions are stored
|in the tree. Moreover, common control structure types are defined in the specification,
|making it possible to translate trees into corresponding control flow graphs if only
|these common control structure types are used, possibly by desugaring on the side of
|the language frontend. For cases where this is not an option,
|the AST specification provides means of storing language-dependent information in the
|AST that can be interpreted by language-dependent control flow construction passes.
|
|This layer MUST be created by the frontend.
|
|""".stripMargin
def apply(
builder: SchemaBuilder,
base: Base.Schema,
namespaces: Namespace.Schema,
methodSchema: Method.Schema,
typeSchema: Type.Schema,
fs: FileSystem.Schema
) =
new Schema(builder, base, namespaces, methodSchema, typeSchema, fs)
class Schema(
builder: SchemaBuilder,
base: Base.Schema,
namespaces: Namespace.Schema,
methodSchema: Method.Schema,
typeSchema: Type.Schema,
fs: FileSystem.Schema
) {
implicit private val schemaInfo: SchemaInfo = SchemaInfo.forClass(getClass)
import base._
import fs._
import methodSchema._
import namespaces._
import typeSchema._
// Base types
val order = builder
.addProperty(
name = "ORDER",
valueType = ValueType.Int,
comment = """This integer indicates the position of the node among
|its siblings in the AST. The left-most child has an
|order of 0.
|""".stripMargin
)
.mandatory(-1)
.protoId(4)
val astNode = builder
.addNodeBaseType(
name = "AST_NODE",
comment = """This is the base type for all nodes of the abstract syntax tree (AST). An AST
|node has a `CODE` and an `ORDER` field. The `CODE` field contains the
|code (verbatim) represented by the AST node. The `ORDER` field contains the
|nodes position among its siblings, encoded as an integer where the left most
|sibling has the position `0`.
|
|AST nodes contain optional `LINE_NUMBER` and `COLUMN_NUMBER` fields. For
|source-based frontends, these fields contain the start line number and
|start column number of the code represented by the node.
|For machine-code-based and bytecode-based frontends, `LINE_NUMBER` contains
|the address at which the code starts while `COLUMN_NUMBER` is undefined.
|""".stripMargin
)
.addProperties(order, code)
.addProperties(lineNumber, columnNumber)
// The following nodes from other schemas are AST nodes
method.extendz(astNode)
methodParameterIn.extendz(astNode)
methodParameterOut.extendz(astNode)
typeDecl.extendz(astNode)
member.extendz(astNode)
typeParameter.extendz(astNode)
typeArgument.extendz(astNode)
file.extendz(astNode)
namespaceBlock.extendz(astNode)
// Type-related nodes that are part of the AST
val block: NodeType = builder
.addNodeType(
name = "BLOCK",
comment = """This node represents a compound statement. Compound statements are used in many languages to allow
|grouping a sequence of statements. For example, in C and Java, compound statements
|are statements enclosed by curly braces. Function/Method bodies are compound
|statements. We do not use the term "compound statement" because "statement" would
|imply that the block does not yield a value upon evaluation, that is, that it is
|not an expression. This is true in languages such as C and Java, but not for languages
|such as Scala where the value of the block is given by that of the last expression it
|contains. In fact, the Scala grammar uses the term "BlockExpr" (short for
|"block expression") to describe what in the CPG we call "Block".
|""".stripMargin
)
.protoId(31)
.addProperties(typeFullName)
val literal: NodeType = builder
.addNodeType(
name = "LITERAL",
comment = """This node represents a literal such as an integer or string constant. Literals
|are symbols included in the code in verbatim form and which are immutable.
|The `TYPE_FULL_NAME` field stores the literal's fully-qualified type name,
|e.g., `java.lang.Integer`.
|""".stripMargin
)
.protoId(8)
.addProperties(typeFullName)
.primaryKey(code)
val local: NodeType = builder
.addNodeType(
name = "LOCAL",
comment = """This node represents a local variable. Its fully qualified type name is stored
|in the `TYPE_FULL_NAME` field and its name in the `NAME` field. The `CODE` field
|contains the entire local variable declaration without initialization, e.g., for
|`int x = 10;`, it contains `int x`.
|""".stripMargin
)
.protoId(23)
.addProperties(typeFullName)
.extendz(declaration, astNode)
.primaryKey(name)
val identifier: NodeType = builder
.addNodeType(
name = "IDENTIFIER",
comment = """This node represents an identifier as used when referring to a variable by name.
|It holds the identifier's name in the `NAME` field and its fully-qualified type
|name in `TYPE_FULL_NAME`.
|""".stripMargin
)
.protoId(27)
.addProperties(typeFullName, name)
.primaryKey(name)
val canonicalName = builder
.addProperty(
name = "CANONICAL_NAME",
valueType = ValueType.String,
comment = """This field holds the canonical name of a `FIELD_IDENTIFIER`. It is typically
|identical to the CODE field, but canonicalized according to source language
|semantics. Human readable names are preferable. `FIELD_IDENTIFIER` nodes must
|share identical `CANONICAL_NAME` if and
|only if they alias, e.g., in C-style unions (if the aliasing relationship is
|unknown or there are partial overlaps, then one must make a reasonable guess,
|and trade off between false negatives and false positives).
|""".stripMargin
)
.mandatory(PropertyDefaults.String)
.protoId(2001092)
val fieldIdentifier: NodeType = builder
.addNodeType(
name = "FIELD_IDENTIFIER",
comment = """This node represents the field accessed in a field access, e.g., in
|`a.b`, it represents `b`. The field name as it occurs in the code is
|stored in the `CODE` field. This may mean that the `CODE` field holds
|an expression. The `CANONICAL_NAME` field MAY contain the same value is
|the `CODE` field but SHOULD contain the normalized name that results
|from evaluating `CODE` as an expression if such an evaluation is
|possible for the language frontend. The objective is to store an identifier
|in `CANONICAL_NAME` that is the same for two nodes iff they refer to the
|same field, regardless of whether they use the same expression to reference
|it.
|""".stripMargin
)
.protoId(2001081)
.addProperties(canonicalName)
val modifierType = builder
.addProperty(
name = "MODIFIER_TYPE",
valueType = ValueType.String,
comment = """The modifier type is a free-form string. The following are known modifier types:
|`STATIC`, `PUBLIC`, `PROTECTED`, `PRIVATE`, `ABSTRACT`, `NATIVE`, `CONSTRUCTOR`, `VIRTUAL`.
|""".stripMargin
)
.mandatory(PropertyDefaults.String)
.protoId(26)
val modifierTypes = builder.addConstants(
category = "ModifierTypes",
Constant(name = "STATIC", value = "STATIC", valueType = ValueType.String, comment = "The static modifier")
.protoId(1),
Constant(name = "PUBLIC", value = "PUBLIC", valueType = ValueType.String, comment = "The public modifier")
.protoId(2),
Constant(
name = "PROTECTED",
value = "PROTECTED",
valueType = ValueType.String,
comment = "The protected modifier"
).protoId(3),
Constant(name = "PRIVATE", value = "PRIVATE", valueType = ValueType.String, comment = "The private modifier")
.protoId(4),
Constant(name = "ABSTRACT", value = "ABSTRACT", valueType = ValueType.String, comment = "The abstract modifier")
.protoId(5),
Constant(name = "NATIVE", value = "NATIVE", valueType = ValueType.String, comment = "The native modifier")
.protoId(6),
Constant(
name = "CONSTRUCTOR",
value = "CONSTRUCTOR",
valueType = ValueType.String,
comment = "The constructor modifier"
).protoId(7),
Constant(name = "VIRTUAL", value = "VIRTUAL", valueType = ValueType.String, comment = "The virtual modifier")
.protoId(8),
Constant(name = "INTERNAL", value = "INTERNAL", valueType = ValueType.String, comment = "The internal modifier")
.protoId(9),
Constant(name = "FINAL", value = "FINAL", valueType = ValueType.String, comment = "The final modifier")
.protoId(10),
Constant(name = "READONLY", value = "READONLY", valueType = ValueType.String, comment = "The readonly modifier")
.protoId(11),
Constant(
name = "MODULE",
value = "MODULE",
valueType = ValueType.String,
comment =
"Indicate that a method defines a module in the sense e.g. a python module does with the creation of a module object"
)
.protoId(12),
Constant(
name = "LAMBDA",
value = "LAMBDA",
valueType = ValueType.String,
comment = "Indicate that a method is an anonymous function, lambda, or closure"
)
.protoId(13)
)
val modifier: NodeType = builder
.addNodeType(
name = "MODIFIER",
comment = """This field represents a (language-dependent) modifier such as `static`, `private`
|or `public`. Unlike most other AST nodes, it is NOT an expression, that is, it
|cannot be evaluated and cannot be passed as an argument in function calls.
|""".stripMargin
)
.protoId(300)
.addProperties(modifierType)
.extendz(astNode)
val jumpTarget: NodeType = builder
.addNodeType(
name = "JUMP_TARGET",
comment = """A jump target is any location in the code that has been specifically marked
|as the target of a jump, e.g., via a label. The `NAME` field holds the name of
|the label while the `PARSER_TYPE_NAME` field holds the name of language construct
|that this jump target is created from, e.g., "Label".
|""".stripMargin
)
.protoId(340)
.addProperties(name, parserTypeName)
.extendz(astNode)
val jumpLabel: NodeType = builder
.addNodeType(
name = "JUMP_LABEL",
comment = """A jump label specifies the label and thus the JUMP_TARGET of control structures
|BREAK and CONTINUE. The `NAME` field holds the name of the label while the
|`PARSER_TYPE_NAME` field holds the name of language construct that this jump
|label is created from, e.g., "Label".
|""".stripMargin
)
.protoId(341)
.addProperties(name, parserTypeName)
.extendz(astNode)
val methodRef: NodeType = builder
.addNodeType(
name = "METHOD_REF",
comment = """This node represents a reference to a method/function/procedure as it
|appears when a method is passed as an argument in a call. The `METHOD_FULL_NAME`
|field holds the fully-qualified name of the referenced method and the
|`TYPE_FULL_NAME` holds its fully-qualified type name.
|""".stripMargin
)
.protoId(333)
.addProperties(typeFullName)
val typeRef: NodeType = builder
.addNodeType(name = "TYPE_REF", comment = "Reference to a type/class")
.protoId(335)
.addProperties(typeFullName)
val ret: NodeType = builder
.addNodeType(
name = "RETURN",
comment = """This node represents a return instruction, e.g., `return x`. Note that it does
|NOT represent a formal return parameter as formal return parameters are
|represented via `METHOD_RETURN` nodes.
|""".stripMargin
)
.protoId(30)
.starterName("ret")
.primaryKey(code)
val controlStructureType = builder
.addProperty(
name = "CONTROL_STRUCTURE_TYPE",
valueType = ValueType.String,
comment = """The `CONTROL_STRUCTURE_TYPE` field indicates which kind of control structure
|a `CONTROL_STRUCTURE` node represents. The available types are the following:
| BREAK, CONTINUE, DO, WHILE, FOR, GOTO, IF, ELSE, TRY, THROW and SWITCH.
|""".stripMargin
)
.mandatory(PropertyDefaults.String)
.protoId(27)
val controlStructureTypes = builder.addConstants(
category = "ControlStructureTypes",
Constant(
name = "BREAK",
value = "BREAK",
valueType = ValueType.String,
comment = """Represents a break statement. Labeled breaks are expected to have a JUMP_LABEL
|node AST child with ORDER 1""".stripMargin
).protoId(1),
Constant(
name = "CONTINUE",
value = "CONTINUE",
valueType = ValueType.String,
comment = """Represents a continue statement. Labeled continues are expected to have a JUMP_LABEL
|node AST child with ORDER 1""".stripMargin
).protoId(2),
Constant(name = "WHILE", value = "WHILE", valueType = ValueType.String, comment = "Represents a while statement")
.protoId(3),
Constant(name = "DO", value = "DO", valueType = ValueType.String, comment = "Represents a do statement")
.protoId(4),
Constant(name = "FOR", value = "FOR", valueType = ValueType.String, comment = "Represents a for statement")
.protoId(5),
Constant(name = "GOTO", value = "GOTO", valueType = ValueType.String, comment = "Represents a goto statement")
.protoId(6),
Constant(name = "IF", value = "IF", valueType = ValueType.String, comment = "Represents an if statement")
.protoId(7),
Constant(name = "ELSE", value = "ELSE", valueType = ValueType.String, comment = "Represents an else statement")
.protoId(8),
Constant(
name = "SWITCH",
value = "SWITCH",
valueType = ValueType.String,
comment = "Represents a switch statement"
).protoId(9),
Constant(name = "TRY", value = "TRY", valueType = ValueType.String, comment = "Represents a try statement")
.protoId(10),
Constant(name = "THROW", value = "THROW", valueType = ValueType.String, comment = "Represents a throw statement")
.protoId(11),
Constant(name = "MATCH", value = "MATCH", valueType = ValueType.String, comment = "Represents a match expression")
.protoId(12),
Constant(name = "YIELD", value = "YIELD", valueType = ValueType.String, comment = "Represents a yield expression")
.protoId(13),
Constant(name = "CATCH", value = "CATCH", valueType = ValueType.String, comment = "Represents a catch clause")
.protoId(14),
Constant(
name = "FINALLY",
value = "FINALLY",
valueType = ValueType.String,
comment = "Represents a finally clause"
)
.protoId(15)
)
val controlStructure: NodeType = builder
.addNodeType(
name = "CONTROL_STRUCTURE",
comment = """This node represents a control structure as introduced by control structure
|statements as well as conditional and unconditional jumps. Its type is stored in the
|`CONTROL_STRUCTURE_TYPE` field to be one of several pre-defined types. These types
| are used in the construction of the control flow layer, making it possible to
| generate the control flow layer from the abstract syntax tree layer automatically.
|
|In addition to the `CONTROL_STRUCTURE_TYPE` field, the `PARSER_TYPE_NAME` field
|MAY be used by frontends to store the name of the control structure as emitted by
|the parser or disassembler, however, the value of this field is not relevant
|for construction of the control flow layer.
|""".stripMargin
)
.protoId(339)
.addProperties(parserTypeName, controlStructureType)
val unknown: NodeType = builder
.addNodeType(
name = "UNKNOWN",
comment = """Any AST node that the frontend would like to include in the AST but for
|which no suitable AST node is specified in the CPG specification may be
|included using a node of type `UNKNOWN`.
|""".stripMargin
)
.protoId(44)
.addProperties(parserTypeName, typeFullName)
// Edge types
val ast = builder
.addEdgeType(name = "AST", comment = "This edge connects a parent node to its child in the syntax tree.")
.protoId(3)
val condition = builder
.addEdgeType(
name = "CONDITION",
comment = "The edge connects control structure nodes to the expressions that holds their conditions."
)
.protoId(56)
file.addOutEdge(edge = ast, inNode = namespaceBlock, cardinalityIn = Cardinality.ZeroOrOne)
member.addOutEdge(edge = ast, inNode = modifier)
tpe.addOutEdge(edge = ast, inNode = typeArgument)
typeDecl
.addOutEdge(edge = ast, inNode = typeParameter)
.addOutEdge(
edge = ast,
inNode = member,
cardinalityIn = Cardinality.One,
stepNameIn = "typeDecl",
stepNameInDoc = "The type declaration this member is defined in"
)
.addOutEdge(edge = ast, inNode = modifier, cardinalityIn = Cardinality.One)
method
.addOutEdge(
edge = ast,
inNode = methodReturn,
cardinalityOut = Cardinality.One,
cardinalityIn = Cardinality.One,
stepNameOut = "methodReturn",
stepNameOutDoc = "Formal return parameters"
)
.addOutEdge(
edge = ast,
inNode = methodParameterIn,
cardinalityIn = Cardinality.One,
stepNameOut = "parameter",
stepNameOutDoc = "Parameters of the method",
stepNameIn = "method",
stepNameInDoc = "Traverse to method associated with this formal parameter"
)
.addOutEdge(edge = ast, inNode = modifier, cardinalityIn = Cardinality.One)
.addOutEdge(
edge = ast,
inNode = block,
cardinalityOut = Cardinality.One,
cardinalityIn = Cardinality.One,
stepNameOut = "block",
stepNameOutDoc = "Root of the abstract syntax tree"
)
.addOutEdge(edge = ast, inNode = typeParameter, cardinalityIn = Cardinality.One)
ret
.addOutEdge(edge = ast, inNode = identifier)
.addOutEdge(edge = ast, inNode = literal)
.addOutEdge(edge = ast, inNode = methodRef)
.addOutEdge(edge = ast, inNode = typeRef)
.addOutEdge(edge = ast, inNode = ret)
.addOutEdge(edge = ast, inNode = block)
.addOutEdge(edge = ast, inNode = unknown)
.addOutEdge(edge = ast, inNode = jumpTarget)
.addOutEdge(edge = ast, inNode = controlStructure)
block
.addOutEdge(edge = ast, inNode = identifier)
.addOutEdge(edge = ast, inNode = literal)
.addOutEdge(edge = ast, inNode = methodRef)
.addOutEdge(edge = ast, inNode = typeRef)
.addOutEdge(edge = ast, inNode = ret)
.addOutEdge(edge = ast, inNode = block, cardinalityIn = Cardinality.One)
.addOutEdge(
edge = ast,
inNode = local,
stepNameIn = "definingBlock",
stepNameInDoc = "The block in which local is declared.",
stepNameOut = "local",
stepNameOutDoc = "Traverse to locals of this block."
)
.addOutEdge(edge = ast, inNode = unknown)
.addOutEdge(edge = ast, inNode = jumpTarget)
.addOutEdge(edge = ast, inNode = controlStructure)
controlStructure
.addOutEdge(edge = ast, inNode = literal, cardinalityIn = Cardinality.One)
.addOutEdge(edge = ast, inNode = modifier)
.addOutEdge(edge = ast, inNode = local)
.addOutEdge(edge = ast, inNode = identifier, cardinalityIn = Cardinality.ZeroOrOne)
.addOutEdge(edge = ast, inNode = ret, cardinalityIn = Cardinality.ZeroOrOne)
.addOutEdge(edge = ast, inNode = block, cardinalityIn = Cardinality.ZeroOrOne)
.addOutEdge(edge = ast, inNode = jumpTarget)
.addOutEdge(edge = ast, inNode = unknown)
.addOutEdge(edge = ast, inNode = controlStructure)
.addOutEdge(edge = ast, inNode = methodRef, cardinalityIn = Cardinality.One)
.addOutEdge(edge = ast, inNode = typeRef)
.addOutEdge(edge = ast, inNode = jumpLabel)
unknown
.addOutEdge(edge = ast, inNode = literal)
.addOutEdge(edge = ast, inNode = modifier)
.addOutEdge(edge = ast, inNode = local)
.addOutEdge(edge = ast, inNode = identifier)
.addOutEdge(edge = ast, inNode = fieldIdentifier)
.addOutEdge(edge = ast, inNode = ret)
.addOutEdge(edge = ast, inNode = block)
.addOutEdge(edge = ast, inNode = jumpTarget)
.addOutEdge(edge = ast, inNode = unknown)
.addOutEdge(edge = ast, inNode = controlStructure)
unknown.addOutEdge(edge = ast, inNode = member)
methodParameterIn.addOutEdge(edge = ast, inNode = unknown)
namespaceBlock
.addOutEdge(edge = ast, inNode = typeDecl, cardinalityIn = Cardinality.ZeroOrOne, stepNameIn = "namespaceBlock")
.addOutEdge(edge = ast, inNode = method, cardinalityIn = Cardinality.ZeroOrOne)
namespace.extendz(astNode)
controlStructure
.addOutEdge(edge = condition, inNode = literal)
.addOutEdge(edge = condition, inNode = identifier)
.addOutEdge(edge = condition, inNode = ret)
.addOutEdge(edge = condition, inNode = block)
.addOutEdge(edge = condition, inNode = methodRef)
.addOutEdge(edge = condition, inNode = typeRef)
.addOutEdge(edge = condition, inNode = controlStructure)
.addOutEdge(edge = condition, inNode = jumpTarget)
.addOutEdge(edge = condition, inNode = unknown)
.addOutEdge(edge = condition, inNode = controlStructure)
typeDecl
.addOutEdge(edge = ast, inNode = typeDecl, cardinalityIn = Cardinality.ZeroOrOne)
.addOutEdge(edge = ast, inNode = method, cardinalityIn = Cardinality.ZeroOrOne)
method
.addOutEdge(edge = ast, inNode = methodParameterOut, cardinalityIn = Cardinality.One, stepNameIn = "method")
.addOutEdge(edge = ast, inNode = typeDecl, cardinalityIn = Cardinality.ZeroOrOne)
.addOutEdge(edge = ast, inNode = method, cardinalityIn = Cardinality.ZeroOrOne)
val callRepr = builder
.addNodeBaseType(
name = "CALL_REPR",
comment = "This is the base class of `CALL` that language implementers may safely ignore."
)
.addProperties(name, signature)
val callNode: NodeType = builder
.addNodeType(
name = "CALL",
comment = """A (function/method/procedure) call. The `METHOD_FULL_NAME` property is the name of the
|invoked method (the callee) while the `TYPE_FULL_NAME` is its return type, and
|therefore, the return type of the call when viewing it as an expression. For
|languages like Javascript, it is common that we may know the (short-) name
|of the invoked method, but we do not know at compile time which method
|will actually be invoked, e.g., because it depends on a dynamic import.
|In this case, we leave `METHOD_FULL_NAME` blank but at least fill out `NAME`,
|which contains the method's (short-) name and `SIGNATURE`, which contains
|any information we may have about the types of arguments and return value.
|""".stripMargin
)
.protoId(15)
.extendz(callRepr)
.addProperties(typeFullName)
.primaryKey(name)
val expression = builder
.addNodeBaseType(
name = "EXPRESSION",
comment = """`EXPRESSION` is the base class for all nodes that represent code pieces
|that can be evaluated.
|
| Expression may be arguments in method calls. For method calls that do
| not involved named parameters, the `ARGUMENT_INDEX` field indicates at
| which position in the argument list the expression occurs, e.g., an
| `ARGUMENT_INDEX` of 1 indicates that the expression is the first argument
| in a method call. For calls that employ named parameters, `ARGUMENT_INDEX`
| is set to -1 and the `ARGUMENT_NAME` fields holds the name of the parameter.
|""".stripMargin
)
.extendz(astNode)
fieldIdentifier.extendz(expression)
identifier.extendz(expression)
literal.extendz(expression)
block.extendz(expression)
controlStructure.extendz(expression)
methodRef.extendz(expression)
typeRef.extendz(expression)
ret.extendz(expression)
unknown.extendz(expression)
callNode
.addOutEdge(edge = ast, inNode = callNode)
.addOutEdge(edge = ast, inNode = identifier)
.addOutEdge(edge = ast, inNode = fieldIdentifier, cardinalityIn = Cardinality.One)
.addOutEdge(edge = ast, inNode = literal)
.addOutEdge(edge = ast, inNode = methodRef)
.addOutEdge(edge = ast, inNode = typeRef)
.addOutEdge(edge = ast, inNode = ret)
.addOutEdge(edge = ast, inNode = block)
.addOutEdge(edge = ast, inNode = controlStructure)
ret.addOutEdge(edge = ast, inNode = callNode)
controlStructure.addOutEdge(edge = ast, inNode = callNode, cardinalityIn = Cardinality.One)
unknown.addOutEdge(edge = ast, inNode = callNode)
controlStructure.addOutEdge(edge = condition, inNode = callNode)
block.addOutEdge(edge = ast, inNode = callNode)
// To refactor
identifier
.addOutEdge(
edge = ref,
inNode = local,
cardinalityOut = Cardinality.ZeroOrOne,
stepNameIn = "referencingIdentifiers",
stepNameInDoc = "Places (identifier) where this local is being referenced"
)
.addOutEdge(
edge = ref,
inNode = methodParameterIn,
cardinalityOut = Cardinality.ZeroOrOne,
stepNameIn = "referencingIdentifiers",
stepNameInDoc = "Places (identifier) where this parameter is being referenced"
)
namespaceBlock.addOutEdge(edge = ref, inNode = namespace)
}
}