SymbolMetadata.java revision 3529:a8fdbd799e42
1/* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.javac.code; 27 28 29import com.sun.tools.javac.code.Attribute.TypeCompound; 30import com.sun.tools.javac.code.Kinds.Kind; 31import com.sun.tools.javac.util.Assert; 32import com.sun.tools.javac.util.List; 33import com.sun.tools.javac.util.ListBuffer; 34 35/** 36 * Container for all annotations (attributes in javac) on a Symbol. 37 * 38 * This class is explicitly mutable. Its contents will change when attributes 39 * are annotated onto the Symbol. However this class depends on the facts that 40 * List (in javac) is immutable. 41 * 42 * An instance of this class can be in one of three states: 43 * 44 * NOT_STARTED indicates that the Symbol this instance belongs to has not been 45 * annotated (yet). Specifically if the declaration is not annotated this 46 * instance will never move past NOT_STARTED. You can never go back to 47 * NOT_STARTED. 48 * 49 * IN_PROGRESS annotations have been found on the declaration. Will be processed 50 * later. You can reset to IN_PROGRESS. While IN_PROGRESS you can set the list 51 * of attributes (and this moves out of the IN_PROGRESS state). 52 * 53 * "unnamed" this SymbolMetadata contains some attributes, possibly the final set. 54 * While in this state you can only prepend or append to the attributes not set 55 * it directly. You can also move back to the IN_PROGRESS state using reset(). 56 * 57 * <p><b>This is NOT part of any supported API. If you write code that depends 58 * on this, you do so at your own risk. This code and its internal interfaces 59 * are subject to change or deletion without notice.</b> 60 */ 61public class SymbolMetadata { 62 63 private static final List<Attribute.Compound> DECL_NOT_STARTED = List.of(null); 64 private static final List<Attribute.Compound> DECL_IN_PROGRESS = List.of(null); 65 66 /* 67 * This field should never be null 68 */ 69 private List<Attribute.Compound> attributes = DECL_NOT_STARTED; 70 71 /* 72 * Type attributes for this symbol. 73 * This field should never be null. 74 */ 75 private List<Attribute.TypeCompound> type_attributes = List.<Attribute.TypeCompound>nil(); 76 77 /* 78 * Type attributes of initializers in this class. 79 * Unused if the current symbol is not a ClassSymbol. 80 */ 81 private List<Attribute.TypeCompound> init_type_attributes = List.<Attribute.TypeCompound>nil(); 82 83 /* 84 * Type attributes of class initializers in this class. 85 * Unused if the current symbol is not a ClassSymbol. 86 */ 87 private List<Attribute.TypeCompound> clinit_type_attributes = List.<Attribute.TypeCompound>nil(); 88 89 /* 90 * The Symbol this SymbolMetadata instance belongs to 91 */ 92 private final Symbol sym; 93 94 public SymbolMetadata(Symbol sym) { 95 this.sym = sym; 96 } 97 98 public List<Attribute.Compound> getDeclarationAttributes() { 99 return filterDeclSentinels(attributes); 100 } 101 102 public List<Attribute.TypeCompound> getTypeAttributes() { 103 return type_attributes; 104 } 105 106 public List<Attribute.TypeCompound> getInitTypeAttributes() { 107 return init_type_attributes; 108 } 109 110 public List<Attribute.TypeCompound> getClassInitTypeAttributes() { 111 return clinit_type_attributes; 112 } 113 114 public void setDeclarationAttributes(List<Attribute.Compound> a) { 115 Assert.check(pendingCompletion() || !isStarted()); 116 if (a == null) { 117 throw new NullPointerException(); 118 } 119 attributes = a; 120 } 121 122 public void setTypeAttributes(List<Attribute.TypeCompound> a) { 123 if (a == null) { 124 throw new NullPointerException(); 125 } 126 type_attributes = a; 127 } 128 129 public void setInitTypeAttributes(List<Attribute.TypeCompound> a) { 130 if (a == null) { 131 throw new NullPointerException(); 132 } 133 init_type_attributes = a; 134 } 135 136 public void setClassInitTypeAttributes(List<Attribute.TypeCompound> a) { 137 if (a == null) { 138 throw new NullPointerException(); 139 } 140 clinit_type_attributes = a; 141 } 142 143 public void setAttributes(SymbolMetadata other) { 144 if (other == null) { 145 throw new NullPointerException(); 146 } 147 setDeclarationAttributes(other.getDeclarationAttributes()); 148 if ((sym.flags() & Flags.BRIDGE) != 0) { 149 Assert.check(other.sym.kind == Kind.MTH); 150 ListBuffer<TypeCompound> typeAttributes = new ListBuffer<>(); 151 for (TypeCompound tc : other.getTypeAttributes()) { 152 // Carry over only contractual type annotations: i.e nothing interior to method body. 153 if (!tc.position.type.isLocal()) 154 typeAttributes.append(tc); 155 } 156 setTypeAttributes(typeAttributes.toList()); 157 } else { 158 setTypeAttributes(other.getTypeAttributes()); 159 } 160 if (sym.kind == Kind.TYP) { 161 setInitTypeAttributes(other.getInitTypeAttributes()); 162 setClassInitTypeAttributes(other.getClassInitTypeAttributes()); 163 } 164 } 165 166 public SymbolMetadata reset() { 167 attributes = DECL_IN_PROGRESS; 168 return this; 169 } 170 171 public boolean isEmpty() { 172 return !isStarted() 173 || pendingCompletion() 174 || attributes.isEmpty(); 175 } 176 177 public boolean isTypesEmpty() { 178 return type_attributes.isEmpty(); 179 } 180 181 public boolean pendingCompletion() { 182 return attributes == DECL_IN_PROGRESS; 183 } 184 185 public SymbolMetadata append(List<Attribute.Compound> l) { 186 attributes = filterDeclSentinels(attributes); 187 188 if (l.isEmpty()) { 189 // no-op 190 } else if (attributes.isEmpty()) { 191 attributes = l; 192 } else { 193 attributes = attributes.appendList(l); 194 } 195 return this; 196 } 197 198 public SymbolMetadata appendUniqueTypes(List<Attribute.TypeCompound> l) { 199 if (l.isEmpty()) { 200 // no-op 201 } else if (type_attributes.isEmpty()) { 202 type_attributes = l; 203 } else { 204 // TODO: in case we expect a large number of annotations, this 205 // might be inefficient. 206 for (Attribute.TypeCompound tc : l) { 207 if (!type_attributes.contains(tc)) 208 type_attributes = type_attributes.append(tc); 209 } 210 } 211 return this; 212 } 213 214 public SymbolMetadata appendInitTypeAttributes(List<Attribute.TypeCompound> l) { 215 if (l.isEmpty()) { 216 // no-op 217 } else if (init_type_attributes.isEmpty()) { 218 init_type_attributes = l; 219 } else { 220 init_type_attributes = init_type_attributes.appendList(l); 221 } 222 return this; 223 } 224 225 public SymbolMetadata appendClassInitTypeAttributes(List<Attribute.TypeCompound> l) { 226 if (l.isEmpty()) { 227 // no-op 228 } else if (clinit_type_attributes.isEmpty()) { 229 clinit_type_attributes = l; 230 } else { 231 clinit_type_attributes = clinit_type_attributes.appendList(l); 232 } 233 return this; 234 } 235 236 public SymbolMetadata prepend(List<Attribute.Compound> l) { 237 attributes = filterDeclSentinels(attributes); 238 239 if (l.isEmpty()) { 240 // no-op 241 } else if (attributes.isEmpty()) { 242 attributes = l; 243 } else { 244 attributes = attributes.prependList(l); 245 } 246 return this; 247 } 248 249 private List<Attribute.Compound> filterDeclSentinels(List<Attribute.Compound> a) { 250 return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED) 251 ? List.<Attribute.Compound>nil() 252 : a; 253 } 254 255 private boolean isStarted() { 256 return attributes != DECL_NOT_STARTED; 257 } 258} 259