From bf421b12cd13c5ae688e9b96abb663071414fa66 Mon Sep 17 00:00:00 2001 From: acolyer Date: Tue, 8 Jun 2004 13:54:29 +0000 Subject: [PATCH] support for asking a pointcut if it matches at a join point --- .../aspectj/weaver/patterns/AndPointcut.java | 16 +- .../weaver/patterns/AndTypePattern.java | 22 +- .../aspectj/weaver/patterns/ArgsPointcut.java | 27 ++- .../weaver/patterns/CflowPointcut.java | 6 + .../patterns/ConcreteCflowPointcut.java | 3 + .../weaver/patterns/ExactTypePattern.java | 24 ++ .../aspectj/weaver/patterns/ExposedState.java | 1 + .../weaver/patterns/HandlerPointcut.java | 18 ++ .../aspectj/weaver/patterns/IfPointcut.java | 17 ++ .../weaver/patterns/KindedPointcut.java | 30 +++ .../aspectj/weaver/patterns/NotPointcut.java | 13 ++ .../weaver/patterns/NotTypePattern.java | 20 +- .../aspectj/weaver/patterns/OrPointcut.java | 14 ++ .../weaver/patterns/OrTypePattern.java | 20 ++ .../org/aspectj/weaver/patterns/PerCflow.java | 2 +- .../aspectj/weaver/patterns/PerClause.java | 6 +- .../org/aspectj/weaver/patterns/Pointcut.java | 37 +++ .../weaver/patterns/ReferencePointcut.java | 4 + .../weaver/patterns/SignaturePattern.java | 123 +++++++++- .../weaver/patterns/ThisOrTargetPointcut.java | 11 + .../weaver/patterns/ThrowsPattern.java | 32 +++ .../aspectj/weaver/patterns/TypePattern.java | 88 +++++++ .../weaver/patterns/TypePatternList.java | 214 ++++++++++++++++++ .../weaver/patterns/WildTypePattern.java | 66 +++++- .../weaver/patterns/WithinPointcut.java | 20 ++ .../weaver/patterns/WithincodePointcut.java | 9 + .../weaver/patterns/AndOrNotTestCase.java | 36 +++ .../aspectj/weaver/patterns/ArgsTestCase.java | 91 ++++++++ .../weaver/patterns/HandlerTestCase.java | 65 ++++++ .../weaver/patterns/KindedTestCase.java | 102 +++++++++ .../weaver/patterns/PatternsTests.java | 5 + .../weaver/patterns/PointcutTestCase.java | 79 +++++++ .../weaver/patterns/ThisOrTargetTestCase.java | 43 ++++ .../weaver/patterns/WithinCodeTestCase.java | 63 ++++++ .../weaver/patterns/WithinTestCase.java | 25 ++ 35 files changed, 1343 insertions(+), 9 deletions(-) create mode 100644 weaver/testsrc/org/aspectj/weaver/patterns/ArgsTestCase.java create mode 100644 weaver/testsrc/org/aspectj/weaver/patterns/HandlerTestCase.java create mode 100644 weaver/testsrc/org/aspectj/weaver/patterns/KindedTestCase.java create mode 100644 weaver/testsrc/org/aspectj/weaver/patterns/PointcutTestCase.java create mode 100644 weaver/testsrc/org/aspectj/weaver/patterns/WithinCodeTestCase.java diff --git a/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java b/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java index aea40a3e3..05952f593 100644 --- a/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java @@ -17,6 +17,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; @@ -42,6 +43,14 @@ public class AndPointcut extends Pointcut { return left.match(shadow).and(right.match(shadow)); } + public FuzzyBoolean match(JoinPoint jp, JoinPoint.StaticPart encJP) { + return left.match(jp,encJP).and(right.match(jp,encJP)); + } + + public FuzzyBoolean match(JoinPoint.StaticPart jpsp) { + return left.match(jpsp).and(right.match(jpsp)); + } + public String toString() { return "(" + left.toString() + " && " + right.toString() + ")"; } @@ -63,8 +72,11 @@ public class AndPointcut extends Pointcut { left.resolveBindings(scope, bindings); right.resolveBindings(scope, bindings); } - - + + public void resolveBindingsFromRTTI() { + left.resolveBindingsFromRTTI(); + right.resolveBindingsFromRTTI(); + } public void write(DataOutputStream s) throws IOException { s.writeByte(Pointcut.AND); diff --git a/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java index 468e95ab2..c055692fe 100644 --- a/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java @@ -48,10 +48,23 @@ public class AndTypePattern extends TypePattern { return left.matchesExactly(type) && right.matchesExactly(type); } - public boolean matchesStatically(ResolvedTypeX type) { + public boolean matchesStatically(Class type) { return left.matchesStatically(type) && right.matchesStatically(type); } + public FuzzyBoolean matchesInstanceof(Class type) { + return left.matchesInstanceof(type).and(right.matchesInstanceof(type)); + } + + protected boolean matchesExactly(Class type) { + //??? if these had side-effects, this sort-circuit could be a mistake + return left.matchesExactly(type) && right.matchesExactly(type); + } + + public boolean matchesStatically(ResolvedTypeX type) { + return left.matchesStatically(type) && right.matchesStatically(type); + } + public void write(DataOutputStream s) throws IOException { s.writeByte(TypePattern.AND); left.write(s); @@ -76,6 +89,13 @@ public class AndTypePattern extends TypePattern { return this; } + public TypePattern resolveBindingsFromRTTI(boolean allowBinding, boolean requireExactType) { + if (requireExactType) return TypePattern.NO; + left = left.resolveBindingsFromRTTI(allowBinding,requireExactType); + right = right.resolveBindingsFromRTTI(allowBinding,requireExactType); + return this; + } + public String toString() { return "(" + left.toString() + " && " + right.toString() + ")"; } diff --git a/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java index 86c55b920..efc1219c0 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java @@ -18,6 +18,9 @@ import java.io.DataOutputStream; import java.io.IOException; import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.bridge.Message; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.weaver.BetaException; import org.aspectj.weaver.ISourceContext; @@ -34,7 +37,7 @@ import org.aspectj.weaver.ast.Test; * @author Erik Hilsdale * @author Jim Hugunin */ -public class ArgsPointcut extends NameBindingPointcut { +public class ArgsPointcut extends NameBindingPointcut { TypePatternList arguments; public ArgsPointcut(TypePatternList arguments) { @@ -50,6 +53,10 @@ public class ArgsPointcut extends NameBindingPointcut { arguments.matches(shadow.getIWorld().resolve(shadow.getArgTypes()), TypePattern.DYNAMIC); return ret; } + + public FuzzyBoolean match(JoinPoint jp, JoinPoint.StaticPart jpsp) { + return arguments.matches(jp.getArgs(),TypePattern.DYNAMIC); + } public void write(DataOutputStream s) throws IOException { s.writeByte(Pointcut.ARGS); @@ -82,6 +89,13 @@ public class ArgsPointcut extends NameBindingPointcut { } } + public void resolveBindingsFromRTTI() { + arguments.resolveBindingsFromRTTI(true, true); + if (arguments.ellipsisCount > 1) { + throw new UnsupportedOperationException("uses more than one .. in args (compiler limitation)"); + } + } + public void postRead(ResolvedTypeX enclosingType) { arguments.postRead(enclosingType); } @@ -118,6 +132,17 @@ public class ArgsPointcut extends NameBindingPointcut { if (type.matchesInstanceof(shadow.getIWorld().resolve(argType)).alwaysTrue()) { continue; } + } else { + BindingTypePattern btp = (BindingTypePattern)type; + // Check if we have already bound something to this formal + if (state.get(btp.getFormalIndex())!=null) { + ISourceLocation isl = getSourceLocation(); + Message errorMessage = new Message( + "Ambiguous binding of type "+type.getExactType().toString()+ + " using args(..) at this line. Use one args(..) per matched join point,"+"" + " see secondary source location for location of extraneous args(..)", + shadow.getSourceLocation(),true,new ISourceLocation[]{getSourceLocation()}); + shadow.getIWorld().getMessageHandler().handleMessage(errorMessage); + } } ret = Test.makeAnd(ret, exposeStateForVar(shadow.getArgVar(i), type, state,shadow.getIWorld())); diff --git a/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java index ef6dc5d80..3a00891b1 100644 --- a/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java @@ -101,6 +101,12 @@ public class CflowPointcut extends Pointcut { } } + public void resolveBindingsFromRTTI() { + if (entry.state != RESOLVED) { + entry.resolveBindingsFromRTTI(); + } + } + public boolean equals(Object other) { if (!(other instanceof CflowPointcut)) return false; CflowPointcut o = (CflowPointcut)other; diff --git a/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java index cbb65f37e..df2c76bba 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java @@ -58,6 +58,9 @@ public class ConcreteCflowPointcut extends Pointcut { throw new RuntimeException("unimplemented"); } + public void resolveBindingsFromRTTI() { + throw new RuntimeException("unimplemented"); + } public boolean equals(Object other) { if (!(other instanceof ConcreteCflowPointcut)) return false; diff --git a/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java index 1da25d363..99ecf9012 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java @@ -48,6 +48,26 @@ public class ExactTypePattern extends TypePattern { return matchType.isCoerceableFrom(type) ? FuzzyBoolean.MAYBE : FuzzyBoolean.NO; } + public boolean matchesExactly(Class matchType) { + try { + Class toMatchAgainst = Class.forName(type.getName()); + return matchType == toMatchAgainst; + } catch (ClassNotFoundException cnfEx) { + return false; + } + } + + public FuzzyBoolean matchesInstanceof(Class matchType) { + if (matchType.equals(Object.class)) return FuzzyBoolean.YES; + + try { + Class toMatchAgainst = Class.forName(type.getName()); + return toMatchAgainst.isAssignableFrom(matchType) ? FuzzyBoolean.YES : FuzzyBoolean.NO; + } catch (ClassNotFoundException cnfEx) { + return FuzzyBoolean.NO; + } + } + public boolean equals(Object other) { if (!(other instanceof ExactTypePattern)) return false; ExactTypePattern o = (ExactTypePattern)other; @@ -81,5 +101,9 @@ public class ExactTypePattern extends TypePattern { throw new BCException("trying to re-resolve"); } + + public TypePattern resolveBindingsFromRTTI(boolean allowBinding, boolean requireExactType) { + throw new IllegalStateException("trying to re-resolve"); + } } diff --git a/weaver/src/org/aspectj/weaver/patterns/ExposedState.java b/weaver/src/org/aspectj/weaver/patterns/ExposedState.java index 8e130c689..063b5608e 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ExposedState.java +++ b/weaver/src/org/aspectj/weaver/patterns/ExposedState.java @@ -35,6 +35,7 @@ public class ExposedState { public void set(int i, Var var) { //XXX add sanity checks + // Check (1) added to call of set(), verifies we aren't binding twice to the same formal vars[i] = var; } public Var get(int i) { diff --git a/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java b/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java index aa50bd7b6..c1fcfdbd3 100644 --- a/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java @@ -17,6 +17,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; @@ -52,6 +53,18 @@ public class HandlerPointcut extends Pointcut { TypePattern.STATIC); } + public FuzzyBoolean match(JoinPoint jp, JoinPoint.StaticPart jpsp) { + if (!jp.getKind().equals(JoinPoint.EXCEPTION_HANDLER)) return FuzzyBoolean.NO; + if (jp.getArgs().length > 0) { + Object caughtException = jp.getArgs()[0]; + return exceptionType.matches(caughtException,TypePattern.STATIC); + } else { + return FuzzyBoolean.NO; + } + } + + + public boolean equals(Object other) { if (!(other instanceof HandlerPointcut)) return false; HandlerPointcut o = (HandlerPointcut)other; @@ -92,6 +105,11 @@ public class HandlerPointcut extends Pointcut { exceptionType = exceptionType.resolveBindings(scope, bindings, false, false); //XXX add error if exact binding and not an exception } + + public void resolveBindingsFromRTTI() { + exceptionType = exceptionType.resolveBindingsFromRTTI(false,false); + } + public Test findResidue(Shadow shadow, ExposedState state) { return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE; } diff --git a/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java b/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java index baf55d85b..e770509b3 100644 --- a/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java @@ -75,6 +75,8 @@ public class IfPointcut extends Pointcut { //??? all we need is good error messages in here in cflow contexts } + public void resolveBindingsFromRTTI() {} + public boolean equals(Object other) { if (!(other instanceof IfPointcut)) return false; IfPointcut o = (IfPointcut)other; @@ -161,6 +163,21 @@ public class IfPointcut extends Pointcut { } IfPointcut ret = new IfPointcut(testMethod, extraParameterFlags); partiallyConcretized = ret; + + // It is possible to directly code your pointcut expression in a per clause + // rather than defining a pointcut declaration and referencing it in your + // per clause. If you do this, we have problems (bug #62458). For now, + // let's police that you are trying to code a pointcut in a per clause and + // put out a compiler error. + if (bindings.directlyInAdvice() && bindings.getEnclosingAdvice()==null) { + // Assumption: if() is in a per clause if we say we are directly in advice + // but we have no enclosing advice. + inAspect.getWorld().showMessage(IMessage.ERROR, + "if() pointcut designator cannot be used directly in a per clause (compiler limitation). Create a named pointcut containing the if() and refer to it", + this.getSourceLocation(),null); + return Pointcut.makeMatchesNothing(Pointcut.CONCRETE); + } + if (bindings.directlyInAdvice()) { ShadowMunger advice = bindings.getEnclosingAdvice(); if (advice instanceof Advice) { diff --git a/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java index 43e53724b..6154f07d8 100644 --- a/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java @@ -18,10 +18,12 @@ import java.io.DataOutputStream; import java.io.IOException; import org.aspectj.bridge.ISourceLocation; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.weaver.Checker; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; +import org.aspectj.weaver.Member; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.Shadow; import org.aspectj.weaver.ShadowMunger; @@ -72,6 +74,15 @@ public class KindedPointcut extends Pointcut { return FuzzyBoolean.YES; } + public FuzzyBoolean match(JoinPoint.StaticPart jpsp) { + if (jpsp.getKind().equals(kind.getName())) { + if (signature.matches(jpsp)) { + return FuzzyBoolean.YES; + } + } + return FuzzyBoolean.NO; + } + private void warnOnConfusingSig(Shadow shadow) { // no warnings for declare error/warning if (munger instanceof Checker) return; @@ -180,7 +191,26 @@ public class KindedPointcut extends Pointcut { // this.getSourceLocation())); } signature = signature.resolveBindings(scope, bindings); + + + if (kind == Shadow.ConstructorExecution) { // Bug fix 60936 + if (signature.getDeclaringType() != null) { + World world = scope.getWorld(); + TypeX exactType = signature.getDeclaringType().getExactType(); + if (signature.getKind() == Member.CONSTRUCTOR && + !exactType.equals(ResolvedTypeX.MISSING) && + exactType.isInterface(world) && + !signature.getDeclaringType().isIncludeSubtypes()) { + world.getLint().noInterfaceCtorJoinpoint.signal(exactType.toString(), getSourceLocation()); + } + } + } + } + + public void resolveBindingsFromRTTI() { + signature = signature.resolveBindingsFromRTTI(); } + public Test findResidue(Shadow shadow, ExposedState state) { return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE; } diff --git a/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java b/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java index 59fe2522a..f57d2475d 100644 --- a/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java @@ -17,6 +17,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; @@ -44,6 +45,14 @@ public class NotPointcut extends Pointcut { public FuzzyBoolean match(Shadow shadow) { return body.match(shadow).not(); } + + public FuzzyBoolean match(JoinPoint jp, JoinPoint.StaticPart encJP) { + return body.match(jp,encJP).not(); + } + + public FuzzyBoolean match(JoinPoint.StaticPart jpsp) { + return body.match(jpsp).not(); + } public String toString() { return "!" + body.toString(); @@ -73,6 +82,10 @@ public class NotPointcut extends Pointcut { } + public void resolveBindingsFromRTTI() { + body.resolveBindingsFromRTTI(); + } + public void write(DataOutputStream s) throws IOException { s.writeByte(Pointcut.NOT); diff --git a/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java index 5a3ceacf9..68a719c73 100644 --- a/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java @@ -47,10 +47,22 @@ public class NotTypePattern extends TypePattern { return !pattern.matchesExactly(type); } - public boolean matchesStatically(ResolvedTypeX type) { + public boolean matchesStatically(Class type) { return !pattern.matchesStatically(type); } + public FuzzyBoolean matchesInstanceof(Class type) { + return pattern.matchesInstanceof(type).not(); + } + + protected boolean matchesExactly(Class type) { + return !pattern.matchesExactly(type); + } + + public boolean matchesStatically(ResolvedTypeX type) { + return !pattern.matchesStatically(type); + } + public void write(DataOutputStream s) throws IOException { s.writeByte(TypePattern.NOT); pattern.write(s); @@ -72,6 +84,12 @@ public class NotTypePattern extends TypePattern { pattern = pattern.resolveBindings(scope, bindings, false, false); return this; } + + public TypePattern resolveBindingsFromRTTI(boolean allowBinding, boolean requireExactType) { + if (requireExactType) return TypePattern.NO; + pattern = pattern.resolveBindingsFromRTTI(allowBinding,requireExactType); + return this; + } public String toString() { return "!" + pattern; diff --git a/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java b/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java index 1d1ce6298..225b100d7 100644 --- a/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java @@ -17,6 +17,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; @@ -43,6 +44,14 @@ public class OrPointcut extends Pointcut { return left.match(shadow).or(right.match(shadow)); } + public FuzzyBoolean match(JoinPoint jp, JoinPoint.StaticPart encJP) { + return left.match(jp,encJP).or(right.match(jp,encJP)); + } + + public FuzzyBoolean match(JoinPoint.StaticPart jpsp) { + return left.match(jpsp).or(right.match(jpsp)); + } + public String toString() { return "(" + left.toString() + " || " + right.toString() + ")"; } @@ -69,6 +78,11 @@ public class OrPointcut extends Pointcut { if (bindings != null) bindings.checkEquals(old, scope); } + + public void resolveBindingsFromRTTI() { + left.resolveBindingsFromRTTI(); + right.resolveBindingsFromRTTI(); + } public void write(DataOutputStream s) throws IOException { s.writeByte(Pointcut.OR); diff --git a/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java index 2900d4a2b..da53ad6e5 100644 --- a/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java @@ -52,6 +52,19 @@ public class OrTypePattern extends TypePattern { return left.matchesStatically(type) || right.matchesStatically(type); } + public FuzzyBoolean matchesInstanceof(Class type) { + return left.matchesInstanceof(type).or(right.matchesInstanceof(type)); + } + + protected boolean matchesExactly(Class type) { + //??? if these had side-effects, this sort-circuit could be a mistake + return left.matchesExactly(type) || right.matchesExactly(type); + } + + public boolean matchesStatically(Class type) { + return left.matchesStatically(type) || right.matchesStatically(type); + } + public void write(DataOutputStream s) throws IOException { s.writeByte(TypePattern.OR); left.write(s); @@ -76,6 +89,13 @@ public class OrTypePattern extends TypePattern { return this; } + public TypePattern resolveBindingsFromRTTI(boolean allowBinding, boolean requireExactType) { + if (requireExactType) return TypePattern.NO; + left = left.resolveBindingsFromRTTI(allowBinding,requireExactType); + right = right.resolveBindingsFromRTTI(allowBinding,requireExactType); + return this; + } + public String toString() { return "(" + left.toString() + " || " + right.toString() + ")"; } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java index 1c511bb08..f0626758f 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java @@ -59,7 +59,7 @@ public class PerCflow extends PerClause { // assert bindings == null; entry.resolve(scope); } - + public Test findResidue(Shadow shadow, ExposedState state) { Expr myInstance = Expr.makeCallExpr(AjcMemberMaker.perCflowAspectOfMethod(inAspect), diff --git a/weaver/src/org/aspectj/weaver/patterns/PerClause.java b/weaver/src/org/aspectj/weaver/patterns/PerClause.java index b28e8fc24..632778c9e 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerClause.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerClause.java @@ -54,7 +54,11 @@ public abstract class PerClause extends Pointcut { throw new BCException("weird kind " + key); } } - + + public void resolveBindingsFromRTTI() { + throw new UnsupportedOperationException("Can't resolve per-clauses at runtime"); + } + public static final Kind SINGLETON = new Kind("issingleton", 1); public static final Kind PERCFLOW = new Kind("percflow", 2); public static final Kind PEROBJECT = new Kind("perobject", 3); diff --git a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java index c7c98b425..466363135 100644 --- a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java @@ -17,6 +17,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.util.TypeSafeEnum; import org.aspectj.weaver.Advice; @@ -72,7 +73,23 @@ public abstract class Pointcut extends PatternNode { * XXX implementors need to handle state */ public abstract FuzzyBoolean match(Shadow shadow); + + /* + * for runtime / dynamic pointcuts. + * Default implementation delegates to StaticPart matcher + */ + public FuzzyBoolean match(JoinPoint jp, JoinPoint.StaticPart enclosingJoinPoint) { + return match(jp.getStaticPart()); + } + /* + * for runtime / dynamic pointcuts. + * Not all pointcuts can be matched at runtime, those that can should overide either + * match(JoinPoint), or this method, or both. + */ + public FuzzyBoolean match(JoinPoint.StaticPart jpsp) { + throw new UnsupportedOperationException("Pointcut expression " + this.toString() + "cannot be matched at runtime"); + } public static final byte KINDED = 1; public static final byte WITHIN = 2; @@ -93,6 +110,9 @@ public abstract class Pointcut extends PatternNode { // internal, only called from resolve protected abstract void resolveBindings(IScope scope, Bindings bindings); + // internal, only called from resolve + protected abstract void resolveBindingsFromRTTI(); + /** * Returns this pointcut mutated */ @@ -104,6 +124,16 @@ public abstract class Pointcut extends PatternNode { this.state = RESOLVED; return this; } + + /** + * Returns this pointcut with type patterns etc resolved based on available RTTI + */ + public Pointcut resolve() { + assertState(SYMBOLIC); + this.resolveBindingsFromRTTI(); + this.state = RESOLVED; + return this; + } /** * Returns a new pointcut @@ -218,9 +248,16 @@ public abstract class Pointcut extends PatternNode { public FuzzyBoolean match(Shadow shadow) { return FuzzyBoolean.NO; } + + public FuzzyBoolean match(JoinPoint.StaticPart jpsp) { + return FuzzyBoolean.NO; + } public void resolveBindings(IScope scope, Bindings bindings) { } + + public void resolveBindingsFromRTTI() { + } public void postRead(ResolvedTypeX enclosingType) { } diff --git a/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java b/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java index b253b4d18..af09bf906 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java @@ -199,6 +199,10 @@ public class ReferencePointcut extends Pointcut { } } + public void resolveBindingsFromRTTI() { + throw new UnsupportedOperationException("Referenced pointcuts are not supported in runtime evaluation"); + } + public void postRead(ResolvedTypeX enclosingType) { arguments.postRead(enclosingType); } diff --git a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java index 64a3f66b7..5e4e12185 100644 --- a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java @@ -16,9 +16,19 @@ package org.aspectj.weaver.patterns; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; +import java.util.List; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.reflect.AdviceSignature; +import org.aspectj.lang.reflect.ConstructorSignature; +import org.aspectj.lang.reflect.FieldSignature; +import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.Member; import org.aspectj.weaver.NameMangler; @@ -68,6 +78,23 @@ public class SignaturePattern extends PatternNode { return this; } + public SignaturePattern resolveBindingsFromRTTI() { + if (returnType != null) { + returnType = returnType.resolveBindingsFromRTTI(false, false); + } + if (declaringType != null) { + declaringType = declaringType.resolveBindingsFromRTTI(false, false); + } + if (parameterTypes != null) { + parameterTypes = parameterTypes.resolveBindingsFromRTTI(false, false); + } + if (throwsPattern != null) { + throwsPattern = throwsPattern.resolveBindingsFromRTTI(); + } + + return this; + } + public void postRead(ResolvedTypeX enclosingType) { if (returnType != null) { @@ -134,6 +161,57 @@ public class SignaturePattern extends PatternNode { return false; } + // for dynamic join point matching + public boolean matches(JoinPoint.StaticPart jpsp) { + Signature sig = jpsp.getSignature(); + if (kind == Member.ADVICE && !(sig instanceof AdviceSignature)) return false; + if (kind == Member.CONSTRUCTOR && !(sig instanceof ConstructorSignature)) return false; + if (kind == Member.FIELD && !(sig instanceof FieldSignature)) return false; + if (kind == Member.METHOD && !(sig instanceof MethodSignature)) return false; + if (kind == Member.STATIC_INITIALIZATION && !(jpsp.getKind().equals(JoinPoint.STATICINITIALIZATION))) return false; + if (kind == Member.POINTCUT) return false; + + if (kind == Member.ADVICE) return true; + + if (!modifiers.matches(sig.getModifiers())) return false; + + if (kind == Member.STATIC_INITIALIZATION) { + //System.err.println("match static init: " + sig.getDeclaringType() + " with " + this); + return declaringType.matchesStatically(sig.getDeclaringType()); + } else if (kind == Member.FIELD) { + Class returnTypeClass = ((FieldSignature)sig).getFieldType(); + if (!returnType.matchesStatically(returnTypeClass)) return false; + if (!name.matches(sig.getName())) return false; + boolean ret = declaringTypeMatch(sig); + //System.out.println(" ret: " + ret); + return ret; + } else if (kind == Member.METHOD) { + MethodSignature msig = ((MethodSignature)sig); + Class returnTypeClass = msig.getReturnType(); + Class[] params = msig.getParameterTypes(); + Class[] exceptionTypes = msig.getExceptionTypes(); + if (!returnType.matchesStatically(returnTypeClass)) return false; + if (!name.matches(sig.getName())) return false; + if (!parameterTypes.matches(params, TypePattern.STATIC).alwaysTrue()) { + return false; + } + if (!throwsPattern.matches(exceptionTypes)) return false; + return declaringTypeMatch(sig); + } else if (kind == Member.CONSTRUCTOR) { + ConstructorSignature csig = (ConstructorSignature)sig; + Class[] params = csig.getParameterTypes(); + Class[] exceptionTypes = csig.getExceptionTypes(); + if (!parameterTypes.matches(params, TypePattern.STATIC).alwaysTrue()) { + return false; + } + if (!throwsPattern.matches(exceptionTypes)) return false; + return declaringType.matchesStatically(sig.getDeclaringType()); + //return declaringTypeMatch(member.getDeclaringType(), member, world); + } + + return false; + } + private boolean declaringTypeMatch(TypeX onTypeUnresolved, Member member, World world) { ResolvedTypeX onType = onTypeUnresolved.resolve(world); @@ -149,7 +227,50 @@ public class SignaturePattern extends PatternNode { return false; } - + private boolean declaringTypeMatch(Signature sig) { + Class onType = sig.getDeclaringType(); + if (declaringType.matchesStatically(onType)) return true; + + Collection declaringTypes = getDeclaringTypes(sig); + + for (Iterator it = declaringTypes.iterator(); it.hasNext(); ) { + Class pClass = (Class) it.next(); + if (declaringType.matchesStatically(pClass)) return true; + } + + return false; + } + + private Collection getDeclaringTypes(Signature sig) { + List l = new ArrayList(); + Class onType = sig.getDeclaringType(); + String memberName = sig.getName(); + if (sig instanceof FieldSignature) { + Class fieldType = ((FieldSignature)sig).getFieldType(); + Class superType = onType; + while(superType != null) { + try { + Field f = (superType.getDeclaredField(memberName)); + if (f.getType() == fieldType) { + l.add(superType); + } + } catch (NoSuchFieldException nsf) {} + superType = superType.getSuperclass(); + } + } else if (sig instanceof MethodSignature) { + Class[] paramTypes = ((MethodSignature)sig).getParameterTypes(); + Class superType = onType; + while(superType != null) { + try { + Method m = (superType.getDeclaredMethod(memberName,paramTypes)); + l.add(superType); + } catch (NoSuchMethodException nsm) {} + superType = superType.getSuperclass(); + } + } + return l; + } + public NamePattern getName() { return name; } public TypePattern getDeclaringType() { return declaringType; } diff --git a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java index daca6f922..4e8c9fc72 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java @@ -18,6 +18,7 @@ import java.io.DataOutputStream; import java.io.IOException; import org.aspectj.bridge.IMessage; +import org.aspectj.lang.JoinPoint; import org.aspectj.util.FuzzyBoolean; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; @@ -67,6 +68,12 @@ public class ThisOrTargetPointcut extends NameBindingPointcut { return type.matches(typeToMatch.resolve(shadow.getIWorld()), TypePattern.DYNAMIC); } + public FuzzyBoolean match(JoinPoint jp, JoinPoint.StaticPart encJP) { + Object toMatch = isThis ? jp.getThis() : jp.getTarget(); + if (toMatch == null) return FuzzyBoolean.NO; + return type.matches(toMatch.getClass(), TypePattern.DYNAMIC); + } + public void write(DataOutputStream s) throws IOException { s.writeByte(Pointcut.THIS_OR_TARGET); s.writeBoolean(isThis); @@ -87,6 +94,10 @@ public class ThisOrTargetPointcut extends NameBindingPointcut { // ??? handle non-formal } + public void resolveBindingsFromRTTI() { + type = type.resolveBindingsFromRTTI(true,true); + } + public void postRead(ResolvedTypeX enclosingType) { type.postRead(enclosingType); } diff --git a/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java b/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java index 113b90000..dd95137ec 100644 --- a/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java @@ -66,6 +66,12 @@ public class ThrowsPattern extends PatternNode { return this; } + public ThrowsPattern resolveBindingsFromRTTI() { + required = required.resolveBindingsFromRTTI(false,false); + forbidden = forbidden.resolveBindingsFromRTTI(false,false); + return this; + } + public boolean matches(TypeX[] tys, World world) { if (this == ANY) return true; @@ -85,6 +91,25 @@ public class ThrowsPattern extends PatternNode { } return true; } + + public boolean matches(Class[] onTypes) { + if (this == ANY) return true; + + //System.out.println("matching: " + this + " with " + Arrays.asList(tys)); + + for (int j=0, lenj = required.size(); j < lenj; j++) { + if (! matchesAny(required.get(j), onTypes)) { + return false; + } + } + for (int j=0, lenj = forbidden.size(); j < lenj; j++) { + if (matchesAny(forbidden.get(j), onTypes)) { + return false; + } + } + return true; + + } private boolean matchesAny( TypePattern typePattern, @@ -95,6 +120,13 @@ public class ThrowsPattern extends PatternNode { } return false; } + + private boolean matchesAny(TypePattern typePattern, Class[] types) { + for (int i = types.length - 1; i >= 0; i--) { + if (typePattern.matchesStatically(types[i])) return true; + } + return false; + } public static ThrowsPattern read(DataInputStream s, ISourceContext context) throws IOException { TypePatternList required = TypePatternList.read(s, context); diff --git a/weaver/src/org/aspectj/weaver/patterns/TypePattern.java b/weaver/src/org/aspectj/weaver/patterns/TypePattern.java index 6c58c5c6b..ad6b88fb4 100644 --- a/weaver/src/org/aspectj/weaver/patterns/TypePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/TypePattern.java @@ -83,6 +83,51 @@ public abstract class TypePattern extends PatternNode { } + // methods for dynamic pc matching... + public final FuzzyBoolean matches(Class toMatch, MatchKind kind) { + if (kind == STATIC) { + return FuzzyBoolean.fromBoolean(matchesStatically(toMatch)); + } else if (kind == DYNAMIC) { + //System.err.println("matching: " + this + " with " + type); + FuzzyBoolean ret = matchesInstanceof(toMatch); + //System.err.println(" got: " + ret); + return ret; + } else { + throw new IllegalArgumentException("kind must be DYNAMIC or STATIC"); + } + } + + public final FuzzyBoolean matches(Object o, MatchKind kind) { + if (kind == STATIC) { + return FuzzyBoolean.fromBoolean(matchesStatically(o.getClass())); + } else if (kind == DYNAMIC) { + return FuzzyBoolean.fromBoolean(matchesSubtypes(o.getClass())); + } else { + throw new IllegalArgumentException("kind must be DYNAMIC or STATIC"); + } + } + + public boolean matchesStatically(Class toMatch) { + if (includeSubtypes) { + return matchesSubtypes(toMatch); + } else { + return matchesExactly(toMatch); + } + } + public abstract FuzzyBoolean matchesInstanceof(Class toMatch); + + protected abstract boolean matchesExactly(Class toMatch); + protected boolean matchesSubtypes(Class toMatch) { + if (matchesExactly(toMatch)) { + return true; + } + Class superClass = toMatch.getSuperclass(); + if (superClass != null) { + return matchesSubtypes(superClass); + } + return false; + } + protected abstract boolean matchesExactly(ResolvedTypeX type); protected boolean matchesSubtypes(ResolvedTypeX type) { //System.out.println("matching: " + this + " to " + type); @@ -133,6 +178,10 @@ public abstract class TypePattern extends PatternNode { return this; } + public TypePattern resolveBindingsFromRTTI(boolean allowBindng, boolean requireExactType) { + return this; + } + public void postRead(ResolvedTypeX enclosingType) { } @@ -221,6 +270,19 @@ class EllipsisTypePattern extends TypePattern { return FuzzyBoolean.NO; } + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType) + */ + protected boolean matchesExactly(Class type) { + return false; + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType) + */ + public FuzzyBoolean matchesInstanceof(Class type) { + return FuzzyBoolean.NO; + } /** * @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream) */ @@ -255,6 +317,19 @@ class AnyTypePattern extends TypePattern { return FuzzyBoolean.YES; } + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType) + */ + protected boolean matchesExactly(Class type) { + return true; + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType) + */ + public FuzzyBoolean matchesInstanceof(Class type) { + return FuzzyBoolean.YES; + } /** * @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream) */ @@ -304,6 +379,19 @@ class NoTypePattern extends TypePattern { return FuzzyBoolean.NO; } + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType) + */ + protected boolean matchesExactly(Class type) { + return false; + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType) + */ + public FuzzyBoolean matchesInstanceof(Class type) { + return FuzzyBoolean.NO; + } /** * @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream) */ diff --git a/weaver/src/org/aspectj/weaver/patterns/TypePatternList.java b/weaver/src/org/aspectj/weaver/patterns/TypePatternList.java index dc4979e30..25111cf15 100644 --- a/weaver/src/org/aspectj/weaver/patterns/TypePatternList.java +++ b/weaver/src/org/aspectj/weaver/patterns/TypePatternList.java @@ -122,6 +122,86 @@ public class TypePatternList extends PatternNode { return b; } } + + + // TODO Add TypePatternList.matches(Object[] objs) + public FuzzyBoolean matches(Object[] objs, TypePattern.MatchKind kind) { + int nameLength = objs.length; + int patternLength = typePatterns.length; + + int nameIndex = 0; + int patternIndex = 0; + + if (ellipsisCount == 0) { + if (nameLength != patternLength) return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (patternIndex < patternLength) { + FuzzyBoolean ret = typePatterns[patternIndex++].matches(objs[nameIndex++],kind); + if (ret == FuzzyBoolean.NO) return ret; + if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; + } + return finalReturn; + } else if (ellipsisCount == 1) { + if (nameLength < patternLength-1) return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (patternIndex < patternLength) { + TypePattern p = typePatterns[patternIndex++]; + if (p == TypePattern.ELLIPSIS) { + nameIndex = nameLength - (patternLength-patternIndex); + } else { + FuzzyBoolean ret = p.matches(objs[nameIndex++],kind); + if (ret == FuzzyBoolean.NO) return ret; + if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; + } + } + return finalReturn; + } else { +// System.err.print("match(" + arguments + ", " + types + ") -> "); + FuzzyBoolean b = outOfStar(typePatterns, objs, 0, 0, patternLength - ellipsisCount, nameLength, ellipsisCount, kind); +// System.err.println(b); + return b; + } + } + + // XXX run-time signature matching, too much duplicated code + public FuzzyBoolean matches(Class[] types, TypePattern.MatchKind kind) { + int nameLength = types.length; + int patternLength = typePatterns.length; + + int nameIndex = 0; + int patternIndex = 0; + + if (ellipsisCount == 0) { + if (nameLength != patternLength) return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (patternIndex < patternLength) { + FuzzyBoolean ret = typePatterns[patternIndex++].matches(types[nameIndex++], kind); + if (ret == FuzzyBoolean.NO) return ret; + if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; + } + return finalReturn; + } else if (ellipsisCount == 1) { + if (nameLength < patternLength-1) return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (patternIndex < patternLength) { + TypePattern p = typePatterns[patternIndex++]; + if (p == TypePattern.ELLIPSIS) { + nameIndex = nameLength - (patternLength-patternIndex); + } else { + FuzzyBoolean ret = p.matches(types[nameIndex++], kind); + if (ret == FuzzyBoolean.NO) return ret; + if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; + } + } + return finalReturn; + } else { +// System.err.print("match(" + arguments + ", " + types + ") -> "); + FuzzyBoolean b = outOfStar(typePatterns, types, 0, 0, patternLength - ellipsisCount, nameLength, ellipsisCount, kind); +// System.err.println(b); + return b; + } + } + private static FuzzyBoolean outOfStar(final TypePattern[] pattern, final ResolvedTypeX[] target, int pi, int ti, int pLeft, int tLeft, @@ -168,6 +248,130 @@ public class TypePatternList extends PatternNode { ti++; tLeft--; } } + + + + private static FuzzyBoolean outOfStar(final TypePattern[] pattern, + final Class[] target, int pi, int ti, int pLeft, int tLeft, + final int starsLeft, TypePattern.MatchKind kind) { + if (pLeft > tLeft) + return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length && pi < + // pattern.length) + if (tLeft == 0) + return finalReturn; + if (pLeft == 0) { + if (starsLeft > 0) { + return finalReturn; + } else { + return FuzzyBoolean.NO; + } + } + if (pattern[pi] == TypePattern.ELLIPSIS) { + return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, + starsLeft - 1, kind); + } + FuzzyBoolean ret = pattern[pi].matches(target[ti], kind); + if (ret == FuzzyBoolean.NO) + return ret; + if (ret == FuzzyBoolean.MAYBE) + finalReturn = ret; + pi++; + ti++; + pLeft--; + tLeft--; + } + } + + private static FuzzyBoolean inStar(final TypePattern[] pattern, + final Class[] target, int pi, int ti, final int pLeft, + int tLeft, int starsLeft, TypePattern.MatchKind kind) { + // invariant: pLeft > 0, so we know we'll run out of stars and find a + // real char in pattern + TypePattern patternChar = pattern[pi]; + while (patternChar == TypePattern.ELLIPSIS) { + starsLeft--; + patternChar = pattern[++pi]; + } + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length) + if (pLeft > tLeft) + return FuzzyBoolean.NO; + FuzzyBoolean ff = patternChar.matches(target[ti], kind); + if (ff.maybeTrue()) { + FuzzyBoolean xx = outOfStar(pattern, target, pi + 1, ti + 1, + pLeft - 1, tLeft - 1, starsLeft, kind); + if (xx.maybeTrue()) + return ff.and(xx); + } + ti++; + tLeft--; + } + } + + private static FuzzyBoolean outOfStar(final TypePattern[] pattern, + final Object[] target, int pi, int ti, int pLeft, int tLeft, + final int starsLeft, TypePattern.MatchKind kind) { + if (pLeft > tLeft) + return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length && pi < + // pattern.length) + if (tLeft == 0) + return finalReturn; + if (pLeft == 0) { + if (starsLeft > 0) { + return finalReturn; + } else { + return FuzzyBoolean.NO; + } + } + if (pattern[pi] == TypePattern.ELLIPSIS) { + return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, + starsLeft - 1,kind); + } + FuzzyBoolean ret = pattern[pi].matches(target[ti],kind); + if (ret == FuzzyBoolean.NO) + return ret; + if (ret == FuzzyBoolean.MAYBE) + finalReturn = ret; + pi++; + ti++; + pLeft--; + tLeft--; + } + } + + private static FuzzyBoolean inStar(final TypePattern[] pattern, + final Object[] target, int pi, int ti, final int pLeft, + int tLeft, int starsLeft, TypePattern.MatchKind kind) { + // invariant: pLeft > 0, so we know we'll run out of stars and find a + // real char in pattern + TypePattern patternChar = pattern[pi]; + while (patternChar == TypePattern.ELLIPSIS) { + starsLeft--; + patternChar = pattern[++pi]; + } + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length) + if (pLeft > tLeft) + return FuzzyBoolean.NO; + FuzzyBoolean ff = patternChar.matches(target[ti],kind); + if (ff.maybeTrue()) { + FuzzyBoolean xx = outOfStar(pattern, target, pi + 1, ti + 1, + pLeft - 1, tLeft - 1, starsLeft,kind); + if (xx.maybeTrue()) + return ff.and(xx); + } + ti++; + tLeft--; + } + } + + public TypePatternList resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) { for (int i=0; i