/******************************************************************************* * Copyright (c) 2011 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.jsdt.internal.core.search.matching; import org.eclipse.wst.jsdt.core.compiler.CharOperation; import org.eclipse.wst.jsdt.core.search.SearchPattern; import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants; /** * <p>Pattern used to find and store constructor declarations.</p> */ public class ConstructorDeclarationPattern extends ConstructorPattern { public int modifiers; public char[][] parameterTypes; public char[][] parameterNames; public ConstructorDeclarationPattern(char[] declaringSimpleName, int matchRule) { this(matchRule); this.declaringSimpleName = (this.isCaseSensitive || this.isCamelCase) ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName); this.findDeclarations = true; this.findReferences = false; this.parameterCount = -1; } ConstructorDeclarationPattern(int matchRule) { super(matchRule); } public SearchPattern getBlankPattern() { return new ConstructorDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE); } public char[][] getIndexCategories() { return DECL_CATEGORIES; } public boolean matchesDecodedKey(SearchPattern decodedPattern) { ConstructorDeclarationPattern pattern = (ConstructorDeclarationPattern) decodedPattern; return (this.parameterCount == pattern.parameterCount || this.parameterCount == -1 || this.varargs) && matchesName(this.declaringSimpleName, pattern.declaringSimpleName); } /** * <p>Decodes an index key made with {@link #createDeclarationIndexKey(char[], int, char[][], char[][], int)} into the * parameters of this pattern.</p> * * @see org.eclipse.wst.jsdt.internal.core.search.matching.ConstructorPattern#decodeIndexKey(char[]) * * @see #createDeclarationIndexKey(char[], int, char[][], char[][], int) */ public void decodeIndexKey(char[] key) { //decode type name 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); last = slash - 1; //decode parameter count 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'); } } // initialize optional fields this.modifiers = 0; this.parameterTypes = null; this.parameterNames = null; /* if no parameters just decode modifiers * else decode parameters and modifiers */ start = slash + 1; if (this.parameterCount == 0) { slash = slash + 3; last = slash - 1; this.modifiers = key[last-1] + (key[last]<<16); } else if (this.parameterCount > 0){ slash = CharOperation.indexOf(SEPARATOR, key, start); last = slash - 1; this.parameterTypes = CharOperation.splitOn(PARAMETER_SEPARATOR, key, start, slash); start = slash + 1; slash = CharOperation.indexOf(SEPARATOR, key, start); last = slash - 1; if (slash != start) { this.parameterNames = CharOperation.splitOn(PARAMETER_SEPARATOR, key, start, slash); } slash = slash + 3; last = slash - 1; this.modifiers = key[last-1] + (key[last]<<16); } else { this.modifiers = ClassFileConstants.AccPublic; } } /** * <p>Creates a constructor index key based on the given information to be placed in the index.</p> * * @param typeName Name of the type the constructor is for * @param parameterCount Number of parameters for the constructor, or -1 for a default constructor * @param parameterTypes Type names of the parameters, should be same length as <code>parameterCount</code> * @param parameterNames Names of the parameters, should be same length as <code>parameterCount</code> * @param modifiers Modifiers to the constructor such as public/private * * @return Constructor index key based on the given information to be used in an index */ public static char[] createDeclarationIndexKey( char[] typeName, int parameterCount, char[][] parameterTypes, char[][] parameterNames, int modifiers) { char[] countChars; char[] parameterTypesChars = null; char[] parameterNamesChars = null; //use pre-made char array for arg counts less then 10, else build a new one countChars = parameterCount < 10 ? COUNTS[parameterCount] : ("/" + String.valueOf(parameterCount)).toCharArray(); //$NON-NLS-1$ if (parameterCount > 0) { //get param types if (parameterTypes != null && parameterTypes.length == parameterCount) { char[][] parameterTypeErasures = new char[parameterCount][]; for (int i = 0; i < parameterTypes.length; i++) { parameterTypeErasures[i] = getTypeErasure(parameterTypes[i]); } parameterTypesChars = CharOperation.concatWith(parameterTypeErasures, PARAMETER_SEPARATOR, false); } //get param names if (parameterNames != null && parameterNames.length == parameterCount) { parameterNamesChars = CharOperation.concatWith(parameterNames, PARAMETER_SEPARATOR); } } //get lengths int typeNameLength = typeName == null ? 0 : typeName.length; int countCharsLength = countChars.length; int parameterTypesLength = parameterTypesChars == null ? 0 : parameterTypesChars.length; int parameterNamesLength = parameterNamesChars == null ? 0 : parameterNamesChars.length; int resultLength = typeNameLength + countCharsLength; //add length for parameters and separators if (parameterCount > 0) { resultLength += parameterTypesLength + parameterNamesLength + 2; //SEPARATOR=1 + SEPARATOR=1 } //add length for modifiers and separator resultLength += 3; //create result char array char[] result = new char[resultLength]; //add type name to result int pos = 0; if (typeNameLength > 0) { System.arraycopy(typeName, 0, result, pos, typeNameLength); pos += typeNameLength; } //add param count to result if (countCharsLength > 0) { System.arraycopy(countChars, 0, result, pos, countCharsLength); pos += countCharsLength; } // if params add to result if (parameterCount > 0) { //add param types result[pos++] = SEPARATOR; if (parameterTypesLength > 0) { System.arraycopy(parameterTypesChars, 0, result, pos, parameterTypesLength); pos += parameterTypesLength; } //add param names result[pos++] = SEPARATOR; if (parameterNamesLength > 0) { System.arraycopy(parameterNamesChars, 0, result, pos, parameterNamesLength); pos += parameterNamesLength; } } //add modifiers result[pos++] = SEPARATOR; result[pos++] = (char) modifiers; result[pos++] = (char) (modifiers>>16); return result; } private static char[] getTypeErasure(char[] typeName) { char[] typeErasurename = new char[0]; if(typeName != null) { int index; if ((index = CharOperation.indexOf('<', typeName)) == -1) return typeName; int length = typeName.length; 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; } }