1 11 12 package org.eclipse.jdt.internal.corext.util; 13 14 import java.util.HashMap ; 15 import java.util.Map ; 16 17 import org.eclipse.core.runtime.Assert; 18 19 import org.eclipse.jdt.core.Flags; 20 import org.eclipse.jdt.core.IMember; 21 import org.eclipse.jdt.core.IMethod; 22 import org.eclipse.jdt.core.IType; 23 import org.eclipse.jdt.core.ITypeHierarchy; 24 import org.eclipse.jdt.core.ITypeParameter; 25 import org.eclipse.jdt.core.JavaModelException; 26 import org.eclipse.jdt.core.Signature; 27 28 29 public class MethodOverrideTester { 30 private static class Substitutions { 31 32 public static final Substitutions EMPTY_SUBST= new Substitutions(); 33 34 private HashMap fMap; 35 36 public Substitutions() { 37 fMap= null; 38 } 39 40 public void addSubstitution(String typeVariable, String substitution, String erasure) { 41 if (fMap == null) { 42 fMap= new HashMap (3); 43 } 44 fMap.put(typeVariable, new String [] { substitution, erasure }); 45 } 46 47 private String [] getSubstArray(String typeVariable) { 48 if (fMap != null) { 49 return (String []) fMap.get(typeVariable); 50 } 51 return null; 52 } 53 54 public String getSubstitution(String typeVariable) { 55 String [] subst= getSubstArray(typeVariable); 56 if (subst != null) { 57 return subst[0]; 58 } 59 return null; 60 } 61 62 public String getErasure(String typeVariable) { 63 String [] subst= getSubstArray(typeVariable); 64 if (subst != null) { 65 return subst[1]; 66 } 67 return null; 68 } 69 } 70 71 private final IType fFocusType; 72 private final ITypeHierarchy fHierarchy; 73 74 private Map fMethodSubstitutions; 75 private Map fTypeVariableSubstitutions; 76 77 public MethodOverrideTester(IType focusType, ITypeHierarchy hierarchy) { 78 if (focusType == null || hierarchy == null) { 79 throw new IllegalArgumentException (); 80 } 81 fFocusType= focusType; 82 fHierarchy= hierarchy; 83 fTypeVariableSubstitutions= null; 84 fMethodSubstitutions= null; 85 } 86 87 public IType getFocusType() { 88 return fFocusType; 89 } 90 91 public ITypeHierarchy getTypeHierarchy() { 92 return fHierarchy; 93 } 94 95 102 public IMethod findDeclaringMethod(IMethod overriding, boolean testVisibility) throws JavaModelException { 103 IMethod result= null; 104 IMethod overridden= findOverriddenMethod(overriding, testVisibility); 105 while (overridden != null) { 106 result= overridden; 107 overridden= findOverriddenMethod(result, testVisibility); 108 } 109 return result; 110 } 111 112 118 public IMethod findOverriddenMethod(IMethod overriding, boolean testVisibility) throws JavaModelException { 119 int flags= overriding.getFlags(); 120 if (Flags.isPrivate(flags) || Flags.isStatic(flags) || overriding.isConstructor()) { 121 return null; 122 } 123 124 IType type= overriding.getDeclaringType(); 125 IType superClass= fHierarchy.getSuperclass(type); 126 if (superClass != null) { 127 IMethod res= findOverriddenMethodInHierarchy(superClass, overriding); 128 if (res != null && !Flags.isPrivate(res.getFlags())) { 129 if (!testVisibility || JavaModelUtil.isVisibleInHierarchy(res, type.getPackageFragment())) { 130 return res; 131 } 132 } 133 } 134 if (!overriding.isConstructor()) { 135 IType[] interfaces= fHierarchy.getSuperInterfaces(type); 136 for (int i= 0; i < interfaces.length; i++) { 137 IMethod res= findOverriddenMethodInHierarchy(interfaces[i], overriding); 138 if (res != null) { 139 return res; } 141 } 142 } 143 return null; 144 } 145 146 154 public IMethod findOverriddenMethodInHierarchy(IType type, IMethod overriding) throws JavaModelException { 155 IMethod method= findOverriddenMethodInType(type, overriding); 156 if (method != null) { 157 return method; 158 } 159 IType superClass= fHierarchy.getSuperclass(type); 160 if (superClass != null) { 161 IMethod res= findOverriddenMethodInHierarchy(superClass, overriding); 162 if (res != null) { 163 return res; 164 } 165 } 166 if (!overriding.isConstructor()) { 167 IType[] superInterfaces= fHierarchy.getSuperInterfaces(type); 168 for (int i= 0; i < superInterfaces.length; i++) { 169 IMethod res= findOverriddenMethodInHierarchy(superInterfaces[i], overriding); 170 if (res != null) { 171 return res; 172 } 173 } 174 } 175 return method; 176 } 177 178 186 public IMethod findOverriddenMethodInType(IType overriddenType, IMethod overriding) throws JavaModelException { 187 IMethod[] overriddenMethods= overriddenType.getMethods(); 188 for (int i= 0; i < overriddenMethods.length; i++) { 189 if (isSubsignature(overriding, overriddenMethods[i])) { 190 return overriddenMethods[i]; 191 } 192 } 193 return null; 194 } 195 196 203 public IMethod findOverridingMethodInType(IType overridingType, IMethod overridden) throws JavaModelException { 204 IMethod[] overridingMethods= overridingType.getMethods(); 205 for (int i= 0; i < overridingMethods.length; i++) { 206 if (isSubsignature(overridingMethods[i], overridden)) { 207 return overridingMethods[i]; 208 } 209 } 210 return null; 211 } 212 213 223 public boolean isSubsignature(IMethod overriding, IMethod overridden) throws JavaModelException { 224 if (!overridden.getElementName().equals(overriding.getElementName())) { 225 return false; 226 } 227 int nParameters= overridden.getNumberOfParameters(); 228 if (nParameters != overriding.getNumberOfParameters()) { 229 return false; 230 } 231 232 if (!hasCompatibleTypeParameters(overriding, overridden)) { 233 return false; 234 } 235 236 return nParameters == 0 || hasCompatibleParameterTypes(overriding, overridden); 237 } 238 239 private boolean hasCompatibleTypeParameters(IMethod overriding, IMethod overridden) throws JavaModelException { 240 ITypeParameter[] overriddenTypeParameters= overridden.getTypeParameters(); 241 ITypeParameter[] overridingTypeParameters= overriding.getTypeParameters(); 242 int nOverridingTypeParameters= overridingTypeParameters.length; 243 if (overriddenTypeParameters.length != nOverridingTypeParameters) { 244 return nOverridingTypeParameters == 0; 245 } 246 Substitutions overriddenSubst= getMethodSubstitions(overridden); 247 Substitutions overridingSubst= getMethodSubstitions(overriding); 248 for (int i= 0; i < nOverridingTypeParameters; i++) { 249 String erasure1= overriddenSubst.getErasure(overriddenTypeParameters[i].getElementName()); 250 String erasure2= overridingSubst.getErasure(overridingTypeParameters[i].getElementName()); 251 if (erasure1 == null || !erasure1.equals(erasure2)) { 252 return false; 253 } 254 int nBounds= overriddenTypeParameters[i].getBounds().length; 256 if (nBounds > 1 && nBounds != overridingTypeParameters[i].getBounds().length) { 257 return false; 258 } 259 } 260 return true; 261 } 262 263 private boolean hasCompatibleParameterTypes(IMethod overriding, IMethod overridden) throws JavaModelException { 264 String [] overriddenParamTypes= overridden.getParameterTypes(); 265 String [] overridingParamTypes= overriding.getParameterTypes(); 266 267 String [] substitutedOverriding= new String [overridingParamTypes.length]; 268 boolean testErasure= false; 269 270 for (int i= 0; i < overridingParamTypes.length; i++) { 271 String overriddenParamSig= overriddenParamTypes[i]; 272 String overriddenParamName= getSubstitutedTypeName(overriddenParamSig, overridden); 273 String overridingParamName= getSubstitutedTypeName(overridingParamTypes[i], overriding); 274 substitutedOverriding[i]= overridingParamName; 275 if (!overriddenParamName.equals(overridingParamName)) { 276 testErasure= true; 277 break; 278 } 279 } 280 if (testErasure) { 281 for (int i= 0; i < overridingParamTypes.length; i++) { 282 String overriddenParamSig= overriddenParamTypes[i]; 283 String overriddenParamName= getErasedTypeName(overriddenParamSig, overridden); 284 String overridingParamName= substitutedOverriding[i]; 285 if (overridingParamName == null) 286 overridingParamName= getSubstitutedTypeName(overridingParamTypes[i], overriding); 287 if (!overriddenParamName.equals(overridingParamName)) { 288 return false; 289 } 290 } 291 } 292 return true; 293 } 294 295 private String getVariableSubstitution(IMember context, String variableName) throws JavaModelException { 296 IType type; 297 if (context instanceof IMethod) { 298 String subst= getMethodSubstitions((IMethod) context).getSubstitution(variableName); 299 if (subst != null) { 300 return subst; 301 } 302 type= context.getDeclaringType(); 303 } else { 304 type= (IType) context; 305 } 306 String subst= getTypeSubstitions(type).getSubstitution(variableName); 307 if (subst != null) { 308 return subst; 309 } 310 return variableName; } 312 313 private String getVariableErasure(IMember context, String variableName) throws JavaModelException { 314 IType type; 315 if (context instanceof IMethod) { 316 String subst= getMethodSubstitions((IMethod) context).getErasure(variableName); 317 if (subst != null) { 318 return subst; 319 } 320 type= context.getDeclaringType(); 321 } else { 322 type= (IType) context; 323 } 324 String subst= getTypeSubstitions(type).getErasure(variableName); 325 if (subst != null) { 326 return subst; 327 } 328 return variableName; } 330 331 334 private Substitutions getMethodSubstitions(IMethod method) throws JavaModelException { 335 if (fMethodSubstitutions == null) { 336 fMethodSubstitutions= new LRUMap(3); 337 } 338 339 Substitutions s= (Substitutions) fMethodSubstitutions.get(method); 340 if (s == null) { 341 ITypeParameter[] typeParameters= method.getTypeParameters(); 342 if (typeParameters.length == 0) { 343 s= Substitutions.EMPTY_SUBST; 344 } else { 345 IType instantiatedType= method.getDeclaringType(); 346 s= new Substitutions(); 347 for (int i= 0; i < typeParameters.length; i++) { 348 ITypeParameter curr= typeParameters[i]; 349 s.addSubstitution(curr.getElementName(), '+' + String.valueOf(i), getTypeParameterErasure(curr, instantiatedType)); 350 } 351 } 352 fMethodSubstitutions.put(method, s); 353 } 354 return s; 355 } 356 357 360 private Substitutions getTypeSubstitions(IType type) throws JavaModelException { 361 if (fTypeVariableSubstitutions == null) { 362 fTypeVariableSubstitutions= new HashMap (); 363 computeSubstitutions(fFocusType, null, null); 364 } 365 Substitutions subst= (Substitutions) fTypeVariableSubstitutions.get(type); 366 if (subst == null) { 367 return Substitutions.EMPTY_SUBST; 368 } 369 return subst; 370 } 371 372 private void computeSubstitutions(IType instantiatedType, IType instantiatingType, String [] typeArguments) throws JavaModelException { 373 Substitutions s= new Substitutions(); 374 fTypeVariableSubstitutions.put(instantiatedType, s); 375 376 ITypeParameter[] typeParameters= instantiatedType.getTypeParameters(); 377 378 if (instantiatingType == null) { for (int i= 0; i < typeParameters.length; i++) { 380 ITypeParameter curr= typeParameters[i]; 381 s.addSubstitution(curr.getElementName(), '*' + curr.getElementName(), getTypeParameterErasure(curr, instantiatedType)); 383 } 384 } else { 385 if (typeParameters.length == typeArguments.length) { 386 for (int i= 0; i < typeParameters.length; i++) { 387 ITypeParameter curr= typeParameters[i]; 388 String substString= getSubstitutedTypeName(typeArguments[i], instantiatingType); String erasure= getErasedTypeName(typeArguments[i], instantiatingType); s.addSubstitution(curr.getElementName(), substString, erasure); 391 } 392 } else if (typeArguments.length == 0) { for (int i= 0; i < typeParameters.length; i++) { 394 ITypeParameter curr= typeParameters[i]; 395 String erasure= getTypeParameterErasure(curr, instantiatedType); 396 s.addSubstitution(curr.getElementName(), erasure, erasure); 397 } 398 } else { 399 } 401 } 402 String superclassTypeSignature= instantiatedType.getSuperclassTypeSignature(); 403 if (superclassTypeSignature != null) { 404 String [] superTypeArguments= Signature.getTypeArguments(superclassTypeSignature); 405 IType superclass= fHierarchy.getSuperclass(instantiatedType); 406 if (superclass != null && !fTypeVariableSubstitutions.containsKey(superclass)) { 407 computeSubstitutions(superclass, instantiatedType, superTypeArguments); 408 } 409 } 410 String [] superInterfacesTypeSignature= instantiatedType.getSuperInterfaceTypeSignatures(); 411 int nInterfaces= superInterfacesTypeSignature.length; 412 if (nInterfaces > 0) { 413 IType[] superInterfaces= fHierarchy.getSuperInterfaces(instantiatedType); 414 if (superInterfaces.length == nInterfaces) { 415 for (int i= 0; i < nInterfaces; i++) { 416 String [] superTypeArguments= Signature.getTypeArguments(superInterfacesTypeSignature[i]); 417 IType superInterface= superInterfaces[i]; 418 if (!fTypeVariableSubstitutions.containsKey(superInterface)) { 419 computeSubstitutions(superInterface, instantiatedType, superTypeArguments); 420 } 421 } 422 } 423 } 424 } 425 426 private String getTypeParameterErasure(ITypeParameter typeParameter, IType context) throws JavaModelException { 427 String [] bounds= typeParameter.getBounds(); 428 if (bounds.length > 0) { 429 return getSubstitutedTypeName(Signature.createTypeSignature(bounds[0], false), context); 430 } 431 return "Object"; } 433 434 435 443 private String getSubstitutedTypeName(String typeSig, IMember context) throws JavaModelException { 444 return internalGetSubstitutedTypeName(typeSig, context, false, new StringBuffer ()).toString(); 445 } 446 447 private String getErasedTypeName(String typeSig, IMember context) throws JavaModelException { 448 return internalGetSubstitutedTypeName(typeSig, context, true, new StringBuffer ()).toString(); 449 } 450 451 private StringBuffer internalGetSubstitutedTypeName(String typeSig, IMember context, boolean erasure, StringBuffer buf) throws JavaModelException { 452 int sigKind= Signature.getTypeSignatureKind(typeSig); 453 switch (sigKind) { 454 case Signature.BASE_TYPE_SIGNATURE: 455 return buf.append(Signature.toString(typeSig)); 456 case Signature.ARRAY_TYPE_SIGNATURE: 457 internalGetSubstitutedTypeName(Signature.getElementType(typeSig), context, erasure, buf); 458 for (int i= Signature.getArrayCount(typeSig); i > 0; i--) { 459 buf.append('[').append(']'); 460 } 461 return buf; 462 case Signature.CLASS_TYPE_SIGNATURE: { 463 String erasureSig= Signature.getTypeErasure(typeSig); 464 String erasureName= Signature.getSimpleName(Signature.toString(erasureSig)); 465 466 char ch= erasureSig.charAt(0); 467 if (ch == Signature.C_RESOLVED) { 468 buf.append(erasureName); 469 } else if (ch == Signature.C_UNRESOLVED) { if (erasure) { 471 buf.append(getVariableErasure(context, erasureName)); 472 } else { 473 buf.append(getVariableSubstitution(context, erasureName)); 474 } 475 } else { 476 Assert.isTrue(false, "Unknown class type signature"); } 478 if (!erasure) { 479 String [] typeArguments= Signature.getTypeArguments(typeSig); 480 if (typeArguments.length > 0) { 481 buf.append('<'); 482 for (int i= 0; i < typeArguments.length; i++) { 483 if (i > 0) { 484 buf.append(','); 485 } 486 internalGetSubstitutedTypeName(typeArguments[i], context, erasure, buf); 487 } 488 buf.append('>'); 489 } 490 } 491 return buf; 492 } 493 case Signature.TYPE_VARIABLE_SIGNATURE: 494 String varName= Signature.toString(typeSig); 495 if (erasure) { 496 return buf.append(getVariableErasure(context, varName)); 497 } else { 498 return buf.append(getVariableSubstitution(context, varName)); 499 } 500 case Signature.WILDCARD_TYPE_SIGNATURE: { 501 buf.append('?'); 502 char ch= typeSig.charAt(0); 503 if (ch == Signature.C_STAR) { 504 return buf; 505 } else if (ch == Signature.C_EXTENDS) { 506 buf.append(" extends "); } else { 508 buf.append(" super "); } 510 return internalGetSubstitutedTypeName(typeSig.substring(1), context, erasure, buf); 511 } 512 case Signature.CAPTURE_TYPE_SIGNATURE: 513 return internalGetSubstitutedTypeName(typeSig.substring(1), context, erasure, buf); 514 default: 515 Assert.isTrue(false, "Unhandled type signature kind"); return buf; 517 } 518 } 519 520 } 521 | Popular Tags |