001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 BEA Systems, Inc.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * tyeung@bea.com - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.apt.core.internal.declaration;
011:
012: import java.util.ArrayList;
013: import java.util.Collection;
014: import java.util.Collections;
015: import java.util.List;
016:
017: import org.eclipse.core.resources.IFile;
018: import org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv;
019: import org.eclipse.jdt.apt.core.internal.util.Factory;
020: import org.eclipse.jdt.core.dom.ASTNode;
021: import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
022: import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
023: import org.eclipse.jdt.core.dom.BodyDeclaration;
024: import org.eclipse.jdt.core.dom.IBinding;
025: import org.eclipse.jdt.core.dom.IMethodBinding;
026: import org.eclipse.jdt.core.dom.ITypeBinding;
027: import org.eclipse.jdt.core.dom.IVariableBinding;
028: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
029:
030: import com.sun.mirror.declaration.Declaration;
031: import com.sun.mirror.declaration.FieldDeclaration;
032: import com.sun.mirror.declaration.MethodDeclaration;
033: import com.sun.mirror.declaration.PackageDeclaration;
034: import com.sun.mirror.declaration.TypeDeclaration;
035: import com.sun.mirror.declaration.TypeParameterDeclaration;
036: import com.sun.mirror.type.DeclaredType;
037: import com.sun.mirror.type.InterfaceType;
038: import com.sun.mirror.type.ReferenceType;
039: import com.sun.mirror.type.TypeMirror;
040: import com.sun.mirror.util.DeclarationVisitor;
041:
042: public abstract class TypeDeclarationImpl extends MemberDeclarationImpl
043: implements TypeDeclaration, DeclaredType, ReferenceType,
044: EclipseMirrorType {
045: // jdt core compiler add a field to a type with the following name when there is a hierachy problem with the type.
046: private static final String HAS_INCONSISTENT_TYPE_HIERACHY = "has inconsistent hierarchy"; //$NON-NLS-1$
047:
048: public TypeDeclarationImpl(final ITypeBinding binding,
049: final BaseProcessorEnv env) {
050: super (binding, env);
051: }
052:
053: public String getQualifiedName() {
054: ITypeBinding type = getTypeBinding();
055: return type.getQualifiedName();
056: }
057:
058: public String getSimpleName() {
059: ITypeBinding type = getTypeBinding();
060: return type.getName();
061: }
062:
063: public PackageDeclaration getPackage() {
064: ITypeBinding binding = getDeclarationBinding();
065: return new PackageDeclarationImpl(binding.getPackage(), this ,
066: _env, false);
067: }
068:
069: public void accept(DeclarationVisitor visitor) {
070: visitor.visitTypeDeclaration(this );
071: }
072:
073: public ITypeBinding getTypeBinding() {
074: return (ITypeBinding) _binding;
075: }
076:
077: @SuppressWarnings("unchecked")
078: private void getASTFields(final AbstractTypeDeclaration typeDecl,
079: final List<FieldDeclaration> results) {
080: final List bodyDecls = typeDecl.bodyDeclarations();
081: for (int i = 0, len = bodyDecls.size(); i < len; i++) {
082: final BodyDeclaration bodyDecl = (BodyDeclaration) bodyDecls
083: .get(i);
084: IFile file = null;
085: if (bodyDecl.getNodeType() == ASTNode.FIELD_DECLARATION) {
086: final List<VariableDeclarationFragment> fragments = ((org.eclipse.jdt.core.dom.FieldDeclaration) bodyDecl)
087: .fragments();
088: for (VariableDeclarationFragment frag : fragments) {
089: final IBinding fieldBinding = frag.resolveBinding();
090: if (fieldBinding == null) {
091: if (file == null)
092: file = getResource();
093: final EclipseDeclarationImpl decl = Factory
094: .createDeclaration(frag, file, _env);
095: if (decl != null)
096: results.add((FieldDeclaration) decl);
097: }
098: }
099: }
100: }
101: }
102:
103: public Collection<FieldDeclaration> getFields() {
104: final List<FieldDeclaration> results = new ArrayList<FieldDeclaration>();
105: final ITypeBinding typeBinding = getDeclarationBinding();
106: if (isFromSource()) {
107: final ASTNode node = _env.getASTNodeForBinding(typeBinding);
108: if (node != null) {
109: switch (node.getNodeType()) {
110: case ASTNode.TYPE_DECLARATION:
111: case ASTNode.ANNOTATION_TYPE_DECLARATION:
112: case ASTNode.ENUM_DECLARATION:
113: AbstractTypeDeclaration typeDecl = (AbstractTypeDeclaration) node;
114: // built the ast based methods first.
115: getASTFields(typeDecl, results);
116: break;
117: default:
118: // the ast node for a type binding should be a AbstractTypeDeclaration.
119: throw new IllegalStateException(
120: "expecting a AbstractTypeDeclaration but got " //$NON-NLS-1$
121: + node.getClass().getName());
122: }
123: }
124: }
125: // either type is binary or
126: // constructing the binding based fields for source type.
127: final IVariableBinding[] fields = typeBinding
128: .getDeclaredFields();
129: for (IVariableBinding field : fields) {
130: // note that the name HAS_INCONSISTENT_TYPE_HIERACHY is not a legal java identifier
131: // so there is no chance that we are filtering out actual declared fields.
132: if (field.isSynthetic()
133: || HAS_INCONSISTENT_TYPE_HIERACHY.equals(field
134: .getName()))
135: continue;
136: Declaration mirrorDecl = Factory.createDeclaration(field,
137: _env);
138: if (mirrorDecl != null)
139: results.add((FieldDeclaration) mirrorDecl);
140: }
141: return results;
142: }
143:
144: public Collection<TypeDeclaration> getNestedTypes() {
145: final ITypeBinding[] memberTypes = getDeclarationBinding()
146: .getDeclaredTypes();
147: final List<TypeDeclaration> results = new ArrayList<TypeDeclaration>(
148: memberTypes.length);
149: for (ITypeBinding type : memberTypes) {
150: Declaration mirrorDecl = Factory.createReferenceType(type,
151: _env);
152: if (mirrorDecl != null)
153: results.add((TypeDeclaration) mirrorDecl);
154: }
155: return results;
156: }
157:
158: public Collection<TypeParameterDeclaration> getFormalTypeParameters() {
159: final ITypeBinding[] typeParams = getDeclarationBinding()
160: .getTypeParameters();
161: final List<TypeParameterDeclaration> results = new ArrayList<TypeParameterDeclaration>(
162: typeParams.length);
163: for (ITypeBinding typeParam : typeParams) {
164: Declaration mirrorDecl = Factory.createDeclaration(
165: typeParam, _env);
166: if (mirrorDecl != null)
167: results.add((TypeParameterDeclaration) mirrorDecl);
168: }
169: return results;
170: }
171:
172: public TypeDeclaration getDeclaringType() {
173: final ITypeBinding decl = getDeclarationBinding();
174: if (decl.isMember())
175: return Factory.createReferenceType(
176: decl.getDeclaringClass(), _env);
177: return null;
178: }
179:
180: // Start of implementation of DeclaredType API
181: public Collection<TypeMirror> getActualTypeArguments() {
182: final ITypeBinding type = getTypeBinding();
183: final ITypeBinding[] typeArgs = type.getTypeArguments();
184: if (typeArgs == null || typeArgs.length == 0)
185: return Collections.emptyList();
186:
187: final Collection<TypeMirror> result = new ArrayList<TypeMirror>(
188: typeArgs.length);
189: for (ITypeBinding arg : typeArgs) {
190: final TypeMirror mirror = Factory.createTypeMirror(arg,
191: _env);
192: if (mirror == null)
193: result.add(Factory.createErrorClassType(arg));
194: else
195: result.add(mirror);
196: }
197:
198: return result;
199: }
200:
201: public DeclaredType getContainingType() {
202: final ITypeBinding outer = getTypeBinding().getDeclaringClass();
203: return Factory.createReferenceType(outer, _env);
204: }
205:
206: public TypeDeclaration getDeclaration() {
207: final ITypeBinding declBinding = getDeclarationBinding();
208: if (declBinding == _binding)
209: return this ;
210: else
211: return Factory.createReferenceType(declBinding, _env);
212: }
213:
214: public Collection<InterfaceType> getSuperinterfaces() {
215: final ITypeBinding[] super InterfaceBindings = getDeclarationBinding()
216: .getInterfaces();
217: if (super InterfaceBindings == null
218: || super InterfaceBindings.length == 0)
219: return Collections.emptyList();
220: final List<InterfaceType> results = new ArrayList<InterfaceType>(
221: super InterfaceBindings.length);
222: for (ITypeBinding binding : super InterfaceBindings) {
223: if (binding.isInterface()) {
224: final TypeDeclarationImpl mirrorDecl = Factory
225: .createReferenceType(binding, _env);
226: if (mirrorDecl.kind() == MirrorKind.TYPE_INTERFACE) {
227: results.add((InterfaceType) mirrorDecl);
228: }
229: } else
230: results.add(Factory.createErrorInterfaceType(binding));
231: }
232: return results;
233: }
234:
235: // End of implementation of DeclaredType API
236:
237: public ITypeBinding getDeclarationBinding() {
238: final ITypeBinding type = getTypeBinding();
239: return type.getTypeDeclaration();
240: }
241:
242: /**
243: * create mirror methods that does not have a binding represention.
244: */
245: @SuppressWarnings("unchecked")
246: protected void getASTMethods(
247: final AbstractTypeDeclaration typeDecl,
248: final List<MethodDeclaration> results) {
249: final List bodyDecls = typeDecl.bodyDeclarations();
250: IFile file = null;
251: for (int i = 0, len = bodyDecls.size(); i < len; i++) {
252: final BodyDeclaration bodyDecl = (BodyDeclaration) bodyDecls
253: .get(i);
254: switch (bodyDecl.getNodeType()) {
255: case ASTNode.METHOD_DECLARATION:
256: final org.eclipse.jdt.core.dom.MethodDeclaration methodDecl = (org.eclipse.jdt.core.dom.MethodDeclaration) bodyDecl;
257:
258: if (!methodDecl.isConstructor()) {
259: final IMethodBinding methodBinding = methodDecl
260: .resolveBinding();
261: // built an ast based representation.
262: if (methodBinding == null) {
263: if (file == null)
264: file = getResource();
265: MethodDeclaration mirrorDecl = (MethodDeclaration) Factory
266: .createDeclaration(methodDecl, file,
267: _env);
268: if (mirrorDecl != null)
269: results.add(mirrorDecl);
270: }
271: }
272: break;
273: case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION:
274: final AnnotationTypeMemberDeclaration memberDecl = (AnnotationTypeMemberDeclaration) bodyDecl;
275: final IMethodBinding methodBinding = memberDecl
276: .resolveBinding();
277: // built an ast based representation.
278: if (methodBinding == null) {
279: if (file == null)
280: file = getResource();
281: MethodDeclaration mirrorDecl = (MethodDeclaration) Factory
282: .createDeclaration(memberDecl, file, _env);
283: if (mirrorDecl != null)
284: results.add(mirrorDecl);
285: }
286: break;
287: }
288: }
289: }
290:
291: protected List<? extends MethodDeclaration> _getMethods() {
292: final List<MethodDeclaration> results = new ArrayList<MethodDeclaration>();
293: if (isFromSource()) {
294: // need to consult the ast since methods with broken signature
295: // do not appear in bindings.
296: final ITypeBinding typeBinding = getDeclarationBinding();
297: final ASTNode node = _env.getASTNodeForBinding(typeBinding);
298: if (node != null) {
299: switch (node.getNodeType()) {
300: case ASTNode.TYPE_DECLARATION:
301: case ASTNode.ANNOTATION_TYPE_DECLARATION:
302: case ASTNode.ENUM_DECLARATION:
303: AbstractTypeDeclaration typeDecl = (AbstractTypeDeclaration) node;
304: // built the ast based methods first.
305: getASTMethods(typeDecl, results);
306: break;
307: default:
308: // the ast node for a type binding should be a AbstractTypeDeclaration.
309: throw new IllegalStateException(
310: "expecting a AbstractTypeDeclaration but got " //$NON-NLS-1$
311: + node.getClass().getName());
312: }
313: }
314: }
315: // build methods for binding type or
316: // build the binding based method for source type.
317: final IMethodBinding[] methods = getDeclarationBinding()
318: .getDeclaredMethods();
319: for (IMethodBinding method : methods) {
320: if (method.isConstructor() || method.isSynthetic())
321: continue;
322: Declaration mirrorDecl = Factory.createDeclaration(method,
323: _env);
324: if (mirrorDecl != null)
325: results.add((MethodDeclaration) mirrorDecl);
326: }
327: return results;
328: }
329:
330: public String toString() {
331: return getQualifiedName();
332: }
333:
334: public boolean isFromSource() {
335: return getDeclarationBinding().isFromSource();
336: }
337:
338: public boolean isAssignmentCompatible(EclipseMirrorType left) {
339: return isSubTypeCompatible(left);
340: }
341:
342: public boolean isSubTypeCompatible(EclipseMirrorType type) {
343: // Operate on erasures - ignore generics for now
344: // Also ignore boxing for now
345: ITypeBinding this Erased = getTypeBinding().getErasure();
346: ITypeBinding typeErased = type.getTypeBinding().getErasure();
347:
348: if (kind() == MirrorKind.TYPE_CLASS) {
349: if (type.kind() == MirrorKind.TYPE_CLASS)
350: return isSubClassOf(this Erased, typeErased);
351: if (type.kind() == MirrorKind.TYPE_INTERFACE)
352: return isImplementorOf(this Erased, typeErased);
353: return false;
354: } else { //kind() == MirrorKind.TYPE_INTERFACE
355: if (type.kind() == MirrorKind.TYPE_INTERFACE)
356: return isImplementorOf(this Erased, typeErased);
357: if (type.kind() == MirrorKind.TYPE_CLASS)
358: return "java.lang.Object".equals(getQualifiedName()); //$NON-NLS-1$
359: return false;
360: }
361: }
362:
363: private static boolean isImplementorOf(ITypeBinding t1,
364: ITypeBinding t2) {
365: if (eq(t1, t2))
366: return true;
367: ITypeBinding[] intfs = t1.getInterfaces();
368:
369: for (ITypeBinding intf : intfs) {
370: if (isImplementorOf(intf.getErasure(), t2))
371: return true;
372: }
373: return false;
374: }
375:
376: private static boolean isSubClassOf(ITypeBinding t1, ITypeBinding t2) {
377: while (t1 != null) {
378: if (eq(t1, t2))
379: return true;
380: t1 = t1.getSuperclass();
381: }
382: return false;
383: }
384:
385: private static boolean eq(ITypeBinding t1, ITypeBinding t2) {
386: return t1.getQualifiedName().equals(t2.getQualifiedName());
387: }
388: }
|