Package org.aspectj.org.eclipse.jdt.internal.core.search.indexing

Source Code of org.aspectj.org.eclipse.jdt.internal.core.search.indexing.BinaryIndexer

/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core.search.indexing;

import org.aspectj.org.eclipse.jdt.core.Signature;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.search.SearchDocument;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.FieldInfo;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.MethodInfo;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.ClassSignature;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.EnumConstantSignature;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.aspectj.org.eclipse.jdt.internal.core.util.Util;

public class BinaryIndexer extends AbstractIndexer implements SuffixConstants {
  private static final char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
  private static final char[] CHAR = "char".toCharArray(); //$NON-NLS-1$
  private static final char[] DOUBLE = "double".toCharArray(); //$NON-NLS-1$
  private static final char[] FLOAT = "float".toCharArray(); //$NON-NLS-1$
  private static final char[] INT = "int".toCharArray(); //$NON-NLS-1$
  private static final char[] LONG = "long".toCharArray(); //$NON-NLS-1$
  private static final char[] SHORT = "short".toCharArray(); //$NON-NLS-1$
  private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$
  private static final char[] VOID = "void".toCharArray(); //$NON-NLS-1$
  private static final char[] INIT = "<init>".toCharArray(); //$NON-NLS-1$

  public BinaryIndexer(SearchDocument document) {
    super(document);
  }
  private void addBinaryStandardAnnotations(long annotationTagBits) {
    if ((annotationTagBits & TagBits.AnnotationTargetMASK) != 0) {
      char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_TARGET;
      addTypeReference(compoundName[compoundName.length-1]);
      addBinaryTargetAnnotation(annotationTagBits);
    }
    if ((annotationTagBits & TagBits.AnnotationRetentionMASK) != 0) {
      char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_RETENTION;
      addTypeReference(compoundName[compoundName.length-1]);
      addBinaryRetentionAnnotation(annotationTagBits);
    }
    if ((annotationTagBits & TagBits.AnnotationDeprecated) != 0) {
      char[][] compoundName = TypeConstants.JAVA_LANG_DEPRECATED;
      addTypeReference(compoundName[compoundName.length-1]);
    }
    if ((annotationTagBits & TagBits.AnnotationDocumented) != 0) {
      char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_DOCUMENTED;
      addTypeReference(compoundName[compoundName.length-1]);
    }
    if ((annotationTagBits & TagBits.AnnotationInherited) != 0) {
      char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_INHERITED;
      addTypeReference(compoundName[compoundName.length-1]);
    }
    if ((annotationTagBits & TagBits.AnnotationOverride) != 0) {
      char[][] compoundName = TypeConstants.JAVA_LANG_OVERRIDE;
      addTypeReference(compoundName[compoundName.length-1]);
    }
    if ((annotationTagBits & TagBits.AnnotationSuppressWarnings) != 0) {
      char[][] compoundName = TypeConstants.JAVA_LANG_SUPPRESSWARNINGS;
      addTypeReference(compoundName[compoundName.length-1]);
    }
  }
  private void addBinaryTargetAnnotation(long bits) {
    char[][] compoundName = null;
    if ((bits & TagBits.AnnotationForAnnotationType) != 0) {
      compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
      addTypeReference(compoundName[compoundName.length-1]);
      addFieldReference(TypeConstants.UPPER_ANNOTATION_TYPE);
    }
    if ((bits & TagBits.AnnotationForConstructor) != 0) {
      if (compoundName == null) {
        compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
        addTypeReference(compoundName[compoundName.length-1]);
      }
      addFieldReference(TypeConstants.UPPER_CONSTRUCTOR);
    }
    if ((bits & TagBits.AnnotationForField) != 0) {
      if (compoundName == null) {
        compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
        addTypeReference(compoundName[compoundName.length-1]);
      }
      addFieldReference(TypeConstants.UPPER_FIELD);
    }
    if ((bits & TagBits.AnnotationForLocalVariable) != 0) {
      if (compoundName == null) {
        compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
        addTypeReference(compoundName[compoundName.length-1]);
      }
      addFieldReference(TypeConstants.UPPER_LOCAL_VARIABLE);
    }
    if ((bits & TagBits.AnnotationForMethod) != 0) {
      if (compoundName == null) {
        compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
        addTypeReference(compoundName[compoundName.length-1]);
      }
      addFieldReference(TypeConstants.UPPER_METHOD);
    }
    if ((bits & TagBits.AnnotationForPackage) != 0) {
      if (compoundName == null) {
        compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
        addTypeReference(compoundName[compoundName.length-1]);
      }
      addFieldReference(TypeConstants.UPPER_PACKAGE);
    }
    if ((bits & TagBits.AnnotationForParameter) != 0) {
      if (compoundName == null) {
        compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
        addTypeReference(compoundName[compoundName.length-1]);
      }
      addFieldReference(TypeConstants.UPPER_PARAMETER);
    }
    if ((bits & TagBits.AnnotationForType) != 0) {
      if (compoundName == null) {
        compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
        addTypeReference(compoundName[compoundName.length-1]);
      }
      addFieldReference(TypeConstants.TYPE);
    }
  }
  private void addBinaryRetentionAnnotation(long bits) {
    char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_RETENTIONPOLICY;
    addTypeReference(compoundName[compoundName.length-1]);
    if ((bits & TagBits.AnnotationRuntimeRetention) != 0) {
      addFieldReference(TypeConstants.UPPER_RUNTIME);
    }
    else if ((bits & TagBits.AnnotationClassRetention) != 0) {
      addFieldReference(TypeConstants.UPPER_CLASS);
    }
    else if ((bits & TagBits.AnnotationSourceRetention) != 0) {
      addFieldReference(TypeConstants.UPPER_SOURCE);
    }
  }
  private void addBinaryAnnotation(IBinaryAnnotation annotation) {
    addTypeReference(replace('/', '.', Signature.toCharArray(annotation.getTypeName())));
    IBinaryElementValuePair[] valuePairs = annotation.getElementValuePairs();
    if (valuePairs != null) {
      for (int j=0, vpLength=valuePairs.length; j<vpLength; j++) {
        IBinaryElementValuePair valuePair = valuePairs[j];
        addMethodReference(valuePair.getName(), 0);
        Object pairValue = valuePair.getValue();
        addPairValue(pairValue);
      }
    }
  }
  private void addPairValue(Object pairValue) {
    if (pairValue instanceof EnumConstantSignature) {
      EnumConstantSignature enumConstant = (EnumConstantSignature) pairValue;
      addTypeReference(replace('/', '.', Signature.toCharArray(enumConstant.getTypeName())));
      addNameReference(enumConstant.getEnumConstantName());
    } else if (pairValue instanceof ClassSignature) {
      ClassSignature classConstant = (ClassSignature) pairValue;
      addTypeReference(replace('/', '.', Signature.toCharArray(classConstant.getTypeName())));
    } else if (pairValue instanceof IBinaryAnnotation) {
      addBinaryAnnotation((IBinaryAnnotation) pairValue);
    } else if (pairValue instanceof Object[]) {
      Object[] objects = (Object[]) pairValue;
      for (int i=0,l=objects.length; i<l; i++) {
        addPairValue(objects[i]);
      }
    }
  }
  public void addTypeReference(char[] typeName) {
    int length = typeName.length;
    if (length > 2 && typeName[length - 2] == '$') {
      switch (typeName[length - 1]) {
        case '0' :
        case '1' :
        case '2' :
        case '3' :
        case '4' :
        case '5' :
        case '6' :
        case '7' :
        case '8' :
        case '9' :
          return; // skip local type names
      }
    }

     // consider that A$B is a member type: so replace '$' with '.'
     // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=40116)
    typeName = CharOperation.replaceOnCopy(typeName, '$', '.'); // copy it so the original is not modified

    super.addTypeReference(typeName);
  }
  /**
   * For example:
   *   - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
   *   - void foo(int) is (I)V ==> int
   */
  private void convertToArrayType(char[][] parameterTypes, int counter, int arrayDim) {
    int length = parameterTypes[counter].length;
    char[] arrayType = new char[length + arrayDim*2];
    System.arraycopy(parameterTypes[counter], 0, arrayType, 0, length);
    for (int i = 0; i < arrayDim; i++) {
      arrayType[length + (i * 2)] = '[';
      arrayType[length + (i * 2) + 1] = ']';
    }
    parameterTypes[counter] = arrayType;
  }
  /**
   * For example:
   *   - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
   *   - void foo(int) is (I)V ==> int
   */
  private char[] convertToArrayType(char[] typeName, int arrayDim) {
    int length = typeName.length;
    char[] arrayType = new char[length + arrayDim*2];
    System.arraycopy(typeName, 0, arrayType, 0, length);
    for (int i = 0; i < arrayDim; i++) {
      arrayType[length + (i * 2)] = '[';
      arrayType[length + (i * 2) + 1] = ']';
    }
    return arrayType;
  }
  private char[] decodeFieldType(char[] signature) throws ClassFormatException {
    if (signature == null) return null;
    int arrayDim = 0;
    for (int i = 0, max = signature.length; i < max; i++) {
      switch(signature[i]) {
        case 'B':
          if (arrayDim > 0)
            return convertToArrayType(BYTE, arrayDim);
          return BYTE;
         
        case 'C':
          if (arrayDim > 0)
            return convertToArrayType(CHAR, arrayDim);
          return CHAR;
         
        case 'D':
          if (arrayDim > 0)
            return convertToArrayType(DOUBLE, arrayDim);
          return DOUBLE;
         
        case 'F':
          if (arrayDim > 0)
            return convertToArrayType(FLOAT, arrayDim);
          return FLOAT;
         
        case 'I':
          if (arrayDim > 0)
          return convertToArrayType(INT, arrayDim);
          return INT;
         
        case 'J':
          if (arrayDim > 0)
            return convertToArrayType(LONG, arrayDim);
          return LONG;
         
        case 'L':
          int indexOfSemiColon = CharOperation.indexOf(';', signature, i+1);
          if (indexOfSemiColon == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
          if (arrayDim > 0) {
            return convertToArrayType(replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon)), arrayDim);
          }
          return replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));
         
