Package org.eclim.plugin.jdt.util

Source Code of org.eclim.plugin.jdt.util.TypeUtils

/**
* Copyright (C) 2005 - 2012  Eric Van Dewoestine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.eclim.plugin.jdt.util;

import java.util.ArrayList;
import java.util.List;

import org.eclim.logging.Logger;

import org.eclim.plugin.jdt.command.search.SearchRequestor;

import org.eclim.util.StringUtils;

import org.eclim.util.file.Position;

import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageDeclaration;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.Signature;

import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;

import org.eclipse.jdt.internal.core.CompilationUnit;

/**
* Utility methods for working with IType.
*
* @author Eric Van Dewoestine
*/
public class TypeUtils
{
  private static final Logger logger = Logger.getLogger(TypeUtils.class);

  /**
   * Gets the type at the supplied offset, which will either be the primary type
   * of the comilation unit, or an inner class.
   *
   * @param src The ICompilationSource.
   * @param offset The offet in the source file.
   * @return The IType.
   */
  public static IType getType(ICompilationUnit src, int offset)
    throws Exception
  {
    IJavaElement element = src.getElementAt(offset);
    IType type = null;

    // offset outside the class source (Above the package declaration most
    // likely)
    if(element == null){
      type = ((CompilationUnit)src).getTypeRoot().findPrimaryType();

    // inner class
    }else if(element != null && element.getElementType() == IJavaElement.TYPE){
      type = (IType)element;
    }else{
      element = element.getParent();

      // offset on import statement
      if(element.getElementType() == IJavaElement.IMPORT_CONTAINER){
        element = element.getParent();
      }

      // offset on the package declaration or continuation of import ^
      if(element.getElementType() == IJavaElement.COMPILATION_UNIT){
        element = ((CompilationUnit)element).getTypeRoot().findPrimaryType();
      }
      type = (IType)element;
    }
    return type;
  }

  /**
   * Gets the Position of the suplied ISourceReference.
   *
   * @param type The type.
   * @param reference The reference.
   * @return The position.
   */
  public static Position getPosition(IType type, ISourceReference reference)
    throws Exception
  {
    ISourceRange range = reference.getSourceRange();
    return Position.fromOffset(
        type.getResource().getLocation().toOSString(), null,
        range.getOffset(), range.getLength());
  }

  /**
   * Gets the signature for the supplied type.
   *
   * @param typeInfo The typeInfo.
   * @return The signature.
   */
  public static String getTypeSignature(TypeInfo typeInfo)
    throws Exception
  {
    StringBuffer buffer = new StringBuffer();
    IType type = typeInfo.getType();
    int flags = type.getFlags();
    if(Flags.isPublic(flags)){
      buffer.append("public ");
    }

    buffer.append(type.isClass() ? "class " : "interface ");
    IJavaElement parent = type.getParent();
    if(parent.getElementType() == IJavaElement.TYPE){
      buffer.append(type.getParent().getElementName()).append('.');
    }else if(parent.getElementType() == IJavaElement.CLASS_FILE){
      int index = parent.getElementName().indexOf('$');
      if(index != -1){
        buffer.append(parent.getElementName().substring(0, index)).append('.');
      }
    }
    buffer.append(type.getElementName());
    String[] params = typeInfo.getTypeParameters();
    String[] args = typeInfo.getTypeArguments();
    if (params != null && params.length > 0 && args != null && args.length > 0){
      buffer.append('<');
      for (int ii = 0; ii < args.length; ii++){
        if (ii > 0){
          buffer.append(',');
        }
        buffer.append(args[ii]);
      }
      buffer.append('>');
    }
    return buffer.toString();
  }

  /**
   * Determines if any of the super types of the supplied type contains the
   * supplied method and if so return that super type.
   *
   * @param type The type.
   * @param method The method.
   * @return The super type that contains the method, or null if none.
   */
  public static TypeInfo getSuperTypeContainingMethod(IType type, IMethod method)
    throws Exception
  {
    TypeInfo[] types = getSuperTypes(type);
    for(TypeInfo info : types){
      IMethod[] methods = info.getType().getMethods();
      for (IMethod m : methods){
        if(m.isSimilar(method)){
          return info;
        }
      }
    }
    return null;
  }

