public static Restrictions getRestrictions(final TypeDefinition<?> type) {
    // Old parser generated types which actually contained based restrictions, but our code deals
    // with that when
    // binding to core Java types. Hence we'll emit empty restrictions for base types.
    if (type == null || type.getBaseType() == null) {
      // Handling of decimal64 has changed in the new parser. It contains range restrictions applied
      // to the type
      // directly, without an extended type. We need to capture such constraints. In order to retain
      // behavior we
      // need to analyze the new semantics and see if the constraints have been overridden. To do
      // that we
      // instantiate a temporary unconstrained type and compare them.
      //
      // FIXME: looking at the generated code it looks as though we need to pass the restrictions
      // without
      //        comparison
      if (type instanceof DecimalTypeDefinition) {
        final DecimalTypeDefinition decimal = (DecimalTypeDefinition) type;
        final DecimalTypeBuilder tmpBuilder = BaseTypes.decimalTypeBuilder(decimal.getPath());
        tmpBuilder.setFractionDigits(decimal.getFractionDigits());
        final DecimalTypeDefinition tmp = tmpBuilder.build();

        if (!tmp.getRangeConstraints().equals(decimal.getRangeConstraints())) {
          return new Restrictions() {
            @Override
            public boolean isEmpty() {
              return false;
            }

            @Override
            public List<RangeConstraint> getRangeConstraints() {
              return decimal.getRangeConstraints();
            }

            @Override
            public List<PatternConstraint> getPatternConstraints() {
              return ImmutableList.of();
            }

            @Override
            public List<LengthConstraint> getLengthConstraints() {
              return ImmutableList.of();
            }
          };
        }
      }

      return EMPTY_RESTRICTIONS;
    }

    final List<LengthConstraint> length;
    final List<PatternConstraint> pattern;
    final List<RangeConstraint> range;

    /*
     * Take care of extended types.
     *
     * Other types which support constraints are check afterwards. There is a slight twist with them, as returned
     * constraints are the effective view, e.g. they are inherited from base type. Since the constraint is already
     * enforced by the base type, we want to skip them and not perform duplicate checks.
     *
     * We end up emitting ConcreteType instances for YANG base types, which leads to their constraints not being
     * enforced (most notably decimal64). Therefore we need to make sure we do not strip the next-to-last
     * restrictions.
     *
     * FIXME: this probably not the best solution and needs further analysis.
     */
    if (type instanceof BinaryTypeDefinition) {
      final BinaryTypeDefinition binary = (BinaryTypeDefinition) type;
      final BinaryTypeDefinition base = binary.getBaseType();
      if (base != null && base.getBaseType() != null) {
        length = currentOrEmpty(binary.getLengthConstraints(), base.getLengthConstraints());
      } else {
        length = binary.getLengthConstraints();
      }

      pattern = ImmutableList.of();
      range = ImmutableList.of();
    } else if (type instanceof DecimalTypeDefinition) {
      length = ImmutableList.of();
      pattern = ImmutableList.of();

      final DecimalTypeDefinition decimal = (DecimalTypeDefinition) type;
      final DecimalTypeDefinition base = decimal.getBaseType();
      if (base != null && base.getBaseType() != null) {
        range = currentOrEmpty(decimal.getRangeConstraints(), base.getRangeConstraints());
      } else {
        range = decimal.getRangeConstraints();
      }
    } else if (type instanceof IntegerTypeDefinition) {
      length = ImmutableList.of();
      pattern = ImmutableList.of();

      final IntegerTypeDefinition integer = (IntegerTypeDefinition) type;
      final IntegerTypeDefinition base = integer.getBaseType();
      if (base != null && base.getBaseType() != null) {
        range = currentOrEmpty(integer.getRangeConstraints(), base.getRangeConstraints());
      } else {
        range = integer.getRangeConstraints();
      }
    } else if (type instanceof StringTypeDefinition) {
      final StringTypeDefinition string = (StringTypeDefinition) type;
      final StringTypeDefinition base = string.getBaseType();
      if (base != null && base.getBaseType() != null) {
        length = currentOrEmpty(string.getLengthConstraints(), base.getLengthConstraints());
      } else {
        length = string.getLengthConstraints();
      }

      pattern = uniquePatterns(string);
      range = ImmutableList.of();
    } else if (type instanceof UnsignedIntegerTypeDefinition) {
      length = ImmutableList.of();
      pattern = ImmutableList.of();

      final UnsignedIntegerTypeDefinition unsigned = (UnsignedIntegerTypeDefinition) type;
      final UnsignedIntegerTypeDefinition base = unsigned.getBaseType();
      if (base != null && base.getBaseType() != null) {
        range = currentOrEmpty(unsigned.getRangeConstraints(), base.getRangeConstraints());
      } else {
        range = unsigned.getRangeConstraints();
      }
    } else {
      length = ImmutableList.of();
      pattern = ImmutableList.of();
      range = ImmutableList.of();
    }

    // Now, this may have ended up being empty, too...
    if (length.isEmpty() && pattern.isEmpty() && range.isEmpty()) {
      return EMPTY_RESTRICTIONS;
    }

    // Nope, not empty allocate a holder
    return new Restrictions() {
      @Override
      public List<RangeConstraint> getRangeConstraints() {
        return range;
      }

      @Override
      public List<PatternConstraint> getPatternConstraints() {
        return pattern;
      }

      @Override
      public List<LengthConstraint> getLengthConstraints() {
        return length;
      }

      @Override
      public boolean isEmpty() {
        return false;
      }
    };
  }