/*
 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.javac.code;

import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.List;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.Set;

TypeMetadata is essentially an immutable EnumMap<Entry.Kind, <? extends Entry>> A metadata class represented by a subtype of Entry can express a property on a Type instance. Thers should be at most one instance of an Entry per Entry.Kind on any given Type instance. Metadata classes of a specific kind are responsible for how they combine themselvs.
Implementation Note:Entry:combine need not be commutative.
/** * TypeMetadata is essentially an immutable {@code EnumMap<Entry.Kind, <? extends Entry>>} * * A metadata class represented by a subtype of Entry can express a property on a Type instance. * Thers should be at most one instance of an Entry per Entry.Kind on any given Type instance. * * Metadata classes of a specific kind are responsible for how they combine themselvs. * * @implNote {@code Entry:combine} need not be commutative. */
public class TypeMetadata { public static final TypeMetadata EMPTY = new TypeMetadata(); private final EnumMap<Entry.Kind, Entry> contents;
Create a new empty TypeMetadata map.
/** * Create a new empty TypeMetadata map. */
private TypeMetadata() { contents = new EnumMap<>(Entry.Kind.class); }
Create a new TypeMetadata map containing the Entry elem.
Params:
  • elem – the sole contents of this map
/** * Create a new TypeMetadata map containing the Entry {@code elem}. * * @param elem the sole contents of this map */
public TypeMetadata(Entry elem) { this(); Assert.checkNonNull(elem); contents.put(elem.kind(), elem); }
Creates a copy of TypeMetadata other with a shallow copy the other's metadata contents.
Params:
  • other – the TypeMetadata to copy contents from.
/** * Creates a copy of TypeMetadata {@code other} with a shallow copy the other's metadata contents. * * @param other the TypeMetadata to copy contents from. */
public TypeMetadata(TypeMetadata other) { Assert.checkNonNull(other); contents = other.contents.clone(); }
Return a copy of this TypeMetadata with the metadata entry for elem.kind() combined with elem.
Params:
  • elem – the new value
Returns:a new TypeMetadata updated with Entry elem
/** * Return a copy of this TypeMetadata with the metadata entry for {@code elem.kind()} combined * with {@code elem}. * * @param elem the new value * @return a new TypeMetadata updated with {@code Entry elem} */
public TypeMetadata combine(Entry elem) { Assert.checkNonNull(elem); TypeMetadata out = new TypeMetadata(this); Entry.Kind key = elem.kind(); if (contents.containsKey(key)) { out.add(key, this.contents.get(key).combine(elem)); } else { out.add(key, elem); } return out; }
Return a copy of this TypeMetadata with the metadata entry for all kinds from other combined with the same kind from this.
Params:
  • other – the TypeMetadata to combine with this
Returns:a new TypeMetadata updated with all entries from other
/** * Return a copy of this TypeMetadata with the metadata entry for all kinds from {@code other} * combined with the same kind from this. * * @param other the TypeMetadata to combine with this * @return a new TypeMetadata updated with all entries from {@code other} */
public TypeMetadata combineAll(TypeMetadata other) { Assert.checkNonNull(other); TypeMetadata out = new TypeMetadata(); Set<Entry.Kind> keys = new HashSet<>(contents.keySet()); keys.addAll(other.contents.keySet()); for(Entry.Kind key : keys) { if (contents.containsKey(key)) { if (other.contents.containsKey(key)) { out.add(key, contents.get(key).combine(other.contents.get(key))); } else { out.add(key, contents.get(key)); } } else if (other.contents.containsKey(key)) { out.add(key, other.contents.get(key)); } } return out; }
Return a TypeMetadata with the metadata entry for kind removed. This may be the same instance or a new TypeMetadata.
Params:
  • kind – the Kind to remove metadata for
Returns:a new TypeMetadata without Kind kind
/** * Return a TypeMetadata with the metadata entry for {@code kind} removed. * * This may be the same instance or a new TypeMetadata. * * @param kind the {@code Kind} to remove metadata for * @return a new TypeMetadata without {@code Kind kind} */
public TypeMetadata without(Entry.Kind kind) { if (this == EMPTY || contents.get(kind) == null) return this; TypeMetadata out = new TypeMetadata(this); out.contents.remove(kind); return out.contents.isEmpty() ? EMPTY : out; } public Entry get(Entry.Kind kind) { return contents.get(kind); } private void add(Entry.Kind kind, Entry elem) { contents.put(kind, elem); } public interface Entry { public enum Kind { ANNOTATIONS }
Get the kind of metadata this object represents
/** * Get the kind of metadata this object represents */
public Kind kind();
Combine this type metadata with another metadata of the same kind.
Params:
  • other – The metadata with which to combine this one.
Returns:The combined metadata.
/** * Combine this type metadata with another metadata of the * same kind. * * @param other The metadata with which to combine this one. * @return The combined metadata. */
public Entry combine(Entry other); }
A type metadata object holding type annotations.
/** * A type metadata object holding type annotations. */
public static class Annotations implements Entry { private List<Attribute.TypeCompound> annos; public static final List<Attribute.TypeCompound> TO_BE_SET = List.nil(); public Annotations(List<Attribute.TypeCompound> annos) { this.annos = annos; }
Get the type annotations contained in this metadata.
Returns:The annotations.
/** * Get the type annotations contained in this metadata. * * @return The annotations. */
public List<Attribute.TypeCompound> getAnnotations() { return annos; } @Override public Annotations combine(Entry other) { Assert.check(annos == TO_BE_SET); annos = ((Annotations)other).annos; return this; } @Override public Kind kind() { return Kind.ANNOTATIONS; } @Override public String toString() { return "ANNOTATIONS [ " + annos + " ]"; } } }