  /**
   * Determines if any of the super types of the supplied type contains a method
   * with the supplied signature and if so return that super type.
   *
   * @param type The type.
   * @param signature The method signature.
   * @return The super type that contains the method, or null if none.
   */
  public static Object[] getSuperTypeContainingMethod(
      IType type, String signature)
    throws Exception
  {
    TypeInfo[] types = getSuperTypes(type);
    for(TypeInfo info : types){
      IMethod[] methods = info.getType().getMethods();
      for (IMethod method : methods){
        String sig = MethodUtils.getMinimalMethodSignature(method, info);
        if(sig.equals(signature)){
          return new Object[]{info, method};
        }
      }
    }
    return null;
  }

  /**
   * Converts the supplied type signature with generic information to the most
   * basic type that it supports.
   *
   * @param type The parent IType.
   * @param typeSignature The type signature.
   * @return The base type.
   */
  public static String getBaseTypeFromGeneric(
      IType type, String typeSignature)
    throws Exception
  {
    int arrayCount = Signature.getArrayCount(typeSignature);
    if(arrayCount > 0){
      for(int ii = 0; ii < arrayCount; ii++){
        typeSignature = Signature.getElementType(typeSignature);
      }
    }

    String result = null;
    ITypeParameter param = type.getTypeParameter(
        Signature.getSignatureSimpleName(typeSignature));
    if(param.exists()){
      result = param.getBounds()[0];
    }else{
      result =  Signature.getSignatureSimpleName(
          Signature.getTypeErasure(typeSignature));
    }

    if(arrayCount > 0){
      for(int ii = 0; ii < arrayCount; ii++){
        result = result + "[]";
      }
    }
    return result;
  }

  /**
   * Attempts to find an unqualified type by searching the import declarations
   * of the supplied source file and attempting to find the type in the same
   * package as the source file..
   *
   * @param src The source file.
   * @param typeName The unqualified type name.
   * @return The type or null if not found.
   */
  public static IType findUnqualifiedType(
      ICompilationUnit src, String typeName)
    throws Exception
  {
    String name = "." + typeName;

    // strip of generic type if present.
    int index = name.indexOf('<');
    if(index != -1){
      name = name.substring(0, index);
    }

    // search imports
    IImportDeclaration[] imports = src.getImports();
    for(IImportDeclaration decl : imports){
      if(decl.getElementName().endsWith(name)){
        return src.getJavaProject().findType(decl.getElementName());
      }
    }

    // attempt to find in current package.
    IPackageDeclaration[] packages = src.getPackageDeclarations();
    if(packages != null && packages.length > 0){
      name = packages[0].getElementName() + name;
    }else{
      name = typeName;
    }
    IType type = src.getJavaProject().findType(name);

    // last effort, search java.lang
    if(type == null){
      type = src.getJavaProject().findType("java.lang." + typeName);
    }

    return type;
  }

  /**
   * Recursively gets all superclass and implemented interfaces from the
   * supplied type.
   *
   * @param type The type.
   * @return Array of types.
   */
  public static TypeInfo[] getSuperTypes(IType type)
    throws Exception
  {
    return getSuperTypes(type, false);
  }

  /**
   * Recursively gets all superclass and implemented interfaces from the
   * supplied type.
   *
   * @param type The type.
   * @param returnNotFound Whether or not to return handle only instances to
   *  super types that could not be found in the project.
   * @return Array of types.
   */
  public static TypeInfo[] getSuperTypes(IType type, boolean returnNotFound)
    throws Exception
  {
    TypeInfo[] interfaces = getInterfaces(type, returnNotFound);
    TypeInfo[] superClasses = getSuperClasses(type, returnNotFound);
    TypeInfo[] types = new TypeInfo[interfaces.length + superClasses.length];

    System.arraycopy(interfaces, 0, types, 0, interfaces.length);
    System.arraycopy(
        superClasses, 0, types, interfaces.length, superClasses.length);

    return types;
  }

