org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.TypeAnnotationWalker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during
compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based
@AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step.
This library is a superset of AspectJ weaver and hence also of AspectJ runtime.
/*******************************************************************************
* Copyright (c) 2013, 2017 GK Software AG.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Stephan Herrmann - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.compiler.classfmt;
import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker;
/** Type annotation walker implementation based an actual annotations decoded from a .class file. */
public class TypeAnnotationWalker implements ITypeAnnotationWalker {
final protected IBinaryTypeAnnotation[] typeAnnotations; // the actual material we're managing here
final protected long matches; // bit mask of indices into typeAnnotations, 1 means active, 0 is filtered during the walk
final protected int pathPtr; // pointer into the typePath
// precondition: not-empty typeAnnotations
public TypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations) {
this(typeAnnotations, -1L >>> (64-typeAnnotations.length)); // initialize so lowest length bits are 1
}
TypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations, long matchBits) {
this(typeAnnotations, matchBits, 0);
}
protected TypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations, long matchBits, int pathPtr) {
this.typeAnnotations = typeAnnotations;
this.matches = matchBits;
this.pathPtr = pathPtr;
}
protected ITypeAnnotationWalker restrict(long newMatches, int newPathPtr) {
if (this.matches == newMatches && this.pathPtr == newPathPtr) return this;
if (newMatches == 0 || this.typeAnnotations == null || this.typeAnnotations.length == 0)
return EMPTY_ANNOTATION_WALKER;
return new TypeAnnotationWalker(this.typeAnnotations, newMatches, newPathPtr);
}
// ==== filter by top-level targetType: ====
@Override
public ITypeAnnotationWalker toField() {
return toTarget(AnnotationTargetTypeConstants.FIELD);
}
@Override
public ITypeAnnotationWalker toMethodReturn() {
return toTarget(AnnotationTargetTypeConstants.METHOD_RETURN);
}
@Override
public ITypeAnnotationWalker toReceiver() {
return toTarget(AnnotationTargetTypeConstants.METHOD_RECEIVER);
}
/*
* Implementation for walking to methodReturn, receiver type or field.
*/
protected ITypeAnnotationWalker toTarget(int targetType) {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
if (this.typeAnnotations[i].getTargetType() != targetType)
newMatches &= ~mask;
}
return restrict(newMatches, 0);
}
@Override
public ITypeAnnotationWalker toTypeParameter(boolean isClassTypeParameter, int rank) {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int targetType = isClassTypeParameter ? AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER : AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
if (candidate.getTargetType() != targetType || candidate.getTypeParameterIndex() != rank) {
newMatches &= ~mask;
}
}
return restrict(newMatches, 0);
}
@Override
public ITypeAnnotationWalker toTypeParameterBounds(boolean isClassTypeParameter, int parameterRank) {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
int targetType = isClassTypeParameter ?
AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND : AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
if (candidate.getTargetType() != targetType || (short)candidate.getTypeParameterIndex() != parameterRank) {
newMatches &= ~mask;
}
}
return restrict(newMatches, 0);
}
@Override
public ITypeAnnotationWalker toTypeBound(short boundIndex) {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
if ((short)candidate.getBoundIndex() != boundIndex) {
newMatches &= ~mask;
}
}
return restrict(newMatches, 0);
}
/**
* {@inheritDoc}
* (superTypesSignature is ignored in this implementation).
*/
@Override
public ITypeAnnotationWalker toSupertype(short index, char[] superTypeSignature) {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
if (candidate.getTargetType() != AnnotationTargetTypeConstants.CLASS_EXTENDS || (short)candidate.getSupertypeIndex() != index) {
newMatches &= ~mask;
}
}
return restrict(newMatches, 0);
}
@Override
public ITypeAnnotationWalker toMethodParameter(short index) {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
if (candidate.getTargetType() != AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER || (short)candidate.getMethodFormalParameterIndex() != index) {
newMatches &= ~mask;
}
}
return restrict(newMatches, 0);
}
@Override
public ITypeAnnotationWalker toThrows(int index) {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
if (candidate.getTargetType() != AnnotationTargetTypeConstants.THROWS || candidate.getThrowsTypeIndex() != index) {
newMatches &= ~mask;
}
}
return restrict(newMatches, 0);
}
// ==== descending into details: ====
@Override
public ITypeAnnotationWalker toTypeArgument(int rank) {
// like toNextDetail() but also checking byte 2 against rank
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
int[] path = candidate.getTypePath();
if (this.pathPtr >= path.length
|| path[this.pathPtr] != AnnotationTargetTypeConstants.TYPE_ARGUMENT
|| path[this.pathPtr+1] != rank) {
newMatches &= ~mask;
}
}
return restrict(newMatches, this.pathPtr+2);
}
@Override
public ITypeAnnotationWalker toWildcardBound() {
long newMatches = this.matches;
if (newMatches == 0)
return EMPTY_ANNOTATION_WALKER;
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
int[] path = candidate.getTypePath();
if (this.pathPtr >= path.length
|| path[this.pathPtr] != AnnotationTargetTypeConstants.WILDCARD_BOUND) {
newMatches &= ~mask;
}
}
return restrict(newMatches, this.pathPtr+2);
}
@Override
public ITypeAnnotationWalker toNextArrayDimension() {
return toNextDetail(AnnotationTargetTypeConstants.NEXT_ARRAY_DIMENSION);
}
@Override
public ITypeAnnotationWalker toNextNestedType() {
return toNextDetail(AnnotationTargetTypeConstants.NEXT_NESTED_TYPE);
}
/*
* Implementation for walking along the type_path for array dimensions & nested types.
*/
protected ITypeAnnotationWalker toNextDetail(int detailKind) {
long newMatches = this.matches;
if (newMatches == 0)
return restrict(newMatches, this.pathPtr+2);
int length = this.typeAnnotations.length;
long mask = 1;
for (int i = 0; i < length; i++, mask = mask << 1) {
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
int[] path = candidate.getTypePath();
if (this.pathPtr >= path.length || path[this.pathPtr] != detailKind) {
newMatches &= ~mask;
}
}
return restrict(newMatches, this.pathPtr+2);
}
// ==== leaves: the actual annotations: ====
@Override
public IBinaryAnnotation[] getAnnotationsAtCursor(int currentTypeId, boolean mayApplyArrayContentsDefaultNullness) {
int length = this.typeAnnotations.length;
IBinaryAnnotation[] filtered = new IBinaryAnnotation[length];
long ptr = 1;
int count = 0;
for (int i = 0; i < length; i++, ptr<<=1) {
if ((this.matches & ptr) == 0)
continue;
IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
if (candidate.getTypePath().length > this.pathPtr)
continue;
filtered[count++] = candidate.getAnnotation();
}
if (count == 0)
return NO_ANNOTATIONS;
if (count < length)
System.arraycopy(filtered, 0, filtered = new IBinaryAnnotation[count], 0, count);
return filtered;
}
}