Revert "Do not call setFullyDefined() in ReplicateStatementContext"
[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.ImmutableList;
15 import com.google.common.collect.ImmutableSet;
16 import java.util.Collection;
17 import java.util.Optional;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
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.Status;
46 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
47 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.UsesNode;
49 import org.opendaylight.yangtools.yang.model.api.WhenConditionAware;
50 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
51 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
52 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
53 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorAppTagEffectiveStatement;
54 import org.opendaylight.yangtools.yang.model.api.stmt.ErrorMessageEffectiveStatement;
55 import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
56 import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement;
57 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
58 import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
59 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
60 import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
61 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
62 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
63 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
64 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
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         @Override
320         default QName getQName() {
321             return getPath().getLastComponent();
322         }
323     }
324
325     /**
326      * Bridge between {@link EffectiveStatementWithFlags} and {@link UnknownSchemaNode}.
327      *
328      * @param <A> Argument type ({@link Void} if statement does not have argument.)
329      * @param <D> Class representing declared version of this statement.
330      */
331     public interface UnknownSchemaNodeMixin<A, D extends DeclaredStatement<A>>
332             extends SchemaNodeMixin<A, D>, CopyableMixin<A, D>, UnknownSchemaNode {
333
334         @Override
335         default String getNodeParameter() {
336             return Strings.nullToEmpty(getDeclared().rawArgument());
337         }
338     }
339
340     /**
341      * Bridge between {@link EffectiveStatementWithFlags} and {@code ordered-by} statement.
342      *
343      * @param <A> Argument type ({@link Void} if statement does not have argument.)
344      * @param <D> Class representing declared version of this statement.
345      */
346     public interface UserOrderedMixin<A, D extends DeclaredStatement<A>> extends EffectiveStatementWithFlags<A, D> {
347         default boolean userOrdered() {
348             return (flags() & FlagsBuilder.USER_ORDERED) != 0;
349         }
350     }
351
352     /**
353      * Helper used to locate the effective {@code when} statement and exposing its argument as per
354      * {@link WhenConditionAware}.
355      *
356      * @param <A> Argument type ({@link Void} if statement does not have argument.)
357      * @param <D> Class representing declared version of this statement.
358      */
359     public interface WhenConditionMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, WhenConditionAware {
360         @Override
361         default Optional<QualifiedBound> getWhenCondition() {
362             return findFirstEffectiveSubstatementArgument(WhenEffectiveStatement.class);
363         }
364     }
365
366     /**
367      * Helper bridge for operation containers ({@code input} and {@code output}).
368      *
369      * @param <D> Class representing declared version of this statement.
370      */
371     public interface OperationContainerMixin<D extends DeclaredStatement<QName>>
372             extends ContainerLike, DocumentedNodeMixin.WithStatus<QName, D>, DataNodeContainerMixin<QName, D>,
373                     MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D>, AugmentationTargetMixin<QName, D>,
374                     SchemaNodeMixin<QName, D>, CopyableMixin<QName, D> {
375         @Override
376         default @NonNull QName argument() {
377             return getQName();
378         }
379
380         @Override
381         default Optional<ActionDefinition> findAction(final QName qname) {
382             return Optional.empty();
383         }
384
385         @Override
386         default Optional<NotificationDefinition> findNotification(final QName qname) {
387             return Optional.empty();
388         }
389
390         @Override
391         default Collection<? extends ActionDefinition> getActions() {
392             return ImmutableSet.of();
393         }
394
395         @Override
396         default Collection<? extends NotificationDefinition> getNotifications() {
397             return ImmutableSet.of();
398         }
399
400         @Override
401         default Optional<Boolean> effectiveConfig() {
402             return Optional.empty();
403         }
404
405         default String defaultToString() {
406             return MoreObjects.toStringHelper(this).add("path", getPath()).toString();
407         }
408     }
409
410     /**
411      * Helper bridge for {@code anydata} and {@code anyxml} opaque data.
412      *
413      * @param <D> Class representing declared version of this statement.
414      */
415     public interface OpaqueDataSchemaNodeMixin<D extends DeclaredStatement<QName>>
416             extends DerivableSchemaNode, DataSchemaNodeMixin<QName, D>, DocumentedNodeMixin.WithStatus<QName, D>,
417                     MandatoryMixin<QName, D>, MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D> {
418         @Override
419         default @NonNull QName argument() {
420             return getQName();
421         }
422     }
423
424     /**
425      * Helper bridge for {@code rpc} and {@code action} operations.
426      *
427      * @param <D> Class representing declared version of this statement.
428      */
429     public interface OperationDefinitionMixin<D extends DeclaredStatement<QName>>
430             extends SchemaNodeMixin<QName, D>, OperationDefinition {
431         @Override
432         default @NonNull QName argument() {
433             return getQName();
434         }
435
436         @Override
437         default Collection<? extends @NonNull TypeDefinition<?>> getTypeDefinitions() {
438             return filterTypeDefinitions(this);
439         }
440
441         @Override
442         default Collection<? extends @NonNull GroupingDefinition> getGroupings() {
443             return filterEffectiveStatements(GroupingDefinition.class);
444         }
445
446         @Override
447         default InputSchemaNode getInput() {
448             return findAsContainer(this, InputEffectiveStatement.class, InputSchemaNode.class);
449         }
450
451         @Override
452         default OutputSchemaNode getOutput() {
453             return findAsContainer(this, OutputEffectiveStatement.class, OutputSchemaNode.class);
454         }
455     }
456
457     /**
458      * Support interface for various mixins. Implementations are required to store 32bits worth of flags, which are
459      * globally assigned to sub-interfaces -- thus providing storage for many low-cardinality properties.
460      *
461      * @param <A> Argument type ({@link Void} if statement does not have argument.)
462      * @param <D> Class representing declared version of this statement.
463      */
464     public interface EffectiveStatementWithFlags<A, D extends DeclaredStatement<A>> extends Mixin<A, D> {
465         /**
466          * Return flags assicated with this statements. Flags can be built using {@link FlagsBuilder}.
467          *
468          * @return Flag field value (32 bits).
469          */
470         int flags();
471
472         @NonNullByDefault
473         final class FlagsBuilder implements Mutable {
474             // We still have 23 flags remaining
475             static final int STATUS_CURRENT       = 0x0001;
476             static final int STATUS_DEPRECATED    = 0x0002;
477             static final int STATUS_OBSOLETE      = 0x0003;
478             static final int MASK_STATUS          = 0x0003;
479
480             static final int MANDATORY            = 0x0004;
481
482             static final int AUGMENTING           = 0x0010;
483             static final int ADDED_BY_USES        = 0x0020;
484             private static final int MASK_HISTORY = 0x0030;
485
486             static final int USER_ORDERED         = 0x0040;
487             static final int PRESENCE             = 0x0080;
488
489             static final int CONFIG_UNDEF         = 0x0100;
490             static final int CONFIG_FALSE         = 0x0200;
491             static final int CONFIG_TRUE          = 0x0300;
492             static final int MASK_CONFIG          = CONFIG_TRUE;
493
494             private int flags;
495
496             public FlagsBuilder setConfiguration(final @Nullable Boolean config) {
497                 final int fl;
498                 if (config != null) {
499                     fl = config ? CONFIG_TRUE : CONFIG_FALSE;
500                 } else {
501                     fl = CONFIG_UNDEF;
502                 }
503                 flags = flags & ~MASK_CONFIG | fl;
504                 return this;
505             }
506
507             public FlagsBuilder setHistory(final CopyHistory history) {
508                 int bits;
509                 if (history.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
510                     bits = AUGMENTING | ADDED_BY_USES;
511                 } else {
512                     bits = 0;
513                     if (history.contains(CopyType.ADDED_BY_AUGMENTATION)) {
514                         bits |= AUGMENTING;
515                     }
516                     if (history.contains(CopyType.ADDED_BY_USES)) {
517                         bits |= ADDED_BY_USES;
518                     }
519                 }
520
521                 flags = flags & ~MASK_HISTORY | bits;
522                 return this;
523             }
524
525             public FlagsBuilder setMandatory(final boolean mandatory) {
526                 if (mandatory) {
527                     flags |= MANDATORY;
528                 } else {
529                     flags &= ~MANDATORY;
530                 }
531                 return this;
532             }
533
534             public FlagsBuilder setPresence(final boolean presence) {
535                 if (presence) {
536                     flags |= PRESENCE;
537                 } else {
538                     flags &= ~PRESENCE;
539                 }
540                 return this;
541             }
542
543             public FlagsBuilder setStatus(final Status status) {
544                 final int bits;
545                 switch (status) {
546                     case CURRENT:
547                         bits = STATUS_CURRENT;
548                         break;
549                     case DEPRECATED:
550                         bits = STATUS_DEPRECATED;
551                         break;
552                     case OBSOLETE:
553                         bits = STATUS_OBSOLETE;
554                         break;
555                     default:
556                         throw new IllegalStateException("Unhandled status " + status);
557                 }
558
559                 flags = flags & ~MASK_STATUS | bits;
560                 return this;
561             }
562
563             public FlagsBuilder setUserOrdered(final boolean userOrdered) {
564                 if (userOrdered) {
565                     flags |= USER_ORDERED;
566                 } else {
567                     flags &= ~USER_ORDERED;
568                 }
569                 return this;
570             }
571
572             public int toFlags() {
573                 return flags;
574             }
575         }
576     }
577
578     private EffectiveStatementMixins() {
579     }
580
581     static <T extends ContainerLike> T findAsContainer(final EffectiveStatement<?, ?> stmt,
582             final Class<? extends EffectiveStatement<QName, ?>> type, final Class<T> target) {
583         return target.cast(stmt.findFirstEffectiveSubstatement(type).get());
584     }
585
586     static Collection<? extends @NonNull TypeDefinition<?>> filterTypeDefinitions(final Mixin<?, ?> stmt) {
587         return Collections2.transform(stmt.filterEffectiveStatements(TypedefEffectiveStatement.class),
588             TypedefEffectiveStatement::getTypeDefinition);
589     }
590
591     public static int historyAndStatusFlags(final CopyHistory history,
592             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
593         return new FlagsBuilder()
594                 .setHistory(history)
595                 .setStatus(AbstractStatementSupport.findFirstArgument(substatements,
596                     StatusEffectiveStatement.class, Status.CURRENT))
597                 .toFlags();
598     }
599 }