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

Unified Diff: third_party/jmake/src/org/pantsbuild/jmake/RefClassFinder.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/RefClassFinder.java
diff --git a/third_party/jmake/src/org/pantsbuild/jmake/RefClassFinder.java b/third_party/jmake/src/org/pantsbuild/jmake/RefClassFinder.java
new file mode 100644
index 0000000000000000000000000000000000000000..58c8884ab55b445e2e71cd51d44f3f62a887536a
--- /dev/null
+++ b/third_party/jmake/src/org/pantsbuild/jmake/RefClassFinder.java
@@ -0,0 +1,697 @@
+/* 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.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * This class implements finding classes referencing other classes and members in various ways.
+ *
+ * @author Misha Dmitriev
+ * 12 March 2004
+ */
+public class RefClassFinder {
+
+ private boolean failOnDependentJar; // If true, will fail if a dependency of a sourceless class
+ // (coming from a .jar) on a "normal" class is detected
+ private boolean noWarnOnDependentJar; // If true, not even a warning will be issued in the above case.
+ private String checkedClassName;
+ private PCDManager pcdm;
+ private Set<String> affectedClassNames;
+ private boolean checkedClassIsFromJar;
+
+ /** An instance of RefClassFinder is created once per session, passing it the global options that do not change */
+ public RefClassFinder(PCDManager pcdm, boolean failOnDependentJar, boolean noWarnOnDependentJar) {
+ this.pcdm = pcdm;
+ this.failOnDependentJar = failOnDependentJar;
+ this.noWarnOnDependentJar = noWarnOnDependentJar;
+ }
+
+ /** This method is called every time we are going to check a new class */
+ public void initialize(String checkedClassName, boolean checkedClassIsFromJar) {
+ this.checkedClassName = checkedClassName;
+ this.checkedClassIsFromJar = checkedClassIsFromJar;
+ affectedClassNames = new LinkedHashSet<String>();
+ }
+
+ /**
+ * Returns the names of project classes that were found potentially affec
+ * by the changes to the checked class.
+ */
+ public String[] getAffectedClassNames() {
+ int size = affectedClassNames.size();
+ if (size == 0) {
+ return null;
+ } else {
+ String[] ret = new String[size];
+ int i = 0;
+ for (String className : affectedClassNames) {
+ ret[i++] = className;
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * Find all project classes that can access field fieldNo of class fieldClassInfo.
+ * Used if a compile-time constant is changed.
+ */
+ public void findAllProjectClasses(ClassInfo fieldClassInfo, int fieldNo) {
+ for (PCDEntry pcde : pcdm.entries()) {
+ if (pcde.checkResult == PCDEntry.CV_DELETED) {
+ continue;
+ }
+ if (pcde.javaFileFullPath.endsWith(".jar")) {
+ continue;
+ }
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (memberAccessibleFrom(fieldClassInfo, fieldNo, clientInfo, true)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+
+ /**
+ * Find all project classes that reference class with the given name
+ * (but not its array class) directly from the constantpool.
+ */
+ public void findReferencingClasses0(ClassInfo classInfo) {
+ findReferencingClasses(classInfo, 0, false, null);
+ }
+
+
+ /* In the following "find...ReferencingClasses1" methods, "referencing C" means
+ * "referencing C or its array class directly from the constant pool, as a type of a data
+ * field, as a type in a method signature or a thrown exception, as a directly implemented
+ * interface or a direct superclass".
+ */
+ /** Used for deleted classes. */
+ public void findReferencingClassesForDeletedClass(ClassInfo classInfo) {
+ String packageName = classInfo.packageName;
+ boolean isPublic = classInfo.isPublic();
+ boolean isInterface = classInfo.isInterface();
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (!isPublic && packageName.equals(clientInfo.packageName)) {
+ continue;
+ }
+ if (clientInfo.referencesClass(classInfo.name, isInterface, 1)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+
+ }
+
+ /**
+ * For the given class p.C, find each project class X referencing C, that is not a member of
+ * package p and is not a direct or indirect subclass of C's directly enclosing class.
+ * (public -&gt; protected transformation)
+ */
+ public void findDiffPackageAndNotSubReferencingClasses1(ClassInfo classInfo) {
+ String packageName = classInfo.packageName;
+ String directlyEnclosingClass = classInfo.directlyEnclosingClass;
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (packageName.equals(clientInfo.packageName) ||
+ clientInfo.isSubclassOf(directlyEnclosingClass, false)) {
+ continue;
+ }
+ if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface(), 1)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+
+ /**
+ * For class p.C, find each project class X referencing C, whose top level enclosing
+ * class is different from that of C.
+ * (public -&gt; private transformation)
+ */
+ public void findReferencingClasses1(ClassInfo classInfo) {
+ String topLevelEnclosingClass = classInfo.topLevelEnclosingClass;
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (topLevelEnclosingClass.equals(clientInfo.topLevelEnclosingClass)) {
+ continue;
+ }
+ if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface(), 1)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+
+ /**
+ * For class p.C, find each project class X referencing C, whose direct or indirect superclass
+ * is C's directly enclosing class, or which is a member of package p, whose top level enclosing
+ * class is different from that of C.
+ * (protected -&gt; private transformation)
+ */
+ public void findThisPackageOrSubReferencingClasses1(ClassInfo classInfo) {
+ String directlyEnclosingClass = classInfo.directlyEnclosingClass;
+ String topLevelEnclosingClass = classInfo.topLevelEnclosingClass;
+ String packageName = classInfo.packageName;
+ for (PCDEntry entry : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, entry);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if ((!clientInfo.packageName.equals(packageName)) &&
+ !clientInfo.isSubclassOf(directlyEnclosingClass, false)) {
+ continue;
+ }
+ if (clientInfo.topLevelEnclosingClass.equals(topLevelEnclosingClass)) {
+ continue;
+ }
+ if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface(), 1)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+
+ /**
+ * For class p.C, find each project class X referencing C, which is a member of package p and whose
+ * top level enclosing class is different from that of C.
+ * (default -&gt; private transformation)
+ */
+ public void findThisPackageReferencingClasses1(ClassInfo classInfo) {
+ String topLevelEnclosingClass = classInfo.topLevelEnclosingClass;
+ String packageName = classInfo.packageName;
+ for (PCDEntry entry : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD,
+ entry);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (!clientInfo.packageName.equals(packageName)) {
+ continue;
+ }
+ if (topLevelEnclosingClass.equals(clientInfo.topLevelEnclosingClass)) {
+ continue;
+ }
+ if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface(), 1)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+
+ /**
+ * For class p.C, find each project class X referencing C, which is not a member of package p.
+ * (public -&gt; default transformation)
+ */
+ public void findDiffPackageReferencingClasses1(ClassInfo classInfo) {
+ String packageName = classInfo.packageName;
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (clientInfo.packageName.equals(packageName)) {
+ continue;
+ }
+ if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface(), 1)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+
+ /**
+ * For class p.C, find each project class X referencing C, which is not a member of package p and
+ * whose direct or indirect superclass is C's directly enclosing class.
+ * (protected -&gt; default transformation)
+ */
+ public void findDiffPackageAndSubReferencingClasses1(ClassInfo classInfo) {
+ String packageName = classInfo.packageName;
+ String directlyEnclosingClass = classInfo.directlyEnclosingClass;
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (clientInfo.packageName.equals(packageName)) {
+ continue;
+ }
+ if (!clientInfo.isSubclassOf(directlyEnclosingClass, false)) {
+ continue;
+ }
+ if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface(), 1)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+
+ /**
+ * Find all project classes that reference both of the classes with the
+ * given names (or array classes of one or both) directly or indirectly from the
+ * constantpool, as a type of a data field, as a type in a method signature or a
+ * thrown exception, as a directly/indirectly implemented interface or a
+ * direct/indirect superclass.
+ */
+ public void findReferencingClasses2(ClassInfo classInfo1, ClassInfo classInfo2) {
+ Set<String> refClazz1 = new LinkedHashSet<String>();
+ findReferencingClasses(classInfo1, 2, false, refClazz1);
+ Set<String> refClazz2 = new LinkedHashSet<String>();
+ findReferencingClasses(classInfo2, 2, false, refClazz2);
+
+ for (String className1 : refClazz1) {
+ if (refClazz2.contains(className1)) {
+ addToAffectedClassNames(className1);
+ }
+ }
+ }
+
+ /** Find all project classes which are direct subclasses of the given class */
+ public void findDirectSubclasses(ClassInfo classInfo) {
+ for (ClassInfo subclassInfo : classInfo.getDirectSubclasses()) {
+ addToAffectedClassNames(subclassInfo.name);
+ }
+ }
+
+ /**
+ * Find all non-abstract project classes that implement the given interface or any of its
+ * subclasses directly, and all non-abstract classes that are direct descendants of abstract
+ * classes that implement the given interface directly or indirectly. Class C implements
+ * interface I indirectly, if C or some superclass of C directly implements I or some sublcass of I.
+ */
+ public void findDirectlyAndOtherwiseImplementingConcreteClasses(ClassInfo intfInfo) {
+ for (PCDEntry entry : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, entry);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (clientInfo.isInterface()) {
+ continue;
+ }
+ if (clientInfo.isAbstract()) {
+ if (clientInfo.implementsInterfaceDirectlyOrIndirectly(intfInfo.name)) {
+ findAllNearestConcreteSubclasses(clientInfo);
+ }
+ } else {
+ if (clientInfo.implementsIntfOrSubintfDirectly(intfInfo.name)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+ }
+
+ private void findAllNearestConcreteSubclasses(ClassInfo classInfo) {
+ for (ClassInfo subclassInfo : classInfo.getDirectSubclasses()) {
+ if (subclassInfo.isAbstract()) {
+ findAllNearestConcreteSubclasses(subclassInfo);
+ } else {
+ addToAffectedClassNames(subclassInfo.name);
+ }
+ }
+ }
+
+ /**
+ * Find all interfaces and abstract classes that implement the given interface and declare or inherit
+ * a method with the given name. For those that overload this method, find referencing classes.
+ */
+ public void findAbstractSubtypesWithSameNameMethod(ClassInfo intfInfo, String mName, final String mSig) {
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo ci =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (ci == null) {
+ continue; // New class or not in project
+ }
+ if (!(ci.isInterface() || ci.isAbstract())) {
+ continue;
+ }
+ if (ci.implementsInterfaceDirectlyOrIndirectly(intfInfo.name)) {
+ addToAffectedClassNames(ci.name);
+ // 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.
+ ci.findExistingSameNameMethods(mName, true, true, new ClassInfo.MethodHandler() {
+
+ void handleMethod(ClassInfo classInfo, int otherMethodIdx) {
+ String otherMSig =
+ classInfo.methodSignatures[otherMethodIdx];
+ if ( (!mSig.equals(otherMSig)) &&
+ Utils.sameParamNumber(mSig, otherMSig)) {
+ findReferencingClassesForMethod(classInfo, otherMethodIdx);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ /** Find all project classes that reference the given field. */
+ public void findReferencingClassesForField(ClassInfo classInfo, int fieldNo) {
+ findReferencingClassesForMember(classInfo, fieldNo, true, false, false);
+ }
+
+ /**
+ * Find all project classes that reference the given field and which are in
+ * different packages.
+ */
+ public void findDiffPackageReferencingClassesForField(ClassInfo classInfo, int fieldNo) {
+ findReferencingClassesForMember(classInfo, fieldNo, true, true, false);
+ }
+
+ /**
+ * Find all project classes that reference the given field, which are in different
+ * packages and are direct or indirect subclasses of the member's declaring class
+ * (protected -&gt; default transformation).
+ */
+ public void findDiffPackageAndSubReferencingClassesForField(ClassInfo classInfo, int fieldNo) {
+ findReferencingClassesForMember(classInfo, fieldNo, true, true, true);
+ }
+
+ /** Find all project classes that reference the given method. */
+ public void findReferencingClassesForMethod(ClassInfo classInfo, int methodNo) {
+ findReferencingClassesForMember(classInfo, methodNo, false, false, false);
+ }
+
+ /**
+ * Find all project classes that reference the given method and which are in
+ * different packages.
+ */
+ public void findDiffPackageReferencingClassesForMethod(ClassInfo classInfo, int methodNo) {
+ findReferencingClassesForMember(classInfo, methodNo, false, true, false);
+ }
+
+ /**
+ * Find all project classes that reference the given method, which are in different
+ * packages and are direct or indirect subclasses of the member's declaring class
+ * (protected -&gt; default transformation)
+ */
+ public void findDiffPackageAndSubReferencingClassesForMethod(ClassInfo classInfo, int methodNo) {
+ findReferencingClassesForMember(classInfo, methodNo, false, true, true);
+ }
+
+ /**
+ * Find all project classes that re-implement the given method and that are
+ * direct/indirect subclasses of this method's declaring class. If some subclass C
+ * re-implements the given method, we don't have to search C's subclasses further.
+ */
+ public void findSubclassesReimplementingMethod(ClassInfo classInfo, int methodNo) {
+ findSubclassesReimplementingMethod(classInfo, classInfo, methodNo);
+ }
+
+ private void findSubclassesReimplementingMethod(ClassInfo targetClass, ClassInfo methodDeclaringClass, int methodNo) {
+ for (ClassInfo subclass : targetClass.getDirectSubclasses()) {
+ if (subclass.declaresMethod(methodDeclaringClass, methodNo)) {
+ addToAffectedClassNames(subclass.name);
+ } else {
+ findSubclassesReimplementingMethod(subclass, methodDeclaringClass, methodNo);
+ }
+ }
+ }
+
+ /**
+ * For a given class C, find all concrete direct subclasses, and all direct concrente subclasses of C's direct
+ * or indirect abstract subclasses.
+ */
+ public void findConcreteSubclasses(ClassInfo targetClass) {
+ for (ClassInfo subclass : targetClass.getDirectSubclasses()) {
+ if (subclass.isAbstract()) {
+ findConcreteSubclasses(subclass);
+ } else {
+ addToAffectedClassNames(subclass.name);
+ }
+ }
+ }
+
+ /**
+ * Find any concrete subclasses of targetClass that don't override or inherit a concrete implementation
+ * of the given method.
+ */
+ public void findConcreteSubclassesNotOverridingAbstractMethod(ClassInfo targetClass, ClassInfo methodDeclaringClass, int methodNo) {
+ for (ClassInfo subclass : targetClass.getDirectSubclasses()) {
+ int pos =
+ subclass.getDeclaredMethodPos(methodDeclaringClass, methodNo);
+ if (pos == -1) { // This method is not overridden in this class
+ if (!subclass.isAbstract()) {
+ addToAffectedClassNames(subclass.name);
+ } else {
+ findConcreteSubclassesNotOverridingAbstractMethod(subclass, methodDeclaringClass, methodNo);
+ }
+ } else { // A chance that this method is declared abstract once again...
+ if (Modifier.isAbstract(subclass.methodAccessFlags[pos])) {
+ findConcreteSubclassesNotOverridingAbstractMethod(subclass, methodDeclaringClass, methodNo);
+ }
+ }
+ }
+ }
+
+ /** Find all project classes that reference any method that throws the given exception. */
+ public void findRefsToMethodsThrowingException(ClassInfo excClassInfo) {
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo classInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (classInfo == null) {
+ continue; // New class
+ }
+ int methodIdx = -1;
+ do {
+ methodIdx =
+ classInfo.hasMethodThrowingException(excClassInfo, methodIdx + 1);
+ if (methodIdx != -1) {
+ findReferencingClassesForMethod(classInfo, methodIdx);
+ }
+ } while (methodIdx != -1);
+ }
+ }
+
+ /**
+ * Find all project classes declaring a static field with the given name. Currently used only to look up
+ * classes referencing given class X via the "X.class" construct.
+ */
+ public void findClassesDeclaringField(String name, String signature, boolean isStatic, String packageToLookIn) {
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo classInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (classInfo == null) {
+ continue; // New class
+ }
+ if (packageToLookIn != null &&
+ !classInfo.packageName.equals(packageToLookIn)) {
+ continue;
+ }
+ if (classInfo.declaresField(name, signature, isStatic)) {
+ addToAffectedClassNames(classInfo.name);
+ }
+ }
+ }
+
+ public void addToAffectedClassNames(String className) {
+ String res = pcdm.classAlreadyRecompiledOrUncompileable(className);
+ if (res == null) {
+ affectedClassNames.add(className);
+ } else if (!"".equals(res)) { // The dependent class comes from a .jar.
+ if (checkedClassIsFromJar || noWarnOnDependentJar) {
+ return;
+ }
+ String message = "Class " + className + " is affected by a change to " + checkedClassName + ", but can't be recompiled, " +
+ "since it is located in archive " + res;
+ if (failOnDependentJar) {
+ throw new PrivateException(new PublicExceptions.JarDependsOnSourceException(message));
+ } else {
+ Utils.printWarningMessage("Warning: " + message);
+ }
+ }
+ }
+
+ /**
+ * Find all project classes that reference the class with the given name.
+ * The second parameter controls the "thoroughness degree", and its value is passed to ClassInfo.referencesClass()
+ * method (see the comment to it). The fromDiffPackages parameter defines whether all such classes
+ * or only classes from different packages are required.
+ */
+ private void findReferencingClasses(ClassInfo classInfo,
+ int thorDegree, boolean fromDiffPackages,
+ Set<String> ret) {
+ String packageName = classInfo.packageName;
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ if (fromDiffPackages && packageName.equals(clientInfo.packageName)) {
+ continue;
+ }
+ // If thorDegree == 2, i.e. indirect references from the constantpool (e.g. a reference to a method which
+ // has classInfo as one of its formal parameter types) are taken into account, then we should check all of
+ // the classes, whether classInfo is directly accessible from them or not.
+ if (thorDegree != 2 && (!classAccessibleFrom(classInfo, clientInfo))) {
+ continue;
+ }
+
+ if (clientInfo.referencesClass(classInfo.name, classInfo.isInterface(), thorDegree)) {
+ if (ret == null) {
+ addToAffectedClassNames(clientInfo.name);
+ } else {
+ ret.add(clientInfo.name);
+ }
+ }
+ }
+ }
+
+ /**
+ * Find all project classes that reference the given member. If fromDiffPackages
+ * is true, then only classes that do not belong to the package of the member's
+ * declaring class should be returned. If onlySubclasses is true, then only
+ * classes that are subclasses of member's declaring class should be returned.
+ */
+ private void findReferencingClassesForMember(ClassInfo declaringClassInfo, int memberNo,
+ boolean isField,
+ boolean fromDiffPackages, boolean onlySubclasses) {
+ String declaringClassName = declaringClassInfo.name;
+ String declaringClassPackage = declaringClassInfo.packageName;
+ for (PCDEntry pcde : pcdm.entries()) {
+ ClassInfo clientInfo =
+ pcdm.getClassInfoForPCDEntry(ClassInfo.VER_OLD, pcde);
+ if (clientInfo == null) {
+ continue; // New class
+ }
+ String className = clientInfo.name;
+ if (className.equals(declaringClassName)) {
+ continue;
+ }
+ if (!memberAccessibleFrom(declaringClassInfo, memberNo, clientInfo, isField)) {
+ continue;
+ }
+ if (fromDiffPackages &&
+ declaringClassPackage.equals(clientInfo.packageName)) {
+ continue;
+ }
+ if (onlySubclasses && !clientInfo.isSubclassOf(declaringClassName, false)) {
+ continue;
+ }
+
+ if (isField) {
+ if (clientInfo.referencesField(declaringClassInfo, memberNo)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ } else {
+ if (clientInfo.referencesMethod(declaringClassInfo, memberNo)) {
+ addToAffectedClassNames(clientInfo.name);
+ }
+ }
+ }
+ }
+
+ /** Checks if class classInfo is accessible from class clientClassInfo. */
+ private boolean classAccessibleFrom(ClassInfo classInfo, ClassInfo clientClassInfo) {
+ char classFlags = classInfo.accessFlags;
+ String classPackage = classInfo.packageName;
+ String clientClassPackage = clientClassInfo.packageName;
+
+ if (Modifier.isPublic(classFlags)) {
+ return true;
+ } else if (Modifier.isProtected(classFlags)) {
+ if (classPackage.equals(clientClassPackage) ||
+ clientClassInfo.isSubclassOf(classInfo.directlyEnclosingClass, false)) {
+ return true;
+ }
+ } else if (Modifier.isPrivate(classFlags)) {
+ if (classInfo.topLevelEnclosingClass.equals(clientClassInfo.topLevelEnclosingClass)) {
+ return true;
+ }
+ } else {
+ if (classPackage.equals(clientClassPackage)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if member memberNo (which is a field if isField == true, and method otherwise) of class memberClassInfo is
+ * accessible from class clientClassInfo.
+ */
+ private boolean memberAccessibleFrom(ClassInfo memberClassInfo,
+ int memberNo, ClassInfo clientClassInfo, boolean isField) {
+ char memberClassFlags = memberClassInfo.accessFlags;
+ char memberFlags = isField ? memberClassInfo.fieldAccessFlags[memberNo]
+ : memberClassInfo.methodAccessFlags[memberNo];
+ String memberClassPackage = memberClassInfo.packageName;
+ String clientClassPackage = clientClassInfo.packageName;
+
+ if (Modifier.isPublic(memberClassFlags)) {
+ if (Modifier.isPublic(memberFlags)) {
+ return true;
+ } else if (Modifier.isProtected(memberFlags) &&
+ (memberClassPackage.equals(clientClassPackage) ||
+ clientClassInfo.isSubclassOf(memberClassInfo.name, false))) {
+ return true;
+ } else if (Modifier.isPrivate(memberFlags)) {
+ if (memberClassInfo.topLevelEnclosingClass.equals(
+ clientClassInfo.topLevelEnclosingClass)) {
+ return true;
+ }
+ } else if (memberClassPackage.equals(clientClassPackage)) {
+ return true;
+ }
+ } else if (Modifier.isProtected(memberClassFlags)) {
+ if (!(memberClassPackage.equals(clientClassPackage) ||
+ clientClassInfo.isSubclassOf(memberClassInfo.directlyEnclosingClass, false))) {
+ return true;
+ }
+ if (Modifier.isPublic(memberFlags) ||
+ Modifier.isProtected(memberFlags)) {
+ return true;
+ } else if (Modifier.isPrivate(memberFlags)) {
+ if (memberClassInfo.topLevelEnclosingClass.equals(
+ clientClassInfo.topLevelEnclosingClass)) {
+ return true;
+ }
+ } else {
+ if (memberClassPackage.equals(clientClassPackage)) {
+ return true;
+ }
+ }
+ } else if (Modifier.isPrivate(memberClassFlags)) {
+ if (memberClassInfo.topLevelEnclosingClass.equals(
+ clientClassInfo.topLevelEnclosingClass)) {
+ return true;
+ }
+ } else { // memberClassInfo is package-private
+ if (!memberClassPackage.equals(clientClassPackage)) {
+ return false;
+ }
+ if (Modifier.isPublic(memberFlags) || Modifier.isProtected(memberFlags)) {
+ return true;
+ } else if (Modifier.isPrivate(memberFlags)) {
+ if (memberClassInfo.topLevelEnclosingClass.equals(
+ clientClassInfo.topLevelEnclosingClass)) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698