Package org.eclipse.jdt.internal.core.hierarchy

Source Code of org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver

/*******************************************************************************
* Copyright (c) 2000, 2014 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
*     Stephan Herrmann - contribution for Bug 300576 - NPE Computing type hierarchy when compliance doesn't match libraries
*******************************************************************************/
package org.eclipse.jdt.internal.core.hierarchy;

/**
* This is the public entry point to resolve type hierarchies.
*
* When requesting additional types from the name environment, the resolver
* accepts all forms (binary, source & compilation unit) for additional types.
*
* Side notes: Binary types already know their resolved supertypes so this
* only makes sense for source types. Even though the compiler finds all binary
* types to complete the hierarchy of a given source type, is there any reason
* why the requestor should be informed that binary type X subclasses Y &
* implements I & J?
*/

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.util.Messages;
import org.eclipse.jdt.internal.core.*;
import org.eclipse.jdt.internal.core.util.ASTNodeFinder;
import org.eclipse.jdt.internal.core.util.HandleFactory;

@SuppressWarnings({"rawtypes", "unchecked"})
public class HierarchyResolver implements ITypeRequestor {

  private ReferenceBinding focusType;
  private boolean superTypesOnly;
  private boolean hasMissingSuperClass;
  LookupEnvironment lookupEnvironment;
  private CompilerOptions options;
  HierarchyBuilder builder;
  private ReferenceBinding[] typeBindings;

  private int typeIndex;
  private IGenericType[] typeModels;

  private static final CompilationUnitDeclaration FakeUnit;
  static {
    IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitAfterAllProblems();
    ProblemReporter problemReporter = new ProblemReporter(policy, new CompilerOptions(), new DefaultProblemFactory());
    CompilationResult result = new CompilationResult(CharOperation.NO_CHAR, 0, 0, 0);
    FakeUnit = new CompilationUnitDeclaration(problemReporter, result, 0);
  }

public HierarchyResolver(INameEnvironment nameEnvironment, Map settings, HierarchyBuilder builder, IProblemFactory problemFactory) {
  // create a problem handler with the 'exit after all problems' handling policy
  this.options = new CompilerOptions(settings);
  IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitAfterAllProblems();
  ProblemReporter problemReporter = new ProblemReporter(policy, this.options, problemFactory);

  LookupEnvironment environment = new LookupEnvironment(this, this.options, problemReporter, nameEnvironment);
  environment.mayTolerateMissingType = true;
  setEnvironment(environment, builder);
}
public HierarchyResolver(LookupEnvironment lookupEnvironment, HierarchyBuilder builder) {
  setEnvironment(lookupEnvironment, builder);
}

/**
* Add an additional binary type
* @param binaryType
* @param packageBinding
*/
public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
  IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
  if (progressMonitor != null && progressMonitor.isCanceled())
    throw new OperationCanceledException();

  BinaryTypeBinding typeBinding = this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
  try {
    this.remember(binaryType, typeBinding);
  } catch (AbortCompilation e) {
    // ignore
  }
}

/**
* Add an additional compilation unit.
* @param sourceUnit
*/
public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
  //System.out.println("Cannot accept compilation units inside the HierarchyResolver.");
  this.lookupEnvironment.problemReporter.abortDueToInternalError(
    new StringBuffer(Messages.accept_cannot)
      .append(sourceUnit.getFileName())
      .toString());
}