  /**
   * Recursively gets all the superclasses for the given type.
   *
   * @param type The type.
   * @return Array of superclass types.
   */
  public static TypeInfo[] getSuperClasses(IType type)
    throws Exception
  {
    return getSuperClasses(type, false);
  }

  /**
   * Recursively gets all the superclasses for the given type.
   *
   * @param type The type.
   * @param returnNotFound Whether or not to return handle only instances to
   *  super class types that could not be found in the project.
   * @return Array of superclass types.
   */
  public static TypeInfo[] getSuperClasses(IType type, boolean returnNotFound)
    throws Exception
  {
    ArrayList<TypeInfo> types = new ArrayList<TypeInfo>();

    getSuperClasses(type, types, returnNotFound, null);

    // add java.lang.Object if not already added
    IType objectType = type.getJavaProject().findType("java.lang.Object");
    TypeInfo objectTypeInfo = new TypeInfo(objectType, null, null);
    if(!types.contains(objectTypeInfo)){
      types.add(objectTypeInfo);
    }

    return (TypeInfo[])types.toArray(new TypeInfo[types.size()]);
  }

  /**
   * Recursively gets all the implemented interfaces for the given type.
   *
   * @param type The type.
   * @return Array of interface types.
   */
  public static TypeInfo[] getInterfaces(IType type)
    throws Exception
  {
    return getInterfaces(type, false);
  }

  /**
   * Recursively gets all the implemented interfaces for the given type.
   *
   * @param type The type.
   * @param returnNotFound Whether or not to return handle only instances to
   *  super interface types that could not be found in the project.
   * @return Array of interface types.
   */
  public static TypeInfo[] getInterfaces(IType type, boolean returnNotFound)
    throws Exception
  {
    ArrayList<TypeInfo> types = new ArrayList<TypeInfo>();
    getInterfaces(type, types, returnNotFound, null);

    return (TypeInfo[])types.toArray(new TypeInfo[types.size()]);
  }

  /**
   * Recursively gets all the superclasses for the given type.
   *
   * @param type The type.
   * @param superclasses The list to add results to.
   * @param includeNotFound Whether or not to include types that were not found
   * (adds them as handle only IType instances).
   * @param baseType The first type in the recursion stack.
   */
  public static void getSuperClasses(
      IType type,
      List<TypeInfo> superclasses,
      boolean includeNotFound,
      TypeInfo baseType)
    throws Exception
  {
    TypeInfo superclassInfo = getSuperClass(type, baseType);
    if (superclassInfo != null){
      if (baseType == null ||
          baseType.getTypeArguments().length !=
            superclassInfo.getTypeArguments().length)
      {
        baseType = superclassInfo;
      }
    }

    if(superclassInfo != null && !superclasses.contains(superclassInfo)){
      superclasses.add(superclassInfo);
      getSuperClasses(
          superclassInfo.getType(), superclasses, includeNotFound, baseType);
    }else if(superclassInfo == null && includeNotFound){
      String typeName = type.getSuperclassName();
      if(typeName != null){
        // get a handle only reference to the super class that wasn't found.
        try{
          IType superclass = type.getType(typeName);
          superclassInfo = new TypeInfo(superclass, null, null);
          if(!superclasses.contains(superclassInfo)){
            superclasses.add(superclassInfo);
          }
        }catch(Exception e){
          // don't let the error cause the command to fail.
          logger.warn("Unable to get a handle to class not found: '" +
              typeName + "'", e);
        }
      }
    }
  }

  /**
   * Gets the super type of the supplied type, if any.
   *
   * @param type The type to get the superclass of.
   * @return The superclass type or null if none.
   */
  public static TypeInfo getSuperClass(IType type)
    throws Exception
  {
    return getSuperClass(type, null);
  }

