Package org.pdtextensions.core.util

Source Code of org.pdtextensions.core.util.PDTModelUtils$SourceTypeFinder

/*
* This file is part of the PDT Extensions eclipse plugin.
*
* (c) Robert Gruendler <r.gruendler@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
package org.pdtextensions.core.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.dltk.ast.declarations.MethodDeclaration;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.ast.references.SimpleReference;
import org.eclipse.dltk.ast.references.TypeReference;
import org.eclipse.dltk.core.IMethod;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptFolder;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.SourceParserUtil;
import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.evaluation.types.MultiTypeType;
import org.eclipse.dltk.internal.core.util.LRUCache;
import org.eclipse.dltk.ti.types.IEvaluatedType;
import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.internal.core.Logger;
import org.eclipse.php.internal.core.compiler.ast.nodes.FullyQualifiedReference;
import org.eclipse.php.internal.core.compiler.ast.nodes.NamespaceReference;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocBlock;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocTag;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPDocTagKinds;
import org.eclipse.php.internal.core.compiler.ast.nodes.UsePart;
import org.eclipse.php.internal.core.compiler.ast.visitor.PHPASTVisitor;
import org.eclipse.php.internal.core.index.IPHPDocAwareElement;
import org.eclipse.php.internal.core.model.PhpModelAccess;
import org.eclipse.php.internal.core.typeinference.PHPClassType;
import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
import org.eclipse.php.internal.core.typeinference.PHPSimpleTypes;
import org.eclipse.php.internal.core.typeinference.TraitAliasObject;
import org.eclipse.php.internal.core.typeinference.TraitPrecedenceObject;
import org.eclipse.php.internal.core.typeinference.TraitUtils;
import org.eclipse.php.internal.core.typeinference.UseTrait;
import org.pdtextensions.core.PEXCorePlugin;

/**
*
* PHP Extension Utility class for the PHP model.
*
* @author Robert Gruendler <r.gruendler@gmail.com>
*
*/
@SuppressWarnings("restriction")
public class PDTModelUtils {
  public final static String BACK_SLASH = "\\"; //$NON-NLS-1$
 
  private final static Pattern ARRAY_TYPE_PATTERN = Pattern
      .compile("array\\[.*\\]");   //$NON-NLS-1$

  private static LRUCache typeCache = new LRUCache();
  private static List<String> builtinTypes = new ArrayList<String>(Arrays.asList("array", "static", "self", "parent"));
 
  public static List<IEvaluatedType> collectUseStatements(List<IType> types, boolean includeAbstract) {
   
    List<IEvaluatedType> statements = new ArrayList<IEvaluatedType>();
   
    try {
      for (IType type : types) {
       
        IType currentNamespace = PHPModelUtils.getCurrentNamespace(type);
               
        boolean isInterface = PHPFlags.isInterface(type.getFlags());
        IEvaluatedType evaluated = getEvaluatedType(type.getElementName(), currentNamespace);
       
        if (!statements.contains(evaluated))
          statements.add(evaluated);

        for (IMethod method : type.getMethods()) {
       
          boolean isAbstract = PHPFlags.isAbstract(method.getFlags());
         
          if (!isInterface && isAbstract && includeAbstract) {           
            statements.addAll(collectParameterTypes(method));
          } else if (isInterface) {
            statements.addAll(collectParameterTypes(method));
          }
        }       
      }
    } catch (ModelException e) {
      e.printStackTrace();
    }
       
    return statements;   
   
  }
 
  /**
   * Extension for {@link PHPModelUtils#getSuperTypeHierarchyMethod(IType, String, boolean, IProgressMonitor)}
   *
   * This method looking for non hierarchy also
   *
   * @since 0.18
   */
  public static IMethod[] getSuperTypeHierarchyMethod(IType type, String prefix, boolean exactName, IProgressMonitor monitor) throws CoreException {
    List<IMethod> list = Arrays.asList(PHPModelUtils.getSuperTypeHierarchyMethod(type, prefix, exactName, monitor));
    superTypeHierarchyMethods(list, type, prefix, exactName);
   
    return list.toArray(new IMethod[list.size()]);
  }
 
  private static boolean superTypeHierarchyMethods(List<IMethod> list, IType type, String prefix, boolean exactName) {
    try {
      if ( type.getSuperClasses() == null || type.getSuperClasses().length == 0) {
        return false;
      }
     
      for (String n : type.getSuperClasses()) {
        if (type.getSourceModule().getType(n) != null) {
          final IType sub = type.getSourceModule().getType(n);
          for (IMethod m : sub.getMethods()) {
            if (!list.contains(m) && m.getElementName().equals(prefix) || (!exactName && m.getElementName().startsWith(prefix))) {
              list.add(m);
              return true;
            }
          }
         
          if (superTypeHierarchyMethods(list, sub, prefix, exactName)) {
            return true;
          }
        }
      }
    } catch (ModelException e) {
    }
   
    return false;
  }
 
