/* Copyright 2016 Immutables Authors and Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.immutables.value.processor.encode; import org.immutables.value.Value.Default; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import java.util.List; import java.util.Set; import org.immutables.generator.Naming; import org.immutables.value.Value; import org.immutables.value.Value.Derived; import org.immutables.value.Value.Enclosing; import org.immutables.value.Value.Immutable; import org.immutables.value.processor.encode.Code.Term; @Immutable @Enclosing public abstract class EncodedElement { enum Tag { IMPL, EXPOSE, BUILDER, STATIC, PRIVATE, FINAL, BUILD, INIT, FROM, HELPER, FIELD, TO_STRING, HASH_CODE, EQUALS, COPY, DEPLURALIZE, // syntethic element which is automatically inserted SYNTH, // applies to impl field VIRTUAL } abstract String name(); abstract Type type(); abstract Naming naming(); abstract List<Param> params(); abstract List<Term> code(); abstract List<Type> thrown(); abstract Set<Tag> tags(); abstract Type.Parameters typeParameters(); abstract List<TypeParam> typeParams(); Param firstParam() { return params().get(0); } @Default StandardNaming standardNaming() { return StandardNaming.NONE; } boolean isVirtual() { return tags().contains(Tag.VIRTUAL); } @Derived Code.Binding asBinding() { return isField() || isImplField() ? Code.Binding.newField(name()) : Code.Binding.newMethod(name()); } @Derived boolean isToString() { return tags().contains(Tag.TO_STRING); } @Derived boolean isHashCode() { return tags().contains(Tag.HASH_CODE); } @Derived boolean isEquals() { return tags().contains(Tag.EQUALS); } @Derived boolean isFrom() { return tags().contains(Tag.FROM); } @Derived boolean isBuild() { return tags().contains(Tag.BUILD); } @Derived boolean isInit() { return tags().contains(Tag.INIT); } @Derived boolean isCopy() { return tags().contains(Tag.COPY) && !inBuilder(); } @Derived boolean isBuilderCopy() { return tags().contains(Tag.COPY) && inBuilder(); } @Derived boolean isExpose() { return tags().contains(Tag.EXPOSE); } @Derived boolean inBuilder() { return tags().contains(Tag.BUILDER); } @Derived boolean isStatic() { return tags().contains(Tag.STATIC); } @Derived boolean isFinal() { return tags().contains(Tag.FINAL); } @Derived boolean isPrivate() { return tags().contains(Tag.PRIVATE); } @Derived boolean isSynthetic() { return tags().contains(Tag.SYNTH); } @Derived boolean isImplField() { return tags().contains(Tag.IMPL); } @Derived boolean isValueField() { return isField() && !tags().contains(Tag.IMPL) && !inBuilder() && !isStatic(); } @Derived boolean isStaticField() { return isField() && !inBuilder() && isStatic(); } @Derived boolean isField() { return tags().contains(Tag.FIELD); } @Derived boolean isBuilderField() { return isField() && inBuilder() && !isStatic(); } @Derived boolean isStaticMethod() { return tags().contains(Tag.HELPER) && isStatic() && !inBuilder(); } @Derived boolean isValueMethod() { return tags().contains(Tag.HELPER) && !isStatic() && !inBuilder(); } @Derived boolean isBuilderMethod() { return tags().contains(Tag.HELPER) && inBuilder(); } @Derived boolean isBuilderStaticField() { return isField() && inBuilder() && isStatic(); } @Derived ImmutableList<Term> oneLiner() { return isInlinable() && typeParams().isEmpty() ? ImmutableList.copyOf(Code.oneLiner(code())) : ImmutableList.<Term>of(); } @Derived boolean isInlinable() { return isEquals() || isToString() || isHashCode() || isFrom() || isCopy() || isBuild(); } boolean depluralize() { return tags().contains(Tag.DEPLURALIZE); } static class Builder extends ImmutableEncodedElement.Builder {} @Immutable abstract static class Param { @Value.Parameter abstract String name(); @Value.Parameter abstract Type type(); @Override public String toString() { return name() + ": " + type(); } static Param of(String name, Type type) { return ImmutableEncodedElement.Param.of(name, type); } public static Param from(String input, Type.Parser parser) { List<String> parts = COLON_SPLITTER.splitToList(input); return of(parts.get(0), parser.parse(parts.get(1))); } } @Immutable abstract static class TypeParam { abstract String name(); abstract List<Type.Defined> bounds(); @Override public String toString() { return name() + ": " + Joiner.on(" & ").join(bounds()); } static class Builder extends ImmutableEncodedElement.TypeParam.Builder {} static TypeParam from(String input, Type.Factory typeFactory, Type.Parameters typeParameters) { List<String> parts = COLON_SPLITTER.splitToList(input); Builder builder = new Builder() .name(parts.get(0)); if (parts.size() == 1) { return builder.build(); } Type.Parser parser = new Type.Parser(typeFactory, typeParameters); for (String bound : AMPER_SPLITTER.split(parts.get(1))) { builder.addBounds((Type.Defined) parser.parse(bound)); } return builder.build(); } } private static final Splitter COLON_SPLITTER = Splitter.on(':').trimResults(); private static final Splitter AMPER_SPLITTER = Splitter.on('&').trimResults(); }