- /* *******************************************************************
- * 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.List;
- import java.util.Map;
- import java.util.StringTokenizer;
-
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.bridge.Message;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.util.FileUtil;
- import org.aspectj.util.FuzzyBoolean;
- import org.aspectj.weaver.AjAttribute;
- import org.aspectj.weaver.BCException;
- import org.aspectj.weaver.BoundedReferenceType;
- import org.aspectj.weaver.CompressingDataOutputStream;
- import org.aspectj.weaver.IHasPosition;
- import org.aspectj.weaver.ISourceContext;
- import org.aspectj.weaver.ReferenceType;
- import org.aspectj.weaver.ResolvedType;
- import org.aspectj.weaver.TypeFactory;
- import org.aspectj.weaver.TypeVariable;
- import org.aspectj.weaver.TypeVariableReference;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.UnresolvedTypeVariableReferenceType;
- import org.aspectj.weaver.VersionedDataInputStream;
- import org.aspectj.weaver.WeaverMessages;
- import org.aspectj.weaver.World;
-
- /**
- * The PatternParser always creates WildTypePatterns for type patterns in pointcut expressions (apart from *, which is sometimes
- * directly turned into TypePattern.ANY). resolveBindings() tries to work out what we've really got and turn it into a type pattern
- * that we can use for matching. This will normally be either an ExactTypePattern or a WildTypePattern.
- *
- * Here's how the process pans out for various generic and parameterized patterns: (see GenericsWildTypePatternResolvingTestCase)
- *
- * Foo where Foo exists and is generic Parser creates WildTypePattern namePatterns={Foo} resolveBindings resolves Foo to RT(Foo -
- * raw) return ExactTypePattern(LFoo;)
- *
- * Foo<String> where Foo exists and String meets the bounds Parser creates WildTypePattern namePatterns = {Foo},
- * typeParameters=WTP{String} resolveBindings resolves typeParameters to ExactTypePattern(String) resolves Foo to RT(Foo) returns
- * ExactTypePattern(PFoo<String>; - parameterized)
- *
- * Foo<Str*> where Foo exists and takes one bound Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{Str*}
- * resolveBindings resolves typeParameters to WTP{Str*} resolves Foo to RT(Foo) returns WildTypePattern(name = Foo, typeParameters =
- * WTP{Str*} isGeneric=false)
- *
- * Fo*<String> Parser creates WildTypePattern namePatterns = {Fo*}, typeParameters=WTP{String} resolveBindings resolves
- * typeParameters to ETP{String} returns WildTypePattern(name = Fo*, typeParameters = ETP{String} isGeneric=false)
- *
- *
- * Foo<?>
- *
- * Foo<? extends Number>
- *
- * Foo<? extends Number+>
- *
- * Foo<? super Number>
- *
- */
- public class WildTypePattern extends TypePattern {
- private static final String GENERIC_WILDCARD_CHARACTER = "?"; // signature of ? is *
- private static final String GENERIC_WILDCARD_SIGNATURE_CHARACTER = "*"; // signature of ? is *
- private NamePattern[] namePatterns;
- private boolean failedResolution = false;
- int ellipsisCount;
- String[] importedPrefixes;
- String[] knownMatches;
- int dim;
-
- // SECRETAPI - just for testing, turns off boundschecking temporarily...
- public static boolean boundscheckingoff = false;
-
- // these next three are set if the type pattern is constrained by extends or super clauses, in which case the
- // namePatterns must have length 1
- // TODO AMC: read/write/resolve of these fields
- TypePattern upperBound; // extends Foo
- TypePattern[] additionalInterfaceBounds; // extends Foo & A,B,C
- TypePattern lowerBound; // super Foo
-
- // if we have type parameters, these fields indicate whether we should be a generic type pattern or a parameterized
- // type pattern. We can only tell during resolve bindings.
- private boolean isGeneric = true;
-
- WildTypePattern(NamePattern[] namePatterns, boolean includeSubtypes, int dim, boolean isVarArgs, TypePatternList typeParams) {
- super(includeSubtypes, isVarArgs, typeParams);
- this.namePatterns = namePatterns;
- this.dim = dim;
- ellipsisCount = 0;
- for (NamePattern namePattern : namePatterns) {
- if (namePattern == NamePattern.ELLIPSIS) {
- ellipsisCount++;
- }
- }
- setLocation(namePatterns[0].getSourceContext(), namePatterns[0].getStart(), namePatterns[namePatterns.length - 1].getEnd());
- }
-
- public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim) {
- this(names.toArray(new NamePattern[0]), includeSubtypes, dim, false, TypePatternList.EMPTY);
-
- }
-
- public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos) {
- this(names, includeSubtypes, dim);
- this.end = endPos;
- }
-
- public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg) {
- this(names, includeSubtypes, dim);
- this.end = endPos;
- this.isVarArgs = isVarArg;
- }
-
- public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg, TypePatternList typeParams,
- TypePattern upperBound, TypePattern[] additionalInterfaceBounds, TypePattern lowerBound) {
- this(names.toArray(new NamePattern[0]), includeSubtypes, dim, isVarArg, typeParams);
- this.end = endPos;
- this.upperBound = upperBound;
- this.lowerBound = lowerBound;
- this.additionalInterfaceBounds = additionalInterfaceBounds;
- }
-
- public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg, TypePatternList typeParams) {
- this(names.toArray(new NamePattern[0]), includeSubtypes, dim, isVarArg, typeParams);
- this.end = endPos;
- }
-
- public NamePattern[] getNamePatterns() {
- return namePatterns;
- }
-
- public TypePattern getUpperBound() {
- return upperBound;
- }
-
- public TypePattern getLowerBound() {
- return lowerBound;
- }
-
- public TypePattern[] getAdditionalIntefaceBounds() {
- return additionalInterfaceBounds;
- }
-
- // called by parser after parsing a type pattern, must bump dim as well as setting flag
- @Override
- public void setIsVarArgs(boolean isVarArgs) {
- this.isVarArgs = isVarArgs;
- if (isVarArgs) {
- this.dim += 1;
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
- */
- @Override
- protected boolean couldEverMatchSameTypesAs(TypePattern other) {
- if (super.couldEverMatchSameTypesAs(other)) {
- return true;
- }
- // false is necessary but not sufficient
- UnresolvedType otherType = other.getExactType();
- if (!ResolvedType.isMissing(otherType)) {
- if (namePatterns.length > 0) {
- if (!namePatterns[0].matches(otherType.getName())) {
- return false;
- }
- }
- }
- if (other instanceof WildTypePattern) {
- WildTypePattern owtp = (WildTypePattern) other;
- String mySimpleName = namePatterns[0].maybeGetSimpleName();
- String yourSimpleName = owtp.namePatterns[0].maybeGetSimpleName();
- if (mySimpleName != null && yourSimpleName != null) {
- return (mySimpleName.startsWith(yourSimpleName) || yourSimpleName.startsWith(mySimpleName));
- }
- }
- return true;
- }
-
- // XXX inefficient implementation
- // we don't know whether $ characters are from nested types, or were
- // part of the declared type name (generated code often uses $s in type
- // names). More work required on our part to get this right...
- public static char[][] splitNames(String s, boolean convertDollar) {
- List<char[]> ret = new ArrayList<>();
- int startIndex = 0;
- while (true) {
- int breakIndex = s.indexOf('.', startIndex); // what about /
- if (convertDollar && (breakIndex == -1)) {
- breakIndex = s.indexOf('$', startIndex); // we treat $ like . here
- }
- if (breakIndex == -1) {
- break;
- }
- char[] name = s.substring(startIndex, breakIndex).toCharArray();
- ret.add(name);
- startIndex = breakIndex + 1;
- }
- ret.add(s.substring(startIndex).toCharArray());
- return ret.toArray(new char[ret.size()][]);
- }
-
- /**
- * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(ResolvedType)
- */
- @Override
- protected boolean matchesExactly(ResolvedType type) {
- return matchesExactly(type, type);
- }
-
- @Override
- protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
- String targetTypeName = type.getName();
-
- // System.err.println("match: " + targetTypeName + ", " + knownMatches); //Arrays.asList(importedPrefixes));
- // Ensure the annotation pattern is resolved
- annotationPattern.resolve(type.getWorld());
-
- return matchesExactlyByName(targetTypeName, type.isAnonymous(), type.isNested()) && matchesParameters(type, STATIC)
- && matchesBounds(type, STATIC)
- && annotationPattern.matches(annotatedType, type.temporaryAnnotationTypes).alwaysTrue();
- }
-
- // we've matched against the base (or raw) type, but if this type pattern specifies parameters or
- // type variables we need to make sure we match against them too
- private boolean matchesParameters(ResolvedType aType, MatchKind staticOrDynamic) {
- if (!isGeneric && typeParameters.size() > 0) {
- if (!aType.isParameterizedType()) {
- return false;
- }
- // we have to match type parameters
- return typeParameters.matches(aType.getResolvedTypeParameters(), staticOrDynamic).alwaysTrue();
- }
- return true;
- }
-
- // we've matched against the base (or raw) type, but if this type pattern specifies bounds because
- // it is a ? extends or ? super deal then we have to match them too.
- private boolean matchesBounds(ResolvedType aType, MatchKind staticOrDynamic) {
- if (!(aType instanceof BoundedReferenceType)) {
- return true;
- }
- BoundedReferenceType boundedRT = (BoundedReferenceType) aType;
- if (upperBound == null && boundedRT.getUpperBound() != null) {
- // for upper bound, null can also match against Object - but anything else and we're out.
- if (!boundedRT.getUpperBound().getName().equals(UnresolvedType.OBJECT.getName())) {
- return false;
- }
- }
- if (lowerBound == null && boundedRT.getLowerBound() != null) {
- return false;
- }
- if (upperBound != null) {
- // match ? extends
- if (aType.isGenericWildcard() && boundedRT.isSuper()) {
- return false;
- }
- if (boundedRT.getUpperBound() == null) {
- return false;
- }
- return upperBound.matches((ResolvedType) boundedRT.getUpperBound(), staticOrDynamic).alwaysTrue();
- }
- if (lowerBound != null) {
- // match ? super
- if (!(boundedRT.isGenericWildcard() && boundedRT.isSuper())) {
- return false;
- }
- return lowerBound.matches((ResolvedType) boundedRT.getLowerBound(), staticOrDynamic).alwaysTrue();
- }
- return true;
- }
-
- /**
- * Used in conjunction with checks on 'isStar()' to tell you if this pattern represents '*' or '*[]' which are different !
- */
- public int getDimensions() {
- return dim;
- }
-
- @Override
- public boolean isArray() {
- return dim > 0;
- }
-
- /**
- * @param targetTypeName
- * @return
- */
- private boolean matchesExactlyByName(String targetTypeName, boolean isAnonymous, boolean isNested) {
- // we deal with parameter matching separately...
- if (targetTypeName.indexOf('<') != -1) {
- targetTypeName = targetTypeName.substring(0, targetTypeName.indexOf('<'));
- }
- // we deal with bounds matching separately too...
- if (targetTypeName.startsWith(GENERIC_WILDCARD_CHARACTER)) {
- targetTypeName = GENERIC_WILDCARD_CHARACTER;
- }
- // XXX hack
- if (knownMatches == null && importedPrefixes == null) {
- return innerMatchesExactly(targetTypeName, isAnonymous, isNested);
- }
-
- if (isNamePatternStar()) {
- // we match if the dimensions match
- int numDimensionsInTargetType = 0;
- if (dim > 0) {
- int index;
- while ((index = targetTypeName.indexOf('[')) != -1) {
- numDimensionsInTargetType++;
- targetTypeName = targetTypeName.substring(index + 1);
- }
- if (numDimensionsInTargetType == dim) {
- return true;
- } else {
- return false;
- }
- }
- }
-
- // if our pattern is length 1, then known matches are exact matches
- // if it's longer than that, then known matches are prefixes of a sort
- if (namePatterns.length == 1) {
- if (isAnonymous) {
- // we've already ruled out "*", and no other name pattern should match an anonymous type
- return false;
- }
- for (String knownMatch : knownMatches) {
- if (knownMatch.equals(targetTypeName)) {
- return true;
- }
- }
- } else {
- for (String knownMatch : knownMatches) {
- // String knownPrefix = knownMatches[i] + "$";
- // if (targetTypeName.startsWith(knownPrefix)) {
- if (targetTypeName.startsWith(knownMatch) && targetTypeName.length() > knownMatch.length()
- && targetTypeName.charAt(knownMatch.length()) == '$') {
- int pos = lastIndexOfDotOrDollar(knownMatch);
- if (innerMatchesExactly(targetTypeName.substring(pos + 1), isAnonymous, isNested)) {
- return true;
- }
- }
- }
- }
-
- // if any prefixes match, strip the prefix and check that the rest matches
- // assumes that prefixes have a dot at the end
- for (String prefix : importedPrefixes) {
- // System.err.println("prefix match? " + prefix + " to " + targetTypeName);
- if (targetTypeName.startsWith(prefix)) {
-
- if (innerMatchesExactly(targetTypeName.substring(prefix.length()), isAnonymous, isNested)) {
- return true;
- }
- }
- }
-
- return innerMatchesExactly(targetTypeName, isAnonymous, isNested);
- }
-
- private int lastIndexOfDotOrDollar(String string) {
- for (int pos = string.length() - 1; pos > -1; pos--) {
- char ch = string.charAt(pos);
- if (ch == '.' || ch == '$') {
- return pos;
- }
- }
- return -1;
- }
-
- private boolean innerMatchesExactly(String s, boolean isAnonymous, boolean convertDollar /* isNested */) {
-
- List<char[]> ret = new ArrayList<>();
- int startIndex = 0;
- while (true) {
- int breakIndex = s.indexOf('.', startIndex); // what about /
- if (convertDollar && (breakIndex == -1)) {
- breakIndex = s.indexOf('$', startIndex); // we treat $ like . here
- }
- if (breakIndex == -1) {
- break;
- }
- char[] name = s.substring(startIndex, breakIndex).toCharArray();
- ret.add(name);
- startIndex = breakIndex + 1;
- }
- ret.add(s.substring(startIndex).toCharArray());
-
- int namesLength = ret.size();
- int patternsLength = namePatterns.length;
-
- int namesIndex = 0;
- int patternsIndex = 0;
-
- if ((!namePatterns[patternsLength - 1].isAny()) && isAnonymous) {
- return false;
- }
-
- if (ellipsisCount == 0) {
- if (namesLength != patternsLength) {
- return false;
- }
- while (patternsIndex < patternsLength) {
- if (!namePatterns[patternsIndex++].matches(ret.get(namesIndex++))) {
- return false;
- }
- }
- return true;
- } else if (ellipsisCount == 1) {
- if (namesLength < patternsLength - 1) {
- return false;
- }
- while (patternsIndex < patternsLength) {
- NamePattern p = namePatterns[patternsIndex++];
- if (p == NamePattern.ELLIPSIS) {
- namesIndex = namesLength - (patternsLength - patternsIndex);
- } else {
- if (!p.matches(ret.get(namesIndex++))) {
- return false;
- }
- }
- }
- return true;
- } else {
- // System.err.print("match(\"" + Arrays.asList(namePatterns) + "\", \"" + Arrays.asList(names) + "\") -> ");
- boolean b = outOfStar(namePatterns, ret.toArray(new char[ret.size()][]), 0, 0, patternsLength - ellipsisCount,
- namesLength, ellipsisCount);
- // System.err.println(b);
- return b;
- }
- }
-
- private static boolean outOfStar(final NamePattern[] pattern, final char[][] target, int pi, int ti, int pLeft, int tLeft,
- final int starsLeft) {
- if (pLeft > tLeft) {
- return false;
- }
- while (true) {
- // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
- if (tLeft == 0) {
- return true;
- }
- if (pLeft == 0) {
- return (starsLeft > 0);
- }
- if (pattern[pi] == NamePattern.ELLIPSIS) {
- return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1);
- }
- if (!pattern[pi].matches(target[ti])) {
- return false;
- }
- pi++;
- ti++;
- pLeft--;
- tLeft--;
- }
- }
-
- private static boolean inStar(final NamePattern[] pattern, final char[][] target, int pi, int ti, final int pLeft, int tLeft,
- int starsLeft) {
- // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
- // of course, we probably can't parse multiple ..'s in a row, but this keeps the algorithm
- // exactly parallel with that in NamePattern
- NamePattern patternChar = pattern[pi];
- while (patternChar == NamePattern.ELLIPSIS) {
- starsLeft--;
- patternChar = pattern[++pi];
- }
- while (true) {
- // invariant: if (tLeft > 0) then (ti < target.length)
- if (pLeft > tLeft) {
- return false;
- }
- if (patternChar.matches(target[ti])) {
- if (outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft)) {
- return true;
- }
- }
- ti++;
- tLeft--;
- }
- }
-
- /**
- * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(ResolvedType)
- */
- @Override
- public FuzzyBoolean matchesInstanceof(ResolvedType type) {
- // XXX hack to let unmatched types just silently remain so
- if (maybeGetSimpleName() != null) {
- return FuzzyBoolean.NO;
- }
-
- type.getWorld().getMessageHandler().handleMessage(
- new Message("can't do instanceof matching on patterns with wildcards", IMessage.ERROR, null, getSourceLocation()));
- return FuzzyBoolean.NO;
- }
-
- public NamePattern extractName() {
- if (isIncludeSubtypes() || isVarArgs() || isArray() || (typeParameters.size() > 0)) {
- // we can't extract a name, the pattern is something like Foo+ and therefore
- // it is not ok to treat Foo as a method name!
- return null;
- }
- // System.err.println("extract from : " + Arrays.asList(namePatterns));
- int len = namePatterns.length;
- if (len == 1 && !annotationPattern.isAny()) {
- return null; // can't extract
- }
- NamePattern ret = namePatterns[len - 1];
- NamePattern[] newNames = new NamePattern[len - 1];
- System.arraycopy(namePatterns, 0, newNames, 0, len - 1);
- namePatterns = newNames;
- // System.err.println(" left : " + Arrays.asList(namePatterns));
- return ret;
- }
-
- /**
- * Method maybeExtractName.
- *
- * @param string
- * @return boolean
- */
- public boolean maybeExtractName(String string) {
- int len = namePatterns.length;
- NamePattern ret = namePatterns[len - 1];
- String simple = ret.maybeGetSimpleName();
- if (simple != null && simple.equals(string)) {
- extractName();
- return true;
- }
- return false;
- }
-
- /**
- * If this type pattern has no '.' or '*' in it, then return a simple string
- *
- * otherwise, this will return null;
- */
- public String maybeGetSimpleName() {
- if (namePatterns.length == 1) {
- return namePatterns[0].maybeGetSimpleName();
- }
- return null;
- }
-
- /**
- * If this type pattern has no '*' or '..' in it
- */
- public String maybeGetCleanName() {
- if (namePatterns.length == 0) {
- throw new RuntimeException("bad name: " + namePatterns);
- }
- // System.out.println("get clean: " + this);
- StringBuilder buf = new StringBuilder();
- for (int i = 0, len = namePatterns.length; i < len; i++) {
- NamePattern p = namePatterns[i];
- String simpleName = p.maybeGetSimpleName();
- if (simpleName == null) {
- return null;
- }
- if (i > 0) {
- buf.append(".");
- }
- buf.append(simpleName);
- }
- // System.out.println(buf);
- return buf.toString();
- }
-
- @Override
- public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
- NamePattern[] newNamePatterns = new NamePattern[namePatterns.length];
- System.arraycopy(namePatterns, 0, newNamePatterns, 0, namePatterns.length);
- if (newNamePatterns.length == 1) {
- String simpleName = newNamePatterns[0].maybeGetSimpleName();
- if (simpleName != null) {
- if (typeVariableMap.containsKey(simpleName)) {
- String newName = ((ReferenceType) typeVariableMap.get(simpleName)).getName().replace('$', '.');
- StringTokenizer strTok = new StringTokenizer(newName, ".");
- newNamePatterns = new NamePattern[strTok.countTokens()];
- int index = 0;
- while (strTok.hasMoreTokens()) {
- newNamePatterns[index++] = new NamePattern(strTok.nextToken());
- }
- }
- }
- }
- WildTypePattern ret = new WildTypePattern(newNamePatterns, includeSubtypes, dim, isVarArgs, typeParameters
- .parameterizeWith(typeVariableMap, w));
- ret.annotationPattern = this.annotationPattern.parameterizeWith(typeVariableMap, w);
- if (additionalInterfaceBounds == null) {
- ret.additionalInterfaceBounds = null;
- } else {
- ret.additionalInterfaceBounds = new TypePattern[additionalInterfaceBounds.length];
- for (int i = 0; i < additionalInterfaceBounds.length; i++) {
- ret.additionalInterfaceBounds[i] = additionalInterfaceBounds[i].parameterizeWith(typeVariableMap, w);
- }
- }
- ret.upperBound = upperBound != null ? upperBound.parameterizeWith(typeVariableMap, w) : null;
- ret.lowerBound = lowerBound != null ? lowerBound.parameterizeWith(typeVariableMap, w) : null;
- ret.isGeneric = isGeneric;
- ret.knownMatches = knownMatches;
- ret.importedPrefixes = importedPrefixes;
- ret.copyLocationFrom(this);
- return ret;
- }
-
- /**
- * Need to determine if I'm really a pattern or a reference to a formal
- *
- * We may wish to further optimize the case of pattern vs. non-pattern
- *
- * We will be replaced by what we return
- */
- @Override
- public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
- if (isNamePatternStar()) {
- TypePattern anyPattern = maybeResolveToAnyPattern(scope, bindings, allowBinding, requireExactType);
- if (anyPattern != null) {
- if (requireExactType) {
- scope.getWorld().getMessageHandler().handleMessage(
- MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
- return NO;
- } else {
- return anyPattern;
- }
- }
- }
-
- TypePattern bindingTypePattern = maybeResolveToBindingTypePattern(scope, bindings, allowBinding, requireExactType);
- if (bindingTypePattern != null) {
- return bindingTypePattern;
- }
-
- annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
-
- // resolve any type parameters
- if (typeParameters != null && typeParameters.size() > 0) {
- typeParameters.resolveBindings(scope, bindings, allowBinding, requireExactType);
- isGeneric = false;
- }
-
- // resolve any bounds
- if (upperBound != null) {
- upperBound = upperBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
- }
- if (lowerBound != null) {
- lowerBound = lowerBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
- // amc - additional interface bounds only needed if we support type vars again.
- }
-
- String fullyQualifiedName = maybeGetCleanName();
- if (fullyQualifiedName != null) {
- return resolveBindingsFromFullyQualifiedTypeName(fullyQualifiedName, scope, bindings, allowBinding, requireExactType);
- } else {
- if (requireExactType) {
- scope.getWorld().getMessageHandler().handleMessage(
- MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
- return NO;
- }
- importedPrefixes = scope.getImportedPrefixes();
- knownMatches = preMatch(scope.getImportedNames());
- return this; // pattern contains wildcards so can't be resolved to an ExactTypePattern...
- // XXX need to implement behavior for Lint.invalidWildcardTypeName
- }
- }
-
- private TypePattern maybeResolveToAnyPattern(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
- // If there is an annotation specified we have to
- // use a special variant of Any TypePattern called
- // AnyWithAnnotation
- if (annotationPattern == AnnotationTypePattern.ANY) {
- if (dim == 0 && !isVarArgs && upperBound == null && lowerBound == null
- && (additionalInterfaceBounds == null || additionalInterfaceBounds.length == 0)) { // pr72531
- return TypePattern.ANY; // ??? loses source location
- }
- } else if (!isVarArgs) {
- annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
- AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(annotationPattern);
- ret.setLocation(sourceContext, start, end);
- return ret;
- }
- return null; // can't resolve to a simple "any" pattern
- }
-
- private TypePattern maybeResolveToBindingTypePattern(IScope scope, Bindings bindings, boolean allowBinding,
- boolean requireExactType) {
- String simpleName = maybeGetSimpleName();
- if (simpleName != null) {
- FormalBinding formalBinding = scope.lookupFormal(simpleName);
- if (formalBinding != null) {
- if (bindings == null) {
- scope.message(IMessage.ERROR, this, "negation doesn't allow binding");
- return this;
- }
- if (!allowBinding) {
- scope.message(IMessage.ERROR, this, "name binding only allowed in target, this, and args pcds");
- return this;
- }
-
- BindingTypePattern binding = new BindingTypePattern(formalBinding, isVarArgs);
- binding.copyLocationFrom(this);
- bindings.register(binding, scope);
-
- return binding;
- }
- }
- return null; // not possible to resolve to a binding type pattern
- }
-
- private TypePattern resolveBindingsFromFullyQualifiedTypeName(String fullyQualifiedName, IScope scope, Bindings bindings,
- boolean allowBinding, boolean requireExactType) {
- String originalName = fullyQualifiedName;
- ResolvedType resolvedTypeInTheWorld = null;
- UnresolvedType type;
-
- // System.out.println("resolve: " + cleanName);
- // ??? this loop has too many inefficiencies to count
- resolvedTypeInTheWorld = lookupTypeInWorldIncludingPrefixes(scope.getWorld(), fullyQualifiedName, scope
- .getImportedPrefixes());
-
- if (resolvedTypeInTheWorld.isGenericWildcard()) {
- type = resolvedTypeInTheWorld;
- } else {
- type = lookupTypeInScope(scope, fullyQualifiedName, this);
- }
- if ((type instanceof ResolvedType) && ((ResolvedType) type).isMissing()) {
- return resolveBindingsForMissingType(resolvedTypeInTheWorld, originalName, scope, bindings, allowBinding,
- requireExactType);
- } else {
- return resolveBindingsForExactType(scope, type, fullyQualifiedName, requireExactType);
- }
- }
-
- private UnresolvedType lookupTypeInScope(IScope scope, String typeName, IHasPosition location) {
- UnresolvedType type = null;
- while (ResolvedType.isMissing(type = scope.lookupType(typeName, location))) {
- int lastDot = typeName.lastIndexOf('.');
- if (lastDot == -1) {
- break;
- }
- typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
- }
- return type;
- }
-
- /**
- * Searches the world for the ResolvedType with the given typeName. If one isn't found then for each of the supplied prefixes,
- * it prepends the typeName with the prefix and searches the world for the ResolvedType with this new name. If one still isn't
- * found then a MissingResolvedTypeWithKnownSignature is returned with the originally requested typeName (this ensures the
- * typeName makes sense).
- */
- private ResolvedType lookupTypeInWorldIncludingPrefixes(World world, String typeName, String[] prefixes) {
- ResolvedType ret = lookupTypeInWorld(world, typeName);
- if (!ret.isMissing()) {
- return ret;
- }
- ResolvedType retWithPrefix = ret;
- int counter = 0;
- while (retWithPrefix.isMissing() && (counter < prefixes.length)) {
- retWithPrefix = lookupTypeInWorld(world, prefixes[counter] + typeName);
- counter++;
- }
- if (!retWithPrefix.isMissing()) {
- return retWithPrefix;
- }
- return ret;
- }
-
- private ResolvedType lookupTypeInWorld(World world, String typeName) {
- UnresolvedType ut = UnresolvedType.forName(typeName);
- ResolvedType ret = world.resolve(ut, true);
- while (ret.isMissing()) {
- int lastDot = typeName.lastIndexOf('.');
- if (lastDot == -1) {
- break;
- }
- typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
- ret = world.resolve(UnresolvedType.forName(typeName), true);
- }
- return ret;
- }
-
- private TypePattern resolveBindingsForExactType(IScope scope, UnresolvedType aType, String fullyQualifiedName,
- boolean requireExactType) {
- TypePattern ret = null;
- if (aType.isTypeVariableReference()) {
- // we have to set the bounds on it based on the bounds of this pattern
- ret = resolveBindingsForTypeVariable(scope, (UnresolvedTypeVariableReferenceType) aType);
- } else if (typeParameters.size() > 0) {
- ret = resolveParameterizedType(scope, aType, requireExactType);
- } else if (upperBound != null || lowerBound != null) {
- // this must be a generic wildcard with bounds
- ret = resolveGenericWildcard(scope, aType);
- } else {
- if (dim != 0) {
- aType = UnresolvedType.makeArray(aType, dim);
- }
- ret = new ExactTypePattern(aType, includeSubtypes, isVarArgs);
- }
- ret.setAnnotationTypePattern(annotationPattern);
- ret.copyLocationFrom(this);
- return ret;
- }
-
- private TypePattern resolveGenericWildcard(IScope scope, UnresolvedType aType) {
- if (!aType.getSignature().equals(GENERIC_WILDCARD_SIGNATURE_CHARACTER)) {
- throw new IllegalStateException("Can only have bounds for a generic wildcard");
- }
- boolean canBeExact = true;
- if ((upperBound != null) && ResolvedType.isMissing(upperBound.getExactType())) {
- canBeExact = false;
- }
- if ((lowerBound != null) && ResolvedType.isMissing(lowerBound.getExactType())) {
- canBeExact = false;
- }
- if (canBeExact) {
- ResolvedType type = null;
- if (upperBound != null) {
- if (upperBound.isIncludeSubtypes()) {
- canBeExact = false;
- } else {
- ReferenceType upper = (ReferenceType) upperBound.getExactType().resolve(scope.getWorld());
- type = new BoundedReferenceType(upper, true, scope.getWorld());
- }
- } else {
- if (lowerBound.isIncludeSubtypes()) {
- canBeExact = false;
- } else {
- ReferenceType lower = (ReferenceType) lowerBound.getExactType().resolve(scope.getWorld());
- type = new BoundedReferenceType(lower, false, scope.getWorld());
- }
- }
- if (canBeExact) {
- // might have changed if we find out include subtypes is set on one of the bounds...
- return new ExactTypePattern(type, includeSubtypes, isVarArgs);
- }
- }
-
- // we weren't able to resolve to an exact type pattern...
- // leave as wild type pattern
- importedPrefixes = scope.getImportedPrefixes();
- knownMatches = preMatch(scope.getImportedNames());
- return this;
- }
-
- private TypePattern resolveParameterizedType(IScope scope, UnresolvedType aType, boolean requireExactType) {
- ResolvedType rt = aType.resolve(scope.getWorld());
- if (!verifyTypeParameters(rt, scope, requireExactType)) {
- return TypePattern.NO; // messages already isued
- }
- // Only if the type is exact *and* the type parameters are exact should we create an
- // ExactTypePattern for this WildTypePattern
- if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
- TypePattern[] typePats = typeParameters.getTypePatterns();
- UnresolvedType[] typeParameterTypes = new UnresolvedType[typePats.length];
- for (int i = 0; i < typeParameterTypes.length; i++) {
- typeParameterTypes[i] = ((ExactTypePattern) typePats[i]).getExactType();
- }
- // rt could be a parameterized type 156058
- if (rt.isParameterizedType()) {
- rt = rt.getGenericType();
- }
- ResolvedType type = TypeFactory.createParameterizedType(rt, typeParameterTypes, scope.getWorld());
- if (isGeneric) {
- type = type.getGenericType();
- }
- // UnresolvedType tx = UnresolvedType.forParameterizedTypes(aType,typeParameterTypes);
- // UnresolvedType type = scope.getWorld().resolve(tx,true);
- if (dim != 0) {
- type = ResolvedType.makeArray(type, dim);
- }
- return new ExactTypePattern(type, includeSubtypes, isVarArgs);
- } else {
- // AMC... just leave it as a wild type pattern then?
- importedPrefixes = scope.getImportedPrefixes();
- knownMatches = preMatch(scope.getImportedNames());
- return this;
- }
- }
-
- private TypePattern resolveBindingsForMissingType(ResolvedType typeFoundInWholeWorldSearch, String nameWeLookedFor,
- IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
- if (requireExactType) {
- if (!allowBinding) {
- scope.getWorld().getMessageHandler().handleMessage(
- MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_BIND_TYPE, nameWeLookedFor),
- getSourceLocation()));
- } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
- scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
- }
- return NO;
- } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
- // Only put the lint warning out if we can't find it in the world
- if (typeFoundInWholeWorldSearch.isMissing()) {
- scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
- this.failedResolution = true;
- }
- }
- importedPrefixes = scope.getImportedPrefixes();
- knownMatches = preMatch(scope.getImportedNames());
- return this;
- }
-
- /**
- * We resolved the type to a type variable declared in the pointcut designator. Now we have to create either an exact type
- * pattern or a wild type pattern for it, with upper and lower bounds set accordingly. XXX none of this stuff gets serialized
- * yet
- *
- * @param scope
- * @param tvrType
- * @return
- */
- private TypePattern resolveBindingsForTypeVariable(IScope scope, UnresolvedTypeVariableReferenceType tvrType) {
- Bindings emptyBindings = new Bindings(0);
- if (upperBound != null) {
- upperBound = upperBound.resolveBindings(scope, emptyBindings, false, false);
- }
- if (lowerBound != null) {
- lowerBound = lowerBound.resolveBindings(scope, emptyBindings, false, false);
- }
- if (additionalInterfaceBounds != null) {
- TypePattern[] resolvedIfBounds = new TypePattern[additionalInterfaceBounds.length];
- for (int i = 0; i < resolvedIfBounds.length; i++) {
- resolvedIfBounds[i] = additionalInterfaceBounds[i].resolveBindings(scope, emptyBindings, false, false);
- }
- additionalInterfaceBounds = resolvedIfBounds;
- }
- if (upperBound == null && lowerBound == null && additionalInterfaceBounds == null) {
- // no bounds to worry about...
- ResolvedType rType = tvrType.resolve(scope.getWorld());
- if (dim != 0) {
- rType = ResolvedType.makeArray(rType, dim);
- }
- return new ExactTypePattern(rType, includeSubtypes, isVarArgs);
- } else {
- // we have to set bounds on the TypeVariable held by tvrType before resolving it
- boolean canCreateExactTypePattern = true;
- if (upperBound != null && ResolvedType.isMissing(upperBound.getExactType())) {
- canCreateExactTypePattern = false;
- }
- if (lowerBound != null && ResolvedType.isMissing(lowerBound.getExactType())) {
- canCreateExactTypePattern = false;
- }
- if (additionalInterfaceBounds != null) {
- for (TypePattern additionalInterfaceBound : additionalInterfaceBounds) {
- if (ResolvedType.isMissing(additionalInterfaceBound.getExactType())) {
- canCreateExactTypePattern = false;
- }
- }
- }
- if (canCreateExactTypePattern) {
- TypeVariable tv = tvrType.getTypeVariable();
- if (upperBound != null) {
- tv.setSuperclass(upperBound.getExactType());
- }
- if (additionalInterfaceBounds != null) {
- UnresolvedType[] ifBounds = new UnresolvedType[additionalInterfaceBounds.length];
- for (int i = 0; i < ifBounds.length; i++) {
- ifBounds[i] = additionalInterfaceBounds[i].getExactType();
- }
- tv.setAdditionalInterfaceBounds(ifBounds);
- }
- ResolvedType rType = tvrType.resolve(scope.getWorld());
- if (dim != 0) {
- rType = ResolvedType.makeArray(rType, dim);
- }
- return new ExactTypePattern(rType, includeSubtypes, isVarArgs);
- }
- return this; // leave as wild type pattern then
- }
- }
-
- /**
- * When this method is called, we have resolved the base type to an exact type. We also have a set of type patterns for the
- * parameters. Time to perform some basic checks: - can the base type be parameterized? (is it generic) - can the type parameter
- * pattern list match the number of parameters on the base type - do all parameter patterns meet the bounds of the respective
- * type variables If any of these checks fail, a warning message is issued and we return false.
- *
- * @return
- */
- private boolean verifyTypeParameters(ResolvedType baseType, IScope scope, boolean requireExactType) {
- ResolvedType genericType = baseType.getGenericType();
- if (genericType == null) {
- // issue message "does not match because baseType.getName() is not generic"
- scope.message(MessageUtil.warn(WeaverMessages.format(WeaverMessages.NOT_A_GENERIC_TYPE, baseType.getName()),
- getSourceLocation()));
- return false;
- }
- int minRequiredTypeParameters = typeParameters.size();
- boolean foundEllipsis = false;
- TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
- for (TypePattern typeParamPattern : typeParamPatterns) {
- if (typeParamPattern instanceof WildTypePattern) {
- WildTypePattern wtp = (WildTypePattern) typeParamPattern;
- if (wtp.ellipsisCount > 0) {
- foundEllipsis = true;
- minRequiredTypeParameters--;
- }
- }
- }
- TypeVariable[] tvs = genericType.getTypeVariables();
- if ((tvs.length < minRequiredTypeParameters) || (!foundEllipsis && minRequiredTypeParameters != tvs.length)) {
- // issue message "does not match because wrong no of type params"
- String msg = WeaverMessages.format(WeaverMessages.INCORRECT_NUMBER_OF_TYPE_ARGUMENTS, genericType.getName(),
- tvs.length);
- if (requireExactType) {
- scope.message(MessageUtil.error(msg, getSourceLocation()));
- } else {
- scope.message(MessageUtil.warn(msg, getSourceLocation()));
- }
- return false;
- }
-
- // now check that each typeParameter pattern, if exact, matches the bounds
- // of the type variable.
-
- // pr133307 - delay verification until type binding completion, these next few lines replace
- // the call to checkBoundsOK
- if (!boundscheckingoff) {
- VerifyBoundsForTypePattern verification = new VerifyBoundsForTypePattern(scope, genericType, requireExactType,
- typeParameters, getSourceLocation());
- scope.getWorld().getCrosscuttingMembersSet().recordNecessaryCheck(verification);
- }
- // return checkBoundsOK(scope,genericType,requireExactType);
-
- return true;
- }
-
- /**
- * By capturing the verification in this class, rather than performing it in verifyTypeParameters(), we can cope with situations
- * where the interactions between generics and declare parents would otherwise cause us problems. For example, if verifying as
- * we go along we may report a problem which would have been fixed by a declare parents that we haven't looked at yet. If we
- * create and store a verification object, we can verify this later when the type system is considered 'complete'
- */
- static class VerifyBoundsForTypePattern implements IVerificationRequired {
-
- private final IScope scope;
- private final ResolvedType genericType;
- private final boolean requireExactType;
- private TypePatternList typeParameters = TypePatternList.EMPTY;
- private final ISourceLocation sLoc;
-
- public VerifyBoundsForTypePattern(IScope scope, ResolvedType genericType, boolean requireExactType,
- TypePatternList typeParameters, ISourceLocation sLoc) {
- this.scope = scope;
- this.genericType = genericType;
- this.requireExactType = requireExactType;
- this.typeParameters = typeParameters;
- this.sLoc = sLoc;
- }
-
- public void verify() {
- TypeVariable[] tvs = genericType.getTypeVariables();
- TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
- if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
- for (int i = 0; i < tvs.length; i++) {
- UnresolvedType ut = typeParamPatterns[i].getExactType();
- boolean continueCheck = true;
- // FIXME asc dont like this but ok temporary measure. If the type parameter
- // is itself a type variable (from the generic aspect) then assume it'll be
- // ok... (see pr112105) Want to break this? Run GenericAspectK test.
- if (ut.isTypeVariableReference()) {
- continueCheck = false;
- }
-
- // System.err.println("Verifying "+ut.getName()+" meets bounds for "+tvs[i]);
- if (continueCheck && !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
- // issue message that type parameter does not meet specification
- String parameterName = ut.getName();
- if (ut.isTypeVariableReference()) {
- parameterName = ((TypeVariableReference) ut).getTypeVariable().getDisplayName();
- }
- String msg = WeaverMessages.format(WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS, parameterName,
- i + 1, tvs[i].getDisplayName(), genericType.getName());
- if (requireExactType) {
- scope.message(MessageUtil.error(msg, sLoc));
- } else {
- scope.message(MessageUtil.warn(msg, sLoc));
- }
- }
- }
- }
- }
- }
-
- // pr133307 - moved to verification object
- // public boolean checkBoundsOK(IScope scope,ResolvedType genericType,boolean requireExactType) {
- // if (boundscheckingoff) return true;
- // TypeVariable[] tvs = genericType.getTypeVariables();
- // TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
- // if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
- // for (int i = 0; i < tvs.length; i++) {
- // UnresolvedType ut = typeParamPatterns[i].getExactType();
- // boolean continueCheck = true;
- // // FIXME asc dont like this but ok temporary measure. If the type parameter
- // // is itself a type variable (from the generic aspect) then assume it'll be
- // // ok... (see pr112105) Want to break this? Run GenericAspectK test.
- // if (ut.isTypeVariableReference()) {
- // continueCheck = false;
- // }
- //
- // if (continueCheck &&
- // !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
- // // issue message that type parameter does not meet specification
- // String parameterName = ut.getName();
- // if (ut.isTypeVariableReference()) parameterName = ((TypeVariableReference)ut).getTypeVariable().getDisplayName();
- // String msg =
- // WeaverMessages.format(
- // WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS,
- // parameterName,
- // new Integer(i+1),
- // tvs[i].getDisplayName(),
- // genericType.getName());
- // if (requireExactType) scope.message(MessageUtil.error(msg,getSourceLocation()));
- // else scope.message(MessageUtil.warn(msg,getSourceLocation()));
- // return false;
- // }
- // }
- // }
- // return true;
- // }
-
- @Override
- public boolean isStar() {
- boolean annPatternStar = annotationPattern == AnnotationTypePattern.ANY;
- return (isNamePatternStar() && annPatternStar && dim == 0);
- }
-
- private boolean isNamePatternStar() {
- return namePatterns.length == 1 && namePatterns[0].isAny();
- }
-
- /**
- * @return those possible matches which I match exactly the last element of
- */
- private String[] preMatch(String[] possibleMatches) {
- // if (namePatterns.length != 1) return CollectionUtil.NO_STRINGS;
-
- List<String> ret = new ArrayList<>();
- for (String possibleMatch : possibleMatches) {
- char[][] names = splitNames(possibleMatch, true); // ??? not most efficient
- if (namePatterns[0].matches(names[names.length - 1])) {
- ret.add(possibleMatch);
- continue;
- }
- if (possibleMatch.contains("$")) {
- names = splitNames(possibleMatch, false); // ??? not most efficient
- if (namePatterns[0].matches(names[names.length - 1])) {
- ret.add(possibleMatch);
- }
- }
- }
- return ret.toArray(new String[0]);
- }
-
- // public void postRead(ResolvedType enclosingType) {
- // this.importedPrefixes = enclosingType.getImportedPrefixes();
- // this.knownNames = prematch(enclosingType.getImportedNames());
- // }
-
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
- if (annotationPattern != AnnotationTypePattern.ANY) {
- buf.append('(');
- buf.append(annotationPattern.toString());
- buf.append(' ');
- }
- for (int i = 0, len = namePatterns.length; i < len; i++) {
- NamePattern name = namePatterns[i];
- if (name == null) {
- buf.append(".");
- } else {
- if (i > 0) {
- buf.append(".");
- }
- buf.append(name.toString());
- }
- }
- if (upperBound != null) {
- buf.append(" extends ");
- buf.append(upperBound.toString());
- }
- if (lowerBound != null) {
- buf.append(" super ");
- buf.append(lowerBound.toString());
- }
- if (typeParameters != null && typeParameters.size() != 0) {
- buf.append("<");
- buf.append(typeParameters.toString());
- buf.append(">");
- }
- if (includeSubtypes) {
- buf.append('+');
- }
- if (isVarArgs) {
- buf.append("...");
- }
- if (annotationPattern != AnnotationTypePattern.ANY) {
- buf.append(')');
- }
- return buf.toString();
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof WildTypePattern)) {
- return false;
- }
- WildTypePattern o = (WildTypePattern) other;
- int len = o.namePatterns.length;
- if (len != this.namePatterns.length) {
- return false;
- }
- if (this.includeSubtypes != o.includeSubtypes) {
- return false;
- }
- if (this.dim != o.dim) {
- return false;
- }
- if (this.isVarArgs != o.isVarArgs) {
- return false;
- }
- if (this.upperBound != null) {
- if (o.upperBound == null) {
- return false;
- }
- if (!this.upperBound.equals(o.upperBound)) {
- return false;
- }
- } else {
- if (o.upperBound != null) {
- return false;
- }
- }
- if (this.lowerBound != null) {
- if (o.lowerBound == null) {
- return false;
- }
- if (!this.lowerBound.equals(o.lowerBound)) {
- return false;
- }
- } else {
- if (o.lowerBound != null) {
- return false;
- }
- }
- if (!typeParameters.equals(o.typeParameters)) {
- return false;
- }
- for (int i = 0; i < len; i++) {
- if (!o.namePatterns[i].equals(this.namePatterns[i])) {
- return false;
- }
- }
- return (o.annotationPattern.equals(this.annotationPattern));
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- for (NamePattern namePattern : namePatterns) {
- result = 37 * result + namePattern.hashCode();
- }
- result = 37 * result + annotationPattern.hashCode();
- if (upperBound != null) {
- result = 37 * result + upperBound.hashCode();
- }
- if (lowerBound != null) {
- result = 37 * result + lowerBound.hashCode();
- }
- return result;
- }
-
- private static final byte VERSION = 1; // rev on change
-
- @Override
- public void write(CompressingDataOutputStream s) throws IOException {
- s.writeByte(TypePattern.WILD);
- s.writeByte(VERSION);
- s.writeShort(namePatterns.length);
- for (NamePattern namePattern : namePatterns) {
- namePattern.write(s);
- }
- s.writeBoolean(includeSubtypes);
- s.writeInt(dim);
- s.writeBoolean(isVarArgs);
- typeParameters.write(s); // ! change from M2
- // ??? storing this information with every type pattern is wasteful of .class
- // file size. Storing it on enclosing types would be more efficient
- FileUtil.writeStringArray(knownMatches, s);
- FileUtil.writeStringArray(importedPrefixes, s);
- writeLocation(s);
- annotationPattern.write(s);
- // generics info, new in M3
- s.writeBoolean(isGeneric);
- s.writeBoolean(upperBound != null);
- if (upperBound != null) {
- upperBound.write(s);
- }
- s.writeBoolean(lowerBound != null);
- if (lowerBound != null) {
- lowerBound.write(s);
- }
- s.writeInt(additionalInterfaceBounds == null ? 0 : additionalInterfaceBounds.length);
- if (additionalInterfaceBounds != null) {
- for (TypePattern additionalInterfaceBound : additionalInterfaceBounds) {
- additionalInterfaceBound.write(s);
- }
- }
- }
-
- public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
- if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
- return readTypePattern150(s, context);
- } else {
- return readTypePatternOldStyle(s, context);
- }
- }
-
- public static TypePattern readTypePattern150(VersionedDataInputStream s, ISourceContext context) throws IOException {
- byte version = s.readByte();
- if (version > VERSION) {
- throw new BCException("WildTypePattern was written by a more recent version of AspectJ, cannot read");
- }
- int len = s.readShort();
- NamePattern[] namePatterns = new NamePattern[len];
- for (int i = 0; i < len; i++) {
- namePatterns[i] = NamePattern.read(s);
- }
- boolean includeSubtypes = s.readBoolean();
- int dim = s.readInt();
- boolean varArg = s.readBoolean();
- TypePatternList typeParams = TypePatternList.read(s, context);
- WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, varArg, typeParams);
- ret.knownMatches = FileUtil.readStringArray(s);
- ret.importedPrefixes = FileUtil.readStringArray(s);
- ret.readLocation(context, s);
- ret.setAnnotationTypePattern(AnnotationTypePattern.read(s, context));
- // generics info, new in M3
- ret.isGeneric = s.readBoolean();
- if (s.readBoolean()) {
- ret.upperBound = TypePattern.read(s, context);
- }
- if (s.readBoolean()) {
- ret.lowerBound = TypePattern.read(s, context);
- }
- int numIfBounds = s.readInt();
- if (numIfBounds > 0) {
- ret.additionalInterfaceBounds = new TypePattern[numIfBounds];
- for (int i = 0; i < numIfBounds; i++) {
- ret.additionalInterfaceBounds[i] = TypePattern.read(s, context);
- }
- }
- return ret;
- }
-
- public static TypePattern readTypePatternOldStyle(VersionedDataInputStream s, ISourceContext context) throws IOException {
- int len = s.readShort();
- NamePattern[] namePatterns = new NamePattern[len];
- for (int i = 0; i < len; i++) {
- namePatterns[i] = NamePattern.read(s);
- }
- boolean includeSubtypes = s.readBoolean();
- int dim = s.readInt();
- WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, false, null);
- ret.knownMatches = FileUtil.readStringArray(s);
- ret.importedPrefixes = FileUtil.readStringArray(s);
- ret.readLocation(context, s);
- return ret;
- }
-
- @Override
- public Object accept(PatternNodeVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-
- public boolean hasFailedResolution() {
- return failedResolution;
- }
-
- }
|