Package org.aspectj.org.eclipse.jdt.internal.codeassist

Source Code of org.aspectj.org.eclipse.jdt.internal.codeassist.MissingTypesGuesser$GuessedTypeRequestor

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
import org.aspectj.org.eclipse.jdt.internal.core.SearchableEnvironment;

public class MissingTypesGuesser extends ASTVisitor {
  public static interface GuessedTypeRequestor {
    public void accept(
        TypeBinding guessedType,
        Binding[] missingElements,
        int[] missingElementsStarts,
        int[] missingElementsEnds,
        boolean hasProblems);
   
  }
 
  private static class ResolutionCleaner extends ASTVisitor {
    private HashtableOfObjectToInt bitsMap = new HashtableOfObjectToInt();
    private boolean firstCall = true;
   
    public ResolutionCleaner(){
      super();
    }
   
    private void cleanUp(TypeReference typeReference) {
      if (this.firstCall) {
        this.bitsMap.put(typeReference, typeReference.bits);
      } else {
        typeReference.bits = this.bitsMap.get(typeReference);
      }
      typeReference.resolvedType = null;
    }
   
    private void cleanUp(ParameterizedSingleTypeReference typeReference) {
      this.cleanUp((TypeReference)typeReference);
      typeReference.bits &= ~ASTNode.DidResolve;
    }
   
    private void cleanUp(ParameterizedQualifiedTypeReference typeReference) {
      this.cleanUp((TypeReference)typeReference);
      typeReference.bits &= ~ASTNode.DidResolve;
    }
   
    public void cleanUp(TypeReference convertedType, BlockScope scope) {
      convertedType.traverse(this, scope);
      this.firstCall = false;
    }

    public void cleanUp(TypeReference convertedType, ClassScope scope) {
      convertedType.traverse(this, scope);
      this.firstCall = false;
    }
   
    public boolean visit(SingleTypeReference singleTypeReference, BlockScope scope) {
      this.cleanUp(singleTypeReference);
      return true;
    }
   
    public boolean visit(SingleTypeReference singleTypeReference, ClassScope scope) {
      this.cleanUp(singleTypeReference);
      return true;
    }
   
    public boolean visit(Wildcard wildcard, BlockScope scope) {
      this.cleanUp(wildcard);
      return true;
    }
   
    public boolean visit(Wildcard wildcard, ClassScope scope) {
      this.cleanUp(wildcard);
      return true;
    }
   
    public boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope) {
      this.cleanUp(arrayTypeReference);
      return true;
    }
   