  public static List<IEvaluatedType> collectParameterTypes(IMethod method) throws ModelException {
   
    List<IEvaluatedType> evaluated = new ArrayList<IEvaluatedType>();
   
    IScriptProject project = method.getScriptProject();
   
    if (project == null)
      return evaluated;
   
    IType currentNamespace = PHPModelUtils.getCurrentNamespace(method);
    String[] typeNames = null;
    if (method instanceof IPHPDocAwareElement) {
      typeNames = ((IPHPDocAwareElement) method).getReturnTypes();
    } else {
      List<String> returnTypeList = new LinkedList<String>();
      PHPDocBlock docBlock = PHPModelUtils.getDocBlock(method);
      if (docBlock == null) {
        return null;
      }
      PHPDocTag[] tags = docBlock.getTags(PHPDocTagKinds.PARAM);
      if (tags != null && tags.length > 0) {
        for (PHPDocTag phpDocTag : tags) {
          if (phpDocTag.getReferences() != null
              && phpDocTag.getReferences().length > 0) {
            for (SimpleReference ref : phpDocTag
                .getReferences()) {
             
              if (ref instanceof TypeReference) {
                String type = ref.getName();
                if (type != null && isValidType(type, project)) {
                  returnTypeList.add(type);
                }               
              }
            }
          }
        }
      }
      typeNames = returnTypeList.toArray(new String[returnTypeList
          .size()]);
    }
    if (typeNames != null) {
      for (String typeName : typeNames) {
        Matcher m = ARRAY_TYPE_PATTERN.matcher(typeName);
        if (m.find()) {
          int offset = 0;
          try {
            offset = method.getSourceRange().getOffset();
          } catch (ModelException e) {
          }
         
          IEvaluatedType t = getArrayType(m.group(), currentNamespace, offset);
          String name = t.getTypeName();
          if (!evaluated.contains(name) && name.startsWith("$"))
            evaluated.add(t);
        } else {

            if (currentNamespace != null) {

              PHPDocBlock docBlock = PHPModelUtils
                  .getDocBlock(method);
              ModuleDeclaration moduleDeclaration = SourceParserUtil
                  .getModuleDeclaration(currentNamespace
                      .getSourceModule());
              if (typeName
                  .indexOf(NamespaceReference.NAMESPACE_SEPARATOR) > 0) {
                // check if the first part
                // is an
                // alias,then get the full
                // name
                String prefix = typeName
                    .substring(
                        0,
                        typeName.indexOf(NamespaceReference.NAMESPACE_SEPARATOR));
                final Map<String, UsePart> result = PHPModelUtils
                    .getAliasToNSMap(prefix,
                        moduleDeclaration,
                        docBlock.sourceStart(),
                        currentNamespace, true);
                if (result.containsKey(prefix)) {
                  String fullName = result.get(prefix)
                      .getNamespace()
                      .getFullyQualifiedName();
                  typeName = typeName.replace(prefix,
                      fullName);
                }
              } else if (typeName
                  .indexOf(NamespaceReference.NAMESPACE_SEPARATOR) < 0) {

                String prefix = typeName;
                final Map<String, UsePart> result = PHPModelUtils
                    .getAliasToNSMap(prefix,
                        moduleDeclaration,
                        docBlock.sourceStart(),
                        currentNamespace, true);
                if (result.containsKey(prefix)) {
                  String fullName = result.get(prefix)
                      .getNamespace()
                      .getFullyQualifiedName();
                  typeName = fullName;
                }
              }
            }
            IEvaluatedType type = getEvaluatedType(typeName,
                currentNamespace);
           
            if (type != null && isValidType(typeName, project) && !evaluated.contains(type.getTypeName()) && !type.getTypeName().startsWith("$")) {             
              evaluated.add(type);
            }
         
        }
      }
    }
   
    return evaluated;   
   
  }
 
  public static IEvaluatedType getEvaluatedType(String typeName,
      IType currentNamespace) {
    IEvaluatedType type = PHPSimpleTypes.fromString(typeName);
    if (type == null) {
      if (typeName.indexOf(NamespaceReference.NAMESPACE_SEPARATOR) != -1
          || currentNamespace == null) {
        type = new PHPClassType(typeName);
      } else if (currentNamespace != null) {
        type = new PHPClassType(currentNamespace.getElementName(),
            typeName);       
      }
    }
    return type;
  }
 