/**
* Add additional source types
* @param sourceTypes
* @param packageBinding
*/
public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
  IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
  if (progressMonitor != null && progressMonitor.isCanceled())
    throw new OperationCanceledException();

  // find most enclosing type first (needed when explicit askForType(...) is done
  // with a member type (e.g. p.A$B))
  ISourceType sourceType = sourceTypes[0];
  while (sourceType.getEnclosingType() != null)
    sourceType = sourceType.getEnclosingType();

  // build corresponding compilation unit
  CompilationResult result = new CompilationResult(sourceType.getFileName(), 1, 1, this.options.maxProblemsPerUnit);
  CompilationUnitDeclaration unit =
    SourceTypeConverter.buildCompilationUnit(
      new ISourceType[] {sourceType}, // ignore secondary types, to improve laziness
      SourceTypeConverter.MEMBER_TYPE | (this.lookupEnvironment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8 ? SourceTypeConverter.METHOD : 0), // need member types
      // no need for field initialization
      this.lookupEnvironment.problemReporter,
      result);

  // build bindings
  if (unit != null) {
    try {
      this.lookupEnvironment.buildTypeBindings(unit, accessRestriction);

      org.eclipse.jdt.core.ICompilationUnit cu = ((SourceTypeElementInfo)sourceType).getHandle().getCompilationUnit();
      rememberAllTypes(unit, cu, false);

      this.lookupEnvironment.completeTypeBindings(unit, true/*build constructor only*/);
    } catch (AbortCompilation e) {
      // missing 'java.lang' package: ignore
    }
  }
}
/*
* Creates the super class handle of the given type.
* Returns null if the type has no super class.
* Adds the simple name to the hierarchy missing types if the class is not found and returns null.
*/
private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
  ReferenceBinding superBinding = typeBinding.superclass();

  if (superBinding != null) {
    superBinding = (ReferenceBinding) superBinding.erasure();
    if (typeBinding.isHierarchyInconsistent()) {
      if (superBinding.problemId() == ProblemReasons.NotFound) {
        this.hasMissingSuperClass = true;
        this.builder.hierarchy.missingTypes.add(new String(superBinding.sourceName)); // note: this could be Map$Entry
        return null;
      } else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
        char[] superclassName;
        char separator;
        if (type instanceof IBinaryType) {
          superclassName = ((IBinaryType)type).getSuperclassName();
          separator = '/';
        } else if (type instanceof ISourceType) {
          superclassName = ((ISourceType)type).getSuperclassName();
          separator = '.';
        } else if (type instanceof HierarchyType) {
          superclassName = ((HierarchyType)type).superclassName;
          separator = '.';
        } else {
          return null;
        }

        if (superclassName != null) { // check whether subclass of Object due to broken hierarchy (as opposed to explicitly extending it)
          int lastSeparator = CharOperation.lastIndexOf(separator, superclassName);
          char[] simpleName = lastSeparator == -1 ? superclassName : CharOperation.subarray(superclassName, lastSeparator+1, superclassName.length);
          if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
            this.hasMissingSuperClass = true;
            this.builder.hierarchy.missingTypes.add(new String(simpleName));
            return null;
          }
        }
      }
    }
    for (int t = this.typeIndex; t >= 0; t--) {
      if (TypeBinding.equalsEquals(this.typeBindings[t], superBinding)) {
        return this.builder.getHandle(this.typeModels[t], superBinding);
      }
    }
  }
  return null;
}
/*
* Returns the handles of the super interfaces of the given type.
* Adds the simple name to the hierarchy missing types if an interface is not found (but don't put null in the returned array)
*/
private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBinding) {
  char[][] superInterfaceNames;
  char separator;
  if (type instanceof IBinaryType) {
    superInterfaceNames = ((IBinaryType)type).getInterfaceNames();
    separator = '/';
  } else if (type instanceof ISourceType) {
    ISourceType sourceType = (ISourceType)type;
    if (sourceType.isAnonymous()) { // if anonymous type
      if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
        superInterfaceNames = new char[][] {sourceType.getSuperclassName()};
      } else {
        superInterfaceNames = sourceType.getInterfaceNames();
      }
    } else {
      if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL)
        superInterfaceNames = new char[][] {TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION};
      else
        superInterfaceNames = sourceType.getInterfaceNames();
    }
    separator = '.';
  } else if (type instanceof HierarchyType) {
    HierarchyType hierarchyType = (HierarchyType)type;
    if (hierarchyType.isAnonymous()) { // if anonymous type
      if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
        superInterfaceNames = new char[][] {hierarchyType.superclassName};
      } else {
        superInterfaceNames = hierarchyType.superInterfaceNames;
      }
    } else {
      superInterfaceNames = hierarchyType.superInterfaceNames;
    }
    separator = '.';
  } else{
    return null;
  }

  ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
  int bindingIndex = 0;
  int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length;
  int length = superInterfaceNames == null ? 0 : superInterfaceNames.length;
  IType[] superinterfaces = new IType[length];
  int index = 0;
  next : for (int i = 0; i < length; i++) {
    char[] superInterfaceName = superInterfaceNames[i];
    int end = superInterfaceName.length;

    // find the end of simple name
    int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName);
    if (genericStart != -1) end = genericStart;

    // find the start of simple name
    int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName, 0, end);
    int start = lastSeparator + 1;

    // case of binary inner type -> take the last part
    int lastDollar = CharOperation.lastIndexOf('$', superInterfaceName, start);
    if (lastDollar != -1) start = lastDollar + 1;

    char[] simpleName = CharOperation.subarray(superInterfaceName, start, end);

    if (bindingIndex < bindingLength) {
      ReferenceBinding interfaceBinding = (ReferenceBinding) interfaceBindings[bindingIndex].erasure();

      // ensure that the binding corresponds to the interface defined by the user
      if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
        bindingIndex++;
        for (int t = this.typeIndex; t >= 0; t--) {
          if (TypeBinding.equalsEquals(this.typeBindings[t], interfaceBinding)) {
            IType handle = this.builder.getHandle(this.typeModels[t], interfaceBinding);
            if (handle != null) {
              superinterfaces[index++] = handle;
              continue next;
            }
          }
        }
      }
    }
    this.builder.hierarchy.missingTypes.add(new String(simpleName));
  }
  if (index != length)
    System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index);
  return superinterfaces;
}
/*
* For all type bindings that have hierarchy problems, artificially fix their superclass/superInterfaces so that the connection
* can be made.
*/
private void fixSupertypeBindings() {
  for (int current = this.typeIndex; current >= 0; current--) {
    ReferenceBinding typeBinding = this.typeBindings[current];
    if ((typeBinding.tagBits & TagBits.HierarchyHasProblems) == 0)
      continue;

    if (typeBinding instanceof SourceTypeBinding) {
      if (typeBinding instanceof LocalTypeBinding) {
        LocalTypeBinding localTypeBinding = (LocalTypeBinding) typeBinding;
        QualifiedAllocationExpression allocationExpression = localTypeBinding.scope.referenceContext.allocation;
        TypeReference type;
        if (allocationExpression != null && (type = allocationExpression.type) != null && type.resolvedType != null) {
          localTypeBinding.setSuperClass((ReferenceBinding) type.resolvedType);
          continue;
        }
      }
      ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
      if (scope != null) {
        TypeDeclaration typeDeclaration = scope.referenceContext;
        TypeReference superclassRef = typeDeclaration == null ? null : typeDeclaration.superclass;
        TypeBinding superclass = superclassRef == null ? null : superclassRef.resolvedType;
        if (superclass != null) {
          superclass = superclass.closestMatch();
        }
        if (superclass instanceof ReferenceBinding) {
          // ensure we are not creating a cycle (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=215681 )
          if (!(subTypeOfType((ReferenceBinding) superclass, typeBinding))) {
            ((SourceTypeBinding) typeBinding).setSuperClass((ReferenceBinding) superclass);
          }
        }

        TypeReference[] superInterfaces = typeDeclaration == null ? null : typeDeclaration.superInterfaces;
        int length;
        ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
        if (superInterfaces != null && (length = superInterfaces.length) > (interfaceBindings == null ? 0 : interfaceBindings.length)) { // check for interfaceBindings being null (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=139689)
          interfaceBindings = new ReferenceBinding[length];
          int index = 0;
          for (int i = 0; i < length; i++) {
            TypeBinding superInterface = superInterfaces[i].resolvedType;
            if (superInterface != null) {
              superInterface = superInterface.closestMatch();
            }
            if (superInterface instanceof ReferenceBinding) {
              // ensure we are not creating a cycle (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=215681 )
              if (!(subTypeOfType((ReferenceBinding) superInterface, typeBinding))) {
                interfaceBindings[index++] = (ReferenceBinding) superInterface;
              }
            }
          }
          if (index < length)
            System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[index], 0 , index);
          ((SourceTypeBinding) typeBinding).setSuperInterfaces(interfaceBindings);
        }
      }
    } else if (typeBinding instanceof BinaryTypeBinding) {
      try {
        typeBinding.superclass();
      } catch (AbortCompilation e) {
        // allow subsequent call to superclass() to succeed so that we don't have to catch AbortCompilation everywhere
        ((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperclass;
        this.builder.hierarchy.missingTypes.add(new String(typeBinding.superclass().sourceName()));
        this.hasMissingSuperClass = true;
      }
      try {
        typeBinding.superInterfaces();
      } catch (AbortCompilation e) {
        // allow subsequent call to superInterfaces() to succeed so that we don't have to catch AbortCompilation everywhere
        ((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperinterfaces;
      }
    }
  }
}
private void remember(IGenericType suppliedType, ReferenceBinding typeBinding) {
  if (typeBinding == null) return;

  if (++this.typeIndex == this.typeModels.length) {
    System.arraycopy(this.typeModels, 0, this.typeModels = new IGenericType[this.typeIndex * 2], 0, this.typeIndex);
    System.arraycopy(this.typeBindings, 0, this.typeBindings = new ReferenceBinding[this.typeIndex * 2], 0, this.typeIndex);
  }
  this.typeModels[this.typeIndex] = suppliedType;
  this.typeBindings[this.typeIndex] = typeBinding;
}
private void remember(IType type, ReferenceBinding typeBinding) {
  if (((CompilationUnit)type.getCompilationUnit()).isOpen()) {
    try {
      IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo();
      remember(genericType, typeBinding);
    } catch (JavaModelException e) {
      // cannot happen since element is open
      return;
    }
  } else {
    if (typeBinding == null) return;
    boolean isAnonymous = false;
    try {
      isAnonymous = type.isAnonymous();
    } catch(JavaModelException jme) {
      // Ignore
    }
    if (typeBinding instanceof SourceTypeBinding) {
      TypeDeclaration typeDeclaration = ((SourceTypeBinding)typeBinding).scope.referenceType();

      // simple super class name
      char[] superclassName = null;
      TypeReference superclass;
      if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
        superclass = typeDeclaration.allocation.type;
      } else {
        superclass = typeDeclaration.superclass;
      }
      if (superclass != null) {
        char[][] typeName = superclass.getTypeName();
        superclassName = typeName == null ? null : typeName[typeName.length-1];
      }

      // simple super interface names
      char[][] superInterfaceNames = null;
      TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
      if (superInterfaces != null) {
        int length = superInterfaces.length;
        superInterfaceNames = new char[length][];
        for (int i = 0; i < length; i++) {
          TypeReference superInterface = superInterfaces[i];
          char[][] typeName = superInterface.getTypeName();
          superInterfaceNames[i] = typeName[typeName.length-1];
        }
      }

      HierarchyType hierarchyType = new HierarchyType(
          type,
          typeDeclaration.name,
          typeDeclaration.binding.modifiers,
          superclassName,
          superInterfaceNames,
          isAnonymous);
      remember(hierarchyType, typeDeclaration.binding);
    } else {
      HierarchyType hierarchyType = new HierarchyType(
          type,
          typeBinding.sourceName(),
          typeBinding.modifiers,
          typeBinding.superclass().sourceName(),
          new char [][] { typeBinding.superInterfaces()[0].sourceName() },
          isAnonymous);
      remember(hierarchyType, typeBinding);
    }
  }

}
/*
* Remembers all type bindings defined in the given parsed unit, adding local/anonymous types if specified.
*/
private void rememberAllTypes(CompilationUnitDeclaration parsedUnit, org.eclipse.jdt.core.ICompilationUnit cu, boolean includeLocalTypes) {
  TypeDeclaration[] types = parsedUnit.types;
  if (types != null) {
    for (int i = 0, length = types.length; i < length; i++) {
      TypeDeclaration type = types[i];
      rememberWithMemberTypes(type, cu.getType(new String(type.name)));
    }
  }
  if (!includeLocalTypes || (parsedUnit.localTypes == null && parsedUnit.functionalExpressions == null))
    return;
 
  HandleFactory factory = new HandleFactory();
  HashSet existingElements = new HashSet(parsedUnit.localTypeCount + parsedUnit.functionalExpressionsCount);
  HashMap knownScopes = new HashMap(parsedUnit.localTypeCount + parsedUnit.functionalExpressionsCount);
 
  if (parsedUnit.localTypes != null) {
    for (int i = 0; i < parsedUnit.localTypeCount; i++) {
      LocalTypeBinding localType = parsedUnit.localTypes[i];
      ClassScope classScope = localType.scope;
      TypeDeclaration typeDecl = classScope.referenceType();
      IType typeHandle = (IType)factory.createElement(classScope, cu, existingElements, knownScopes);
      rememberWithMemberTypes(typeDecl, typeHandle);
    }
  }
  if (parsedUnit.functionalExpressions != null) {
    for (int i = 0; i < parsedUnit.functionalExpressionsCount; i++) {
      if (parsedUnit.functionalExpressions[i] instanceof LambdaExpression) {
        final LambdaExpression expression = (LambdaExpression) parsedUnit.functionalExpressions[i];
        if (expression.resolvedType != null && expression.resolvedType.isValidBinding()) {
          IType typeHandle = (IType)factory.createLambdaTypeElement(expression, cu, existingElements, knownScopes);
          remember(typeHandle, expression.getTypeBinding());
        }
      }
    }
  }
}
private void rememberWithMemberTypes(TypeDeclaration typeDecl, IType typeHandle) {
  remember(typeHandle, typeDecl.binding);

  TypeDeclaration[] memberTypes = typeDecl.memberTypes;
  if (memberTypes != null) {
    for (int i = 0, length = memberTypes.length; i < length; i++) {
      TypeDeclaration memberType = memberTypes[i];
      rememberWithMemberTypes(memberType, typeHandle.getType(new String(memberType.name)));
    }
  }
}
/*
* Reports the hierarchy from the remembered bindings.
* Note that 'binaryTypeBinding' is null if focus type is a source type.
*/
private void reportHierarchy(IType focus, TypeDeclaration focusLocalType, ReferenceBinding binaryTypeBinding) {

  // set focus type binding
  if (focus != null) {
    if (binaryTypeBinding != null) {
      // binary type
      this.focusType = binaryTypeBinding;
    } else {
      // source type
      if (focusLocalType != null) {
        // anonymous or local type
        this.focusType = focusLocalType.binding;
      } else {
        // top level or member type
        char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray();
        setFocusType(CharOperation.splitOn('.', fullyQualifiedName));
      }
    }
  }

  // be resilient and fix super type bindings
  fixSupertypeBindings();

  int objectIndex = -1;
  IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
  for (int current = this.typeIndex; current >= 0; current--) {
    if (progressMonitor != null && progressMonitor.isCanceled())
      throw new OperationCanceledException();
   
    ReferenceBinding typeBinding = this.typeBindings[current];

    // java.lang.Object treated at the end
    if (typeBinding.id == TypeIds.T_JavaLangObject) {
      objectIndex = current;
      continue;
    }

    IGenericType suppliedType = this.typeModels[current];

    if (!subOrSuperOfFocus(typeBinding)) {
      continue; // ignore types outside of hierarchy
    }

    IType superclass;
    if (typeBinding.isInterface()){ // do not connect interfaces to Object
      superclass = null;
    } else {
      superclass = findSuperClass(suppliedType, typeBinding);
    }
    IType[] superinterfaces = findSuperInterfaces(suppliedType, typeBinding);

    this.builder.connect(suppliedType, this.builder.getHandle(suppliedType, typeBinding), superclass, superinterfaces);
  }
  // add java.lang.Object only if the super class is not missing
  if (objectIndex > -1 && (!this.hasMissingSuperClass || this.focusType == null)) {
    IGenericType objectType = this.typeModels[objectIndex];
    this.builder.connect(objectType, this.builder.getHandle(objectType, this.typeBindings[objectIndex]), null, null);
  }
}
private void reset(){
  this.lookupEnvironment.reset();

  this.focusType = null;
  this.superTypesOnly = false;
  this.typeIndex = -1;
  this.typeModels = new IGenericType[5];
  this.typeBindings = new ReferenceBinding[5];
}

/**
* Resolve the supertypes for the supplied source type.
* Inform the requestor of the resolved supertypes using:
*    connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
* @param suppliedType
*/
public void resolve(IGenericType suppliedType) {
  try {
    if (suppliedType.isBinaryType()) {
      BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType((IBinaryType) suppliedType, false/*don't need field and method (bug 125067)*/, null /*no access restriction*/);
      remember(suppliedType, binaryTypeBinding);
      // We still need to add superclasses and superinterfaces bindings (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53095)
      int startIndex = this.typeIndex;
      for (int i = startIndex; i <= this.typeIndex; i++) {
        IGenericType igType = this.typeModels[i];
        if (igType != null && igType.isBinaryType()) {
          CompilationUnitDeclaration previousUnitBeingCompleted = this.lookupEnvironment.unitBeingCompleted;
          // fault in its hierarchy...
          try {
            // ensure that unitBeingCompleted is set so that we don't get an AbortCompilation for a missing type
            // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=213249 )
            if (previousUnitBeingCompleted == null) {
              this.lookupEnvironment.unitBeingCompleted = FakeUnit;
            }
            ReferenceBinding typeBinding = this.typeBindings[i];
            typeBinding.superclass();
            typeBinding.superInterfaces();
          } catch (AbortCompilation e) {
            // classpath problem for this type: ignore
          } finally {
            this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted;
          }
        }
      }
      this.superTypesOnly = true;
      reportHierarchy(this.builder.getType(), null, binaryTypeBinding);
    } else {
      org.eclipse.jdt.core.ICompilationUnit cu = ((SourceTypeElementInfo)suppliedType).getHandle().getCompilationUnit();
      if (cu != null) {
        HashSet localTypes = new HashSet();
        localTypes.add(cu.getPath().toString());
        this.superTypesOnly = true;
        resolve(new Openable[] {(Openable)cu}, localTypes, null);
      }
    }
  } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
  } finally {
    reset();
  }
}

/**
* Resolve the supertypes for the types contained in the given openables (ICompilationUnits and/or IClassFiles).
* Inform the requestor of the resolved supertypes for each
* supplied source type using:
*    connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
*
* Also inform the requestor of the supertypes of each
* additional requested super type which is also a source type
* instead of a binary type.
* @param openables
* @param localTypes
* @param monitor
*/
public void resolve(Openable[] openables, HashSet localTypes, IProgressMonitor monitor) {
  try {
    int openablesLength = openables.length;
    CompilationUnitDeclaration[] parsedUnits = new CompilationUnitDeclaration[openablesLength];
    boolean[] hasLocalType = new boolean[openablesLength];
    org.eclipse.jdt.core.ICompilationUnit[] cus = new org.eclipse.jdt.core.ICompilationUnit[openablesLength];
    int unitsIndex = 0;

    CompilationUnitDeclaration focusUnit = null;
    ReferenceBinding focusBinaryBinding = null;
    IType focus = this.builder.getType();
    Openable focusOpenable = null;
    if (focus != null) {
      if (focus.isBinary()) {
        focusOpenable = (Openable)focus.getClassFile();
      } else {
        focusOpenable = (Openable)focus.getCompilationUnit();
      }
    }

    // build type bindings
    Parser parser = new Parser(this.lookupEnvironment.problemReporter, true);
    final boolean isJava8 = this.options.sourceLevel >= ClassFileConstants.JDK1_8;
    for (int i = 0; i < openablesLength; i++) {
      Openable openable = openables[i];
      if (openable instanceof org.eclipse.jdt.core.ICompilationUnit) {
        org.eclipse.jdt.core.ICompilationUnit cu = (org.eclipse.jdt.core.ICompilationUnit)openable;

        // contains a potential subtype as a local or anonymous type?
        boolean containsLocalType = false;
        if (localTypes == null) { // case of hierarchy on region
          containsLocalType = true;
        } else {
          IPath path = cu.getPath();
          containsLocalType = cu.isWorkingCopy() ? true /* presume conservatively */ : localTypes.contains(path.toString());
        }

        // build parsed unit
        CompilationUnitDeclaration parsedUnit = null;
        if (cu.isOpen()) {
          // create parsed unit from source element infos
          CompilationResult result = new CompilationResult((ICompilationUnit)cu, i, openablesLength, this.options.maxProblemsPerUnit);
          SourceTypeElementInfo[] typeInfos = null;
          try {
            IType[] topLevelTypes = cu.getTypes();
            int topLevelLength = topLevelTypes.length;
            if (topLevelLength == 0) continue; // empty cu: no need to parse (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=65677)
            typeInfos = new SourceTypeElementInfo[topLevelLength];
            for (int j = 0; j < topLevelLength; j++) {
              IType topLevelType = topLevelTypes[j];
              typeInfos[j] = (SourceTypeElementInfo)((JavaElement)topLevelType).getElementInfo();
            }
          } catch (JavaModelException e) {
            // types/cu exist since cu is opened
          }
          int flags = !containsLocalType
            ? SourceTypeConverter.MEMBER_TYPE | (isJava8 ? SourceTypeConverter.METHOD : 0)
            : SourceTypeConverter.FIELD_AND_METHOD | SourceTypeConverter.MEMBER_TYPE | SourceTypeConverter.LOCAL_TYPE;
          parsedUnit =
            SourceTypeConverter.buildCompilationUnit(
              typeInfos,
              flags,
              this.lookupEnvironment.problemReporter,
              result);
         
          // We would have got all the necessary local types by now and hence there is no further need
          // to parse the method bodies. Parser.getMethodBodies, which is called latter in this function,
          // will not parse the method statements if ASTNode.HasAllMethodBodies is set.
          if (containsLocalType)   parsedUnit.bits |= ASTNode.HasAllMethodBodies;
        } else {
          // create parsed unit from file
          IFile file = (IFile) cu.getResource();
          ICompilationUnit sourceUnit = this.builder.createCompilationUnitFromPath(openable, file);
          CompilationResult unitResult = new CompilationResult(sourceUnit, i, openablesLength, this.options.maxProblemsPerUnit);
          parsedUnit = parser.dietParse(sourceUnit, unitResult);
        }

        if (parsedUnit != null) {
          hasLocalType[unitsIndex] = containsLocalType;
          cus[unitsIndex] = cu;
          parsedUnits[unitsIndex++] = parsedUnit;
          try {
            this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
            if (openable.equals(focusOpenable)) {
              focusUnit = parsedUnit;
            }
          } catch (AbortCompilation e) {
            // classpath problem for this type: ignore
          }
        }
      } else {
        // cache binary type binding
        ClassFile classFile = (ClassFile)openable;
        IBinaryType binaryType = (IBinaryType) JavaModelManager.getJavaModelManager().getInfo(classFile.getType());
        if (binaryType == null) {
          // create binary type from file
          if (classFile.getPackageFragmentRoot().isArchive()) {
            binaryType = this.builder.createInfoFromClassFileInJar(classFile);
          } else {
            IResource file = classFile.resource();
            binaryType = this.builder.createInfoFromClassFile(classFile, file);
          }
        }
        if (binaryType != null) {
          try {
            BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType(binaryType, false/*don't need field and method (bug 125067)*/, null /*no access restriction*/);
            remember(binaryType, binaryTypeBinding);
            if (openable.equals(focusOpenable)) {
              focusBinaryBinding = binaryTypeBinding;
            }
          } catch (AbortCompilation e) {
            // classpath problem for this type: ignore
          }
        }
      }
    }

    // remember type declaration of focus if local/anonymous early (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=210498)
    TypeDeclaration focusLocalType = null;
    if (focus != null && focusBinaryBinding == null && focusUnit != null && ((Member)focus).getOuterMostLocalContext() != null) {
      focusLocalType = new ASTNodeFinder(focusUnit).findType(focus);
    }


    for (int i = 0; i <= this.typeIndex; i++) {
      IGenericType suppliedType = this.typeModels[i];
      if (suppliedType != null && suppliedType.isBinaryType()) {
        CompilationUnitDeclaration previousUnitBeingCompleted = this.lookupEnvironment.unitBeingCompleted;
        // fault in its hierarchy...
        try {
          // ensure that unitBeingCompleted is set so that we don't get an AbortCompilation for a missing type
          // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=213249 )
          if (previousUnitBeingCompleted == null) {
            this.lookupEnvironment.unitBeingCompleted = FakeUnit;
          }
          ReferenceBinding typeBinding = this.typeBindings[i];
          typeBinding.superclass();
          typeBinding.superInterfaces();
        } catch (AbortCompilation e) {
          // classpath problem for this type: ignore
        } finally {
          this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted;
        }
      }
    }

    // complete type bindings (i.e. connect super types)
    for (int i = 0; i < unitsIndex; i++) {
      CompilationUnitDeclaration parsedUnit = parsedUnits[i];
      if (parsedUnit != null) {
        try {
          if (hasLocalType[i]) { // NB: no-op if method bodies have been already parsed
            if (monitor != null && monitor.isCanceled())
              throw new OperationCanceledException();
            parser.getMethodBodies(parsedUnit);
          }
        } catch (AbortCompilation e) {
          // classpath problem for this type: don't try to resolve (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49809)
          hasLocalType[i] = false;
        }
      }
    }
    // complete type bindings and build fields and methods only for local types
    // (in this case the constructor is needed when resolving local types)
    // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=145333)
    try {
      this.lookupEnvironment.completeTypeBindings(parsedUnits, hasLocalType, unitsIndex);
      // remember type bindings
      for (int i = 0; i < unitsIndex; i++) {
        CompilationUnitDeclaration parsedUnit = parsedUnits[i];
        if (parsedUnit != null && !parsedUnit.hasErrors()) {
          boolean containsLocalType = hasLocalType[i];
          if (containsLocalType) {
            if (monitor != null && monitor.isCanceled())
              throw new OperationCanceledException();
            parsedUnit.scope.faultInTypes();
            parsedUnit.resolve();
          }
         
          rememberAllTypes(parsedUnit, cus[i], containsLocalType);
        }
      }
    } catch (AbortCompilation e) {
      // skip it silently
    }
    worked(monitor, 1);


    // if no potential subtype was a real subtype of the binary focus type, no need to go further
    // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=54043)
    if (focusBinaryBinding == null && focus != null && focus.isBinary()) {
      char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray();
      focusBinaryBinding = this.lookupEnvironment.getCachedType(CharOperation.splitOn('.', fullyQualifiedName));
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=436155
      // When local types are requested, it's likely a type is found from cache without
      // the hierarchy being resolved completely, so consider that factor too
      if (focusBinaryBinding == null ||
          (focusBinaryBinding.tagBits & TagBits.HasUnresolvedSuperclass) != 0)
        return;
    }

    reportHierarchy(focus, focusLocalType, focusBinaryBinding);

  } catch (ClassCastException e){ // work-around for 1GF5W1S - can happen in case duplicates are fed to the hierarchy with binaries hiding sources
  } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
    if (TypeHierarchy.DEBUG)
      e.printStackTrace();
  } finally {
    reset();
  }
}
private void setEnvironment(LookupEnvironment lookupEnvironment, HierarchyBuilder builder) {
  this.lookupEnvironment = lookupEnvironment;
  this.builder = builder;

  this.typeIndex = -1;
  this.typeModels = new IGenericType[5];
  this.typeBindings = new ReferenceBinding[5];
}