  /**
   * Gets the super type of the supplied type, if any.
   *
   * @param type The type to get the superclass of.
   * @return The superclass type or null if none.
   */
  private static TypeInfo getSuperClass(IType type, TypeInfo baseType)
    throws Exception
  {
    String superclassSig = type.getSuperclassTypeSignature();
    if(superclassSig != null){
      String qualifier = Signature.getSignatureQualifier(superclassSig);
      qualifier =
        (qualifier != null && !qualifier.equals(StringUtils.EMPTY)) ?
        qualifier + '.' : StringUtils.EMPTY;
      String superclass =
        qualifier + Signature.getSignatureSimpleName(superclassSig);
      String[] args = Signature.getTypeArguments(superclassSig);
      String[] typeArgs = new String[args.length];
      for (int ii = 0; ii < args.length; ii++){
        typeArgs[ii] = Signature.getSignatureSimpleName(args[ii]);
      }
      if (baseType != null &&
          baseType.getTypeArguments().length == typeArgs.length)
      {
        typeArgs = baseType.getTypeArguments();
      }

      String[][] types = type.resolveType(superclass);
      if(types != null){
        for(String[] typeInfo : types){
          String typeName = typeInfo[0] + "." + typeInfo[1];
          IType found = type.getJavaProject().findType(typeName);
          if (found != null){
            ITypeParameter[] params = found.getTypeParameters();
            String[] typeParams = new String[params.length];
            for (int ii = 0; ii < params.length; ii++){
              typeParams[ii] = params[ii].getElementName();
            }
            return new TypeInfo(found, typeParams, typeArgs);
          }
        }
      }else{
        IType found = type.getJavaProject().findType(superclass);
        if (found != null){
          return new TypeInfo(found, null, typeArgs);
        }
      }
    }
    return null;
  }

  /**
   * Gets an array of directly implemented interfaces for the supplied type, if
   * any.
   *
   * @param type The type to get the interfaces of.
   * @return Array of interface types.
   */
  public static IType[] getSuperInterfaces(IType type)
    throws Exception
  {
    String[] parents = type.getSuperInterfaceNames();
    ArrayList<IType> interfaces = new ArrayList<IType>(parents.length);
    for(String parent : parents){
      String[][] types = type.resolveType(parent);
      if(types != null){
        for(String[] typeInfo : types){
          String typeName = typeInfo[0] + "." + typeInfo[1];
          IType found = type.getJavaProject().findType(typeName);
          if(found != null){
            interfaces.add(found);
          }
        }
      }else{
        IType found = type.getJavaProject().findType(parent);
        if(found != null){
          interfaces.add(found);
        }
      }
    }
    return interfaces.toArray(new IType[interfaces.size()]);
  }

