Index: buildnotes_jdt-core.html =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/buildnotes_jdt-core.html,v retrieving revision 1.3354 diff -u -r1.3354 buildnotes_jdt-core.html --- buildnotes_jdt-core.html 8 Oct 2004 12:05:44 -0000 1.3354 +++ buildnotes_jdt-core.html 8 Oct 2004 12:15:54 -0000 @@ -53,7 +53,9 @@

Problem Reports Fixed

-73671 +73277 +[1.5][Search] Fields search does not work with generics +
73671 [1.5] Signature.getTypeArguments should also tolerate normal types
73078 ISourceManipulation.delete() tries to run in WorkspaceRoot scheduling rule Index: model/org/eclipse/jdt/core/Signature.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java,v retrieving revision 1.54 diff -u -r1.54 Signature.java --- model/org/eclipse/jdt/core/Signature.java 8 Oct 2004 12:05:44 -0000 1.54 +++ model/org/eclipse/jdt/core/Signature.java 8 Oct 2004 12:15:54 -0000 @@ -1443,7 +1443,10 @@ * @since 3.1 */ public static char[][] getTypeArguments(char[] parameterizedTypeSignature) throws IllegalArgumentException { - int start = CharOperation.indexOf(C_GENERIC_START, parameterizedTypeSignature); + int lastDot = CharOperation.lastIndexOf(C_DOT, parameterizedTypeSignature); + int start = lastDot == -1 + ? CharOperation.indexOf(C_GENERIC_START, parameterizedTypeSignature) + : CharOperation.indexOf(C_GENERIC_START, parameterizedTypeSignature, lastDot+1); if (start == -1) return CharOperation.NO_CHAR_CHAR; ArrayList args = new ArrayList(); @@ -1492,12 +1495,37 @@ * @since 3.1 */ public static char[] getTypeErasure(char[] parameterizedTypeSignature) throws IllegalArgumentException { - int genericStart = CharOperation.indexOf(C_GENERIC_START, parameterizedTypeSignature); - if (genericStart == -1) return parameterizedTypeSignature; - char[] result = new char[genericStart+1]; - System.arraycopy(parameterizedTypeSignature, 0, result, 0, genericStart); - result[genericStart] = C_SEMICOLON; - return result; + int end = CharOperation.indexOf(C_GENERIC_START, parameterizedTypeSignature); + if (end == -1) return parameterizedTypeSignature; + int length = parameterizedTypeSignature.length; + char[] result = new char[length]; + int pos = 0; + int start = 0; + int deep= 0; + for (int idx=end; idx 0) throw new IllegalArgumentException(); + int size = pos+length-start; + char[] resized = new char[size]; + System.arraycopy(result, 0, resized, 0, pos); + System.arraycopy(parameterizedTypeSignature, start, resized, pos, length-start); + return resized; } /** Index: model/org/eclipse/jdt/internal/core/BinaryType.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java,v retrieving revision 1.90 diff -u -r1.90 BinaryType.java --- model/org/eclipse/jdt/internal/core/BinaryType.java 6 Oct 2004 10:51:17 -0000 1.90 +++ model/org/eclipse/jdt/internal/core/BinaryType.java 8 Oct 2004 12:15:54 -0000 @@ -466,7 +466,8 @@ return typeParameters; } -// SEARCH_15 Get type parameter names +// Get type parameter names +// TODO (frederic) see if this method needs to be added to API public char[][] getTypeParameterNames() throws JavaModelException { String[] typeParameterSignatures = getTypeParameterSignatures(); int length = typeParameterSignatures.length; Index: model/org/eclipse/jdt/internal/core/JavaProject.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java,v retrieving revision 1.324 diff -u -r1.324 JavaProject.java --- model/org/eclipse/jdt/internal/core/JavaProject.java 1 Oct 2004 14:26:42 -0000 1.324 +++ model/org/eclipse/jdt/internal/core/JavaProject.java 8 Oct 2004 12:15:54 -0000 @@ -127,7 +127,7 @@ /** * Name of file containing custom project preferences * @deprecated WARNING Visibility will be reduce to private before M9 - * If you use this variable, change your implementation to avoid future comilation error... + * If you use this variable, change your implementation to avoid future compilation error... * @see bug 59258 * TODO (frederic) set visibility from public to private */ Index: model/org/eclipse/jdt/internal/core/SourceType.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java,v retrieving revision 1.99 diff -u -r1.99 SourceType.java --- model/org/eclipse/jdt/internal/core/SourceType.java 7 Oct 2004 13:27:30 -0000 1.99 +++ model/org/eclipse/jdt/internal/core/SourceType.java 8 Oct 2004 12:15:54 -0000 @@ -407,7 +407,8 @@ return info.typeParameters; } -// SEARCH_15 Get type parameter names +// Get type parameter names +// TODO (frederic) see if this method needs to be added to API public char[][] getTypeParameterNames() throws JavaModelException { SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo(); return info.getTypeParameterNames(); Index: search/org/eclipse/jdt/core/search/SearchPattern.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java,v retrieving revision 1.20 diff -u -r1.20 SearchPattern.java --- search/org/eclipse/jdt/core/search/SearchPattern.java 6 Oct 2004 14:31:57 -0000 1.20 +++ search/org/eclipse/jdt/core/search/SearchPattern.java 8 Oct 2004 12:15:54 -0000 @@ -752,9 +752,7 @@ */ /* (non-Javadoc) * SEARCH_15 - * Modified to handle generics. - * Note that no change are done for declaration patterns as the search works well for generics - * without any additional information. + * Modified to handle generics: * 1) Field defined on parameterized types * In this case, we need to split the erasure name and type argument names. * Erasure name is used as type simple name and type argument names @@ -762,6 +760,8 @@ * 2) Generic types declaration * In this case, type arguments names are got from IType and stored * in instanciated type reference pattern. + * Note that no change was done for declaration patterns as the search works well for generics + * without any additional information. */ public static SearchPattern createPattern(IJavaElement element, int limitTo) { SearchPattern searchPattern = null; @@ -779,28 +779,51 @@ char[] typeSimpleName; char[] typeQualification; char[][] typeNames = null; + int[] wildcards = null; try { char[] typeSignature = field.getTypeSignature().toCharArray(); - // SEARCH_15 (start) char[] typeErasure = null; if (CharOperation.indexOf(Signature.C_GENERIC_START, typeSignature) == -1) { typeErasure = Signature.toCharArray(typeSignature); } else { typeErasure = Signature.toCharArray(Signature.getTypeErasure(typeSignature)); CharOperation.replace(typeErasure, '$', '.'); - if ((typeNames = Signature.getTypeArguments(typeSignature)) != null) { + try { + typeNames = Signature.getTypeArguments(typeSignature); + } + catch (IllegalArgumentException iae) { + // do nothing + } + if (typeNames != null) { int length = typeNames.length; + wildcards = new int[length]; for (int i=0; i - * 2) '*' is not treated yet inside <> - * 3) that nested <> are not treated yet - * 4) that only one type arguments definition is allowed - * (ie. Gen.Member will be treated same as - * Gen.Member pattern) - * Using regexp syntax, we can described allowed patterns as: + * + * @since 3.1 + * Type arguments can be specified to search references to parameterized types. + * Then patterns will look as follow: * [qualification.] type [ '<' [ [ '?' {'extends'|'super'} ] type ( ',' [ '?' {'extends'|'super'} ] type )* ] '>' ] + * Please note that: + * - '*' is not valid inside type arguments definition <> + * - '?' is treated as a wildcard when it is inside <> (ie. it must be put on first position of the type argument) + * - nested <> are not allowed; List> will be treated as pattern List + * - only one type arguments definition is allowed; Gen.Member + * will be treated as pattern Gen.Member */ private static SearchPattern createTypePattern(String patternString, int limitTo, int matchRule) { @@ -1185,14 +1203,14 @@ int parameterized = 0; int paramPtr = -1; char[][] paramNames = null; - int[] wildcards = new int[10]; + int[] wildcards = null; while (token != TerminalTokens.TokenNameEOF) { if (token != TerminalTokens.TokenNameWHITESPACE) { if (storeParam) { switch (token) { case TerminalTokens.TokenNameMULTIPLY: if (parameterized > 0) { - // SEARCH_15 (frederic) Not treated yet... + // TODO (frederic) Should warn user that syntax is not valid } break; case TerminalTokens.TokenNameQUESTION: @@ -1200,7 +1218,7 @@ if (wildcards[paramPtr] == -1) { wildcards[paramPtr] = Wildcard.UNBOUND; } else { - // SEARCH_15 (frederic) Invalid syntax + // TODO (frederic) Should warn user that syntax is not valid } } break; @@ -1209,7 +1227,7 @@ if (wildcards[paramPtr] == Wildcard.UNBOUND) { wildcards[paramPtr] = Wildcard.EXTENDS; } else { - // SEARCH_15 (frederic) Invalid syntax + // TODO (frederic) Should warn user that syntax is not valid } } break; @@ -1218,7 +1236,7 @@ if (wildcards[paramPtr] == Wildcard.UNBOUND) { wildcards[paramPtr] = Wildcard.SUPER; } else { - // SEARCH_15 (frederic) Invalid syntax + // TODO (frederic) Should warn user that syntax is not valid } } break; @@ -1236,6 +1254,7 @@ if (parameterized == 0) { paramNames = new char[10][]; // 10 parameters max paramPtr++; + wildcards = new int[10]; // 10 parameters max wildcards[paramPtr] = -1; storeType = false; } @@ -1340,8 +1359,7 @@ } } /** - * Returns the enclosing type names of the given type. - * TODO (frederic) Add-on for generic search + * Returns the type parameter names of the given type. */ private static char[][] typeParameterNames(IType type) { char[][] paramNames = null; Index: search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java,v retrieving revision 1.24 diff -u -r1.24 FieldLocator.java --- search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java 6 Oct 2004 12:42:55 -0000 1.24 +++ search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java 8 Oct 2004 12:15:54 -0000 @@ -30,6 +30,13 @@ this.isDeclarationOfAccessedFieldsPattern = this.pattern instanceof DeclarationOfAccessedFieldsPattern; } +/* + * Get binding of type argument from an index position. + * Delegate this search to the pattern which can cache results. + */ +protected TypeBinding getTypeNameBinding(int index) { + return ((FieldPattern) this.pattern).getTypeNameBinding(this.unitScope, index); +} //public int match(ASTNode node, MatchingNodeSet nodeSet) - SKIP IT //public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) - SKIP IT public int match(FieldDeclaration node, MatchingNodeSet nodeSet) { @@ -84,47 +91,13 @@ // look at field type only if declaring type is not specified if (fieldPattern.declaringSimpleName == null) return declaringLevel; - int typeLevel = resolveLevelForType(fieldPattern.typeSimpleName, fieldPattern.typeQualification, field.type); - - // SEARCH_15 (frederic) Specific field pattern verification for generics (not fully tested yet...) - if (typeLevel == IMPOSSIBLE_MATCH) { - return IMPOSSIBLE_MATCH; - } - TypeBinding typeBinding = field.type; - if (typeBinding != null) { - boolean isParameterized = typeBinding.isParameterizedType(); - boolean isRawType = typeBinding.isRawType(); - if (fieldPattern.typeNames== null) { - if (isParameterized && !isRawType) return IMPOSSIBLE_MATCH; - } else { - if (!isParameterized) return IMPOSSIBLE_MATCH; - ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) typeBinding; - if (paramTypeBinding.arguments == null) { - return IMPOSSIBLE_MATCH; - } - int length = fieldPattern.typeNames.length; - if (paramTypeBinding.arguments.length != length) return IMPOSSIBLE_MATCH; - for (int i= 0; i typeLevel ? typeLevel : declaringLevel; // return the weaker match } protected int matchReference(Reference node, MatchingNodeSet nodeSet, boolean writeOnlyAccess) { @@ -315,5 +288,39 @@ } } return IMPOSSIBLE_MATCH; +} +/* (non-Javadoc) + * Resolve level for type with a given binding. + */ +protected int resolveLevelForType(TypeBinding typeBinding) { + FieldPattern fieldPattern = (FieldPattern) this.pattern; + return resolveLevelForType( + fieldPattern.typeSimpleName, + fieldPattern.typeQualification, + fieldPattern.typeNames, + fieldPattern.wildcards, + ((InternalSearchPattern)this.pattern).mustResolve, + fieldPattern.declaration, + typeBinding); +} +/* (non-Javadoc) + * Overrides PatternLocator method behavior in order to accept member pattern as X.Member + * @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#resolveLevelForType(char[], char[], org.eclipse.jdt.internal.compiler.lookup.TypeBinding) + */ +protected int resolveLevelForType (char[] simpleNamePattern, char[] qualificationPattern, TypeBinding type) { + char[] qualifiedPattern = getQualifiedPattern(simpleNamePattern, qualificationPattern); + int level = resolveLevelForType(qualifiedPattern, type); + if (level == ACCURATE_MATCH || type == null) return level; + boolean match = false; + if (type.isMemberType() || type.isLocalType()) { + if (qualificationPattern != null) { + match = CharOperation.equals(qualifiedPattern, getQualifiedSourceName(type), this.isCaseSensitive); + } else { + match = CharOperation.equals(qualifiedPattern, type.sourceName(), this.isCaseSensitive); + } + } else if (qualificationPattern == null) { + match = CharOperation.equals(qualifiedPattern, getQualifiedSourceName(type), this.isCaseSensitive); + } + return match ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; } } Index: search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java,v retrieving revision 1.19 diff -u -r1.19 FieldPattern.java --- search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java 6 Oct 2004 12:42:55 -0000 1.19 +++ search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java 8 Oct 2004 12:15:54 -0000 @@ -12,6 +12,8 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.search.SearchPattern; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants; public class FieldPattern extends VariablePattern implements IIndexConstants { @@ -24,8 +26,11 @@ protected char[] typeQualification; protected char[] typeSimpleName; -// SEARCH_15 Store type names -protected char[][] typeNames; +// Additional information for generics search +protected boolean declaration; // show whether the search is based on a declaration or an instance +protected char[][] typeNames; // type arguments names storage +protected TypeBinding[] typeBindings; // cache for type arguments bindings +protected int[] wildcards; // show wildcard kind for each type arguments protected static char[][] REF_CATEGORIES = { REF }; protected static char[][] REF_AND_DECL_CATEGORIES = { REF, FIELD_DECL }; @@ -55,7 +60,9 @@ ((InternalSearchPattern)this).mustResolve = mustResolve(); } -// SEARCH_15 Create field pattern with generics additional information +/* + * Instanciate a field pattern with additional information for generics search + */ public FieldPattern( boolean findDeclarations, boolean readAccess, @@ -66,6 +73,7 @@ char[] typeQualification, char[] typeSimpleName, char[][] typeNames, + int[] wildcards, int matchRule) { this(findDeclarations, readAccess, writeAccess, name, declaringQualification, declaringSimpleName, typeQualification, typeSimpleName, matchRule); @@ -73,6 +81,7 @@ if (typeNames != null) { this.typeNames= typeNames; } + this.wildcards = wildcards; } public void decodeIndexKey(char[] key) { this.name = key; @@ -89,6 +98,25 @@ if (this.findDeclarations) return DECL_CATEGORIES; return CharOperation.NO_CHAR_CHAR; +} +/* + * Get binding of type argument from a class unit scope and its index position. + * Cache is lazy initialized and if no binding is found, then store a problem binding + * to avoid making research twice... + */ +protected TypeBinding getTypeNameBinding(CompilationUnitScope unitScope, int index) { + int length = this.typeNames.length; + if (this.typeBindings == null) this.typeBindings = new TypeBinding[length]; + if (index <0 || index > length) return null; + TypeBinding typeBinding = this.typeBindings[index]; + if (typeBinding == null) { + typeBinding = unitScope.getType(this.typeNames[index]); + this.typeBindings[index] = typeBinding; + } + if (!typeBinding.isValidBinding()) { + typeBinding = null; + } + return typeBinding; } public boolean matchesDecodedKey(SearchPattern decodedPattern) { return true; // index key is not encoded so query results all match Index: search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java,v retrieving revision 1.202 diff -u -r1.202 MatchLocator.java --- search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java 8 Oct 2004 10:09:21 -0000 1.202 +++ search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java 8 Oct 2004 12:15:54 -0000 @@ -58,8 +58,6 @@ public SearchRequestor requestor; public IJavaSearchScope scope; public IProgressMonitor progressMonitor; -// SEARCH_15 -public CompilationUnitScope unitScope; public org.eclipse.jdt.core.ICompilationUnit[] workingCopies; public HandleFactory handleFactory; @@ -1286,7 +1284,7 @@ } /** - * SEARCH_15 + * @since 3.1 * Finds the accurate positions of the sequence of tokens given by qualifiedName * in the source and reports a reference to this this qualified name * to the search requestor. @@ -1316,11 +1314,18 @@ if (token == TerminalTokens.TokenNameIdentifier && this.pattern.matchesName(name, scanner.getCurrentTokenSource())) { // extends selection end for parameterized types if necessary try { - while (token != TerminalTokens.TokenNameGREATER) { + int count = 0; + while (token != TerminalTokens.TokenNameGREATER || count > 0) { token = scanner.getNextToken(); - if (token == TerminalTokens.TokenNameEOF) { - // TODO (search-frederic) Abnormal end of file, perhaps trace something in DEBUG - return; + switch (token) { + case TerminalTokens.TokenNameLESS: + count++; + break; + case TerminalTokens.TokenNameGREATER: + count--; + break; + case TerminalTokens.TokenNameEOF: + return; } } } catch (InvalidInputException e1) { @@ -1487,15 +1492,12 @@ } /** * Visit the given resolved parse tree and report the nodes that match the search pattern. - * SEARCH_15 - * Add unit scope storage in pattern locator. This will allow some additional verification - * while resolving levels of type arguments. */ protected void reportMatching(CompilationUnitDeclaration unit, boolean mustResolve) throws CoreException { MatchingNodeSet nodeSet = this.currentPossibleMatch.nodeSet; if (mustResolve) { - this.unitScope = unit.scope.compilationUnitScope(); - this.patternLocator.unitScope = this.unitScope; + CompilationUnitScope unitScope= unit.scope.compilationUnitScope(); + this.patternLocator.unitScope = unitScope; // move the possible matching nodes that exactly match the search pattern to the matching nodes set Object[] nodes = nodeSet.possibleMatchingNodesSet.values; for (int i = 0, l = nodes.length; i < l; i++) { @@ -1516,7 +1518,6 @@ } nodeSet.possibleMatchingNodesSet = new SimpleSet(3); } else { - this.unitScope = null; this.patternLocator.unitScope = null; } Index: search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java,v retrieving revision 1.26 diff -u -r1.26 PatternLocator.java --- search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java 6 Oct 2004 10:51:17 -0000 1.26 +++ search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java 8 Oct 2004 12:15:54 -0000 @@ -22,7 +22,6 @@ protected int matchMode; protected boolean isCaseSensitive; -// SEARCH_15 protected CompilationUnitScope unitScope; /* match levels */ @@ -92,6 +91,45 @@ this.isCaseSensitive = (matchRule & SearchPattern.R_CASE_SENSITIVE) != 0; this.matchMode = matchRule - (this.isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0); } +/* (non-Javadoc) + * Modify PatternLocator.qualifiedPattern behavior: + * do not add star before simple name pattern when qualification pattern is null. + * This avoid to match p.X when pattern is only X... + */ +protected char[] getQualifiedPattern(char[] simpleNamePattern, char[] qualificationPattern) { + // NOTE: if case insensitive search then simpleNamePattern & qualificationPattern are assumed to be lowercase + if (simpleNamePattern == null) { + if (qualificationPattern == null) return null; + return CharOperation.concat(qualificationPattern, ONE_STAR, '.'); + } else if (qualificationPattern == null) { + return simpleNamePattern; + } else { + return CharOperation.concat(qualificationPattern, simpleNamePattern, '.'); + } +} +/* (non-Javadoc) + * Modify PatternLocator.qualifiedSourceName behavior: + * also concatene enclosing type name when type is a only a member type. + */ +protected char[] getQualifiedSourceName(TypeBinding binding) { + if (binding instanceof ReferenceBinding) { + ReferenceBinding type = (ReferenceBinding) binding; + if (type.isLocalType()) { + return CharOperation.concat(qualifiedSourceName(type.enclosingType()), new char[] {'.', '1', '.'}, type.sourceName()); + } else if (type.isMemberType()) { + return CharOperation.concat(qualifiedSourceName(type.enclosingType()), type.sourceName(), '.'); + } + } + return binding != null ? binding.qualifiedSourceName() : null; +} +/* + * Get binding of type argument from a class unit scope and its index position. + * Cache is lazy initialized and if no binding is found, then store a problem binding + * to avoid making research twice... + */ +protected TypeBinding getTypeNameBinding(int index) { + return null; +} /** * Initializes this search pattern so that polymorphic search can be performed. */ @@ -316,6 +354,173 @@ return CharOperation.match(qualifiedPattern, fullyQualifiedTypeName, this.isCaseSensitive) ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; +} +/* (non-Javadoc) + * Resolve level for type with a given binding with all pattern information. + */ +protected int resolveLevelForType (char[] simpleNamePattern, + char[] qualificationPattern, + char[][] typeNames, + int[] wildcards, + boolean mustResolve, + boolean declaration, + TypeBinding type) { + // standard search with no generic additional information must succeed + int level = resolveLevelForType(simpleNamePattern, qualificationPattern, type); + if (level == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH; + if (type == null) return level; + + // pattern has no type parameter, return standard result + if (typeNames == null || typeNames.length == 0) { + return level; + } + + // pattern has type parameter(s) or type argument(s) + boolean isRawType = type.isRawType(); + if (type.isGenericType()) { + // Binding is generic, get its type variable(s) + TypeVariableBinding[] typeVariables = null; + if (type instanceof SourceTypeBinding) { + SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type; + typeVariables = sourceTypeBinding.typeVariables; + } else if (type instanceof BinaryTypeBinding) { + BinaryTypeBinding binaryTypeBinding = (BinaryTypeBinding) type; + if (mustResolve) + typeVariables = binaryTypeBinding.typeVariables(); // TODO (frederic) verify performance + } + // type variables length must match at least specified type names length + if (typeVariables == null || typeVariables.length == 0) { + return IMPOSSIBLE_MATCH; + } + int length = typeNames.length; + if (typeVariables.length != length) return IMPOSSIBLE_MATCH; + // TODO (frederic) do we need to verify each parameter? + return level; // we can't do better + } else if (!type.isParameterizedType() && !isRawType) { + // Standard types (ie. neither generic nor parameterized nor raw types) + // cannot match pattern with type parameters or arguments + return IMPOSSIBLE_MATCH; + } else { + // Binding is parameterized type + ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) type; + if (paramTypeBinding.arguments == null) { + // binding has no type parameters => ok for raw types + if (isRawType) return level; + // need to verify hierarchy for member types (raw type of generic member + // are stored as parameterized types...) + if (type.isMemberType() && qualificationPattern != null) { + int lastDot = CharOperation.lastIndexOf('.', qualificationPattern); + char[] enclosingQualificationPattern = lastDot==-1 ? null : CharOperation.subarray(qualificationPattern, 0, lastDot); + char[] enclosingSimpleNamePattern = lastDot==-1 ? qualificationPattern : CharOperation.subarray(qualificationPattern, lastDot+1, qualificationPattern.length); + if (resolveLevelForType(enclosingSimpleNamePattern, enclosingQualificationPattern, typeNames, wildcards, mustResolve, declaration, paramTypeBinding.enclosingType()) == IMPOSSIBLE_MATCH) { + return IMPOSSIBLE_MATCH; + } + return level; + } + return IMPOSSIBLE_MATCH; + } + + // type parameters length must match at least specified type names length + int length = typeNames.length; + if (paramTypeBinding.arguments.length != length) return IMPOSSIBLE_MATCH; + + // for generic type declaration, verification is different than for parameterized type + if (declaration) { + // TODO (frederic) more verification to do here with type parameter bounds? + return level; + } + + // verify each pattern type parameter + nextTypeArgument: for (int i= 0; i verify that types are compatible + if (argTypeBinding == patternBinding) continue; + if (argTypeBinding.isWildcard()) { + TypeBinding bound = ((WildcardBinding) argTypeBinding).bound; + switch (patternWildcard) { + case Wildcard.SUPER: + if (bound == null || patternBinding.isCompatibleWith(bound)) + // argument type is in bound hierarchy => match + continue; + break; + case Wildcard.EXTENDS: + if (bound == null || bound.isCompatibleWith(patternBinding)) + // argument type is a subclass of bound => match + continue; + break; + default: //UNBOUND + // there's no bound name => match + continue; + } + } + return IMPOSSIBLE_MATCH; + } + + // pattern hasn't be solved, try to see if names match in hierarchy + // First if type argument is a wildcard + if (argTypeBinding.isWildcard()) { + WildcardBinding wildcardBinding = (WildcardBinding) argTypeBinding; + switch (wildcardBinding.kind) { + case Wildcard.EXTENDS: + // We cannot know in this case... + level = INACCURATE_MATCH; + case Wildcard.UNBOUND: + // there's no bound name to match => valid + continue; + } + // try to match name in hierarchy + ReferenceBinding boundBinding = (ReferenceBinding) wildcardBinding.bound; + while (boundBinding != null) { + if (CharOperation.equals(argType, boundBinding.shortReadableName(), this.isCaseSensitive) || + CharOperation.equals(argType, boundBinding.readableName(), this.isCaseSensitive)) { + // found name in hierarchy => match + continue nextTypeArgument; + } + boundBinding = boundBinding.superclass(); + } + return IMPOSSIBLE_MATCH; + } + + // try to match names when there's no wildcard + // first get real binding + ReferenceBinding refBinding = null; + if (argTypeBinding.isArrayType()) { + TypeBinding leafBinding = ((ArrayBinding) argTypeBinding).leafComponentType; + if (!leafBinding.isBaseType()) { + refBinding = (ReferenceBinding) leafBinding; + } + } else if (!argTypeBinding.isBaseType()) { + refBinding = (ReferenceBinding) argTypeBinding; + } + // Compare name + if (refBinding == null) { + // Based type + if (!CharOperation.equals(argType, argTypeBinding.shortReadableName(), this.isCaseSensitive) && + !CharOperation.equals(argType, argTypeBinding.readableName(), this.isCaseSensitive)) { + return IMPOSSIBLE_MATCH; + } + } else { + while (refBinding != null) { + if (CharOperation.equals(argType, refBinding.shortReadableName(), this.isCaseSensitive) || + CharOperation.equals(argType, refBinding.readableName(), this.isCaseSensitive)) { + // found name in hierarchy => match + continue nextTypeArgument; + } + refBinding = refBinding.superclass(); + } + return IMPOSSIBLE_MATCH; + } + } + return level; + } } public String toString(){ return "SearchPattern"; //$NON-NLS-1$ Index: search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java,v retrieving revision 1.23 diff -u -r1.23 TypeReferenceLocator.java --- search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java 6 Oct 2004 10:51:22 -0000 1.23 +++ search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java 8 Oct 2004 12:15:54 -0000 @@ -31,37 +31,6 @@ this.pattern = pattern; this.isDeclarationOfReferencedTypesPattern = this.pattern instanceof DeclarationOfReferencedTypesPattern; } -/* SEARCH_15 - * Modify PatternLocator.qualifiedPattern behavior: - * do not add star before simple name pattern when qualification pattern is null. - * This avoid to match p.X when pattern is X... - */ -public static char[] qualifiedPattern(char[] simpleNamePattern, char[] qualificationPattern) { - // NOTE: if case insensitive search then simpleNamePattern & qualificationPattern are assumed to be lowercase - if (simpleNamePattern == null) { - if (qualificationPattern == null) return null; - return CharOperation.concat(qualificationPattern, ONE_STAR, '.'); - } else if (qualificationPattern == null) { - return simpleNamePattern; - } else { - return CharOperation.concat(qualificationPattern, simpleNamePattern, '.'); - } -} -/* SEARCH_15 - * Modify PatternLocator.qualifiedSourceName behavior: - * concat enclosing type when type is a only a member type. - */ -public static char[] qualifiedSourceName(TypeBinding binding) { - if (binding instanceof ReferenceBinding) { - ReferenceBinding type = (ReferenceBinding) binding; - if (type.isLocalType()) { - return CharOperation.concat(qualifiedSourceName(type.enclosingType()), new char[] {'.', '1', '.'}, type.sourceName()); - } else if (type.isMemberType()) { - return CharOperation.concat(qualifiedSourceName(type.enclosingType()), type.sourceName(), '.'); - } - } - return binding != null ? binding.qualifiedSourceName() : null; -} protected IJavaElement findElement(IJavaElement element, int accuracy) { // need exact match to be able to open on type ref if (accuracy != SearchMatch.A_ACCURATE) return null; @@ -72,6 +41,13 @@ element = element.getParent(); return element; } +/* + * Get binding of type argument from an index position. + * Delegate this search to the pattern which can cache results. + */ +protected TypeBinding getTypeNameBinding(int index) { + return this.pattern.getTypeNameBinding(this.unitScope, index); +} public int match(ASTNode node, MatchingNodeSet nodeSet) { // interested in ImportReference if (!(node instanceof ImportReference)) return IMPOSSIBLE_MATCH; @@ -144,7 +120,7 @@ } protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException { if (this.pattern.shouldExtendSelection()) { - // SEARCH_15 do not report import ref for generic patterns... + // do not report import ref for generic patterns... return; } if (this.isDeclarationOfReferencedTypesPattern) { @@ -193,7 +169,7 @@ locator.report(match); } } else if (this.pattern.shouldExtendSelection() && arrayRef.resolvedType.isParameterizedType() && ((ParameterizedTypeBinding)arrayRef.resolvedType).arguments != null) { - // SEARCH_15 specific report accurate match for parameterized types + // specific report accurate match for parameterized types locator.reportAccurateParameterizedTypeReference(arrayRef, this.pattern.simpleName, element, accuracy); } else locator.reportAccurateTypeReference(arrayRef, this.pattern.simpleName, element, accuracy); @@ -287,7 +263,7 @@ int start = (int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32); int end = (int) positions[lastIndex]; if (this.pattern.shouldExtendSelection() && refBinding.isParameterizedType() && ((ParameterizedTypeBinding)refBinding).arguments != null) { - // SEARCH_15 specific report accurate match for parameterized types + // specific report accurate match for parameterized types locator.reportAccurateParameterizedTypeReference(qTypeRef, this.pattern.simpleName, element, accuracy); } else { SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, start, end-start+1, qTypeRef); @@ -480,7 +456,6 @@ return resolveLevelForTypeOrEnclosingTypes(this.pattern.simpleName, this.pattern.qualification, typeBinding); } /* (non-Javadoc) - * SEARCH_15 * Resolve level for type with a given binding. * This is just an helper to avoid call of method with all parameters... */ @@ -489,189 +464,30 @@ this.pattern.simpleName, this.pattern.qualification, this.pattern.typeNames, + this.pattern.wildcards, ((InternalSearchPattern)this.pattern).mustResolve, this.pattern.declaration, typeBinding); } /* (non-Javadoc) - * SEARCH_15 * Overrides PatternLocator method behavior in order to accept member pattern as X.Member * @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#resolveLevelForType(char[], char[], org.eclipse.jdt.internal.compiler.lookup.TypeBinding) */ protected int resolveLevelForType (char[] simpleNamePattern, char[] qualificationPattern, TypeBinding type) { - char[] qualifiedPattern = qualifiedPattern(simpleNamePattern, qualificationPattern); + char[] qualifiedPattern = getQualifiedPattern(simpleNamePattern, qualificationPattern); int level = resolveLevelForType(qualifiedPattern, type); if (level == ACCURATE_MATCH || type == null) return level; boolean match = false; if (type.isMemberType() || type.isLocalType()) { if (qualificationPattern != null) { - match = CharOperation.equals(qualifiedPattern, qualifiedSourceName(type), this.isCaseSensitive); + match = CharOperation.equals(qualifiedPattern, getQualifiedSourceName(type), this.isCaseSensitive); } else { match = CharOperation.equals(qualifiedPattern, type.sourceName(), this.isCaseSensitive); } } else if (qualificationPattern == null) { - match = CharOperation.equals(qualifiedPattern, qualifiedSourceName(type), this.isCaseSensitive); + match = CharOperation.equals(qualifiedPattern, getQualifiedSourceName(type), this.isCaseSensitive); } return match ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; -} -/* (non-Javadoc) - * SEARCH_15 - * Resolve level for type with a given binding with all pattern information. - */ -protected int resolveLevelForType (char[] simpleNamePattern, - char[] qualificationPattern, - char[][] typeNames, - boolean mustResolve, - boolean declaration, - TypeBinding type) { - int level = resolveLevelForType(simpleNamePattern, qualificationPattern, type); - if (level == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH; - if (type == null) return level; - - // pattern has no type parameter - if (typeNames == null || typeNames.length == 0) { - return level; - } - - // pattern has type parameter(s) or type argument(s) - boolean isRawType = type.isRawType(); - if (type.isGenericType()) { - // Binding is generic, get its type variable(s) - TypeVariableBinding[] typeVariables = null; - if (type instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type; - typeVariables = sourceTypeBinding.typeVariables; - } else if (type instanceof BinaryTypeBinding) { - BinaryTypeBinding binaryTypeBinding = (BinaryTypeBinding) type; - if (mustResolve) - typeVariables = binaryTypeBinding.typeVariables(); // TODO (frederic) do we really want to resolve? - } - // type variables length must match at least specified type names length - if (typeVariables == null || typeVariables.length == 0) { - return IMPOSSIBLE_MATCH; - } - int length = typeNames.length; - if (typeVariables.length != length) return IMPOSSIBLE_MATCH; - // verify each parameters - return level; // we can't do better - // TODO (frederic) need to do more verifications here? - } else if (!type.isParameterizedType() && !isRawType) { - // Standard types (ie. neither generic nor parameterized nor raw types) - // cannot match pattern when it has type parameters or arguments - return IMPOSSIBLE_MATCH; - } else { - // Binding is parameterized type - ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) type; - if (paramTypeBinding.arguments == null) { - // binding has no type parameters => ok for raw types - if (isRawType) return level; - // need to verify hierarchy for member types - if (type.isMemberType() && qualificationPattern != null) { - int lastDot = CharOperation.lastIndexOf('.', qualificationPattern); - char[] enclosingQualificationPattern = lastDot==-1 ? null : CharOperation.subarray(qualificationPattern, 0, lastDot); - char[] enclosingSimpleNamePattern = lastDot==-1 ? qualificationPattern : CharOperation.subarray(qualificationPattern, lastDot+1, qualificationPattern.length); - if (resolveLevelForType(enclosingSimpleNamePattern, enclosingQualificationPattern, typeNames, mustResolve, declaration, paramTypeBinding.enclosingType()) == IMPOSSIBLE_MATCH) { - return IMPOSSIBLE_MATCH; - } - return level; - } - return IMPOSSIBLE_MATCH; - } - // type parameters length must match at least specified type names length - int length = typeNames.length; - if (paramTypeBinding.arguments.length != length) return IMPOSSIBLE_MATCH; - // verify each type parameter - if (declaration) { - // TODO (frederic) more verification to do here with type parameter bounds? - return level; - } - nextTypeArgument: for (int i= 0; i verify that types are compatible - if (argTypeBinding == patternBinding) continue; - if (argTypeBinding.isWildcard()) { - TypeBinding bound = ((WildcardBinding) argTypeBinding).bound; - if (this.pattern.wildcards != null) { - switch (this.pattern.wildcards[i]) { - case Wildcard.SUPER: - if (bound == null || patternBinding.isCompatibleWith(bound)) - // argument type is in bound hierarchy => valid - continue; - break; - case Wildcard.EXTENDS: - if (bound == null || bound.isCompatibleWith(patternBinding)) - // argument type is a subclass of bound => valid - continue; - break; - default: //UNBOUND - // there's no bound name to match => valid - continue; - } - } - } - return IMPOSSIBLE_MATCH; - } - - // pattern hasn't be solved, try to see if names match in hierarchy - // First if type argument is a wildcard - if (argTypeBinding.isWildcard()) { - WildcardBinding wildcardBinding = (WildcardBinding) argTypeBinding; - switch (wildcardBinding.kind) { - case Wildcard.EXTENDS: - // We cannot know in this case... - level = INACCURATE_MATCH; - case Wildcard.UNBOUND: - // there's no bound name to match => valid - continue; - } - // try to match name in hierarchy - ReferenceBinding boundBinding = (ReferenceBinding) wildcardBinding.bound; - while (boundBinding != null) { - if (CharOperation.equals(argType, boundBinding.shortReadableName(), this.isCaseSensitive) || - CharOperation.equals(argType, boundBinding.readableName(), this.isCaseSensitive)) { - continue nextTypeArgument; - } - boundBinding = boundBinding.superclass(); - } - return IMPOSSIBLE_MATCH; - } - - // try to match names when there's no wildcard - ReferenceBinding refBinding = null; - if (argTypeBinding.isArrayType()) { - TypeBinding leafBinding = ((ArrayBinding) argTypeBinding).leafComponentType; - if (!leafBinding.isBaseType()) { - refBinding = (ReferenceBinding) leafBinding; - } - } else if (!argTypeBinding.isBaseType()) { - refBinding = (ReferenceBinding) argTypeBinding; - } - if (refBinding == null) { - // Based type - if (!CharOperation.equals(argType, argTypeBinding.shortReadableName(), this.isCaseSensitive) && - !CharOperation.equals(argType, argTypeBinding.readableName(), this.isCaseSensitive)) { - return IMPOSSIBLE_MATCH; - } - } else { - while (refBinding != null) { - if (CharOperation.equals(argType, refBinding.shortReadableName(), this.isCaseSensitive) || - CharOperation.equals(argType, refBinding.readableName(), this.isCaseSensitive)) { - continue nextTypeArgument; - } - refBinding = refBinding.superclass(); - } - return IMPOSSIBLE_MATCH; - } - } - return level; - } } /** * Returns whether the given type binding or one of its enclosing types Index: search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java =================================================================== RCS file: /data/cvs/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java,v retrieving revision 1.64 diff -u -r1.64 TypeReferencePattern.java --- search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java 6 Oct 2004 10:51:17 -0000 1.64 +++ search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java 8 Oct 2004 12:15:54 -0000 @@ -13,8 +13,6 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants; @@ -23,7 +21,7 @@ protected char[] qualification; protected char[] simpleName; -// SEARCH_15 Additional information for generics search +// Additional information for generics search protected boolean declaration; // show whether the search is based on a declaration or an instance protected char[][] typeNames; // type arguments names storage protected TypeBinding[] typeBindings; // cache for type arguments bindings @@ -50,7 +48,9 @@ ((InternalSearchPattern)this).mustResolve = true; // always resolve (in case of a simple name reference being a potential match) } -// SEARCH_15 Instanciate a type reference pattern with additional information for generics search +/* + * Instanciate a type reference pattern with additional information for generics search + */ public TypeReferencePattern(char[] qualification, char[] simpleName, char[][] typeNames, boolean fromJavaElement, int[] wildcards, int matchRule) { this(qualification, simpleName,matchRule); @@ -94,12 +94,9 @@ TypeBinding typeBinding = this.typeBindings[index]; if (typeBinding == null) { typeBinding = unitScope.getType(this.typeNames[index]); - if (typeBinding == null) { - this.typeBindings[index] = new ProblemReferenceBinding(this.typeNames[index], ProblemReasons.NotFound); - } else { - this.typeBindings[index] = typeBinding; - } - } else if (!typeBinding.isValidBinding()) { + this.typeBindings[index] = typeBinding; + } + if (!typeBinding.isValidBinding()) { typeBinding = null; } return typeBinding;