001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
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: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core.search.indexing;
011:
012: import org.eclipse.jdt.core.Signature;
013: import org.eclipse.jdt.core.compiler.CharOperation;
014: import org.eclipse.jdt.core.search.SearchDocument;
015: import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
016: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
017: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
018: import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
019: import org.eclipse.jdt.internal.compiler.classfmt.FieldInfo;
020: import org.eclipse.jdt.internal.compiler.classfmt.MethodInfo;
021: import org.eclipse.jdt.internal.compiler.env.ClassSignature;
022: import org.eclipse.jdt.internal.compiler.env.EnumConstantSignature;
023: import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
024: import org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair;
025: import org.eclipse.jdt.internal.compiler.lookup.TagBits;
026: import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
027: import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
028: import org.eclipse.jdt.internal.core.util.Util;
029:
030: public class BinaryIndexer extends AbstractIndexer implements
031: SuffixConstants {
032: private static final char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
033: private static final char[] CHAR = "char".toCharArray(); //$NON-NLS-1$
034: private static final char[] DOUBLE = "double".toCharArray(); //$NON-NLS-1$
035: private static final char[] FLOAT = "float".toCharArray(); //$NON-NLS-1$
036: private static final char[] INT = "int".toCharArray(); //$NON-NLS-1$
037: private static final char[] LONG = "long".toCharArray(); //$NON-NLS-1$
038: private static final char[] SHORT = "short".toCharArray(); //$NON-NLS-1$
039: private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$
040: private static final char[] VOID = "void".toCharArray(); //$NON-NLS-1$
041: private static final char[] INIT = "<init>".toCharArray(); //$NON-NLS-1$
042:
043: public BinaryIndexer(SearchDocument document) {
044: super (document);
045: }
046:
047: private void addBinaryStandardAnnotations(long annotationTagBits) {
048: if ((annotationTagBits & TagBits.AnnotationTargetMASK) != 0) {
049: char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_TARGET;
050: addTypeReference(compoundName[compoundName.length - 1]);
051: addBinaryTargetAnnotation(annotationTagBits);
052: }
053: if ((annotationTagBits & TagBits.AnnotationRetentionMASK) != 0) {
054: char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_RETENTION;
055: addTypeReference(compoundName[compoundName.length - 1]);
056: addBinaryRetentionAnnotation(annotationTagBits);
057: }
058: if ((annotationTagBits & TagBits.AnnotationDeprecated) != 0) {
059: char[][] compoundName = TypeConstants.JAVA_LANG_DEPRECATED;
060: addTypeReference(compoundName[compoundName.length - 1]);
061: }
062: if ((annotationTagBits & TagBits.AnnotationDocumented) != 0) {
063: char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_DOCUMENTED;
064: addTypeReference(compoundName[compoundName.length - 1]);
065: }
066: if ((annotationTagBits & TagBits.AnnotationInherited) != 0) {
067: char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_INHERITED;
068: addTypeReference(compoundName[compoundName.length - 1]);
069: }
070: if ((annotationTagBits & TagBits.AnnotationOverride) != 0) {
071: char[][] compoundName = TypeConstants.JAVA_LANG_OVERRIDE;
072: addTypeReference(compoundName[compoundName.length - 1]);
073: }
074: if ((annotationTagBits & TagBits.AnnotationSuppressWarnings) != 0) {
075: char[][] compoundName = TypeConstants.JAVA_LANG_SUPPRESSWARNINGS;
076: addTypeReference(compoundName[compoundName.length - 1]);
077: }
078: }
079:
080: private void addBinaryTargetAnnotation(long bits) {
081: char[][] compoundName = null;
082: if ((bits & TagBits.AnnotationForAnnotationType) != 0) {
083: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
084: addTypeReference(compoundName[compoundName.length - 1]);
085: addFieldReference(TypeConstants.UPPER_ANNOTATION_TYPE);
086: }
087: if ((bits & TagBits.AnnotationForConstructor) != 0) {
088: if (compoundName == null) {
089: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
090: addTypeReference(compoundName[compoundName.length - 1]);
091: }
092: addFieldReference(TypeConstants.UPPER_CONSTRUCTOR);
093: }
094: if ((bits & TagBits.AnnotationForField) != 0) {
095: if (compoundName == null) {
096: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
097: addTypeReference(compoundName[compoundName.length - 1]);
098: }
099: addFieldReference(TypeConstants.UPPER_FIELD);
100: }
101: if ((bits & TagBits.AnnotationForLocalVariable) != 0) {
102: if (compoundName == null) {
103: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
104: addTypeReference(compoundName[compoundName.length - 1]);
105: }
106: addFieldReference(TypeConstants.UPPER_LOCAL_VARIABLE);
107: }
108: if ((bits & TagBits.AnnotationForMethod) != 0) {
109: if (compoundName == null) {
110: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
111: addTypeReference(compoundName[compoundName.length - 1]);
112: }
113: addFieldReference(TypeConstants.UPPER_METHOD);
114: }
115: if ((bits & TagBits.AnnotationForPackage) != 0) {
116: if (compoundName == null) {
117: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
118: addTypeReference(compoundName[compoundName.length - 1]);
119: }
120: addFieldReference(TypeConstants.UPPER_PACKAGE);
121: }
122: if ((bits & TagBits.AnnotationForParameter) != 0) {
123: if (compoundName == null) {
124: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
125: addTypeReference(compoundName[compoundName.length - 1]);
126: }
127: addFieldReference(TypeConstants.UPPER_PARAMETER);
128: }
129: if ((bits & TagBits.AnnotationForType) != 0) {
130: if (compoundName == null) {
131: compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
132: addTypeReference(compoundName[compoundName.length - 1]);
133: }
134: addFieldReference(TypeConstants.TYPE);
135: }
136: }
137:
138: private void addBinaryRetentionAnnotation(long bits) {
139: char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_RETENTIONPOLICY;
140: addTypeReference(compoundName[compoundName.length - 1]);
141: if ((bits & TagBits.AnnotationRuntimeRetention) != 0) {
142: addFieldReference(TypeConstants.UPPER_RUNTIME);
143: } else if ((bits & TagBits.AnnotationClassRetention) != 0) {
144: addFieldReference(TypeConstants.UPPER_CLASS);
145: } else if ((bits & TagBits.AnnotationSourceRetention) != 0) {
146: addFieldReference(TypeConstants.UPPER_SOURCE);
147: }
148: }
149:
150: private void addBinaryAnnotation(IBinaryAnnotation annotation) {
151: addTypeReference(replace('/', '.', Signature
152: .toCharArray(annotation.getTypeName())));
153: IBinaryElementValuePair[] valuePairs = annotation
154: .getElementValuePairs();
155: if (valuePairs != null) {
156: for (int j = 0, vpLength = valuePairs.length; j < vpLength; j++) {
157: IBinaryElementValuePair valuePair = valuePairs[j];
158: addMethodReference(valuePair.getName(), 0);
159: Object pairValue = valuePair.getValue();
160: addPairValue(pairValue);
161: }
162: }
163: }
164:
165: private void addPairValue(Object pairValue) {
166: if (pairValue instanceof EnumConstantSignature) {
167: EnumConstantSignature enumConstant = (EnumConstantSignature) pairValue;
168: addTypeReference(replace('/', '.', Signature
169: .toCharArray(enumConstant.getTypeName())));
170: addNameReference(enumConstant.getEnumConstantName());
171: } else if (pairValue instanceof ClassSignature) {
172: ClassSignature classConstant = (ClassSignature) pairValue;
173: addTypeReference(replace('/', '.', Signature
174: .toCharArray(classConstant.getTypeName())));
175: } else if (pairValue instanceof IBinaryAnnotation) {
176: addBinaryAnnotation((IBinaryAnnotation) pairValue);
177: } else if (pairValue instanceof Object[]) {
178: Object[] objects = (Object[]) pairValue;
179: for (int i = 0, l = objects.length; i < l; i++) {
180: addPairValue(objects[i]);
181: }
182: }
183: }
184:
185: public void addTypeReference(char[] typeName) {
186: int length = typeName.length;
187: if (length > 2 && typeName[length - 2] == '$') {
188: switch (typeName[length - 1]) {
189: case '0':
190: case '1':
191: case '2':
192: case '3':
193: case '4':
194: case '5':
195: case '6':
196: case '7':
197: case '8':
198: case '9':
199: return; // skip local type names
200: }
201: }
202:
203: // consider that A$B is a member type: so replace '$' with '.'
204: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=40116)
205: typeName = CharOperation.replaceOnCopy(typeName, '$', '.'); // copy it so the original is not modified
206:
207: super .addTypeReference(typeName);
208: }
209:
210: /**
211: * For example:
212: * - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
213: * - void foo(int) is (I)V ==> int
214: */
215: private void convertToArrayType(char[][] parameterTypes,
216: int counter, int arrayDim) {
217: int length = parameterTypes[counter].length;
218: char[] arrayType = new char[length + arrayDim * 2];
219: System.arraycopy(parameterTypes[counter], 0, arrayType, 0,
220: length);
221: for (int i = 0; i < arrayDim; i++) {
222: arrayType[length + (i * 2)] = '[';
223: arrayType[length + (i * 2) + 1] = ']';
224: }
225: parameterTypes[counter] = arrayType;
226: }
227:
228: /**
229: * For example:
230: * - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
231: * - void foo(int) is (I)V ==> int
232: */
233: private char[] convertToArrayType(char[] typeName, int arrayDim) {
234: int length = typeName.length;
235: char[] arrayType = new char[length + arrayDim * 2];
236: System.arraycopy(typeName, 0, arrayType, 0, length);
237: for (int i = 0; i < arrayDim; i++) {
238: arrayType[length + (i * 2)] = '[';
239: arrayType[length + (i * 2) + 1] = ']';
240: }
241: return arrayType;
242: }
243:
244: private char[] decodeFieldType(char[] signature)
245: throws ClassFormatException {
246: if (signature == null)
247: return null;
248: int arrayDim = 0;
249: for (int i = 0, max = signature.length; i < max; i++) {
250: switch (signature[i]) {
251: case 'B':
252: if (arrayDim > 0)
253: return convertToArrayType(BYTE, arrayDim);
254: return BYTE;
255:
256: case 'C':
257: if (arrayDim > 0)
258: return convertToArrayType(CHAR, arrayDim);
259: return CHAR;
260:
261: case 'D':
262: if (arrayDim > 0)
263: return convertToArrayType(DOUBLE, arrayDim);
264: return DOUBLE;
265:
266: case 'F':
267: if (arrayDim > 0)
268: return convertToArrayType(FLOAT, arrayDim);
269: return FLOAT;
270:
271: case 'I':
272: if (arrayDim > 0)
273: return convertToArrayType(INT, arrayDim);
274: return INT;
275:
276: case 'J':
277: if (arrayDim > 0)
278: return convertToArrayType(LONG, arrayDim);
279: return LONG;
280:
281: case 'L':
282: int indexOfSemiColon = CharOperation.indexOf(';',
283: signature, i + 1);
284: if (indexOfSemiColon == -1)
285: throw new ClassFormatException(
286: ClassFormatException.ErrInvalidMethodSignature);
287: if (arrayDim > 0) {
288: return convertToArrayType(replace('/', '.',
289: CharOperation.subarray(signature, i + 1,
290: indexOfSemiColon)), arrayDim);
291: }
292: return replace('/', '.', CharOperation.subarray(
293: signature, i + 1, indexOfSemiColon));
294:
295: case 'S':
296: if (arrayDim > 0)
297: return convertToArrayType(SHORT, arrayDim);
298: return SHORT;
299:
300: case 'Z':
301: if (arrayDim > 0)
302: return convertToArrayType(BOOLEAN, arrayDim);
303: return BOOLEAN;
304:
305: case 'V':
306: return VOID;
307:
308: case '[':
309: arrayDim++;
310: break;
311:
312: default:
313: throw new ClassFormatException(
314: ClassFormatException.ErrInvalidMethodSignature);
315: }
316: }
317: return null;
318: }
319:
320: /**
321: * For example:
322: * - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
323: * - void foo(int) is (I)V ==> int
324: */
325: private char[][] decodeParameterTypes(char[] signature,
326: boolean firstIsSynthetic) throws ClassFormatException {
327: if (signature == null)
328: return null;
329: int indexOfClosingParen = CharOperation.lastIndexOf(')',
330: signature);
331: if (indexOfClosingParen == 1) {
332: // there is no parameter
333: return null;
334: }
335: if (indexOfClosingParen == -1) {
336: throw new ClassFormatException(
337: ClassFormatException.ErrInvalidMethodSignature);
338: }
339: char[][] parameterTypes = new char[3][];
340: int parameterTypesCounter = 0;
341: int arrayDim = 0;
342: for (int i = 1; i < indexOfClosingParen; i++) {
343: if (parameterTypesCounter == parameterTypes.length) {
344: // resize
345: System
346: .arraycopy(
347: parameterTypes,
348: 0,
349: (parameterTypes = new char[parameterTypesCounter * 2][]),
350: 0, parameterTypesCounter);
351: }
352: switch (signature[i]) {
353: case 'B':
354: parameterTypes[parameterTypesCounter++] = BYTE;
355: if (arrayDim > 0)
356: convertToArrayType(parameterTypes,
357: parameterTypesCounter - 1, arrayDim);
358: arrayDim = 0;
359: break;
360:
361: case 'C':
362: parameterTypes[parameterTypesCounter++] = CHAR;
363: if (arrayDim > 0)
364: convertToArrayType(parameterTypes,
365: parameterTypesCounter - 1, arrayDim);
366: arrayDim = 0;
367: break;
368:
369: case 'D':
370: parameterTypes[parameterTypesCounter++] = DOUBLE;
371: if (arrayDim > 0)
372: convertToArrayType(parameterTypes,
373: parameterTypesCounter - 1, arrayDim);
374: arrayDim = 0;
375: break;
376:
377: case 'F':
378: parameterTypes[parameterTypesCounter++] = FLOAT;
379: if (arrayDim > 0)
380: convertToArrayType(parameterTypes,
381: parameterTypesCounter - 1, arrayDim);
382: arrayDim = 0;
383: break;
384:
385: case 'I':
386: parameterTypes[parameterTypesCounter++] = INT;
387: if (arrayDim > 0)
388: convertToArrayType(parameterTypes,
389: parameterTypesCounter - 1, arrayDim);
390: arrayDim = 0;
391: break;
392:
393: case 'J':
394: parameterTypes[parameterTypesCounter++] = LONG;
395: if (arrayDim > 0)
396: convertToArrayType(parameterTypes,
397: parameterTypesCounter - 1, arrayDim);
398: arrayDim = 0;
399: break;
400:
401: case 'L':
402: int indexOfSemiColon = CharOperation.indexOf(';',
403: signature, i + 1);
404: if (indexOfSemiColon == -1)
405: throw new ClassFormatException(
406: ClassFormatException.ErrInvalidMethodSignature);
407: if (firstIsSynthetic && parameterTypesCounter == 0) {
408: // skip first synthetic parameter
409: firstIsSynthetic = false;
410: } else {
411: parameterTypes[parameterTypesCounter++] = replace(
412: '/', '.', CharOperation.subarray(signature,
413: i + 1, indexOfSemiColon));
414: if (arrayDim > 0)
415: convertToArrayType(parameterTypes,
416: parameterTypesCounter - 1, arrayDim);
417: }
418: i = indexOfSemiColon;
419: arrayDim = 0;
420: break;
421:
422: case 'S':
423: parameterTypes[parameterTypesCounter++] = SHORT;
424: if (arrayDim > 0)
425: convertToArrayType(parameterTypes,
426: parameterTypesCounter - 1, arrayDim);
427: arrayDim = 0;
428: break;
429:
430: case 'Z':
431: parameterTypes[parameterTypesCounter++] = BOOLEAN;
432: if (arrayDim > 0)
433: convertToArrayType(parameterTypes,
434: parameterTypesCounter - 1, arrayDim);
435: arrayDim = 0;
436: break;
437:
438: case '[':
439: arrayDim++;
440: break;
441:
442: default:
443: throw new ClassFormatException(
444: ClassFormatException.ErrInvalidMethodSignature);
445: }
446: }
447: if (parameterTypes.length != parameterTypesCounter) {
448: System.arraycopy(parameterTypes, 0,
449: parameterTypes = new char[parameterTypesCounter][],
450: 0, parameterTypesCounter);
451: }
452: return parameterTypes;
453: }
454:
455: private char[] decodeReturnType(char[] signature)
456: throws ClassFormatException {
457: if (signature == null)
458: return null;
459: int indexOfClosingParen = CharOperation.lastIndexOf(')',
460: signature);
461: if (indexOfClosingParen == -1)
462: throw new ClassFormatException(
463: ClassFormatException.ErrInvalidMethodSignature);
464: int arrayDim = 0;
465: for (int i = indexOfClosingParen + 1, max = signature.length; i < max; i++) {
466: switch (signature[i]) {
467: case 'B':
468: if (arrayDim > 0)
469: return convertToArrayType(BYTE, arrayDim);
470: return BYTE;
471:
472: case 'C':
473: if (arrayDim > 0)
474: return convertToArrayType(CHAR, arrayDim);
475: return CHAR;
476:
477: case 'D':
478: if (arrayDim > 0)
479: return convertToArrayType(DOUBLE, arrayDim);
480: return DOUBLE;
481:
482: case 'F':
483: if (arrayDim > 0)
484: return convertToArrayType(FLOAT, arrayDim);
485: return FLOAT;
486:
487: case 'I':
488: if (arrayDim > 0)
489: return convertToArrayType(INT, arrayDim);
490: return INT;
491:
492: case 'J':
493: if (arrayDim > 0)
494: return convertToArrayType(LONG, arrayDim);
495: return LONG;
496:
497: case 'L':
498: int indexOfSemiColon = CharOperation.indexOf(';',
499: signature, i + 1);
500: if (indexOfSemiColon == -1)
501: throw new ClassFormatException(
502: ClassFormatException.ErrInvalidMethodSignature);
503: if (arrayDim > 0) {
504: return convertToArrayType(replace('/', '.',
505: CharOperation.subarray(signature, i + 1,
506: indexOfSemiColon)), arrayDim);
507: }
508: return replace('/', '.', CharOperation.subarray(
509: signature, i + 1, indexOfSemiColon));
510:
511: case 'S':
512: if (arrayDim > 0)
513: return convertToArrayType(SHORT, arrayDim);
514: return SHORT;
515:
516: case 'Z':
517: if (arrayDim > 0)
518: return convertToArrayType(BOOLEAN, arrayDim);
519: return BOOLEAN;
520:
521: case 'V':
522: return VOID;
523:
524: case '[':
525: arrayDim++;
526: break;
527:
528: default:
529: throw new ClassFormatException(
530: ClassFormatException.ErrInvalidMethodSignature);
531: }
532: }
533: return null;
534: }
535:
536: private int extractArgCount(char[] signature, char[] className)
537: throws ClassFormatException {
538: int indexOfClosingParen = CharOperation.lastIndexOf(')',
539: signature);
540: if (indexOfClosingParen == 1) {
541: // there is no parameter
542: return 0;
543: }
544: if (indexOfClosingParen == -1) {
545: throw new ClassFormatException(
546: ClassFormatException.ErrInvalidMethodSignature);
547: }
548: int parameterTypesCounter = 0;
549: for (int i = 1; i < indexOfClosingParen; i++) {
550: switch (signature[i]) {
551: case 'B':
552: case 'C':
553: case 'D':
554: case 'F':
555: case 'I':
556: case 'J':
557: case 'S':
558: case 'Z':
559: parameterTypesCounter++;
560: break;
561: case 'L':
562: int indexOfSemiColon = CharOperation.indexOf(';',
563: signature, i + 1);
564: if (indexOfSemiColon == -1)
565: throw new ClassFormatException(
566: ClassFormatException.ErrInvalidMethodSignature);
567: // verify if first parameter is synthetic
568: if (className != null && parameterTypesCounter == 0) {
569: char[] classSignature = Signature
570: .createCharArrayTypeSignature(className,
571: true);
572: int length = indexOfSemiColon - i + 1;
573: if (classSignature.length > (length + 1)) {
574: // synthetic means that parameter type has same signature than given class
575: for (int j = i, k = 0; j < indexOfSemiColon; j++, k++) {
576: if (!(signature[j] == classSignature[k] || (signature[j] == '/' && classSignature[k] == '.'))) {
577: parameterTypesCounter++;
578: break;
579: }
580: }
581: } else {
582: parameterTypesCounter++;
583: }
584: className = null; // do not verify following parameters
585: } else {
586: parameterTypesCounter++;
587: }
588: i = indexOfSemiColon;
589: break;
590: case '[':
591: break;
592: default:
593: throw new ClassFormatException(
594: ClassFormatException.ErrInvalidMethodSignature);
595: }
596: }
597: return parameterTypesCounter;
598: }
599:
600: private char[] extractClassName(int[] constantPoolOffsets,
601: ClassFileReader reader, int index) {
602: // the entry at i has to be a field ref or a method/interface method ref.
603: int class_index = reader.u2At(constantPoolOffsets[index] + 1);
604: int utf8Offset = constantPoolOffsets[reader
605: .u2At(constantPoolOffsets[class_index] + 1)];
606: return reader.utf8At(utf8Offset + 3, reader
607: .u2At(utf8Offset + 1));
608: }
609:
610: private char[] extractName(int[] constantPoolOffsets,
611: ClassFileReader reader, int index) {
612: int nameAndTypeIndex = reader
613: .u2At(constantPoolOffsets[index] + 3);
614: int utf8Offset = constantPoolOffsets[reader
615: .u2At(constantPoolOffsets[nameAndTypeIndex] + 1)];
616: return reader.utf8At(utf8Offset + 3, reader
617: .u2At(utf8Offset + 1));
618: }
619:
620: private char[] extractClassReference(int[] constantPoolOffsets,
621: ClassFileReader reader, int index) {
622: // the entry at i has to be a class ref.
623: int utf8Offset = constantPoolOffsets[reader
624: .u2At(constantPoolOffsets[index] + 1)];
625: return reader.utf8At(utf8Offset + 3, reader
626: .u2At(utf8Offset + 1));
627: }
628:
629: /**
630: * Extract all type, method, field and interface method references from the constant pool
631: */
632: private void extractReferenceFromConstantPool(byte[] contents,
633: ClassFileReader reader) throws ClassFormatException {
634: int[] constantPoolOffsets = reader.getConstantPoolOffsets();
635: int constantPoolCount = constantPoolOffsets.length;
636: for (int i = 1; i < constantPoolCount; i++) {
637: int tag = reader.u1At(constantPoolOffsets[i]);
638: /**
639: * u1 tag
640: * u2 class_index
641: * u2 name_and_type_index
642: */
643: char[] name = null;
644: char[] type = null;
645: switch (tag) {
646: case ClassFileConstants.FieldRefTag:
647: // add reference to the class/interface and field name and type
648: name = extractName(constantPoolOffsets, reader, i);
649: addFieldReference(name);
650: break;
651: case ClassFileConstants.MethodRefTag:
652: // add reference to the class and method name and type
653: case ClassFileConstants.InterfaceMethodRefTag:
654: // add reference to the interface and method name and type
655: name = extractName(constantPoolOffsets, reader, i);
656: type = extractType(constantPoolOffsets, reader, i);
657: if (CharOperation.equals(INIT, name)) {
658: // get class name and see if it's a local type or not
659: char[] className = extractClassName(
660: constantPoolOffsets, reader, i);
661: boolean localType = false;
662: if (className != null) {
663: for (int c = 0, max = className.length; c < max; c++) {
664: switch (className[c]) {
665: case '/':
666: className[c] = '.';
667: break;
668: case '$':
669: localType = true;
670: break;
671: }
672: }
673: }
674: // add a constructor reference, use class name to extract arg count if it's a local type to remove synthetic parameter
675: addConstructorReference(className, extractArgCount(
676: type, localType ? className : null));
677: } else {
678: // add a method reference
679: addMethodReference(name,
680: extractArgCount(type, null));
681: }
682: break;
683: case ClassFileConstants.ClassTag:
684: // add a type reference
685: name = extractClassReference(constantPoolOffsets,
686: reader, i);
687: if (name.length > 0 && name[0] == '[')
688: break; // skip over array references
689: name = replace('/', '.', name); // so that it looks like java.lang.String
690: addTypeReference(name);
691:
692: // also add a simple reference on each segment of the qualification (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=24741)
693: char[][] qualification = CharOperation.splitOn('.',
694: name);
695: for (int j = 0, length = qualification.length; j < length; j++) {
696: addNameReference(qualification[j]);
697: }
698: break;
699: }
700: }
701: }
702:
703: private char[] extractType(int[] constantPoolOffsets,
704: ClassFileReader reader, int index) {
705: int constantPoolIndex = reader
706: .u2At(constantPoolOffsets[index] + 3);
707: int utf8Offset = constantPoolOffsets[reader
708: .u2At(constantPoolOffsets[constantPoolIndex] + 3)];
709: return reader.utf8At(utf8Offset + 3, reader
710: .u2At(utf8Offset + 1));
711: }
712:
713: public void indexDocument() {
714: try {
715: final byte[] contents = this .document.getByteContents();
716: // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=107124
717: // contents can potentially be null if a IOException occurs while retrieving the contents
718: if (contents == null)
719: return;
720: final String path = this .document.getPath();
721: ClassFileReader reader = new ClassFileReader(contents,
722: path == null ? null : path.toCharArray());
723:
724: // first add type references
725: char[] className = replace('/', '.', reader.getName()); // looks like java/lang/String
726: // need to extract the package name and the simple name
727: int packageNameIndex = CharOperation.lastIndexOf('.',
728: className);
729: char[] packageName = null;
730: char[] name = null;
731: if (packageNameIndex >= 0) {
732: packageName = CharOperation.subarray(className, 0,
733: packageNameIndex);
734: name = CharOperation.subarray(className,
735: packageNameIndex + 1, className.length);
736: } else {
737: packageName = CharOperation.NO_CHAR;
738: name = className;
739: }
740: char[] enclosingTypeName = null;
741: boolean isNestedType = reader.isNestedType();
742: if (isNestedType) {
743: if (reader.isAnonymous()) {
744: name = CharOperation.NO_CHAR;
745: } else {
746: name = reader.getInnerSourceName();
747: }
748: if (reader.isLocal() || reader.isAnonymous()) {
749: // set specific ['0'] value for local and anonymous to be able to filter them
750: enclosingTypeName = ONE_ZERO;
751: } else {
752: char[] fullEnclosingName = reader
753: .getEnclosingTypeName();
754: int nameLength = fullEnclosingName.length
755: - packageNameIndex - 1;
756: if (nameLength <= 0) {
757: // See PR 1GIR345: ITPJCORE:ALL - Indexer: NegativeArraySizeException
758: return;
759: }
760: enclosingTypeName = new char[nameLength];
761: System.arraycopy(fullEnclosingName,
762: packageNameIndex + 1, enclosingTypeName, 0,
763: nameLength);
764: }
765: }
766: // type parameters
767: char[][] typeParameterSignatures = null;
768: char[] genericSignature = reader.getGenericSignature();
769: if (genericSignature != null) {
770: CharOperation.replace(genericSignature, '/', '.');
771: typeParameterSignatures = Signature
772: .getTypeParameters(genericSignature);
773: }
774:
775: // eliminate invalid innerclasses (1G4KCF7)
776: if (name == null)
777: return;
778:
779: char[][] super interfaces = replace('/', '.', reader
780: .getInterfaceNames());
781: char[][] enclosingTypeNames = enclosingTypeName == null ? null
782: : new char[][] { enclosingTypeName };
783: int modifiers = reader.getModifiers();
784: switch (TypeDeclaration.kind(modifiers)) {
785: case TypeDeclaration.CLASS_DECL:
786: char[] super class = replace('/', '.', reader
787: .getSuperclassName());
788: addClassDeclaration(modifiers, packageName, name,
789: enclosingTypeNames, super class,
790: super interfaces, typeParameterSignatures, false);
791: break;
792: case TypeDeclaration.INTERFACE_DECL:
793: addInterfaceDeclaration(modifiers, packageName, name,
794: enclosingTypeNames, super interfaces,
795: typeParameterSignatures, false);
796: break;
797: case TypeDeclaration.ENUM_DECL:
798: super class = replace('/', '.', reader
799: .getSuperclassName());
800: addEnumDeclaration(modifiers, packageName, name,
801: enclosingTypeNames, super class,
802: super interfaces, false);
803: break;
804: case TypeDeclaration.ANNOTATION_TYPE_DECL:
805: addAnnotationTypeDeclaration(modifiers, packageName,
806: name, enclosingTypeNames, false);
807: break;
808: }
809:
810: // Look for references in class annotations
811: IBinaryAnnotation[] annotations = reader.getAnnotations();
812: if (annotations != null) {
813: for (int a = 0, length = annotations.length; a < length; a++) {
814: IBinaryAnnotation annotation = annotations[a];
815: addBinaryAnnotation(annotation);
816: }
817: }
818: long tagBits = reader.getTagBits()
819: & TagBits.AllStandardAnnotationsMask;
820: if (tagBits != 0) {
821: addBinaryStandardAnnotations(tagBits);
822: }
823:
824: // first reference all methods declarations and field declarations
825: MethodInfo[] methods = (MethodInfo[]) reader.getMethods();
826: if (methods != null) {
827: for (int i = 0, max = methods.length; i < max; i++) {
828: MethodInfo method = methods[i];
829: boolean isConstructor = method.isConstructor();
830: char[] descriptor = method.getMethodDescriptor();
831: char[][] parameterTypes = decodeParameterTypes(
832: descriptor, isConstructor && isNestedType);
833: char[] returnType = decodeReturnType(descriptor);
834: char[][] exceptionTypes = replace('/', '.', method
835: .getExceptionTypeNames());
836: if (isConstructor) {
837: addConstructorDeclaration(className,
838: parameterTypes, exceptionTypes);
839: } else {
840: if (!method.isClinit()) {
841: addMethodDeclaration(method.getSelector(),
842: parameterTypes, returnType,
843: exceptionTypes);
844: }
845: }
846: // look for references in method annotations
847: annotations = method.getAnnotations();
848: if (annotations != null) {
849: for (int a = 0, length = annotations.length; a < length; a++) {
850: IBinaryAnnotation annotation = annotations[a];
851: addBinaryAnnotation(annotation);
852: }
853: }
854: }
855: }
856: FieldInfo[] fields = (FieldInfo[]) reader.getFields();
857: if (fields != null) {
858: for (int i = 0, max = fields.length; i < max; i++) {
859: FieldInfo field = fields[i];
860: char[] fieldName = field.getName();
861: char[] fieldType = decodeFieldType(replace('/',
862: '.', field.getTypeName()));
863: addFieldDeclaration(fieldType, fieldName);
864: // look for references in field annotations
865: annotations = field.getAnnotations();
866: if (annotations != null) {
867: for (int a = 0, length = annotations.length; a < length; a++) {
868: IBinaryAnnotation annotation = annotations[a];
869: addBinaryAnnotation(annotation);
870: }
871: }
872: }
873: }
874: // record all references found inside the .class file
875: extractReferenceFromConstantPool(contents, reader);
876: } catch (ClassFormatException e) {
877: // ignore
878: this .document.removeAllIndexEntries();
879: Util
880: .log(
881: e,
882: "ClassFormatException in " + this .document.getPath() + ". Please report this issue to JDT/Core including the problematic document"); //$NON-NLS-1$ //$NON-NLS-2$
883: } catch (RuntimeException e) {
884: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=182154
885: // logging the entry that could not be indexed and continue with the next one
886: // we remove all entries relative to the boggus document
887: this .document.removeAllIndexEntries();
888: Util
889: .log(
890: e,
891: "Indexer crashed on document " + this .document.getPath() + ". Please report this issue to JDT/Core including the problematic document"); //$NON-NLS-1$ //$NON-NLS-2$
892: }
893: }
894:
895: /*
896: * Modify the array by replacing all occurences of toBeReplaced with newChar
897: */
898: private char[][] replace(char toBeReplaced, char newChar,
899: char[][] array) {
900: if (array == null)
901: return null;
902: for (int i = 0, max = array.length; i < max; i++) {
903: replace(toBeReplaced, newChar, array[i]);
904: }
905: return array;
906: }
907:
908: /*
909: * Modify the array by replacing all occurences of toBeReplaced with newChar
910: */
911: private char[] replace(char toBeReplaced, char newChar, char[] array) {
912: if (array == null)
913: return null;
914: for (int i = 0, max = array.length; i < max; i++) {
915: if (array[i] == toBeReplaced) {
916: array[i] = newChar;
917: }
918: }
919: return array;
920: }
921: }
|