Package org.aspectj.org.eclipse.jdt.internal.core.util

Source Code of org.aspectj.org.eclipse.jdt.internal.core.util.CaptureFinder

/*******************************************************************************
* Copyright (c) 2005, 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.core.util;

import java.util.ArrayList;

import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
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.CaptureBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;

public class BindingKeyResolver extends BindingKeyParser {
  Compiler compiler;
  Binding compilerBinding;
 
  char[][] compoundName;
  int dimension;
  LookupEnvironment environment;
  ReferenceBinding genericType;
  MethodBinding methodBinding;
 
  char[] secondarySimpleName;
  CompilationUnitDeclaration parsedUnit;
  BlockScope scope;
  TypeBinding typeBinding;
  TypeDeclaration typeDeclaration;
  ArrayList types = new ArrayList();
  int rank = 0;
 
  int wildcardRank;
 
  CompilationUnitDeclaration outerMostParsedUnit;
 
  private BindingKeyResolver(BindingKeyParser parser, Compiler compiler, LookupEnvironment environment, int wildcardRank, CompilationUnitDeclaration outerMostParsedUnit) {
    super(parser);
    this.compiler = compiler;
    this.environment = environment;
    this.wildcardRank = wildcardRank;
    this.outerMostParsedUnit = outerMostParsedUnit;
  }
 
  public BindingKeyResolver(String key) {
    this(key, null, null);
  }

  public BindingKeyResolver(String key, Compiler compiler, LookupEnvironment environment) {
    super(key);
    this.compiler = compiler;
    this.environment = environment;
  }
 
  /*
   * If not already cached, computes and cache the compound name (pkg name + top level name) of this key.
   * Returns the package name if key is a pkg key.
   * Returns an empty array if malformed.
   * This key's scanner should be positioned on the package or type token.
   */
  public char[][] compoundName() {
    return this.compoundName;
  }
  
  public void consumeArrayDimension(char[] brakets) {
    this.dimension = brakets.length;
  }
 
  public void consumeBaseType(char[] baseTypeSig) {
    this.compoundName = new char[][] {getKey().toCharArray()};
    TypeBinding baseTypeBinding = getBaseTypeBinding(baseTypeSig);
    if (baseTypeBinding != null) {
      this.typeBinding = baseTypeBinding;
    }
  }
 
  public void consumeCapture(final int position) {
    CompilationUnitDeclaration outerParsedUnit = this.outerMostParsedUnit == null ? this.parsedUnit : this.outerMostParsedUnit;
    if (outerParsedUnit == null) return;
    final Binding wildcardBinding = ((BindingKeyResolver) this.types.get(0)).compilerBinding;
    class CaptureFinder extends ASTVisitor {
      CaptureBinding capture;
      boolean checkType(TypeBinding binding) {
        if (binding == null)
          return false;
        switch (binding.kind()) {
          case Binding.PARAMETERIZED_TYPE:
            TypeBinding[] arguments = ((ParameterizedTypeBinding) binding).arguments;
            if (arguments == null) return false;
            for (int i = 0, length = arguments.length; i < length; i++) {
              if (checkType(arguments[i]))
                return true;
            }
            break;
          case Binding.WILDCARD_TYPE:
            return checkType(((WildcardBinding) binding).bound);
          case Binding.ARRAY_TYPE:
            return checkType(((ArrayBinding) binding).leafComponentType);
          case Binding.TYPE_PARAMETER:
            if (binding.isCapture()) {
              CaptureBinding captureBinding = (CaptureBinding) binding;
              if (captureBinding.position == position && captureBinding.wildcard == wildcardBinding) {
                this.capture = captureBinding;
                return true;
              }
            }
            break;
        }
        return false;
      }
      public boolean visit(SingleNameReference singleNameReference, BlockScope blockScope) {
        if (checkType(singleNameReference.resolvedType))
          return false;
        return super.visit(singleNameReference, blockScope);
      }
      public boolean visit(QualifiedNameReference qualifiedNameReference, BlockScope blockScope) {
        if (checkType(qualifiedNameReference.resolvedType))
          return false;
        return super.visit(qualifiedNameReference, blockScope);
      }
      public boolean visit(MessageSend messageSend, BlockScope blockScope) {
        if (checkType(messageSend.resolvedType))
          return false;
        return super.visit(messageSend, blockScope);
      }
      public boolean visit(FieldReference fieldReference, BlockScope blockScope) {
        if (checkType(fieldReference.resolvedType))
          return false;
        return super.visit(fieldReference, blockScope);
      }
      public boolean visit(ConditionalExpression conditionalExpression, BlockScope blockScope) {
        if (checkType(conditionalExpression.resolvedType))
          return false;
        return super.visit(conditionalExpression, blockScope);
      }
      public boolean visit(CastExpression castExpression, BlockScope blockScope) {
        if (checkType(castExpression.resolvedType))
          return false;
        return super.visit(castExpression, blockScope);
      }
      public boolean visit(Assignment assignment, BlockScope blockScope) {
        if (checkType(assignment.resolvedType))
          return false;
        return super.visit(assignment, blockScope);
      }
      public boolean visit(ArrayReference arrayReference, BlockScope blockScope) {
        if (checkType(arrayReference.resolvedType))
          return false;
        return super.visit(arrayReference, blockScope);
      }
    }
    CaptureFinder captureFinder = new CaptureFinder();
    outerParsedUnit.traverse(captureFinder, outerParsedUnit.scope);
    this.typeBinding = captureFinder.capture;
  }
 
  public void consumeException() {
    this.types = new ArrayList();
  }

  public void consumeField(char[] fieldName) {
    FieldBinding[] fields = ((ReferenceBinding) this.typeBinding).availableFields(); // resilience
     for (int i = 0, length = fields.length; i < length; i++) {
      FieldBinding field = fields[i];
      if (CharOperation.equals(fieldName, field.name)) {
        this.typeBinding = null;
        this.compilerBinding = field;
        return;
      }
    }
  }

  public void consumeParameterizedGenericMethod() {
    if (this.methodBinding == null)
      return;
    TypeBinding[] arguments = getTypeBindingArguments();
    if (arguments.length != this.methodBinding.typeVariables().length)
      this.methodBinding = this.environment.createParameterizedGenericMethod(this.methodBinding, (RawTypeBinding) null);
    else
       this.methodBinding = this.environment.createParameterizedGenericMethod(this.methodBinding, arguments);
    this.compilerBinding = this.methodBinding;
  }
 
  public void consumeLocalType(char[] uniqueKey) {
     LocalTypeBinding[] localTypeBindings  = this.parsedUnit.localTypes;
     for (int i = 0; i < this.parsedUnit.localTypeCount; i++)
       if (CharOperation.equals(uniqueKey, localTypeBindings[i].computeUniqueKey(false/*not a leaf*/))) {
         this.typeBinding = localTypeBindings[i];
         return;
       }
  }

  public void consumeLocalVar(char[] varName) {
    if (this.scope == null) {
      this.scope = this.methodBinding.sourceMethod().scope;
    }
     for (int i = 0; i < this.scope.localIndex; i++) {
      LocalVariableBinding local = this.scope.locals[i];
      if (CharOperation.equals(varName, local.name)) {
        this.methodBinding = null;
        this.compilerBinding = local;
        return;
      }
    }
  }

  public void consumeMethod(char[] selector, char[] signature) {
    MethodBinding[] methods = ((ReferenceBinding) this.typeBinding).availableMethods(); // resilience
     for (int i = 0, methodLength = methods.length; i < methodLength; i++) {
      MethodBinding method = methods[i];
      if (CharOperation.equals(selector, method.selector) || (selector.length == 0 && method.isConstructor())) {
        char[] methodSignature = method.genericSignature();
        if (methodSignature == null)
          methodSignature = method.signature();
        if (CharOperation.equals(signature, methodSignature)) {
          this.typeBinding = null;
          this.methodBinding = method;
          this.compilerBinding = this.methodBinding;
          return;
        }
      }
    }
  }
 
  public void consumeMemberType(char[] simpleTypeName) {
    this.typeBinding = getTypeBinding(simpleTypeName);
  }

  public void consumePackage(char[] pkgName) {
    this.compoundName = CharOperation.splitOn('/', pkgName);
    this.compilerBinding = new PackageBinding(this.compoundName, null, this.environment);
  }
 
  public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) {
    TypeBinding[] arguments = getTypeBindingArguments();
    if (simpleTypeName != null) {
      if (this.genericType == null) {
        // parameterized member type with raw enclosing type
        this.genericType = ((ReferenceBinding) this.typeBinding).getMemberType(simpleTypeName);
      } else {
        // parameterized member type with parameterized enclosing type
        this.genericType = this.genericType.getMemberType(simpleTypeName);
      }
      if (!isRaw)
        this.typeBinding = this.environment.createParameterizedType(this.genericType, arguments, (ReferenceBinding) this.typeBinding);
      else
        // raw type
        this.typeBinding = this.environment.createRawType(this.genericType, (ReferenceBinding) this.typeBinding);
    } else {
      // parameterized top level type or parameterized member type with raw enclosing type
      this.genericType = (ReferenceBinding) this.typeBinding;
      ReferenceBinding enclosing = this.genericType.enclosingType();
      if (enclosing != null) enclosing = (ReferenceBinding) this.environment.convertToRawType(enclosing);
      this.typeBinding = this.environment.createParameterizedType(this.genericType, arguments, enclosing);
    }
  }
 

  public void consumeParser(BindingKeyParser parser) {
    this.types.add(parser);
    if (((BindingKeyResolver) parser).compilerBinding instanceof WildcardBinding)
      this.rank++;
  }
 
  public void consumeScope(int scopeNumber) {
    if (this.scope == null) {
      this.scope = this.methodBinding.sourceMethod().scope;
    }
    if (scopeNumber >= this.scope.subscopeCount)
      return; // malformed key
    this.scope = (BlockScope) this.scope.subscopes[scopeNumber];
  }
 
  public void consumeRawType() {
    if (this.typeBinding == null) return;
    this.typeBinding = this.environment.convertToRawType(this.typeBinding);
  }
  public void consumeSecondaryType(char[] simpleTypeName) {
    this.secondarySimpleName = simpleTypeName;
  }
 
  public void consumeFullyQualifiedName(char[] fullyQualifiedName) {
    this.compoundName = CharOperation.splitOn('/', fullyQualifiedName);
  }
 
  public void consumeTopLevelType() {
    this.parsedUnit = getCompilationUnitDeclaration();
    if (this.parsedUnit != null && this.compiler != null) {
      this.compiler.process(this.parsedUnit, this.compiler.totalUnits+1); // noop if unit has already been resolved
    }
    if (this.parsedUnit == null) {
      this.typeBinding = getBinaryBinding();
    } else {
      char[] typeName = this.secondarySimpleName == null ? this.compoundName[this.compoundName.length-1] : this.secondarySimpleName;
      this.typeBinding = getTypeBinding(typeName);
    }
  }
 
  public void consumeKey() {
    if (this.typeBinding != null) {
      this.typeBinding = getArrayBinding(this.dimension, this.typeBinding);
      this.compilerBinding = this.typeBinding;
    }
  }
 
  public void consumeTypeVariable(char[] position, char[] typeVariableName) {
    if (position.length > 0) {
      int pos = Integer.parseInt(new String(position));
      MethodBinding[] methods = ((ReferenceBinding) this.typeBinding).availableMethods(); // resilience
      if (methods != null && pos < methods.length) {
        this.methodBinding = methods[pos];
      }
    }
     TypeVariableBinding[] typeVariableBindings = this.methodBinding != null ? this.methodBinding.typeVariables() : this.typeBinding.typeVariables();
     for (int i = 0, length = typeVariableBindings.length; i < length; i++) {
      TypeVariableBinding typeVariableBinding = typeVariableBindings[i];
      if (CharOperation.equals(typeVariableName, typeVariableBinding.sourceName())) {
        this.typeBinding = typeVariableBinding;
        return;
      }
    }
  }
 
  public void consumeTypeWithCapture() {
    BindingKeyResolver resolver = (BindingKeyResolver) this.types.get(0);
    this.typeBinding =(TypeBinding) resolver.compilerBinding;
  }
 
  public void consumeWildCard(int kind) {
    switch (kind) {
      case Wildcard.EXTENDS:
      case Wildcard.SUPER:
        BindingKeyResolver boundResolver = (BindingKeyResolver) this.types.get(0);
        this.typeBinding = this.environment.createWildcard((ReferenceBinding) this.typeBinding, this.wildcardRank, (TypeBinding) boundResolver.compilerBinding, null /*no extra bound*/, kind);
        break;
      case Wildcard.UNBOUND:
        this.typeBinding = this.environment.createWildcard((ReferenceBinding) this.typeBinding, rank++, null/*no bound*/, null /*no extra bound*/, kind);
        break;
    }
  }
 
  /*
   * If the given dimension is greater than 0 returns an array binding for the given type binding.
   * Otherwise return the given type binding.
   * Returns null if the given type binding is null.
   */
  private TypeBinding getArrayBinding(int dim, TypeBinding binding) {
    if (binding == null) return null;
    if (dim == 0) return binding;
    return this.environment.createArrayType(binding, dim);
  }
 
  private TypeBinding getBaseTypeBinding(char[] signature) {
    switch (signature[0]) {
      case 'I' :
        return TypeBinding.INT;
      case 'Z' :
        return TypeBinding.BOOLEAN;
      case 'V' :
        return TypeBinding.VOID;
      case 'C' :
        return TypeBinding.CHAR;
      case 'D' :
        return TypeBinding.DOUBLE;
      case 'B' :
        return TypeBinding.BYTE;
      case 'F' :
        return TypeBinding.FLOAT;
      case 'J' :
        return TypeBinding.LONG;
      case 'S' :
        return TypeBinding.SHORT;
      case 'N':
        return TypeBinding.NULL;
      default :
        return null;
    }
  }
  
  /*
   * Returns a binary binding corresonding to this key's compound name.
   * Returns null if not found.
   */
  private TypeBinding getBinaryBinding() {
    if (this.compoundName.length == 0) return null;
    return this.environment.getType(this.compoundName);
  }
  
  /*
   * Finds the compilation unit declaration corresponding to the key in the given lookup environment.
   * Returns null if no compilation unit declaration could be found.
   * This key's scanner should be positioned on the package token.
   */
  public CompilationUnitDeclaration getCompilationUnitDeclaration() {
    char[][] name = this.compoundName;
    if (name.length == 0) return null;
    if (this.environment == null) return null;
    ReferenceBinding binding = this.environment.getType(name);
    if (!(binding instanceof SourceTypeBinding)) {
      if (this.secondarySimpleName == null)
        return null;
      // case of a secondary type with no primary type (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=177115)
      int length = name.length;
      System.arraycopy(name, 0, name = new char[length][], 0, length-1);
      name[length-1] = this.secondarySimpleName;
      binding = this.environment.getType(name);
      if (!(binding instanceof SourceTypeBinding))
        return null;
    }
    SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) binding;
    if (sourceTypeBinding.scope == null)
      return null;
    return sourceTypeBinding.scope.compilationUnitScope().referenceContext;
  }
  
  /*
   * Returns the compiler binding corresponding to this key.
   * Returns null is malformed.
   * This key's scanner should be positioned on the package token.
   */
  public Binding getCompilerBinding() {
    try {
      parse();
      return this.compilerBinding;
    } catch (RuntimeException e) {
      Util.log(e, "Could not create binding from binding key: " + getKey()); //$NON-NLS-1$
      return null;
    }
  }
 
  private TypeBinding getTypeBinding(char[] simpleTypeName) {
    if (this.typeBinding instanceof BinaryTypeBinding) {
      return ((BinaryTypeBinding) this.typeBinding).getMemberType(simpleTypeName);
    } else {
      TypeDeclaration[] typeDeclarations =
        this.typeDeclaration == null ?
          (this.parsedUnit == null ? null : this.parsedUnit.types) :
          this.typeDeclaration.memberTypes;
      if (typeDeclarations == null) return null;
      for (int i = 0, length = typeDeclarations.length; i < length; i++) {
        TypeDeclaration declaration = typeDeclarations[i];
        if (CharOperation.equals(simpleTypeName, declaration.name)) {
          this.typeDeclaration = declaration;
          return declaration.binding;
        }
      }
    }
    return null;
  }
 
  private TypeBinding[] getTypeBindingArguments() {
    int size = this.types.size();
    TypeBinding[] arguments = new TypeBinding[size];
    for (int i = 0; i < size; i++) {
      BindingKeyResolver resolver = (BindingKeyResolver) this.types.get(i);
      TypeBinding compilerBinding2 = (TypeBinding) resolver.compilerBinding;
      if (compilerBinding2 == null) {
        throw new IllegalArgumentException();
      }
      arguments[i] = compilerBinding2;
    }
    this.types = new ArrayList();
    return arguments;
  }
  
  public void malformedKey() {
    this.compoundName = CharOperation.NO_CHAR_CHAR;
  }
 
  public BindingKeyParser newParser() {
    return new BindingKeyResolver(this, this.compiler, this.environment, this.rank, this.outerMostParsedUnit == null ? this.parsedUnit : this.outerMostParsedUnit);
  }
  
  public String toString() {
    return getKey();
  }

}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.core.util.CaptureFinder

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.