12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025 |
- /* *******************************************************************
- * 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.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
-
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.util.FuzzyBoolean;
- import org.aspectj.weaver.AjAttribute;
- import org.aspectj.weaver.AjcMemberMaker;
- import org.aspectj.weaver.AnnotationTargetKind;
- import org.aspectj.weaver.CompressingDataOutputStream;
- import org.aspectj.weaver.ConcreteTypeMunger;
- import org.aspectj.weaver.ISourceContext;
- import org.aspectj.weaver.JoinPointSignature;
- import org.aspectj.weaver.JoinPointSignatureIterator;
- import org.aspectj.weaver.Member;
- import org.aspectj.weaver.MemberKind;
- import org.aspectj.weaver.NewFieldTypeMunger;
- import org.aspectj.weaver.ResolvableTypeList;
- import org.aspectj.weaver.ResolvedMember;
- import org.aspectj.weaver.ResolvedType;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.VersionedDataInputStream;
- import org.aspectj.weaver.World;
-
- public class SignaturePattern extends PatternNode implements ISignaturePattern {
- private final MemberKind kind;
- private final ModifiersPattern modifiers;
- private TypePattern returnType;
- private TypePattern declaringType;
- private final NamePattern name;
- private TypePatternList parameterTypes;
- private int bits = 0x0000;
- private static final int PARAMETER_ANNOTATION_MATCHING = 0x0001;
- private static final int CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING = 0x0002;
-
- private ThrowsPattern throwsPattern;
- private AnnotationTypePattern annotationPattern;
- private transient int hashcode = -1;
-
- private transient boolean isExactDeclaringTypePattern = false;
-
- public SignaturePattern(MemberKind kind, ModifiersPattern modifiers, TypePattern returnType, TypePattern declaringType,
- NamePattern name, TypePatternList parameterTypes, ThrowsPattern throwsPattern, AnnotationTypePattern annotationPattern) {
- this.kind = kind;
- this.modifiers = modifiers;
- this.returnType = returnType;
- this.name = name;
- this.declaringType = declaringType;
- this.parameterTypes = parameterTypes;
- this.throwsPattern = throwsPattern;
- this.annotationPattern = annotationPattern;
- this.isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
- }
-
- @Override
- public SignaturePattern resolveBindings(IScope scope, Bindings bindings) {
- if (returnType != null) {
- returnType = returnType.resolveBindings(scope, bindings, false, false);
- checkForIncorrectTargetKind(returnType, scope, false);
- }
- if (declaringType != null) {
- declaringType = declaringType.resolveBindings(scope, bindings, false, false);
- checkForIncorrectTargetKind(declaringType, scope, false);
- isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
- }
- if (parameterTypes != null) {
- parameterTypes = parameterTypes.resolveBindings(scope, bindings, false, false);
- checkForIncorrectTargetKind(parameterTypes, scope, false, true);
- }
- if (throwsPattern != null) {
- throwsPattern = throwsPattern.resolveBindings(scope, bindings);
- if (throwsPattern.getForbidden().getTypePatterns().length > 0
- || throwsPattern.getRequired().getTypePatterns().length > 0) {
- checkForIncorrectTargetKind(throwsPattern, scope, false);
- }
- }
- if (annotationPattern != null) {
- annotationPattern = annotationPattern.resolveBindings(scope, bindings, false);
- checkForIncorrectTargetKind(annotationPattern, scope, true);
- }
- hashcode = -1;
- return this;
- }
-
- private void checkForIncorrectTargetKind(PatternNode patternNode, IScope scope, boolean targetsOtherThanTypeAllowed) {
- checkForIncorrectTargetKind(patternNode, scope, targetsOtherThanTypeAllowed, false);
- }
-
- // bug 115252 - adding an xlint warning if the annnotation target type is
- // wrong. This logic, or similar, may have to be applied elsewhere in the case
- // of pointcuts which don't go through SignaturePattern.resolveBindings(..)
- private void checkForIncorrectTargetKind(
- PatternNode patternNode,
- IScope scope,
- boolean targetsOtherThanTypeAllowed,
- boolean parameterTargettingAnnotationsAllowed
- )
- {
- final World world = scope.getWorld();
- // return if we're not in java5 mode, if the unmatchedTargetKind Xlint
- // warning has been turned off, or if the patternNode is *
- if (
- !world.isInJava5Mode() ||
- !world.getLint().unmatchedTargetKind.isEnabled() ||
- patternNode instanceof AnyTypePattern
- ) {
- return;
- }
- if (patternNode instanceof ExactAnnotationTypePattern) {
- ResolvedType resolvedType = ((ExactAnnotationTypePattern) patternNode).getAnnotationType().resolve(world);
- if (targetsOtherThanTypeAllowed) {
- AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
- if (targetKinds == null) {
- return;
- }
- reportUnmatchedTargetKindMessage(targetKinds, patternNode, scope, true);
- } else if (!resolvedType.canAnnotationTargetType()) {
- // everything is incorrect since we've already checked whether we have the TYPE target annotation
- AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
- if (targetKinds == null) {
- return;
- }
- reportUnmatchedTargetKindMessage(targetKinds, patternNode, scope, false);
- }
- } else {
- TypePatternVisitor visitor = new TypePatternVisitor(scope, targetsOtherThanTypeAllowed, parameterTargettingAnnotationsAllowed);
- patternNode.traverse(visitor, null);
- if (visitor.containedIncorrectTargetKind()) {
- Set<ExactAnnotationTypePattern> keys = visitor.getIncorrectTargetKinds().keySet();
- for (ExactAnnotationTypePattern node : keys) {
- AnnotationTargetKind[] targetKinds = visitor.getIncorrectTargetKinds().get(node);
- reportUnmatchedTargetKindMessage(targetKinds, node, scope, false);
- }
- }
- }
- }
-
- private void reportUnmatchedTargetKindMessage(AnnotationTargetKind[] annotationTargetKinds, PatternNode node, IScope scope,
- boolean checkMatchesMemberKindName) {
- StringBuilder targetNames = new StringBuilder("{");
- for (int i = 0; i < annotationTargetKinds.length; i++) {
- AnnotationTargetKind targetKind = annotationTargetKinds[i];
- if (checkMatchesMemberKindName && kind.getName().equals(targetKind.getName())) {
- return;
- }
- if (i < (annotationTargetKinds.length - 1)) {
- targetNames.append("ElementType.").append(targetKind.getName()).append(",");
- } else {
- targetNames.append("ElementType.").append(targetKind.getName()).append("}");
- }
- }
- scope.getWorld().getLint().unmatchedTargetKind.signal(
- new String[] { node.toString(), targetNames.toString() },
- getSourceLocation(),
- new ISourceLocation[0]
- );
- }
-
- /**
- * Class which visits the nodes in the TypePattern tree until an ExactTypePattern is found. Once this is found it creates a new
- * ExactAnnotationTypePattern and checks whether the targetKind (created via the @Target annotation) matches ElementType.TYPE if
- * this is the only target kind which is allowed, or matches the signature pattern kind if there is no restriction.
- */
- private class TypePatternVisitor extends AbstractPatternNodeVisitor {
-
- private final IScope scope;
- private final Map<ExactAnnotationTypePattern, AnnotationTargetKind[]> incorrectTargetKinds = new HashMap<>();
- private final boolean targetsOtherThanTypeAllowed;
- private final boolean parameterTargettingAnnotationsAllowed;
-
- public TypePatternVisitor(IScope scope, boolean targetsOtherThanTypeAllowed, boolean parameterTargettingAnnotationsAllowed) {
- this.scope = scope;
- this.targetsOtherThanTypeAllowed = targetsOtherThanTypeAllowed;
- this.parameterTargettingAnnotationsAllowed = parameterTargettingAnnotationsAllowed;
- }
-
- @Override
- public Object visit(WildAnnotationTypePattern node, Object data) {
- node.getTypePattern().accept(this, data);
- return node;
- }
-
- /**
- * Do the ExactAnnotationTypePatterns have the incorrect target?
- */
- @Override
- public Object visit(ExactAnnotationTypePattern node, Object data) {
- ResolvedType resolvedType = node.getAnnotationType().resolve(scope.getWorld());
- AnnotationTargetKind[] targetKinds = resolvedType.getAnnotationTargetKinds();
- if (targetKinds == null)
- return data;
- boolean isMetaAnnotation = data instanceof AnnotationTypePattern || data instanceof AnyWithAnnotationTypePattern;
- if (targetsOtherThanTypeAllowed) {
- List<AnnotationTargetKind> incorrectTargets = new ArrayList<>();
- for (AnnotationTargetKind targetKind : targetKinds) {
- if (
- isMetaAnnotation && targetKind.equals(AnnotationTargetKind.ANNOTATION_TYPE) ||
- targetKind.getName().equals(kind.getName()) ||
- targetKind.equals(AnnotationTargetKind.PARAMETER) && node.isForParameterAnnotationMatch()
- ) {
- return data;
- }
- incorrectTargets.add(targetKind);
- }
- if (incorrectTargets.isEmpty())
- return data;
- AnnotationTargetKind[] kinds = new AnnotationTargetKind[incorrectTargets.size()];
- incorrectTargetKinds.put(node, incorrectTargets.toArray(kinds));
- }
- else if (!resolvedType.canAnnotationTargetType()) {
- for (AnnotationTargetKind targetKind : targetKinds) {
- if (
- isMetaAnnotation && targetKind.equals(AnnotationTargetKind.ANNOTATION_TYPE) ||
- parameterTargettingAnnotationsAllowed &&
- targetKind.equals(AnnotationTargetKind.PARAMETER) && node.isForParameterAnnotationMatch()
- ) {
- return data;
- }
- }
- incorrectTargetKinds.put(node, targetKinds);
- }
- return data;
- }
-
- @Override
- public Object visit(ExactTypePattern node, Object data) {
- ExactAnnotationTypePattern eatp = new ExactAnnotationTypePattern(node.getExactType().resolve(scope.getWorld()), null);
- eatp.accept(this, data);
- return data;
- }
-
- @Override
- public Object visit(AndTypePattern node, Object data) {
- node.getLeft().accept(this, data);
- node.getRight().accept(this, data);
- return node;
- }
-
- @Override
- public Object visit(OrTypePattern node, Object data) {
- node.getLeft().accept(this, data);
- node.getRight().accept(this, data);
- return node;
- }
-
- @Override
- public Object visit(AnyWithAnnotationTypePattern node, Object data) {
- node.getAnnotationPattern().accept(this, data);
- return node;
- }
-
- public boolean containedIncorrectTargetKind() {
- return (!incorrectTargetKinds.isEmpty());
- }
-
- public Map<ExactAnnotationTypePattern, AnnotationTargetKind[]> getIncorrectTargetKinds() {
- return incorrectTargetKinds;
- }
- }
-
- public void postRead(ResolvedType enclosingType) {
- if (returnType != null) {
- returnType.postRead(enclosingType);
- }
- if (declaringType != null) {
- declaringType.postRead(enclosingType);
- }
- if (parameterTypes != null) {
- parameterTypes.postRead(enclosingType);
- }
- }
-
- /**
- * return a copy of this signature pattern in which every type variable reference is replaced by the corresponding entry in the
- * map.
- */
- @Override
- public SignaturePattern parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
- SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType.parameterizeWith(typeVariableMap, w), declaringType
- .parameterizeWith(typeVariableMap, w), name, parameterTypes.parameterizeWith(typeVariableMap, w), throwsPattern
- .parameterizeWith(typeVariableMap, w), annotationPattern.parameterizeWith(typeVariableMap, w));
- ret.copyLocationFrom(this);
- return ret;
- }
-
- @Override
- public boolean matches(Member joinPointSignature, World world, boolean allowBridgeMethods) {
- // fail (or succeed!) fast tests...
- if (joinPointSignature == null) {
- return false;
- }
- if (kind != joinPointSignature.getKind()) {
- return false;
- }
- if (kind == Member.ADVICE) {
- return true;
- }
-
- // do the hard work then...
- boolean subjectMatch = true;
- boolean wantsAnnotationMatch = wantToMatchAnnotationPattern();
- JoinPointSignatureIterator candidateMatches = joinPointSignature.getJoinPointSignatures(world);
- while (candidateMatches.hasNext()) {
- JoinPointSignature aSig = candidateMatches.next();
- // System.out.println(aSig);
- FuzzyBoolean matchResult = matchesExactly(aSig, world, allowBridgeMethods, subjectMatch);
- if (matchResult.alwaysTrue()) {
- return true;
- } else if (matchResult.alwaysFalse()) {
- return false;
- }
- // if we got a "MAYBE" it's worth looking at the other signatures
- // The first signature is the subject signature - and against it we must match modifiers/annotations/throws
- // see https://github.com/eclipse-aspectj/aspectj/blob/master/docs/adk15notebook/joinpointsignatures.adoc#join-point-modifiers
- subjectMatch = false;
- // Early exit
- if (wantsAnnotationMatch) {
- return false;
- }
- }
- return false;
- }
-
- // Does this pattern match this exact signature (no declaring type mucking about
- // or chasing up the hierarchy)
- // return YES if it does, NO if it doesn't and no ancester member could match either,
- // and MAYBE if it doesn't but an ancester member could.
- private FuzzyBoolean matchesExactly(JoinPointSignature aMember, World inAWorld, boolean allowBridgeMethods, boolean subjectMatch) {
- // Java5 introduces bridge methods, we match a call to them but nothing else...
- if (aMember.isBridgeMethod() && !allowBridgeMethods) {
- return FuzzyBoolean.MAYBE;
- }
-
- // Only the subject is checked for modifiers
- // see https://github.com/eclipse-aspectj/aspectj/blob/master/docs/adk15notebook/joinpointsignatures.adoc#join-point-modifiers
- if (subjectMatch && !modifiers.matches(aMember.getModifiers())) {
- return FuzzyBoolean.NO;
- }
-
- FuzzyBoolean matchesIgnoringAnnotations = FuzzyBoolean.YES;
- if (kind == Member.STATIC_INITIALIZATION) {
- matchesIgnoringAnnotations = matchesExactlyStaticInitialization(aMember, inAWorld);
- } else if (kind == Member.FIELD) {
- matchesIgnoringAnnotations = matchesExactlyField(aMember, inAWorld);
- } else if (kind == Member.METHOD) {
- matchesIgnoringAnnotations = matchesExactlyMethod(aMember, inAWorld, subjectMatch);
- } else if (kind == Member.CONSTRUCTOR) {
- matchesIgnoringAnnotations = matchesExactlyConstructor(aMember, inAWorld);
- }
- if (matchesIgnoringAnnotations.alwaysFalse()) {
- return FuzzyBoolean.NO;
- }
-
- // Only the subject is checked for annotations (239441/119749)
- // see https://github.com/eclipse-aspectj/aspectj/blob/master/docs/adk15notebook/joinpointsignatures.adoc#join-point-modifiers
- if (subjectMatch) {
- // The annotations must match if specified
- if (!matchesAnnotations(aMember, inAWorld).alwaysTrue()) {
- return FuzzyBoolean.NO;
- } else {
- return matchesIgnoringAnnotations;
- }
- } else {
- // Unless they specified any annotation then it is a failure
- if (annotationPattern instanceof AnyAnnotationTypePattern) {
- return matchesIgnoringAnnotations;
- } else {
- return FuzzyBoolean.NO;
- }
- }
-
- // if (subjectMatch && !matchesAnnotations(aMember, inAWorld).alwaysTrue()) {
- // return FuzzyBoolean.NO;
- // } else {
- //
- // return matchesIgnoringAnnotations;
- // }
-
- }
-
- private boolean wantToMatchAnnotationPattern() {
- return !(annotationPattern instanceof AnyAnnotationTypePattern);
- }
-
- /**
- * Matches on declaring type
- */
- private FuzzyBoolean matchesExactlyStaticInitialization(JoinPointSignature aMember, World world) {
- return FuzzyBoolean.fromBoolean(declaringType.matchesStatically(aMember.getDeclaringType().resolve(world)));
- }
-
- /**
- * Matches on name, declaring type, field type
- */
- private FuzzyBoolean matchesExactlyField(JoinPointSignature aField, World world) {
- if (!name.matches(aField.getName())) {
- return FuzzyBoolean.NO;
- }
- ResolvedType fieldDeclaringType = aField.getDeclaringType().resolve(world);
- if (!declaringType.matchesStatically(fieldDeclaringType)) {
- return FuzzyBoolean.MAYBE;
- }
- if (!returnType.matchesStatically(aField.getReturnType().resolve(world))) {
- // looking bad, but there might be parameterization to consider...
- if (!returnType.matchesStatically(aField.getGenericReturnType().resolve(world))) {
- // ok, it's bad.
- return FuzzyBoolean.MAYBE;
- }
- }
- // passed all the guards...
- return FuzzyBoolean.YES;
- }
-
- /**
- * Quickly detect if the joinpoint absolutely cannot match becaused the method parameters at the joinpoint cannot match against
- * this signature pattern.
- *
- * @param methodJoinpoint the joinpoint to quickly match against
- * @return true if it is impossible for the joinpoint to match this signature
- */
- private boolean parametersCannotMatch(JoinPointSignature methodJoinpoint) {
- if (methodJoinpoint.isVarargsMethod()) {
- // just give up early (for now)
- return false;
- }
-
- int patternParameterCount = parameterTypes.size();
-
- if (patternParameterCount == 0 || parameterTypes.ellipsisCount == 0) {
- boolean equalCount = patternParameterCount == methodJoinpoint.getParameterTypes().length;
-
- // Quick rule: pattern specifies zero parameters, and joinpoint has parameters *OR*
- if (patternParameterCount == 0 && !equalCount) {
- return true;
- }
-
- // Quick rule: pattern doesn't specify ellipsis and there are a different number of parameters on the
- // method join point as compared with the pattern
- if (parameterTypes.ellipsisCount == 0 && !equalCount)
- return patternParameterCount <= 0 || !parameterTypes.get(patternParameterCount - 1).isVarArgs();
- }
-
- return false;
- }
-
- /**
- * Matches on name, declaring type, return type, parameter types, throws types
- */
- private FuzzyBoolean matchesExactlyMethod(JoinPointSignature aMethod, World world, boolean subjectMatch) {
- if (!returnType.matchesArray(aMethod.getReturnType())) {
- return FuzzyBoolean.NO;
- }
- if (parametersCannotMatch(aMethod)) {
- // System.err.println("Parameter types pattern " + parameterTypes + " pcount: " + aMethod.getParameterTypes().length);
- return FuzzyBoolean.NO;
- }
- // OPTIMIZE only for exact match do the pattern match now? Otherwise defer it until other fast checks complete?
- if (!name.matches(aMethod.getName())) {
- return FuzzyBoolean.NO;
- }
- // Check the throws pattern
- if (subjectMatch && !throwsPattern.matches(aMethod.getExceptions(), world)) {
- return FuzzyBoolean.NO;
- }
-
- // '*' trivially matches everything, no need to check further
- if (!declaringType.isStar()) {
- if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) {
- return FuzzyBoolean.MAYBE;
- }
- }
-
- // '*' would match any return value
- if (!returnType.isStar()) {
- boolean b = returnType.isBangVoid();
- if (b) {
- String s = aMethod.getReturnType().getSignature();
- if (s.length() == 1 && s.charAt(0) == 'V') {
- // it is void, so not a match
- return FuzzyBoolean.NO;
- }
- } else {
- if (returnType.isVoid()) {
- String s = aMethod.getReturnType().getSignature();
- if (s.length() != 1 || s.charAt(0) != 'V') {
- // it is not void, so not a match
- return FuzzyBoolean.NO;
- }
- } else {
- if (!returnType.matchesStatically(aMethod.getReturnType().resolve(world))) {
- // looking bad, but there might be parameterization to consider...
- if (!returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) {
- // ok, it's bad.
- return FuzzyBoolean.MAYBE;
- }
- }
- }
- }
- }
-
- // The most simple case: pattern is (..) will match anything
- if (parameterTypes.size() == 1 && parameterTypes.get(0).isEllipsis()) {
- return FuzzyBoolean.YES;
- }
-
- if (!parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) {
- return FuzzyBoolean.NO;
- }
-
- // OPTIMIZE both resolution of these types and their annotations should be deferred - just pass down a world and do it lower
- // down
- // ResolvedType[] resolvedParameters = world.resolve(aMethod.getParameterTypes());
-
- ResolvableTypeList rtl = new ResolvableTypeList(world, aMethod.getParameterTypes());
- // Only fetch the parameter annotations if the pointcut is going to be matching on them
- ResolvedType[][] parameterAnnotationTypes = null;
- if (isMatchingParameterAnnotations()) {
- parameterAnnotationTypes = aMethod.getParameterAnnotationTypes();
- if (parameterAnnotationTypes != null && parameterAnnotationTypes.length == 0) {
- parameterAnnotationTypes = null;
- }
- }
-
- if (!parameterTypes.matches(rtl, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
- // It could still be a match based on the generic sig parameter types of a parameterized type
- if (!parameterTypes.matches(new ResolvableTypeList(world, aMethod.getGenericParameterTypes()), TypePattern.STATIC,
- parameterAnnotationTypes).alwaysTrue()) {
- return FuzzyBoolean.MAYBE;
- // It could STILL be a match based on the erasure of the parameter types??
- // to be determined via test cases...
- }
- }
-
- // check that varargs specifications match
- if (!matchesVarArgs(aMethod, world)) {
- return FuzzyBoolean.MAYBE;
- }
-
- // passed all the guards..
- return FuzzyBoolean.YES;
- }
-
- /**
- * Determine if any pattern in the parameter type pattern list is attempting to match on parameter annotations.
- *
- * @return true if a parameter type pattern wants to match on a parameter annotation
- */
- private boolean isMatchingParameterAnnotations() {
- if ((bits & CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING) == 0) {
- bits |= CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING;
- for (int tp = 0, max = parameterTypes.size(); tp < max; tp++) {
- TypePattern typePattern = parameterTypes.get(tp);
- if (isParameterAnnotationMatching(typePattern)) {
- bits |= PARAMETER_ANNOTATION_MATCHING;
- }
- }
- }
- return (bits & PARAMETER_ANNOTATION_MATCHING) != 0;
- }
-
- /**
- * Walk the simple structure of a type pattern and determine if any leaf node is involved in parameter annotation matching.
- */
- private boolean isParameterAnnotationMatching(TypePattern tp) {
- if (tp instanceof OrTypePattern) {
- OrTypePattern orAtp = (OrTypePattern) tp;
- return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
- } else if (tp instanceof AndTypePattern) {
- AndTypePattern andAtp = (AndTypePattern) tp;
- return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
- } else if (tp instanceof NotTypePattern) {
- NotTypePattern notAtp = (NotTypePattern) tp;
- return (isParameterAnnotationMatching(notAtp.getNegatedPattern()));
- } else {
- AnnotationTypePattern atp = tp.getAnnotationPattern();
- return isParameterAnnotationMatching(atp);
- }
- }
-
- private boolean isParameterAnnotationMatching(AnnotationTypePattern tp) {
- if (tp instanceof OrAnnotationTypePattern) {
- OrAnnotationTypePattern orAtp = (OrAnnotationTypePattern) tp;
- return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight()));
- } else if (tp instanceof AndAnnotationTypePattern) {
- AndAnnotationTypePattern andAtp = (AndAnnotationTypePattern) tp;
- return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight()));
- } else if (tp instanceof NotAnnotationTypePattern) {
- NotAnnotationTypePattern notAtp = (NotAnnotationTypePattern) tp;
- return (isParameterAnnotationMatching(notAtp.negatedPattern));
- } else {
- return tp.isForParameterAnnotationMatch();
- }
- }
-
- /**
- * match on declaring type, parameter types, throws types
- */
- private FuzzyBoolean matchesExactlyConstructor(JoinPointSignature aConstructor, World world) {
- if (!declaringType.matchesStatically(aConstructor.getDeclaringType().resolve(world))) {
- return FuzzyBoolean.NO;
- }
-
- if (!parameterTypes.canMatchSignatureWithNParameters(aConstructor.getParameterTypes().length)) {
- return FuzzyBoolean.NO;
- }
- ResolvedType[] resolvedParameters = world.resolve(aConstructor.getParameterTypes());
-
- ResolvedType[][] parameterAnnotationTypes = aConstructor.getParameterAnnotationTypes();
-
- if (parameterAnnotationTypes == null || parameterAnnotationTypes.length == 0) {
- parameterAnnotationTypes = null;
- }
-
- if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
- // It could still be a match based on the generic sig parameter types of a parameterized type
- if (!parameterTypes.matches(world.resolve(aConstructor.getGenericParameterTypes()), TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) {
- return FuzzyBoolean.MAYBE;
- // It could STILL be a match based on the erasure of the parameter types??
- // to be determined via test cases...
- }
- }
-
- // check that varargs specifications match
- if (!matchesVarArgs(aConstructor, world)) {
- return FuzzyBoolean.NO;
- }
-
- // Check the throws pattern
- if (!throwsPattern.matches(aConstructor.getExceptions(), world)) {
- return FuzzyBoolean.NO;
- }
-
- // passed all the guards..
- return FuzzyBoolean.YES;
- }
-
- /**
- * We've matched against this method or constructor so far, but without considering varargs (which has been matched as a simple
- * array thus far). Now we do the additional checks to see if the parties agree on whether the last parameter is varargs or a
- * straight array.
- */
- private boolean matchesVarArgs(JoinPointSignature aMethodOrConstructor, World inAWorld) {
- if (parameterTypes.size() == 0) {
- return true;
- }
-
- TypePattern lastPattern = parameterTypes.get(parameterTypes.size() - 1);
- boolean canMatchVarArgsSignature = lastPattern.isStar() || lastPattern.isVarArgs() || (lastPattern == TypePattern.ELLIPSIS);
-
- if (aMethodOrConstructor.isVarargsMethod()) {
- // we have at least one parameter in the pattern list, and the method has a varargs signature
- if (!canMatchVarArgsSignature) {
- // XXX - Ideally the shadow would be included in the msg but we don't know it...
- inAWorld.getLint().cantMatchArrayTypeOnVarargs.signal(aMethodOrConstructor.toString(), getSourceLocation());
- return false;
- }
- } else {
- // the method ends with an array type, check that we don't *require* a varargs
- return !lastPattern.isVarArgs();
- }
-
- return true;
- }
-
- private FuzzyBoolean matchesAnnotations(ResolvedMember member, World world) {
- if (member == null) {
- // world.getLint().unresolvableMember.signal(member.toString(), getSourceLocation());
- return FuzzyBoolean.NO;
- }
- annotationPattern.resolve(world);
-
- // optimization before we go digging around for annotations on ITDs
- if (annotationPattern instanceof AnyAnnotationTypePattern) {
- return FuzzyBoolean.YES;
- }
-
- // fake members represent ITD'd fields - for their annotations we should go and look up the
- // relevant member in the original aspect
- if (member.isAnnotatedElsewhere() && member.getKind() == Member.FIELD) {
- // FIXME asc duplicate of code in AnnotationPointcut.matchInternal()? same fixmes apply here.
- // ResolvedMember [] mems = member.getDeclaringType().resolve(world).getDeclaredFields(); // FIXME asc should include
- // supers with getInterTypeMungersIncludingSupers?
- List<ConcreteTypeMunger> mungers = member.getDeclaringType().resolve(world).getInterTypeMungers();
- for (ConcreteTypeMunger typeMunger : mungers) {
- if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
- ResolvedMember fakerm = typeMunger.getSignature();
- ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
- ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
- if (fakerm.equals(member)) {
- member = rmm;
- }
- }
- }
- }
-
- if (annotationPattern.matches(member).alwaysTrue()) {
- return FuzzyBoolean.YES;
- } else {
- // do NOT look at ancestor members... only the subject can have an annotation match
- // see https://github.com/eclipse-aspectj/aspectj/blob/master/docs/adk15notebook/joinpointsignatures.adoc#join-point-modifiers
- return FuzzyBoolean.NO;
- }
- }
-
- private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
- ResolvedMember[] decMethods = aspectType.getDeclaredMethods();
- for (ResolvedMember member : decMethods) {
- if (member.equals(ajcMethod)) {
- return member;
- }
- }
- return null;
- }
-
- public boolean declaringTypeMatchAllowingForCovariance(Member member, UnresolvedType shadowDeclaringType, World world,
- TypePattern returnTypePattern, ResolvedType sigReturn) {
-
- ResolvedType onType = shadowDeclaringType.resolve(world);
-
- // fastmatch
- if (declaringType.matchesStatically(onType) && returnTypePattern.matchesStatically(sigReturn)) {
- return true;
- }
-
- Collection<ResolvedType> declaringTypes = member.getDeclaringTypes(world);
-
- boolean checkReturnType = true;
- // XXX Possible enhancement? Doesn't seem to speed things up
- // if (returnTypePattern.isStar()) {
- // if (returnTypePattern instanceof WildTypePattern) {
- // if (((WildTypePattern)returnTypePattern).getDimensions()==0) checkReturnType = false;
- // }
- // }
-
- // Sometimes that list includes types that don't explicitly declare the member we are after -
- // they are on the list because their supertype is on the list, that's why we use
- // lookupMethod rather than lookupMemberNoSupers()
- for (ResolvedType type : declaringTypes) {
- if (declaringType.matchesStatically(type)) {
- if (!checkReturnType) {
- return true;
- }
- ResolvedMember rm = type.lookupMethod(member);
- if (rm == null) {
- rm = type.lookupMethodInITDs(member); // It must be in here, or we have *real* problems
- }
- if (rm == null) {
- continue; // might be currently looking at the generic type and we need to continue searching in case we hit a
- }
- // parameterized version of this same type...
- UnresolvedType returnTypeX = rm.getReturnType();
- ResolvedType returnType = returnTypeX.resolve(world);
- if (returnTypePattern.matchesStatically(returnType)) {
- 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 {
- // 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;
- }
-
- public MemberKind getKind() {
- return kind;
- }
-
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
-
- if (annotationPattern != AnnotationTypePattern.ANY) {
- buf.append(annotationPattern.toString());
- buf.append(' ');
- }
-
- if (modifiers != ModifiersPattern.ANY) {
- buf.append(modifiers.toString());
- buf.append(' ');
- }
-
- if (kind == Member.STATIC_INITIALIZATION) {
- buf.append(declaringType.toString());
- buf.append(".<clinit>()");// FIXME AV - bad, cannot be parsed again
- } else if (kind == Member.HANDLER) {
- buf.append("handler(");
- buf.append(parameterTypes.get(0));
- buf.append(")");
- } else {
- if (!(kind == Member.CONSTRUCTOR)) {
- buf.append(returnType.toString());
- buf.append(' ');
- }
- if (declaringType != TypePattern.ANY) {
- buf.append(declaringType.toString());
- buf.append('.');
- }
- if (kind == Member.CONSTRUCTOR) {
- buf.append("new");
- } else {
- buf.append(name.toString());
- }
- if (kind == Member.METHOD || kind == Member.CONSTRUCTOR) {
- buf.append(parameterTypes.toString());
- }
- // FIXME AV - throws is not printed here, weird
- }
- return buf.toString();
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof SignaturePattern)) {
- return false;
- }
- SignaturePattern o = (SignaturePattern) other;
- return o.kind.equals(this.kind) && o.modifiers.equals(this.modifiers) && o.returnType.equals(this.returnType)
- && o.declaringType.equals(this.declaringType) && o.name.equals(this.name)
- && o.parameterTypes.equals(this.parameterTypes) && o.throwsPattern.equals(this.throwsPattern)
- && o.annotationPattern.equals(this.annotationPattern);
- }
-
- @Override
- public int hashCode() {
- if (hashcode == -1) {
- hashcode = 17;
- hashcode = 37 * hashcode + kind.hashCode();
- hashcode = 37 * hashcode + modifiers.hashCode();
- hashcode = 37 * hashcode + returnType.hashCode();
- hashcode = 37 * hashcode + declaringType.hashCode();
- hashcode = 37 * hashcode + name.hashCode();
- hashcode = 37 * hashcode + parameterTypes.hashCode();
- hashcode = 37 * hashcode + throwsPattern.hashCode();
- hashcode = 37 * hashcode + annotationPattern.hashCode();
- }
- return hashcode;
- }
-
- @Override
- public void write(CompressingDataOutputStream s) throws IOException {
- kind.write(s);
- modifiers.write(s);
- returnType.write(s);
- declaringType.write(s);
- name.write(s);
- parameterTypes.write(s);
- throwsPattern.write(s);
- annotationPattern.write(s);
- writeLocation(s);
- }
-
- public static SignaturePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
- // ISignaturePattern kind should already have been read by the time this read is entered
- MemberKind kind = MemberKind.read(s);
- ModifiersPattern modifiers = ModifiersPattern.read(s);
- TypePattern returnType = TypePattern.read(s, context);
- TypePattern declaringType = TypePattern.read(s, context);
- NamePattern name = NamePattern.read(s);
- TypePatternList parameterTypes = TypePatternList.read(s, context);
- ThrowsPattern throwsPattern = ThrowsPattern.read(s, context);
-
- AnnotationTypePattern annotationPattern = AnnotationTypePattern.ANY;
-
- if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
- annotationPattern = AnnotationTypePattern.read(s, context);
- }
-
- SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes,
- throwsPattern, annotationPattern);
- ret.readLocation(context, s);
- return ret;
- }
-
- /**
- * @return
- */
- public ModifiersPattern getModifiers() {
- return modifiers;
- }
-
- /**
- * @return
- */
- public TypePatternList getParameterTypes() {
- return parameterTypes;
- }
-
- /**
- * @return
- */
- public TypePattern getReturnType() {
- return returnType;
- }
-
- /**
- * @return
- */
- public ThrowsPattern getThrowsPattern() {
- return throwsPattern;
- }
-
- /**
- * return true if last argument in params is an Object[] but the modifiers say this method was declared with varargs
- * (Object...). We shouldn't be matching if this is the case.
- */
- // private boolean matchedArrayAgainstVarArgs(TypePatternList params,int modifiers) {
- // if (params.size()>0 && (modifiers & Constants.ACC_VARARGS)!=0) {
- // // we have at least one parameter in the pattern list, and the method has a varargs signature
- // TypePattern lastPattern = params.get(params.size()-1);
- // if (lastPattern.isArray() && !lastPattern.isVarArgs) return true;
- // }
- // return false;
- // }
- public AnnotationTypePattern getAnnotationPattern() {
- return annotationPattern;
- }
-
- @Override
- public boolean isStarAnnotation() {
- return annotationPattern == AnnotationTypePattern.ANY;
- }
-
- @Override
- 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.annotationPattern != null)
- this.annotationPattern.traverse(visitor, ret);
- if (this.returnType != null)
- this.returnType.traverse(visitor, ret);
- if (this.declaringType != null)
- this.declaringType.traverse(visitor, ret);
- if (this.name != null)
- this.name.traverse(visitor, ret);
- if (this.parameterTypes != null)
- this.parameterTypes.traverse(visitor, ret);
- if (this.throwsPattern != null)
- this.throwsPattern.traverse(visitor, ret);
- return ret;
- }
-
- public boolean isExactDeclaringTypePattern() {
- return isExactDeclaringTypePattern;
- }
-
- @Override
- public boolean isMatchOnAnyName() {
- return getName().isAny();
- }
-
- @Override
- public List<ExactTypePattern> getExactDeclaringTypes() {
- if (declaringType instanceof ExactTypePattern) {
- List<ExactTypePattern> l = new ArrayList<>();
- l.add((ExactTypePattern) declaringType);
- return l;
- } else {
- return Collections.emptyList();
- }
- }
-
- @Override
- public boolean couldEverMatch(ResolvedType type) {
- return declaringType.matches(type, TypePattern.STATIC).maybeTrue();
- }
-
- }
|