OLD | NEW |
(Empty) | |
| 1 /* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved |
| 2 * |
| 3 * This program is distributed under the terms of |
| 4 * the GNU General Public License Version 2. See the LICENSE file |
| 5 * at the top of the source tree. |
| 6 */ |
| 7 package org.pantsbuild.jmake; |
| 8 |
| 9 import java.lang.reflect.Modifier; |
| 10 import java.util.LinkedHashSet; |
| 11 import java.util.Set; |
| 12 |
| 13 /** |
| 14 * This class implements finding classes referencing other classes and members i
n various ways. |
| 15 * |
| 16 * @author Misha Dmitriev |
| 17 * 12 March 2004 |
| 18 */ |
| 19 public class RefClassFinder { |
| 20 |
| 21 private boolean failOnDependentJar; // If true, will fail if a dependency
of a sourceless class |
| 22 // (coming from a .jar) on a "normal" class is detected |
| 23 private boolean noWarnOnDependentJar; // If true, not even a warning will be
issued in the above case. |
| 24 private String checkedClassName; |
| 25 private PCDManager pcdm; |
| 26 private Set<String> affectedClassNames; |
| 27 private boolean checkedClassIsFromJar; |
| 28 |
| 29 /** An instance of RefClassFinder is created once per session, passing it th
e global options that do not change */ |
| 30 public RefClassFinder(PCDManager pcdm, boolean failOnDependentJar, boolean n
oWarnOnDependentJar) { |
| 31 this.pcdm = pcdm; |
| 32 this.failOnDependentJar = failOnDependentJar; |
| 33 this.noWarnOnDependentJar = noWarnOnDependentJar; |
| 34 } |
| 35 |
| 36 /** This method is called every time we are going to check a new class */ |
| 37 public void initialize(String checkedClassName, boolean checkedClassIsFromJa
r) { |
| 38 this.checkedClassName = checkedClassName; |
| 39 this.checkedClassIsFromJar = checkedClassIsFromJar; |
| 40 affectedClassNames = new LinkedHashSet<String>(); |
| 41 } |
| 42 |
| 43 /** |
| 44 * Returns the names of project classes that were found potentially affec |
| 45 * by the changes to the checked class. |
| 46 */ |
| 47 public String[] getAffectedClassNames() { |
| 48 int size = affectedClassNames.size(); |
| 49 if (size == 0) { |
| 50 return null; |
| 51 } else { |
| 52 String[] ret = new String[size]; |
| 53 int i = 0; |
| 54 for (String className : affectedClassNames) { |
| 55 ret[i++] = className; |
| 56 } |
| 57 return ret; |
| 58 } |
| 59 } |
| 60 |
| 61 /** |
| 62 * Find all project classes that can access field fieldNo of class fieldClas
sInfo. |
| 63 * Used if a compile-time constant is changed. |
| 64 */ |
| 65 public void findAllProjectClasses(ClassInfo fieldClassInfo, int fieldNo) { |
| 66 for (PCDEntry pcde : pcdm.entries()) { |
| 67 if (pcde.checkResult == PCDEntry.CV_DELETED) { |
| 68 continue; |
| 69 } |
| 70 if (pcde.javaFileFullPath.endsWith(".jar")) { |
| 71 continue; |
| 72 } |
| 73 ClassInfo clientInfo = |
| 74 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 75 if (clientInfo == null) { |
| 76 continue; // New class |
| 77 } |
| 78 if (memberAccessibleFrom(fieldClassInfo, fieldNo, clientInfo, true))
{ |
| 79 addToAffectedClassNames(clientInfo.name); |
| 80 } |
| 81 } |
| 82 } |
| 83 |
| 84 /** |
| 85 * Find all project classes that reference class with the given name |
| 86 * (but not its array class) directly from the constantpool. |
| 87 */ |
| 88 public void findReferencingClasses0(ClassInfo classInfo) { |
| 89 findReferencingClasses(classInfo, 0, false, null); |
| 90 } |
| 91 |
| 92 |
| 93 /* In the following "find...ReferencingClasses1" methods, "referencing C" me
ans |
| 94 * "referencing C or its array class directly from the constant pool, as a t
ype of a data |
| 95 * field, as a type in a method signature or a thrown exception, as a direct
ly implemented |
| 96 * interface or a direct superclass". |
| 97 */ |
| 98 /** Used for deleted classes. */ |
| 99 public void findReferencingClassesForDeletedClass(ClassInfo classInfo) { |
| 100 String packageName = classInfo.packageName; |
| 101 boolean isPublic = classInfo.isPublic(); |
| 102 boolean isInterface = classInfo.isInterface(); |
| 103 for (PCDEntry pcde : pcdm.entries()) { |
| 104 ClassInfo clientInfo = |
| 105 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 106 if (clientInfo == null) { |
| 107 continue; // New class |
| 108 } |
| 109 if (!isPublic && packageName.equals(clientInfo.packageName)) { |
| 110 continue; |
| 111 } |
| 112 if (clientInfo.referencesClass(classInfo.name, isInterface, 1)) { |
| 113 addToAffectedClassNames(clientInfo.name); |
| 114 } |
| 115 } |
| 116 |
| 117 } |
| 118 |
| 119 /** |
| 120 * For the given class p.C, find each project class X referencing C, that is
not a member of |
| 121 * package p and is not a direct or indirect subclass of C's directly enclos
ing class. |
| 122 * (public -> protected transformation) |
| 123 */ |
| 124 public void findDiffPackageAndNotSubReferencingClasses1(ClassInfo classInfo)
{ |
| 125 String packageName = classInfo.packageName; |
| 126 String directlyEnclosingClass = classInfo.directlyEnclosingClass; |
| 127 for (PCDEntry pcde : pcdm.entries()) { |
| 128 ClassInfo clientInfo = |
| 129 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 130 if (clientInfo == null) { |
| 131 continue; // New class |
| 132 } |
| 133 if (packageName.equals(clientInfo.packageName) || |
| 134 clientInfo.isSubclassOf(directlyEnclosingClass, false)) { |
| 135 continue; |
| 136 } |
| 137 if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface
(), 1)) { |
| 138 addToAffectedClassNames(clientInfo.name); |
| 139 } |
| 140 } |
| 141 } |
| 142 |
| 143 /** |
| 144 * For class p.C, find each project class X referencing C, whose top level e
nclosing |
| 145 * class is different from that of C. |
| 146 * (public -> private transformation) |
| 147 */ |
| 148 public void findReferencingClasses1(ClassInfo classInfo) { |
| 149 String topLevelEnclosingClass = classInfo.topLevelEnclosingClass; |
| 150 for (PCDEntry pcde : pcdm.entries()) { |
| 151 ClassInfo clientInfo = |
| 152 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 153 if (clientInfo == null) { |
| 154 continue; // New class |
| 155 } |
| 156 if (topLevelEnclosingClass.equals(clientInfo.topLevelEnclosingClass)
) { |
| 157 continue; |
| 158 } |
| 159 if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface
(), 1)) { |
| 160 addToAffectedClassNames(clientInfo.name); |
| 161 } |
| 162 } |
| 163 } |
| 164 |
| 165 /** |
| 166 * For class p.C, find each project class X referencing C, whose direct or i
ndirect superclass |
| 167 * is C's directly enclosing class, or which is a member of package p, whose
top level enclosing |
| 168 * class is different from that of C. |
| 169 * (protected -> private transformation) |
| 170 */ |
| 171 public void findThisPackageOrSubReferencingClasses1(ClassInfo classInfo) { |
| 172 String directlyEnclosingClass = classInfo.directlyEnclosingClass; |
| 173 String topLevelEnclosingClass = classInfo.topLevelEnclosingClass; |
| 174 String packageName = classInfo.packageName; |
| 175 for (PCDEntry entry : pcdm.entries()) { |
| 176 ClassInfo clientInfo = |
| 177 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, entry); |
| 178 if (clientInfo == null) { |
| 179 continue; // New class |
| 180 } |
| 181 if ((!clientInfo.packageName.equals(packageName)) && |
| 182 !clientInfo.isSubclassOf(directlyEnclosingClass, false)) { |
| 183 continue; |
| 184 } |
| 185 if (clientInfo.topLevelEnclosingClass.equals(topLevelEnclosingClass)
) { |
| 186 continue; |
| 187 } |
| 188 if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface
(), 1)) { |
| 189 addToAffectedClassNames(clientInfo.name); |
| 190 } |
| 191 } |
| 192 } |
| 193 |
| 194 /** |
| 195 * For class p.C, find each project class X referencing C, which is a member
of package p and whose |
| 196 * top level enclosing class is different from that of C. |
| 197 * (default -> private transformation) |
| 198 */ |
| 199 public void findThisPackageReferencingClasses1(ClassInfo classInfo) { |
| 200 String topLevelEnclosingClass = classInfo.topLevelEnclosingClass; |
| 201 String packageName = classInfo.packageName; |
| 202 for (PCDEntry entry : pcdm.entries()) { |
| 203 ClassInfo clientInfo = |
| 204 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, |
| 205 entry); |
| 206 if (clientInfo == null) { |
| 207 continue; // New class |
| 208 } |
| 209 if (!clientInfo.packageName.equals(packageName)) { |
| 210 continue; |
| 211 } |
| 212 if (topLevelEnclosingClass.equals(clientInfo.topLevelEnclosingClass)
) { |
| 213 continue; |
| 214 } |
| 215 if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface
(), 1)) { |
| 216 addToAffectedClassNames(clientInfo.name); |
| 217 } |
| 218 } |
| 219 } |
| 220 |
| 221 /** |
| 222 * For class p.C, find each project class X referencing C, which is not a me
mber of package p. |
| 223 * (public -> default transformation) |
| 224 */ |
| 225 public void findDiffPackageReferencingClasses1(ClassInfo classInfo) { |
| 226 String packageName = classInfo.packageName; |
| 227 for (PCDEntry pcde : pcdm.entries()) { |
| 228 ClassInfo clientInfo = |
| 229 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 230 if (clientInfo == null) { |
| 231 continue; // New class |
| 232 } |
| 233 if (clientInfo.packageName.equals(packageName)) { |
| 234 continue; |
| 235 } |
| 236 if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface
(), 1)) { |
| 237 addToAffectedClassNames(clientInfo.name); |
| 238 } |
| 239 } |
| 240 } |
| 241 |
| 242 /** |
| 243 * For class p.C, find each project class X referencing C, which is not a me
mber of package p and |
| 244 * whose direct or indirect superclass is C's directly enclosing class. |
| 245 * (protected -> default transformation) |
| 246 */ |
| 247 public void findDiffPackageAndSubReferencingClasses1(ClassInfo classInfo) { |
| 248 String packageName = classInfo.packageName; |
| 249 String directlyEnclosingClass = classInfo.directlyEnclosingClass; |
| 250 for (PCDEntry pcde : pcdm.entries()) { |
| 251 ClassInfo clientInfo = |
| 252 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 253 if (clientInfo == null) { |
| 254 continue; // New class |
| 255 } |
| 256 if (clientInfo.packageName.equals(packageName)) { |
| 257 continue; |
| 258 } |
| 259 if (!clientInfo.isSubclassOf(directlyEnclosingClass, false)) { |
| 260 continue; |
| 261 } |
| 262 if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface
(), 1)) { |
| 263 addToAffectedClassNames(clientInfo.name); |
| 264 } |
| 265 } |
| 266 } |
| 267 |
| 268 /** |
| 269 * Find all project classes that reference both of the classes with the |
| 270 * given names (or array classes of one or both) directly or indirectly from
the |
| 271 * constantpool, as a type of a data field, as a type in a method signature
or a |
| 272 * thrown exception, as a directly/indirectly implemented interface or a |
| 273 * direct/indirect superclass. |
| 274 */ |
| 275 public void findReferencingClasses2(ClassInfo classInfo1, ClassInfo classInf
o2) { |
| 276 Set<String> refClazz1 = new LinkedHashSet<String>(); |
| 277 findReferencingClasses(classInfo1, 2, false, refClazz1); |
| 278 Set<String> refClazz2 = new LinkedHashSet<String>(); |
| 279 findReferencingClasses(classInfo2, 2, false, refClazz2); |
| 280 |
| 281 for (String className1 : refClazz1) { |
| 282 if (refClazz2.contains(className1)) { |
| 283 addToAffectedClassNames(className1); |
| 284 } |
| 285 } |
| 286 } |
| 287 |
| 288 /** Find all project classes which are direct subclasses of the given class
*/ |
| 289 public void findDirectSubclasses(ClassInfo classInfo) { |
| 290 for (ClassInfo subclassInfo : classInfo.getDirectSubclasses()) { |
| 291 addToAffectedClassNames(subclassInfo.name); |
| 292 } |
| 293 } |
| 294 |
| 295 /** |
| 296 * Find all non-abstract project classes that implement the given interface
or any of its |
| 297 * subclasses directly, and all non-abstract classes that are direct descend
ants of abstract |
| 298 * classes that implement the given interface directly or indirectly. Class
C implements |
| 299 * interface I indirectly, if C or some superclass of C directly implements
I or some sublcass of I. |
| 300 */ |
| 301 public void findDirectlyAndOtherwiseImplementingConcreteClasses(ClassInfo in
tfInfo) { |
| 302 for (PCDEntry entry : pcdm.entries()) { |
| 303 ClassInfo clientInfo = |
| 304 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, entry); |
| 305 if (clientInfo == null) { |
| 306 continue; // New class |
| 307 } |
| 308 if (clientInfo.isInterface()) { |
| 309 continue; |
| 310 } |
| 311 if (clientInfo.isAbstract()) { |
| 312 if (clientInfo.implementsInterfaceDirectlyOrIndirectly(intfInfo.
name)) { |
| 313 findAllNearestConcreteSubclasses(clientInfo); |
| 314 } |
| 315 } else { |
| 316 if (clientInfo.implementsIntfOrSubintfDirectly(intfInfo.name)) { |
| 317 addToAffectedClassNames(clientInfo.name); |
| 318 } |
| 319 } |
| 320 } |
| 321 } |
| 322 |
| 323 private void findAllNearestConcreteSubclasses(ClassInfo classInfo) { |
| 324 for (ClassInfo subclassInfo : classInfo.getDirectSubclasses()) { |
| 325 if (subclassInfo.isAbstract()) { |
| 326 findAllNearestConcreteSubclasses(subclassInfo); |
| 327 } else { |
| 328 addToAffectedClassNames(subclassInfo.name); |
| 329 } |
| 330 } |
| 331 } |
| 332 |
| 333 /** |
| 334 * Find all interfaces and abstract classes that implement the given interfa
ce and declare or inherit |
| 335 * a method with the given name. For those that overload this method, find r
eferencing classes. |
| 336 */ |
| 337 public void findAbstractSubtypesWithSameNameMethod(ClassInfo intfInfo, Strin
g mName, final String mSig) { |
| 338 for (PCDEntry pcde : pcdm.entries()) { |
| 339 ClassInfo ci = |
| 340 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 341 if (ci == null) { |
| 342 continue; // New class or not in project |
| 343 } |
| 344 if (!(ci.isInterface() || ci.isAbstract())) { |
| 345 continue; |
| 346 } |
| 347 if (ci.implementsInterfaceDirectlyOrIndirectly(intfInfo.name)) { |
| 348 addToAffectedClassNames(ci.name); |
| 349 // Check if the new method overloads an existing (declared or in
herited) method. Overloading test is rough - |
| 350 // we just check if the number of parameters is the same. |
| 351 ci.findExistingSameNameMethods(mName, true, true, new ClassInfo.
MethodHandler() { |
| 352 |
| 353 void handleMethod(ClassInfo classInfo, int otherMethodIdx) { |
| 354 String otherMSig = |
| 355 classInfo.methodSignatures[otherMethodIdx]; |
| 356 if ( (!mSig.equals(otherMSig)) && |
| 357 Utils.sameParamNumber(mSig, otherMSig)) { |
| 358 findReferencingClassesForMethod(classInfo, otherMeth
odIdx); |
| 359 } |
| 360 } |
| 361 }); |
| 362 } |
| 363 } |
| 364 } |
| 365 |
| 366 /** Find all project classes that reference the given field. */ |
| 367 public void findReferencingClassesForField(ClassInfo classInfo, int fieldNo)
{ |
| 368 findReferencingClassesForMember(classInfo, fieldNo, true, false, false); |
| 369 } |
| 370 |
| 371 /** |
| 372 * Find all project classes that reference the given field and which are in |
| 373 * different packages. |
| 374 */ |
| 375 public void findDiffPackageReferencingClassesForField(ClassInfo classInfo, i
nt fieldNo) { |
| 376 findReferencingClassesForMember(classInfo, fieldNo, true, true, false); |
| 377 } |
| 378 |
| 379 /** |
| 380 * Find all project classes that reference the given field, which are in dif
ferent |
| 381 * packages and are direct or indirect subclasses of the member's declaring
class |
| 382 * (protected -> default transformation). |
| 383 */ |
| 384 public void findDiffPackageAndSubReferencingClassesForField(ClassInfo classI
nfo, int fieldNo) { |
| 385 findReferencingClassesForMember(classInfo, fieldNo, true, true, true); |
| 386 } |
| 387 |
| 388 /** Find all project classes that reference the given method. */ |
| 389 public void findReferencingClassesForMethod(ClassInfo classInfo, int methodN
o) { |
| 390 findReferencingClassesForMember(classInfo, methodNo, false, false, false
); |
| 391 } |
| 392 |
| 393 /** |
| 394 * Find all project classes that reference the given method and which are in |
| 395 * different packages. |
| 396 */ |
| 397 public void findDiffPackageReferencingClassesForMethod(ClassInfo classInfo,
int methodNo) { |
| 398 findReferencingClassesForMember(classInfo, methodNo, false, true, false)
; |
| 399 } |
| 400 |
| 401 /** |
| 402 * Find all project classes that reference the given method, which are in di
fferent |
| 403 * packages and are direct or indirect subclasses of the member's declaring
class |
| 404 * (protected -> default transformation) |
| 405 */ |
| 406 public void findDiffPackageAndSubReferencingClassesForMethod(ClassInfo class
Info, int methodNo) { |
| 407 findReferencingClassesForMember(classInfo, methodNo, false, true, true); |
| 408 } |
| 409 |
| 410 /** |
| 411 * Find all project classes that re-implement the given method and that are |
| 412 * direct/indirect subclasses of this method's declaring class. If some subc
lass C |
| 413 * re-implements the given method, we don't have to search C's subclasses fu
rther. |
| 414 */ |
| 415 public void findSubclassesReimplementingMethod(ClassInfo classInfo, int meth
odNo) { |
| 416 findSubclassesReimplementingMethod(classInfo, classInfo, methodNo); |
| 417 } |
| 418 |
| 419 private void findSubclassesReimplementingMethod(ClassInfo targetClass, Class
Info methodDeclaringClass, int methodNo) { |
| 420 for (ClassInfo subclass : targetClass.getDirectSubclasses()) { |
| 421 if (subclass.declaresMethod(methodDeclaringClass, methodNo)) { |
| 422 addToAffectedClassNames(subclass.name); |
| 423 } else { |
| 424 findSubclassesReimplementingMethod(subclass, methodDeclaringClas
s, methodNo); |
| 425 } |
| 426 } |
| 427 } |
| 428 |
| 429 /** |
| 430 * For a given class C, find all concrete direct subclasses, and all direct
concrente subclasses of C's direct |
| 431 * or indirect abstract subclasses. |
| 432 */ |
| 433 public void findConcreteSubclasses(ClassInfo targetClass) { |
| 434 for (ClassInfo subclass : targetClass.getDirectSubclasses()) { |
| 435 if (subclass.isAbstract()) { |
| 436 findConcreteSubclasses(subclass); |
| 437 } else { |
| 438 addToAffectedClassNames(subclass.name); |
| 439 } |
| 440 } |
| 441 } |
| 442 |
| 443 /** |
| 444 * Find any concrete subclasses of targetClass that don't override or inheri
t a concrete implementation |
| 445 * of the given method. |
| 446 */ |
| 447 public void findConcreteSubclassesNotOverridingAbstractMethod(ClassInfo targ
etClass, ClassInfo methodDeclaringClass, int methodNo) { |
| 448 for (ClassInfo subclass : targetClass.getDirectSubclasses()) { |
| 449 int pos = |
| 450 subclass.getDeclaredMethodPos(methodDeclaringClass, methodNo
); |
| 451 if (pos == -1) { // This method is not overridden in this class |
| 452 if (!subclass.isAbstract()) { |
| 453 addToAffectedClassNames(subclass.name); |
| 454 } else { |
| 455 findConcreteSubclassesNotOverridingAbstractMethod(subclass,
methodDeclaringClass, methodNo); |
| 456 } |
| 457 } else { // A chance that this method is declared abstract once agai
n... |
| 458 if (Modifier.isAbstract(subclass.methodAccessFlags[pos])) { |
| 459 findConcreteSubclassesNotOverridingAbstractMethod(subclass,
methodDeclaringClass, methodNo); |
| 460 } |
| 461 } |
| 462 } |
| 463 } |
| 464 |
| 465 /** Find all project classes that reference any method that throws the given
exception. */ |
| 466 public void findRefsToMethodsThrowingException(ClassInfo excClassInfo) { |
| 467 for (PCDEntry pcde : pcdm.entries()) { |
| 468 ClassInfo classInfo = |
| 469 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 470 if (classInfo == null) { |
| 471 continue; // New class |
| 472 } |
| 473 int methodIdx = -1; |
| 474 do { |
| 475 methodIdx = |
| 476 classInfo.hasMethodThrowingException(excClassInfo, metho
dIdx + 1); |
| 477 if (methodIdx != -1) { |
| 478 findReferencingClassesForMethod(classInfo, methodIdx); |
| 479 } |
| 480 } while (methodIdx != -1); |
| 481 } |
| 482 } |
| 483 |
| 484 /** |
| 485 * Find all project classes declaring a static field with the given name. Cu
rrently used only to look up |
| 486 * classes referencing given class X via the "X.class" construct. |
| 487 */ |
| 488 public void findClassesDeclaringField(String name, String signature, boolean
isStatic, String packageToLookIn) { |
| 489 for (PCDEntry pcde : pcdm.entries()) { |
| 490 ClassInfo classInfo = |
| 491 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 492 if (classInfo == null) { |
| 493 continue; // New class |
| 494 } |
| 495 if (packageToLookIn != null && |
| 496 !classInfo.packageName.equals(packageToLookIn)) { |
| 497 continue; |
| 498 } |
| 499 if (classInfo.declaresField(name, signature, isStatic)) { |
| 500 addToAffectedClassNames(classInfo.name); |
| 501 } |
| 502 } |
| 503 } |
| 504 |
| 505 public void addToAffectedClassNames(String className) { |
| 506 String res = pcdm.classAlreadyRecompiledOrUncompileable(className); |
| 507 if (res == null) { |
| 508 affectedClassNames.add(className); |
| 509 } else if (!"".equals(res)) { // The dependent class comes from a .jar. |
| 510 if (checkedClassIsFromJar || noWarnOnDependentJar) { |
| 511 return; |
| 512 } |
| 513 String message = "Class " + className + " is affected by a change to
" + checkedClassName + ", but can't be recompiled, " + |
| 514 "since it is located in archive " + res; |
| 515 if (failOnDependentJar) { |
| 516 throw new PrivateException(new PublicExceptions.JarDependsOnSour
ceException(message)); |
| 517 } else { |
| 518 Utils.printWarningMessage("Warning: " + message); |
| 519 } |
| 520 } |
| 521 } |
| 522 |
| 523 /** |
| 524 * Find all project classes that reference the class with the given name. |
| 525 * The second parameter controls the "thoroughness degree", and its value is
passed to ClassInfo.referencesClass() |
| 526 * method (see the comment to it). The fromDiffPackages parameter defines wh
ether all such classes |
| 527 * or only classes from different packages are required. |
| 528 */ |
| 529 private void findReferencingClasses(ClassInfo classInfo, |
| 530 int thorDegree, boolean fromDiffPackages, |
| 531 Set<String> ret) { |
| 532 String packageName = classInfo.packageName; |
| 533 for (PCDEntry pcde : pcdm.entries()) { |
| 534 ClassInfo clientInfo = |
| 535 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 536 if (clientInfo == null) { |
| 537 continue; // New class |
| 538 } |
| 539 if (fromDiffPackages && packageName.equals(clientInfo.packageName))
{ |
| 540 continue; |
| 541 } |
| 542 // If thorDegree == 2, i.e. indirect references from the constantpoo
l (e.g. a reference to a method which |
| 543 // has classInfo as one of its formal parameter types) are taken int
o account, then we should check all of |
| 544 // the classes, whether classInfo is directly accessible from them o
r not. |
| 545 if (thorDegree != 2 && (!classAccessibleFrom(classInfo, clientInfo))
) { |
| 546 continue; |
| 547 } |
| 548 |
| 549 if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface
(), thorDegree)) { |
| 550 if (ret == null) { |
| 551 addToAffectedClassNames(clientInfo.name); |
| 552 } else { |
| 553 ret.add(clientInfo.name); |
| 554 } |
| 555 } |
| 556 } |
| 557 } |
| 558 |
| 559 /** |
| 560 * Find all project classes that reference the given member. If fromDiffPack
ages |
| 561 * is true, then only classes that do not belong to the package of the membe
r's |
| 562 * declaring class should be returned. If onlySubclasses is true, then only |
| 563 * classes that are subclasses of member's declaring class should be returne
d. |
| 564 */ |
| 565 private void findReferencingClassesForMember(ClassInfo declaringClassInfo, i
nt memberNo, |
| 566 boolean isField, |
| 567 boolean fromDiffPackages, boolean onlySubclasses) { |
| 568 String declaringClassName = declaringClassInfo.name; |
| 569 String declaringClassPackage = declaringClassInfo.packageName; |
| 570 for (PCDEntry pcde : pcdm.entries()) { |
| 571 ClassInfo clientInfo = |
| 572 pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde); |
| 573 if (clientInfo == null) { |
| 574 continue; // New class |
| 575 } |
| 576 String className = clientInfo.name; |
| 577 if (className.equals(declaringClassName)) { |
| 578 continue; |
| 579 } |
| 580 if (!memberAccessibleFrom(declaringClassInfo, memberNo, clientInfo,
isField)) { |
| 581 continue; |
| 582 } |
| 583 if (fromDiffPackages && |
| 584 declaringClassPackage.equals(clientInfo.packageName)) { |
| 585 continue; |
| 586 } |
| 587 if (onlySubclasses && !clientInfo.isSubclassOf(declaringClassName, f
alse)) { |
| 588 continue; |
| 589 } |
| 590 |
| 591 if (isField) { |
| 592 if (clientInfo.referencesField(declaringClassInfo, memberNo)) { |
| 593 addToAffectedClassNames(clientInfo.name); |
| 594 } |
| 595 } else { |
| 596 if (clientInfo.referencesMethod(declaringClassInfo, memberNo)) { |
| 597 addToAffectedClassNames(clientInfo.name); |
| 598 } |
| 599 } |
| 600 } |
| 601 } |
| 602 |
| 603 /** Checks if class classInfo is accessible from class clientClassInfo. */ |
| 604 private boolean classAccessibleFrom(ClassInfo classInfo, ClassInfo clientCla
ssInfo) { |
| 605 char classFlags = classInfo.accessFlags; |
| 606 String classPackage = classInfo.packageName; |
| 607 String clientClassPackage = clientClassInfo.packageName; |
| 608 |
| 609 if (Modifier.isPublic(classFlags)) { |
| 610 return true; |
| 611 } else if (Modifier.isProtected(classFlags)) { |
| 612 if (classPackage.equals(clientClassPackage) || |
| 613 clientClassInfo.isSubclassOf(classInfo.directlyEnclosingClas
s, false)) { |
| 614 return true; |
| 615 } |
| 616 } else if (Modifier.isPrivate(classFlags)) { |
| 617 if (classInfo.topLevelEnclosingClass.equals(clientClassInfo.topLevel
EnclosingClass)) { |
| 618 return true; |
| 619 } |
| 620 } else { |
| 621 if (classPackage.equals(clientClassPackage)) { |
| 622 return true; |
| 623 } |
| 624 } |
| 625 |
| 626 return false; |
| 627 } |
| 628 |
| 629 /** |
| 630 * Checks if member memberNo (which is a field if isField == true, and metho
d otherwise) of class memberClassInfo is |
| 631 * accessible from class clientClassInfo. |
| 632 */ |
| 633 private boolean memberAccessibleFrom(ClassInfo memberClassInfo, |
| 634 int memberNo, ClassInfo clientClassInfo, boolean isField) { |
| 635 char memberClassFlags = memberClassInfo.accessFlags; |
| 636 char memberFlags = isField ? memberClassInfo.fieldAccessFlags[memberNo] |
| 637 : memberClassInfo.methodAccessFlags[memberNo]; |
| 638 String memberClassPackage = memberClassInfo.packageName; |
| 639 String clientClassPackage = clientClassInfo.packageName; |
| 640 |
| 641 if (Modifier.isPublic(memberClassFlags)) { |
| 642 if (Modifier.isPublic(memberFlags)) { |
| 643 return true; |
| 644 } else if (Modifier.isProtected(memberFlags) && |
| 645 (memberClassPackage.equals(clientClassPackage) || |
| 646 clientClassInfo.isSubclassOf(memberClassInfo.name, false)))
{ |
| 647 return true; |
| 648 } else if (Modifier.isPrivate(memberFlags)) { |
| 649 if (memberClassInfo.topLevelEnclosingClass.equals( |
| 650 clientClassInfo.topLevelEnclosingClass)) { |
| 651 return true; |
| 652 } |
| 653 } else if (memberClassPackage.equals(clientClassPackage)) { |
| 654 return true; |
| 655 } |
| 656 } else if (Modifier.isProtected(memberClassFlags)) { |
| 657 if (!(memberClassPackage.equals(clientClassPackage) || |
| 658 clientClassInfo.isSubclassOf(memberClassInfo.directlyEnclosi
ngClass, false))) { |
| 659 return true; |
| 660 } |
| 661 if (Modifier.isPublic(memberFlags) || |
| 662 Modifier.isProtected(memberFlags)) { |
| 663 return true; |
| 664 } else if (Modifier.isPrivate(memberFlags)) { |
| 665 if (memberClassInfo.topLevelEnclosingClass.equals( |
| 666 clientClassInfo.topLevelEnclosingClass)) { |
| 667 return true; |
| 668 } |
| 669 } else { |
| 670 if (memberClassPackage.equals(clientClassPackage)) { |
| 671 return true; |
| 672 } |
| 673 } |
| 674 } else if (Modifier.isPrivate(memberClassFlags)) { |
| 675 if (memberClassInfo.topLevelEnclosingClass.equals( |
| 676 clientClassInfo.topLevelEnclosingClass)) { |
| 677 return true; |
| 678 } |
| 679 } else { // memberClassInfo is package-private |
| 680 if (!memberClassPackage.equals(clientClassPackage)) { |
| 681 return false; |
| 682 } |
| 683 if (Modifier.isPublic(memberFlags) || Modifier.isProtected(memberFla
gs)) { |
| 684 return true; |
| 685 } else if (Modifier.isPrivate(memberFlags)) { |
| 686 if (memberClassInfo.topLevelEnclosingClass.equals( |
| 687 clientClassInfo.topLevelEnclosingClass)) { |
| 688 return true; |
| 689 } |
| 690 } else { |
| 691 return true; |
| 692 } |
| 693 } |
| 694 |
| 695 return false; |
| 696 } |
| 697 } |
OLD | NEW |