org.aspectj.org.eclipse.jdt.internal.core.search.matching.ConstructorPattern 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) 2000, 2014 IBM Corporation and others.
*
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core.search.matching;
import java.io.IOException;
import org.aspectj.org.eclipse.jdt.core.BindingKey;
import org.aspectj.org.eclipse.jdt.core.Flags;
import org.aspectj.org.eclipse.jdt.core.IMethod;
import org.aspectj.org.eclipse.jdt.core.IType;
import org.aspectj.org.eclipse.jdt.core.JavaModelException;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.aspectj.org.eclipse.jdt.core.search.SearchPattern;
import org.aspectj.org.eclipse.jdt.internal.compiler.ExtraFlags;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.aspectj.org.eclipse.jdt.internal.core.index.EntryResult;
import org.aspectj.org.eclipse.jdt.internal.core.index.Index;
import org.aspectj.org.eclipse.jdt.internal.core.util.Util;
public class ConstructorPattern extends JavaSearchPattern {
protected boolean findDeclarations = true;
protected boolean findReferences = true;
public char[] declaringQualification;
public char[] declaringSimpleName;
public char[][] parameterQualifications;
public char[][] parameterSimpleNames;
public int parameterCount;
public boolean varargs = false;
// Signatures and arguments for generic search
char[][][] parametersTypeSignatures;
char[][][][] parametersTypeArguments;
boolean constructorParameters = false;
char[][] constructorArguments;
protected static char[][] REF_CATEGORIES = { CONSTRUCTOR_REF };
protected static char[][] REF_AND_DECL_CATEGORIES = { CONSTRUCTOR_REF, CONSTRUCTOR_DECL };
protected static char[][] DECL_CATEGORIES = { CONSTRUCTOR_DECL };
public final static int FINE_GRAIN_MASK =
IJavaSearchConstants.SUPER_REFERENCE |
IJavaSearchConstants.QUALIFIED_REFERENCE |
IJavaSearchConstants.THIS_REFERENCE |
IJavaSearchConstants.IMPLICIT_THIS_REFERENCE |
IJavaSearchConstants.METHOD_REFERENCE_EXPRESSION;
/**
* Constructor entries are encoded as described
*
* Binary constructor for class
* TypeName '/' Arity '/' TypeModifers '/' PackageName '/' Signature '/' ParameterNamesopt '/' Modifiers
* Source constructor for class
* TypeName '/' Arity '/' TypeModifers '/' PackageName '/' ParameterTypes '/' ParameterNamesopt '/' Modifiers
* Constructor with 0 arity for class
* TypeName '/' 0 '/' TypeModifers '/' PackageName '/' Modifiers
* Constructor for enum, interface (annotation) and class with default constructor
* TypeName '/' # '/' TypeModifers '/' PackageName
* Constructor for member type
* TypeName '/' Arity '/' TypeModifers
*
* TypeModifiers contains some encoded extra information
* {@link ExtraFlags#IsMemberType}
* {@link ExtraFlags#HasNonPrivateStaticMemberTypes}
* {@link ExtraFlags#ParameterTypesStoredAsSignature}
*/
public static char[] createDeclarationIndexKey(
char[] typeName,
int argCount,
char[] signature,
char[][] parameterTypes,
char[][] parameterNames,
int modifiers,
char[] packageName,
int typeModifiers,
int extraFlags) {
char[] countChars;
char[] parameterTypesChars = null;
char[] parameterNamesChars = null;
if (argCount < 0) {
countChars = DEFAULT_CONSTRUCTOR;
} else {
countChars = argCount < 10
? COUNTS[argCount]
: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
if (argCount > 0) {
if (signature == null) {
if (parameterTypes != null && parameterTypes.length == argCount) {
char[][] parameterTypeErasures = new char[argCount][];
for (int i = 0; i < parameterTypes.length; i++) {
parameterTypeErasures[i] = getTypeErasure(parameterTypes[i]);
}
parameterTypesChars = CharOperation.concatWith(parameterTypeErasures, PARAMETER_SEPARATOR);
}
} else {
extraFlags |= ExtraFlags.ParameterTypesStoredAsSignature;
}
if (parameterNames != null && parameterNames.length == argCount) {
parameterNamesChars = CharOperation.concatWith(parameterNames, PARAMETER_SEPARATOR);
}
}
}
boolean isMemberType = (extraFlags & ExtraFlags.IsMemberType) != 0;
int typeNameLength = typeName == null ? 0 : typeName.length;
int packageNameLength = packageName == null ? 0 : packageName.length;
int countCharsLength = countChars.length;
int parameterTypesLength = signature == null ? (parameterTypesChars == null ? 0 : parameterTypesChars.length): signature.length;
int parameterNamesLength = parameterNamesChars == null ? 0 : parameterNamesChars.length;
int resultLength = typeNameLength + countCharsLength + 3; // SEPARATOR=1 + TypeModifers=2
if (!isMemberType) {
resultLength += packageNameLength + 1; // SEPARATOR=1
if (argCount >= 0) {
resultLength += 3; // SEPARATOR=1 + Modifiers=2
}
if (argCount > 0) {
resultLength += parameterTypesLength + parameterNamesLength + 2; //SEPARATOR=1 + SEPARATOR=1
}
}
char[] result = new char[resultLength];
int pos = 0;
if (typeNameLength > 0) {
System.arraycopy(typeName, 0, result, pos, typeNameLength);
pos += typeNameLength;
}
if (countCharsLength > 0) {
System.arraycopy(countChars, 0, result, pos, countCharsLength);
pos += countCharsLength;
}
int typeModifiersWithExtraFlags = typeModifiers | encodeExtraFlags(extraFlags);
result[pos++] = SEPARATOR;
result[pos++] = (char) typeModifiersWithExtraFlags;
result[pos++] = (char) (typeModifiersWithExtraFlags>>16);
if (!isMemberType) {
result[pos++] = SEPARATOR;
if (packageNameLength > 0) {
System.arraycopy(packageName, 0, result, pos, packageNameLength);
pos += packageNameLength;
}
if (argCount == 0) {
result[pos++] = SEPARATOR;
result[pos++] = (char) modifiers;
result[pos++] = (char) (modifiers>>16);
} else if (argCount > 0) {
result[pos++] = SEPARATOR;
if (parameterTypesLength > 0) {
if (signature == null) {
System.arraycopy(parameterTypesChars, 0, result, pos, parameterTypesLength);
} else {
System.arraycopy(CharOperation.replaceOnCopy(signature, SEPARATOR, '\\'), 0, result, pos, parameterTypesLength);
}
pos += parameterTypesLength;
}
result[pos++] = SEPARATOR;
if (parameterNamesLength > 0) {
System.arraycopy(parameterNamesChars, 0, result, pos, parameterNamesLength);
pos += parameterNamesLength;
}
result[pos++] = SEPARATOR;
result[pos++] = (char) modifiers;
result[pos++] = (char) (modifiers>>16);
}
}
return result;
}
public static char[] createDefaultDeclarationIndexKey(
char[] typeName,
char[] packageName,
int typeModifiers,
int extraFlags) {
return createDeclarationIndexKey(
typeName,
-1, // used to identify default constructor
null,
null,
null,
0, //
packageName,
typeModifiers,
extraFlags);
}
/**
* Constructor entries are encoded as TypeName '/' Arity:
* e.g. 'X/0'
*/
public static char[] createIndexKey(char[] typeName, int argCount) {
char[] countChars = argCount < 10
? COUNTS[argCount]
: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
return CharOperation.concat(typeName, countChars);
}
static int decodeExtraFlags(int modifiersWithExtraFlags) {
int extraFlags = 0;
if ((modifiersWithExtraFlags & ASTNode.Bit28) != 0) {
extraFlags |= ExtraFlags.ParameterTypesStoredAsSignature;
}
if ((modifiersWithExtraFlags & ASTNode.Bit29) != 0) {
extraFlags |= ExtraFlags.IsLocalType;
}
if ((modifiersWithExtraFlags & ASTNode.Bit30) != 0) {
extraFlags |= ExtraFlags.IsMemberType;
}
if ((modifiersWithExtraFlags & ASTNode.Bit31) != 0) {
extraFlags |= ExtraFlags.HasNonPrivateStaticMemberTypes;
}
return extraFlags;
}
static int decodeModifers(int modifiersWithExtraFlags) {
return modifiersWithExtraFlags & ~(ASTNode.Bit31 | ASTNode.Bit30 | ASTNode.Bit29 | ASTNode.Bit28);
}
private static int encodeExtraFlags(int extraFlags) {
int encodedExtraFlags = 0;
if ((extraFlags & ExtraFlags.ParameterTypesStoredAsSignature) != 0) {
encodedExtraFlags |= ASTNode.Bit28;
}
if ((extraFlags & ExtraFlags.IsLocalType) != 0) {
encodedExtraFlags |= ASTNode.Bit29;
}
if ((extraFlags & ExtraFlags.IsMemberType) != 0) {
encodedExtraFlags |= ASTNode.Bit30;
}
if ((extraFlags & ExtraFlags.HasNonPrivateStaticMemberTypes) != 0) {
encodedExtraFlags |= ASTNode.Bit31;
}
return encodedExtraFlags;
}
private static char[] getTypeErasure(char[] typeName) {
int index;
if ((index = CharOperation.indexOf('<', typeName)) == -1) return typeName;
int length = typeName.length;
char[] typeErasurename = new char[length - 2];
System.arraycopy(typeName, 0, typeErasurename, 0, index);
int depth = 1;
for (int i = index + 1; i < length; i++) {
switch (typeName[i]) {
case '<':
depth++;
break;
case '>':
depth--;
break;
default:
if (depth == 0) {
typeErasurename[index++] = typeName[i];
}
break;
}
}
System.arraycopy(typeErasurename, 0, typeErasurename = new char[index], 0, index);
return typeErasurename;
}
ConstructorPattern(int matchRule) {
super(CONSTRUCTOR_PATTERN, matchRule);
}
public ConstructorPattern(
char[] declaringSimpleName,
char[] declaringQualification,
char[][] parameterQualifications,
char[][] parameterSimpleNames,
int limitTo,
int matchRule,
boolean isStaticInnerConstructor) {
this(matchRule);
this.fineGrain = limitTo & FINE_GRAIN_MASK;
if (this.fineGrain == 0) {
switch (limitTo) {
case IJavaSearchConstants.DECLARATIONS :
this.findReferences = false;
break;
case IJavaSearchConstants.REFERENCES :
this.findDeclarations = false;
break;
case IJavaSearchConstants.ALL_OCCURRENCES :
break;
}
} else {
this.findDeclarations = false;
}
this.declaringQualification = this.isCaseSensitive ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
this.declaringSimpleName = (this.isCaseSensitive || this.isCamelCase) ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
if (parameterSimpleNames != null) {
this.parameterCount = parameterSimpleNames.length;
boolean synthetic = !isStaticInnerConstructor && this.parameterCount>0 && declaringQualification != null && CharOperation.equals(CharOperation.concat(parameterQualifications[0], parameterSimpleNames[0], '.'), declaringQualification);
int offset = 0;
if (synthetic) {
// skip first synthetic parameter
this.parameterCount--;
offset++;
}
this.parameterQualifications = new char[this.parameterCount][];
this.parameterSimpleNames = new char[this.parameterCount][];
for (int i = 0; i < this.parameterCount; i++) {
this.parameterQualifications[i] = this.isCaseSensitive ? parameterQualifications[i+offset] : CharOperation.toLowerCase(parameterQualifications[i+offset]);
this.parameterSimpleNames[i] = this.isCaseSensitive ? parameterSimpleNames[i+offset] : CharOperation.toLowerCase(parameterSimpleNames[i+offset]);
}
} else {
this.parameterCount = -1;
}
this.mustResolve = mustResolve();
}
/*
* Instantiate a method pattern with signatures for generics search
*/
public ConstructorPattern(
char[] declaringSimpleName,
char[] declaringQualification,
char[][] parameterQualifications,
char[][] parameterSimpleNames,
String[] parameterSignatures,
IMethod method,
int limitTo,
int matchRule) {
this(declaringSimpleName,
declaringQualification,
parameterQualifications,
parameterSimpleNames,
limitTo,
matchRule,
isStaticInnerConstructor(method));
// Set flags
try {
this.varargs = (method.getFlags() & Flags.AccVarargs) != 0;
} catch (JavaModelException e) {
// do nothing
}
// Get unique key for parameterized constructors
String genericDeclaringTypeSignature = null;
if (method.isResolved()) {
String key = method.getKey();
BindingKey bindingKey = new BindingKey(key);
if (bindingKey.isParameterizedType()) {
genericDeclaringTypeSignature = Util.getDeclaringTypeSignature(key);
// Store type signature and arguments for declaring type
if (genericDeclaringTypeSignature != null) {
this.typeSignatures = Util.splitTypeLevelsSignature(genericDeclaringTypeSignature);
setTypeArguments(Util.getAllTypeArguments(this.typeSignatures));
}
}
} else {
this.constructorParameters = true;
storeTypeSignaturesAndArguments(method.getDeclaringType());
}
// store type signatures and arguments for method parameters type
if (parameterSignatures != null) {
int length = parameterSignatures.length;
if (length > 0) {
this.parametersTypeSignatures = new char[length][][];
this.parametersTypeArguments = new char[length][][][];
for (int i=0; i 0) {
this.parametersTypeSignatures = new char[length][][];
this.parametersTypeArguments = new char[length][][][];
for (int i=0; i 0) {
this.constructorArguments = getTypeArguments()[0];
}
}
if (hasConstructorArguments()) this.mustResolve = true;
}
@Override
public void decodeIndexKey(char[] key) {
int last = key.length - 1;
int slash = CharOperation.indexOf(SEPARATOR, key, 0);
this.declaringSimpleName = CharOperation.subarray(key, 0, slash);
int start = slash + 1;
slash = CharOperation.indexOf(SEPARATOR, key, start);
if (slash != -1) {
last = slash - 1;
}
boolean isDefaultConstructor = key[last] == '#';
if (isDefaultConstructor) {
this.parameterCount = -1;
} else {
this.parameterCount = 0;
int power = 1;
for (int i = last; i >= start; i--) {
if (i == last) {
this.parameterCount = key[i] - '0';
} else {
power *= 10;
this.parameterCount += power * (key[i] - '0');
}
}
}
}
@Override
public SearchPattern getBlankPattern() {
return new ConstructorPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
}
@Override
public char[][] getIndexCategories() {
if (this.findReferences)
return this.findDeclarations ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
if (this.findDeclarations)
return DECL_CATEGORIES;
return CharOperation.NO_CHAR_CHAR;
}
boolean hasConstructorArguments() {
return this.constructorArguments != null && this.constructorArguments.length > 0;
}
boolean hasConstructorParameters() {
return this.constructorParameters;
}
@Override
public boolean matchesDecodedKey(SearchPattern decodedPattern) {
ConstructorPattern pattern = (ConstructorPattern) decodedPattern;
return pattern.parameterCount != -1
&& (this.parameterCount == pattern.parameterCount || this.parameterCount == -1 || this.varargs)
&& matchesName(this.declaringSimpleName, pattern.declaringSimpleName);
}
protected boolean mustResolve() {
if (this.declaringQualification != null) return true;
// parameter types
if (this.parameterSimpleNames != null)
for (int i = 0, max = this.parameterSimpleNames.length; i < max; i++)
if (this.parameterQualifications[i] != null) return true;
return this.findReferences; // need to check resolved default constructors and explicit constructor calls
}
@Override
public EntryResult[] queryIn(Index index) throws IOException {
char[] key = this.declaringSimpleName; // can be null
int matchRule = getMatchRule();
switch(getMatchMode()) {
case R_EXACT_MATCH :
if (this.declaringSimpleName != null && this.parameterCount >= 0 && !this.varargs) {
key = createIndexKey(this.declaringSimpleName, this.parameterCount);
}
matchRule &= ~R_EXACT_MATCH;
matchRule |= R_PREFIX_MATCH;
break;
case R_PREFIX_MATCH :
// do a prefix query with the declaringSimpleName
break;
case R_PATTERN_MATCH :
if (this.parameterCount >= 0 && !this.varargs) {
key = CharOperation.concat(createIndexKey(this.declaringSimpleName == null ? ONE_STAR : this.declaringSimpleName, this.parameterCount), ONE_STAR);
} else if (this.declaringSimpleName != null && this.declaringSimpleName[this.declaringSimpleName.length - 1] != '*') {
key = CharOperation.concat(this.declaringSimpleName, ONE_STAR, SEPARATOR);
} else if (key != null){
key = CharOperation.concat(key, ONE_STAR);
}
// else do a pattern query with just the declaringSimpleName
break;
case R_REGEXP_MATCH :
// TODO (frederic) implement regular expression match
break;
case R_CAMELCASE_MATCH:
case R_CAMELCASE_SAME_PART_COUNT_MATCH:
// do a prefix query with the declaringSimpleName
break;
}
return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
}
@Override
protected StringBuilder print(StringBuilder output) {
if (this.findDeclarations) {
output.append(this.findReferences
? "ConstructorCombinedPattern: " //$NON-NLS-1$
: "ConstructorDeclarationPattern: "); //$NON-NLS-1$
} else {
output.append("ConstructorReferencePattern: "); //$NON-NLS-1$
}
if (this.declaringQualification != null)
output.append(this.declaringQualification).append('.');
if (this.declaringSimpleName != null)
output.append(this.declaringSimpleName);
else if (this.declaringQualification != null)
output.append("*"); //$NON-NLS-1$
output.append('(');
if (this.parameterSimpleNames == null) {
output.append("..."); //$NON-NLS-1$
} else {
for (int i = 0, max = this.parameterSimpleNames.length; i < max; i++) {
if (i > 0) output.append(", "); //$NON-NLS-1$
if (this.parameterQualifications[i] != null) output.append(this.parameterQualifications[i]).append('.');
if (this.parameterSimpleNames[i] == null) output.append('*'); else output.append(this.parameterSimpleNames[i]);
}
}
output.append(')');
return super.print(output);
}
private static boolean isStaticInnerConstructor(IMethod method) {
try {
IType declaringType = method.getDeclaringType();
int flags = declaringType.getFlags();
return Flags.isStatic(flags);
} catch (JavaModelException e) {
// assume no
return false;
}
}
}