  public static MultiTypeType getArrayType(String type, IType currentNamespace,
      int offset) {
    int beginIndex = type.indexOf("[") + 1;
    int endIndex = type.lastIndexOf("]");
    type = type.substring(beginIndex, endIndex);
    MultiTypeType arrayType = new MultiTypeType();
    Matcher m = ARRAY_TYPE_PATTERN.matcher(type);
    if (m.find()) {
      arrayType
          .addType(getArrayType(m.group(), currentNamespace, offset));
      type = m.replaceAll("");
    }
    String[] typeNames = type.split(",");
    for (String name : typeNames) {
      if (!"".equals(name)) {

        if (name.indexOf(NamespaceReference.NAMESPACE_SEPARATOR) > 0
            && currentNamespace != null) {
          // check if the first part is an
          // alias,then get the full name
          ModuleDeclaration moduleDeclaration = SourceParserUtil
              .getModuleDeclaration(currentNamespace
                  .getSourceModule());
          String prefix = name.substring(0, name
              .indexOf(NamespaceReference.NAMESPACE_SEPARATOR));
          final Map<String, UsePart> result = PHPModelUtils
              .getAliasToNSMap(prefix, moduleDeclaration, offset,
                  currentNamespace, true);
          if (result.containsKey(prefix)) {
            String fullName = result.get(prefix).getNamespace()
                .getFullyQualifiedName();
            name = name.replace(prefix, fullName);
          }
        }
        arrayType.addType(getEvaluatedType(name, currentNamespace));
      }
    }
    return arrayType;
  }
 
 
  public static String getMethodSignature(MethodDeclaration method, IScriptProject project) {
   
    String signature = method.getName().toLowerCase();
    return signature;
//    Integer num = new Integer(method.getArguments().size());
//   
//    if (signature.equals("current")) {
//      System.err.println("c: " + num);
//    }
   
//    return signature + num.toString();
   
//    for (Object o: method.getArguments()) {
//
//      try {
//        FormalParameter param = (FormalParameter) o;
//
//        SimpleReference type = param.getParameterType();
//        if (type != null && isValidType(type.getName(), project)) {
//         
//          if (signature.startsWith("setmetadatafor")) {
//            System.err.println(": " + param.getParameterType().getName().toLowerCase()); 
//          }
//         
//          signature += param.getParameterType().getName().toLowerCase();                   
//        }
//       
//      } catch (ClassCastException e) {
//
//      }
//    }
//   
//    return signature;
       
  }
 
