29b540b8e4dfd32e961f0fa9aa79a060f1549bfa
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / EffectiveStatementMixins.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.Strings;
13 import com.google.common.collect.Collections2;
14 import com.google.common.collect.ImmutableSet;
15 import java.util.Collection;
16 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.yangtools.concepts.Immutable;
21 import org.opendaylight.yangtools.concepts.Mutable;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
24 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
25 import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
26 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
28 import org.opendaylight.yangtools.yang.model.api.ConstraintMetaDefinition;
29 import org.opendaylight.yangtools.yang.model.api.ContainerLike;
30 import org.opendaylight.yangtools.yang.model.api.CopyableNode;
31 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
32 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
35 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
36 import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.MandatoryAware;
38 import org.opendaylight.yangtools.yang.model.api.MustConstraintAware;
39 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
40 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
41 import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
42 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
43 import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
46 import org.opendaylight.yangtools.yang.model.api.Status;
47 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
48 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.UsesNode;
50 import org.opendaylight.yangtools.yang.model.api.WhenConditionAware;
51 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
52 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
53 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
54 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorAppTagEffectiveStatement;
55 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorMessageEffectiveStatement;
56 import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
57 import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement;
58 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
59 import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
60 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
61 import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
62 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
63 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
64 import org.opendaylight.yangtools.yang.parser.spi.meta.SchemaPathSupport;
65 import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression.QualifiedBound;
66
67 /**
68  * Mix-in interfaces providing services required by SchemaNode et al. These interfaces provide implementations, or
69  * implementation helpers based on default methods, so the correct behavior can be logically centralized.
70  */
71 @Beta
72 public final class EffectiveStatementMixins {
73     // Marker interface requiring all mixins to be derived from EffectiveStatement.
74     private interface Mixin<A, D extends DeclaredStatement<A>> extends EffectiveStatement<A, D> {
75         @SuppressWarnings("unchecked")
76         default <T> @NonNull Collection<? extends @NonNull T> filterEffectiveStatements(final Class<T> type) {
77             // Yeah, this is not nice, but saves one transformation
78             return (Collection<? extends T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
79         }
80     }
81
82     /**
83      * Bridge between {@link EffectiveStatement} and {@link AugmentationTarget}.
84      *
85      * @param <A> Argument type ({@link Void} if statement does not have argument.)
86      * @param <D> Class representing declared version of this statement.
87      */
88     public interface AugmentationTargetMixin<A, D extends DeclaredStatement<A>>
89             extends Mixin<A, D>, AugmentationTarget {
90         @Override
91         default Collection<? extends AugmentationSchemaNode> getAvailableAugmentations() {
92             return filterEffectiveStatements(AugmentationSchemaNode.class);
93         }
94     }
95
96     /**
97      * Bridge between {@link EffectiveStatementWithFlags} and {@link AddedByUsesAware}.
98      *
99      * @param <A> Argument type ({@link Void} if statement does not have argument.)
100      * @param <D> Class representing declared version of this statement.
101      */
102     public interface AddedByUsesMixin<A, D extends DeclaredStatement<A>>
103             extends EffectiveStatementWithFlags<A, D>, AddedByUsesAware {
104         @Override
105         @Deprecated
106         default boolean isAddedByUses() {
107             return (flags() & FlagsBuilder.ADDED_BY_USES) != 0;
108         }
109     }
110
111     /**
112      * Bridge between {@link EffectiveStatementWithFlags} and {@link ActionNodeContainer}.
113      *
114      * @param <A> Argument type ({@link Void} if statement does not have argument.)
115      * @param <D> Class representing declared version of this statement.
116      */
117     public interface ActionNodeContainerMixin<A, D extends DeclaredStatement<A>>
118             extends Mixin<A, D>, ActionNodeContainer {
119         @Override
120         default Collection<? extends ActionDefinition> getActions() {
121             return filterEffectiveStatements(ActionDefinition.class);
122         }
123     }
124
125     /**
126      * Bridge between {@link EffectiveStatementWithFlags} and {@link NotificationNodeContainer}.
127      *
128      * @param <A> Argument type ({@link Void} if statement does not have argument.)
129      * @param <D> Class representing declared version of this statement.
130      */
131     public interface NotificationNodeContainerMixin<A, D extends DeclaredStatement<A>>
132             extends Mixin<A, D>, NotificationNodeContainer {
133         @Override
134         default Collection<? extends NotificationDefinition> getNotifications() {
135             return filterEffectiveStatements(NotificationDefinition.class);
136         }
137     }
138
139     /**
140      * Bridge between {@link EffectiveStatementWithFlags} and {@link MustConstraintAware}.
141      *
142      * @param <A> Argument type ({@link Void} if statement does not have argument.)
143      * @param <D> Class representing declared version of this statement.
144      */
145     public interface MustConstraintMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, MustConstraintAware {
146         @Override
147         default Collection<? extends @NonNull MustDefinition> getMustConstraints() {
148             return filterEffectiveStatements(MustDefinition.class);
149         }
150     }
151
152     /**
153      * Bridge between {@link EffectiveStatementWithFlags} and {@link CopyableNode}.
154      *
155      * @param <A> Argument type ({@link Void} if statement does not have argument.)
156      * @param <D> Class representing declared version of this statement.
157      */
158     public interface CopyableMixin<A, D extends DeclaredStatement<A>> extends AddedByUsesMixin<A, D>, CopyableNode {
159         @Override
160         @Deprecated
161         default boolean isAugmenting() {
162             return (flags() & FlagsBuilder.AUGMENTING) != 0;
163         }
164     }
165
166     /**
167      * Bridge between {@link EffectiveStatementWithFlags} and {@link DataNodeContainer}.
168      *
169      * @param <A> Argument type ({@link Void} if statement does not have argument.)
170      * @param <D> Class representing declared version of this statement.
171      */
172     public interface DataNodeContainerMixin<A, D extends DeclaredStatement<A>> extends DataNodeContainer, Mixin<A, D> {
173         @Override
174         default Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
175             return filterTypeDefinitions(this);
176         }
177
178         @Override
179         default Collection<? extends DataSchemaNode> getChildNodes() {
180             return filterEffectiveStatements(DataSchemaNode.class);
181         }
182
183         @Override
184         default Collection<? extends GroupingDefinition> getGroupings() {
185             return filterEffectiveStatements(GroupingDefinition.class);
186         }
187
188         @Override
189         default Collection<? extends UsesNode> getUses() {
190             return filterEffectiveStatements(UsesNode.class);
191         }
192     }
193
194     /**
195      * Bridge between {@link EffectiveStatementWithFlags} and {@link DataSchemaNode}.
196      *
197      * @param <A> Argument type ({@link Void} if statement does not have argument.)
198      * @param <D> Class representing declared version of this statement.
199      */
200     public interface DataSchemaNodeMixin<A, D extends DeclaredStatement<A>>
201             extends DataSchemaNode, CopyableMixin<A, D>, SchemaNodeMixin<A, D>, WhenConditionMixin<A, D> {
202         @Override
203         default Optional<Boolean> effectiveConfig() {
204             final int fl = flags() & FlagsBuilder.MASK_CONFIG;
205             switch (fl) {
206                 case FlagsBuilder.CONFIG_FALSE:
207                     return Optional.of(Boolean.FALSE);
208                 case FlagsBuilder.CONFIG_TRUE:
209                     return Optional.of(Boolean.TRUE);
210                 case FlagsBuilder.CONFIG_UNDEF:
211                     return Optional.empty();
212                 default:
213                     throw new IllegalStateException("Unhandled effective config flags " + fl);
214             }
215         }
216     }
217
218     /**
219      * Bridge between {@link EffectiveStatementWithFlags} and {@link DocumentedNode}.
220      *
221      * @param <A> Argument type ({@link Void} if statement does not have argument.)
222      * @param <D> Class representing declared version of this statement.
223      */
224     public interface DocumentedNodeMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, DocumentedNode {
225         /**
226          * Bridge between {@link EffectiveStatementWithFlags} and
227          * {@link org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus}.
228          *
229          * @param <A> Argument type ({@link Void} if statement does not have argument.)
230          * @param <D> Class representing declared version of this statement.
231          */
232         interface WithStatus<A, D extends DeclaredStatement<A>>
233                 extends EffectiveStatementWithFlags<A, D>, DocumentedNodeMixin<A, D>, DocumentedNode.WithStatus {
234             @Override
235             default Status getStatus() {
236                 final int status = flags() & FlagsBuilder.MASK_STATUS;
237                 switch (status) {
238                     case FlagsBuilder.STATUS_CURRENT:
239                         return Status.CURRENT;
240                     case FlagsBuilder.STATUS_DEPRECATED:
241                         return Status.DEPRECATED;
242                     case FlagsBuilder.STATUS_OBSOLETE:
243                         return Status.OBSOLETE;
244                     default:
245                         throw new IllegalStateException("Illegal status " + status);
246                 }
247             }
248         }
249
250         @Override
251         default Optional<String> getDescription() {
252             return findFirstEffectiveSubstatementArgument(DescriptionEffectiveStatement.class);
253         }
254
255         @Override
256         default Optional<String> getReference() {
257             return findFirstEffectiveSubstatementArgument(ReferenceEffectiveStatement.class);
258         }
259
260         @Override
261         default Collection<? extends UnknownSchemaNode> getUnknownSchemaNodes() {
262             return filterEffectiveStatements(UnknownSchemaNode.class);
263         }
264     }
265
266     /**
267      * Bridge between {@link EffectiveStatementWithFlags} and {@link ConstraintMetaDefinition}.
268      *
269      * @param <A> Argument type ({@link Void} if statement does not have argument.)
270      * @param <D> Class representing declared version of this statement.
271      */
272     public interface ConstraintMetaDefinitionMixin<A, D extends DeclaredStatement<A>> extends DocumentedNodeMixin<A, D>,
273             ConstraintMetaDefinition {
274         @Override
275         default Optional<String> getErrorAppTag() {
276             return findFirstEffectiveSubstatementArgument(ErrorAppTagEffectiveStatement.class);
277         }
278
279         @Override
280         default Optional<String> getErrorMessage() {
281             return findFirstEffectiveSubstatementArgument(ErrorMessageEffectiveStatement.class);
282         }
283     }
284
285     /**
286      * Bridge between {@link EffectiveStatementWithFlags} and {@link MandatoryAware}.
287      *
288      * @param <A> Argument type ({@link Void} if statement does not have argument.)
289      * @param <D> Class representing declared version of this statement.
290      */
291     public interface MandatoryMixin<A, D extends DeclaredStatement<A>>
292             extends EffectiveStatementWithFlags<A, D>, MandatoryAware {
293         @Override
294         default boolean isMandatory() {
295             return (flags() & FlagsBuilder.MANDATORY) != 0;
296         }
297     }
298
299     /**
300      * Bridge between {@link EffectiveStatementWithFlags} and {@code presence} statement.
301      *
302      * @param <A> Argument type ({@link Void} if statement does not have argument.)
303      * @param <D> Class representing declared version of this statement.
304      */
305     public interface PresenceMixin<A, D extends DeclaredStatement<A>> extends EffectiveStatementWithFlags<A, D> {
306         default boolean presence() {
307             return (flags() & FlagsBuilder.PRESENCE) != 0;
308         }
309     }
310
311     /**
312      * Bridge between {@link EffectiveStatementWithFlags} and {@link SchemaNode}.
313      *
314      * @param <A> Argument type ({@link Void} if statement does not have argument.)
315      * @param <D> Class representing declared version of this statement.
316      */
317     public interface SchemaNodeMixin<A, D extends DeclaredStatement<A>>
318             extends DocumentedNodeMixin.WithStatus<A, D>, SchemaNode {
319         // FIXME: ditch all this complexity once we do not require SchemaPath
320         @Override
321         default QName getQName() {
322             return SchemaPathSupport.extractQName(pathObject());
323         }
324
325         @Override
326         @Deprecated
327         default SchemaPath getPath() {
328             return SchemaPathSupport.extractPath(this, pathObject());
329         }
330
331         @NonNull Immutable pathObject();
332     }
333
334     /**
335      * Bridge between {@link EffectiveStatementWithFlags} and {@link UnknownSchemaNode}.
336      *
337      * @param <A> Argument type ({@link Void} if statement does not have argument.)
338      * @param <D> Class representing declared version of this statement.
339      */
340     public interface UnknownSchemaNodeMixin<A, D extends DeclaredStatement<A>>
341             extends SchemaNodeMixin<A, D>, CopyableMixin<A, D>, UnknownSchemaNode {
342
343         @Override
344         default String getNodeParameter() {
345             return Strings.nullToEmpty(getDeclared().rawArgument());
346         }
347     }
348
349     /**
350      * Bridge between {@link EffectiveStatementWithFlags} and {@code ordered-by} statement.
351      *
352      * @param <A> Argument type ({@link Void} if statement does not have argument.)
353      * @param <D> Class representing declared version of this statement.
354      */
355     public interface UserOrderedMixin<A, D extends DeclaredStatement<A>> extends EffectiveStatementWithFlags<A, D> {
356         default boolean userOrdered() {
357             return (flags() & FlagsBuilder.USER_ORDERED) != 0;
358         }
359     }
360
361     /**
362      * Helper used to locate the effective {@code when} statement and exposing its argument as per
363      * {@link WhenConditionAware}.
364      *
365      * @param <A> Argument type ({@link Void} if statement does not have argument.)
366      * @param <D> Class representing declared version of this statement.
367      */
368     public interface WhenConditionMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, WhenConditionAware {
369         @Override
370         default Optional<QualifiedBound> getWhenCondition() {
371             return findFirstEffectiveSubstatementArgument(WhenEffectiveStatement.class);
372         }
373     }
374
375     /**
376      * Helper bridge for operation containers ({@code input} and {@code output}).
377      *
378      * @param <D> Class representing declared version of this statement.
379      */
380     public interface OperationContainerMixin<D extends DeclaredStatement<QName>>
381             extends ContainerLike, DocumentedNodeMixin.WithStatus<QName, D>, DataNodeContainerMixin<QName, D>,
382                     MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D>, AugmentationTargetMixin<QName, D>,
383                     SchemaNodeMixin<QName, D>, CopyableMixin<QName, D> {
384         @Override
385         default @NonNull QName argument() {
386             return getQName();
387         }
388
389         @Override
390         default Optional<ActionDefinition> findAction(final QName qname) {
391             return Optional.empty();
392         }
393
394         @Override
395         default Optional<NotificationDefinition> findNotification(final QName qname) {
396             return Optional.empty();
397         }
398
399         @Override
400         default Collection<? extends ActionDefinition> getActions() {
401             return ImmutableSet.of();
402         }
403
404         @Override
405         default Collection<? extends NotificationDefinition> getNotifications() {
406             return ImmutableSet.of();
407         }
408
409         @Override
410         default Optional<Boolean> effectiveConfig() {
411             return Optional.empty();
412         }
413
414         default String defaultToString() {
415             return MoreObjects.toStringHelper(this).add("qname", getQName()).toString();
416         }
417     }
418
419     /**
420      * Helper bridge for {@code anydata} and {@code anyxml} opaque data.
421      *
422      * @param <D> Class representing declared version of this statement.
423      */
424     public interface OpaqueDataSchemaNodeMixin<D extends DeclaredStatement<QName>>
425             extends DerivableSchemaNode, DataSchemaNodeMixin<QName, D>, DocumentedNodeMixin.WithStatus<QName, D>,
426                     MandatoryMixin<QName, D>, MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D> {
427         @Override
428         default @NonNull QName argument() {
429             return getQName();
430         }
431     }
432
433     /**
434      * Helper bridge for {@code rpc} and {@code action} operations.
435      *
436      * @param <D> Class representing declared version of this statement.
437      */
438     public interface OperationDefinitionMixin<D extends DeclaredStatement<QName>>
439             extends SchemaNodeMixin<QName, D>, OperationDefinition {
440         @Override
441         default @NonNull QName argument() {
442             return getQName();
443         }
444
445         @Override
446         default Collection<? extends @NonNull TypeDefinition<?>> getTypeDefinitions() {
447             return filterTypeDefinitions(this);
448         }
449
450         @Override
451         default Collection<? extends @NonNull GroupingDefinition> getGroupings() {
452             return filterEffectiveStatements(GroupingDefinition.class);
453         }
454
455         @Override
456         default InputSchemaNode getInput() {
457             return findAsContainer(this, InputEffectiveStatement.class, InputSchemaNode.class);
458         }
459
460         @Override
461         default OutputSchemaNode getOutput() {
462             return findAsContainer(this, OutputEffectiveStatement.class, OutputSchemaNode.class);
463         }
464     }
465
466     /**
467      * Support interface for various mixins. Implementations are required to store 32bits worth of flags, which are
468      * globally assigned to sub-interfaces -- thus providing storage for many low-cardinality properties.
469      *
470      * @param <A> Argument type ({@link Void} if statement does not have argument.)
471      * @param <D> Class representing declared version of this statement.
472      */
473     public interface EffectiveStatementWithFlags<A, D extends DeclaredStatement<A>> extends Mixin<A, D> {
474         /**
475          * Return flags associated with this statements. Flags can be built using {@link FlagsBuilder}.
476          *
477          * @return Flag field value (32 bits).
478          */
479         int flags();
480
481         @NonNullByDefault
482         final class FlagsBuilder implements Mutable {
483             // We still have 23 flags remaining
484             static final int STATUS_CURRENT       = 0x0001;
485             static final int STATUS_DEPRECATED    = 0x0002;
486             static final int STATUS_OBSOLETE      = 0x0003;
487             static final int MASK_STATUS          = 0x0003;
488
489             static final int MANDATORY            = 0x0004;
490
491             static final int AUGMENTING           = 0x0010;
492             static final int ADDED_BY_USES        = 0x0020;
493             private static final int MASK_HISTORY = 0x0030;
494
495             static final int USER_ORDERED         = 0x0040;
496             static final int PRESENCE             = 0x0080;
497
498             static final int CONFIG_UNDEF         = 0x0100;
499             static final int CONFIG_FALSE         = 0x0200;
500             static final int CONFIG_TRUE          = 0x0300;
501             static final int MASK_CONFIG          = CONFIG_TRUE;
502
503             private int flags;
504
505             public FlagsBuilder setConfiguration(final @Nullable Boolean config) {
506                 final int fl;
507                 if (config != null) {
508                     fl = config ? CONFIG_TRUE : CONFIG_FALSE;
509                 } else {
510                     fl = CONFIG_UNDEF;
511                 }
512                 flags = flags & ~MASK_CONFIG | fl;
513                 return this;
514             }
515
516             public FlagsBuilder setHistory(final CopyableNode history) {
517                 flags = flags & ~MASK_HISTORY
518                     | (history.isAugmenting() ? AUGMENTING : 0) | (history.isAddedByUses() ? ADDED_BY_USES : 0);
519                 return this;
520             }
521
522             public FlagsBuilder setMandatory(final boolean mandatory) {
523                 if (mandatory) {
524                     flags |= MANDATORY;
525                 } else {
526                     flags &= ~MANDATORY;
527                 }
528                 return this;
529             }
530
531             public FlagsBuilder setPresence(final boolean presence) {
532                 if (presence) {
533                     flags |= PRESENCE;
534                 } else {
535                     flags &= ~PRESENCE;
536                 }
537                 return this;
538             }
539
540             public FlagsBuilder setStatus(final Status status) {
541                 final int bits;
542                 switch (status) {
543                     case CURRENT:
544                         bits = STATUS_CURRENT;
545                         break;
546                     case DEPRECATED:
547                         bits = STATUS_DEPRECATED;
548                         break;
549                     case OBSOLETE:
550                         bits = STATUS_OBSOLETE;
551                         break;
552                     default:
553                         throw new IllegalStateException("Unhandled status " + status);
554                 }
555
556                 flags = flags & ~MASK_STATUS | bits;
557                 return this;
558             }
559
560             public FlagsBuilder setUserOrdered(final boolean userOrdered) {
561                 if (userOrdered) {
562                     flags |= USER_ORDERED;
563                 } else {
564                     flags &= ~USER_ORDERED;
565                 }
566                 return this;
567             }
568
569             public int toFlags() {
570                 return flags;
571             }
572         }
573     }
574
575     private EffectiveStatementMixins() {
576     }
577
578     static <T extends ContainerLike> T findAsContainer(final EffectiveStatement<?, ?> stmt,
579             final Class<? extends EffectiveStatement<QName, ?>> type, final Class<T> target) {
580         return target.cast(stmt.findFirstEffectiveSubstatement(type).get());
581     }
582
583     static Collection<? extends @NonNull TypeDefinition<?>> filterTypeDefinitions(final Mixin<?, ?> stmt) {
584         return Collections2.transform(stmt.filterEffectiveStatements(TypedefEffectiveStatement.class),
585             TypedefEffectiveStatement::getTypeDefinition);
586     }
587
588     public static int historyAndStatusFlags(final CopyableNode history,
589             final Collection<? extends EffectiveStatement<?, ?>> substatements) {
590         return new FlagsBuilder()
591                 .setHistory(history)
592                 .setStatus(AbstractStatementSupport.findFirstArgument(substatements,
593                     StatusEffectiveStatement.class, Status.CURRENT))
594                 .toFlags();
595     }
596 }