Fix if-feature propagation for implicit case statements
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / ImplicitStmtCtx.java
1 /*
2  * Copyright (c) 2022 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.stmt.reactor;
9
10 import static com.google.common.base.Verify.verify;
11
12 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
13 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
14 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
15
16 /**
17  * A statement which has not been declared, but exists in the statement hierarchy through being an implicit intermediate
18  * statement -- like a {@code case} created by a {@code leaf} inside a {@code choice}.
19  *
20  * <p>
21  * That the contract of this class requires the caller to add child effective statement, if that does not happen, you
22  * get to keep the pieces.
23  *
24  * @param <A> Argument type
25  * @param <D> Declared Statement representation
26  * @param <E> Effective Statement representation
27  */
28 final class ImplicitStmtCtx<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
29         extends UndeclaredStmtCtx<A, D, E> {
30     private boolean checkedSubstatement;
31
32     // Exposed for AbstractResumedStatement.createUndeclared()
33     ImplicitStmtCtx(final StatementContextBase<?, ?, ?> parent, final StatementSupport<A, D, E> support,
34             final String rawArgument) {
35         super(parent, support, rawArgument);
36     }
37
38     @Override
39     public boolean isSupportedToBuildEffective() {
40         // The availability of this statement depends on its first substatement, added by the sole user of this class.
41         // We do not really have a reasonable lifecycle hook (yet?), so here we deactivate just before the state could
42         // be leaked.
43         if (!checkedSubstatement) {
44             final var substatements = effectiveSubstatements();
45             verify(!substatements.isEmpty(), "Unexpected empty substatements in %s", this);
46             final var substatement = substatements.iterator().next();
47             // Note: isSupportedByFeatures() is implemented as a walk towards root and we are walking in the opposite
48             //       direction. This check therefore must never be checked as part of isSupportedByFeatures() -- for
49             //       that reason we first in our direction (which may involve recursive calls to this method in a
50             //       substatement)
51             if (!substatement.isSupportedToBuildEffective() || !substatement.isSupportedByFeatures()) {
52                 setUnsupported();
53             }
54             checkedSubstatement = true;
55         }
56         return super.isSupportedToBuildEffective();
57     }
58 }