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