    public boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope) {
      this.cleanUp(arrayTypeReference);
      return true;
    }
   
    public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, BlockScope scope) {
      this.cleanUp(parameterizedSingleTypeReference);
      return true;
    }
   
    public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, ClassScope scope) {
      this.cleanUp(parameterizedSingleTypeReference);
      return true;
    }
   
    public boolean visit(QualifiedTypeReference qualifiedTypeReference, BlockScope scope) {
      this.cleanUp(qualifiedTypeReference);
      return true;
    }
   
    public boolean visit(QualifiedTypeReference qualifiedTypeReference, ClassScope scope) {
      this.cleanUp(qualifiedTypeReference);
      return true;
    }
   
    public boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, BlockScope scope) {
      this.cleanUp(arrayQualifiedTypeReference);
      return true;
    }
   
    public boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, ClassScope scope) {
      this.cleanUp(arrayQualifiedTypeReference);
      return true;
    }
   
    public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, BlockScope scope) {
      this.cleanUp(parameterizedQualifiedTypeReference);
      return true;
    }
   
    public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, ClassScope scope) {
      this.cleanUp(parameterizedQualifiedTypeReference);
      return true;
    }

  }
 
  private CompletionEngine.CompletionProblemFactory problemFactory ;
  private  SearchableEnvironment nameEnvironment;
 
  private HashMap substituedTypes;
  private HashMap originalTypes;
  private int combinationsCount;
     
  public MissingTypesGuesser(CompletionEngine completionEngine) {
    this.problemFactory = completionEngine.problemFactory;
    this.nameEnvironment = completionEngine.nameEnvironment;
  }
 
  private boolean computeMissingElements(
      QualifiedTypeReference[] substituedTypeNodes,
      char[][][] originalTypeNames,
      Binding[] missingElements,
      int[] missingElementsStarts,
      int[] missingElementsEnds) {
    int length = substituedTypeNodes.length;
   
    for (int i = 0; i < length; i++) {
      TypeReference substituedType = substituedTypeNodes[i];
      if (substituedType.resolvedType == null) return false;
      ReferenceBinding erasure = (ReferenceBinding)substituedType.resolvedType.leafComponentType().erasure();
      Binding missingElement;
      int depthToRemove = originalTypeNames[i].length - 1 ;
      if (depthToRemove == 0) {
        missingElement = erasure;
      } else {
        int depth = erasure.depth() + 1;
       
        if (depth > depthToRemove) {
          missingElement = erasure.enclosingTypeAt(depthToRemove);
        } else {
          return false;
          ///////////////////////////////////////////////////////////
          //// Uncomment the following code to return missing package
          ///////////////////////////////////////////////////////////
          //depthToRemove -= depth;
          //PackageBinding packageBinding = erasure.getPackage();
          //while(depthToRemove > 0) {
          //  packageBinding = packageBinding.parent;
          //  depthToRemove--;
          //}
          //missingElement = packageBinding;
        }
      }
     
      missingElements[i] = missingElement;
      missingElementsStarts[i] = substituedType.sourceStart;
      missingElementsEnds[i] = substituedType.sourceEnd + 1;
     
    }
   
    return true;
  }

  private TypeReference convert(ArrayQualifiedTypeReference typeRef) {
    if (typeRef.resolvedType != null) {
      if (typeRef.resolvedType.isValidBinding()) {
        ArrayQualifiedTypeReference convertedType =
          new ArrayQualifiedTypeReference(
              typeRef.tokens,
              typeRef.dimensions(),
              typeRef.sourcePositions);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.sourceEnd;
        return convertedType;
      } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
        // only the first token must be resolved
        if(((ReferenceBinding)typeRef.resolvedType.leafComponentType()).compoundName.length != 1) return null;
       
        char[][] typeName = typeRef.getTypeName();
        char[][][] typeNames = findTypeNames(typeName);
        if(typeNames == null || typeNames.length == 0) return null;
        ArrayQualifiedTypeReference convertedType =
          new ArrayQualifiedTypeReference(
              typeNames[0],
              typeRef.dimensions(),
              new long[typeNames[0].length]);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL);
        this.substituedTypes.put(convertedType, typeNames);
        this.originalTypes.put(convertedType, typeName);
        this.combinationsCount *= typeNames.length;
        return convertedType;
      }
    }
    return null;
  }

  private TypeReference convert(ArrayTypeReference typeRef) {
    if (typeRef.resolvedType != null) {
      if (typeRef.resolvedType.isValidBinding()) {
        ArrayTypeReference convertedType =
          new ArrayTypeReference(
              typeRef.token,
              typeRef.dimensions,
              0);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.originalSourceEnd;
        return convertedType;
      } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
        char[][] typeName = typeRef.getTypeName();
        char[][][] typeNames = findTypeNames(typeName);
        if(typeNames == null || typeNames.length == 0) return null;
        ArrayQualifiedTypeReference convertedType =
          new ArrayQualifiedTypeReference(
              typeNames[0],
              typeRef.dimensions,
              new long[typeNames[0].length]);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.originalSourceEnd;
        this.substituedTypes.put(convertedType, typeNames);
        this.originalTypes.put(convertedType, typeName);
        this.combinationsCount *= typeNames.length;
        return convertedType;
      }
    }
    return null;
  }
 
  private TypeReference convert(ParameterizedQualifiedTypeReference typeRef) {
    if (typeRef.resolvedType != null) {
      TypeReference[][] typeArguments = typeRef.typeArguments;
      int length = typeArguments.length;
      TypeReference[][] convertedTypeArguments = new TypeReference[length][];
      next : for (int i = 0; i < length; i++) {
        if (typeArguments[i] == null) continue next;
        int length2 = typeArguments[i].length;
        convertedTypeArguments[i] = new TypeReference[length2];
        for (int j = 0; j < length2; j++) {
          convertedTypeArguments[i][j] = convert(typeArguments[i][j]);
          if (convertedTypeArguments[i][j] == null) return null;
        }
      }
     
      if (typeRef.resolvedType.isValidBinding()) {
        ParameterizedQualifiedTypeReference convertedType =
          new ParameterizedQualifiedTypeReference(
              typeRef.tokens,
              convertedTypeArguments,
              typeRef.dimensions(),
              new long[typeRef.tokens.length]);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.sourceEnd;
        return convertedType;
      } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
        // only the first token must be resolved
        if(((ReferenceBinding)typeRef.resolvedType.leafComponentType()).compoundName.length != 1) return null;
       
        char[][] typeName = typeRef.getTypeName();
        char[][][] typeNames = findTypeNames(typeName);
        if(typeNames == null || typeNames.length == 0) return null;
       
        TypeReference[][] newConvertedTypeArguments = new TypeReference[typeNames[0].length][];
        for (int k = newConvertedTypeArguments.length - 1, l = convertedTypeArguments.length -1; k > -1 && l > -1;) {
          newConvertedTypeArguments[k] = convertedTypeArguments[l];
          k--;
          l--;
        }
       
        ParameterizedQualifiedTypeReference convertedType =
          new ParameterizedQualifiedTypeReference(
              typeNames[0],
              newConvertedTypeArguments,
              typeRef.dimensions(),
              new long[typeNames[0].length]);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL);
        this.substituedTypes.put(convertedType, typeNames);
        this.originalTypes.put(convertedType, typeName);
        this.combinationsCount *= typeNames.length;
        return convertedType;
      }
    }
    return null;
  }
 
  private TypeReference convert(ParameterizedSingleTypeReference typeRef) {
    if (typeRef.resolvedType != null) {
      TypeReference[] typeArguments = typeRef.typeArguments;
      int length = typeArguments.length;
      TypeReference[] convertedTypeArguments = new TypeReference[length];
      for (int i = 0; i < length; i++) {
        convertedTypeArguments[i] = convert(typeArguments[i]);
        if(convertedTypeArguments[i] == null) return null;
      }
     
      if (typeRef.resolvedType.isValidBinding()) {
        ParameterizedSingleTypeReference convertedType =
          new ParameterizedSingleTypeReference(
              typeRef.token,
              convertedTypeArguments,
              typeRef.dimensions,
              0);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.sourceEnd;
        return convertedType;
      } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
        char[][] typeName = typeRef.getTypeName();
        char[][][] typeNames = findTypeNames(typeName);
        if(typeNames == null || typeNames.length == 0) return null;
       
        TypeReference[][] allConvertedTypeArguments = new TypeReference[typeNames[0].length][];
        allConvertedTypeArguments[allConvertedTypeArguments.length - 1] = convertedTypeArguments;
       
        ParameterizedQualifiedTypeReference convertedType =
          new ParameterizedQualifiedTypeReference(
              typeNames[0],
              allConvertedTypeArguments,
              typeRef.dimensions,
              new long[typeNames[0].length]);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.sourceEnd;
        this.substituedTypes.put(convertedType, typeNames);
        this.originalTypes.put(convertedType, typeName);
        this.combinationsCount *= typeNames.length;
        return convertedType;
      }
    }
    return null;
  }
 
  private TypeReference convert(QualifiedTypeReference typeRef) {
    if (typeRef.resolvedType != null) {
      if (typeRef.resolvedType.isValidBinding()) {
        QualifiedTypeReference convertedType = new QualifiedTypeReference(typeRef.tokens, typeRef.sourcePositions);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.sourceEnd;
        return convertedType;
      } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
        // only the first token must be resolved
        if(((ReferenceBinding)typeRef.resolvedType).compoundName.length != 1) return null;
       
        char[][] typeName = typeRef.getTypeName();
        char[][][] typeNames = findTypeNames(typeName);
        if(typeNames == null || typeNames.length == 0) return null;
        QualifiedTypeReference convertedType = new QualifiedTypeReference(typeNames[0], new long[typeNames[0].length]);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL);
        this.substituedTypes.put(convertedType, typeNames);
        this.originalTypes.put(convertedType, typeName);
        this.combinationsCount *= typeNames.length;
        return convertedType;
      }
    }
    return null;
  }
 
  private TypeReference convert(SingleTypeReference typeRef) {
    if (typeRef.resolvedType != null) {
      if (typeRef.resolvedType.isValidBinding()) {
        SingleTypeReference convertedType = new SingleTypeReference(typeRef.token, 0);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.sourceEnd;
        return convertedType;
      } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
        char[][] typeName = typeRef.getTypeName();
        char[][][] typeNames = findTypeNames(typeName);
        if(typeNames == null || typeNames.length == 0) return null;
        QualifiedTypeReference convertedType = new QualifiedTypeReference(typeNames[0], new long[typeNames[0].length]);
        convertedType.sourceStart = typeRef.sourceStart;
        convertedType.sourceEnd = typeRef.sourceEnd;
        this.substituedTypes.put(convertedType, typeNames);
        this.originalTypes.put(convertedType, typeName);
        this.combinationsCount *= typeNames.length;
        return convertedType;
      }
    }
    return null;
  }
 
  private TypeReference convert(TypeReference typeRef) {
    if (typeRef instanceof ParameterizedSingleTypeReference) {
      return convert((ParameterizedSingleTypeReference)typeRef);
    } else if(typeRef instanceof ParameterizedQualifiedTypeReference) {
      return convert((ParameterizedQualifiedTypeReference)typeRef);
    } else if (typeRef instanceof ArrayTypeReference) {
      return convert((ArrayTypeReference)typeRef);
    } else if(typeRef instanceof ArrayQualifiedTypeReference) {
      return convert((ArrayQualifiedTypeReference)typeRef);
    } else if(typeRef instanceof Wildcard) {
      return convert((Wildcard)typeRef);
    } else if (typeRef instanceof SingleTypeReference) {
      return convert((SingleTypeReference)typeRef);
    } else if (typeRef instanceof QualifiedTypeReference) {
      return convert((QualifiedTypeReference)typeRef);
    }
    return null;
  }
 
  private TypeReference convert(Wildcard typeRef) {
    TypeReference bound = typeRef.bound;
    TypeReference convertedBound = null;
    if (bound != null) {
      convertedBound = convert(bound);
      if (convertedBound == null) return null;
    }
    Wildcard convertedType = new Wildcard(typeRef.kind);
    convertedType.bound = convertedBound;
    convertedType.sourceStart = typeRef.sourceStart;
    convertedType.sourceEnd = typeRef.sourceEnd;
    return convertedType;
  }
 
  private char[][][] findTypeNames(char[][] missingTypeName) {
    char[] missingSimpleName = missingTypeName[missingTypeName.length - 1];
    final boolean isQualified = missingTypeName.length > 1;
    final char[] missingFullyQualifiedName =
      isQualified ? CharOperation.concatWith(missingTypeName, '.') : null;
    final ArrayList results = new ArrayList();
    ISearchRequestor storage = new ISearchRequestor() {
     
      public void acceptPackage(char[] packageName) {
        // package aren't searched
      }
      public void acceptType(
          char[] packageName,
          char[] typeName,
          char[][] enclosingTypeNames,
          int modifiers,
          AccessRestriction accessRestriction) {
        char[] fullyQualifiedName = CharOperation.concat(packageName, CharOperation.concat(CharOperation.concatWith(enclosingTypeNames, '.'), typeName, '.'), '.');
        if (isQualified && !CharOperation.endsWith(fullyQualifiedName, missingFullyQualifiedName)) return;
        char[][] compoundName = CharOperation.splitOn('.', fullyQualifiedName);
        results.add(compoundName);
      }
   
    };
    nameEnvironment.findExactTypes(missingSimpleName, true, IJavaSearchConstants.TYPE, storage);
    if(results.size() == 0) return null;
    return (char[][][])results.toArray(new char[results.size()][0][0]);
  }
 
  private char[][] getOriginal(TypeReference typeRef) {
    return (char[][])this.originalTypes.get(typeRef);
  }
 
  private QualifiedTypeReference[] getSubstituedTypes() {
    Set types = this.substituedTypes.keySet();
    return (QualifiedTypeReference[]) types.toArray(new QualifiedTypeReference[types.size()]);
  }
 
  private char[][][] getSubstitution(TypeReference typeRef) {
    return (char[][][])this.substituedTypes.get(typeRef);
  }
 
  public void guess(TypeReference typeRef, Scope scope, GuessedTypeRequestor requestor) {
    this.substituedTypes = new HashMap();
    this.originalTypes = new HashMap();
    this.combinationsCount = 1;
   
    TypeReference convertedType = convert(typeRef);
   
    if(convertedType == null) return;
   
    QualifiedTypeReference[] substituedTypeNodes = this.getSubstituedTypes();
    int length = substituedTypeNodes.length;
   
    int[] substitutionsIndexes = new int[substituedTypeNodes.length];
    char[][][][] subtitutions = new char[substituedTypeNodes.length][][][];
    char[][][] originalTypeNames = new char[substituedTypeNodes.length][][];
    for (int i = 0; i < substituedTypeNodes.length; i++) {
      subtitutions[i] = this.getSubstitution(substituedTypeNodes[i]);
      originalTypeNames[i] = this.getOriginal(substituedTypeNodes[i]);
    }
   
    ResolutionCleaner resolutionCleaner = new ResolutionCleaner();
    for (int i = 0; i < this.combinationsCount; i++) {
     
      nextSubstitution(substituedTypeNodes, subtitutions, substitutionsIndexes);
     
     
      this.problemFactory.startCheckingProblems();
      TypeBinding guessedType = null;
      switch (scope.kind) {
        case Scope.METHOD_SCOPE :
        case Scope.BLOCK_SCOPE :
          resolutionCleaner.cleanUp(convertedType, (BlockScope)scope);
          guessedType = convertedType.resolveType((BlockScope)scope);
          break;
        case Scope.CLASS_SCOPE :
          resolutionCleaner.cleanUp(convertedType, (ClassScope)scope);
          guessedType = convertedType.resolveType((ClassScope)scope);
          break;
      }
      this.problemFactory.stopCheckingProblems();
      if (!this.problemFactory.hasForbiddenProblems) {
        if (guessedType != null) {
          Binding[] missingElements = new Binding[length];
          int[] missingElementsStarts = new int[length];
          int[] missingElementsEnds = new int[length];
         
          if(computeMissingElements(
              substituedTypeNodes,
              originalTypeNames,
              missingElements,
              missingElementsStarts,
              missingElementsEnds)) {
            requestor.accept(
                guessedType.capture(scope, typeRef.sourceEnd),
                missingElements,
                missingElementsStarts,
                missingElementsEnds,
                this.problemFactory.hasAllowedProblems);
          }
        }
      }
    }
  }
  private void nextSubstitution(
      QualifiedTypeReference[] substituedTypeNodes,
      char[][][][] subtitutions,
      int[] substitutionsIndexes) {
    int length = substituedTypeNodes.length;
   
    done : for (int i = 0; i < length; i++) {
      if(substitutionsIndexes[i] < subtitutions[i].length - 1) {
        substitutionsIndexes[i]++;
        break done;
      } else {
        substitutionsIndexes[i] = 0;
      }
    }
   
    for (int i = 0; i < length; i++) {
      QualifiedTypeReference qualifiedTypeReference = substituedTypeNodes[i];
      qualifiedTypeReference.tokens = subtitutions[i][substitutionsIndexes[i]];
      qualifiedTypeReference.sourcePositions = new long[qualifiedTypeReference.tokens.length];
      if(qualifiedTypeReference instanceof ParameterizedQualifiedTypeReference) {
        ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference =
          (ParameterizedQualifiedTypeReference)qualifiedTypeReference;
        TypeReference[][] typeArguments = parameterizedQualifiedTypeReference.typeArguments;
        TypeReference[][] newTypeArguments = new TypeReference[qualifiedTypeReference.tokens.length][];
        for (int j = newTypeArguments.length - 1, k = typeArguments.length -1; j > -1 && k > -1;) {
          newTypeArguments[j] = typeArguments[k];
          j--;
          k--;
        }
      }
    }
  }
}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.codeassist.MissingTypesGuesser$GuessedTypeRequestor

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.