Tue, 11 Aug 2009 01:13:14 +0100
6521805: Regression: JDK5/JDK6 javac allows write access to outer class reference
Summary: javac should warn/complain about identifiers with the same name as synthetic symbol
Reviewed-by: jjg
duke@1 | 1 | /* |
xdono@117 | 2 | * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. |
duke@1 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@1 | 4 | * |
duke@1 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@1 | 6 | * under the terms of the GNU General Public License version 2 only, as |
duke@1 | 7 | * published by the Free Software Foundation. Sun designates this |
duke@1 | 8 | * particular file as subject to the "Classpath" exception as provided |
duke@1 | 9 | * by Sun in the LICENSE file that accompanied this code. |
duke@1 | 10 | * |
duke@1 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@1 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@1 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@1 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@1 | 15 | * accompanied this code). |
duke@1 | 16 | * |
duke@1 | 17 | * You should have received a copy of the GNU General Public License version |
duke@1 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@1 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@1 | 20 | * |
duke@1 | 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
duke@1 | 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
duke@1 | 23 | * have any questions. |
duke@1 | 24 | */ |
duke@1 | 25 | |
duke@1 | 26 | package com.sun.tools.javadoc; |
duke@1 | 27 | |
duke@1 | 28 | import com.sun.javadoc.*; |
duke@1 | 29 | |
duke@1 | 30 | import com.sun.tools.javac.code.Flags; |
duke@1 | 31 | import com.sun.tools.javac.code.Kinds; |
duke@1 | 32 | import com.sun.tools.javac.code.Scope; |
duke@1 | 33 | import com.sun.tools.javac.code.Symbol.VarSymbol; |
duke@1 | 34 | import com.sun.tools.javac.code.Symbol.ClassSymbol; |
duke@1 | 35 | import com.sun.tools.javac.code.Symbol.MethodSymbol; |
duke@1 | 36 | import com.sun.tools.javac.util.Name; |
duke@1 | 37 | import com.sun.tools.javac.util.ListBuffer; |
jjg@113 | 38 | import com.sun.tools.javac.util.Names; |
duke@1 | 39 | |
duke@1 | 40 | /** |
duke@1 | 41 | * The serialized form is the specification of a class' serialization |
duke@1 | 42 | * state. <p> |
duke@1 | 43 | * |
duke@1 | 44 | * It consists of the following information:<p> |
duke@1 | 45 | * |
duke@1 | 46 | * <pre> |
duke@1 | 47 | * 1. Whether class is Serializable or Externalizable. |
duke@1 | 48 | * 2. Javadoc for serialization methods. |
duke@1 | 49 | * a. For Serializable, the optional readObject, writeObject, |
duke@1 | 50 | * readResolve and writeReplace. |
duke@1 | 51 | * serialData tag describes, in prose, the sequence and type |
duke@1 | 52 | * of optional data written by writeObject. |
duke@1 | 53 | * b. For Externalizable, writeExternal and readExternal. |
duke@1 | 54 | * serialData tag describes, in prose, the sequence and type |
duke@1 | 55 | * of optional data written by writeExternal. |
duke@1 | 56 | * 3. Javadoc for serialization data layout. |
duke@1 | 57 | * a. For Serializable, the name,type and description |
duke@1 | 58 | * of each Serializable fields. |
duke@1 | 59 | * b. For Externalizable, data layout is described by 2(b). |
duke@1 | 60 | * </pre> |
duke@1 | 61 | * |
duke@1 | 62 | * @since 1.2 |
duke@1 | 63 | * @author Joe Fialli |
duke@1 | 64 | * @author Neal Gafter (rewrite but not too proud) |
duke@1 | 65 | */ |
duke@1 | 66 | class SerializedForm { |
duke@1 | 67 | ListBuffer<MethodDoc> methods = new ListBuffer<MethodDoc>(); |
duke@1 | 68 | |
duke@1 | 69 | /* List of FieldDocImpl - Serializable fields. |
duke@1 | 70 | * Singleton list if class defines Serializable fields explicitly. |
duke@1 | 71 | * Otherwise, list of default serializable fields. |
duke@1 | 72 | * 0 length list for Externalizable. |
duke@1 | 73 | */ |
duke@1 | 74 | private final ListBuffer<FieldDocImpl> fields = new ListBuffer<FieldDocImpl>(); |
duke@1 | 75 | |
duke@1 | 76 | /* True if class specifies serializable fields explicitly. |
duke@1 | 77 | * using special static member, serialPersistentFields. |
duke@1 | 78 | */ |
duke@1 | 79 | private boolean definesSerializableFields = false; |
duke@1 | 80 | |
duke@1 | 81 | // Specially treated field/method names defined by Serialization. |
duke@1 | 82 | private static final String SERIALIZABLE_FIELDS = "serialPersistentFields"; |
duke@1 | 83 | private static final String READOBJECT = "readObject"; |
duke@1 | 84 | private static final String WRITEOBJECT = "writeObject"; |
duke@1 | 85 | private static final String READRESOLVE = "readResolve"; |
duke@1 | 86 | private static final String WRITEREPLACE = "writeReplace"; |
duke@1 | 87 | private static final String READOBJECTNODATA = "readObjectNoData"; |
duke@1 | 88 | |
duke@1 | 89 | /** |
duke@1 | 90 | * Constructor. |
duke@1 | 91 | * |
duke@1 | 92 | * Catalog Serializable fields for Serializable class. |
duke@1 | 93 | * Catalog serialization methods for Serializable and |
duke@1 | 94 | * Externalizable classes. |
duke@1 | 95 | */ |
duke@1 | 96 | SerializedForm(DocEnv env, ClassSymbol def, ClassDocImpl cd) { |
duke@1 | 97 | if (cd.isExternalizable()) { |
duke@1 | 98 | /* look up required public accessible methods, |
duke@1 | 99 | * writeExternal and readExternal. |
duke@1 | 100 | */ |
duke@1 | 101 | String[] readExternalParamArr = { "java.io.ObjectInput" }; |
duke@1 | 102 | String[] writeExternalParamArr = { "java.io.ObjectOutput" }; |
duke@1 | 103 | MethodDoc md = cd.findMethod("readExternal", readExternalParamArr); |
duke@1 | 104 | if (md != null) { |
duke@1 | 105 | methods.append(md); |
duke@1 | 106 | } |
duke@1 | 107 | md = cd.findMethod("writeExternal", writeExternalParamArr); |
duke@1 | 108 | if (md != null) { |
duke@1 | 109 | methods.append(md); |
duke@1 | 110 | Tag tag[] = md.tags("serialData"); |
duke@1 | 111 | } |
duke@1 | 112 | // } else { // isSerializable() //### ??? |
duke@1 | 113 | } else if (cd.isSerializable()) { |
duke@1 | 114 | |
duke@1 | 115 | VarSymbol dsf = getDefinedSerializableFields(def); |
duke@1 | 116 | if (dsf != null) { |
duke@1 | 117 | |
duke@1 | 118 | /* Define serializable fields with array of ObjectStreamField. |
duke@1 | 119 | * Each ObjectStreamField should be documented by a |
duke@1 | 120 | * serialField tag. |
duke@1 | 121 | */ |
duke@1 | 122 | definesSerializableFields = true; |
duke@1 | 123 | //### No modifier filtering applied here. |
duke@1 | 124 | FieldDocImpl dsfDoc = env.getFieldDoc(dsf); |
duke@1 | 125 | fields.append(dsfDoc); |
duke@1 | 126 | mapSerialFieldTagImplsToFieldDocImpls(dsfDoc, env, def); |
duke@1 | 127 | } else { |
duke@1 | 128 | |
duke@1 | 129 | /* Calculate default Serializable fields as all |
duke@1 | 130 | * non-transient, non-static fields. |
duke@1 | 131 | * Fields should be documented by serial tag. |
duke@1 | 132 | */ |
duke@1 | 133 | computeDefaultSerializableFields(env, def, cd); |
duke@1 | 134 | } |
duke@1 | 135 | |
duke@1 | 136 | /* Check for optional customized readObject, writeObject, |
duke@1 | 137 | * readResolve and writeReplace, which can all contain |
duke@1 | 138 | * the serialData tag. */ |
duke@1 | 139 | addMethodIfExist(env, def, READOBJECT); |
duke@1 | 140 | addMethodIfExist(env, def, WRITEOBJECT); |
duke@1 | 141 | addMethodIfExist(env, def, READRESOLVE); |
duke@1 | 142 | addMethodIfExist(env, def, WRITEREPLACE); |
duke@1 | 143 | addMethodIfExist(env, def, READOBJECTNODATA); |
duke@1 | 144 | } |
duke@1 | 145 | } |
duke@1 | 146 | |
duke@1 | 147 | /* |
duke@1 | 148 | * Check for explicit Serializable fields. |
duke@1 | 149 | * Check for a private static array of ObjectStreamField with |
duke@1 | 150 | * name SERIALIZABLE_FIELDS. |
duke@1 | 151 | */ |
duke@1 | 152 | private VarSymbol getDefinedSerializableFields(ClassSymbol def) { |
jjg@113 | 153 | Names names = def.name.table.names; |
duke@1 | 154 | |
duke@1 | 155 | /* SERIALIZABLE_FIELDS can be private, |
duke@1 | 156 | * so must lookup by ClassSymbol, not by ClassDocImpl. |
duke@1 | 157 | */ |
duke@1 | 158 | for (Scope.Entry e = def.members().lookup(names.fromString(SERIALIZABLE_FIELDS)); e.scope != null; e = e.next()) { |
duke@1 | 159 | if (e.sym.kind == Kinds.VAR) { |
duke@1 | 160 | VarSymbol f = (VarSymbol)e.sym; |
duke@1 | 161 | if ((f.flags() & Flags.STATIC) != 0 && |
duke@1 | 162 | (f.flags() & Flags.PRIVATE) != 0) { |
duke@1 | 163 | return f; |
duke@1 | 164 | } |
duke@1 | 165 | } |
duke@1 | 166 | } |
duke@1 | 167 | return null; |
duke@1 | 168 | } |
duke@1 | 169 | |
duke@1 | 170 | /* |
duke@1 | 171 | * Compute default Serializable fields from all members of ClassSymbol. |
duke@1 | 172 | * |
duke@1 | 173 | * Since the fields of ClassDocImpl might not contain private or |
duke@1 | 174 | * package accessible fields, must walk over all members of ClassSymbol. |
duke@1 | 175 | */ |
duke@1 | 176 | private void computeDefaultSerializableFields(DocEnv env, |
duke@1 | 177 | ClassSymbol def, |
duke@1 | 178 | ClassDocImpl cd) { |
duke@1 | 179 | for (Scope.Entry e = def.members().elems; e != null; e = e.sibling) { |
duke@1 | 180 | if (e.sym != null && e.sym.kind == Kinds.VAR) { |
duke@1 | 181 | VarSymbol f = (VarSymbol)e.sym; |
duke@1 | 182 | if ((f.flags() & Flags.STATIC) == 0 && |
duke@1 | 183 | (f.flags() & Flags.TRANSIENT) == 0) { |
duke@1 | 184 | //### No modifier filtering applied here. |
duke@1 | 185 | FieldDocImpl fd = env.getFieldDoc(f); |
duke@1 | 186 | //### Add to beginning. |
duke@1 | 187 | //### Preserve order used by old 'javadoc'. |
duke@1 | 188 | fields.prepend(fd); |
duke@1 | 189 | } |
duke@1 | 190 | } |
duke@1 | 191 | } |
duke@1 | 192 | } |
duke@1 | 193 | |
duke@1 | 194 | /* |
duke@1 | 195 | * Catalog Serializable method if it exists in current ClassSymbol. |
duke@1 | 196 | * Do not look for method in superclasses. |
duke@1 | 197 | * |
duke@1 | 198 | * Serialization requires these methods to be non-static. |
duke@1 | 199 | * |
duke@1 | 200 | * @param method should be an unqualified Serializable method |
duke@1 | 201 | * name either READOBJECT, WRITEOBJECT, READRESOLVE |
duke@1 | 202 | * or WRITEREPLACE. |
duke@1 | 203 | * @param visibility the visibility flag for the given method. |
duke@1 | 204 | */ |
duke@1 | 205 | private void addMethodIfExist(DocEnv env, ClassSymbol def, String methodName) { |
jjg@113 | 206 | Names names = def.name.table.names; |
duke@1 | 207 | |
duke@1 | 208 | for (Scope.Entry e = def.members().lookup(names.fromString(methodName)); e.scope != null; e = e.next()) { |
duke@1 | 209 | if (e.sym.kind == Kinds.MTH) { |
duke@1 | 210 | MethodSymbol md = (MethodSymbol)e.sym; |
duke@1 | 211 | if ((md.flags() & Flags.STATIC) == 0) { |
duke@1 | 212 | /* |
duke@1 | 213 | * WARNING: not robust if unqualifiedMethodName is overloaded |
duke@1 | 214 | * method. Signature checking could make more robust. |
duke@1 | 215 | * READOBJECT takes a single parameter, java.io.ObjectInputStream. |
duke@1 | 216 | * WRITEOBJECT takes a single parameter, java.io.ObjectOutputStream. |
duke@1 | 217 | */ |
duke@1 | 218 | methods.append(env.getMethodDoc(md)); |
duke@1 | 219 | } |
duke@1 | 220 | } |
duke@1 | 221 | } |
duke@1 | 222 | } |
duke@1 | 223 | |
duke@1 | 224 | /* |
duke@1 | 225 | * Associate serialField tag fieldName with FieldDocImpl member. |
duke@1 | 226 | * Note: A serialField tag does not have to map an existing field |
duke@1 | 227 | * of a class. |
duke@1 | 228 | */ |
duke@1 | 229 | private void mapSerialFieldTagImplsToFieldDocImpls(FieldDocImpl spfDoc, |
duke@1 | 230 | DocEnv env, |
duke@1 | 231 | ClassSymbol def) { |
jjg@113 | 232 | Names names = def.name.table.names; |
duke@1 | 233 | |
duke@1 | 234 | SerialFieldTag[] sfTag = spfDoc.serialFieldTags(); |
duke@1 | 235 | for (int i = 0; i < sfTag.length; i++) { |
duke@1 | 236 | Name fieldName = names.fromString(sfTag[i].fieldName()); |
duke@1 | 237 | |
duke@1 | 238 | // Look for a FieldDocImpl that is documented by serialFieldTagImpl. |
duke@1 | 239 | for (Scope.Entry e = def.members().lookup(fieldName); e.scope != null; e = e.next()) { |
duke@1 | 240 | if (e.sym.kind == Kinds.VAR) { |
duke@1 | 241 | VarSymbol f = (VarSymbol)e.sym; |
duke@1 | 242 | FieldDocImpl fdi = env.getFieldDoc(f); |
duke@1 | 243 | ((SerialFieldTagImpl)(sfTag[i])).mapToFieldDocImpl(fdi); |
duke@1 | 244 | break; |
duke@1 | 245 | } |
duke@1 | 246 | } |
duke@1 | 247 | } |
duke@1 | 248 | } |
duke@1 | 249 | |
duke@1 | 250 | /** |
duke@1 | 251 | * Return serializable fields in class. <p> |
duke@1 | 252 | * |
duke@1 | 253 | * Returns either a list of default fields documented by serial tag comment or |
duke@1 | 254 | * javadoc comment<p> |
duke@1 | 255 | * Or Returns a single FieldDocImpl for serialPersistentField. There is a |
duke@1 | 256 | * serialField tag for each serializable field.<p> |
duke@1 | 257 | * |
duke@1 | 258 | * @return an array of FieldDocImpl for representing the visible |
duke@1 | 259 | * fields in this class. |
duke@1 | 260 | */ |
duke@1 | 261 | FieldDoc[] fields() { |
duke@1 | 262 | return (FieldDoc[])fields.toArray(new FieldDocImpl[fields.length()]); |
duke@1 | 263 | } |
duke@1 | 264 | |
duke@1 | 265 | /** |
duke@1 | 266 | * Return serialization methods in class. |
duke@1 | 267 | * |
duke@1 | 268 | * @return an array of MethodDocImpl for serialization methods in this class. |
duke@1 | 269 | */ |
duke@1 | 270 | MethodDoc[] methods() { |
jjg@74 | 271 | return methods.toArray(new MethodDoc[methods.length()]); |
duke@1 | 272 | } |
duke@1 | 273 | |
duke@1 | 274 | /** |
duke@1 | 275 | * Returns true if Serializable fields are defined explicitly using |
duke@1 | 276 | * member, serialPersistentFields. |
duke@1 | 277 | * |
duke@1 | 278 | * @see #fields() |
duke@1 | 279 | */ |
duke@1 | 280 | boolean definesSerializableFields() { |
duke@1 | 281 | return definesSerializableFields; |
duke@1 | 282 | } |
duke@1 | 283 | } |