EMMA Coverage Report (generated Thu Nov 26 15:54:18 CST 2009)
[all classes][org.eclipse.pde.api.tools.internal.builder]

COVERAGE SUMMARY FOR SOURCE FILE [ReferenceExtractor.java]

nameclass, %method, %block, %line, %
ReferenceExtractor.java100% (7/7)86%  (61/71)82%  (1649/2019)83%  (433.6/525)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ReferenceExtractor$LineInfo100% (1/1)50%  (2/4)26%  (16/62)38%  (5/13)
equals (Object): boolean 0%   (0/1)0%   (0/25)0%   (0/5)
toString (): String 0%   (0/1)0%   (0/21)0%   (0/3)
ReferenceExtractor$LineInfo (int, Label): void 100% (1/1)100% (9/9)100% (4/4)
compareTo (Object): int 100% (1/1)100% (7/7)100% (1/1)
     
class ReferenceExtractor$LocalLineNumberMarker100% (1/1)33%  (1/3)26%  (9/34)44%  (4/9)
equals (Object): boolean 0%   (0/1)0%   (0/22)0%   (0/4)
hashCode (): int 0%   (0/1)0%   (0/3)0%   (0/1)
ReferenceExtractor$LocalLineNumberMarker (int, int): void 100% (1/1)100% (9/9)100% (4/4)
     
class ReferenceExtractor$LabelInfo100% (1/1)50%  (1/2)30%  (9/30)57%  (4/7)
toString (): String 0%   (0/1)0%   (0/21)0%   (0/3)
ReferenceExtractor$LabelInfo (Reference, Label): void 100% (1/1)100% (9/9)100% (4/4)
     
