TypeMetadata.java revision 2646:ff1998c1ecab
1/*
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights
3 * reserved.  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE
4 * HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.  Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package com.sun.tools.javac.code;
28
29import com.sun.tools.javac.util.Assert;
30import com.sun.tools.javac.util.List;
31import java.util.EnumMap;
32import java.util.HashSet;
33import java.util.Map;
34import java.util.Set;
35
36/**
37 * A super-interface for all type metadata elements.  Metadata classes
38 * can be created for any metadata on types with the following
39 * properties:
40 *
41 * <ul>
42 * <li>They have a default value (preferably empty)</li>
43 * <li>The field is usually the default value</li>
44 * <li>Different values of the field are visible, and denote distinct
45 *     types</li>
46 * </ul>
47 */
48public class TypeMetadata {
49
50    public static final TypeMetadata empty = new TypeMetadata();
51    private final EnumMap<TypeMetadata.Element.Kind, TypeMetadata.Element> contents;
52
53    private TypeMetadata() {
54        contents = new EnumMap<Element.Kind, Element>(Element.Kind.class);
55    }
56
57    public TypeMetadata(final Element elem) {
58        this();
59        contents.put(elem.kind(), elem);
60    }
61
62    public TypeMetadata(final TypeMetadata other) {
63        contents = other.contents.clone();
64    }
65
66    public TypeMetadata copy() {
67        return new TypeMetadata(this);
68    }
69
70    public TypeMetadata combine(final Element elem) {
71        final TypeMetadata out = new TypeMetadata(this);
72        final Element.Kind key = elem.kind();
73        if (contents.containsKey(key)) {
74            out.add(key, this.contents.get(key).combine(elem));
75        } else {
76            out.add(key, elem);
77        }
78        return out;
79    }
80
81    public TypeMetadata combine(final TypeMetadata other) {
82        final TypeMetadata out = new TypeMetadata();
83        final Set<Element.Kind> keys = new HashSet<>(this.contents.keySet());
84        keys.addAll(other.contents.keySet());
85
86        for(final Element.Kind key : keys) {
87            if (this.contents.containsKey(key)) {
88                if (other.contents.containsKey(key)) {
89                    out.add(key, this.contents.get(key).combine(other.contents.get(key)));
90                } else {
91                    out.add(key, this.contents.get(key));
92                }
93            } else if (other.contents.containsKey(key)) {
94                out.add(key, other.contents.get(key));
95            }
96        }
97        return out;
98    }
99
100    public Element get(final Element.Kind kind) {
101        return contents.get(kind);
102    }
103
104    public boolean isEmpty() {
105        return contents.isEmpty();
106    }
107
108    private void add(final Element.Kind kind, final Element elem) {
109        contents.put(kind, elem);
110    }
111
112    private void addAll(final Map<? extends Element.Kind,? extends Element> m) {
113        contents.putAll(m);
114    }
115
116    public interface Element {
117
118        public enum Kind {
119            ANNOTATIONS;
120        }
121
122        /**
123         * Get the kind of metadata this object represents
124         */
125        public Kind kind();
126
127        /**
128         * Combine this type metadata with another metadata of the
129         * same kind.
130         *
131         * @param other The metadata with which to combine this one.
132         * @return The combined metadata.
133         */
134        public Element combine(Element other);
135    }
136
137    /**
138     * A type metadata object holding type annotations.
139     */
140    public static class Annotations implements Element {
141        private final List<Attribute.TypeCompound> annos;
142
143        public Annotations(final List<Attribute.TypeCompound> annos) {
144            this.annos = annos;
145        }
146
147        /**
148         * Get the type annotations contained in this metadata.
149         *
150         * @return The annotations.
151         */
152        public List<Attribute.TypeCompound> getAnnotations() {
153            return annos;
154        }
155
156        @Override
157        public Annotations combine(final Element other) {
158            // Temporary: we should append the lists, but that won't
159            // work with type annotations today.  Instead, we replace
160            // the list.
161            return new Annotations(((Annotations) other).annos);
162        }
163
164        @Override
165        public Kind kind() { return Kind.ANNOTATIONS; }
166
167        @Override
168        public String toString() { return "ANNOTATIONS { " + annos + " }"; }
169    }
170
171}
172