/*
* Set the focus type (i.e. the type that this resolver is computing the hierarch for.
* Returns the binding of this focus type or null if it could not be found.
*/
public ReferenceBinding setFocusType(char[][] compoundName) {
  if (compoundName == null || this.lookupEnvironment == null) return null;
  this.focusType = this.lookupEnvironment.getCachedType(compoundName);
  if (this.focusType == null) {
    this.focusType = this.lookupEnvironment.askForType(compoundName);
    if (this.focusType == null) {
      int length = compoundName.length;
      char[] typeName = compoundName[length-1];
      int firstDollar = CharOperation.indexOf('$', typeName);
      if (firstDollar != -1) {
        compoundName[length-1] = CharOperation.subarray(typeName, 0, firstDollar);
        this.focusType = this.lookupEnvironment.askForType(compoundName);
        if (this.focusType != null) {
          char[][] memberTypeNames = CharOperation.splitOn('$', typeName, firstDollar+1, typeName.length);
          for (int i = 0; i < memberTypeNames.length; i++) {
            this.focusType = this.focusType.getMemberType(memberTypeNames[i]);
            if (this.focusType == null)
              return null;
          }
        }
      }
    }
  }
  return this.focusType;
}
public boolean subOrSuperOfFocus(ReferenceBinding typeBinding) {
  if (this.focusType == null) return true; // accept all types (case of hierarchy in a region)
  try {
    if (subTypeOfType(this.focusType, typeBinding)) return true;
    if (!this.superTypesOnly && subTypeOfType(typeBinding, this.focusType)) return true;
  } catch (AbortCompilation e) {
    // unresolved superclass/superinterface -> ignore
  }
  return false;
}
private boolean subTypeOfType(ReferenceBinding subType, ReferenceBinding typeBinding) {
  if (typeBinding == null || subType == null) return false;
  if (TypeBinding.equalsEquals(subType, typeBinding)) return true;
  ReferenceBinding superclass = subType.superclass();
  if (superclass != null) superclass = (ReferenceBinding) superclass.erasure();
//  if (superclass != null && superclass.id == TypeIds.T_JavaLangObject && subType.isHierarchyInconsistent()) return false;
  if (subTypeOfType(superclass, typeBinding)) return true;
  ReferenceBinding[] superInterfaces = subType.superInterfaces();
  if (superInterfaces != null) {
    for (int i = 0, length = superInterfaces.length; i < length; i++) {
      ReferenceBinding superInterface = (ReferenceBinding) superInterfaces[i].erasure();
      if (subTypeOfType(superInterface, typeBinding)) return true;
    }
  }
  return false;
}
protected void worked(IProgressMonitor monitor, int work) {
  if (monitor != null) {
    if (monitor.isCanceled()) {
      throw new OperationCanceledException();
    } else {
      monitor.worked(work);
    }
  }
}
}
TOP

Related Classes of org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver

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.