*/
package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
-import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangVersion;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.UnresolvedNumber;
+import org.opendaylight.yangtools.yang.model.api.stmt.ValueRange;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
-import org.opendaylight.yangtools.yang.model.util.BinaryType;
-import org.opendaylight.yangtools.yang.model.util.BooleanType;
-import org.opendaylight.yangtools.yang.model.util.EmptyType;
-import org.opendaylight.yangtools.yang.model.util.Int16;
-import org.opendaylight.yangtools.yang.model.util.Int32;
-import org.opendaylight.yangtools.yang.model.util.Int64;
-import org.opendaylight.yangtools.yang.model.util.Int8;
-import org.opendaylight.yangtools.yang.model.util.StringType;
-import org.opendaylight.yangtools.yang.model.util.Uint16;
-import org.opendaylight.yangtools.yang.model.util.Uint32;
-import org.opendaylight.yangtools.yang.model.util.Uint64;
-import org.opendaylight.yangtools.yang.model.util.Uint8;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.LengthConstraintEffectiveImpl;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.QNameCacheNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.RangeConstraintEffectiveImpl;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type.TypeDefinitionEffectiveBuilder;
-import org.opendaylight.yangtools.yang.parser.util.UnknownBoundaryNumber;
/**
-* util class for manipulating YANG base and extended types implementation
+* Utility class for manipulating YANG base and extended types implementation.
*/
public final class TypeUtils {
public static final String UINT64 = "uint64";
public static final String UNION = "union";
- private static final Set<String> BUILT_IN_TYPES = new HashSet<>();
- public static final Set<String> TYPE_BODY_STMTS = new HashSet<>();
- public static final Map<String, TypeDefinition<?>> PRIMITIVE_TYPES_MAP = new HashMap<>();
-
- private static final Comparator<TypeDefinition<?>> TYPE_SORT_COMPARATOR = new Comparator<TypeDefinition<?>>() {
- @Override
- public int compare(TypeDefinition<?> o1, TypeDefinition<?> o2) {
- if (isBuiltInType(o1) && !isBuiltInType(o2)) {
- return -1;
- }
- if (!isBuiltInType(o1) && isBuiltInType(o2)) {
- return 1;
- }
- return 0;
- }
- };
- static {
-
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,BINARY));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,BITS));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,BOOLEAN));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,DECIMAL64));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,EMPTY));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,ENUMERATION));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,IDENTITY_REF));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INSTANCE_IDENTIFIER));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT8));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT16));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT32));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,INT64));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,LEAF_REF));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,STRING));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT8));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT16));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT32));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UINT64));
-// BUILT_IN_TYPES.add(QName.create(YangConstants.RFC6020_YANG_MODULE,UNION));
-
- BUILT_IN_TYPES.add(BINARY);
- BUILT_IN_TYPES.add(BITS);
- BUILT_IN_TYPES.add(BOOLEAN);
- BUILT_IN_TYPES.add(DECIMAL64);
- BUILT_IN_TYPES.add(EMPTY);
- BUILT_IN_TYPES.add(ENUMERATION);
- BUILT_IN_TYPES.add(IDENTITY_REF);
- BUILT_IN_TYPES.add(INSTANCE_IDENTIFIER);
- BUILT_IN_TYPES.add(INT8);
- BUILT_IN_TYPES.add(INT16);
- BUILT_IN_TYPES.add(INT32);
- BUILT_IN_TYPES.add(INT64);
- BUILT_IN_TYPES.add(LEAF_REF);
- BUILT_IN_TYPES.add(STRING);
- BUILT_IN_TYPES.add(UINT8);
- BUILT_IN_TYPES.add(UINT16);
- BUILT_IN_TYPES.add(UINT32);
- BUILT_IN_TYPES.add(UINT64);
- BUILT_IN_TYPES.add(UNION);
-
- TYPE_BODY_STMTS.add(DECIMAL64);
- TYPE_BODY_STMTS.add(ENUMERATION);
- TYPE_BODY_STMTS.add(LEAF_REF);
- TYPE_BODY_STMTS.add(IDENTITY_REF);
- TYPE_BODY_STMTS.add(INSTANCE_IDENTIFIER);
- TYPE_BODY_STMTS.add(BITS);
- TYPE_BODY_STMTS.add(UNION);
-
- PRIMITIVE_TYPES_MAP.put(BINARY, BinaryType.getInstance());
- PRIMITIVE_TYPES_MAP.put(BOOLEAN, BooleanType.getInstance());
- PRIMITIVE_TYPES_MAP.put(EMPTY, EmptyType.getInstance());
- PRIMITIVE_TYPES_MAP.put(INT8, Int8.getInstance());
- PRIMITIVE_TYPES_MAP.put(INT16, Int16.getInstance());
- PRIMITIVE_TYPES_MAP.put(INT32, Int32.getInstance());
- PRIMITIVE_TYPES_MAP.put(INT64, Int64.getInstance());
- PRIMITIVE_TYPES_MAP.put(STRING, StringType.getInstance());
- PRIMITIVE_TYPES_MAP.put(UINT8, Uint8.getInstance());
- PRIMITIVE_TYPES_MAP.put(UINT16, Uint16.getInstance());
- PRIMITIVE_TYPES_MAP.put(UINT32, Uint32.getInstance());
- PRIMITIVE_TYPES_MAP.put(UINT64, Uint64.getInstance());
- }
+ private static final Map<String, String> BUILT_IN_TYPES = ImmutableMap.<String, String>builder()
+ .put(BINARY, BINARY)
+ .put(BITS, BITS)
+ .put(BOOLEAN, BOOLEAN)
+ .put(DECIMAL64, DECIMAL64)
+ .put(EMPTY, EMPTY)
+ .put(ENUMERATION, ENUMERATION)
+ .put(IDENTITY_REF,IDENTITY_REF)
+ .put(INSTANCE_IDENTIFIER, INSTANCE_IDENTIFIER)
+ .put(INT8, INT8)
+ .put(INT16, INT16)
+ .put(INT32, INT32)
+ .put(INT64, INT64)
+ .put(LEAF_REF, LEAF_REF)
+ .put(STRING, STRING)
+ .put(UINT8, UINT8)
+ .put(UINT16, UINT16)
+ .put(UINT32, UINT32)
+ .put(UINT64, UINT64)
+ .put(UNION, UNION)
+ .build();
+
+ private static final Set<String> TYPE_BODY_STMTS = ImmutableSet.of(
+ DECIMAL64, ENUMERATION, LEAF_REF, IDENTITY_REF, BITS, UNION);
+ private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
+ private static final Splitter TWO_DOTS_SPLITTER = Splitter.on("..").trimResults();
private TypeUtils() {
}
- private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
- private static final Splitter TWO_DOTS_SPLITTER = Splitter.on("..").trimResults();
-
- private static BigDecimal yangConstraintToBigDecimal(Number number) {
- if (number instanceof UnknownBoundaryNumber) {
- if (number.toString().equals("min")) {
- return RangeStatementImpl.YANG_MIN_NUM;
- } else {
- return RangeStatementImpl.YANG_MAX_NUM;
- }
- } else {
- return new BigDecimal(number.toString());
+ private static BigDecimal yangConstraintToBigDecimal(final Number number) {
+ if (UnresolvedNumber.max().equals(number)) {
+ return RangeStatementImpl.YANG_MAX_NUM;
+ }
+ if (UnresolvedNumber.min().equals(number)) {
+ return RangeStatementImpl.YANG_MIN_NUM;
}
+
+ return new BigDecimal(number.toString());
}
- public static int compareNumbers(Number n1, Number n2) {
+ private static int compareNumbers(final Number n1, final Number n2) {
final BigDecimal num1 = yangConstraintToBigDecimal(n1);
final BigDecimal num2 = yangConstraintToBigDecimal(n2);
return new BigDecimal(num1.toString()).compareTo(new BigDecimal(num2.toString()));
}
- private static Number parseIntegerConstraintValue(final String value) {
- Number result;
+ private static Number parseIntegerConstraintValue(final StmtContext<?, ?, ?> ctx, final String value) {
+ if ("max".equals(value)) {
+ return UnresolvedNumber.max();
+ }
+ if ("min".equals(value)) {
+ return UnresolvedNumber.min();
+ }
- if (isMinOrMaxString(value)) {
- result = new UnknownBoundaryNumber(value);
- } else {
- try {
- result = new BigInteger(value);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(String.format("Value %s is not a valid integer", value), e);
- }
+ try {
+ return new BigInteger(value);
+ } catch (final NumberFormatException e) {
+ throw new SourceException(ctx.getStatementSourceReference(), e, "Value %s is not a valid integer", value);
}
- return result;
}
- private static Number parseDecimalConstraintValue(final String value) {
- final Number result;
-
- if (isMinOrMaxString(value)) {
- result = new UnknownBoundaryNumber(value);
- } else {
- try {
- if (value.indexOf('.') != -1) {
- result = new BigDecimal(value);
- } else {
- result = new BigInteger(value);
- }
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(String.format("Value %s is not a valid decimal number", value), e);
- }
+ private static Number parseDecimalConstraintValue(final StmtContext<?, ?, ?> ctx, final String value) {
+ if ("max".equals(value)) {
+ return UnresolvedNumber.max();
+ }
+ if ("min".equals(value)) {
+ return UnresolvedNumber.min();
}
- return result;
- }
- private static boolean isMinOrMaxString(final String value) {
- return "min".equals(value) || "max".equals(value);
+ try {
+ return value.indexOf('.') != -1 ? new BigDecimal(value) : new BigInteger(value);
+ } catch (final NumberFormatException e) {
+ throw new SourceException(String.format("Value %s is not a valid decimal number", value),
+ ctx.getStatementSourceReference(), e);
+ }
}
- public static List<RangeConstraint> parseRangeListFromString(String rangeArgument) {
+ public static List<RangeConstraint> parseRangeListFromString(final StmtContext<?, ?, ?> ctx,
+ final String rangeArgument) {
- Optional<String> description = Optional.absent();
- Optional<String> reference = Optional.absent();
+ final Optional<String> description = Optional.empty();
+ final Optional<String> reference = Optional.empty();
- List<RangeConstraint> rangeConstraints = new ArrayList<>();
+ final List<RangeConstraint> rangeConstraints = new ArrayList<>();
for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) {
final Iterator<String> boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator();
- final Number min = parseDecimalConstraintValue(boundaries.next());
+ final Number min = parseDecimalConstraintValue(ctx, boundaries.next());
final Number max;
if (boundaries.hasNext()) {
- max = parseDecimalConstraintValue(boundaries.next());
+ max = parseDecimalConstraintValue(ctx, boundaries.next());
// if min larger than max then error
- if (compareNumbers(min, max) == 1) {
- throw new IllegalArgumentException(String.format(
- "Range constraint %s has descending order of boundaries; should be ascending", singleRange));
- }
- if (boundaries.hasNext()) {
- throw new IllegalArgumentException("Wrong number of boundaries in range constraint " + singleRange);
- }
+ InferenceException.throwIf(compareNumbers(min, max) == 1, ctx.getStatementSourceReference(),
+ "Range constraint %s has descending order of boundaries; should be ascending", singleRange);
+
+ SourceException.throwIf(boundaries.hasNext(), ctx.getStatementSourceReference(),
+ "Wrong number of boundaries in range constraint %s", singleRange);
} else {
max = min;
}
// some of intervals overlapping
if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) {
- throw new IllegalArgumentException(String.format("Some of the ranges in %s are not disjoint",
- rangeArgument));
+ throw new InferenceException(ctx.getStatementSourceReference(),
+ "Some of the ranges in %s are not disjoint", rangeArgument);
}
rangeConstraints.add(new RangeConstraintEffectiveImpl(min, max, description, reference));
return rangeConstraints;
}
- public static List<LengthConstraint> parseLengthListFromString(String rangeArgument) {
+ public static List<ValueRange> parseLengthListFromString(final StmtContext<?, ?, ?> ctx,
+ final String lengthArgument) {
+ final List<ValueRange> ranges = new ArrayList<>();
- Optional<String> description = Optional.absent();
- Optional<String> reference = Optional.absent();
-
- List<LengthConstraint> rangeConstraints = new ArrayList<>();
-
- for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) {
- final Iterator<String> boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator();
- final Number min = parseIntegerConstraintValue(boundaries.next());
+ for (final String singleRange : PIPE_SPLITTER.split(lengthArgument)) {
+ final Iterator<String> boundaries = TWO_DOTS_SPLITTER.split(singleRange).iterator();
+ final Number min = parseIntegerConstraintValue(ctx, boundaries.next());
final Number max;
if (boundaries.hasNext()) {
- max = parseIntegerConstraintValue(boundaries.next());
+ max = parseIntegerConstraintValue(ctx, boundaries.next());
// if min larger than max then error
- if (compareNumbers(min, max) == 1) {
- throw new IllegalArgumentException(
- String.format(
- "Length constraint %s has descending order of boundaries; should be ascending",
- singleRange));
- }
- if (boundaries.hasNext()) {
- throw new IllegalArgumentException("Wrong number of boundaries in length constraint " + singleRange);
- }
+ SourceException.throwIf(compareNumbers(min, max) == 1, ctx.getStatementSourceReference(),
+ "Length constraint %s has descending order of boundaries; should be ascending.",
+ singleRange);
+ SourceException.throwIf(boundaries.hasNext(), ctx.getStatementSourceReference(),
+ "Wrong number of boundaries in length constraint %s.", singleRange);
} else {
max = min;
}
// some of intervals overlapping
- if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) {
- throw new IllegalArgumentException(String.format("Some of the length ranges in %s are not disjoint",
- rangeArgument));
- }
+ InferenceException.throwIf(ranges.size() > 1
+ && compareNumbers(min, Iterables.getLast(ranges).upperBound()) != 1,
+ ctx.getStatementSourceReference(), "Some of the length ranges in %s are not disjoint",
+ lengthArgument);
- rangeConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference));
+ ranges.add(ValueRange.of(min, max));
}
- return rangeConstraints;
+ return ranges;
+ }
+
+ public static boolean isYangTypeBodyStmtString(final String typeName) {
+ return TYPE_BODY_STMTS.contains(typeName);
}
- public static boolean isBuiltInType(TypeDefinition<?> o1) {
- return BUILT_IN_TYPES.contains(o1.getQName().getLocalName());
+ public static boolean isYangBuiltInTypeString(final String typeName) {
+ return BUILT_IN_TYPES.containsKey(typeName);
}
- public static boolean isYangBuiltInTypeString(String typeName) {
- return BUILT_IN_TYPES.contains(typeName);
+
+ public static SchemaPath typeEffectiveSchemaPath(final StmtContext<?, ?, ?> stmtCtx) {
+ final SchemaPath path = stmtCtx.getSchemaPath().get();
+ final SchemaPath parent = path.getParent();
+ final QName parentQName = parent.getLastComponent();
+ Preconditions.checkArgument(parentQName != null, "Path %s has an empty parent", path);
+
+ final QName qname = stmtCtx.getFromNamespace(QNameCacheNamespace.class,
+ QName.create(parentQName, path.getLastComponent().getLocalName()));
+ return parent.createChild(qname);
}
- public static boolean isYangPrimitiveTypeString(String typeName) {
- return PRIMITIVE_TYPES_MAP.containsKey(typeName);
+ /**
+ * Checks whether supplied type has any of specified default values marked
+ * with an if-feature. This method creates mutable copy of supplied set of
+ * default values.
+ *
+ * @param yangVersion
+ * yang version
+ * @param typeStmt
+ * type statement which should be checked
+ * @param defaultValues
+ * set of default values which should be checked. The method
+ * creates mutable copy of this set
+ *
+ * @return true if any of specified default values is marked with an
+ * if-feature, otherwise false
+ */
+ public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
+ final TypeEffectiveStatement<?> typeStmt, final Set<String> defaultValues) {
+ return !defaultValues.isEmpty() && yangVersion == YangVersion.VERSION_1_1
+ && isRelevantForIfFeatureCheck(typeStmt)
+ && isAnyDefaultValueMarkedWithIfFeature(typeStmt, new HashSet<>(defaultValues));
}
- public static boolean isYangTypeBodyStmtString(String typeName) {
- return TYPE_BODY_STMTS.contains(typeName);
+ /**
+ * Checks whether supplied type has specified default value marked with an
+ * if-feature. This method creates mutable set of supplied default value.
+ *
+ * @param yangVersion
+ * yang version
+ * @param typeStmt
+ * type statement which should be checked
+ * @param defaultValue
+ * default value to be checked
+ *
+ * @return true if specified default value is marked with an if-feature,
+ * otherwise false
+ */
+ public static boolean hasDefaultValueMarkedWithIfFeature(final YangVersion yangVersion,
+ final TypeEffectiveStatement<?> typeStmt, final String defaultValue) {
+ final HashSet<String> defaultValues = new HashSet<>();
+ defaultValues.add(defaultValue);
+ return !Strings.isNullOrEmpty(defaultValue) && yangVersion == YangVersion.VERSION_1_1
+ && isRelevantForIfFeatureCheck(typeStmt)
+ && isAnyDefaultValueMarkedWithIfFeature(typeStmt, defaultValues);
}
- public static TypeDefinition<?> getYangPrimitiveTypeFromString(String typeName) {
- if (PRIMITIVE_TYPES_MAP.containsKey(typeName)) {
- return PRIMITIVE_TYPES_MAP.get(typeName);
- }
- return null;
+ static String findBuiltinString(final String rawArgument) {
+ return BUILT_IN_TYPES.get(rawArgument);
}
- public static TypeDefinition<?> getTypeFromEffectiveStatement(EffectiveStatement<?, ?> effectiveStatement) {
- if (effectiveStatement instanceof TypeDefinitionEffectiveBuilder) {
- TypeDefinitionEffectiveBuilder typeDefEffectiveBuilder = (TypeDefinitionEffectiveBuilder) effectiveStatement;
- return typeDefEffectiveBuilder.buildType();
- } else {
- final String typeName = ((TypeDefinition<?>) effectiveStatement).getQName().getLocalName();
- return PRIMITIVE_TYPES_MAP.get(typeName);
- }
+ private static boolean isRelevantForIfFeatureCheck(final TypeEffectiveStatement<?> typeStmt) {
+ final TypeDefinition<?> typeDefinition = typeStmt.getTypeDefinition();
+ return typeDefinition instanceof EnumTypeDefinition || typeDefinition instanceof BitsTypeDefinition
+ || typeDefinition instanceof UnionTypeDefinition;
}
- public static void sortTypes(List<TypeDefinition<?>> typesInit) {
- Collections.sort(typesInit, TYPE_SORT_COMPARATOR);
+ private static boolean isAnyDefaultValueMarkedWithIfFeature(final TypeEffectiveStatement<?> typeStmt,
+ final Set<String> defaultValues) {
+ final Iterator<? extends EffectiveStatement<?, ?>> iter = typeStmt.effectiveSubstatements().iterator();
+ while (iter.hasNext() && !defaultValues.isEmpty()) {
+ final EffectiveStatement<?, ?> effectiveSubstatement = iter.next();
+ if (YangStmtMapping.BIT.equals(effectiveSubstatement.statementDefinition())) {
+ final QName bitQName = (QName) effectiveSubstatement.argument();
+ if (defaultValues.remove(bitQName.getLocalName()) && containsIfFeature(effectiveSubstatement)) {
+ return true;
+ }
+ } else if (YangStmtMapping.ENUM.equals(effectiveSubstatement.statementDefinition())
+ && defaultValues.remove(effectiveSubstatement.argument())
+ && containsIfFeature(effectiveSubstatement)) {
+ return true;
+ } else if (effectiveSubstatement instanceof TypeEffectiveStatement && isAnyDefaultValueMarkedWithIfFeature(
+ (TypeEffectiveStatement<?>) effectiveSubstatement, defaultValues)) {
+ return true;
+ }
+ }
+
+ return false;
}
+ private static boolean containsIfFeature(final EffectiveStatement<?, ?> effectiveStatement) {
+ for (final EffectiveStatement<?, ?> effectiveSubstatement : effectiveStatement.effectiveSubstatements()) {
+ if (YangStmtMapping.IF_FEATURE.equals(effectiveSubstatement.statementDefinition())) {
+ return true;
+ }
+ }
+ return false;
+ }
}