class ReferenceExtractor$ClassFileMethodVisitor100% (1/1)93%  (14/15)82%  (477/582)84%  (140.6/168)
toString (): String 0%   (0/1)0%   (0/25)0%   (0/6)
visitLabel (Label): void 100% (1/1)45%  (25/55)54%  (7/13)
visitLocalVariable (String, String, String, Label, Label, int): void 100% (1/1)64%  (80/125)62%  (21.8/35)
visitTypeInsn (int, String): void 100% (1/1)94%  (47/50)88%  (15/17)
visitLdcInsn (Object): void 100% (1/1)94%  (33/35)98%  (8.8/9)
ReferenceExtractor$ClassFileMethodVisitor (ReferenceExtractor, MethodVisitor,... 100% (1/1)100% (32/32)100% (9/9)
getTypeFromDescription (String): Type 100% (1/1)100% (27/27)100% (8/8)
visitCode (): void 100% (1/1)100% (3/3)100% (2/2)
visitEnd (): void 100% (1/1)100% (16/16)100% (6/6)
visitFieldInsn (int, String, String, String): void 100% (1/1)100% (33/33)100% (14/14)
visitLineNumber (int, Label): void 100% (1/1)100% (9/9)100% (3/3)
visitMethodInsn (int, String, String, String): void 100% (1/1)100% (117/117)100% (30/30)
visitMultiANewArrayInsn (String, int): void 100% (1/1)100% (17/17)100% (5/5)
visitTryCatchBlock (Label, Label, Label, String): void 100% (1/1)100% (23/23)100% (7/7)
visitVarInsn (int, int): void 100% (1/1)100% (15/15)100% (4/4)
     
class ReferenceExtractor100% (1/1)91%  (20/22)84%  (739/876)83%  (173/209)
setDebug (boolean): void 0%   (0/1)0%   (0/9)0%   (0/2)
toString (): String 0%   (0/1)0%   (0/44)0%   (0/10)
visitEnd (): void 100% (1/1)56%  (14/25)83%  (5/6)
visitField (int, String, String, String, Object): FieldVisitor 100% (1/1)66%  (40/61)61%  (11/18)
visitMethod (int, String, String, String, String []): MethodVisitor 100% (1/1)84%  (150/179)78%  (32/41)
visit (int, int, String, String, String, String []): void 100% (1/1)87%  (89/102)95%  (20/21)
addFieldReference (Type, String, int): Reference 100% (1/1)89%  (17/19)80%  (4/5)
addMethodReference (Type, String, String, int): Reference 100% (1/1)90%  (18/20)80%  (4/5)
consider (String): boolean 100% (1/1)93%  (25/27)67%  (2/3)
consider (Reference): boolean 100% (1/1)96%  (53/55)92%  (11/12)
visitInnerClass (String, String, String, int): void 100% (1/1)98%  (80/82)90%  (19/21)
<static initializer> 100% (1/1)100% (9/9)100% (3/3)
ReferenceExtractor (IApiType, Set, int): void 100% (1/1)100% (61/61)100% (15/15)
addReference (Reference): Reference 100% (1/1)100% (13/13)100% (4/4)
addTypeReference (Type, int): Reference 100% (1/1)100% (18/18)100% (5/5)
enterMember (IApiMember): void 100% (1/1)100% (6/6)100% (2/2)
exitMember (): void 100% (1/1)100% (5/5)100% (2/2)
getMember (): IApiMember 100% (1/1)100% (5/5)100% (1/1)
processInnerClass (IApiType, int): Set 100% (1/1)100% (25/25)100% (5/5)
processName (String): String 100% (1/1)100% (19/19)100% (5/5)
processSignature (String, String, int, int): List 100% (1/1)100% (68/68)100% (15/15)
resolveType (String): Type 100% (1/1)100% (24/24)100% (8/8)
     
class ReferenceExtractor$ClassFileSignatureVisitor100% (1/1)89%  (17/19)87%  (162/187)85%  (51/60)
visitExceptionType (): SignatureVisitor 0%   (0/1)0%   (0/5)0%   (0/2)
visitInnerClassType (String): void 0%   (0/1)0%   (0/4)0%   (0/2)
visitBaseType (char): void 100% (1/1)56%  (9/16)60%  (3/5)
visitFormalTypeParameter (String): void 100% (1/1)62%  (5/8)67%  (2/3)
processType (String): void 100% (1/1)90%  (53/59)83%  (10/12)
ReferenceExtractor$ClassFileSignatureVisitor (ReferenceExtractor): void 100% (1/1)100% (29/29)100% (9/9)
reset (): void 100% (1/1)100% (19/19)100% (7/7)
visitArrayType (): SignatureVisitor 100% (1/1)100% (2/2)100% (1/1)
visitClassBound (): SignatureVisitor 100% (1/1)100% (5/5)100% (2/2)
visitClassType (String): void 100% (1/1)100% (4/4)100% (2/2)
visitEnd (): void 100% (1/1)100% (1/1)100% (1/1)
visitInterface (): SignatureVisitor 100% (1/1)100% (5/5)100% (2/2)
visitInterfaceBound (): SignatureVisitor 100% (1/1)100% (5/5)100% (2/2)
visitParameterType (): SignatureVisitor 100% (1/1)100% (11/11)100% (3/3)
visitReturnType (): SignatureVisitor 100% (1/1)100% (5/5)100% (2/2)
visitSuperclass (): SignatureVisitor 100% (1/1)100% (5/5)100% (2/2)
visitTypeArgument (): void 100% (1/1)100% (1/1)100% (1/1)
visitTypeArgument (char): SignatureVisitor 100% (1/1)100% (2/2)100% (1/1)
visitTypeVariable (String): void 100% (1/1)100% (1/1)100% (1/1)
     
class ReferenceExtractor$LinePositionTracker100% (1/1)100% (6/6)96%  (237/248)95%  (56/59)
computeLineNumbers (): void 100% (1/1)94%  (173/184)93%  (41/44)
ReferenceExtractor$LinePositionTracker (): void 100% (1/1)100% (23/23)100% (6/6)
addCatchLabelInfos (Reference, Label): void 100% (1/1)100% (10/10)100% (2/2)
addLabel (Label): void 100% (1/1)100% (6/6)100% (2/2)
addLineInfo (int, Label): void 100% (1/1)100% (19/19)100% (3/3)
addLocation (Reference): void 100% (1/1)100% (6/6)100% (2/2)

1/*******************************************************************************
2 * Copyright (c) 2007, 2009 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *     IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.pde.api.tools.internal.builder;
12 
13import java.util.ArrayList;
14import java.util.HashMap;
15import java.util.HashSet;
16import java.util.Iterator;
17import java.util.List;
18import java.util.Set;
19import java.util.SortedSet;
20import java.util.Stack;
21import java.util.TreeSet;
22 
23import org.eclipse.core.runtime.CoreException;
24import org.eclipse.core.runtime.IStatus;
25import org.eclipse.core.runtime.Status;
26import org.eclipse.osgi.util.NLS;
27import org.eclipse.pde.api.tools.internal.model.AbstractApiTypeRoot;
28import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
29import org.eclipse.pde.api.tools.internal.provisional.builder.IReference;
30import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
31import org.eclipse.pde.api.tools.internal.provisional.model.IApiField;
32import org.eclipse.pde.api.tools.internal.provisional.model.IApiMember;
33import org.eclipse.pde.api.tools.internal.provisional.model.IApiMethod;
34import org.eclipse.pde.api.tools.internal.provisional.model.IApiType;
35import org.eclipse.pde.api.tools.internal.util.Signatures;
36import org.eclipse.pde.api.tools.internal.util.Util;
37import org.objectweb.asm.ClassAdapter;
38import org.objectweb.asm.ClassReader;
39import org.objectweb.asm.FieldVisitor;
40import org.objectweb.asm.Label;
41import org.objectweb.asm.MethodAdapter;
42import org.objectweb.asm.MethodVisitor;
43import org.objectweb.asm.Opcodes;
44import org.objectweb.asm.Type;
45import org.objectweb.asm.signature.SignatureReader;
46import org.objectweb.asm.signature.SignatureVisitor;
47import org.objectweb.asm.tree.ClassNode;
48 
49/**
50 * Extracts references from a class file
51 *
52 * @since 1.0.0
53 */
54public class ReferenceExtractor extends ClassAdapter {
55 
56        /**
57         * Constant used for controlling tracing in the visitor
58         */
59        private static boolean DEBUG = Util.DEBUG;
60 
61        /**
62         * Method used for initializing tracing in the visitor
63         */
64        public static void setDebug(boolean debugValue) {
65                DEBUG = debugValue || Util.DEBUG;
66        }
67 
68        /**
69         * A visitor for visiting java 5+ signatures
70         * TODO this visitor does not currently visit annotations
71         *
72         * ClassSignature = (visitFormalTypeParameter visitClassBound? visitInterfaceBound* )* (visitSuperClass visitInterface* )
73         * MethodSignature = (visitFormalTypeParameter visitClassBound? visitInterfaceBound* )* (visitParameterType visitReturnType visitExceptionType* )
74         * TypeSignature = visitBaseType | visitTypeVariable | visitArrayType | (visitClassType visitTypeArgument* (visitInnerClassType visitTypeArgument* )* visitEnd</tt> ) )
75         */
76        class ClassFileSignatureVisitor implements SignatureVisitor {
77 
78                protected int kind = -1;
79                protected int originalkind = -1;
80                protected int argumentcount = 0;
81                protected int type = 0;
82                protected String signature = null;
83                protected String name = null;
84                protected List references;
85 
86                public ClassFileSignatureVisitor() {
87                        this.references = new ArrayList();
88                }
89 
90                /**
91                 * Resets the visitor to its initial state.
92                 * This method should be called after processing is done with the visitor
93                 */
94                protected void reset() {
95                        //do not reset argument count, as it is needed once the signature visitor is done
96                        this.kind = -1;
97                        this.originalkind = -1;
98                        this.name = null;
99                        this.signature = null;
100                        this.type = 0;
101                        this.references.clear();
102                }
103 
104                /**
105                 * Processes the type specified by the name for the current signature context.
106                 * The kind flag is set to a parameterized type as subsequent calls to this method without visiting other nodes only occurs
107                 * when we are processing parameterized types of generic declarations
108                 * @param name the name of the type
109                 */
110                protected void processType(String name) {
111                        Type type = ReferenceExtractor.this.resolveType(Type.getObjectType(name).getDescriptor());
112                        if(type != null) {
113                                String tname = type.getClassName();
114                                if(tname.equals("E") || tname.equals("T")) {  //$NON-NLS-1$//$NON-NLS-2$
115                                        type = Type.getObjectType("java.lang.Object"); //$NON-NLS-1$
116                                        tname = type.getClassName();
117                                }
118                                if(ReferenceExtractor.this.consider(tname) && this.kind != -1) {
119                                        if(this.name != null && this.signature != null) {
120                                                this.references.add(
121                                                        Reference.typeReference(ReferenceExtractor.this.getMember(), tname, this.signature, this.kind));
122                                        }
123                                }
124                        }
125                        this.kind = this.originalkind;
126                }
127 
128                /* (non-Javadoc)
129                 * @see org.objectweb.asm.signature.SignatureVisitor#visitClassType(java.lang.String)
130                 */
131                public void visitClassType(String name) {
132                        this.processType(name);
133                }
134                /* (non-Javadoc)
135                 * @see org.objectweb.asm.signature.SignatureVisitor#visitFormalTypeParameter(java.lang.String)
136                 */
137                public void visitFormalTypeParameter(String name) {
138                        if(this.type != TYPE) {
139                                this.processType(name);
140                        }
141                }
142                /* (non-Javadoc)
143                 * @see org.objectweb.asm.signature.SignatureVisitor#visitTypeVariable(java.lang.String)
144                 */
145                public void visitTypeVariable(String name) {
146                }
147                /* (non-Javadoc)
148                 * @see org.objectweb.asm.signature.SignatureVisitor#visitInnerClassType(java.lang.String)
149                 */
150                public void visitInnerClassType(String name) {
151                        this.processType(name);
152                }
153                /* (non-Javadoc)
154                 * @see org.objectweb.asm.signature.SignatureVisitor#visitParameterType()
155                 */
156                public SignatureVisitor visitParameterType() {
157                        this.argumentcount++;
158                        this.kind = IReference.REF_PARAMETER;
159                        return this;
160                }
161                /* (non-Javadoc)
162                 * @see org.objectweb.asm.signature.SignatureVisitor#visitInterface()
163                 */
164                public SignatureVisitor visitInterface() {
165                        this.kind = IReference.REF_IMPLEMENTS;
166                        return this;
167                }
168                /* (non-Javadoc)
169                 * @see org.objectweb.asm.signature.SignatureVisitor#visitExceptionType()
170                 */
171                public SignatureVisitor visitExceptionType() {
172                        this.kind = IReference.REF_THROWS;
173                        return this;
174                }
175                /* (non-Javadoc)
176                 * @see org.objectweb.asm.signature.SignatureVisitor#visitArrayType()
177                 */
178                public SignatureVisitor visitArrayType() {
179                        return this;
180                }
181                /* (non-Javadoc)
182                 * @see org.objectweb.asm.signature.SignatureVisitor#visitReturnType()
183                 */
184                public SignatureVisitor visitReturnType() {
185                        this.kind = IReference.REF_RETURNTYPE;
186                        return this;
187                }
188                /* (non-Javadoc)
189                 * @see org.objectweb.asm.signature.SignatureVisitor#visitClassBound()
190                 */
191                public SignatureVisitor visitClassBound() {
192                        this.kind = IReference.REF_PARAMETERIZED_TYPEDECL;
193                        return this;
194                }
195                /* (non-Javadoc)
196                 * @see org.objectweb.asm.signature.SignatureVisitor#visitInterfaceBound()
197                 */
198                public SignatureVisitor visitInterfaceBound() {
199                        this.kind = IReference.REF_PARAMETERIZED_TYPEDECL;
200                        return this;
201                }
202                /* (non-Javadoc)
203                 * @see org.objectweb.asm.signature.SignatureVisitor#visitSuperclass()
204                 */
205                public SignatureVisitor visitSuperclass() {
206                        this.kind = IReference.REF_EXTENDS;
207                        return this;
208                }
209                /* (non-Javadoc)
210                 * @see org.objectweb.asm.signature.SignatureVisitor#visitTypeArgument(char)
211                 */
212                public SignatureVisitor visitTypeArgument(char wildcard) {
213                        return this;
214                }
215                /* (non-Javadoc)
216                 * @see org.objectweb.asm.signature.SignatureVisitor#visitEnd()
217                 */
218                public void visitEnd() {}
219 
220                public void visitBaseType(char descriptor) {
221                        switch(descriptor) {
222                                case 'J' :
223                                case 'D' :
224                                        argumentcount += 2;
225                                        break;
226                                default :
227                                        this.argumentcount++;
228                        }
229                }
230                public void visitTypeArgument() {}
231        }
232 
233        /**
234         * Visitor used to visit the methods of a type
235         * [ visitCode ( visitFrame | visit<i>X</i>Insn | visitLabel | visitTryCatchBlock | visitLocalVariable | visitLineNumber)* visitMaxs ] visitEnd
236         */
237        class ClassFileMethodVisitor extends MethodAdapter {
238                int argumentcount = 0;
239                LinePositionTracker linePositionTracker;
240                /**
241                 * Most recent string literal encountered. Used to infer Class.forName("...") references.
242                 */
243                String stringLiteral;
244                String methodName;
245                int lastLineNumber;
246                boolean implicitConstructor = false;
247                LocalLineNumberMarker localVariableMarker;
248 
249                HashMap labelsToLocalMarkers;
250 
251                /**
252                 * Constructor
253                 * @param mv
254                 */
255                public ClassFileMethodVisitor(MethodVisitor mv, String name, int argumentcount) {
256                        super(mv);
257                        this.argumentcount = argumentcount;
258                        this.linePositionTracker = new LinePositionTracker();
259                        this.lastLineNumber = -1;
260                        this.labelsToLocalMarkers = new HashMap();
261                        this.methodName = name;
262                }
263                /* (non-Javadoc)
264                 * @see org.objectweb.asm.MethodAdapter#visitEnd()
265                 */
266                public void visitEnd() {
267                        this.implicitConstructor = false;
268                        this.argumentcount = 0;
269                        ReferenceExtractor.this.exitMember();
270                        this.linePositionTracker.computeLineNumbers();
271                        this.labelsToLocalMarkers = null;
272                }
273                
274                /* (non-Javadoc)
275                 * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)
276                 */
277                public void visitVarInsn(int opcode, int var) {
278                        switch(opcode) {
279                                case Opcodes.ASTORE :
280                                        if (this.lastLineNumber != -1) {
281                                                this.localVariableMarker = new LocalLineNumberMarker(this.lastLineNumber, var);
282                                        }
283                        }
284                }
285                
286                /* (non-Javadoc)
287                 * @see org.objectweb.asm.MethodAdapter#visitFieldInsn(int, java.lang.String, java.lang.String, java.lang.String)
288                 */
289                public void visitFieldInsn(int opcode, String owner, String name, String desc) {
290                        int refType = -1;
291                        switch (opcode) {
292                        case Opcodes.PUTSTATIC:
293                                refType = IReference.REF_PUTSTATIC;
294                                break;
295                        case Opcodes.PUTFIELD:
296                                refType = IReference.REF_PUTFIELD;
297                                break;
298                        case Opcodes.GETSTATIC:
299                                refType = IReference.REF_GETSTATIC;
300                                break;
301                        case Opcodes.GETFIELD:
302                                refType = IReference.REF_GETFIELD;
303                                break;
304                        }
305                        if (refType != -1) {
306                                Reference reference = ReferenceExtractor.this.addFieldReference(Type.getObjectType(owner), name, refType);
307                                if (reference != null) {
308                                        this.linePositionTracker.addLocation(reference);
309                                }
310                        }
311                }
312 
313                /* (non-Javadoc)
314                 * @see org.objectweb.asm.MethodAdapter#visitTryCatchBlock(org.objectweb.asm.Label, org.objectweb.asm.Label, org.objectweb.asm.Label, java.lang.String)
315                 */
316                public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
317                        if(type != null) {
318                                Type ctype = Type.getObjectType(type);
319                                Reference reference = ReferenceExtractor.this.addTypeReference(ctype, IReference.REF_CATCHEXCEPTION);
320                                if (reference != null) {
321                                        this.linePositionTracker.addCatchLabelInfos(reference, handler);
322                                        this.linePositionTracker.addLocation(reference);
323                                }
324                        }
325                }
326 
327                /* (non-Javadoc)
328                 * @see org.objectweb.asm.MethodAdapter#visitLabel(Label)
329                 */
330                public void visitLabel(Label label) {
331                        this.linePositionTracker.addLabel(label);
332                        if (this.localVariableMarker != null) {
333                                Object object = this.labelsToLocalMarkers.get(label);
334                                if (object != null) {
335                                        // add in the list
336                                        if (object instanceof List) {
337                                                ((List) object).add(this.localVariableMarker);
338                                        } else {
339                                                List list = new ArrayList();
340                                                list.add(object);
341                                                list.add(this.localVariableMarker);
342                                                this.labelsToLocalMarkers.put(label, list);
343                                        }
344                                } else {
345                                        this.labelsToLocalMarkers.put(label, this.localVariableMarker);
346                                }
347                                this.localVariableMarker = null;
348                        }
349                }
350 
351                /* (non-Javadoc)
352                 * @see org.objectweb.asm.MethodAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)
353                 */
354                public void visitMethodInsn(int opcode, String owner, String name, String desc) {
355                        Type declaringType = Type.getObjectType(owner);
356                        int kind = -1;
357                        switch(opcode){
358                                case Opcodes.INVOKESPECIAL: {
359                                        kind = ("<init>".equals(name) ? IReference.REF_CONSTRUCTORMETHOD : IReference.REF_SPECIALMETHOD); //$NON-NLS-1$
360                                        if (kind == IReference.REF_CONSTRUCTORMETHOD) {
361                                                if(!implicitConstructor && this.methodName.equals("<init>") && !fSuperStack.isEmpty() && (fSuperStack.peek()).equals(declaringType.getClassName())) { //$NON-NLS-1$
362                                                        implicitConstructor = true;
363                                                        kind = IReference.REF_SUPER_CONSTRUCTORMETHOD;
364                                                }
365                                                else {
366                                                        Reference reference = ReferenceExtractor.this.addTypeReference(declaringType, IReference.REF_INSTANTIATE);
367                                                        if (reference != null) {
368                                                                this.linePositionTracker.addLocation(reference);
369                                                        }
370                                                }
371                                        }
372                                        break;
373                                }
374                                case Opcodes.INVOKESTATIC: {
375                                        kind = IReference.REF_STATICMETHOD;
376                                        // check for reference to a class literal
377                                        if (name.equals("forName")) { //$NON-NLS-1$
378                                                if (ReferenceExtractor.this.processName(owner).equals("java.lang.Class")) { //$NON-NLS-1$
379                                                        if (this.stringLiteral != null) {
380                                                                Type classLiteral = Type.getObjectType(this.stringLiteral);
381                                                                Reference reference = ReferenceExtractor.this.addTypeReference(classLiteral, IReference.REF_CONSTANTPOOL);
382                                                                if (reference != null) {
383                                                                        this.linePositionTracker.addLocation(reference);
384                                                                }
385                                                        }
386                                                }
387                                        }
388                                        break;
389                                }
390                                case Opcodes.INVOKEVIRTUAL: {
391                                        kind = IReference.REF_VIRTUALMETHOD;
392                                        break;
393                                }
394                                case Opcodes.INVOKEINTERFACE: {
395                                        kind = IReference.REF_INTERFACEMETHOD;
396                                        break;
397                                }
398                        }
399                        if(kind != -1) {
400                                Reference reference = ReferenceExtractor.this.addMethodReference(declaringType, name, desc, kind);
401                                if (reference != null) {
402                                        this.linePositionTracker.addLocation(reference);
403                                }
404                        }
405                        this.stringLiteral = null;
406                }
407 
408                /* (non-Javadoc)
409                 * @see org.objectweb.asm.MethodAdapter#visitMultiANewArrayInsn(java.lang.String, int)
410                 */
411                public void visitMultiANewArrayInsn(String desc, int dims) {
412                        Type type = this.getTypeFromDescription(desc);
413                        Reference reference = ReferenceExtractor.this.addTypeReference(type, IReference.REF_ARRAYALLOC);
414                        if (reference != null) {
415                                this.linePositionTracker.addLocation(reference);
416                        }
417                }
418 
419                /* (non-Javadoc)
420                 * @see org.objectweb.asm.MethodAdapter#visitLineNumber(int, org.objectweb.asm.Label)
421                 */
422                public void visitLineNumber(int line, Label start) {
423                        this.lastLineNumber = line;
424                        this.linePositionTracker.addLineInfo(line, start);
425                }
426                
427                public void visitCode() {
428                        super.visitCode();
429                }
430 
431                /* (non-Javadoc)
432                 * @see java.lang.Object#toString()
433                 */
434                public String toString() {
435                        StringBuffer buffer = new StringBuffer();
436                        buffer.append("Method visitor for: "); //$NON-NLS-1$
437                        buffer.append(methodName);
438                        buffer.append("\nCurrent line number: "); //$NON-NLS-1$
439                        buffer.append(lastLineNumber);
440                        return buffer.toString();
441                }
442                
443                /**
444                 * Creates a type from a type description. Works around bugs creating
445                 * types from array type signatures in ASM.
446                 *
447                 * @param desc signature
448                 * @return Type
449                 */
450                private Type getTypeFromDescription(String desc) {
451                        String ldesc = desc;
452                        while (ldesc.charAt(0) == '[') {
453                                ldesc = ldesc.substring(1);
454                        }
455                        Type type = null;
456                        if (ldesc.endsWith(";")) { //$NON-NLS-1$
457                                type = Type.getType(ldesc);
458                        } else {
459                                type = Type.getObjectType(ldesc);
460                        }
461                        return type;
462                }
463                /* (non-Javadoc)
464                 * @see org.objectweb.asm.MethodAdapter#visitTypeInsn(int, java.lang.String)
465                 */
466                public void visitTypeInsn(int opcode, String desc) {
467                        Type type = this.getTypeFromDescription(desc);
468                        int kind = -1;
469                        switch(opcode) {
470                                case Opcodes.ANEWARRAY: {
471                                        kind = IReference.REF_ARRAYALLOC;
472                                        break;
473                                }
474                                case Opcodes.CHECKCAST: {
475                                        kind = IReference.REF_CHECKCAST;
476                                        break;
477                                }
478                                case Opcodes.INSTANCEOF: {
479                                        kind = IReference.REF_INSTANCEOF;
480                                        break;
481                                }
482                                case Opcodes.NEW: {
483                                        //we can omit the NEW case as it is caught by the constructor call
484                                        //handle it only for anonymous / local types
485                                        Reference ref = (Reference) fAnonymousTypes.get(processName(type.getInternalName()));
486                                        if(ref != null) {
487                                                this.linePositionTracker.addLocation(ref);
488                                        }
489                                }
490                        }
491                        if(kind != -1) {
492                                Reference reference = ReferenceExtractor.this.addTypeReference(type, kind);
493                                if (reference != null) {
494                                        this.linePositionTracker.addLocation(reference);
495                                }
496                        }
497                }
498 
499                /* (non-Javadoc)
500                 * @see org.objectweb.asm.MethodAdapter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)
501                 */
502                public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
503                        if (desc.length() == 1) {
504                                // base type
505                                return;
506                        }
507                        if(index > this.argumentcount) {
508                                Object object = this.labelsToLocalMarkers.get(start);
509                                int lineNumber = -1;
510                                if (object != null) {
511                                        if (object instanceof List) {
512                                                // list of potential localMarker
513                                                // iterate the list to find the one that matches the index
514                                                List markersList = (List) object;
515                                                LocalLineNumberMarker removeMarker = null;
516                                                loop: for(Iterator iterator = markersList.iterator(); iterator.hasNext(); ) {
517                                                        LocalLineNumberMarker marker = (LocalLineNumberMarker) iterator.next();
518                                                        if (marker.varIndex == index) {
519                                                                lineNumber = marker.lineNumber;
520                                                                removeMarker = marker;
521                                                                break loop;
522                                                        }
523                                                }
524                                                if (removeMarker != null) {
525                                                        markersList.remove(removeMarker);
526                                                        if (markersList.isEmpty()) {
527                                                                this.labelsToLocalMarkers.remove(start);
528                                                        }
529                                                }
530                                        } else {
531                                                // single marker
532                                                LocalLineNumberMarker marker = (LocalLineNumberMarker) object;
533                                                if (marker.varIndex == index) {
534                                                        lineNumber = marker.lineNumber;
535                                                        this.labelsToLocalMarkers.remove(start);
536                                                }
537                                        }
538                                }
539                                if (lineNumber == -1) return;
540                                if(signature != null) {
541                                        List references = ReferenceExtractor.this.processSignature(name, signature, IReference.REF_PARAMETERIZED_VARIABLE, METHOD);
542                                        for (Iterator iterator = references.iterator(); iterator.hasNext();) {
543                                                Reference reference = (Reference) iterator.next();
544                                                reference.setLineNumber(lineNumber);
545                                        }
546                                } else {
547                                        Type type = Type.getType(desc);
548                                        if(type.getSort() == Type.OBJECT) {
549                                                Reference reference = ReferenceExtractor.this.addTypeReference(type, IReference.REF_LOCALVARIABLEDECL);
550                                                if (reference != null) {
551                                                        reference.setLineNumber(lineNumber);
552                                                }
553                                        }
554                                }
555                        }
556                }
557 
558                /* (non-Javadoc)
559                 * @see org.objectweb.asm.MethodAdapter#visitLdcInsn(java.lang.Object)
560                 */
561                public void visitLdcInsn(Object cst) {
562                        if(cst instanceof Type) {
563                                Type type = (Type) cst;
564                                Reference reference = ReferenceExtractor.this.addTypeReference(type, IReference.REF_CONSTANTPOOL);
565                                if (reference != null) {
566                                        this.linePositionTracker.addLocation(reference);
567                                }
568                        } else if (cst instanceof String) {
569                                String str = (String) cst;
570                                this.stringLiteral = (Util.EMPTY_STRING.equals(str) ? null : str);
571                        }
572                }
573                
574                
575        }
576 
577        static class LinePositionTracker {
578                List labelsAndLocations;
579                SortedSet lineInfos;
580                List catchLabelInfos;
581                HashMap lineMap;
582 
583                public LinePositionTracker() {
584                        this.labelsAndLocations = new ArrayList();
585                        this.lineInfos = new TreeSet();
586                        this.catchLabelInfos = new ArrayList();
587                        this.lineMap = new HashMap();
588                }
589 
590                void addLocation(Reference location) {
591                        this.labelsAndLocations.add(location);
592                }
593 
594                void addLineInfo(int line, Label label) {
595                        this.lineInfos.add(new LineInfo(line, label));
596                        this.lineMap.put(label, new Integer(line));
597                }
598 
599                void addCatchLabelInfos(Reference location, Label label) {
600                        this.catchLabelInfos.add(new LabelInfo(location, label));
601                }
602 
603                void addLabel(Label label) {
604                        this.labelsAndLocations.add(label);
605                }
606                
607                public void computeLineNumbers() {
608 
609                        if (this.lineInfos.size() < 1 || this.labelsAndLocations.size() < 1) {
610                                // nothing to do
611                                return;
612                        }
613                        Iterator lineInfosIterator = this.lineInfos.iterator();
614                        LineInfo firstLineInfo = (LineInfo) lineInfosIterator.next();
615                        int currentLineNumber = firstLineInfo.line;
616 
617                        List remainingCatchLabelInfos = new ArrayList();
618                        for (Iterator iterator = this.catchLabelInfos.iterator(); iterator.hasNext();) {
619                                LabelInfo catchLabelInfo = (LabelInfo) iterator.next();
620                                Integer lineValue = (Integer) this.lineMap.get(catchLabelInfo.label);
621                                if (lineValue != null) {
622                                        catchLabelInfo.location.setLineNumber(lineValue.intValue());
623                                } else {
624                                        remainingCatchLabelInfos.add(catchLabelInfo);
625                                }
626                        }
627                        // Iterate over List of Labels and SourceLocations.
628                        List computedEntries = new ArrayList();
629                        for (Iterator iterator = this.labelsAndLocations.iterator(); iterator.hasNext();) {
630                                Object current = iterator.next();
631                                if (current instanceof Label) {
632                                        // label
633                                        Integer lineValue = (Integer) this.lineMap.get(current);
634                                        if (lineValue != null) {
635                                                computedEntries.add(new LineInfo(lineValue.intValue(), (Label) current));
636                                        } else {
637                                                computedEntries.add(current);
638                                        }
639                                } else {
640                                        // location
641                                        computedEntries.add(current);
642                                }
643                        }
644                        List remaingEntriesTemp;
645                        for (Iterator iterator = computedEntries.iterator(); iterator.hasNext();) {
646                                Object current = iterator.next();
647                                if (current instanceof Label) {
648                                        // try to set the line number for remaining catch labels
649                                        if (remainingCatchLabelInfos != null) {
650                                                remaingEntriesTemp = new ArrayList();
651                                                loop: for (Iterator catchLabelInfosIterator = remainingCatchLabelInfos.iterator(); catchLabelInfosIterator.hasNext();) {
652                                                        LabelInfo catchLabelInfo = (LabelInfo) catchLabelInfosIterator.next();
653                                                        if (!current.equals(catchLabelInfo.label)) {
654                                                                remaingEntriesTemp.add(catchLabelInfo);
655                                                                continue loop;
656                                                        }
657                                                        catchLabelInfo.location.setLineNumber(currentLineNumber);
658                                                }
659                                                if (remaingEntriesTemp.size() == 0) {
660                                                        remainingCatchLabelInfos = null;
661                                                } else {
662                                                        remainingCatchLabelInfos = remaingEntriesTemp;
663                                                }
664                                        }
665                                } else if (current instanceof Reference) {
666                                        Reference ref = (Reference) current;
667                                        if (ref.getLineNumber() == -1) {
668                                                ref.setLineNumber(currentLineNumber);
669                                        } else {
670                                                currentLineNumber = ref.getLineNumber();
671                                        }
672                                } else if (current instanceof LineInfo) {
673                                        LineInfo lineInfo = (LineInfo) current;
674                                        currentLineNumber = lineInfo.line;
675                                }
676                        }
677                }
678        }
679 
680        static class LabelInfo {
681                public Reference location;
682                public Label label;
683 
684                public LabelInfo(Reference location, Label label) {
685                        this.location = location;
686                        this.label = label;
687                }
688 
689                public String toString() {
690                        StringBuffer buffer = new StringBuffer();
691                        buffer.append('(').append(this.label).append(',').append(this.location).append(')');
692                        return String.valueOf(buffer);
693                }
694        }
695 
696        static class LineInfo implements Comparable {
697                int line;
698                Label label;
699 
700                LineInfo(int line, Label label) {
701                        this.line = line;
702                        this.label = label;
703                }
704 
705                /* (non-Javadoc)
706                 * @see java.lang.Comparable#compareTo(java.lang.Object)
707                 */
708                public int compareTo(Object o) {
709                        return this.line - ((LineInfo) o).line;
710                }
711                public boolean equals(Object obj) {
712                        if (obj instanceof LineInfo) {
713                                LineInfo lineInfo2 = (LineInfo) obj;
714                                return this.line == lineInfo2.line
715                                                && this.label.equals(lineInfo2.label);
716                        }
717                        return super.equals(obj);
718                }
719                public String toString() {
720                        StringBuffer buffer = new StringBuffer();
721                        buffer.append('(').append(this.line).append(',').append(this.label).append(')');
722                        return String.valueOf(buffer);
723                }
724        }
725 
726        static class LocalLineNumberMarker {
727                int lineNumber;
728                int varIndex;
729                
730                public LocalLineNumberMarker(int line, int varIndex) {
731                        this.lineNumber = line;
732                        this.varIndex = varIndex;
733                }
734                public boolean equals(Object obj) {
735                        if (obj instanceof LocalLineNumberMarker) {
736                                LocalLineNumberMarker marker = (LocalLineNumberMarker) obj;
737                                return this.lineNumber == marker.lineNumber && this.varIndex == marker.varIndex;
738                        }
739                        return false;
740                }
741 
742                public int hashCode() {
743                        return this.varIndex;
744                }
745        }
746 
747        /**
748         * The list we collect references in. Entries in the list are
749         * of the type {@link org.eclipse.pde.api.tools.internal.provisional.builder.IReference}
750         */
751        private Set collector = null;
752        
753        /**
754         * The full internal name of the class we are extracting references from
755         */
756        private String classname = null;
757 
758        /**
759         * Current type being visited.
760         */
761        private IApiType fType;
762 
763        /**
764         * Stack of members being visited. When a member is entered its
765         * element descriptor is pushed onto the stack. When a member
766         * is exited, the stack is popped.
767         */
768        Stack fMemberStack = new Stack();
769 
770        /**
771         * Stack of super types *names* (String) being visited. When a type is
772         * entered, its super type is pushed onto the stack. When a type
773         * is exited, the stack is popped.
774         */
775        Stack fSuperStack = new Stack();
776        
777        /**
778         * Mapping of anonymous type names to their reference
779         */
780        HashMap fAnonymousTypes = new HashMap();
781 
782        /**
783         * Whether to extract references to elements within the classfile
784         * being scanned.
785         */
786        private boolean fIncludeLocalRefs = false;
787        
788        /**
789         * Bit mask of {@link ReferenceModifiers} to extract.
790         */
791        private int fReferenceKinds = 0;
792 
793        /**
794         * Bit mask that determines if we need to visit members
795         */
796        private static final int VISIT_MEMBERS_MASK = 
797                IReference.MASK_REF_ALL ^
798                        (IReference.REF_EXTENDS | IReference.REF_IMPLEMENTS);
799        
800        /**
801         * If members should be visited for type visits
802         */
803        private boolean fIsVisitMembers = false;
804        
805        /**
806         * Current field being visited, or <code>null</code> (when
807         * not within a field).
808         */
809        private ClassFileSignatureVisitor signaturevisitor = new ClassFileSignatureVisitor();
810        static int TYPE = 0, FIELD = 1, METHOD = 2;
811 
812        /**
813         * Constructor
814         * @param type the type to extract references from
815         * @param collector the listing of references to annotate from this pass
816         * @param referenceKinds kinds of references to extract as defined by {@link ReferenceModifiers}
817         */
818        public ReferenceExtractor(IApiType type, Set collector, int referenceKinds) {
819                super(new ClassNode());
820                fType = type;
821                this.collector = collector;
822                fReferenceKinds = referenceKinds;
823                fIsVisitMembers = (VISIT_MEMBERS_MASK & fReferenceKinds) > 0; 
824        }
825 
826        /* (non-Javadoc)
827         * @see java.lang.Object#toString()
828         */
829        public String toString() {
830                StringBuffer buffer = new StringBuffer();
831                buffer.append("Reference extractor for: "); //$NON-NLS-1$
832                buffer.append(fType.getName());
833                buffer.append("\n"); //$NON-NLS-1$
834                buffer.append("Reference kinds: "); //$NON-NLS-1$
835                buffer.append(Reference.getReferenceText(fReferenceKinds));
836                buffer.append("\n"); //$NON-NLS-1$
837                buffer.append("Is visiting members: "); //$NON-NLS-1$
838                buffer.append(fIsVisitMembers);
839                return buffer.toString();
840        }
841        
842        /**
843         * Returns whether to consider a reference to the specified type.
844         * Configured by setting to include references within the same
845         * class file.
846         *
847         * @param owner
848         * @return true if considered, false otherwise
849         */
850        protected boolean consider(String owner) {
851                if (this.fIncludeLocalRefs) {
852                        return true;
853                }
854                return !(this.classname.equals(owner) || this.classname.startsWith(owner) || "<clinit>".equals(owner) || "this".equals(owner)); //$NON-NLS-1$ //$NON-NLS-2$
855        }
856 
857        /**
858         * Returns whether the specified reference should be
859         * considered when extracting references. Configured by setting on whether
860         * to include references within the same class file.
861         *
862         * @param ref reference
863         * @return whether to include the reference
864         */
865        protected boolean consider(Reference ref) {
866                if ((ref.getReferenceKind() & fReferenceKinds) == 0) {
867                        return false;
868                }
869                if (this.fIncludeLocalRefs) {
870                        return true;
871                }
872                // don't consider references to anonymous types or elements in them
873                String referencedTypeName = ref.getReferencedTypeName();
874                if (ref.getReferenceKind() == IReference.REF_VIRTUALMETHOD || ref.getReferenceKind() == IReference.REF_OVERRIDE) {
875                        return true;
876                }
877                if (referencedTypeName.startsWith(fType.getName())) {
878                        // don't include references within this type or a member type
879                        if (referencedTypeName.length() > fType.getName().length()) {
880                                return referencedTypeName.charAt(fType.getName().length()) != '$';
881                        }
882                        return false;
883                }
884                return true;
885        }
886 
887        /**
888         * Returns the full internal name (if available) from the given simple name.
889         * The returned name has been modified to be '.' separated
890         * @param name
891         * @return
892         */
893        protected String processName(String name) {
894                String newname = name;
895                Type type = Type.getObjectType(name);
896                if(type != null && type.getSort() == Type.OBJECT) {
897                        newname = type.getInternalName();
898                }
899                return newname.replaceAll("/", "."); //$NON-NLS-1$ //$NON-NLS-2$
900        }
901 
902        /**
903         * Adds a reference to the given type from the current member. Discards
904         * the reference if the type corresponds to the class file being scanned
905         * or if the type is a primitive type.
906         *
907         * @param type referenced type
908         * @param linenumber line number where referenced
909         * @param kind kind of reference
910         * @return reference added, or <code>null</code> if none
911         */
912        protected Reference addTypeReference(Type type, int kind) {
913                Type rtype = this.resolveType(type.getDescriptor());
914                if(rtype != null) {
915                        return addReference(
916                                Reference.typeReference(getMember(), rtype.getClassName(), kind));
917                }
918                return null;
919        }
920 
921        /**
922         * Adds a reference to the given field from the current member. Discards
923         * the reference if the field is defined in the class file being scanned.
924         *
925         * @param declaringType type declaring the field being referenced
926         * @param name of the field being referenced
927         * @param linenumber line number where referenced
928         * @param kind kind of reference
929         * @return reference added, or <code>null</code> if none
930         */
931        protected Reference addFieldReference(Type declaringType, String name, int kind) {
932                Type rtype = this.resolveType(declaringType.getDescriptor());
933                if(rtype != null) {
934                        return addReference(
935                                Reference.fieldReference(getMember(), rtype.getClassName(), name, kind));
936                }
937                return null;
938        }
939 
940        /**
941         * Adds a reference to the given method from the current member. Discards
942         * the reference if the method is defined in the class file being scanned.
943         *
944         * @param declaringType type declaring the method (but could be a virtual lookup)
945         * @param name of the method being referenced
946         * @param signature signature of the method
947         * @param linenumber line number where referenced
948         * @param kind kind of reference
949         * @return reference added, or <code>null</code> if none
950         */
951        protected Reference addMethodReference(Type declaringType, String name, String signature, int kind) {
952                Type rtype = this.resolveType(declaringType.getDescriptor());
953                if(rtype != null) {
954                        return this.addReference(
955                                        Reference.methodReference(getMember(), rtype.getClassName(), name, signature, kind));
956                }
957                return null;
958        }
959 
960        /**
961         * Adds a reference to the given target member from the given line number
962         * in the class file being scanned. If the target member is contained
963         * in the class file being scanned it is discarded based on the
964         * setting to include local references.
965         *
966         * @param target reference
967         * @param reference added, or <code>null</code> if none
968         */
969        protected Reference addReference(Reference target) {
970                if(this.consider(target)) {
971                        this.collector.add(target);
972                        return target;
973                }
974                return null;
975        }
976 
977        /**
978         * Processes the member signature from the specified type with the given signature and kind.
979         * A member can be either a type, method, field or local variable
980         *
981         * @param name the name of the member to process
982         * @param signature the signature of the member to process
983         * @param kind the kind
984         * @param type the type of member wanting to use the visitor
985         *
986         * @return the collection of references created for this signature
987         */
988        protected List processSignature(String name, String signature, int kind, int type) {
989                SignatureReader reader = new SignatureReader(signature);
990                this.signaturevisitor.kind = kind;
991                this.signaturevisitor.name = this.processName(name);
992                this.signaturevisitor.signature = signature;
993                this.signaturevisitor.originalkind = kind;
994                this.signaturevisitor.argumentcount = 0;
995                this.signaturevisitor.type = type;
996                if(kind == IReference.REF_PARAMETERIZED_TYPEDECL || kind == IReference.REF_PARAMETERIZED_METHODDECL) {
997                        reader.accept(this.signaturevisitor);
998                } else {
999                        reader.acceptType(this.signaturevisitor);
1000                }
1001                List result = new ArrayList();
1002                result.addAll(this.signaturevisitor.references);
1003                this.collector.addAll(this.signaturevisitor.references);
1004                this.signaturevisitor.reset();
1005                return result;
1006        }
1007 
1008        /**
1009         * Resolves the type from the string description. This method takes only type descriptions
1010         * as a parameter, all else will throw an exception from the ASM framework
1011         * If the description is an array, the underlying type of the array is returned.
1012         * @param desc
1013         * @return the {@link Type} of the description or <code>null</code>
1014         */
1015        protected Type resolveType(String desc) {
1016                Type type = Type.getType(desc);
1017                if(type.getSort() == Type.OBJECT) {
1018                        return type;
1019                }
1020                if(type.getSort() == Type.ARRAY) {
1021                        type = type.getElementType();
1022                        if(type.getSort() == Type.OBJECT) {
1023                                return type;
1024                        }
1025                }
1026                return null;
1027        }
1028 
1029        /* (non-Javadoc)
1030         * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
1031         */
1032        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
1033                this.classname = this.processName(name);
1034                if(DEBUG) {
1035                        System.out.println("Starting visit of type: ["+this.fType.getName()+"]"); //$NON-NLS-1$ //$NON-NLS-2$
1036                }
1037                this.enterMember(this.fType);
1038                //if there is a signature we get more information from it, so we don't need to do both
1039                if(signature != null) {
1040                        this.processSignature(name, signature, IReference.REF_PARAMETERIZED_TYPEDECL, TYPE);
1041                }
1042                else {
1043                        if((access & Opcodes.ACC_INTERFACE) != 0) {
1044                                //the type is an interface and we need to treat the interfaces set as extends, not implements
1045                                Type supertype = null;
1046                                for(int i = 0; i < interfaces.length; i++) {
1047                                        supertype = Type.getObjectType(interfaces[i]);
1048                                        this.addTypeReference(supertype, IReference.REF_EXTENDS);
1049                                        this.fSuperStack.add(supertype.getClassName());
1050                                }
1051                        }
1052                        else {
1053                                Type supertype = null;
1054                                if(superName != null) {
1055                                        supertype = Type.getObjectType(superName);
1056                                        this.addTypeReference(supertype, IReference.REF_EXTENDS);
1057                                        this.fSuperStack.add(supertype.getClassName());
1058                                }
1059                                for(int i = 0; i < interfaces.length; i++) {
1060                                        supertype = Type.getObjectType(interfaces[i]);
1061                                        this.addTypeReference(supertype, IReference.REF_IMPLEMENTS);
1062                                }
1063                        }
1064                }
1065        }
1066        
1067        /* (non-Javadoc)
1068         * @see org.objectweb.asm.ClassVisitor#visitEnd()
1069         */
1070        public void visitEnd() {
1071                this.exitMember();
1072                if (!this.fSuperStack.isEmpty()) {
1073                        String typeName = (String) this.fSuperStack.pop();
1074                        if(DEBUG) {
1075                                System.out.println("ending visit of type: ["+typeName+"]"); //$NON-NLS-1$ //$NON-NLS-2$
1076                        }
1077                }
1078        }
1079 
1080        /* (non-Javadoc)
1081         * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
1082         */
1083        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
1084                if (fIsVisitMembers) {
1085                        IApiType owner = (IApiType) this.getMember();
1086                        IApiField field = owner.getField(name);
1087                        if(field == null) {
1088                                ApiPlugin.log(
1089                                                new Status(
1090                                                                IStatus.WARNING, 
1091                                                                ApiPlugin.PLUGIN_ID, 
1092                                                                NLS.bind(BuilderMessages.ReferenceExtractor_failed_to_lookup_field, 
1093                                                                                new String[] {name, Signatures.getQualifiedTypeSignature(owner)})
1094                                                )
1095                                );
1096                                //if we can't find the method there is no point trying to process it
1097                                return null;
1098                        }
1099                        this.enterMember(field);
1100                        if((access & Opcodes.ACC_SYNTHETIC) == 0) {
1101                                if(signature != null) {
1102                                        this.processSignature(name, signature, IReference.REF_PARAMETERIZED_FIELDDECL, FIELD);
1103                                } else {
1104                                        this.addTypeReference(Type.getType(desc), IReference.REF_FIELDDECL);
1105                                }
1106                        }
1107                        this.exitMember();
1108                }
1109                return null;
1110        }
1111 
1112        /* (non-Javadoc)
1113         * @see org.objectweb.asm.ClassAdapter#visitInnerClass(java.lang.String, java.lang.String, java.lang.String, int)
1114         */
1115        public void visitInnerClass(String name, String outerName, String innerName, int access) {
1116                try {
1117                        String pname = processName(name);
1118                        if(fType.getName().equals(pname) || !pname.startsWith(fType.getName())) {
1119                                return;
1120                        }
1121                        IApiComponent comp = fType.getApiComponent();
1122                        if(comp == null) {
1123                                return;
1124                        }
1125                        AbstractApiTypeRoot root = (AbstractApiTypeRoot) comp.findTypeRoot(pname);
1126                        if(root != null) {
1127                                IApiType type = root.getStructure();
1128                                if(type == null) {
1129                                        //do nothing for a bad classfile
1130                                        return;
1131                                }
1132                                Set refs = null;
1133                                if(type.isAnonymous() || type.isLocal()) {
1134                                        //visit the class files for the dependent anonymous and local inner types
1135                                        refs = processInnerClass(type, IReference.REF_EXTENDS);
1136                                        if(refs.iterator().hasNext()) {
1137                                                fAnonymousTypes.put(pname, refs.iterator().next());
1138                                        }
1139                                }
1140                                else {
1141                                        refs = processInnerClass(type, fReferenceKinds);
1142                                }
1143                                if(refs != null && !refs.isEmpty()) {
1144                                        this.collector.addAll(refs);
1145                                }
1146                        }
1147                }
1148                catch(CoreException ce) {}
1149        }
1150        
1151        /**
1152         * Processes the dependent inner class
1153         * @param type
1154         * @param refkinds
1155         * @return
1156         * @throws CoreException
1157         */
1158        private Set processInnerClass(IApiType type, int refkinds) throws CoreException {
1159                HashSet refs = new HashSet();
1160                ReferenceExtractor extractor = new ReferenceExtractor(type, refs, refkinds);
1161                ClassReader reader = new ClassReader(((AbstractApiTypeRoot)type.getTypeRoot()).getContents());
1162                reader.accept(extractor, ClassReader.SKIP_FRAMES);
1163                return refs;
1164        }
1165        
1166        /* (non-Javadoc)
1167         * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
1168         */
1169        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
1170                if (fIsVisitMembers) {
1171                        IApiMember member = this.getMember();
1172                        IApiType owner = null;
1173                        if (member instanceof IApiType) {
1174                                owner = (IApiType) member;
1175                        } else {
1176                                try {
1177                                        owner = member.getEnclosingType();
1178                                } catch (CoreException e) {
1179                                        // should not happen for field or method
1180                                        ApiPlugin.log(e.getStatus());
1181                                }
1182                        }
1183                        IApiMethod method = owner.getMethod(name, desc);
1184                        if(method == null) {
1185                                ApiPlugin.log(
1186                                                new Status(
1187                                                                IStatus.WARNING, 
1188                                                                ApiPlugin.PLUGIN_ID, 
1189                                                                NLS.bind(BuilderMessages.ReferenceExtractor_failed_to_lookup_method, 
1190                                                                                new String[] {name, desc, Signatures.getQualifiedTypeSignature(owner)})
1191                                                )
1192                                );
1193                                //if we can't find the method there is no point trying to process it
1194                                return null;
1195                        }
1196                        this.enterMember(method);
1197                        // record potential method override reference
1198                        if ((access & (Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) > 0) {
1199                                if (!this.fSuperStack.isEmpty()) {
1200                                        String superTypeName = (String) this.fSuperStack.peek();
1201                                        addReference(
1202                                                Reference.methodReference(method, superTypeName, method.getName(), method.getSignature(), IReference.REF_OVERRIDE));
1203                                }
1204                        }
1205                        if((access & Opcodes.ACC_SYNTHETIC) == 0 && !"<clinit>".equals(name)) { //$NON-NLS-1$
1206                                int argumentcount = 0;
1207                                if(signature != null) {
1208                                        this.processSignature(name, signature, IReference.REF_PARAMETERIZED_METHODDECL, METHOD);
1209                                        argumentcount = this.signaturevisitor.argumentcount;
1210                                }
1211                                else {
1212                                        Type[] arguments = Type.getArgumentTypes(desc);
1213                                        for(int i = 0; i < arguments.length; i++) {
1214                                                Type type = arguments[i];
1215                                                this.addTypeReference(type, IReference.REF_PARAMETER);
1216                                                argumentcount += type.getSize();
1217                                        }
1218                                        this.addTypeReference(Type.getReturnType(desc), IReference.REF_RETURNTYPE);
1219                                        if(exceptions != null) {
1220                                                for(int i = 0; i < exceptions.length; i++) {
1221                                                        this.addTypeReference(Type.getObjectType(exceptions[i]), IReference.REF_THROWS);
1222                                                }
1223                                        }
1224                                }
1225                                MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
1226                                if(mv != null && ((access & (Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT)) == 0)) {
1227                                        return new ClassFileMethodVisitor(mv, name, argumentcount);
1228                                }
1229                        }
1230                }
1231                return null;
1232        }
1233 
1234        /**
1235         * Called when a member is entered. Pushes the member onto the member
1236         * stack.
1237         *
1238         * @param member current member
1239         */
1240        protected void enterMember(IApiMember member) {
1241                this.fMemberStack.push(member);
1242        }
1243 
1244        /**
1245         * Called when a member is exited. Pops the top member off the stack.
1246         */
1247        protected void exitMember() {
1248                this.fMemberStack.pop();
1249        }
1250 
1251        /**
1252         * Returns the member currently being visited.
1253         *
1254         * @return current member
1255         */
1256        protected IApiMember getMember() {
1257                return (IApiMember) this.fMemberStack.peek();
1258        }
1259}

[all classes][org.eclipse.pde.api.tools.internal.builder]
EMMA 2.0.5312 EclEmma Fix 1 (C) Vladimir Roubtsov