All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jdt.internal.compiler.classfmt.TypeAnnotationWalker Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2013, 2015 GK Software AG.
 * 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
 *
 * Contributors:
 *     Stephan Herrmann - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.classfmt;

import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
import 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 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] != detailKind) { newMatches &= ~mask; } } return restrict(newMatches, this.pathPtr+2); } // ==== leaves: the actual annotations: ==== @Override public IBinaryAnnotation[] getAnnotationsAtCursor(int currentTypeId) { 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy