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

Unified Diff: third_party/jmake/src/org/pantsbuild/jmake/ClassInfo.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/ClassInfo.java
diff --git a/third_party/jmake/src/org/pantsbuild/jmake/ClassInfo.java b/third_party/jmake/src/org/pantsbuild/jmake/ClassInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bfcd5a0b218988c2acd36a61690de45e7f9becc
--- /dev/null
+++ b/third_party/jmake/src/org/pantsbuild/jmake/ClassInfo.java
@@ -0,0 +1,746 @@
+/* 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.io.Serializable;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A reflection of a class, in the form that allows fast checks and information obtaining.
+ *
+ * @author Misha Dmitriev
+ * 5 April 2004
+ */
+@SuppressWarnings("serial")
+public class ClassInfo implements Serializable {
+
+ public static final int VER_OLD = 0; // Old version
+ public static final int VER_NEW = 1; // New version
+ public static final int NO_VERSIONS = 2; // Non-project class, no change tracking
+ private transient PCDManager pcdm;
+ transient int verCode; // Version code for this ClassInfo - one of the above.
+ String name = null;
+ transient String packageName; // Package name; restored when database is reloaded
+ int javacTargetRelease = Utils.JAVAC_TARGET_RELEASE_OLDEST; // Can have values from Utils.JAVAC_TARGET_RELEASE_xxx
+ String cpoolRefsToClasses[]; // Directly referenced class names trimmed of array and 'L' prefixes and ';' suffixes
+ boolean isRefClassArray[]; // Indicates if a directly referenced class is actually an array class
+ // In all signatures we replace the 'L' and ';' symbols that enclose non-primitive type names with '@' and '#' respectively,
+ // so that class names inside signatures can be located fast and unambiguously.
+ String cpoolRefsToFieldClasses[]; // Defining classes of referenced fields, trimmed of enclosing 'L' and ';' symbols
+ String cpoolRefsToFieldNames[]; // Names of referenced fields
+ String cpoolRefsToFieldSignatures[]; // Signatures of referenced fields
+ String cpoolRefsToMethodClasses[]; // Defining classes of referenced methods, trimmed of enclosing 'L' and ';' symbols
+ String cpoolRefsToMethodNames[]; // Names of referenced methods
+ String cpoolRefsToMethodSignatures[]; // Signatures of referenced methods
+ char accessFlags; // isInterface flag included
+ boolean isNonMemberNestedClass = false; // True if this is a non-member nested class
+ String superName;
+ String interfaces[];
+ String fieldNames[];
+ String fieldSignatures[];
+ char fieldAccessFlags[];
+ Object primitiveConstantInitValues[];
+ String methodNames[];
+ String methodSignatures[];
+ char methodAccessFlags[];
+ String checkedExceptions[][];
+ transient ClassInfo directSubclasses[]; // Direct subclasses. Created lazily and not preserved on disk.
+ transient String directlyEnclosingClass; // Directly enclosing class name; restored when database is reloaded
+ transient String topLevelEnclosingClass; // Top-level enclosing class name; restored when database is reloaded
+ String nestedClasses[]; // Names of all nested classes. Don't make transient - it's used to check
+ // if nested classes for this class were added/deleted in new version
+ transient char nestedClassAccessFlags[]; // No need to store this information permanently
+ transient boolean nestedClassNonMember[]; // Ditto
+
+ /** Creates new ClassInfo out of a class file. The last parameter is needed only to produce sensible error reports.*/
+ public ClassInfo(byte[] classFileBytes, int verCode, PCDManager pcdm, String classFileFullPath) {
+ this.pcdm = pcdm;
+ this.verCode = verCode;
+ pcdm.getClassFileReader().readClassFile(classFileBytes, this, classFileFullPath, true);
+ packageName = Utils.getPackageName(name);
+ directlyEnclosingClass =
+ Utils.getDirectlyEnclosingClass(name, this.javacTargetRelease);
+ topLevelEnclosingClass = Utils.getTopLevelEnclosingClass(name);
+ }
+
+ /**
+ * Create a "lightweight" ClassInfo, that contains just the class name, super name, interfaces, flags and verCode.
+ * Used for non-project classes, that don't change themselves, for which we are only interested in type hierarchy structure.
+ */
+ public ClassInfo(byte[] classFileBytes, PCDManager pcdm, String classFileFullPath) {
+ this.pcdm = pcdm;
+ this.verCode = NO_VERSIONS;
+ pcdm.getClassFileReader().readClassFile(classFileBytes, this, classFileFullPath, false);
+ packageName = Utils.getPackageName(name);
+ directlyEnclosingClass =
+ Utils.getDirectlyEnclosingClass(name, this.javacTargetRelease);
+ topLevelEnclosingClass = Utils.getTopLevelEnclosingClass(name);
+ }
+
+ /** Even more lightweight variant - created for a deleted non-project class, to enable minimum possible checks. */
+ public ClassInfo(String name, PCDManager pcdm) {
+ this.pcdm = pcdm;
+ this.verCode = NO_VERSIONS;
+ this.name = name;
+ packageName = Utils.getPackageName(name);
+ directlyEnclosingClass = Utils.getDirectlyEnclosingClass(name, 0);
+ topLevelEnclosingClass = Utils.getTopLevelEnclosingClass(name);
+ }
+
+ public ClassInfo() {
+ }
+
+ /** Initialize transient data that can be initialized immediately after this ClassInfo is read from the project database */
+ public void initializeImmediateTransientFields() {
+ verCode = VER_OLD;
+
+ packageName = Utils.getPackageName(name);
+
+ directlyEnclosingClass =
+ Utils.getDirectlyEnclosingClass(name, this.javacTargetRelease);
+ topLevelEnclosingClass = Utils.getTopLevelEnclosingClass(name);
+ }
+
+ /**
+ * Called to restore the pointer to the current PCDManager after this ClassInfo is brought back
+ * from the store.
+ */
+ public void restorePCDM(PCDManager pcdm) {
+ this.pcdm = pcdm;
+ }
+
+ public boolean isInterface() {
+ return Modifier.isInterface(accessFlags);
+ }
+
+ public boolean isAbstract() {
+ return Modifier.isAbstract(accessFlags);
+ }
+
+ public boolean isPublic() {
+ return Modifier.isPublic(accessFlags);
+ }
+
+ /**
+ * Returns the names of the superclasses of the given class (transitively), that belong
+ * to the same project, plus those of the superclasses that can be found on the class path
+ * supplied to jmake, and on the boot class path.
+ */
+ public List<String> getAllSuperclassNames() {
+ List<String> res = new ArrayList<String>();
+ String superName = this.superName;
+ while (superName != null && !"java/lang/Object".equals(superName)) {
+ res.add(superName);
+ ClassInfo classInfo = pcdm.getClassInfoForName(verCode, superName);
+ if (classInfo == null) { // Class not in project (or deleted?). Try to find it and further superclasses in non-project classes
+ ClassPath.getSuperclasses(superName, res, pcdm);
+ break;
+ }
+ superName = classInfo.superName;
+ }
+ return res;
+ }
+
+ /**
+ * Returns the set of names of the interfaces transitively implemented by the given
+ * class, that belong to the same project.
+ */
+ public Set<String> getAllImplementedIntfNames() {
+ Set<String> res = new LinkedHashSet<String>();
+ addImplementedInterfaceNames(false, res);
+ return res;
+ }
+
+ /** Add to the given set the names of direct/all interfaces implemented by the given class. */
+ private void addImplementedInterfaceNames(boolean directOnly,
+ Set<String> intfSet) {
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; i++) {
+ String superIntfName = interfaces[i];
+ intfSet.add(superIntfName);
+ if (directOnly) {
+ continue;
+ }
+ ClassInfo superIntfInfo =
+ pcdm.getClassInfoForName(verCode, superIntfName);
+ if (superIntfInfo == null) { // Class not in project
+ ClassPath.addAllImplementedInterfaceNames(superIntfName, intfSet, pcdm);
+ } else {
+ superIntfInfo.addImplementedInterfaceNames(false, intfSet);
+ }
+ }
+ }
+
+ if (directOnly || superName == null ||
+ "java/lang/Object".equals(superName)) {
+ return;
+ }
+ ClassInfo superInfo = pcdm.getClassInfoForName(verCode, superName);
+ if (superInfo == null) { // Class not in project
+ ClassPath.addAllImplementedInterfaceNames(superName, intfSet, pcdm);
+ } else {
+ superInfo.addImplementedInterfaceNames(false, intfSet);
+ }
+ }
+
+ /** Returns the array of all direct subclasses of this class (array of zero length if there are none). */
+ public ClassInfo[] getDirectSubclasses() {
+ if (directSubclasses != null) {
+ return directSubclasses;
+ }
+
+ List<ClassInfo> listRes = new ArrayList<ClassInfo>();
+
+ for (PCDEntry entry : pcdm.entries()) {
+ ClassInfo classInfo = pcdm.getClassInfoForPCDEntry(verCode, entry);
+ if (classInfo == null) {
+ continue; // New or deleted class, depending on verCode
+ }
+ if (classInfo.superName.equals(name)) {
+ listRes.add(classInfo);
+ }
+ }
+
+ directSubclasses = listRes.toArray(new ClassInfo[listRes.size()]);
+ return directSubclasses;
+ }
+
+ /** Check if the initial values for the given primitive constatnts in two classes are the same. */
+ public static boolean constFieldInitValuesEqual(ClassInfo oldClassInfo, int oldFieldNo,
+ ClassInfo newClassInfo, int newFieldNo) {
+ Object oldInitValue = oldClassInfo.primitiveConstantInitValues == null ? null
+ : oldClassInfo.primitiveConstantInitValues[oldFieldNo];
+ Object newInitValue = newClassInfo.primitiveConstantInitValues == null ? null
+ : newClassInfo.primitiveConstantInitValues[newFieldNo];
+ if (oldInitValue == newInitValue) {
+ return true;
+ }
+ if (oldInitValue == null || newInitValue == null) {
+ return false;
+ }
+
+ if (oldInitValue instanceof Integer) {
+ if (((Integer) oldInitValue).intValue() == ((Integer) newInitValue).intValue()) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (oldInitValue instanceof String) {
+ if ( ((String) oldInitValue).equals((String) newInitValue) ) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (oldInitValue instanceof Long) {
+ if (((Long) oldInitValue).longValue() == ((Long) newInitValue).longValue()) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (oldInitValue instanceof Float) {
+ if (((Float) oldInitValue).floatValue() == ((Float) newInitValue).floatValue()) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (oldInitValue instanceof Double) {
+ if (((Double) oldInitValue).doubleValue() == ((Double) newInitValue).doubleValue()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public boolean implementsInterfaceDirectly(String intfName) {
+ if (interfaces == null) {
+ return false;
+ }
+ for (int i = 0; i < interfaces.length; i++) {
+ if (intfName.equals(interfaces[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Check if this class implements interface I or any subinterface of I directly */
+ public boolean implementsIntfOrSubintfDirectly(String intfName) {
+ if (interfaces == null) {
+ return false;
+ }
+ for (int i = 0; i < interfaces.length; i++) {
+ if (intfName.equals(interfaces[i])) {
+ return true;
+ }
+ // An interface can have multiple superinterfaces, all of which are listed in its "interfaces" array
+ // (although in the .java source it "extends" them all).
+ ClassInfo superIntfInfo =
+ pcdm.getClassInfoForName(verCode, interfaces[i]);
+ if (superIntfInfo == null) {
+ continue; // Class not in project
+ }
+ if (superIntfInfo.implementsIntfOrSubintfDirectly(intfName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Class C implements interface I indirectly, if C or some superclass of C directly implements I
+ * or some subinterface of I.
+ */
+ public boolean implementsInterfaceDirectlyOrIndirectly(String intfName) {
+ if (interfaces == null) {
+ return false;
+ }
+
+ if (implementsIntfOrSubintfDirectly(intfName)) {
+ return true;
+ }
+
+ if (superName != null) {
+ ClassInfo superInfo = pcdm.getClassInfoForName(verCode, superName);
+ if (superInfo == null) {
+ return false; // Class not in project
+ }
+ return superInfo.implementsInterfaceDirectlyOrIndirectly(intfName);
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if this class declares a field with the same name and type as
+ * the field number fieldNo in class classInfo.
+ */
+ public boolean declaresField(ClassInfo classInfo, int fieldNo) {
+ if (fieldNames == null) {
+ return false;
+ }
+ String fieldName = classInfo.fieldNames[fieldNo];
+ String fieldSignature = classInfo.fieldSignatures[fieldNo];
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if (fieldName.equals(fieldNames[i]) &&
+ fieldSignature.equals(fieldSignatures[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Returns true if this class declares a field with the given name, signature and access */
+ public boolean declaresField(String name, String signature, boolean isStatic) {
+ if (fieldNames == null) {
+ return false;
+ }
+ signature = ("@" + signature + "#").intern();
+ for (int i = 0; i < fieldNames.length; i++) {
+ if (name.equals(fieldNames[i]) &&
+ signature.equals(fieldSignatures[i]) &&
+ Modifier.isStatic(fieldAccessFlags[i]) == isStatic) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this class declares a method with the same name and signature as
+ * the method number methodNo in class classInfo.
+ */
+ public boolean declaresMethod(ClassInfo classInfo, int methodNo) {
+ if (methodNames == null) {
+ return false;
+ }
+ String methodName = classInfo.methodNames[methodNo];
+ String methodSignature = classInfo.methodSignatures[methodNo];
+
+ for (int i = 0; i < methodNames.length; i++) {
+ if (methodName.equals(methodNames[i]) &&
+ methodSignature.equals(methodSignatures[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * If this class declares a method with the same name and signature as the given method,
+ * return its position. Otherwise, return -1.
+ */
+ public int getDeclaredMethodPos(ClassInfo classInfo, int methodNo) {
+ if (methodNames == null) {
+ return -1;
+ }
+ String methodName = classInfo.methodNames[methodNo];
+ String methodSignature = classInfo.methodSignatures[methodNo];
+
+ for (int i = 0; i < methodNames.length; i++) {
+ if (methodName.equals(methodNames[i]) &&
+ methodSignature.equals(methodSignatures[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns a nonnegative number (position in the method array) if this class declares a method with the
+ * name methodName, and -1 otherwise.
+ */
+ public int declaresSameNameMethod(String methodName) {
+ if (methodNames == null) {
+ return -1;
+ }
+ for (int j = 0; j < methodNames.length; j++) {
+ if (methodName.equals(methodNames[j])) {
+ return j;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Check if this class references the given class in different ways, depending on thorDegree parameter.
+ * thorDegree = 0: the given class (but not its array class) directly from the constantpool.
+ *
+ * thorDegree = 1: the given class or its array class directly from the constantpool, 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
+ *
+ * thorDegree = 2: the given class or its array class 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.
+ *
+ * isRefTypeInterface indicates whether className is an interface.
+ */
+ public boolean referencesClass(String className, boolean isRefTypeInterface, int thorDegree) {
+ int i;
+
+ if (thorDegree == 0) {
+ if (cpoolRefsToClasses == null) {
+ return false;
+ }
+ for (i = 0; i < cpoolRefsToClasses.length; i++) {
+ if (!isRefClassArray[i] &&
+ className.equals(cpoolRefsToClasses[i])) {
+ return true;
+ }
+ }
+ } else {
+ if (isSubclassOf(className, (thorDegree == 1))) {
+ return true;
+ }
+ if (isRefTypeInterface) {
+ if (thorDegree == 1) {
+ if (implementsInterfaceDirectly(className)) {
+ return true;
+ }
+ } else {
+ // Check for indirectly implemented interfaces
+ if (implementsInterfaceDirectlyOrIndirectly(className)) {
+ return true;
+ }
+ }
+ }
+
+ if (cpoolRefsToClasses != null) {
+ for (i = 0; i < cpoolRefsToClasses.length; i++) {
+ if (className.equals(cpoolRefsToClasses[i])) {
+ return true;
+ }
+ }
+ }
+ if (thorDegree == 2) {
+ // Check for indirect references from the constantpool
+ if (cpoolRefsToFieldSignatures != null) {
+ for (i = 0; i < cpoolRefsToFieldSignatures.length; i++) {
+ if (signatureIncludesClassName(cpoolRefsToFieldSignatures[i], className)) {
+ return true;
+ }
+ }
+ }
+ if (cpoolRefsToMethodNames != null) {
+ for (i = 0; i < cpoolRefsToMethodSignatures.length; i++) {
+ if (signatureIncludesClassName(cpoolRefsToMethodSignatures[i], className)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ if (fieldSignatures != null) {
+ for (i = 0; i < fieldSignatures.length; i++) {
+ if (signatureIncludesClassName(fieldSignatures[i], className)) {
+ return true;
+ }
+ }
+ }
+ if (methodSignatures != null) {
+ for (i = 0; i < methodSignatures.length; i++) {
+ if (signatureIncludesClassName(methodSignatures[i], className)) {
+ return true;
+ }
+ }
+ }
+ if (checkedExceptions != null) {
+ for (i = 0; i < checkedExceptions.length; i++) {
+ if (checkedExceptions[i] != null) {
+ String excArray[] = checkedExceptions[i];
+ for (int j = 0; j < excArray.length; j++) {
+ if (className.equals(excArray[j])) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean signatureIncludesClassName(String signature, String className) {
+ int stIndex = signature.indexOf(className);
+ if (stIndex == -1) {
+ return false;
+ }
+ return ((stIndex != 0 && signature.charAt(stIndex - 1) == '@' && signature.charAt(stIndex + className.length()) == '#') ||
+ (stIndex == 0 && signature.length() == className.length()));
+ }
+
+ public boolean isSubclassOf(String className, boolean directOnly) {
+ if (className.equals(superName)) {
+ return true;
+ }
+ if (directOnly) {
+ return false;
+ }
+ String superName = this.superName;
+ while (superName != null) {
+ if (className.equals(superName)) {
+ return true;
+ }
+ ClassInfo classInfo = pcdm.getClassInfoForName(verCode, superName);
+ if (classInfo == null) {
+ break; // Class not in project
+ }
+ superName = classInfo.superName;
+ }
+ return false;
+ }
+
+ /**
+ * Check if this class references field number fieldNo of class fieldDefClassInfo. Let us call
+ * this field C.f. Actual reference contained in the constant pool may be not to C.f itself,
+ * but to Csub.f, where Csub is some subclass of C such that neither Csub nor any other class
+ * located between C and Csub in the class hierarchy redeclares f. We look up both "real"
+ * references C.f and "fake" references such as Csub.f.
+ */
+ public boolean referencesField(ClassInfo fieldDefClassInfo, int fieldNo) {
+ if (cpoolRefsToFieldNames == null) {
+ return false;
+ }
+ String fieldDefClassName = fieldDefClassInfo.name;
+ String fieldName = fieldDefClassInfo.fieldNames[fieldNo];
+ String fieldSig = fieldDefClassInfo.fieldSignatures[fieldNo];
+ for (int i = 0; i < cpoolRefsToFieldNames.length; i++) {
+ if (fieldName.equals(cpoolRefsToFieldNames[i]) &&
+ fieldSig.equals(cpoolRefsToFieldSignatures[i]) ) {
+ if (fieldDefClassName.equals(cpoolRefsToFieldClasses[i]) ) {
+ return true; // "real" reference
+ } else { // Check if this is a "fake" reference that resolves to the above "real" reference
+ ClassInfo classInThisCpool =
+ pcdm.getClassInfoForName(verCode, cpoolRefsToFieldClasses[i]);
+ if (classInThisCpool == null) {
+ continue; // Class not in project
+ }
+ if (!classInThisCpool.isSubclassOf(fieldDefClassInfo.name, false)) {
+ continue;
+ }
+
+ // Ok, now check that this field is not actually redeclared in fieldDefClassInfo or
+ // somewhere in between it and classInThisCpool
+ boolean redeclared = false;
+ ClassInfo curClass = classInThisCpool;
+ do {
+ if (curClass.declaresField(fieldDefClassInfo, fieldNo)) {
+ redeclared = true;
+ break;
+ }
+ String superName = curClass.superName;
+ curClass = pcdm.getClassInfoForName(verCode, superName);
+ if (curClass == null) {
+ break;
+ }
+ } while (curClass != fieldDefClassInfo);
+ if (!redeclared) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if this class references method number methodNo of class methodDefClassInfo. Let us
+ * call this method C.m. Actual reference contained in the constant pool may be not to C.m
+ * itself, but to Csub.m, where Csub is some subclass of C such that neither Csub nor any
+ * other class located between C and Csub in the class hierarchy redeclares m. We look up
+ * both "real" references C.m and "fake" references such as Csub.m.
+ */
+ public boolean referencesMethod(ClassInfo methodDefClassInfo, int methodNo) {
+ if (cpoolRefsToMethodNames == null) {
+ return false;
+ }
+ String methodDefClassName = methodDefClassInfo.name;
+ String methodName = methodDefClassInfo.methodNames[methodNo];
+ String methodSig = methodDefClassInfo.methodSignatures[methodNo];
+ for (int i = 0; i < cpoolRefsToMethodNames.length; i++) {
+ if (methodName.equals(cpoolRefsToMethodNames[i]) &&
+ methodSig.equals(cpoolRefsToMethodSignatures[i])) {
+ if (methodDefClassName.equals(cpoolRefsToMethodClasses[i])) {
+ return true; // "real" reference
+ } else { // Check if this is a "fake" reference that resolves to the above "real" reference
+ // Be careful - class in the cpool may be not a project class (e.g. a core class).
+ ClassInfo classInThisCpool =
+ pcdm.getClassInfoForName(verCode, cpoolRefsToMethodClasses[i]);
+ if (classInThisCpool == null) {
+ continue; // Class not in project
+ }
+ if (classInThisCpool.isSubclassOf(methodDefClassInfo.name, false)) {
+ // Ok, now check that this method is not actually redeclared in classInThisCpool (which is
+ // lower in the hierarchy) or somewhere in between it and classInThisCpool
+ boolean redeclared = false;
+ ClassInfo curClass = classInThisCpool;
+ do {
+ if (curClass.declaresMethod(methodDefClassInfo, methodNo)) {
+ redeclared = true;
+ break;
+ }
+ String superName = curClass.superName;
+ curClass =
+ pcdm.getClassInfoForName(verCode, superName);
+ if (curClass == null) {
+ break;
+ }
+ } while (curClass != methodDefClassInfo);
+ if (!redeclared) {
+ return true;
+ }
+ } else if (methodDefClassInfo.isInterface() && classInThisCpool.implementsIntfOrSubintfDirectly(methodDefClassName)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * If this class has a method that throws the given exception, return its index. Otherwise return -1.
+ * The search starts from method with index startMethodIdx.
+ */
+ public int hasMethodThrowingException(ClassInfo excClassInfo, int startMethodIdx) {
+ if (checkedExceptions == null) {
+ return -1;
+ }
+ if (startMethodIdx >= checkedExceptions.length) {
+ return -1;
+ }
+ String excName = excClassInfo.name;
+ for (int i = startMethodIdx; i < checkedExceptions.length; i++) {
+ if (checkedExceptions[i] == null) {
+ continue;
+ }
+ String[] exc = checkedExceptions[i];
+ for (int j = 0; j < exc.length; j++) {
+ if (exc[j].equals(excName)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public static abstract class MethodHandler {
+
+ abstract void handleMethod(ClassInfo ci, int methodIdx);
+ }
+
+ /**
+ * Check this class and all its superclasses (if includeSuperclasses == true) and superinterfaces (if includeInterfaces == true)
+ * for a method with the given name. If such a method is found, call h.handleMethod(classInfo, methodIdx).
+ */
+ public void findExistingSameNameMethods(String methodName, boolean includeSuperclasses, boolean includeInterfaces, MethodHandler h) {
+ String className = name;
+ ClassInfo classInfo;
+ while (className != null) {
+ classInfo = pcdm.getClassInfoForName(verCode, className);
+ if (classInfo == null) {
+ break; // Class not in project
+ }
+ String mNames[] = classInfo.methodNames;
+ int mNamesLen = mNames != null ? mNames.length : 0;
+ for (int i = 0; i < mNamesLen; i++) {
+ if (methodName.equals(mNames[i])) {
+ h.handleMethod(classInfo, i);
+ }
+ }
+ if (includeInterfaces && classInfo.interfaces != null) {
+ String intfNames[] = classInfo.interfaces;
+ for (int i = 0; i < intfNames.length; i++) {
+ ClassInfo superIntfInfo =
+ pcdm.getClassInfoForName(verCode, intfNames[i]);
+ if (superIntfInfo == null) {
+ continue; // Class not in project
+ }
+ superIntfInfo.findExistingSameNameMethods(methodName, true, includeInterfaces, h);
+ }
+ }
+ if (includeSuperclasses) {
+ className = classInfo.superName;
+ } else {
+ return;
+ }
+ }
+ }
+
+ public static boolean isPrimitiveFieldSig(String fieldSig) {
+ return fieldSig.indexOf('@') == -1;
+ }
+
+ /**
+ * Check if the given signature is of a class type, and that class does not belong to the project.
+ * It used to be a check for just a core type name, but sometimes people use JDK sources as e.g. a test
+ * case - so better perform a universal (and entirely correct, unlike just a core type name) test here.
+ */
+ public boolean isNonProjectClassTypeFieldSig(String fieldSig) {
+ int stPos = fieldSig.indexOf('@');
+ if (stPos == -1) {
+ return false;
+ }
+ int endPos = fieldSig.indexOf('#');
+ String className = fieldSig.substring(stPos + 1, endPos);
+ return (!pcdm.isProjectClass(verCode, className));
+ }
+
+ /** For debugging. */
+ public String toString() {
+ return name + (verCode == VER_OLD ? " OLD" : " NEW");
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698