  /**
   * Recursively gets the interfaces implemented by the given type.
   *
   * @param type The type.
   * @param interfaces The list to add results to.
   * @param includeNotFound Whether or not to include types that were not found
   *  (adds them as handle only IType instances).
   * @param baseType The first type in the recursion stack.
   */
  public static void getInterfaces(
      IType type,
      List<TypeInfo> interfaces,
      boolean includeNotFound,
      TypeInfo baseType)
    throws Exception
  {
    // directly implemented interfaces.
    String[] parentSigs = type.getSuperInterfaceTypeSignatures();
    for(String parentSig : parentSigs){
      String parent = Signature.getSignatureSimpleName(parentSig);

      String[] args = Signature.getTypeArguments(parentSig);
      String[] typeArgs = new String[args.length];
      for (int ii = 0; ii < args.length; ii++){
        typeArgs[ii] = Signature.getSignatureSimpleName(args[ii]);
      }
      if (baseType != null &&
          baseType.getTypeArguments().length == typeArgs.length)
      {
        typeArgs = baseType.getTypeArguments();
      }

      IType found = null;
      String[][] types = type.resolveType(parent);
      if(types != null){
        for(String[] typeInfo : types){
          String typeName = typeInfo[0] + "." + typeInfo[1];
          found = type.getJavaProject().findType(typeName);
        }
      }else{
        found = type.getJavaProject().findType(parent);
      }

      if(found != null){
        ITypeParameter[] params = found.getTypeParameters();
        String[] typeParams = new String[params.length];
        for (int ii = 0; ii < params.length; ii++){
          typeParams[ii] = params[ii].getElementName();
        }
        TypeInfo typeInfo = new TypeInfo(found, typeParams, typeArgs);
        if (!interfaces.contains(typeInfo)){
          interfaces.add(typeInfo);
          if (baseType == null ||
              baseType.getTypeArguments().length !=
                typeInfo.getTypeArguments().length)
          {
            baseType = typeInfo;
          }
          getInterfaces(found, interfaces, includeNotFound, baseType);
        }
      }else if(found == null && includeNotFound){
        String typeName = parent;
        if(typeName != null){
          // get a handle only reference to the super class that wasn't found.
          try{
            found = type.getType(typeName);
            TypeInfo typeInfo = new TypeInfo(found, null, typeArgs);
            if(!interfaces.contains(typeInfo)){
              interfaces.add(typeInfo);
            }
          }catch(Exception e){
            // don't let the error cause the command to fail.
            logger.warn("Unable to get a handle to interface not found: '" +
                typeName + "'", e);
          }
        }
      }else if(found == null){
        logger.warn("Unable to resolve implmented interface '{}' for '{}'",
            parent, type.getFullyQualifiedName());
      }
    }

    // indirectly implemented parents
    TypeInfo superclassInfo = getSuperClass(type);
    if(superclassInfo != null){
      getInterfaces(
          superclassInfo.getType(), interfaces, includeNotFound, superclassInfo);
    }
  }

  /**
   * If the supplied type represents a generic param type, then replace it with
   * the properly concrete type from the supplied type info.
   *
   * @param type The possibly generic param type.
   * @param typeInfo The type info.
   * @return The concrete type.
   */
  public static String replaceTypeParams(String type, TypeInfo typeInfo)
  {
    if(typeInfo != null){
      String[] params = typeInfo.getTypeParameters();
      String[] args = typeInfo.getTypeArguments();
      if (params != null && params.length == args.length){
        for (int ii = 0; ii < params.length; ii++){
          type = type.replaceAll("\\b" + params[ii] + "\\b", args[ii]);
        }
      }
    }
    return type;
  }

  /**
   * Find types by the supplied fully qualified name or unqualified class name.
   *
   * @param javaProject The java project to be searched.
   * @param name The name to search.
   *
   * @return A possibly empty array of IType results found.
   */
  public static IType[] findTypes(IJavaProject javaProject, String name)
    throws Exception
  {
    SearchPattern pattern =
      SearchPattern.createPattern(name,
          IJavaSearchConstants.TYPE,
          IJavaSearchConstants.DECLARATIONS,
          SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
    IJavaSearchScope scope =
      SearchEngine.createJavaSearchScope(new IJavaElement[]{javaProject});
    SearchRequestor requestor = new SearchRequestor();
    SearchEngine engine = new SearchEngine();
    SearchParticipant[] participants =
      new SearchParticipant[]{SearchEngine.getDefaultSearchParticipant()};
    engine.search(pattern, participants, scope, requestor, null);

    ArrayList<IType> types = new ArrayList<IType>();
    if (requestor.getMatches().size() > 0){
      for (SearchMatch match : requestor.getMatches()){
        if(match.getAccuracy() != SearchMatch.A_ACCURATE){
          continue;
        }
        IJavaElement element = (IJavaElement)match.getElement();
        if (element.getElementType() == IJavaElement.TYPE){
          types.add((IType)element);
        }
      }
    }
    return types.toArray(new IType[types.size()]);
  }
}
TOP

Related Classes of org.eclim.plugin.jdt.util.TypeUtils

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.