TypeMetadata.java revision 3170:dc017a37aac5
1168404Spjd/* 2168404Spjd * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3168404Spjd * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4168404Spjd * 5168404Spjd * This code is free software; you can redistribute it and/or modify it 6168404Spjd * under the terms of the GNU General Public License version 2 only, as 7168404Spjd * published by the Free Software Foundation. Oracle designates this 8168404Spjd * particular file as subject to the "Classpath" exception as provided 9168404Spjd * by Oracle in the LICENSE file that accompanied this code. 10168404Spjd * 11168404Spjd * This code is distributed in the hope that it will be useful, but WITHOUT 12168404Spjd * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13168404Spjd * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14168404Spjd * version 2 for more details (a copy is included in the LICENSE file that 15168404Spjd * accompanied this code). 16168404Spjd * 17168404Spjd * You should have received a copy of the GNU General Public License version 18168404Spjd * 2 along with this work; if not, write to the Free Software Foundation, 19168404Spjd * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20168404Spjd * 21168404Spjd * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22168404Spjd * or visit www.oracle.com if you need additional information or have any 23168404Spjd * questions. 24168404Spjd */ 25168404Spjd 26168404Spjdpackage com.sun.tools.javac.code; 27168404Spjd 28168404Spjdimport com.sun.tools.javac.util.Assert; 29168404Spjdimport com.sun.tools.javac.util.List; 30168404Spjdimport java.util.EnumMap; 31168404Spjdimport java.util.HashSet; 32168404Spjdimport java.util.Set; 33168404Spjd 34168404Spjd/** 35168404Spjd * TypeMetadata is essentially an immutable {@code EnumMap<Entry.Kind, <? extends Entry>>} 36168404Spjd * 37168404Spjd * A metadata class represented by a subtype of Entry can express a property on a Type instance. 38168404Spjd * Thers should be at most one instance of an Entry per Entry.Kind on any given Type instance. 39168404Spjd * 40168404Spjd * Metadata classes of a specific kind are responsible for how they combine themselvs. 41168404Spjd * 42168404Spjd * @implNote {@code Entry:combine} need not be commutative. 43168404Spjd */ 44168404Spjdpublic class TypeMetadata { 45168404Spjd public static final TypeMetadata EMPTY = new TypeMetadata(); 46168404Spjd 47168404Spjd private final EnumMap<Entry.Kind, Entry> contents; 48168404Spjd 49168404Spjd /** 50168404Spjd * Create a new empty TypeMetadata map. 51168404Spjd */ 52168404Spjd private TypeMetadata() { 53168404Spjd contents = new EnumMap<>(Entry.Kind.class); 54168404Spjd } 55168404Spjd 56168404Spjd /** 57168404Spjd * Create a new TypeMetadata map containing the Entry {@code elem}. 58168404Spjd * 59168404Spjd * @param elem the sole contents of this map 60168404Spjd */ 61168712Spjd public TypeMetadata(Entry elem) { 62168712Spjd this(); 63168712Spjd Assert.checkNonNull(elem); 64168712Spjd contents.put(elem.kind(), elem); 65168712Spjd } 66168712Spjd 67168404Spjd /** 68168712Spjd * Creates a copy of TypeMetadata {@code other} with a shallow copy the other's metadata contents. 69168404Spjd * 70168404Spjd * @param other the TypeMetadata to copy contents from. 71168404Spjd */ 72168404Spjd public TypeMetadata(TypeMetadata other) { 73168404Spjd Assert.checkNonNull(other); 74168404Spjd contents = other.contents.clone(); 75168404Spjd } 76168404Spjd 77168404Spjd /** 78168404Spjd * Return a copy of this TypeMetadata with the metadata entry for {@code elem.kind()} combined 79168404Spjd * with {@code elem}. 80168404Spjd * 81168404Spjd * @param elem the new value 82168404Spjd * @return a new TypeMetadata updated with {@code Entry elem} 83168404Spjd */ 84168404Spjd public TypeMetadata combine(Entry elem) { 85168404Spjd Assert.checkNonNull(elem); 86168404Spjd 87168404Spjd TypeMetadata out = new TypeMetadata(this); 88168404Spjd Entry.Kind key = elem.kind(); 89168404Spjd if (contents.containsKey(key)) { 90168404Spjd out.add(key, this.contents.get(key).combine(elem)); 91168404Spjd } else { 92168404Spjd out.add(key, elem); 93168404Spjd } 94168404Spjd return out; 95168404Spjd } 96168404Spjd 97168404Spjd /** 98168404Spjd * Return a copy of this TypeMetadata with the metadata entry for all kinds from {@code other} 99168404Spjd * combined with the same kind from this. 100168404Spjd * 101168404Spjd * @param other the TypeMetadata to combine with this 102168404Spjd * @return a new TypeMetadata updated with all entries from {@code other} 103168404Spjd */ 104168404Spjd public TypeMetadata combineAll(TypeMetadata other) { 105168404Spjd Assert.checkNonNull(other); 106168404Spjd 107168404Spjd TypeMetadata out = new TypeMetadata(); 108168404Spjd Set<Entry.Kind> keys = new HashSet<>(contents.keySet()); 109168404Spjd keys.addAll(other.contents.keySet()); 110168404Spjd 111168404Spjd for(Entry.Kind key : keys) { 112168404Spjd if (contents.containsKey(key)) { 113168404Spjd if (other.contents.containsKey(key)) { 114168404Spjd out.add(key, contents.get(key).combine(other.contents.get(key))); 115168404Spjd } else { 116168404Spjd out.add(key, contents.get(key)); 117168404Spjd } 118168404Spjd } else if (other.contents.containsKey(key)) { 119168404Spjd out.add(key, other.contents.get(key)); 120168712Spjd } 121168712Spjd } 122168404Spjd return out; 123168404Spjd } 124168404Spjd 125168404Spjd /** 126168404Spjd * Return a TypeMetadata with the metadata entry for {@code kind} removed. 127168404Spjd * 128168404Spjd * This may be the same instance or a new TypeMetadata. 129168712Spjd * 130168715Spjd * @param kind the {@code Kind} to remove metadata for 131168404Spjd * @return a new TypeMetadata without {@code Kind kind} 132168712Spjd */ 133168712Spjd public TypeMetadata without(Entry.Kind kind) { 134168712Spjd if (this == EMPTY || contents.get(kind) == null) 135168712Spjd return this; 136168712Spjd 137168712Spjd TypeMetadata out = new TypeMetadata(this); 138168404Spjd out.contents.remove(kind); 139168404Spjd return out.contents.isEmpty() ? EMPTY : out; 140168404Spjd } 141168404Spjd 142168404Spjd public Entry get(Entry.Kind kind) { 143168404Spjd return contents.get(kind); 144168404Spjd } 145168404Spjd 146168404Spjd private void add(Entry.Kind kind, Entry elem) { 147168404Spjd contents.put(kind, elem); 148168404Spjd } 149168404Spjd 150168404Spjd public interface Entry { 151168404Spjd 152168404Spjd public enum Kind { 153168404Spjd ANNOTATIONS 154168404Spjd } 155168404Spjd 156168404Spjd /** 157168404Spjd * Get the kind of metadata this object represents 158168404Spjd */ 159168404Spjd public Kind kind(); 160168404Spjd 161168404Spjd /** 162168404Spjd * Combine this type metadata with another metadata of the 163168404Spjd * same kind. 164168404Spjd * 165168404Spjd * @param other The metadata with which to combine this one. 166168404Spjd * @return The combined metadata. 167168404Spjd */ 168168404Spjd public Entry combine(Entry other); 169168404Spjd } 170168404Spjd 171168404Spjd /** 172168404Spjd * A type metadata object holding type annotations. 173168404Spjd */ 174168404Spjd public static class Annotations implements Entry { 175168404Spjd private List<Attribute.TypeCompound> annos; 176168404Spjd 177168404Spjd public static final List<Attribute.TypeCompound> TO_BE_SET = List.nil(); 178168404Spjd 179168404Spjd public Annotations(List<Attribute.TypeCompound> annos) { 180168404Spjd this.annos = annos; 181168404Spjd } 182168404Spjd 183168404Spjd /** 184168404Spjd * Get the type annotations contained in this metadata. 185168404Spjd * 186168404Spjd * @return The annotations. 187168404Spjd */ 188168404Spjd public List<Attribute.TypeCompound> getAnnotations() { 189168404Spjd return annos; 190168404Spjd } 191168404Spjd 192168404Spjd @Override 193168404Spjd public Annotations combine(Entry other) { 194168404Spjd Assert.check(annos == TO_BE_SET); 195168404Spjd annos = ((Annotations)other).annos; 196168404Spjd return this; 197168404Spjd } 198168404Spjd 199168404Spjd @Override 200168404Spjd public Kind kind() { return Kind.ANNOTATIONS; } 201168404Spjd 202168404Spjd @Override 203168404Spjd public String toString() { return "ANNOTATIONS [ " + annos + " ]"; } 204168404Spjd } 205168404Spjd} 206168404Spjd