001 // This file is part of the RECODER library and protected by the LGPL.
002
003 package recoder.java.declaration;
004
005 import recoder.java.Identifier;
006 import recoder.java.ProgramElement;
007 import recoder.java.SourceVisitor;
008 import recoder.java.Statement;
009 import recoder.java.StatementBlock;
010 import recoder.java.StatementContainer;
011 import recoder.list.generic.ASTList;
012
013 /**
014 * Outer or member class declaration. There are several types of class
015 * declarations:
016 * <ul>
017 * <li>outer classes
018 * <ul>
019 * <li>getContainer() instanceof Package
020 * <li>getStatementContainer() == null
021 * <li>getName() != null
022 * </ul>
023 * <li>member classes
024 * <ul>
025 * <li>getContainer() instanceof TypeDeclaration
026 * <li>getStatementContainer() == null
027 * <li>getName() != null
028 * </ul>
029 * <li>inner classes
030 * <ul>
031 * <li>as member classes, and
032 * <li>not declared "static" (explicitly or implicitly)
033 * </ul>
034 * <li>local classes
035 * <ul>
036 * <li>getContainer() != null (either Method or ClassInitializer)
037 * <li>getStatementContainer() != null
038 * <li>getName() != null
039 * </ul>
040 * <li>anonymous classes
041 * <ul>
042 * <li>getContainer() != null (but further unspecified;
043 * could be Method, ClassInitializer, but also Package in case
044 * it appears in )
045 * <li>getStatementContainer() == null
046 * <li>getName() == null
047 * </ul>
048 * </ul>
049 * Anonymous local classes have exactly one supertype and no subtypes. <BR>
050 * Binary classes may have only binary members.
051 */
052 public class ClassDeclaration extends TypeDeclaration implements Statement {
053
054 /**
055 * serialization id
056 */
057 private static final long serialVersionUID = -1520369925548201696L;
058
059 /**
060 * Extending.
061 */
062 private Extends extending;
063
064 /**
065 * Type Parameters (Java 5)
066 */
067 private ASTList<TypeParameterDeclaration> typeParameters;
068
069 /**
070 * Implementing.
071 */
072 private Implements implementing;
073
074 /**
075 * Class declaration.
076 */
077 public ClassDeclaration() {
078 // nothing to do here
079 }
080
081 /** Construct a non-anonymous class. */
082 public ClassDeclaration(ASTList<DeclarationSpecifier> declSpecs, Identifier name, Extends extended, Implements implemented,
083 ASTList<MemberDeclaration> members, ASTList<TypeParameterDeclaration> typeParameters) {
084 super(declSpecs, name);
085 setExtendedTypes(extended);
086 setImplementedTypes(implemented);
087 setMembers(members);
088 setTypeParameters(typeParameters);
089 makeParentRoleValid();
090 }
091
092 public ClassDeclaration(ASTList<DeclarationSpecifier> declSpecs, Identifier name, Extends extended, Implements implemented,
093 ASTList<MemberDeclaration> members) {
094 this (declSpecs, name, extended, implemented, members, null);
095 }
096
097 /**
098 * Class declaration.
099 *
100 * @param members
101 * a member declaration mutable list.
102 */
103 public ClassDeclaration(ASTList<MemberDeclaration> members) {
104 setMembers(members);
105 makeParentRoleValid();
106 }
107
108 /**
109 * Class declaration.
110 *
111 * @param proto
112 * a class declaration.
113 */
114 protected ClassDeclaration(ClassDeclaration proto) {
115 super(proto);
116 if (proto.extending != null) {
117 extending = proto.extending.deepClone();
118 }
119 if (proto.implementing != null) {
120 implementing = proto.implementing.deepClone();
121 }
122 if (proto.typeParameters != null) {
123 typeParameters = proto.typeParameters.deepClone();
124 }
125 makeParentRoleValid();
126 }
127
128 /**
129 * Deep clone.
130 *
131 * @return the object.
132 */
133 public ClassDeclaration deepClone() {
134 return new ClassDeclaration(this);
135 }
136
137 /**
138 * Make parent role valid.
139 */
140 public void makeParentRoleValid() {
141 super.makeParentRoleValid();
142 if (extending != null) {
143 extending.setParent(this);
144 }
145 if (implementing != null) {
146 implementing.setParent(this);
147 }
148 if (typeParameters != null) {
149 for (TypeParameterDeclaration tp : typeParameters) {
150 tp.setParent(this);
151 }
152 }
153 }
154
155 /**
156 * Returns the number of children of this node.
157 *
158 * @return an int giving the number of children of this node
159 */
160 public int getChildCount() {
161 int result = 0;
162 if (declarationSpecifiers != null)
163 result += declarationSpecifiers.size();
164 if (name != null)
165 result++;
166 if (extending != null)
167 result++;
168 if (implementing != null)
169 result++;
170 if (members != null)
171 result += members.size();
172 if (typeParameters != null)
173 result += typeParameters.size();
174 return result;
175 }
176
177 /**
178 * Returns the child at the specified index in this node's "virtual" child
179 * array
180 *
181 * @param index
182 * an index into this node's "virtual" child array
183 * @return the program element at the given position
184 * @exception ArrayIndexOutOfBoundsException
185 * if <tt>index</tt> is out of bounds
186 */
187 public ProgramElement getChildAt(int index) {
188 int len;
189 if (declarationSpecifiers != null) {
190 len = declarationSpecifiers.size();
191 if (len > index) {
192 return declarationSpecifiers.get(index);
193 }
194 index -= len;
195 }
196 if (name != null) {
197 if (index == 0)
198 return name;
199 index--;
200 }
201 if (typeParameters != null) {
202 len = typeParameters.size();
203 if (len > index)
204 return typeParameters.get(index);
205 index -= len;
206 }
207 if (extending != null) {
208 if (index == 0)
209 return extending;
210 index--;
211 }
212 if (implementing != null) {
213 if (index == 0)
214 return implementing;
215 index--;
216 }
217 if (members != null) {
218 if (index < members.size())
219 return members.get(index);
220 index -= members.size();
221 }
222 throw new ArrayIndexOutOfBoundsException();
223 }
224
225 public int getChildPositionCode(ProgramElement child) {
226 // role 0 (IDX): declaration specifier
227 // role 1: identifier
228 // role 2: extends
229 // role 3: implements (no occurrence in interfaces)
230 // role 4 (IDX): members
231 // role 5 (IDX): type parameters
232 if (declarationSpecifiers != null) {
233 int index = declarationSpecifiers.indexOf(child);
234 if (index >= 0) {
235 return (index << 4) | 0;
236 }
237 }
238 if (name == child)
239 return 1;
240 if (extending == child)
241 return 2;
242 if (implementing == child)
243 return 3;
244 if (members != null) {
245 int index = members.indexOf(child);
246 if (index >= 0) {
247 return (index << 4) | 4;
248 }
249 }
250 if (typeParameters != null) {
251 int index = typeParameters.size();
252 if (index >= 0) {
253 return (index << 4) | 5;
254 }
255 }
256 return -1;
257 }
258
259 /**
260 * Replace a single child in the current node. The child to replace is
261 * matched by identity and hence must be known exactly. The replacement
262 * element can be null - in that case, the child is effectively removed. The
263 * parent role of the new child is validated, while the parent link of the
264 * replaced child is left untouched.
265 *
266 * @param p
267 * the old child.
268 * @param p
269 * the new child.
270 * @return true if a replacement has occured, false otherwise.
271 * @exception ClassCastException
272 * if the new child cannot take over the role of the old one.
273 */
274 public boolean replaceChild(ProgramElement p, ProgramElement q) {
275 if (p == null) {
276 throw new NullPointerException();
277 }
278 int count;
279 count = (declarationSpecifiers == null) ? 0 : declarationSpecifiers.size();
280 for (int i = 0; i < count; i++) {
281 if (declarationSpecifiers.get(i) == p) {
282 if (q == null) {
283 declarationSpecifiers.remove(i);
284 } else {
285 DeclarationSpecifier r = (DeclarationSpecifier) q;
286 declarationSpecifiers.set(i, r);
287 r.setParent(this);
288 }
289 return true;
290 }
291 }
292 if (name == p) {
293 Identifier r = (Identifier) q;
294 name = r;
295 if (r != null) {
296 r.setParent(this);
297 }
298 return true;
299 }
300 if (extending == p) {
301 Extends r = (Extends) q;
302 extending = r;
303 if (r != null) {
304 r.setParent(this);
305 }
306 return true;
307 }
308 if (implementing == p) {
309 Implements r = (Implements) q;
310 implementing = r;
311 if (r != null) {
312 r.setParent(this);
313 }
314 return true;
315 }
316 count = (members == null) ? 0 : members.size();
317 for (int i = 0; i < count; i++) {
318 if (members.get(i) == p) {
319 if (q == null) {
320 members.remove(i);
321 } else {
322 MemberDeclaration r = (MemberDeclaration) q;
323 members.set(i, r);
324 r.setMemberParent(this);
325 }
326 return true;
327 }
328 }
329 if (typeParameters != null) {
330 int idx = typeParameters.indexOf(p);
331 if (idx != -1) {
332 if (q == null) {
333 typeParameters.remove(idx);
334 } else {
335 TypeParameterDeclaration r = (TypeParameterDeclaration)q;
336 typeParameters.set(idx, r);
337 r.setParent(this);
338 }
339 return true;
340 }
341 }
342 return false;
343 }
344
345 /**
346 * Get statement container.
347 *
348 * @return null, if the type is not declared locally.
349 */
350 public StatementContainer getStatementContainer() {
351 return (parent instanceof StatementContainer) ? (StatementContainer) parent : null;
352 }
353
354 /**
355 * Set statement container. Must be a {@link recoder.java.StatementBlock}.
356 *
357 * @param p
358 * a statement container.
359 */
360 public void setStatementContainer(StatementContainer p) {
361 parent = (StatementBlock) p;
362 }
363
364 /**
365 * Get extended types.
366 *
367 * @return the extends.
368 */
369 public Extends getExtendedTypes() {
370 return extending;
371 }
372
373 /**
374 * Set extended types.
375 *
376 * @param spec
377 * an extends.
378 */
379 public void setExtendedTypes(Extends spec) {
380 extending = spec;
381 }
382
383 /**
384 * Get implemented types.
385 *
386 * @return the implements.
387 */
388 public Implements getImplementedTypes() {
389 return implementing;
390 }
391
392 /**
393 * Set implemented types.
394 *
395 * @param spec
396 * an implements.
397 */
398 public void setImplementedTypes(Implements spec) {
399 implementing = spec;
400 }
401
402 /**
403 * Classes are never strictfp.
404 */
405 public boolean isStrictFp() {
406 return false;
407 }
408
409 /**
410 * Classes are never transient.
411 */
412 public boolean isTransient() {
413 return false;
414 }
415
416 /**
417 * Classes are never volatile.
418 */
419 public boolean isVolatile() {
420 return false;
421 }
422
423 public boolean isInterface() {
424 return false;
425 }
426
427 public boolean isOrdinaryInterface() {
428 return false;
429 }
430
431 public boolean isAnnotationType() {
432 return false;
433 }
434
435 public boolean isEnumType() {
436 return false;
437 }
438
439 public boolean isOrdinaryClass() {
440 return true;
441 }
442
443 public void accept(SourceVisitor v) {
444 v.visitClassDeclaration(this);
445 }
446
447 public void setTypeParameters(ASTList<TypeParameterDeclaration> typeParameters) {
448 this.typeParameters = typeParameters;
449 }
450
451 public ASTList<TypeParameterDeclaration> getTypeParameters() {
452 return typeParameters;
453 }
454
455 public boolean isInner() {
456 if (isStatic())
457 return false;
458 if (!(getContainingClassType() instanceof ClassDeclaration))
459 return false;
460 if (getName() == null)
461 return false;
462 if (getStatementContainer() != null)
463 return false;
464 return true;
465 }
466 }