Package org.eclipse.jdt.internal.compiler.parser

Source Code of org.eclipse.jdt.internal.compiler.parser.TypeConverter

/*******************************************************************************
* Copyright (c) 2008 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.eclipse.jdt.internal.compiler.parser;

import java.util.ArrayList;

import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;

public abstract class TypeConverter {
 
  int namePos;
 
  protected ProblemReporter problemReporter;
  protected boolean has1_5Compliance;
  private char memberTypeSeparator;
 
  protected TypeConverter(ProblemReporter problemReporter, char memberTypeSeparator) {
    this.problemReporter = problemReporter;
    this.has1_5Compliance = problemReporter.options.complianceLevel >= ClassFileConstants.JDK1_5;
    this.memberTypeSeparator = memberTypeSeparator;
  }
 
  private void addIdentifiers(String typeSignature, int start, int endExclusive, int identCount, ArrayList fragments) {
    if (identCount == 1) {
      char[] identifier;
      typeSignature.getChars(start, endExclusive, identifier = new char[endExclusive-start], 0);
      fragments.add(identifier);
    } else
      fragments.add(extractIdentifiers(typeSignature, start, endExclusive-1, identCount));
  }
 
  /*
   * Build an import reference from an import name, e.g. java.lang.*
   */
  protected ImportReference createImportReference(
    String[] importName,
    int start,
    int end,
    boolean onDemand,
    int modifiers) {
 
    int length = importName.length;
    long[] positions = new long[length];
    long position = ((long) start << 32) + end;
    char[][] qImportName = new char[length][];
    for (int i = 0; i < length; i++) {
      qImportName[i] = importName[i].toCharArray();
      positions[i] = position; // dummy positions
    }
    return new ImportReference(
      qImportName,
      positions,
      onDemand,
      modifiers);
  }

  protected TypeParameter createTypeParameter(char[] typeParameterName, char[][] typeParameterBounds, int start, int end) {

    TypeParameter parameter = new TypeParameter();
    parameter.name = typeParameterName;
    parameter.sourceStart = start;
    parameter.sourceEnd = end;
    if (typeParameterBounds != null) {
      int length = typeParameterBounds.length;
      if (length > 0) {
        parameter.type = createTypeReference(typeParameterBounds[0], start, end);
        if (length > 1) {
          parameter.bounds = new TypeReference[length-1];
          for (int i = 1; i < length; i++) {
            TypeReference bound = createTypeReference(typeParameterBounds[i], start, end);
            bound.bits |= ASTNode.IsSuperType;
            parameter.bounds[i-1] = bound;
          }
        }
      }
    }
    return parameter;
  }
 
  /*
   * Build a type reference from a readable name, e.g. java.lang.Object[][]
   */
  protected TypeReference createTypeReference(
    char[] typeName,
    int start,
    int end) {

    int length = typeName.length;
    this.namePos = 0;
    return decodeType(typeName, length, start, end);
  }
 
  /*
   * Build a type reference from a type signature, e.g. Ljava.lang.Object;
   */
  protected TypeReference createTypeReference(
      String typeSignature,
      int start,
      int end) {
   
    int length = typeSignature.length();
    this.namePos = 0;
    return decodeType(typeSignature, length, start, end);
  }
 
  private TypeReference decodeType(String typeSignature, int length, int start, int end) {
    int identCount = 1;
    int dim = 0;
    int nameFragmentStart = this.namePos, nameFragmentEnd = -1;
    boolean nameStarted = false;
    ArrayList fragments = null;
    typeLoop: while (this.namePos < length) {
      char currentChar = typeSignature.charAt(this.namePos);
      switch (currentChar) {
        case Signature.C_BOOLEAN :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.BOOLEAN.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.BOOLEAN.simpleName, dim, ((long) start << 32) + end);
          }
          break;
        case Signature.C_BYTE :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.BYTE.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.BYTE.simpleName, dim, ((long) start << 32) + end);       
          }
          break;
        case Signature.C_CHAR :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.CHAR.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.CHAR.simpleName, dim, ((long) start << 32) + end);
          }
          break;
        case Signature.C_DOUBLE :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.DOUBLE.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.DOUBLE.simpleName, dim, ((long) start << 32) + end);       
          }
          break;
        case Signature.C_FLOAT :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.FLOAT.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.FLOAT.simpleName, dim, ((long) start << 32) + end);       
          }
          break;
        case Signature.C_INT :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.INT.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.INT.simpleName, dim, ((long) start << 32) + end);       
          }
          break;
        case Signature.C_LONG :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.LONG.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.LONG.simpleName, dim, ((long) start << 32) + end);       
          }
          break;
        case Signature.C_SHORT :
          if (!nameStarted) {
            this.namePos++;
            if (dim == 0)
              return new SingleTypeReference(TypeBinding.SHORT.simpleName, ((long) start << 32) + end);
            else
              return new ArrayTypeReference(TypeBinding.SHORT.simpleName, dim, ((long) start << 32) + end);       
          }
          break;
        case Signature.C_VOID :
          if (!nameStarted) {
            this.namePos++;
            return new SingleTypeReference(TypeBinding.VOID.simpleName, ((long) start << 32) + end);
          }
          break;
        case Signature.C_RESOLVED :
        case Signature.C_UNRESOLVED :
        case Signature.C_TYPE_VARIABLE :
          if (!nameStarted) {
            nameFragmentStart = this.namePos+1;
            nameStarted = true;
          }
          break;
        case Signature.C_STAR:
          this.namePos++;
          Wildcard result = new Wildcard(Wildcard.UNBOUND);
          result.sourceStart = start;
          result.sourceEnd = end;
          return result;
        case Signature.C_EXTENDS:
          this.namePos++;
          result = new Wildcard(Wildcard.EXTENDS);
          result.bound = decodeType(typeSignature, length, start, end);
          result.sourceStart = start;
          result.sourceEnd = end;
          return result;
        case Signature.C_SUPER:
          this.namePos++;
          result = new Wildcard(Wildcard.SUPER);
          result.bound = decodeType(typeSignature, length, start, end);
          result.sourceStart = start;
          result.sourceEnd = end;
          return result;
        case Signature.C_ARRAY :
          dim++;
          break;
        case Signature.C_GENERIC_END :
        case Signature.C_SEMICOLON :
          nameFragmentEnd = this.namePos-1;
          this.namePos++;
          break typeLoop;
        case Signature.C_DOLLAR:
          if (this.memberTypeSeparator != Signature.C_DOLLAR)
            break;
        case Signature.C_DOT :
          if (!nameStarted) {
            nameFragmentStart = this.namePos+1;
            nameStarted = true;
          } else if (this.namePos > nameFragmentStart) // handle name starting with a $ (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=91709)
            identCount ++;
          break;
        case Signature.C_GENERIC_START :
          nameFragmentEnd = this.namePos-1;
          // convert 1.5 specific constructs only if compliance is 1.5 or above
          if (!this.has1_5Compliance)
            break typeLoop;
          if (fragments == null) fragments = new ArrayList(2);
          addIdentifiers(typeSignature, nameFragmentStart, nameFragmentEnd + 1, identCount, fragments);
          this.namePos++; // skip '<'
          TypeReference[] arguments = decodeTypeArguments(typeSignature, length, start, end); // positionned on '>' at end
          fragments.add(arguments);
          identCount = 1;
          nameStarted = false;
          // next increment will skip '>'
          break;
      }
      this.namePos++;
    }
    if (fragments == null) { // non parameterized
      /* rebuild identifiers and dimensions */
      if (identCount == 1) { // simple type reference
        if (dim == 0) {
          char[] nameFragment = new char[nameFragmentEnd - nameFragmentStart + 1];
          typeSignature.getChars(nameFragmentStart, nameFragmentEnd +1, nameFragment, 0);
          return new SingleTypeReference(nameFragment, ((long) start << 32) + end);
        } else {
          char[] nameFragment = new char[nameFragmentEnd - nameFragmentStart + 1];
          typeSignature.getChars(nameFragmentStart, nameFragmentEnd +1, nameFragment, 0);
          return new ArrayTypeReference(nameFragment, dim, ((long) start << 32) + end);
        }
      } else { // qualified type reference
        long[] positions = new long[identCount];
        long pos = ((long) start << 32) + end;
        for (int i = 0; i < identCount; i++) {
          positions[i] = pos;
        }
        char[][] identifiers = extractIdentifiers(typeSignature, nameFragmentStart, nameFragmentEnd, identCount);
        if (dim == 0) {
          return new QualifiedTypeReference(identifiers, positions);
        } else {
          return new ArrayQualifiedTypeReference(identifiers, dim, positions);
        }
      }
    } else { // parameterized
      // rebuild type reference from available fragments: char[][], arguments, char[][], arguments...
      // check trailing qualified name
      if (nameStarted) {
        addIdentifiers(typeSignature, nameFragmentStart, nameFragmentEnd + 1, identCount, fragments);
      }
      int fragmentLength = fragments.size();
      if (fragmentLength == 2) {
        Object firstFragment = fragments.get(0);
        if (firstFragment instanceof char[]) {
          // parameterized single type
          return new ParameterizedSingleTypeReference((char[]) firstFragment, (TypeReference[]) fragments.get(1), dim, ((long) start << 32) + end);
        }
      }
      // parameterized qualified type
      identCount = 0;
      for (int i = 0; i < fragmentLength; i ++) {
        Object element = fragments.get(i);
        if (element instanceof char[][]) {
          identCount += ((char[][])element).length;
        } else if (element instanceof char[])
          identCount++;
      }
      char[][] tokens = new char[identCount][];
      TypeReference[][] arguments = new TypeReference[identCount][];
      int index = 0;
      for (int i = 0; i < fragmentLength; i ++) {
        Object element = fragments.get(i);
        if (element instanceof char[][]) {
          char[][] fragmentTokens = (char[][]) element;
          int fragmentTokenLength = fragmentTokens.length;
          System.arraycopy(fragmentTokens, 0, tokens, index, fragmentTokenLength);
          index += fragmentTokenLength;
        } else if (element instanceof char[]) {
          tokens[index++] = (char[]) element;
        } else {
          arguments[index-1] = (TypeReference[]) element;
        }
      }
      long[] positions = new long[identCount];
      long pos = ((long) start << 32) + end;
      for (int i = 0; i < identCount; i++) {
        positions[i] = pos;
      }
      return new ParameterizedQualifiedTypeReference(tokens, arguments, dim, positions);
    }
  }
 
  private TypeReference decodeType(char[] typeName, int length, int start, int end) {
    int identCount = 1;
    int dim = 0;
    int nameFragmentStart = this.namePos, nameFragmentEnd = -1;
    ArrayList fragments = null;
    typeLoop: while (this.namePos < length) {
      char currentChar = typeName[this.namePos];
      switch (currentChar) {
        case '?' :
          this.namePos++; // skip '?'
          while (typeName[this.namePos] == ' ') this.namePos++;
          switch(typeName[this.namePos]) {
            case 's' :
              checkSuper: {
                int max = TypeConstants.WILDCARD_SUPER.length-1;
                for (int ahead = 1; ahead < max; ahead++) {
                  if (typeName[this.namePos+ahead] != TypeConstants.WILDCARD_SUPER[ahead+1]) {
                    break checkSuper;
                  }
                }
                this.namePos += max;
                Wildcard result = new Wildcard(Wildcard.SUPER);
                result.bound = decodeType(typeName, length, start, end);
                result.sourceStart = start;
                result.sourceEnd = end;
                return result;
              }
              break;
            case 'e' :
              checkExtends: {
                int max = TypeConstants.WILDCARD_EXTENDS.length-1;
                for (int ahead = 1; ahead < max; ahead++) {
                  if (typeName[this.namePos+ahead] != TypeConstants.WILDCARD_EXTENDS[ahead+1]) {
                    break checkExtends;
                  }
                }
                this.namePos += max;
                Wildcard result = new Wildcard(Wildcard.EXTENDS);
                result.bound = decodeType(typeName, length, start, end);
                result.sourceStart = start;
                result.sourceEnd = end;
                return result;
              }
              break;
          }
          Wildcard result = new Wildcard(Wildcard.UNBOUND);
          result.sourceStart = start;
          result.sourceEnd = end;
          return result;
        case '[' :
          if (dim == 0) nameFragmentEnd = this.namePos-1;
          dim++;
          break;
        case ']' :
          break;
        case '>' :
        case ',' :
          break typeLoop;
        case '.' :
          if (nameFragmentStart < 0) nameFragmentStart = this.namePos+1; // member type name
          identCount ++;
          break;
        case '<' :
          // convert 1.5 specific constructs only if compliance is 1.5 or above
          if (!this.has1_5Compliance)
            break typeLoop;
          if (fragments == null) fragments = new ArrayList(2);
          nameFragmentEnd = this.namePos-1;
          char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, this.namePos);
          fragments.add(identifiers);
          this.namePos++; // skip '<'
          TypeReference[] arguments = decodeTypeArguments(typeName, length, start, end); // positionned on '>' at end
          fragments.add(arguments);
          identCount = 0;
          nameFragmentStart = -1;
          nameFragmentEnd = -1;
          // next increment will skip '>'
          break;
      }
      this.namePos++;
    }
    if (nameFragmentEnd < 0) nameFragmentEnd = this.namePos-1;
    if (fragments == null) { // non parameterized
      /* rebuild identifiers and dimensions */
      if (identCount == 1) { // simple type reference
        if (dim == 0) {
          char[] nameFragment;
          if (nameFragmentStart != 0 || nameFragmentEnd >= 0) {
            int nameFragmentLength = nameFragmentEnd - nameFragmentStart + 1;
            System.arraycopy(typeName, nameFragmentStart, nameFragment = new char[nameFragmentLength], 0, nameFragmentLength);           
          } else {
            nameFragment = typeName;
          }
          return new SingleTypeReference(nameFragment, ((long) start << 32) + end);
        } else {
          int nameFragmentLength = nameFragmentEnd - nameFragmentStart + 1;
          char[] nameFragment = new char[nameFragmentLength];
          System.arraycopy(typeName, nameFragmentStart, nameFragment, 0, nameFragmentLength);
          return new ArrayTypeReference(nameFragment, dim, ((long) start << 32) + end);
        }
      } else { // qualified type reference
        long[] positions = new long[identCount];
        long pos = ((long) start << 32) + end;
        for (int i = 0; i < identCount; i++) {
          positions[i] = pos;
        }
        char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, nameFragmentEnd+1);
        if (dim == 0) {
          return new QualifiedTypeReference(identifiers, positions);
        } else {
          return new ArrayQualifiedTypeReference(identifiers, dim, positions);
        }
      }
    } else { // parameterized
      // rebuild type reference from available fragments: char[][], arguments, char[][], arguments...
      // check trailing qualified name
      if (nameFragmentStart > 0 && nameFragmentStart < length) {
        char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, nameFragmentEnd+1);
        fragments.add(identifiers);
      }
      int fragmentLength = fragments.size();
      if (fragmentLength == 2) {
        char[][] firstFragment = (char[][]) fragments.get(0);
        if (firstFragment.length == 1) {
          // parameterized single type
          return new ParameterizedSingleTypeReference(firstFragment[0], (TypeReference[]) fragments.get(1), dim, ((long) start << 32) + end);
        }
      }
      // parameterized qualified type
      identCount = 0;
      for (int i = 0; i < fragmentLength; i ++) {
        Object element = fragments.get(i);
        if (element instanceof char[][]) {
          identCount += ((char[][])element).length;
        }
      }
      char[][] tokens = new char[identCount][];
      TypeReference[][] arguments = new TypeReference[identCount][];
      int index = 0;
      for (int i = 0; i < fragmentLength; i ++) {
        Object element = fragments.get(i);
        if (element instanceof char[][]) {
          char[][] fragmentTokens = (char[][]) element;
          int fragmentTokenLength = fragmentTokens.length;
          System.arraycopy(fragmentTokens, 0, tokens, index, fragmentTokenLength);
          index += fragmentTokenLength;
        } else {
          arguments[index-1] = (TypeReference[]) element;
        }
      }
      long[] positions = new long[identCount];
      long pos = ((long) start << 32) + end;
      for (int i = 0; i < identCount; i++) {
        positions[i] = pos;
      }
      return new ParameterizedQualifiedTypeReference(tokens, arguments, dim, positions);
    }
  }
 
  private TypeReference[] decodeTypeArguments(char[] typeName, int length, int start, int end) {
    ArrayList argumentList = new ArrayList(1);
    int count = 0;
    argumentsLoop: while (this.namePos < length) {
      TypeReference argument = decodeType(typeName, length, start, end);
      count++;
      argumentList.add(argument);
      if (this.namePos >= length) break argumentsLoop;
      if (typeName[this.namePos] == '>') {
        break argumentsLoop;
      }
      this.namePos++; // skip ','
    }
    TypeReference[] typeArguments = new TypeReference[count];
    argumentList.toArray(typeArguments);
    return typeArguments;
  }
 
  private TypeReference[] decodeTypeArguments(String typeSignature, int length, int start, int end) {
    ArrayList argumentList = new ArrayList(1);
    int count = 0;
    argumentsLoop: while (this.namePos < length) {
      TypeReference argument = decodeType(typeSignature, length, start, end);
      count++;
      argumentList.add(argument);
      if (this.namePos >= length) break argumentsLoop;
      if (typeSignature.charAt(this.namePos) == Signature.C_GENERIC_END) {
        break argumentsLoop;
      }
    }
    TypeReference[] typeArguments = new TypeReference[count];
    argumentList.toArray(typeArguments);
    return typeArguments;
  }
 
  private char[][] extractIdentifiers(String typeSignature, int start, int endInclusive, int identCount) {
    char[][] result = new char[identCount][];
    int charIndex = start;
    int i = 0;
    while (charIndex < endInclusive) {
      char currentChar;
      if ((currentChar = typeSignature.charAt(charIndex)) == this.memberTypeSeparator || currentChar == Signature.C_DOT) {
        typeSignature.getChars(start, charIndex, result[i++] = new char[charIndex - start], 0);
        start = ++charIndex;
      } else
        charIndex++;
    }
    typeSignature.getChars(start, charIndex + 1, result[i++] = new char[charIndex - start + 1], 0);
    return result;
  }
}
TOP

Related Classes of org.eclipse.jdt.internal.compiler.parser.TypeConverter

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.