2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.parser.util;
11 import java.util.ArrayList;
12 import java.util.Date;
13 import java.util.HashSet;
14 import java.util.List;
17 import java.util.TreeMap;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
22 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
25 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.Module;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
30 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
31 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
33 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
34 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
38 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
39 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
40 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
49 public final class GroupingUtils {
51 private GroupingUtils() {
55 * Search given modules for grouping by name defined in uses node.
58 * builder of uses statement
63 * @return grouping with given name if found, null otherwise
65 public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
66 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
67 final int line = usesBuilder.getLine();
68 final String groupingString = usesBuilder.getGroupingPathAsString();
69 String groupingPrefix;
72 if (groupingString.contains(":")) {
73 String[] splitted = groupingString.split(":");
74 if (splitted.length != 2 || groupingString.contains("/")) {
75 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
77 groupingPrefix = splitted[0];
78 groupingName = splitted[1];
80 groupingPrefix = module.getPrefix();
81 groupingName = groupingString;
84 ModuleBuilder dependentModule = null;
85 if (groupingPrefix.equals(module.getPrefix())) {
86 dependentModule = module;
88 dependentModule = ParserUtils.findModuleFromBuilders(modules, module, groupingPrefix, line);
91 if (dependentModule == null) {
95 GroupingBuilder result = null;
96 Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
97 result = findGroupingBuilder(groupings, groupingName);
102 Builder parent = usesBuilder.getParent();
104 while (parent != null) {
105 if (parent instanceof DataNodeContainerBuilder) {
106 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
107 } else if (parent instanceof RpcDefinitionBuilder) {
108 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
110 result = findGroupingBuilder(groupings, groupingName);
111 if (result == null) {
112 parent = parent.getParent();
118 if (result == null) {
119 throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
126 * Search context for grouping by name defined in uses node.
129 * builder of uses statement
133 * SchemaContext containing already resolved modules
134 * @return grouping with given name if found, null otherwise
136 public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
137 final ModuleBuilder module, final SchemaContext context) {
138 final int line = usesBuilder.getLine();
139 String groupingString = usesBuilder.getGroupingPathAsString();
140 String groupingPrefix;
143 if (groupingString.contains(":")) {
144 String[] splitted = groupingString.split(":");
145 if (splitted.length != 2 || groupingString.contains("/")) {
146 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
148 groupingPrefix = splitted[0];
149 groupingName = splitted[1];
151 groupingPrefix = module.getPrefix();
152 groupingName = groupingString;
155 Module dependentModule = ParserUtils.findModuleFromContext(context, module, groupingPrefix, line);
156 return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
160 * Find grouping by name.
163 * collection of grouping builders to search
166 * @return grouping with given name if present in collection, null otherwise
168 public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
169 for (GroupingBuilder grouping : groupings) {
170 if (grouping.getQName().getLocalName().equals(name)) {
178 * Find grouping by name.
181 * collection of grouping definitions to search
184 * @return grouping with given name if present in collection, null otherwise
186 public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
187 for (GroupingDefinition grouping : groupings) {
188 if (grouping.getQName().getLocalName().equals(name)) {
196 * Add nodes defined in uses target grouping to uses parent.
200 public static void updateUsesParent(UsesNodeBuilder usesNode) {
201 DataNodeContainerBuilder parent = usesNode.getParent();
202 ModuleBuilder module = ParserUtils.getParentModule(parent);
203 URI ns = module.getNamespace();
204 Date rev = module.getRevision();
205 String prefix = module.getPrefix();
207 SchemaPath parentPath = parent.getPath();
210 if(parent instanceof AugmentationSchemaBuilder) {
211 parentPath = ((AugmentationSchemaBuilder)parent).getTargetNodeSchemaPath();
215 for (DataSchemaNodeBuilder child : usesNode.getTargetChildren()) {
216 if (child instanceof GroupingMember) {
217 ((GroupingMember) child).setAddedByUses(true);
220 GroupingMember gm = (GroupingMember) child;
221 if (gm.isAddedByUses()) {
222 if(usesNode.isAugmenting()) {
223 child.setAugmenting(true);
225 if(usesNode.isAugmenting() && !(usesNode.getParentAugment().getParent() instanceof UsesNodeBuilder)) {
226 AugmentationSchemaBuilder parentAugment = usesNode.getParentAugment();
227 ModuleBuilder m = ParserUtils.getParentModule(parentAugment);
228 correctNodePathForUsesNodes(child, parentPath, m);
230 child.setQName(new QName(ns, rev, prefix, child.getQName().getLocalName()));
231 correctNodePathForUsesNodes(child, parentPath, module);
235 parent.addChildNode(child);
239 for (GroupingBuilder gb : usesNode.getTargetGroupings()) {
240 gb.setAddedByUses(true);
241 gb.setQName(new QName(ns, rev, prefix, gb.getQName().getLocalName()));
242 correctNodePathForUsesNodes(gb, parentPath, module);
243 parent.addGrouping(gb);
247 for (TypeDefinitionBuilder tdb : usesNode.getTargetTypedefs()) {
248 tdb.setAddedByUses(true);
249 tdb.setQName(new QName(ns, rev, prefix, tdb.getQName().getLocalName()));
250 correctNodePathForUsesNodes(tdb, parentPath, module);
251 parent.addTypedef(tdb);
255 for (UnknownSchemaNodeBuilder un : usesNode.getTargetUnknownNodes()) {
256 un.setAddedByUses(true);
257 un.setQName(new QName(ns, rev, prefix, un.getQName().getLocalName()));
258 correctNodePathForUsesNodes(un, parentPath, module);
259 parent.addUnknownNodeBuilder(un);
264 * Read data defined in target grouping builder, make a copy and add them to
270 public static void collectUsesData(UsesNodeBuilder usesNode) {
271 collectTargetChildNodes(usesNode);
272 collectTargetTypedefs(usesNode);
273 collectTargetGroupings(usesNode);
274 collectTargetUnknownNodes(usesNode);
275 usesNode.setDataCollected(true);
279 * Read child nodes defined in target grouping and make a copy of them.
282 * @return copy of child nodes defined in uses target grouping
284 private static void collectTargetChildNodes(UsesNodeBuilder usesNode) {
285 final GroupingBuilder target = usesNode.getGroupingBuilder();
286 final Set<DataSchemaNodeBuilder> collection = new HashSet<>();
287 addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders());
289 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
290 Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses,
291 usesNode.getParent());
292 addChildNodeToCollection(usesNode, collection, targetUsesChildNodes);
294 usesNode.getTargetChildren().addAll(collection);
297 private static Set<DataSchemaNodeBuilder> collectTargetUsesChildNodes(UsesNodeBuilder usesNode,
298 DataNodeContainerBuilder parent) {
299 final GroupingBuilder target = usesNode.getGroupingBuilder();
300 final Set<DataSchemaNodeBuilder> collection = new HashSet<>(usesNode.getTargetChildren());
301 addChildNodeToCollection(usesNode, collection, target.getChildNodeBuilders());
303 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
304 Set<DataSchemaNodeBuilder> targetUsesChildNodes = collectTargetUsesChildNodes(targetUses, parent);
305 addChildNodeToCollection(usesNode, collection, targetUsesChildNodes);
310 private static void addChildNodeToCollection(UsesNodeBuilder usesNode, Set<DataSchemaNodeBuilder> collection,
311 Set<DataSchemaNodeBuilder> allNodes) {
312 for (DataSchemaNodeBuilder childNode : allNodes) {
313 boolean exists = false;
314 for (DataSchemaNodeBuilder usesChildNode : usesNode.getTargetChildren()) {
315 if (usesChildNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
321 DataSchemaNodeBuilder copy = CopyUtils.copy(childNode, usesNode.getParent(), true);
322 collection.add(copy);
328 * Read typedefs defined in target grouping and make a copy of them.
331 * @return copy of typedefs defined in uses target grouping
333 private static void collectTargetTypedefs(UsesNodeBuilder usesNode) {
334 final GroupingBuilder target = usesNode.getGroupingBuilder();
335 Set<TypeDefinitionBuilder> collection = new HashSet<>();
336 addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders());
338 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
339 Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, usesNode.getParent());
340 addTypedefToCollection(usesNode, collection, targetUsesTypedefs);
342 usesNode.getTargetTypedefs().addAll(collection);
345 private static Set<TypeDefinitionBuilder> collectTargetUsesTypedefs(UsesNodeBuilder usesNode,
346 DataNodeContainerBuilder parent) {
347 final GroupingBuilder target = usesNode.getGroupingBuilder();
348 Set<TypeDefinitionBuilder> collection = new HashSet<>(usesNode.getTargetTypedefs());
349 addTypedefToCollection(usesNode, collection, target.getTypeDefinitionBuilders());
351 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
352 Set<TypeDefinitionBuilder> targetUsesTypedefs = collectTargetUsesTypedefs(targetUses, parent);
353 addTypedefToCollection(usesNode, collection, targetUsesTypedefs);
358 private static void addTypedefToCollection(UsesNodeBuilder usesNode, Set<TypeDefinitionBuilder> collection,
359 Set<TypeDefinitionBuilder> allTypedefs) {
360 for (TypeDefinitionBuilder childNode : allTypedefs) {
361 boolean exists = false;
362 for (TypeDefinitionBuilder usesTypedef : usesNode.getTargetTypedefs()) {
363 if (usesTypedef.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
369 TypeDefinitionBuilder copy = CopyUtils.copy(childNode, usesNode.getParent(), true);
370 collection.add(copy);
376 * Read groupings defined in target grouping and make a copy of them.
379 * @return copy of groupings defined in uses target grouping
381 private static void collectTargetGroupings(UsesNodeBuilder usesNode) {
382 final GroupingBuilder target = usesNode.getGroupingBuilder();
383 Set<GroupingBuilder> collection = new HashSet<>();
384 addGroupingToCollection(usesNode, collection, target.getGroupingBuilders());
386 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
387 Set<GroupingBuilder> targetUsesGrouping = collectTargetGroupings(targetUses, usesNode.getParent());
388 addGroupingToCollection(usesNode, collection, targetUsesGrouping);
390 usesNode.getTargetGroupings().addAll(collection);
393 private static Set<GroupingBuilder> collectTargetGroupings(UsesNodeBuilder usesNode, DataNodeContainerBuilder parent) {
394 final GroupingBuilder target = usesNode.getGroupingBuilder();
395 Set<GroupingBuilder> collection = new HashSet<>(usesNode.getTargetGroupings());
396 addGroupingToCollection(usesNode, collection, target.getGroupingBuilders());
398 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
399 Set<GroupingBuilder> targetUsesGroupings = collectTargetGroupings(targetUses, parent);
400 addGroupingToCollection(usesNode, collection, targetUsesGroupings);
405 private static void addGroupingToCollection(UsesNodeBuilder usesNode, Set<GroupingBuilder> collection,
406 Set<GroupingBuilder> allGroupings) {
407 for (GroupingBuilder childNode : allGroupings) {
408 boolean exists = false;
409 for (GroupingBuilder usesGrouping : usesNode.getTargetGroupings()) {
410 if (usesGrouping.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
416 GroupingBuilder copy = CopyUtils.copy(childNode, usesNode.getParent(), true);
417 collection.add(copy);
423 * Read unknown nodes defined in target grouping and make a copy of them.
426 * @return copy of unknown nodes defined in uses target grouping
428 private static void collectTargetUnknownNodes(UsesNodeBuilder usesNode) {
429 final GroupingBuilder target = usesNode.getGroupingBuilder();
430 final List<UnknownSchemaNodeBuilder> collection = new ArrayList<>();
431 addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders());
433 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
434 List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses,
435 usesNode.getParent());
436 addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes);
438 usesNode.getTargetUnknownNodes().addAll(collection);
441 private static List<UnknownSchemaNodeBuilder> collectTargetUnknownNodes(UsesNodeBuilder usesNode,
442 DataNodeContainerBuilder parent) {
443 final GroupingBuilder target = usesNode.getGroupingBuilder();
444 List<UnknownSchemaNodeBuilder> collection = new ArrayList<>(usesNode.getTargetUnknownNodes());
445 addUnknownNodeToCollection(usesNode, collection, target.getUnknownNodeBuilders());
447 for (UsesNodeBuilder targetUses : target.getUsesNodes()) {
448 List<UnknownSchemaNodeBuilder> targetUsesUnknownNodes = collectTargetUnknownNodes(targetUses, parent);
449 addUnknownNodeToCollection(usesNode, collection, targetUsesUnknownNodes);
454 private static void addUnknownNodeToCollection(UsesNodeBuilder usesNode, List<UnknownSchemaNodeBuilder> collection,
455 List<UnknownSchemaNodeBuilder> allUnknownNodes) {
456 for (UnknownSchemaNodeBuilder childNode : allUnknownNodes) {
457 boolean exists = false;
458 for (UnknownSchemaNodeBuilder usesUnknownNode : usesNode.getTargetUnknownNodes()) {
459 if (usesUnknownNode.getQName().getLocalName().equals(childNode.getQName().getLocalName())) {
465 UnknownSchemaNodeBuilder copy = CopyUtils.copy(childNode, usesNode.getParent(), true);
466 collection.add(copy);
472 * Read data defined in target grouping definition, make a copy and add them
473 * to uses node builder.
478 public static void collectUsesDataFromContext(UsesNodeBuilder usesNode) {
479 DataNodeContainerBuilder parent = usesNode.getParent();
480 URI namespace = parent.getQName().getNamespace();
481 Date revision = parent.getQName().getRevision();
482 String prefix = parent.getQName().getPrefix();
483 String moduleName = parent.getModuleName();
484 int line = parent.getLine();
487 copyGroupingNodesToUsesNode(usesNode, namespace, revision, prefix, moduleName, line);
490 final Set<GroupingBuilder> newGroupings = new HashSet<>();
491 for (GroupingDefinition g : usesNode.getGroupingDefinition().getGroupings()) {
492 QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
493 GroupingBuilder newGrouping = CopyUtils.createGrouping(g, newQName, moduleName, line);
494 newGrouping.setAddedByUses(true);
495 newGroupings.add(newGrouping);
497 usesNode.getTargetGroupings().addAll(newGroupings);
500 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
501 for (TypeDefinition<?> td : usesNode.getGroupingDefinition().getTypeDefinitions()) {
502 QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
503 TypeDefinitionBuilder newType = CopyUtils.createTypedef((ExtendedType) td, newQName, moduleName, line);
504 newType.setAddedByUses(true);
505 newTypedefs.add(newType);
507 usesNode.getTargetTypedefs().addAll(newTypedefs);
510 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
511 for (UnknownSchemaNode un : usesNode.getGroupingDefinition().getUnknownSchemaNodes()) {
512 QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
513 UnknownSchemaNodeBuilder newNode = CopyUtils.createUnknownSchemaNode(un, newQName, moduleName, line);
514 newNode.setAddedByUses(true);
515 newUnknownNodes.add(newNode);
517 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
519 usesNode.setDataCollected(true);
523 * Read data defined in target grouping definition, make a copy and add them
524 * to uses node builder.
527 * used node builder to which are copied nodes from its
528 * <code>GroupingDefinition</code>
530 * URI with parent namespace
532 * date with parent revision date
534 * string with parent prefix
536 * string with parent module name
538 * number with YANG file row where is the parent defined
540 private static void copyGroupingNodesToUsesNode(final UsesNodeBuilder usesNode, final URI namespace,
541 final Date revision, final String prefix, final String moduleName, final int lineNumber) {
542 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
543 for (DataSchemaNode child : usesNode.getGroupingDefinition().getChildNodes()) {
545 DataSchemaNodeBuilder newChild = null;
546 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
547 if (child instanceof AnyXmlSchemaNode) {
548 newChild = CopyUtils.createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, lineNumber);
549 } else if (child instanceof ChoiceNode) {
550 newChild = CopyUtils.createChoice((ChoiceNode) child, newQName, moduleName, lineNumber);
551 } else if (child instanceof ContainerSchemaNode) {
552 newChild = CopyUtils.createContainer((ContainerSchemaNode) child, newQName, moduleName, lineNumber);
553 } else if (child instanceof LeafListSchemaNode) {
554 newChild = CopyUtils.createLeafList((LeafListSchemaNode) child, newQName, moduleName, lineNumber);
555 } else if (child instanceof LeafSchemaNode) {
556 newChild = CopyUtils.createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, lineNumber);
557 } else if (child instanceof ListSchemaNode) {
558 newChild = CopyUtils.createList((ListSchemaNode) child, newQName, moduleName, lineNumber);
561 if (newChild == null) {
562 throw new YangParseException(moduleName, lineNumber,
563 "Unknown member of target grouping while resolving uses node.");
565 if (newChild instanceof GroupingMember) {
566 ((GroupingMember) newChild).setAddedByUses(true);
569 newChildren.add(newChild);
572 usesNode.getTargetChildren().addAll(newChildren);
577 * Correct schema path of nodes added by uses statement.
580 * node added by uses statement
581 * @param parentSchemaPath
582 * schema path of parent node
583 * @param parentModule
584 * current parent node module
586 private static void correctNodePathForUsesNodes(final SchemaNodeBuilder node, final SchemaPath parentSchemaPath,
587 final ModuleBuilder parentModule) {
589 List<QName> targetNodePath = new ArrayList<QName>(parentSchemaPath.getPath());
590 targetNodePath.add(new QName(parentModule.getNamespace(), parentModule.getRevision(), parentModule.getPrefix(),
591 node.getQName().getLocalName()));
592 node.setPath(new SchemaPath(targetNodePath, true));
594 // set correct path for all child nodes
595 if (node instanceof DataNodeContainerBuilder) {
596 DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) node;
597 for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
598 correctNodePathForUsesNodes(child, node.getPath(), parentModule);
602 // set correct path for all cases
603 if (node instanceof ChoiceBuilder) {
604 ChoiceBuilder choiceBuilder = (ChoiceBuilder) node;
605 for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
606 correctNodePathForUsesNodes(choiceCaseBuilder, node.getPath(), parentModule);
612 * Perform refinement of uses target grouping nodes. Uses process has to be
617 public static void performRefine(UsesNodeBuilder usesNode) {
618 for (RefineHolder refine : usesNode.getRefines()) {
619 String refineTargetPath = refine.getName();
621 String[] splitted = refineTargetPath.split("/");
622 Builder currentNode = usesNode.getParent();
623 for (String pathElement : splitted) {
624 if (currentNode instanceof DataNodeContainerBuilder) {
625 currentNode = ((DataNodeContainerBuilder) currentNode).getDataChildByName(pathElement);
626 } else if (currentNode instanceof ChoiceBuilder) {
627 currentNode = ((ChoiceBuilder) currentNode).getCaseNodeByName(pathElement);
631 DataSchemaNodeBuilder nodeToRefine = (DataSchemaNodeBuilder) currentNode;
632 if (nodeToRefine == null) {
633 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
634 + refine.getName() + "' not found");
636 RefineUtils.performRefine(nodeToRefine, refine);
637 usesNode.addRefineNode(nodeToRefine);