/* ******************************************************************* * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Eclipse Public License v 2.0 * which accompanies this distribution and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt * * Contributors: * PARC initial implementation * ******************************************************************/ package org.aspectj.weaver.patterns; import java.io.IOException; import java.util.List; import java.util.Map; import org.aspectj.bridge.IMessage; import org.aspectj.weaver.CompressingDataOutputStream; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.VersionedDataInputStream; import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.World; public class DeclarePrecedence extends Declare { private TypePatternList patterns; private IScope scope = null; // non-null means it has not yet been resolved (used by annotation style lazy resolution) public DeclarePrecedence(List patterns) { this(new TypePatternList(patterns)); } private DeclarePrecedence(TypePatternList patterns) { this.patterns = patterns; } public Object accept(PatternNodeVisitor visitor, Object data) { return visitor.visit(this, data); } public Object traverse(PatternNodeVisitor visitor, Object data) { Object ret = accept(visitor, data); if (this.patterns != null) this.patterns.traverse(visitor, ret); return ret; } public Declare parameterizeWith(Map typeVariableBindingMap, World w) { DeclarePrecedence ret = new DeclarePrecedence(this.patterns.parameterizeWith(typeVariableBindingMap, w)); ret.copyLocationFrom(this); return ret; } public String toString() { StringBuilder buf = new StringBuilder(); buf.append("declare precedence: "); buf.append(patterns); buf.append(";"); return buf.toString(); } public boolean equals(Object other) { if (!(other instanceof DeclarePrecedence)) { return false; } DeclarePrecedence o = (DeclarePrecedence) other; return o.patterns.equals(patterns); } public int hashCode() { return patterns.hashCode(); } public void write(CompressingDataOutputStream s) throws IOException { s.writeByte(Declare.DOMINATES); patterns.write(s); writeLocation(s); } public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException { Declare ret = new DeclarePrecedence(TypePatternList.read(s, context)); ret.readLocation(context, s); return ret; } public void setScopeForResolution(IScope scope) { this.scope = scope; } public void ensureResolved() { // Lazy resolution - due to pr256779 if (scope != null) { try { resolve(scope); } finally { scope = null; } } } public void resolve(IScope scope) { patterns = patterns.resolveBindings(scope, Bindings.NONE, false, false); boolean seenStar = false; for (int i = 0; i < patterns.size(); i++) { TypePattern pi = patterns.get(i); if (pi.isStar()) { if (seenStar) { scope.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.TWO_STARS_IN_PRECEDENCE), pi.getSourceLocation(), null); } seenStar = true; continue; } ResolvedType exactType = pi.getExactType().resolve(scope.getWorld()); if (exactType.isMissing()) { continue; } // Cannot do a dec prec specifying a non-aspect types unless suffixed with a '+' if (!exactType.isAspect() && !exactType.isAnnotationStyleAspect() && !pi.isIncludeSubtypes() && !exactType.isTypeVariableReference()) { scope.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CLASSES_IN_PRECEDENCE, exactType.getName()), pi.getSourceLocation(), null); } for (int j = 0; j < patterns.size(); j++) { if (j == i) { continue; } TypePattern pj = patterns.get(j); if (pj.isStar()) { continue; } if (pj.matchesStatically(exactType)) { scope.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.TWO_PATTERN_MATCHES_IN_PRECEDENCE, exactType.getName()), pi.getSourceLocation(), pj.getSourceLocation()); } } } } public TypePatternList getPatterns() { ensureResolved(); return patterns; } private int matchingIndex(ResolvedType a) { ensureResolved(); int knownMatch = -1; int starMatch = -1; for (int i = 0, len = patterns.size(); i < len; i++) { TypePattern p = patterns.get(i); if (p.isStar()) { starMatch = i; } else if (p.matchesStatically(a)) { if (knownMatch != -1) { a.getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.MULTIPLE_MATCHES_IN_PRECEDENCE, a, patterns.get(knownMatch), p), patterns.get(knownMatch).getSourceLocation(), p.getSourceLocation()); return -1; } else { knownMatch = i; } } } if (knownMatch == -1) { return starMatch; } else { return knownMatch; } } public int compare(ResolvedType aspect1, ResolvedType aspect2) { ensureResolved(); int index1 = matchingIndex(aspect1); int index2 = matchingIndex(aspect2); // System.out.println("a1: " + aspect1 + ", " + aspect2 + " = " + index1 + ", " + index2); if (index1 == -1 || index2 == -1) { return 0; } if (index1 == index2) { return 0; } else if (index1 > index2) { return -1; } else { return +1; } } public boolean isAdviceLike() { return false; } public String getNameSuffix() { return "precedence"; } }