blob: 50332c1c01296a922e00354cc8ad20fb96929faf [file] [log] [blame]
/* *******************************************************************
* Copyright (c) 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://eclipse.org/legal/epl-v10.html
*
* Contributors:
* Adrian Colyer Initial implementation
* ******************************************************************/
package org.aspectj.weaver;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Iterates over the signatures of a join point, calculating new signatures lazily to minimize processing and to avoid unneccessary
* "can't find type" errors. Iterator can be cached and reused by calling the "reset" method between iterations.
*/
public class JoinPointSignatureIterator implements Iterator<JoinPointSignature> {
ResolvedType firstDefiningType;
private Member signaturesOfMember;
private ResolvedMember firstDefiningMember;
private World world;
private List<JoinPointSignature> discoveredSignatures = new ArrayList<JoinPointSignature>();
private List<JoinPointSignature> additionalSignatures = Collections.emptyList();
private Iterator<JoinPointSignature> discoveredSignaturesIterator = null;
private Iterator<ResolvedType> superTypeIterator = null;
private boolean isProxy = false;
private Set<ResolvedType> visitedSuperTypes = new HashSet<ResolvedType>();
private List<SearchPair> yetToBeProcessedSuperMembers = null;
private boolean iteratingOverDiscoveredSignatures = true;
private boolean couldBeFurtherAsYetUndiscoveredSignatures = true;
private final static UnresolvedType jlrProxy = UnresolvedType.forSignature("Ljava/lang/reflect/Proxy;");
public JoinPointSignatureIterator(Member joinPointSignature, World world) {
this.signaturesOfMember = joinPointSignature;
this.world = world;
addSignaturesUpToFirstDefiningMember();
if (!shouldWalkUpHierarchy()) {
couldBeFurtherAsYetUndiscoveredSignatures = false;
}
}
public void reset() {
discoveredSignaturesIterator = discoveredSignatures.iterator();
additionalSignatures.clear();
iteratingOverDiscoveredSignatures = true;
}
public boolean hasNext() {
if (iteratingOverDiscoveredSignatures && discoveredSignaturesIterator.hasNext()) {
return true;
} else if (couldBeFurtherAsYetUndiscoveredSignatures) {
if (additionalSignatures.size() > 0) {
return true;
} else {
return findSignaturesFromSupertypes();
}
} else {
return false;
}
}
public JoinPointSignature next() {
if (iteratingOverDiscoveredSignatures && discoveredSignaturesIterator.hasNext()) {
return discoveredSignaturesIterator.next();
} else {
if (additionalSignatures.size() > 0) {
return additionalSignatures.remove(0);
}
}
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException("can't remove from JoinPointSignatureIterator");
}
/**
* Walk up the hierarchy creating one member for each type up to and including the first defining type.
*/
private void addSignaturesUpToFirstDefiningMember() {
ResolvedType originalDeclaringType = signaturesOfMember.getDeclaringType().resolve(world);
ResolvedType superType = originalDeclaringType.getSuperclass();
if (superType != null && superType.equals(jlrProxy)) {
// Proxy types are generated without any regard to generics (pr268419) and so the member walking
// should also ignore them
isProxy = true;
}
// is it the array constructor join point?
if (world.isJoinpointArrayConstructionEnabled() && originalDeclaringType.isArray()) {
Member m = signaturesOfMember;
ResolvedMember rm = new ResolvedMemberImpl(m.getKind(), m.getDeclaringType(), m.getModifiers(), m.getReturnType(), m
.getName(), m.getParameterTypes());
discoveredSignatures.add(new JoinPointSignature(rm, originalDeclaringType));
couldBeFurtherAsYetUndiscoveredSignatures = false;
return;
}
firstDefiningMember = (signaturesOfMember instanceof ResolvedMember ?
(ResolvedMember) signaturesOfMember: signaturesOfMember.resolve(world));
if (firstDefiningMember == null) {
couldBeFurtherAsYetUndiscoveredSignatures = false;
return;
}
// declaringType can be unresolved if we matched a synthetic member generated by Aj...
// should be fixed elsewhere but add this resolve call on the end for now so that we can
// focus on one problem at a time...
firstDefiningType = firstDefiningMember.getDeclaringType().resolve(world);
if (firstDefiningType != originalDeclaringType) {
if (signaturesOfMember.getKind() == Member.CONSTRUCTOR) {
return;
}
}
if (originalDeclaringType == firstDefiningType) {
// a common case
discoveredSignatures.add(new JoinPointSignature(firstDefiningMember, originalDeclaringType));
} else {
List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
accumulateTypesInBetween(originalDeclaringType, firstDefiningType, declaringTypes);
for (ResolvedType declaringType : declaringTypes) {
discoveredSignatures.add(new JoinPointSignature(firstDefiningMember, declaringType));
}
}
}
/**
* Build a list containing every type between subtype and supertype, inclusively.
*/
private void accumulateTypesInBetween(ResolvedType subType, ResolvedType superType, List<ResolvedType> types) {
types.add(subType);
if (subType == superType) {
return;
} else {
for (Iterator<ResolvedType> iter = subType.getDirectSupertypes(); iter.hasNext();) {
ResolvedType parent = iter.next();
if (superType.isAssignableFrom(parent, true)) {
accumulateTypesInBetween(parent, superType, types);
}
}
}
}
private boolean shouldWalkUpHierarchy() {
if (signaturesOfMember.getKind() == Member.CONSTRUCTOR) {
return false;
}
if (signaturesOfMember.getKind() == Member.FIELD) {
return false;
}
if (Modifier.isStatic(signaturesOfMember.getModifiers())) {
return false;
}
return true;
}
private boolean findSignaturesFromSupertypes() {
iteratingOverDiscoveredSignatures = false;
if (superTypeIterator == null) {
superTypeIterator = firstDefiningType.getDirectSupertypes();
}
if (superTypeIterator.hasNext()) {
ResolvedType superType = superTypeIterator.next();
if (isProxy && (superType.isGenericType() || superType.isParameterizedType())) {
superType = superType.getRawType();
}
if (visitedSuperTypes.contains(superType)) {
return findSignaturesFromSupertypes();
} else {
// we haven't looked in this type yet
visitedSuperTypes.add(superType);
if (superType.isMissing()) {
// issue a warning, stop looking for join point signatures in this line
warnOnMissingType(superType);
return findSignaturesFromSupertypes();
}
ResolvedMemberImpl foundMember = (ResolvedMemberImpl) superType.lookupResolvedMember(firstDefiningMember, true,
isProxy);
if (foundMember != null && isVisibleTo(firstDefiningMember, foundMember)) {
List<ResolvedType> declaringTypes = new ArrayList<ResolvedType>();
// declaring type can be unresolved if the member can from an ITD...
ResolvedType resolvedDeclaringType = foundMember.getDeclaringType().resolve(world);
accumulateTypesInBetween(superType, resolvedDeclaringType, declaringTypes);
for (ResolvedType declaringType : declaringTypes) {
JoinPointSignature member = null;
if (isProxy) {
if (declaringType.isGenericType() || declaringType.isParameterizedType()) {
declaringType = declaringType.getRawType();
}
}
member = new JoinPointSignature(foundMember, declaringType);
discoveredSignatures.add(member); // for next time we are reset
if (additionalSignatures == Collections.EMPTY_LIST) {
additionalSignatures = new ArrayList<JoinPointSignature>();
}
additionalSignatures.add(member); // for this time
}
// if this was a parameterized type, look in the generic type that backs it too
if (!isProxy && superType.isParameterizedType() && (foundMember.backingGenericMember != null)) {
JoinPointSignature member = new JoinPointSignature(foundMember.backingGenericMember,
foundMember.declaringType.resolve(world));
discoveredSignatures.add(member); // for next time we are reset
if (additionalSignatures == Collections.EMPTY_LIST) {
additionalSignatures = new ArrayList<JoinPointSignature>();
}
additionalSignatures.add(member); // for this time
}
if (yetToBeProcessedSuperMembers == null) {
yetToBeProcessedSuperMembers = new ArrayList<SearchPair>();
}
yetToBeProcessedSuperMembers.add(new SearchPair(foundMember, superType));
return true;
} else {
return findSignaturesFromSupertypes();
}
}
}
if (yetToBeProcessedSuperMembers != null && !yetToBeProcessedSuperMembers.isEmpty()) {
SearchPair nextUp = yetToBeProcessedSuperMembers.remove(0);
firstDefiningType = nextUp.type;
firstDefiningMember = nextUp.member;
superTypeIterator = null;
return findSignaturesFromSupertypes();
}
couldBeFurtherAsYetUndiscoveredSignatures = false;
return false;
}
/**
* Returns true if the parent member is visible to the child member In the same declaring type this is always true, otherwise if
* parent is private it is false.
*
* @param childMember
* @param parentMember
* @return
*/
private boolean isVisibleTo(ResolvedMember childMember, ResolvedMember parentMember) {
if (childMember.getDeclaringType().equals(parentMember.getDeclaringType())) {
return true;
}
if (Modifier.isPrivate(parentMember.getModifiers())) {
return false;
} else {
return true;
}
}
private void warnOnMissingType(ResolvedType missing) {
if (missing instanceof MissingResolvedTypeWithKnownSignature) {
// which it should be...
MissingResolvedTypeWithKnownSignature mrt = (MissingResolvedTypeWithKnownSignature) missing;
mrt.raiseWarningOnJoinPointSignature(signaturesOfMember.toString());
}
}
private static class SearchPair {
public ResolvedMember member;
public ResolvedType type;
public SearchPair(ResolvedMember member, ResolvedType type) {
this.member = member;
this.type = type;
}
}
}