The existing check crudely only checked the top level, failing to find nested WildTypePatterns. Resolves #542682tags/V1_9_3RC1
/* ******************************************************************* | /* ******************************************************************* | ||||
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). | |||||
* Copyright (c) 2002-2019 Contributors | |||||
* All rights reserved. | * All rights reserved. | ||||
* This program and the accompanying materials are made available | * This program and the accompanying materials are made available | ||||
* under the terms of the Eclipse Public License v1.0 | * under the terms of the Eclipse Public License v1.0 | ||||
* which accompanies this distribution and is available at | * which accompanies this distribution and is available at | ||||
* http://www.eclipse.org/legal/epl-v10.html | * http://www.eclipse.org/legal/epl-v10.html | ||||
* | |||||
* Contributors: | |||||
* PARC initial implementation | |||||
* ******************************************************************/ | * ******************************************************************/ | ||||
package org.aspectj.weaver.patterns; | package org.aspectj.weaver.patterns; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import org.aspectj.weaver.WeaverMessages; | import org.aspectj.weaver.WeaverMessages; | ||||
import org.aspectj.weaver.World; | import org.aspectj.weaver.World; | ||||
/** | |||||
* @author Thomas Kiviaho | |||||
* @author Andy Clement | |||||
* @author PARC | |||||
*/ | |||||
public class DeclareParents extends Declare { | public class DeclareParents extends Declare { | ||||
protected TypePattern child; | protected TypePattern child; | ||||
protected TypePatternList parents; | protected TypePatternList parents; | ||||
private boolean isWildChild = false; | private boolean isWildChild = false; | ||||
protected boolean isExtends = true; | protected boolean isExtends = true; | ||||
// private String[] typeVariablesInScope = new String[0]; // AspectJ 5 extension for generic types | |||||
public DeclareParents(TypePattern child, List parents, boolean isExtends) { | |||||
public DeclareParents(TypePattern child, List<TypePattern> parents, boolean isExtends) { | |||||
this(child, new TypePatternList(parents), isExtends); | this(child, new TypePatternList(parents), isExtends); | ||||
} | } | ||||
this.child = child; | this.child = child; | ||||
this.parents = parents; | this.parents = parents; | ||||
this.isExtends = isExtends; | this.isExtends = isExtends; | ||||
if (child instanceof WildTypePattern) { | |||||
isWildChild = true; | |||||
} | |||||
WildChildFinder wildChildFinder = new WildChildFinder(); | |||||
child.accept(wildChildFinder, null); | |||||
isWildChild = wildChildFinder.containedWildChild(); | |||||
} | } | ||||
// public String[] getTypeParameterNames() { | |||||
// return this.typeVariablesInScope; | |||||
// } | |||||
// | |||||
// public void setTypeParametersInScope(String[] typeParameters) { | |||||
// this.typeVariablesInScope = typeParameters; | |||||
// } | |||||
public boolean match(ResolvedType typeX) { | public boolean match(ResolvedType typeX) { | ||||
if (!child.matchesStatically(typeX)) { | if (!child.matchesStatically(typeX)) { | ||||
return false; | return false; | ||||
} | } | ||||
@Override | @Override | ||||
public Declare parameterizeWith(Map typeVariableBindingMap, World w) { | |||||
public Declare parameterizeWith(Map<String,UnresolvedType> typeVariableBindingMap, World w) { | |||||
DeclareParents ret = new DeclareParents(child.parameterizeWith(typeVariableBindingMap, w), parents.parameterizeWith( | DeclareParents ret = new DeclareParents(child.parameterizeWith(typeVariableBindingMap, w), parents.parameterizeWith( | ||||
typeVariableBindingMap, w), isExtends); | typeVariableBindingMap, w), isExtends); | ||||
ret.copyLocationFrom(this); | ret.copyLocationFrom(this); | ||||
s.writeByte(Declare.PARENTS); | s.writeByte(Declare.PARENTS); | ||||
child.write(s); | child.write(s); | ||||
parents.write(s); | parents.write(s); | ||||
// s.writeInt(typeVariablesInScope.length); | |||||
// for (int i = 0; i < typeVariablesInScope.length; i++) { | |||||
// s.writeUTF(typeVariablesInScope[i]); | |||||
// } | |||||
writeLocation(s); | writeLocation(s); | ||||
} | } | ||||
public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException { | public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException { | ||||
DeclareParents ret = new DeclareParents(TypePattern.read(s, context), TypePatternList.read(s, context), true); | DeclareParents ret = new DeclareParents(TypePattern.read(s, context), TypePatternList.read(s, context), true); | ||||
// if (s.getMajorVersion()>=AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) { | |||||
// int numTypeVariablesInScope = s.readInt(); | |||||
// ret.typeVariablesInScope = new String[numTypeVariablesInScope]; | |||||
// for (int i = 0; i < numTypeVariablesInScope; i++) { | |||||
// ret.typeVariablesInScope[i] = s.readUTF(); | |||||
// } | |||||
// } | |||||
ret.readLocation(context, s); | ret.readLocation(context, s); | ||||
return ret; | return ret; | ||||
} | } | ||||
@Override | @Override | ||||
public void resolve(IScope scope) { | public void resolve(IScope scope) { | ||||
// ScopeWithTypeVariables resolutionScope = new ScopeWithTypeVariables(typeVariablesInScope,scope); | |||||
child = child.resolveBindings(scope, Bindings.NONE, false, false); | |||||
isWildChild = (child instanceof WildTypePattern); | |||||
TypePattern resolvedChild = child.resolveBindings(scope, Bindings.NONE, false, false); | |||||
if (!resolvedChild.equals(child)) { | |||||
WildChildFinder wildChildFinder = new WildChildFinder(); | |||||
resolvedChild.accept(wildChildFinder, null); | |||||
isWildChild = wildChildFinder.containedWildChild(); | |||||
this.child = resolvedChild; | |||||
} | |||||
parents = parents.resolveBindings(scope, Bindings.NONE, false, true); | parents = parents.resolveBindings(scope, Bindings.NONE, false, true); | ||||
// Could assert this ... | // Could assert this ... | ||||
// for (int i=0; i < parents.size(); i++) { | // for (int i=0; i < parents.size(); i++) { | ||||
// parents.get(i).assertExactType(scope.getMessageHandler()); | // parents.get(i).assertExactType(scope.getMessageHandler()); |
/* ******************************************************************* | |||||
* Copyright (c) 2019 Contributors | |||||
* All rights reserved. | |||||
* This program and the accompanying materials are made available | |||||
* under the terms of the Eclipse Public License v1.0 | |||||
* which accompanies this distribution and is available at | |||||
* http://www.eclipse.org/legal/epl-v10.html | |||||
* | |||||
* ******************************************************************/ | |||||
package org.aspectj.weaver.patterns; | |||||
/** | |||||
* @author Tuomas Kiviaho | |||||
*/ | |||||
public class WildChildFinder extends AbstractPatternNodeVisitor { | |||||
private boolean wildChild; | |||||
public WildChildFinder() { | |||||
super(); | |||||
} | |||||
public boolean containedWildChild() { | |||||
return wildChild; | |||||
} | |||||
@Override | |||||
public Object visit(WildAnnotationTypePattern node, Object data) { | |||||
node.getTypePattern().accept(this, data); | |||||
return node; | |||||
} | |||||
@Override | |||||
public Object visit(WildTypePattern node, Object data) { | |||||
this.wildChild = true; | |||||
return super.visit(node, data); | |||||
} | |||||
@Override | |||||
public Object visit(AndTypePattern node, Object data) { | |||||
node.getLeft().accept(this, data); | |||||
if (!this.wildChild) { | |||||
node.getRight().accept(this, data); | |||||
} | |||||
return node; | |||||
} | |||||
@Override | |||||
public Object visit(OrTypePattern node, Object data) { | |||||
node.getLeft().accept(this, data); | |||||
if (!this.wildChild) { | |||||
node.getRight().accept(this, data); | |||||
} | |||||
return node; | |||||
} | |||||
public Object visit(NotTypePattern node, Object data) { | |||||
node.getNegatedPattern().accept(this, data); | |||||
return node; | |||||
} | |||||
@Override | |||||
public Object visit(AnyWithAnnotationTypePattern node, Object data) { | |||||
node.getAnnotationPattern().accept(this, data); | |||||
return node; | |||||
} | |||||
} |
import java.lang.annotation.*; | |||||
import org.aspectj.lang.annotation.*; | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
@interface SomeAnnotation {} | |||||
@SomeAnnotation | |||||
public class CaseA { | |||||
public static void main(String[]argv) { | |||||
CaseA ca = new CaseA(); | |||||
((I)ca).methodOne(); // will only succeed if mixin applied | |||||
} | |||||
} | |||||
@SomeAnnotation | |||||
enum Color {R,G,B} | |||||
aspect X { | |||||
@DeclareMixin("(@SomeAnnotation *)") | |||||
public static I createImplementation() { | |||||
System.out.println("Delegate factory invoked"); | |||||
return new Implementation(); | |||||
} | |||||
} | |||||
interface I { | |||||
void methodOne(); | |||||
} | |||||
class Implementation implements I { | |||||
public void methodOne() { | |||||
System.out.println("methodOne running"); | |||||
} | |||||
} | |||||
import java.lang.annotation.*; | |||||
import java.lang.Enum; | |||||
public aspect EnumAspect04 { | |||||
interface I {}; | |||||
//declare parents: SimpleE* implements I; | |||||
//declare parents: !*Aspect04 implements I; | |||||
declare parents: @Foo * implements I; | |||||
} | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
@interface Foo {} |
@Foo | |||||
public class SimpleClass {} |
@Foo | |||||
public enum SimpleEnum { Red,Orange,Yellow,Green,Blue,Indigo,Violet }; |
@Foo | |||||
public enum SimpleEnum2 { Black, White }; |
/******************************************************************************* | /******************************************************************************* | ||||
* Copyright (c) 2018 Contributors | |||||
* Copyright (c) 2018-2019 Contributors | |||||
* All rights reserved. This program and the accompanying materials | * All rights reserved. This program and the accompanying materials | ||||
* are made available under the terms of the Eclipse Public License v1.0 | * are made available under the terms of the Eclipse Public License v1.0 | ||||
* which accompanies this distribution, and is available at | * which accompanies this distribution, and is available at | ||||
* http://www.eclipse.org/legal/epl-v10.html | * http://www.eclipse.org/legal/epl-v10.html | ||||
* | |||||
* Contributors: | |||||
* Andy Clement - initial API and implementation | |||||
*******************************************************************************/ | *******************************************************************************/ | ||||
package org.aspectj.systemtest.ajc193; | package org.aspectj.systemtest.ajc193; | ||||
*/ | */ | ||||
public class Ajc193Tests extends XMLBasedAjcTestCaseForJava10OrLater { | public class Ajc193Tests extends XMLBasedAjcTestCaseForJava10OrLater { | ||||
// Altered version of this test from org.aspectj.systemtest.ajc150.Enums for 542682 | |||||
public void decpOnEnumNotAllowed_xlints() { | |||||
runTest("wildcard enum match in itd"); | |||||
} | |||||
public void testEnumDecmixinMessage() { | |||||
runTest("declare mixin a"); | |||||
} | |||||
public void testIsAbstractType() { | public void testIsAbstractType() { | ||||
runTest("is abstract"); | runTest("is abstract"); | ||||
} | } | ||||
public void testIsAbstractType2() { | public void testIsAbstractType2() { | ||||
runTest("is abstract - 2"); | runTest("is abstract - 2"); | ||||
} | } | ||||
// --- | // --- | ||||
public static Test suite() { | public static Test suite() { | ||||
@Override | @Override | ||||
protected File getSpecFile() { | protected File getSpecFile() { | ||||
return getClassResource("ajc193.xml"); | |||||
return getClassResource("ajc193.xml"); | |||||
} | } | ||||
} | } |
<suite> | <suite> | ||||
<ajc-test dir="bugs193/542682" vm="1.5" title="wildcard enum match in itd"> | |||||
<compile files="SimpleEnum.java,SimpleEnum2.java,EnumAspect04.aj" options="-1.5"> | |||||
<message kind="warning" line="8" text="enum type SimpleEnum2 matches a declare parents type pattern but is being ignored"/> | |||||
<message kind="warning" line="8" text="enum type SimpleEnum matches a declare parents type pattern but is being ignored"/> | |||||
</compile> | |||||
</ajc-test> | |||||
<ajc-test dir="bugs193/542682" title="declare mixin a"> | |||||
<compile files="CaseA.java" options="-1.8"> | |||||
<message kind="warning" line="1" text="enum type Color matches a declare parents type pattern but is being ignored"/> | |||||
</compile> | |||||
<run class="CaseA"> | |||||
<stdout> | |||||
<line text="Delegate factory invoked"/> | |||||
<line text="methodOne running"/> | |||||
</stdout> | |||||
</run> | |||||
</ajc-test> | |||||
<ajc-test dir="bugs193/isAbstractType" title="is abstract"> | <ajc-test dir="bugs193/isAbstractType" title="is abstract"> | ||||
<compile files="Code.java" options="-1.8"/> | <compile files="Code.java" options="-1.8"/> | ||||
<run class="Code"> | <run class="Code"> |