Logo Search packages:      
Sourcecode: aspectj version File versions

InterTypeMemberFinder.java

/* *******************************************************************
 * Copyright (c) 2002,2005 Contributors.
 * 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: 
 *     PARC     initial implementation 
 *     Andy Clement - upgrade to support fields targetting generic types
 * ******************************************************************/


package org.aspectj.ajdt.internal.compiler.lookup;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.IMemberFinder;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
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.SourceTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;

/**
 * The member finder looks after intertype declared members on a type, there is
 * one member finder per type that was hit by an ITD.
 */
00041 public class InterTypeMemberFinder implements IMemberFinder {
      private List interTypeFields = new ArrayList();
      private List interTypeMethods = new ArrayList();
      
      public SourceTypeBinding sourceTypeBinding;
      
      public FieldBinding getField(SourceTypeBinding sourceTypeBinding,char[] fieldName,InvocationSite site,Scope scope) {
            FieldBinding retField = sourceTypeBinding.getFieldBase(fieldName, true);  // XXX may need to get the correct value for second parameter in the future (see #55341)
            if (interTypeFields.isEmpty()) return retField;
            int fieldLength = fieldName.length;
            
            for (int i=0, len=interTypeFields.size(); i < len; i++) {
                  FieldBinding field = (FieldBinding)interTypeFields.get(i);
                  if (field.name.length == fieldLength      && CharOperation.prefixEquals(field.name, fieldName)) {
                        retField = resolveConflicts(sourceTypeBinding, retField, field, site, scope); 
                  }
            }
            
            return retField;
      }
      
      private FieldBinding resolveConflicts(
            SourceTypeBinding sourceTypeBinding,
            FieldBinding retField,
            FieldBinding field,
            InvocationSite site,
            Scope scope)
      {
            if (retField == null) return field;
            if (site != null) {
                  if (!field.canBeSeenBy(sourceTypeBinding, site, scope)) return retField;
                  if (!retField.canBeSeenBy(sourceTypeBinding, site, scope)) return field;
            }
            //XXX need dominates check on aspects
            return new ProblemFieldBinding(retField.declaringClass, retField.name, IProblem.AmbiguousField);//ProblemReporter.Ambiguous);
      }


//    private void reportConflicts(SourceTypeBinding sourceTypeBinding,
//          MethodBinding m1, MethodBinding m2)
//    {
//          if (m1 == m2) {
//                System.err.println("odd that we're ecomparing the same: " + m1);
//                return;
//          }
//          
//          if (!m1.areParametersEqual(m2)) return;
            
//          if (m1 instanceof InterTypeMethodBinding) {
//                if (m2 instanceof InterTypeMethodBinding) {
//                      reportConflictsBoth(sourceTypeBinding,
//                                                    (InterTypeMethodBinding)m1,
//                                                    (InterTypeMethodBinding)m2);
//                } else {
//                      reportConflictsOne(sourceTypeBinding,
//                                                    (InterTypeMethodBinding)m1,
//                                                    m2);
//                }
//          } else if (m2 instanceof InterTypeMethodBinding) {
//                reportConflictsOne(sourceTypeBinding,
//                                                    (InterTypeMethodBinding)m2,
//                                                    m1);
//          } else {
//                reportConflictsNone(sourceTypeBinding,
//                                              m2,
//                                              m1);
//          }
//    }
      

//    private void reportConflicts(
//          SourceTypeBinding sourceTypeBinding,
//          MethodBinding m1,
//          MethodBinding m2)
//    {
//          //System.err.println("compare: " + m1 + " with " + m2);
//          
//          if (m1 == m2) {
//                System.err.println("odd that we're ecomparing the same: " + m1);
//                return;
//          }
//          
//          if (!m1.areParametersEqual(m2)) return;
//          
//          //System.err.println("t1: " + getTargetType(m1) + ", " + getTargetType(m2));
//          
//          if (getTargetType(m1) != getTargetType(m2)) return;
//          
//          if (m1.declaringClass == m2.declaringClass) {
//                duplicateMethodBinding(m1, m2);
//                return;
//          }
//          
//          
//          if (m1.isPublic() || m2.isPublic()) {
//                duplicateMethodBinding(m1, m2);
//                return;
//          }
//          
//          // handle the wierd case where the aspect is a subtype of the target
//          if (m2.isProtected()) {
//                if (m2.declaringClass.isSuperclassOf(m1.declaringClass)) {
//                      duplicateMethodBinding(m1, m2);
//                }
//                // don't return because we also want to do the package test
//          }
//          
//          if (!m1.isPrivate() || !m2.isPrivate()) {
//                // at least package visible
//                if (m1.declaringClass.getPackage() == m2.declaringClass.getPackage()) {
//                      duplicateMethodBinding(m1, m2);
//                }
//                return;
//          }                       
//          
//          //XXX think about inner types some day
//    }
////  
      private boolean isVisible(MethodBinding m1, ReferenceBinding s) {
            if (m1.declaringClass == s) return true;

            
            if (m1.isPublic()) return true;

            //don't need to handle protected
            //if (m1.isProtected()) {

            
            if (!m1.isPrivate()) {
                  // at least package visible
                  return (m1.declaringClass.getPackage() == s.getPackage());
            }
            
            return false;
      }
      
//
//    private void duplicateMethodBinding(MethodBinding m1, MethodBinding m2) {
//          ReferenceBinding t1 = m1.declaringClass;
//          ReferenceBinding t2 = m2.declaringClass;
//          
//          
//          
//          
//          
//          
//          if (!(t1 instanceof SourceTypeBinding) || !(t2 instanceof SourceTypeBinding)) {
//                throw new RuntimeException("unimplemented");
//          }
//          
//          SourceTypeBinding s1 = (SourceTypeBinding)t1;
//          SourceTypeBinding s2 = (SourceTypeBinding)t2;
//
//          if (m1.sourceMethod() != null) {
//                s1.scope.problemReporter().duplicateMethodInType(s2, m1.sourceMethod());
//          }
//          if (m2.sourceMethod() != null) {
//                s2.scope.problemReporter().duplicateMethodInType(s1, m2.sourceMethod());
//          }
//    }
      
//    private void reportConflictsNone(
//          SourceTypeBinding sourceTypeBinding,
//          MethodBinding m2,
//          MethodBinding m1)
//    {
//          throw new RuntimeException("not possible");
//    }



//          ReferenceBinding t1 = getDeclaringClass(m1);
//          //.declaringClass;
//          ReferenceBinding t2 = getDeclaringClass(m2);
//          //.declaringClass;
//          
//          if (t1 == t2) {
//                AbstractMethodDeclaration methodDecl = m2.sourceMethod(); // cannot be retrieved after binding is lost
//                System.err.println("duplicate: " + t1 + ", " + t2);
//                sourceTypeBinding.scope.problemReporter().duplicateMethodInType(sourceTypeBinding, methodDecl);
//                methodDecl.binding = null;
//                //methods[m] = null;  //XXX duplicate problem reports
//                return;
//          }
//          
//          if (!(t1 instanceof SourceTypeBinding) || !(t2 instanceof SourceTypeBinding)) {
//                throw new RuntimeException("unimplemented");
//          }
//          
//          SourceTypeBinding s1 = (SourceTypeBinding)t1;
//          SourceTypeBinding s2 = (SourceTypeBinding)t2;
//          
//          
//          if (m1.canBeSeenBy(s1, null, s2.scope) || m2.canBeSeenBy(s2, null, s1.scope)) {
//                s1.scope.problemReporter().duplicateMethodInType(s2, m1.sourceMethod());
//                s2.scope.problemReporter().duplicateMethodInType(s1, m2.sourceMethod());
//          }
//    }

//    private ReferenceBinding getTargetType(MethodBinding m2) {
//          if (m2 instanceof InterTypeMethodBinding) {
//                return ((InterTypeMethodBinding)m2).getTargetType();
//          }
//          
//          return m2.declaringClass;
//    }

      // find all of my methods, including ITDs
      // PLUS: any public ITDs made on interfaces that I implement
      public MethodBinding[] methods(SourceTypeBinding sourceTypeBinding) {
            MethodBinding[] orig = sourceTypeBinding.methodsBase();
//          if (interTypeMethods.isEmpty()) return orig;
            
            List ret = new ArrayList(Arrays.asList(orig));
            for (int i=0, len=interTypeMethods.size(); i < len; i++) {
                  MethodBinding method = (MethodBinding)interTypeMethods.get(i);
                  ret.add(method);
            }
            
            ReferenceBinding [] interfaces = sourceTypeBinding.superInterfaces();
            for (int i = 0; i < interfaces.length; i++) {
                  if (interfaces[i] instanceof SourceTypeBinding) {
                        SourceTypeBinding intSTB = (SourceTypeBinding) interfaces[i];
                        addPublicITDSFrom(intSTB,ret);
                  }
            }
            
            if (ret.isEmpty()) return Binding.NO_METHODS;
            return (MethodBinding[])ret.toArray(new MethodBinding[ret.size()]);     
      }
      
      private void addPublicITDSFrom(SourceTypeBinding anInterface,List toAList) {
            if (anInterface.memberFinder != null) {
                  InterTypeMemberFinder finder = (InterTypeMemberFinder) anInterface.memberFinder;
                  for (Iterator iter = finder.interTypeMethods.iterator(); iter.hasNext();) {
                        MethodBinding aBinding = (MethodBinding) iter.next();
                        if (Modifier.isPublic(aBinding.modifiers)) {
                              toAList.add(aBinding);
                        }
                  }
            }
            ReferenceBinding superType = anInterface.superclass;
            if (superType instanceof SourceTypeBinding && superType.isInterface()) {
                  addPublicITDSFrom((SourceTypeBinding)superType,toAList);
            }
      }
      
      //XXX conflicts
      public MethodBinding[] getMethods(
            SourceTypeBinding sourceTypeBinding,
            char[] selector) {
//          System.err.println("getMethods: " + new String(sourceTypeBinding.signature()) +
//                                        ", " + new String(selector));
                  
            MethodBinding[] orig = sourceTypeBinding.getMethodsBase(selector);
            if (interTypeMethods.isEmpty()) return orig;
            
            List ret = new ArrayList(Arrays.asList(orig));
//          System.err.println("declared method: " + ret + " inters = " + interTypeMethods);
            
            for (int i=0, len=interTypeMethods.size(); i < len; i++) {
                  MethodBinding method = (MethodBinding)interTypeMethods.get(i);
                  
                  if (CharOperation.equals(selector, method.selector)) {
                        ret.add(method);
                  }
            }
            
            if (ret.isEmpty()) return Binding.NO_METHODS;
            
//          System.err.println("method: " + ret);
            
            // check for conflicts
//          int len = ret.size();
//          if (len > 1) {
//                for (int i=0; i <len; i++) {
//                      MethodBinding m1 = (MethodBinding)ret.get(i);
//                      for (int j=i+1; j < len; j++) {
//                            MethodBinding m2 = (MethodBinding)ret.get(j);
//                            //reportConflicts(sourceTypeBinding, m1, m2);
//                      }
//                }     
//          }
            
            
            //System.err.println("got methods: " + ret + " on " + sourceTypeBinding);
            
            return (MethodBinding[])ret.toArray(new MethodBinding[ret.size()]);     
      }
      
      public MethodBinding getExactMethod(
            SourceTypeBinding sourceTypeBinding,
            char[] selector,
            TypeBinding[] argumentTypes,
            CompilationUnitScope refScope)
      {
            MethodBinding ret = sourceTypeBinding.getExactMethodBase(selector, argumentTypes,refScope);
            
            // An intertype declaration may override an inherited member (Bug#50776)
            for (int i=0, len=interTypeMethods.size(); i < len; i++) {
                  MethodBinding im =
                        (MethodBinding)interTypeMethods.get(i);
                  if (matches(im, selector, argumentTypes)) {
                        return im;
                  }
            }
            return ret;
      }
//                      if (isVisible(im, sourceTypeBinding)) {
//                            if (ret == null) {
//                                  ret = im;
//                            } else {
//                                  ret = resolveOverride(ret, im);
//                            }
//                      }
//                }
//          }
//          return ret;
//    }

//    private MethodBinding resolveOverride(MethodBinding m1, MethodBinding m2) {
//          ReferenceBinding t1 = getTargetType(m1);
//          ReferenceBinding t2 = getTargetType(m2);
//          if (t1 == t2) {
//                //XXX also need a test for completely matching sigs
//                if (m1.isAbstract()) return m2;
//                else if (m2.isAbstract()) return m1;
//                
//                
//                if (m1 instanceof InterTypeMethodBinding) {
//                      //XXX need to handle dominates here
//                      EclipseWorld world = EclipseWorld.fromScopeLookupEnvironment(sourceTypeBinding.scope);
//                      int cmp = compareAspectPrecedence(world.fromEclipse(m1.declaringClass), 
//                                                        world.fromEclipse(m2.declaringClass));
//                      if (cmp < 0) return m2;
//                      else if (cmp > 0) return m1;
//                }
//                
//                duplicateMethodBinding(m1, m2);
//                return null;
//          }
//          if (t1.isSuperclassOf(t2)) {
//                return m2;
//          }
//          if (t2.isSuperclassOf(t1)) {
//                return m1;
//          }
//          
//          duplicateMethodBinding(m1, m2);
//          return null;
//    }


//    private int compareAspectPrecedence(ResolvedType a1, ResolvedType a2) {
//          World world = a1.getWorld();
//          int ret = world.compareByDominates(a1, a2);
//          if (ret == 0) {
//                if (a1.isAssignableFrom(a2)) return -1;
//                if (a2.isAssignableFrom(a1)) return +1;
//          }
//          return ret;
//    }

      
      //
      private boolean matches(MethodBinding m1, MethodBinding m2) {
            return matches(m1, m2.selector, m2.parameters);
            // && 
            //    (isVisible(m1, m2.declaringClass) || isVisible(m2, m1.declaringClass));
      }
      
      private boolean matches(MethodBinding method, char[] selector, TypeBinding[] argumentTypes) {
            if (!CharOperation.equals(selector, method.selector)) return false;
            int argCount = argumentTypes.length;
            if (method.parameters.length != argCount) return false;
            
            TypeBinding[] toMatch = method.parameters;
            for (int p = 0; p < argCount; p++) {
                  if (toMatch[p] != argumentTypes[p]) return false;
            }
            return true;
      }
      
      
      

      public void addInterTypeField(FieldBinding binding) {
            //System.err.println("adding: " + binding + " to " + this);
            interTypeFields.add(binding);
      }
      
      public void addInterTypeMethod(MethodBinding binding) {
            // check for conflicts with existing methods, should really check type as well...
            //System.err.println("adding: " + binding + " to " + sourceTypeBinding);
            if (isVisible(binding, sourceTypeBinding)) {
                  MethodBinding[] baseMethods = sourceTypeBinding.methods;
                  for (int i=0, len=baseMethods.length; i < len; i++) {
                        MethodBinding b = baseMethods[i];
                        sourceTypeBinding.resolveTypesFor(b); // this will return fast if its already been done.
                        if (matches(binding, b)) {
                              // this always means we should remove the existing method
                              if (b.sourceMethod() != null) {
                                    b.sourceMethod().binding = null; 
                              }
                              sourceTypeBinding.removeMethod(i);
                              //System.err.println("    left: " + Arrays.asList(sourceTypeBinding.methods));
                              break;
                        }
                  }
            }

            interTypeMethods.add(binding);
      }

}

Generated by  Doxygen 1.6.0   Back to index