Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Unified Diff: third_party/jmake/src/org/pantsbuild/jmake/CompatibilityChecker.java

Issue 1373723003: Fix javac --incremental by using jmake for dependency analysis (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@aidl
Patch Set: fix license check Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/jmake/src/org/pantsbuild/jmake/CompatibilityChecker.java
diff --git a/third_party/jmake/src/org/pantsbuild/jmake/CompatibilityChecker.java b/third_party/jmake/src/org/pantsbuild/jmake/CompatibilityChecker.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd74cfb3e0ad6529372945a2deb9b84c653de339
--- /dev/null
+++ b/third_party/jmake/src/org/pantsbuild/jmake/CompatibilityChecker.java
@@ -0,0 +1,610 @@
+/* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved
+ *
+ * This program is distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+package org.pantsbuild.jmake;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class implements checking of source compatibility of classes and supporting operations
+ *
+ * @author Misha Dmitriev
+ * 12 March 2004
+ */
+public class CompatibilityChecker {
+
+ private PCDManager pcdm;
+ private RefClassFinder rf;
+ ClassInfo oldClassInfo = null;
+ ClassInfo newClassInfo = null;
+ private boolean versionsCompatible;
+ private boolean publicConstantChanged;
+
+ public CompatibilityChecker(PCDManager pcdm, boolean failOnDependentJar, boolean noWarnOnDependentJar) {
+ this.pcdm = pcdm;
+ publicConstantChanged = false;
+ rf = new RefClassFinder(pcdm, failOnDependentJar, noWarnOnDependentJar);
+ }
+
+ /**
+ * Compares the two class versions for the given PCDEntry. Returns true if all changes are source
+ * compatible, and false otherwise.
+ */
+ public boolean compareClassVersions(PCDEntry entry) {
+ // I once had the following optimization here with the comment "No sense to make any further checks if
+ // everything is recompiled anyway", but now I believe it's wrong. For each class that was found changed
+ // we need to know whether the new version is compatible with the old or not, since this may determine
+ // whether the new version of this class is promoted into the pdb or not (see PCDManager.updateClassInfoInPCD()).
+ // So, all changed classes should be checked just to correctly determine version compatibility.
+ // if (publicConstantChanged) return false;
+
+ oldClassInfo = pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, entry);
+ newClassInfo = pcdm.getClassInfoForPCDEntry(ClassInfo.VER_NEW, entry);
+
+ rf.initialize(oldClassInfo.name, entry.javaFileFullPath.endsWith(".jar"));
+ versionsCompatible = true;
+
+ checkAccessFlags();
+ checkSuperclasses();
+ checkImplementedInterfaces();
+ checkFields();
+ checkMethodsAndConstructors();
+
+ return versionsCompatible;
+ }
+
+ /** Find all dependent classes for a deleted class. */
+ public void checkDeletedClass(PCDEntry entry) {
+ oldClassInfo = entry.oldClassInfo;
+ rf.initialize(oldClassInfo.name, entry.javaFileFullPath.endsWith(".jar"));
+ rf.findReferencingClassesForDeletedClass(oldClassInfo);
+ // It may happen that the only reference to deleted class X is via "X.class" construct
+ String packageToLookIn =
+ oldClassInfo.isPublic() ? null : oldClassInfo.packageName;
+ rf.findClassesDeclaringField(("class$" + oldClassInfo.name).intern(), "java/lang/Class", true, packageToLookIn);
+ checkForFinalFields();
+ }
+
+ /** Returns the names of classes affected by source incompatible changes to the new version of the checked class. */
+ public String[] getAffectedClasses() {
+ return rf.getAffectedClassNames();
+ }
+
+ /** All of the following methods return true if no source incompatible changes found, and false otherwise */
+ private void checkAccessFlags() {
+ char oldClassFlags = oldClassInfo.accessFlags;
+ char newClassFlags = newClassInfo.accessFlags;
+ if (oldClassFlags == newClassFlags) {
+ return;
+ }
+
+ if (!Modifier.isFinal(oldClassFlags) && Modifier.isFinal(newClassFlags)) {
+ versionsCompatible = false;
+ rf.findDirectSubclasses(oldClassInfo);
+ }
+
+ if (!Modifier.isAbstract(oldClassFlags) && Modifier.isAbstract(newClassFlags)) {
+ versionsCompatible = false;
+ rf.findReferencingClasses0(oldClassInfo);
+ }
+
+ // Now to accessibility modifiers checking...
+ if (Modifier.isPublic(newClassFlags)) {
+ return;
+ }
+
+ if (Modifier.isProtected(newClassFlags)) {
+ if (Modifier.isPublic(oldClassFlags)) {
+ versionsCompatible = false;
+ rf.findDiffPackageAndNotSubReferencingClasses1(oldClassInfo);
+ }
+ } else if (Modifier.isPrivate(newClassFlags)) {
+ if (!Modifier.isPrivate(oldClassFlags)) {
+ versionsCompatible = false;
+ } else {
+ return; // private -> private, nothing more to check
+ }
+ if (Modifier.isPublic(oldClassFlags)) {
+ rf.findReferencingClasses1(oldClassInfo);
+ } else if (Modifier.isProtected(oldClassFlags)) {
+ rf.findThisPackageOrSubReferencingClasses1(oldClassInfo);
+ } else {
+ rf.findThisPackageReferencingClasses1(oldClassInfo);
+ }
+ } else { // newClassFlags has default access, since public has already been excluded
+ if (Modifier.isPublic(oldClassFlags)) {
+ versionsCompatible = false;
+ rf.findDiffPackageReferencingClasses1(oldClassInfo);
+ } else if (Modifier.isProtected(oldClassFlags)) {
+ versionsCompatible = false;
+ rf.findDiffPackageAndSubReferencingClasses1(oldClassInfo);
+ }
+ }
+ }
+
+ private void checkSuperclasses() {
+ List<String> oldSuperNames = oldClassInfo.getAllSuperclassNames();
+ List<String> newSuperNames = newClassInfo.getAllSuperclassNames();
+
+ int oldNamesSizeMinusOne = oldSuperNames.size() - 1;
+ for (int i = 0; i <= oldNamesSizeMinusOne; i++) {
+ String oldSuperName = oldSuperNames.get(i);
+ if (!newSuperNames.contains(oldSuperName)) {
+ versionsCompatible = false;
+ ClassInfo missingSuperClass =
+ pcdm.getClassInfoForName(ClassInfo.VER_OLD, oldSuperName);
+ if (missingSuperClass == null) { // This class is not in project
+ missingSuperClass =
+ ClassPath.getClassInfoForName(oldSuperName, pcdm);
+ if (missingSuperClass == null) {
+ missingSuperClass = new ClassInfo(oldSuperName, pcdm);
+ }
+ }
+ rf.findReferencingClasses2(missingSuperClass, oldClassInfo);
+ }
+ }
+
+ // Now check if the class is an exception, and its kind has changed from unchecked to checked
+ if (oldClassInfo.isInterface() || oldSuperNames.size() == 0) {
+ return;
+ }
+ if (!(oldSuperNames.contains("java/lang/RuntimeException") || oldSuperNames.contains("java/lang/Error"))) {
+ return;
+ }
+ if (!(newSuperNames.contains("java/lang/RuntimeException") || newSuperNames.contains("java/lang/Error"))) {
+ if (!newSuperNames.contains("java/lang/Throwable")) {
+ return;
+ }
+ // Ok, exception kind has changed from unchecked to checked.
+ versionsCompatible = false;
+ rf.findReferencingClasses0(oldClassInfo);
+ rf.findRefsToMethodsThrowingException(oldClassInfo);
+ }
+ }
+
+ private void checkImplementedInterfaces() {
+ Set<String> oldIntfNames = oldClassInfo.getAllImplementedIntfNames();
+ Set<String> newIntfNames = newClassInfo.getAllImplementedIntfNames();
+
+ for (String oldIntfName : oldIntfNames) {
+ if (!newIntfNames.contains(oldIntfName)) {
+ versionsCompatible = false;
+ ClassInfo missingSuperInterface =
+ pcdm.getClassInfoForName(ClassInfo.VER_OLD, oldIntfName);
+ if (missingSuperInterface == null) { // This class is not in project
+ missingSuperInterface =
+ ClassPath.getClassInfoForName(oldIntfName, pcdm);
+ if (missingSuperInterface == null) {
+ missingSuperInterface = new ClassInfo(oldIntfName, pcdm);
+ }
+ }
+ rf.findReferencingClasses2(missingSuperInterface, oldClassInfo);
+ }
+ }
+
+ // Check if the class is abstract, and an interface has been added to its list of implemented interfaces
+ if (newClassInfo.isAbstract()) {
+ for (String newIntfName : newIntfNames) {
+ if (!oldIntfNames.contains(newIntfName)) {
+ versionsCompatible = false;
+ rf.findConcreteSubclasses(oldClassInfo);
+ break;
+ }
+ }
+ }
+ }
+
+ private void checkFields() {
+ String oFNames[] = oldClassInfo.fieldNames;
+ String oFSignatures[] = oldClassInfo.fieldSignatures;
+ char oFFlags[] = oldClassInfo.fieldAccessFlags;
+ String nFNames[] = newClassInfo.fieldNames;
+ String nFSignatures[] = newClassInfo.fieldSignatures;
+ char nFFlags[] = newClassInfo.fieldAccessFlags;
+ int oFLen = oFNames != null ? oFNames.length : 0;
+ int nFLen = nFNames != null ? nFNames.length : 0;
+
+ int oFMod, nFMod;
+ String oFName, oFSig, nFName;
+ int i, j, k, endIdx;
+ int nonMatchingNewFields = nFLen;
+
+ for (i = 0; i < oFLen; i++) {
+ oFMod = oFFlags[i];
+ if (Modifier.isPrivate(oFMod)) {
+ continue; // Changes to private fields don't affect compatibility
+ }
+ oFName = oFNames[i];
+ oFSig = oFSignatures[i];
+ boolean found = false;
+
+ // Look for the same field in the new version considering name and type
+ endIdx = nFLen - 1;
+ k = i < nFLen ? i : endIdx;
+ for (j = 0; j < nFLen; j++) {
+ if (oFName.equals(nFNames[k]) &&
+ oFSig.equals(nFSignatures[k])) {
+ found = true;
+ break;
+ }
+ if (k < endIdx) {
+ k++;
+ } else {
+ k = 0;
+ }
+ }
+
+ if (found) {
+ nonMatchingNewFields--;
+ nFMod = nFFlags[k];
+ checkFieldModifiers(oFMod, nFMod, i, k);
+ if (publicConstantChanged) {
+ return;
+ }
+ } else { // Matching field not found
+ if (Modifier.isStatic(oFMod) && Modifier.isFinal(oFMod) &&
+ oldClassInfo.primitiveConstantInitValues != null &&
+ oldClassInfo.primitiveConstantInitValues[i] != null) {
+ // Compile-time constant deleted
+ versionsCompatible = false;
+ rf.findAllProjectClasses(oldClassInfo, i);
+ if (Modifier.isPublic(oFMod)) {
+ publicConstantChanged = true;
+ return;
+ }
+ } else {
+ versionsCompatible = false;
+ rf.findReferencingClassesForField(oldClassInfo, i);
+ }
+ }
+ }
+
+ if (nonMatchingNewFields > 0) { // There are some fields declared in the new version which don't exist in the old one
+ // Look for fields hiding same-named fields in superclasses
+ for (i = 0; i < nFLen; i++) {
+ nFName = nFNames[i];
+
+ boolean found = false;
+ for (j = 0; j < oFLen; j++) {
+ if (nFName.equals(oFNames[j])) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ continue; // nFName is not an added field
+ }
+ String superName = oldClassInfo.superName;
+ ClassInfo superInfo;
+ while (superName != null) {
+ superInfo =
+ pcdm.getClassInfoForName(ClassInfo.VER_OLD, superName);
+ if (superInfo == null) {
+ break;
+ }
+ String[] superOFNames = superInfo.fieldNames;
+ int superOFNamesLen = superOFNames != null ? superOFNames.length
+ : 0;
+ for (j = 0; j < superOFNamesLen; j++) {
+ if (nFName == superOFNames[j]) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForField(superInfo, j);
+ }
+ }
+ superName = superInfo.superName;
+ }
+ }
+ }
+ }
+
+ /** It is already known that old field is not private */
+ private void checkFieldModifiers(int oFMod, int nFMod, int oldFieldIdx, int newFieldIdx) {
+ if (oFMod == nFMod) {
+ if (Modifier.isFinal(oFMod) &&
+ (!ClassInfo.constFieldInitValuesEqual(oldClassInfo, oldFieldIdx, newClassInfo, newFieldIdx))) {
+ versionsCompatible = false;
+ rf.findAllProjectClasses(oldClassInfo, oldFieldIdx);
+ if (Modifier.isPublic(oFMod)) {
+ publicConstantChanged = true; // Means we will have to recompile ALL project classes
+ }
+ return;
+ }
+ }
+
+ // These tests are ordered such that if a previous test succeeds, there is no need to do further tests, since that
+ // former test will cause more classes to be checked than any of the further tests. That is why it is possible to
+ // check properties that are in fact independent (e.g. accessibility vs. static/non-static) together. But this
+ // optimization only works since all kinds of tests result in the same kind of find..ReferencingClassesForField()
+ // outcome. For methods this is not true, and so there we have to check independent properties separately.
+ if (Modifier.isStatic(oFMod) && Modifier.isFinal(oFMod) && // oFMod is known to be non-private
+ (!Modifier.isFinal(nFMod) || !ClassInfo.constFieldInitValuesEqual(oldClassInfo, oldFieldIdx, newClassInfo, newFieldIdx))) {
+ versionsCompatible = false;
+ rf.findAllProjectClasses(oldClassInfo, oldFieldIdx);
+ if (Modifier.isPublic(oFMod)) {
+ publicConstantChanged = true;
+ }
+ } else if (Modifier.isPrivate(nFMod) || // oFMod is known to be non-private
+ (!Modifier.isFinal(oFMod) && Modifier.isFinal(nFMod)) ||
+ (Modifier.isStatic(oFMod) != Modifier.isStatic(nFMod)) ||
+ (Modifier.isVolatile(oFMod) != Modifier.isVolatile(nFMod))) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForField(oldClassInfo, oldFieldIdx);
+ } else if (Modifier.isPublic(oFMod) && Modifier.isProtected(nFMod)) {
+ versionsCompatible = false;
+ rf.findDiffPackageReferencingClassesForField(oldClassInfo, oldFieldIdx);
+ } else if ((Modifier.isPublic(oFMod) || Modifier.isProtected(oFMod)) &&
+ (!(Modifier.isPublic(nFMod) || Modifier.isProtected(nFMod) || Modifier.isPrivate(nFMod)))) {
+ versionsCompatible = false;
+ if (Modifier.isPublic(oFMod)) {
+ rf.findDiffPackageReferencingClassesForField(oldClassInfo, oldFieldIdx);
+ } else {
+ rf.findDiffPackageAndSubReferencingClassesForField(oldClassInfo, oldFieldIdx);
+ }
+ }
+ }
+
+ private void checkForFinalFields() {
+ char oFFlags[] = oldClassInfo.fieldAccessFlags;
+ int oFLen = oldClassInfo.fieldNames != null ? oldClassInfo.fieldNames.length
+ : 0;
+ int oFMod;
+
+ for (int i = 0; i < oFLen; i++) {
+ oFMod = oFFlags[i];
+ if (Modifier.isPrivate(oFMod)) {
+ continue; // Changes to private fields don't affect compatibility
+ }
+ if (Modifier.isStatic(oFMod) && Modifier.isFinal(oFMod)) {
+ rf.findAllProjectClasses(oldClassInfo, i);
+ if (Modifier.isPublic(oFMod)) {
+ publicConstantChanged = true;
+ return;
+ }
+ }
+ }
+ }
+
+ private void checkMethodsAndConstructors() {
+ String oMNames[] = oldClassInfo.methodNames;
+ String oMSignatures[] = oldClassInfo.methodSignatures;
+ char oMFlags[] = oldClassInfo.methodAccessFlags;
+ String nMNames[] = newClassInfo.methodNames;
+ String nMSignatures[] = newClassInfo.methodSignatures;
+ char nMFlags[] = newClassInfo.methodAccessFlags;
+ int oMLen = oMNames != null ? oMNames.length : 0;
+ int nMLen = nMNames != null ? nMNames.length : 0;
+
+ int oMMod, nMMod;
+ String oMName, oMSig, nMName, nMSig;
+ int i, j, k, endIdx;
+ int nonMatchingNewMethods = nMLen;
+
+ for (i = 0; i < oMLen; i++) {
+ oMMod = oMFlags[i];
+ if (Modifier.isPrivate(oMMod)) {
+ continue; // Changes to private methods don't affect compatibility
+ }
+ oMName = oMNames[i];
+ oMSig = oMSignatures[i];
+ boolean found = false;
+
+ // Look for the same method in the new version considering name and signature
+ endIdx = nMLen - 1;
+ k = i < nMLen ? i : endIdx;
+ for (j = 0; j < nMLen; j++) {
+ if (oMName == nMNames[k] && oMSig == nMSignatures[k]) {
+ found = true;
+ break;
+ }
+ if (k < endIdx) {
+ k++;
+ } else {
+ k = 0;
+ }
+ }
+
+ if (found) {
+ nonMatchingNewMethods--;
+ nMMod = nMFlags[k];
+ if (oMMod != nMMod) {
+ checkMethodModifiers(oMMod, nMMod, i);
+ }
+
+ // Check if the new method throws more exceptions than the old one
+ if (newClassInfo.checkedExceptions != null && newClassInfo.checkedExceptions[k] != null) {
+ if (oldClassInfo.checkedExceptions == null) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForMethod(oldClassInfo, i);
+ } else if (oldClassInfo.checkedExceptions[i] == null) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForMethod(oldClassInfo, i);
+ } else {
+ String oldExceptions[] =
+ oldClassInfo.checkedExceptions[i];
+ String newExceptions[] =
+ newClassInfo.checkedExceptions[k];
+ for (int ei = 0; ei < newExceptions.length; ei++) {
+ String newEx = newExceptions[ei];
+ found = false;
+ for (int ej = 0; ej < oldExceptions.length; ej++) {
+ if (newEx.equals(oldExceptions[ej])) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForMethod(oldClassInfo, i);
+ break;
+ }
+ }
+ }
+ }
+ } else { // Matching method not found
+ versionsCompatible = false;
+ rf.findReferencingClassesForMethod(oldClassInfo, i);
+ // Deleting a concrete method from an abstract class is a special case
+ if (oldClassInfo.isAbstract() && !Modifier.isAbstract(oMMod)) {
+ rf.findConcreteSubclassesNotOverridingAbstractMethod(oldClassInfo, oldClassInfo, i);
+ }
+ }
+ }
+
+ if (nonMatchingNewMethods > 0) { // There are some methods/constructors declared in the new version which don't exist in the old one
+ if (!oldClassInfo.isInterface()) {
+ for (i = 0; i < nMLen; i++) {
+ nMMod = nMFlags[i];
+ if (Modifier.isPrivate(nMMod)) {
+ continue;
+ }
+ String newMName = nMNames[i];
+ final String newMSig = nMSignatures[i];
+ final boolean isStatic = Modifier.isStatic(nMMod);
+
+ boolean found = false;
+ for (j = 0; j < oMLen; j++) {
+ if (newMName.equals(oMNames[j]) &&
+ newMSig.equals(oMSignatures[j])) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ continue; // nMName is not an added method
+ }
+ // Check if the new method is a static one that hides an inherited static method
+ // Check if the new method overloads an existing (declared or inherited) method. Overloading test is rough -
+ // we just check if the number of parameters is the same. Note that if a new constructor has been added, it
+ // can be treated in the same way, except that we shouldn't look up "same name methods" for it in superclasses.
+ oldClassInfo.findExistingSameNameMethods(newMName,
+ !newMName.equals("<init>"), false,
+ new ClassInfo.MethodHandler() {
+
+ void handleMethod(ClassInfo classInfo, int methodIdx) {
+ String otherMSig =
+ classInfo.methodSignatures[methodIdx];
+ if ((newMSig.equals(otherMSig) && isStatic &&
+ classInfo != oldClassInfo) ||
+ (newMSig != otherMSig &&
+ Utils.sameParamNumber(newMSig, otherMSig))) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForMethod(classInfo, methodIdx);
+ }
+ }
+ });
+
+ if (Modifier.isAbstract(nMMod)) {
+ // An abstract method added to the class. Find any concrete subclasses that don't override
+ // or inherit a concrete implementation of this method.
+ versionsCompatible = false;
+ rf.findConcreteSubclassesNotOverridingAbstractMethod(oldClassInfo, newClassInfo, i);
+ }
+ // Check if there is a method with the same name in some subclass, such that it now overrides
+ // or overloads the added method.
+ if (subclassesDeclareSameNameMethod(oldClassInfo, newMName)) {
+ versionsCompatible = false;
+ }
+ }
+ } else { // We are checking an interface.
+ for (i = 0; i < nMLen; i++) {
+ String newMName = nMNames[i];
+ final String newMSig = nMSignatures[i];
+
+ boolean found = false;
+ for (j = 0; j < oMLen; j++) {
+ if (newMName == oMNames[j] && newMSig == oMSignatures[j]) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ versionsCompatible = false;
+
+ // Check if the new method overloads an existing (declared or inherited) method. Overloading test is rough -
+ // we just check if the number of parameters is the same.
+ oldClassInfo.findExistingSameNameMethods(newMName, true, true, new ClassInfo.MethodHandler() {
+
+ void handleMethod(ClassInfo classInfo, int methodIdx) {
+ String otherMSig =
+ classInfo.methodSignatures[methodIdx];
+ if (newMSig != otherMSig &&
+ Utils.sameParamNumber(newMSig, otherMSig)) {
+ rf.findReferencingClassesForMethod(classInfo, methodIdx);
+ }
+ }
+ });
+
+ rf.findDirectlyAndOtherwiseImplementingConcreteClasses(oldClassInfo);
+ rf.findAbstractSubtypesWithSameNameMethod(oldClassInfo, newMName, newMSig);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private void checkMethodModifiers(int oMMod, int nMMod, int oldMethodIdx) {
+ if (Modifier.isPrivate(nMMod)) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForMethod(oldClassInfo, oldMethodIdx);
+ } else if (Modifier.isPublic(oMMod) && Modifier.isProtected(nMMod)) {
+ versionsCompatible = false;
+ rf.findDiffPackageReferencingClassesForMethod(oldClassInfo, oldMethodIdx);
+ } else if ((Modifier.isPublic(oMMod) || Modifier.isProtected(oMMod)) &&
+ (!(Modifier.isPublic(nMMod) || Modifier.isProtected(nMMod) || Modifier.isPrivate(nMMod)))) {
+ versionsCompatible = false;
+ if (Modifier.isPublic(oMMod)) {
+ rf.findDiffPackageReferencingClassesForMethod(oldClassInfo, oldMethodIdx);
+ } else {
+ rf.findDiffPackageAndSubReferencingClassesForMethod(oldClassInfo, oldMethodIdx);
+ }
+ } else if ((Modifier.isPrivate(oMMod) && !Modifier.isPrivate(nMMod)) ||
+ (Modifier.isProtected(oMMod) && Modifier.isPublic(nMMod)) ||
+ (!(Modifier.isPublic(oMMod) || Modifier.isProtected(oMMod) || Modifier.isPrivate(oMMod)) &&
+ (Modifier.isPublic(nMMod) || Modifier.isProtected(nMMod)))) {
+ versionsCompatible = false;
+ rf.findSubclassesReimplementingMethod(oldClassInfo, oldMethodIdx);
+ }
+
+ if ((!Modifier.isAbstract(oMMod) && Modifier.isAbstract(nMMod)) ||
+ (Modifier.isStatic(oMMod) != Modifier.isStatic(nMMod))) {
+ versionsCompatible = false;
+ rf.findReferencingClassesForMethod(oldClassInfo, oldMethodIdx);
+ if (!Modifier.isAbstract(oMMod) && Modifier.isAbstract(nMMod)) {
+ rf.findConcreteSubclassesNotOverridingAbstractMethod(oldClassInfo, newClassInfo, oldMethodIdx);
+ }
+ }
+ if (!Modifier.isFinal(oMMod) && Modifier.isFinal(nMMod)) {
+ versionsCompatible = false;
+ rf.findSubclassesReimplementingMethod(oldClassInfo, oldMethodIdx);
+ }
+ }
+
+ /**
+ * Returns true if any subclass(es), direct or indirect, declare a method with name methodName.
+ * For each such occurence, referencing classes are looked up and added to the list of affected classes.
+ */
+ private boolean subclassesDeclareSameNameMethod(ClassInfo oldClassInfo, String methodName) {
+ boolean res = false;
+ ClassInfo[] directSubclasses = oldClassInfo.getDirectSubclasses();
+ for (int i = 0; i < directSubclasses.length; i++) {
+ ClassInfo subclass = directSubclasses[i];
+ int methNo = subclass.declaresSameNameMethod(methodName);
+ if (methNo >= 0) {
+ rf.addToAffectedClassNames(subclass.name);
+ rf.findReferencingClassesForMethod(subclass, methNo);
+ res = true;
+ }
+ if (subclassesDeclareSameNameMethod(subclass, methodName)) {
+ res = true;
+ }
+ }
+ return res;
+ }
+}
« no previous file with comments | « third_party/jmake/src/org/pantsbuild/jmake/ClassPath.java ('k') | third_party/jmake/src/org/pantsbuild/jmake/Main.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698