        case 'S':
          if (arrayDim > 0)
            return convertToArrayType(SHORT, arrayDim);
          return SHORT;
         
        case 'Z':
          if (arrayDim > 0)
            return convertToArrayType(BOOLEAN, arrayDim);
          return BOOLEAN;
         
        case 'V':
          return VOID;
         
        case '[':
          arrayDim++;
          break;
         
        default:
          throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
      }
    }
    return null;
  }
  /**
   * For example:
   *   - int foo(String[]) is ([Ljava/lang/String;)I => java.lang.String[] in a char[][]
   *   - void foo(int) is (I)V ==> int
   */
  private char[][] decodeParameterTypes(char[] signature, boolean firstIsSynthetic) throws ClassFormatException {
    if (signature == null) return null;
    int indexOfClosingParen = CharOperation.lastIndexOf(')', signature);
    if (indexOfClosingParen == 1) {
      // there is no parameter
      return null;
    }
    if (indexOfClosingParen == -1) {
      throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
    }
    char[][] parameterTypes = new char[3][];
    int parameterTypesCounter = 0;
    int arrayDim = 0;
    for (int i = 1; i < indexOfClosingParen; i++) {
      if (parameterTypesCounter == parameterTypes.length) {
        // resize
        System.arraycopy(parameterTypes, 0, (parameterTypes = new char[parameterTypesCounter * 2][]), 0, parameterTypesCounter);
      }
      switch(signature[i]) {
        case 'B':
          parameterTypes[parameterTypesCounter++] = BYTE;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;
         
        case 'C':
          parameterTypes[parameterTypesCounter++] = CHAR;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;

        case 'D':
          parameterTypes[parameterTypesCounter++] = DOUBLE;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;

        case 'F':
          parameterTypes[parameterTypesCounter++] = FLOAT;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;
         
        case 'I':
          parameterTypes[parameterTypesCounter++] = INT;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;
         
        case 'J':
          parameterTypes[parameterTypesCounter++] = LONG;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;

        case 'L':
          int indexOfSemiColon = CharOperation.indexOf(';', signature, i+1);
          if (indexOfSemiColon == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
          if (firstIsSynthetic && parameterTypesCounter == 0) {
            // skip first synthetic parameter
            firstIsSynthetic = false;
          } else {
            parameterTypes[parameterTypesCounter++] = replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));
            if (arrayDim > 0)
              convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          }
          i = indexOfSemiColon;
          arrayDim = 0;
          break;

        case 'S':
          parameterTypes[parameterTypesCounter++] = SHORT;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;

        case 'Z':
          parameterTypes[parameterTypesCounter++] = BOOLEAN;
          if (arrayDim > 0)
            convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
          arrayDim = 0;
          break;

        case '[':
          arrayDim++;
          break;
         
        default:
          throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
      }
    }
    if (parameterTypes.length != parameterTypesCounter) {
      System.arraycopy(parameterTypes, 0, parameterTypes = new char[parameterTypesCounter][], 0, parameterTypesCounter);
    }
    return parameterTypes;
  }
  private char[] decodeReturnType(char[] signature) throws ClassFormatException {
    if (signature == null) return null;
    int indexOfClosingParen = CharOperation.lastIndexOf(')', signature);
    if (indexOfClosingParen == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
    int arrayDim = 0;
    for (int i = indexOfClosingParen + 1, max = signature.length; i < max; i++) {
      switch(signature[i]) {
        case 'B':
          if (arrayDim > 0)
            return convertToArrayType(BYTE, arrayDim);
          return BYTE;
         
        case 'C':
          if (arrayDim > 0)
            return convertToArrayType(CHAR, arrayDim);
          return CHAR;
         
        case 'D':
          if (arrayDim > 0)
            return convertToArrayType(DOUBLE, arrayDim);
          return DOUBLE;

        case 'F':
          if (arrayDim > 0)
            return convertToArrayType(FLOAT, arrayDim);
          return FLOAT;

        case 'I':
          if (arrayDim > 0)
            return convertToArrayType(INT, arrayDim);
          return INT;

        case 'J':
          if (arrayDim > 0)
            return convertToArrayType(LONG, arrayDim);
          return LONG;

        case 'L':
          int indexOfSemiColon = CharOperation.indexOf(';', signature, i+1);
          if (indexOfSemiColon == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
          if (arrayDim > 0) {
            return convertToArrayType(replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon)), arrayDim);
          }
          return replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));

        case 'S':
          if (arrayDim > 0)
            return convertToArrayType(SHORT, arrayDim);
          return SHORT;

        case 'Z':
          if (arrayDim > 0)
            return convertToArrayType(BOOLEAN, arrayDim);
          return BOOLEAN;

        case 'V':
          return VOID;

        case '[':
          arrayDim++;
          break;
         
        default:
          throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
      }
    }
    return null;
  }
  private int extractArgCount(char[] signature, char[] className) throws ClassFormatException {
    int indexOfClosingParen = CharOperation.lastIndexOf(')', signature);
    if (indexOfClosingParen == 1) {
      // there is no parameter
      return 0;
    }
    if (indexOfClosingParen == -1) {
      throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
    }
    int parameterTypesCounter = 0;
    for (int i = 1; i < indexOfClosingParen; i++) {
      switch(signature[i]) {
        case 'B':
        case 'C':
        case 'D':
        case 'F':
        case 'I':
        case 'J':
        case 'S':
        case 'Z':
          parameterTypesCounter++;
          break;
        case 'L':
          int indexOfSemiColon = CharOperation.indexOf(';', signature, i+1);
          if (indexOfSemiColon == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
          // verify if first parameter is synthetic
          if (className != null && parameterTypesCounter == 0) {
            char[] classSignature = Signature.createCharArrayTypeSignature(className, true);
            int length = indexOfSemiColon-i+1;
            if (classSignature.length > (length+1)) {
              // synthetic means that parameter type has same signature than given class
              for (int j=i, k=0; j<indexOfSemiColon; j++, k++) {
                if (!(signature[j] == classSignature[k] || (signature[j] == '/' && classSignature[k] == '.' ))) {
                  parameterTypesCounter++;
                  break;
                }
              }
            } else {
              parameterTypesCounter++;
            }
            className = null; // do not verify following parameters
          } else {
            parameterTypesCounter++;
          }
          i = indexOfSemiColon;
          break;
        case '[':
          break;
        default:
          throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
      }
    }
    return parameterTypesCounter;
  }
  private char[] extractClassName(int[] constantPoolOffsets, ClassFileReader reader, int index) {
    // the entry at i has to be a field ref or a method/interface method ref.
    int class_index = reader.u2At(constantPoolOffsets[index] + 1);
    int utf8Offset = constantPoolOffsets[reader.u2At(constantPoolOffsets[class_index] + 1)];
    return reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
  }
  private char[] extractName(int[] constantPoolOffsets, ClassFileReader reader, int index) {
    int nameAndTypeIndex = reader.u2At(constantPoolOffsets[index] + 3);
    int utf8Offset = constantPoolOffsets[reader.u2At(constantPoolOffsets[nameAndTypeIndex] + 1)];
    return reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
  }
  private char[] extractClassReference(int[] constantPoolOffsets, ClassFileReader reader, int index) {
    // the entry at i has to be a class ref.
    int utf8Offset = constantPoolOffsets[reader.u2At(constantPoolOffsets[index] + 1)];
    return reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
  }
  /**
   * Extract all type, method, field and interface method references from the constant pool
   */
  private void extractReferenceFromConstantPool(byte[] contents, ClassFileReader reader) throws ClassFormatException {
    int[] constantPoolOffsets = reader.getConstantPoolOffsets();
    int constantPoolCount = constantPoolOffsets.length;
    for (int i = 1; i < constantPoolCount; i++) {
      int tag = reader.u1At(constantPoolOffsets[i]);
      /**
       * u1 tag
       * u2 class_index
       * u2 name_and_type_index
       */
      char[] name = null;
      char[] type = null;
      switch (tag) {
        case ClassFileConstants.FieldRefTag :
          // add reference to the class/interface and field name and type
          name = extractName(constantPoolOffsets, reader, i);
          addFieldReference(name);
          break;
        case ClassFileConstants.MethodRefTag :
          // add reference to the class and method name and type
        case ClassFileConstants.InterfaceMethodRefTag :
          // add reference to the interface and method name and type
          name = extractName(constantPoolOffsets, reader, i);
          type = extractType(constantPoolOffsets, reader, i);
          if (CharOperation.equals(INIT, name)) {
            // get class name and see if it's a local type or not
            char[] className = extractClassName(constantPoolOffsets, reader, i);
            boolean localType = false;
            if (className !=  null) {
              for (int c = 0, max = className.length; c < max; c++) {
                switch (className[c]) {
                  case '/':
                    className[c] = '.';
                    break;
                  case '$':
                    localType = true;
                    break;
                }
              }
            }
            // add a constructor reference, use class name to extract arg count if it's a local type to remove synthetic parameter
            addConstructorReference(className, extractArgCount(type, localType?className:null));
          } else {
            // add a method reference
            addMethodReference(name, extractArgCount(type, null));
          }
          break;
        case ClassFileConstants.ClassTag :
          // add a type reference
          name = extractClassReference(constantPoolOffsets, reader, i);
          if (name.length > 0 && name[0] == '[')
            break; // skip over array references
          name = replace('/', '.', name); // so that it looks like java.lang.String
          addTypeReference(name);
         
          // also add a simple reference on each segment of the qualification (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=24741)
          char[][] qualification = CharOperation.splitOn('.', name);
          for (int j = 0, length = qualification.length; j < length; j++) {
            addNameReference(qualification[j]);
          }
          break;
      }
    }
  }
  private char[] extractType(int[] constantPoolOffsets, ClassFileReader reader, int index) {
    int constantPoolIndex = reader.u2At(constantPoolOffsets[index] + 3);
    int utf8Offset = constantPoolOffsets[reader.u2At(constantPoolOffsets[constantPoolIndex] + 3)];
    return reader.utf8At(utf8Offset + 3, reader.u2At(utf8Offset + 1));
  }
  public void indexDocument() {
    try {
      final byte[] contents = this.document.getByteContents();
      // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=107124
      // contents can potentially be null if a IOException occurs while retrieving the contents
      if (contents == null) return;
      final String path = this.document.getPath();
      ClassFileReader reader = new ClassFileReader(contents, path == null ? null : path.toCharArray());
 
      // first add type references
      char[] className = replace('/', '.', reader.getName()); // looks like java/lang/String
      // need to extract the package name and the simple name
      int packageNameIndex = CharOperation.lastIndexOf('.', className);
      char[] packageName = null;
      char[] name = null;
      if (packageNameIndex >= 0) {
        packageName = CharOperation.subarray(className, 0, packageNameIndex);
        name = CharOperation.subarray(className, packageNameIndex + 1, className.length);
      } else {
        packageName = CharOperation.NO_CHAR;
        name = className;
      }
      char[] enclosingTypeName = null;
      boolean isNestedType = reader.isNestedType();
      if (isNestedType) {
        if (reader.isAnonymous()) {
          name = CharOperation.NO_CHAR;
        } else {
          name = reader.getInnerSourceName();
        }
        if (reader.isLocal() || reader.isAnonymous()) {
          // set specific ['0'] value for local and anonymous to be able to filter them
          enclosingTypeName = ONE_ZERO;
        } else {
          char[] fullEnclosingName = reader.getEnclosingTypeName();
          int nameLength = fullEnclosingName.length - packageNameIndex - 1;
          if (nameLength <= 0) {
            // See PR 1GIR345: ITPJCORE:ALL - Indexer: NegativeArraySizeException
            return;
          }
          enclosingTypeName = new char[nameLength];
          System.arraycopy(fullEnclosingName, packageNameIndex + 1, enclosingTypeName, 0, nameLength);
        }
      }
      // type parameters
      char[][] typeParameterSignatures = null;
      char[] genericSignature = reader.getGenericSignature();
      if (genericSignature != null) {
        CharOperation.replace(genericSignature, '/', '.');
        typeParameterSignatures = Signature.getTypeParameters(genericSignature);
      }
     
      // eliminate invalid innerclasses (1G4KCF7)
      if (name == null) return;
     
      char[][] superinterfaces = replace('/', '.', reader.getInterfaceNames());
      char[][] enclosingTypeNames = enclosingTypeName == null ? null : new char[][] {enclosingTypeName};
      int modifiers = reader.getModifiers();
      switch (TypeDeclaration.kind(modifiers)) {
        case TypeDeclaration.CLASS_DECL :
          char[] superclass = replace('/', '.', reader.getSuperclassName());
          addClassDeclaration(modifiers, packageName, name, enclosingTypeNames, superclass, superinterfaces, typeParameterSignatures, false);
          break;
        case TypeDeclaration.INTERFACE_DECL :
          addInterfaceDeclaration(modifiers, packageName, name, enclosingTypeNames, superinterfaces, typeParameterSignatures, false);
          break;
        case TypeDeclaration.ENUM_DECL :
          superclass = replace('/', '.', reader.getSuperclassName());
          addEnumDeclaration(modifiers, packageName, name, enclosingTypeNames, superclass, superinterfaces, false);
          break;
        case TypeDeclaration.ANNOTATION_TYPE_DECL :
          addAnnotationTypeDeclaration(modifiers, packageName, name, enclosingTypeNames, false);
          break;
      }     

      // Look for references in class annotations
      IBinaryAnnotation[] annotations = reader.getAnnotations();
      if (annotations != null) {
        for (int a=0, length=annotations.length; a<length; a++) {
          IBinaryAnnotation annotation = annotations[a];
          addBinaryAnnotation(annotation);
        }
      }
      long tagBits = reader.getTagBits() & TagBits.AllStandardAnnotationsMask;
      if (tagBits != 0) {
        addBinaryStandardAnnotations(tagBits);
      }

      // first reference all methods declarations and field declarations
      MethodInfo[] methods = (MethodInfo[]) reader.getMethods();
      if (methods != null) {
        for (int i = 0, max = methods.length; i < max; i++) {
          MethodInfo method = methods[i];
          boolean isConstructor = method.isConstructor();
          char[] descriptor = method.getMethodDescriptor();
          char[][] parameterTypes = decodeParameterTypes(descriptor, isConstructor && isNestedType);
          char[] returnType = decodeReturnType(descriptor);
          char[][] exceptionTypes = replace('/', '.', method.getExceptionTypeNames());
          if (isConstructor) {
            addConstructorDeclaration(className, parameterTypes, exceptionTypes);
          } else {
            if (!method.isClinit()) {
              addMethodDeclaration(method.getSelector(), parameterTypes, returnType, exceptionTypes);
            }
          }
          // look for references in method annotations
          annotations = method.getAnnotations();
          if (annotations != null) {
            for (int a=0, length=annotations.length; a<length; a++) {
              IBinaryAnnotation annotation = annotations[a];
              addBinaryAnnotation(annotation);
            }
          }
        }
      }
      FieldInfo[] fields = (FieldInfo[]) reader.getFields();
      if (fields != null) {
        for (int i = 0, max = fields.length; i < max; i++) {
          FieldInfo field = fields[i];
          char[] fieldName = field.getName();
          char[] fieldType = decodeFieldType(replace('/', '.', field.getTypeName()));
          addFieldDeclaration(fieldType, fieldName);
          // look for references in field annotations
          annotations = field.getAnnotations();
          if (annotations != null) {
            for (int a=0, length=annotations.length; a<length; a++) {
              IBinaryAnnotation annotation = annotations[a];
              addBinaryAnnotation(annotation);
            }
          }
        }
      }
      // record all references found inside the .class file
      extractReferenceFromConstantPool(contents, reader);
    } catch (ClassFormatException e) {
      // ignore
      this.document.removeAllIndexEntries();
      Util.log(e, "ClassFormatException in " + this.document.getPath() + ". Please report this issue to JDT/Core including the problematic document"); //$NON-NLS-1$ //$NON-NLS-2$
    } catch (RuntimeException e) {
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=182154
      // logging the entry that could not be indexed and continue with the next one
      // we remove all entries relative to the boggus document
      this.document.removeAllIndexEntries();
      Util.log(e, "Indexer crashed on document " + this.document.getPath() + ". Please report this issue to JDT/Core including the problematic document"); //$NON-NLS-1$ //$NON-NLS-2$
    }
  }
  /*
   * Modify the array by replacing all occurences of toBeReplaced with newChar
   */
  private char[][] replace(char toBeReplaced, char newChar, char[][] array) {
    if (array == null) return null;
    for (int i = 0, max = array.length; i < max; i++) {
      replace(toBeReplaced, newChar, array[i]);
    }
    return array;
  }
  /*
   * Modify the array by replacing all occurences of toBeReplaced with newChar
   */
  private char[] replace(char toBeReplaced, char newChar, char[] array) {
    if (array == null) return null;
    for (int i = 0, max = array.length; i < max; i++) {
      if (array[i] == toBeReplaced) {
        array[i] = newChar;
      }
    }
    return array;
  }
}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.core.search.indexing.BinaryIndexer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.