  public static String getMethodSignature(IMethod method) {
   
    try {
      String methodSignature = method.getElementName().toLowerCase();
      return methodSignature;
     
//      Integer num = new Integer(method.getParameters().length);
//     
//      if (methodSignature.equals("current")) {
//          System.err.println(num);
//      }
//
//      return methodSignature + num;
    } catch (Exception e) {
      return "";
    }
   
//    try {
//      for (IParameter param: method.getParameters()) {       
//        try {
//         
//          if (isValidType(param.getType(), method.getScriptProject())) {           
//            if (methodSignature.startsWith("setmetadatafor")) {
//              System.err.println(param.getType());
//            }
//            methodSignature += param.getType().toLowerCase();           
//          }
//         
//        } catch (ClassCastException e) {
//
//        }
//      }
//    } catch (ModelException e) {
//      e.printStackTrace();
//    }
//   
//    return methodSignature;
   
   
 
 
  public static boolean isBuiltinType(String type) {
   
    return builtinTypes.contains(type);
  }

  public static boolean isValidType(String type, IScriptProject project) {
   
      if (builtinTypes.contains(type)) {
          return true;
      }
     
    String key = type + project.getElementName();
   
    if (typeCache.get(key) != null)
      return (Boolean) typeCache.get(key);
   
    if (type == null || "object".equals(type))
      return (Boolean) typeCache.put(key, new Boolean(false));
   
    IDLTKSearchScope scope = SearchEngine.createSearchScope(project);
    IType[] types = PhpModelAccess.getDefault().findTypes(type, MatchRule.EXACT, 0, 0,
        scope, new NullProgressMonitor());
   
    return (Boolean) typeCache.put(key, new Boolean(types.length > 0));
   
  }
 
 
  /**
   * Get full list of imported trait methods
   *
   * Entry<ImportedName, IMethod_from_trait>
   *
   * @param type
   * @return
   */
  public static Map<String, IMethod> getImportedMethods(IType type) {
    Map<String, IMethod> ret = new HashMap<String, IMethod>();
   
    UseTrait parsed = TraitUtils.parse(type);
    IDLTKSearchScope scope = TraitUtils.createSearchScope(type);
   
    Map<String, IType> traits = new HashMap<String, IType>();
    Set<String> usedMethods = new HashSet<String>();
    for (String traitName : parsed.getTraits()) {
      if (findType(type.getSourceModule(), traitName) != null) {
        traits.put(traitName, findType(type.getSourceModule(), traitName)); // out of index
        continue;
      }
      IType[] traitTypes = PhpModelAccess.getDefault().findTraits(traitName, MatchRule.EXACT, 0, 0, scope, new NullProgressMonitor());
      if (traitTypes.length != 1) {
        continue; //more than one ignore it
      }
     
      traits.put(traitName, traitTypes[0]);
    }
   
    if (traits.size() == 0) {
      return ret;
    }
   
    //load aliases
    for (TraitAliasObject alias : parsed.getTraitAliases()) {
      IType trait = traits.get(alias.traitName);
      if (trait == null) {
        continue;
      }

      IMethod[] methods;
      try {
       
        methods = PHPModelUtils.getTypeMethod(trait, alias.traitMethodName, true);
        if (methods.length != 1) {
          continue;
        }
        usedMethods.add(alias.traitName + "::" + alias.traitMethodName);
        ret.put(alias.newMethodName, methods[0]);
      } catch (ModelException e) {
        Logger.logException(e);
      }
    }
   
    //load precedences
    for (Entry<String, TraitPrecedenceObject> entry : parsed.getPrecedenceMap().entrySet()) {
      IType trait = traits.get(entry.getValue().traitName);
      if (trait == null) {
        continue;
      }
     
      IMethod[] methods;
      try {
        methods = PHPModelUtils.getTypeMethod(trait, entry.getValue().traitMethodName, true);
        if (methods.length != 1) {
          continue;
        }
       
        usedMethods.add(entry.getValue().traitName + "::" + entry.getValue().traitMethodName);
        ret.put(entry.getValue().traitMethodName, methods[0]);
      } catch (ModelException e) {
        Logger.logException(e);
      }
   
    }
   
   
    // load other methods
    for (Entry<String, IType> entry : traits.entrySet()) {
      try {
        IMethod[] methods = PHPModelUtils.getTypeMethod(entry.getValue(), "", false);
        for (IMethod method : methods) {
          if (!ret.containsKey(method.getElementName()) && !usedMethods.contains(entry.getKey() + "::" + method.getElementName())) {
            usedMethods.add(entry.getKey() + "::" + method.getElementName());
            ret.put(method.getElementName(), method);
            continue;
          }
        }
      } catch (ModelException e) {
        Logger.logException(e);
      }
    }
   
    return ret;
  }

  /**
   * @since 0.17.0
   */
  public static IModelElement getSourceElement(IModelElement element, int offset, int length) throws CoreException {
    Assert.isNotNull(element);

    ISourceModule sourceModule = (ISourceModule) element.getAncestor(IModelElement.SOURCE_MODULE);
    if (sourceModule == null) return null;

    return getSourceElement(sourceModule, offset, length);
  }

  /**
   * @since 0.17.0
   */
  public static IModelElement getSourceElement(ISourceModule sourceModule, int offset, int length) throws CoreException {
    Assert.isNotNull(sourceModule);

    IModelElement[] sourceElements = sourceModule.codeSelect(offset, length);
    if (sourceElements.length > 0) {
      if (sourceElements[0].getElementType() == IModelElement.METHOD && ((IMethod) sourceElements[0]).isConstructor()) {
        IType sourceType = fixInvalidSourceElement((IMethod) sourceElements[0], offset, length);
        if (sourceType != null) {
          return sourceType;
        }
      }

      return sourceElements[0];
    } else {
      return null;
    }
  }

  /**
   * @since 0.17.0
   */
  private static IType fixInvalidSourceElement(IMethod sourceElement, int offset, int length) throws CoreException {
    ModuleDeclaration moduleDeclaration = SourceParserUtil.getModuleDeclaration(sourceElement.getSourceModule());
    if (moduleDeclaration != null) {
      SourceTypeFinder sourceTypeFinder = new PDTModelUtils().new SourceTypeFinder(sourceElement.getSourceModule(), offset, length);

      try {
        moduleDeclaration.traverse(sourceTypeFinder);
      } catch (Exception e) {
        throw new CoreException(new Status(IStatus.ERROR, PEXCorePlugin.PLUGIN_ID, e.getMessage(), e));
      }

      return sourceTypeFinder.getSourceType();
    }

    return null;
  }

  /**
   * @since 0.17.0
   */
  private class SourceTypeFinder extends PHPASTVisitor {
    private ISourceModule sourceModule;
    private int offset;
    private int length;
    private IType sourceType;

    public SourceTypeFinder(ISourceModule sourceModule, int offset, int length) {
      this.sourceModule = sourceModule;
      this.offset = offset;
      this.length = length;
    }

    @Override
    public boolean visit(FullyQualifiedReference s) throws Exception {
      if (s.sourceStart() <= offset && s.sourceEnd() >= offset + length) {
        IType[] sourceTypes = PDTTypeInferenceUtils.getTypes(s, sourceModule);
        if (sourceTypes.length > 0) {
          sourceType = sourceTypes[0];

          return false;
        }
      }

      return true;
    }

    public IType getSourceType() {
      return sourceType;
    }
  }

  /**
   * Allow to find IType in current module (source file)
   *
   * @since 0.18
   */
  public static IType findType(ISourceModule module, String fqn) {
    try {
      for (IType t : module.getAllTypes()) {
        if (t.getFullyQualifiedName(BACK_SLASH).equals(fqn)) {
          return t;
        }
      }
    } catch (ModelException e) {
      e.printStackTrace();
    }
   
    return null;
  }
 
 
  /**
   * Ease method to select to find IType (Classes, Interfaces, Traits) by FQN
   *
   * @since 0.18
   */
  public static IType[] findTypes(IScriptProject project, String fqn) {
    Set<IType> list = new HashSet<IType>();
   
    IDLTKSearchScope searchScope = SearchEngine.createSearchScope(project);
    IType[] types = PhpModelAccess.getDefault().findTypes(fqn,
        MatchRule.EXACT, 0, 0, searchScope, new NullProgressMonitor());

    for (IType type : types) {
      if (fqn.equals(type.getFullyQualifiedName(BACK_SLASH))) {
        list.add(type);
      }
    }

    types = PhpModelAccess.getDefault().findTraits(fqn,
        MatchRule.EXACT, 0, 0, searchScope, new NullProgressMonitor());

    for (IType type : types) {
      if (fqn.equals(type.getFullyQualifiedName(BACK_SLASH))) {
        list.add(type);
      }
    }
   
    return list.toArray(new IType[list.size()]);
  }
 
  /**
   * Too slow on startup
   * Because sometimes DLTK index is not ready (for ex. while start), force options allow to search file by file.
   *
   * @since 0.18
   */
  public static IType[] findTypes(IScriptProject project, String fqn, boolean force) throws ModelException {
    if (!force) {
      return findTypes(project, fqn);
    }
    Set<IType> list = new HashSet<IType>();
    for (IProjectFragment f : project.getAllProjectFragments()) {
      rawSearch(list, f, fqn);
    }
   
    return list.toArray(new IType[list.size()]);
  }
 
  private static void rawSearch(Set<IType> list, IModelElement el, String name) throws ModelException {
    if (el instanceof IScriptFolder ) {
      for (IModelElement sub : ((IScriptFolder) el).getChildren()) {
        rawSearch(list, sub, name);
      }
    } else if (el instanceof IProjectFragment ) {
      for (IModelElement sub : ((IProjectFragment) el).getChildren()) {
        rawSearch(list, sub, name);
      }
    } else if (el instanceof ISourceModule){
      ISourceModule mod = (ISourceModule) el;
      for (IType t : mod.getAllTypes()) {
        if (t.getFullyQualifiedName(BACK_SLASH).equals(name)) {
         
          list.add(t);
        }
      }
    }
   
  }

  /**
   * @since 0.22.0
   */
  public static boolean inResourceWithSameName(IResource resource, String typeName) throws CoreException {
    if (resource instanceof IFile) {
      return resource.getName().substring(0, resource.getName().indexOf(resource.getFileExtension()) - 1).equals(typeName);
    } else if (resource instanceof IFolder) {
      return resource.getName().equals(typeName.substring(typeName.lastIndexOf(BACK_SLASH) + 1));
    } else {
      throw new CoreException(new Status(IStatus.ERROR, PEXCorePlugin.PLUGIN_ID, "The resource is neither a file or folder")); //$NON-NLS-1$
    }
  }
}
TOP

Related Classes of org.pdtextensions.core.util.PDTModelUtils$SourceTypeFinder

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.