196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Projectpackage jdiff;
296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Projectimport java.util.*;
496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project/**
696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * This class contains method to compare two API objects.
796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * The differences are stored in an APIDiff object.
896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project *
996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * See the file LICENSE.txt for copyright details.
1096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * @author Matthew Doar, mdoar@pobox.com
1196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */
1296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Projectpublic class APIComparator {
1396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
1496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
1596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Top-level object representing the differences between two APIs.
1696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * It is this object which is used to generate the report later on.
1796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
1896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public APIDiff apiDiff;
1996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
2096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
2196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Package-level object representing the differences between two packages.
2296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * This object is also used to determine which file to write documentation
2396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * differences into.
2496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
2596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public PackageDiff pkgDiff;
2696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
2796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /** Default constructor. */
2896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public APIComparator() {
2996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        apiDiff = new APIDiff();
3096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
3196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
3296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /** For easy local access to the old API object. */
3396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    private static API oldAPI_;
3496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /** For easy local access to the new API object. */
3596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    private static API newAPI_;
3696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
3796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
3896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Compare two APIs.
3996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
4096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public void compareAPIs(API oldAPI, API newAPI) {
4196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        System.out.println("JDiff: comparing the old and new APIs ...");
4296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        oldAPI_ = oldAPI;
4396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        newAPI_ = newAPI;
4496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
4596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        double differs = 0.0;
4696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
4796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        apiDiff.oldAPIName_ = oldAPI.name_;
4896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        apiDiff.newAPIName_ = newAPI.name_;
4996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
5096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(oldAPI.packages_);
5196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(newAPI.packages_);
5296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
5396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find packages which were removed in the new API
5496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Iterator iter = oldAPI.packages_.iterator();
5596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
5696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            PackageAPI oldPkg = (PackageAPI)(iter.next());
5796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            // This search is looking for an *exact* match. This is true in
5896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            // all the *API classes.
5996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(newAPI.packages_, oldPkg);
6096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
6196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // If there an instance of a package with the same name
6296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // in both the old and new API, then treat it as changed,
6396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // rather than removed and added. There will never be more than
6496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // one instance of a package with the same name in an API.
6596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int existsNew = newAPI.packages_.indexOf(oldPkg);
6696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (existsNew != -1) {
6796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Package by the same name exists in both APIs
6896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // but there has been some or other change.
6996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs += 2.0 * comparePackages(oldPkg, (PackageAPI)(newAPI.packages_.get(existsNew)));
7096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }  else {
7196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
7296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("Package " + oldPkg.name_ + " was removed");
7396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    apiDiff.packagesRemoved.add(oldPkg);
7496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs += 1.0;
7596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
7696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            } else {
7796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // The package exists unchanged in name or doc, but may
7896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // differ in classes and their members, so it still needs to
7996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // be compared.
8096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                differs += 2.0 * comparePackages(oldPkg, (PackageAPI)(newAPI.packages_.get(idx)));
8196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
8296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
8396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
8496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find packages which were added or changed in the new API
8596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        iter = newAPI.packages_.iterator();
8696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
8796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            PackageAPI newPkg = (PackageAPI)(iter.next());
8896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(oldAPI.packages_, newPkg);
8996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
9096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // See comments above
9196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int existsOld = oldAPI.packages_.indexOf(newPkg);
9296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (existsOld != -1) {
9396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Don't mark a package as added or compare it
9496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // if it was already marked as changed
9596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                } else {
9696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
9796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("Package " + newPkg.name_ + " was added");
9896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    apiDiff.packagesAdded.add(newPkg);
9996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs += 1.0;
10096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
10196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            } else {
10296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // It will already have been compared above.
10396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
10496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
10596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
10696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Now that the numbers of members removed and added are known
10796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // we can deduce more information about changes.
10896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        MergeChanges.mergeRemoveAdd(apiDiff);
10996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
11096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// The percent change statistic reported for all elements in each API is
11196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// defined recursively as follows:
11296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project//
11396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// %age change = 100 * (added + removed + 2*changed)
11496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project//               -----------------------------------
11596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project//               sum of public elements in BOTH APIs
11696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project//
11796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// The definition ensures that if all classes are removed and all new classes
11896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// added, the change will be 100%.
11996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// Evaluation of the visibility of elements has already been done when the
12096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// XML was written out.
12196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// Note that this doesn't count changes in the modifiers of classes and
12296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// packages. Other changes in members are counted.
12396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Long denom = new Long(oldAPI.packages_.size() + newAPI.packages_.size());
12496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // This should never be zero because an API always has packages?
12596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (denom.intValue() == 0) {
12696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("Error: no packages found in the APIs.");
12796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return;
12896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
12996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace)
13096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("Top level changes: " + differs + "/" + denom.intValue());
13196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        differs = (100.0 * differs)/denom.doubleValue();
13296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
13396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Some differences such as documentation changes are not tracked in
13496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // the difference statistic, so a value of 0.0 does not mean that there
13596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // were no differences between the APIs.
13696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        apiDiff.pdiff = differs;
13796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Double percentage = new Double(differs);
13896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        int approxPercentage = percentage.intValue();
13996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (approxPercentage == 0)
14096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println(" Approximately " + percentage + "% difference between the APIs");
14196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        else
14296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println(" Approximately " + approxPercentage + "% difference between the APIs");
14396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
14496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Diff.closeDiffFile();
14596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
14696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
14796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
14896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Compare two packages.
14996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
15096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public double comparePackages(PackageAPI oldPkg, PackageAPI newPkg) {
15196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace)
15296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("Comparing old package " + oldPkg.name_ +
15396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                               " and new package " + newPkg.name_);
15496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        pkgDiff = new PackageDiff(oldPkg.name_);
15596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        double differs = 0.0;
15696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
15796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(oldPkg.classes_);
15896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(newPkg.classes_);
15996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
16096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find classes which were removed in the new package
16196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Iterator iter = oldPkg.classes_.iterator();
16296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
16396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            ClassAPI oldClass = (ClassAPI)(iter.next());
16496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            // This search is looking for an *exact* match. This is true in
16596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            // all the *API classes.
16696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(newPkg.classes_, oldClass);
16796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
16896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // If there an instance of a class with the same name
16996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // in both the old and new package, then treat it as changed,
17096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // rather than removed and added. There will never be more than
17196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // one instance of a class with the same name in a package.
17296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int existsNew = newPkg.classes_.indexOf(oldClass);
17396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (existsNew != -1) {
17496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Class by the same name exists in both packages
17596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // but there has been some or other change.
17696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs += 2.0 * compareClasses(oldClass, (ClassAPI)(newPkg.classes_.get(existsNew)), pkgDiff);
17796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }  else {
17896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
17996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("  Class " + oldClass.name_ + " was removed");
18096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    pkgDiff.classesRemoved.add(oldClass);
18196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs += 1.0;
18296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
18396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            } else {
18496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // The class exists unchanged in name or modifiers, but may
18596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // differ in members, so it still needs to be compared.
18696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                differs += 2.0 * compareClasses(oldClass, (ClassAPI)(newPkg.classes_.get(idx)), pkgDiff);
18796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
18896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
18996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
19096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find classes which were added or changed in the new package
19196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        iter = newPkg.classes_.iterator();
19296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
19396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            ClassAPI newClass = (ClassAPI)(iter.next());
19496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(oldPkg.classes_, newClass);
19596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
19696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // See comments above
19796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int existsOld = oldPkg.classes_.indexOf(newClass);
19896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (existsOld != -1) {
19996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Don't mark a class as added or compare it
20096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // if it was already marked as changed
20196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                } else {
20296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
20396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("  Class " + newClass.name_ + " was added");
20496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    pkgDiff.classesAdded.add(newClass);
20596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs += 1.0;
20696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
20796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            } else {
20896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // It will already have been compared above.
20996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
21096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
21196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
21296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Check if the only change was in documentation. Bug 472521.
21396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differsFlag = false;
21496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (docChanged(oldPkg.doc_, newPkg.doc_)) {
21596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String link = "<a href=\"pkg_" + oldPkg.name_ + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">";
21696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String id = oldPkg.name_ + "!package";
21796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String title = link + "Package <b>" + oldPkg.name_ + "</b></a>";
21896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            pkgDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, null, oldPkg.doc_, newPkg.doc_, id, title);
21996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differsFlag = true;
22096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
22196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
22296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Only add to the parent Diff object if some difference has been found
22396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (differs != 0.0 || differsFlag)
22496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            apiDiff.packagesChanged.add(pkgDiff);
22596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
22696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Long denom = new Long(oldPkg.classes_.size() + newPkg.classes_.size());
22796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // This should never be zero because a package always has classes?
22896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (denom.intValue() == 0) {
22996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("Warning: no classes found in the package " + oldPkg.name_);
23096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return 0.0;
23196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
23296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace)
23396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("Package " + pkgDiff.name_ + " had a difference of " + differs + "/" + denom.intValue());
23496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        pkgDiff.pdiff = 100.0 * differs/denom.doubleValue();
23596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return differs/denom.doubleValue();
23696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    } // comparePackages()
23796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
23896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
23996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Compare two classes.
24096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *
24196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Need to compare constructors, methods and fields.
24296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
24396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public double compareClasses(ClassAPI oldClass, ClassAPI newClass, PackageDiff pkgDiff) {
24496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace)
24596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("  Comparing old class " + oldClass.name_ +
24696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                               " and new class " + newClass.name_);
24796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differsFlag = false;
24896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        double differs = 0.0;
24996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        ClassDiff classDiff = new ClassDiff(oldClass.name_);
25096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        classDiff.isInterface_ = newClass.isInterface_; // Used in the report
25196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
25296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Track changes in modifiers - class or interface
25396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldClass.isInterface_ != newClass.isInterface_) {
25496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.modifiersChange_  = "Changed from ";
25596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (oldClass.isInterface_)
25696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                classDiff.modifiersChange_ += "an interface to a class.";
25796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            else
25896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                classDiff.modifiersChange_ += "a class to an interface.";
25996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differsFlag = true;
26096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
26196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Track changes in inheritance
26296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        String inheritanceChange = ClassDiff.diff(oldClass, newClass);
26396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (inheritanceChange != null) {
26496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.inheritanceChange_ = inheritanceChange;
26596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differsFlag = true;
26696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
26796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Abstract or not
26896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldClass.isAbstract_ != newClass.isAbstract_) {
26996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String changeText = "";
27096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (oldClass.isAbstract_)
27196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from abstract to non-abstract.";
27296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            else
27396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from non-abstract to abstract.";
27496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.addModifiersChange(changeText);
27596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differsFlag = true;
27696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
27796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Track changes in documentation
27896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (docChanged(oldClass.doc_, newClass.doc_)) {
27996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String fqName = pkgDiff.name_ + "." + classDiff.name_;
28096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String link = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">";
28196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String id = pkgDiff.name_ + "." + classDiff.name_ + "!class";
28296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String title = link + "Class <b>" + classDiff.name_ + "</b></a>";
28396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_,
28496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.name_, oldClass.doc_, newClass.doc_, id, title);
28596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differsFlag = true;
28696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
28796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // All other modifiers
28896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        String modifiersChange = oldClass.modifiers_.diff(newClass.modifiers_);
28996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (modifiersChange != null) {
29096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differsFlag = true;
29196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) {
29296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                System.out.println("JDiff: warning: change from deprecated to undeprecated for class " + pkgDiff.name_ + "." + newClass.name_);
29396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
29496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
29596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
29696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        classDiff.addModifiersChange(modifiersChange);
29796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
29896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Track changes in members
29996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differsCtors =
30096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            compareAllCtors(oldClass, newClass, classDiff);
30196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differsMethods =
30296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            compareAllMethods(oldClass, newClass, classDiff);
30396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differsFields =
30496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            compareAllFields(oldClass, newClass, classDiff);
30596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (differsCtors || differsMethods || differsFields)
30696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differsFlag = true;
30796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
30896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace) {
30996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("  Ctors differ? " + differsCtors +
31096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                ", Methods differ? " + differsMethods +
31196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                ", Fields differ? " + differsFields);
31296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
31396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
31496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Only add to the parent if some difference has been found
31596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (differsFlag)
31696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            pkgDiff.classesChanged.add(classDiff);
31796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
31896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Get the numbers of affected elements from the classDiff object
31996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         differs =
32096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.ctorsRemoved.size() + classDiff.ctorsAdded.size() +
32196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.ctorsChanged.size() +
32296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.methodsRemoved.size() + classDiff.methodsAdded.size() +
32396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.methodsChanged.size() +
32496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.fieldsRemoved.size() + classDiff.fieldsAdded.size() +
32596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.fieldsChanged.size();
32696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         Long denom = new Long(
32796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             oldClass.ctors_.size() +
32896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             numLocalMethods(oldClass.methods_) +
32996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             numLocalFields(oldClass.fields_) +
33096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             newClass.ctors_.size() +
33196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             numLocalMethods(newClass.methods_) +
33296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             numLocalFields(newClass.fields_));
33396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         if (denom.intValue() == 0) {
33496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             // This is probably a placeholder interface, but documentation
33596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             // or modifiers etc may have changed
33696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             if (differsFlag) {
33796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                 classDiff.pdiff = 0.0; // 100.0 is too much
33896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                 return 1.0;
33996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             } else {
34096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                 return 0.0;
34196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             }
34296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         }
34396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         // Handle the case where the only change is in documentation or
34496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         // the modifiers
34596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         if (differsFlag && differs == 0.0) {
34696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             differs = 1.0;
34796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         }
34896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         if (trace)
34996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project             System.out.println("  Class " + classDiff.name_ + " had a difference of " + differs + "/" + denom.intValue());
35096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         classDiff.pdiff = 100.0 * differs/denom.doubleValue();
35196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project         return differs/denom.doubleValue();
35296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    } // compareClasses()
35396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
35496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
35596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Compare all the constructors in two classes.
35696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *
35796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * The compareTo method in the ConstructorAPI class acts only upon the type.
35896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
35996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public boolean compareAllCtors(ClassAPI oldClass, ClassAPI newClass,
36096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                   ClassDiff classDiff) {
36196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace)
36296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("    Comparing constructors: #old " +
36396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project              oldClass.ctors_.size() + ", #new " + newClass.ctors_.size());
36496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differs = false;
36596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean singleCtor = false; // Set if there is only one ctor
36696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
36796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(oldClass.ctors_);
36896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(newClass.ctors_);
36996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
37096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find ctors which were removed in the new class
37196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Iterator iter = oldClass.ctors_.iterator();
37296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
37396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            ConstructorAPI oldCtor = (ConstructorAPI)(iter.next());
37496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(newClass.ctors_, oldCtor);
37596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
37696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int oldSize = oldClass.ctors_.size();
37796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int newSize = newClass.ctors_.size();
37896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (oldSize == 1 && oldSize == newSize) {
37996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // If there is one constructor in the oldClass and one
38096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // constructor in the new class, then mark it as changed
38196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    MemberDiff memberDiff = new MemberDiff(oldClass.name_);
3820860aaa8b3cd01b42407009ffe4e0697ef0c1356C. Sean Young                    memberDiff.oldType_ = oldCtor.getSignature();
38396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    memberDiff.oldExceptions_ = oldCtor.exceptions_;
38496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    ConstructorAPI newCtor  = (ConstructorAPI)(newClass.ctors_.get(0));
3850860aaa8b3cd01b42407009ffe4e0697ef0c1356C. Sean Young                    memberDiff.newType_ = newCtor.getSignature();
38696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    memberDiff.newExceptions_ = newCtor.exceptions_;
38796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Track changes in documentation
38896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (docChanged(oldCtor.doc_, newCtor.doc_)) {
38996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        String type = memberDiff.newType_;
39096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (type.compareTo("void") == 0)
39196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            type = "";
39296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        String fqName = pkgDiff.name_ + "." + classDiff.name_;
39396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        String link1 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">";
39496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        String link2 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + ".ctor_changed(" + type + ")\" class=\"hiddenlink\">";
39596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        String id = pkgDiff.name_ + "." + classDiff.name_ + ".ctor(" + HTMLReportGenerator.simpleName(type) + ")";
39696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        String title = link1 + "Class <b>" + classDiff.name_ +
39796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            "</b></a>, " + link2 + "constructor <b>" + classDiff.name_ + "(" + HTMLReportGenerator.simpleName(type) + ")</b></a>";
39896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        memberDiff.documentationChange_ = Diff.saveDocDiffs(
39996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            pkgDiff.name_, classDiff.name_, oldCtor.doc_, newCtor.doc_, id, title);
40096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    }
40196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    String modifiersChange = oldCtor.modifiers_.diff(newCtor.modifiers_);
40296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (modifiersChange != null && modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) {
40396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("JDiff: warning: change from deprecated to undeprecated for a constructor in class" + newClass.name_);
40496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    }
40596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    memberDiff.addModifiersChange(modifiersChange);
40696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
40796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("    The single constructor was changed");
40896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    classDiff.ctorsChanged.add(memberDiff);
40996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    singleCtor = true;
41096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                } else {
41196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
41296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("    Constructor " + oldClass.name_ + " was removed");
41396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    classDiff.ctorsRemoved.add(oldCtor);
41496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
41596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                differs = true;
41696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
41796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
41896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
41996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find ctors which were added in the new class
42096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        iter = newClass.ctors_.iterator();
42196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
42296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            ConstructorAPI newCtor = (ConstructorAPI)(iter.next());
42396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(oldClass.ctors_, newCtor);
42496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
42596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (!singleCtor) {
42696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
42796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("    Constructor " + oldClass.name_ + " was added");
42896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    classDiff.ctorsAdded.add(newCtor);
42996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs = true;
43096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
43196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
43296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
43396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
43496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return differs;
43596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    } // compareAllCtors()
43696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
43796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
43896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Compare all the methods in two classes.
43996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *
44096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * We have to deal with the cases where:
44196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *  - there is only one method with a given name, but its signature changes
44296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *  - there is more than one method with the same name, and some of them
44396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *    may have signature changes
44496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * The simplest way to deal with this is to make the MethodAPI comparator
44596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * check the params and return type, as well as the name. This means that
44696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * changing a parameter's type would cause the method to be seen as
44796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * removed and added. To avoid this for the simple case, check for before
44896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * recording a method as removed or added.
44996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
45096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public boolean compareAllMethods(ClassAPI oldClass, ClassAPI newClass, ClassDiff classDiff) {
45196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace)
45296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("    Comparing methods: #old " +
45396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                               oldClass.methods_.size() + ", #new " +
45496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                               newClass.methods_.size());
45596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differs = false;
45696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
45796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(oldClass.methods_);
45896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(newClass.methods_);
45996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
46096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find methods which were removed in the new class
46196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Iterator iter = oldClass.methods_.iterator();
46296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
46396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            MethodAPI oldMethod = (MethodAPI)(iter.next());
46496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = -1;
46596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            MethodAPI[] methodArr = new MethodAPI[newClass.methods_.size()];
46696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodArr = (MethodAPI[])newClass.methods_.toArray(methodArr);
46796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            for (int methodIdx = 0; methodIdx < methodArr.length; methodIdx++) {
46896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                MethodAPI newMethod = methodArr[methodIdx];
46996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (oldMethod.compareTo(newMethod) == 0) {
47096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    idx  = methodIdx;
47196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    break;
47296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
47396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
47496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// NOTE: there was a problem with the binarySearch for
47596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// java.lang.Byte.toString(byte b) returning -16 when the compareTo method
47696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// returned 0 on entry 13. Changed to use arrays instead, so maybe it was
47796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// an issue with methods having another List of params used indirectly by
47896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// compareTo(), unlike constructors and fields?
47996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project//            int idx = Collections.binarySearch(newClass.methods_, oldMethod);
48096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
48196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // If there is only one instance of a method with this name
48296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // in both the old and new class, then treat it as changed,
48396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // rather than removed and added.
48496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // Find how many instances of this method name there are in
48596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // the old and new class. The equals comparator is just on
48696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // the method name.
48796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int startOld = oldClass.methods_.indexOf(oldMethod);
48896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int endOld = oldClass.methods_.lastIndexOf(oldMethod);
48996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int startNew = newClass.methods_.indexOf(oldMethod);
49096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int endNew = newClass.methods_.lastIndexOf(oldMethod);
49196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
49296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (startOld != -1 && startOld == endOld &&
49396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    startNew != -1 && startNew == endNew) {
49496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    MethodAPI newMethod = (MethodAPI)(newClass.methods_.get(startNew));
49596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Only one method with that name exists in both packages,
49696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // so it is valid to compare the two methods. We know it
49796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // has changed, because the binarySearch did not find it.
49896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (oldMethod.inheritedFrom_ == null ||
49996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        newMethod.inheritedFrom_ == null) {
50096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // We also know that at least one of the methods is
50196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // locally defined.
50296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        compareMethods(oldMethod, newMethod, classDiff);
50396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        differs = true;
50496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    }
50596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                } else if (oldMethod.inheritedFrom_ == null) {
50696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Only concerned with locally defined methods
50796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
50896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("    Method " + oldMethod.name_ +
50996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                           "(" + oldMethod.getSignature() +
51096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                           ") was removed");
51196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    classDiff.methodsRemoved.add(oldMethod);
51296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs = true;
51396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
51496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
51596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
51696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
51796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find methods which were added in the new class
51896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        iter = newClass.methods_.iterator();
51996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
52096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            MethodAPI newMethod = (MethodAPI)(iter.next());
52196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            // Only concerned with locally defined methods
52296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (newMethod.inheritedFrom_ != null)
52396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                continue;
52496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = -1;
52596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            MethodAPI[] methodArr = new MethodAPI[oldClass.methods_.size()];
52696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodArr = (MethodAPI[])oldClass.methods_.toArray(methodArr);
52796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            for (int methodIdx = 0; methodIdx < methodArr.length; methodIdx++) {
52896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                MethodAPI oldMethod = methodArr[methodIdx];
52996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (newMethod.compareTo(oldMethod) == 0) {
53096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    idx  = methodIdx;
53196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    break;
53296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
53396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
53496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project// See note above about searching an array instead of binarySearch
53596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project//            int idx = Collections.binarySearch(oldClass.methods_, newMethod);
53696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
53796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // See comments above
53896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int startOld = oldClass.methods_.indexOf(newMethod);
53996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int endOld = oldClass.methods_.lastIndexOf(newMethod);
54096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int startNew = newClass.methods_.indexOf(newMethod);
54196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int endNew = newClass.methods_.lastIndexOf(newMethod);
54296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
54396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (startOld != -1 && startOld == endOld &&
54496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    startNew != -1 && startNew == endNew) {
54596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Don't mark a method as added if it was marked as changed
54696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // The comparison will have been done just above here.
54796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                } else {
54896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
54996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("    Method " + newMethod.name_ +
55096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                           "(" + newMethod.getSignature() + ") was added");
55196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    classDiff.methodsAdded.add(newMethod);
55296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs = true;
55396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
55496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
55596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
55696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
55796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return differs;
55896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    } // compareAllMethods()
55996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
56096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
56196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Compare two methods which have the same name.
56296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
56396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public boolean compareMethods(MethodAPI oldMethod, MethodAPI newMethod, ClassDiff classDiff) {
56496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        MemberDiff methodDiff = new MemberDiff(oldMethod.name_);
56596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differs = false;
56696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Check changes in return type
56796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        methodDiff.oldType_ = oldMethod.returnType_;
56896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        methodDiff.newType_ = newMethod.returnType_;
56996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldMethod.returnType_.compareTo(newMethod.returnType_) != 0) {
57096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
57196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
57296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Check changes in signature
57396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        String oldSig = oldMethod.getSignature();
57496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        String newSig = newMethod.getSignature();
57596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        methodDiff.oldSignature_ = oldSig;
57696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        methodDiff.newSignature_ = newSig;
57796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldSig.compareTo(newSig) != 0) {
57896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
57996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
58096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Changes in inheritance
58196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        int inh = changedInheritance(oldMethod.inheritedFrom_, newMethod.inheritedFrom_);
58296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (inh != 0)
58396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
58496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (inh == 1) {
58596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.addModifiersChange("Method was locally defined, but is now inherited from " + linkToClass(newMethod, true) + ".");
58696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.inheritedFrom_ = newMethod.inheritedFrom_;
58796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } else if (inh == 2) {
58896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.addModifiersChange("Method was inherited from " + linkToClass(oldMethod, false) + ", but is now defined locally.");
58996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } else if (inh == 3) {
59096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.addModifiersChange("Method was inherited from " +
59196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                          linkToClass(oldMethod, false) + ", and is now inherited from " + linkToClass(newMethod, true) + ".");
59296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.inheritedFrom_ = newMethod.inheritedFrom_;
59396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
59496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Abstract or not
59596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldMethod.isAbstract_ != newMethod.isAbstract_) {
59696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String changeText = "";
59796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (oldMethod.isAbstract_)
59896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from abstract to non-abstract.";
59996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            else
60096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from non-abstract to abstract.";
60196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.addModifiersChange(changeText);
60296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
60396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
60496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Native or not
60596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (Diff.showAllChanges &&
60696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project	    oldMethod.isNative_ != newMethod.isNative_) {
60796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String changeText = "";
60896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (oldMethod.isNative_)
60996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from native to non-native.";
61096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            else
61196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from non-native to native.";
61296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.addModifiersChange(changeText);
61396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
61496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
61596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Synchronized or not
61696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (Diff.showAllChanges &&
61796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project	    oldMethod.isSynchronized_ != newMethod.isSynchronized_) {
61896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String changeText = "";
61996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (oldMethod.isSynchronized_)
62096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from synchronized to non-synchronized.";
62196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            else
62296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                changeText += "Changed from non-synchronized to synchronized.";
62396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.addModifiersChange(changeText);
62496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
62596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
62696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
62796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Check changes in exceptions thrown
62896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        methodDiff.oldExceptions_ = oldMethod.exceptions_;
62996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        methodDiff.newExceptions_ = newMethod.exceptions_;
63096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldMethod.exceptions_.compareTo(newMethod.exceptions_) != 0) {
63196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
63296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
63396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
63496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Track changes in documentation
63596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (docChanged(oldMethod.doc_, newMethod.doc_)) {
63696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String sig = methodDiff.newSignature_;
63796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (sig.compareTo("void") == 0)
63896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                sig = "";
63996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String fqName = pkgDiff.name_ + "." + classDiff.name_;
64096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String link1 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">";
64196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String link2 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + "." + newMethod.name_ + "_changed(" + sig + ")\" class=\"hiddenlink\">";
64296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String id = pkgDiff.name_ + "." + classDiff.name_ + ".dmethod." + newMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")";
64396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String title = link1 + "Class <b>" + classDiff.name_ + "</b></a>, " +
64496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                link2 + HTMLReportGenerator.simpleName(methodDiff.newType_) + " <b>" + newMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")</b></a>";
64596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            methodDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, oldMethod.doc_, newMethod.doc_, id, title);
64696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
64796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
64896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
64996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // All other modifiers
65096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        String modifiersChange = oldMethod.modifiers_.diff(newMethod.modifiers_);
65196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (modifiersChange != null) {
65296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            differs = true;
65396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) {
65496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                System.out.println("JDiff: warning: change from deprecated to undeprecated for method " +  classDiff.name_ + "." + newMethod.name_);
65596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
65696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
65796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
65896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        methodDiff.addModifiersChange(modifiersChange);
65996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
66096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Only add to the parent if some difference has been found
66196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (differs) {
66296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (trace) {
66396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                System.out.println("    Method " + newMethod.name_ +
66496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    " was changed: old: " +
66596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                   oldMethod.returnType_ + "(" + oldSig + "), new: " +
66696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                   newMethod.returnType_ + "(" + newSig + ")");
66796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (methodDiff.modifiersChange_ != null)
66896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    System.out.println("    Modifier change: " + methodDiff.modifiersChange_);
66996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
67096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            classDiff.methodsChanged.add(methodDiff);
67196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
67296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
67396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return differs;
67496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    } // compareMethods()
67596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
67696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
67796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Compare all the fields in two classes.
67896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
67996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public boolean compareAllFields(ClassAPI oldClass, ClassAPI newClass,
68096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                    ClassDiff classDiff) {
68196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (trace)
68296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            System.out.println("    Comparing fields: #old " +
68396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                               oldClass.fields_.size() + ", #new "
68496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                               + newClass.fields_.size());
68596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        boolean differs = false;
68696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
68796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(oldClass.fields_);
68896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Collections.sort(newClass.fields_);
68996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
69096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find fields which were removed in the new class
69196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Iterator iter = oldClass.fields_.iterator();
69296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
69396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            FieldAPI oldField = (FieldAPI)(iter.next());
69496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(newClass.fields_, oldField);
69596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
69696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // If there an instance of a field with the same name
69796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // in both the old and new class, then treat it as changed,
69896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // rather than removed and added. There will never be more than
69996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // one instance of a field with the same name in a class.
70096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int existsNew = newClass.fields_.indexOf(oldField);
70196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (existsNew != -1) {
70296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    FieldAPI newField = (FieldAPI)(newClass.fields_.get(existsNew));
70396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (oldField.inheritedFrom_ == null ||
70496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        newField.inheritedFrom_ == null) {
70596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // We also know that one of the fields is locally defined.
70696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        MemberDiff memberDiff = new MemberDiff(oldField.name_);
70796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        memberDiff.oldType_ = oldField.type_;
70896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        memberDiff.newType_ = newField.type_;
70996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // Changes in inheritance
71096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        int inh = changedInheritance(oldField.inheritedFrom_, newField.inheritedFrom_);
71196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (inh != 0)
71296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            differs = true;
71396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (inh == 1) {
71496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.addModifiersChange("Field was locally defined, but is now inherited from " + linkToClass(newField, true) + ".");
71596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.inheritedFrom_ = newField.inheritedFrom_;
71696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        } else if (inh == 2) {
71796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.addModifiersChange("Field was inherited from " + linkToClass(oldField, false) + ", but is now defined locally.");
71896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        } else if (inh == 3) {
71996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.addModifiersChange("Field was inherited from " + linkToClass(oldField, false) + ", and is now inherited from " + linkToClass(newField, true) + ".");
72096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.inheritedFrom_ = newField.inheritedFrom_;
72196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        }
72296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // Transient or not
72396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (oldField.isTransient_ != newField.isTransient_) {
72496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String changeText = "";
72596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            if (oldField.isTransient_)
72696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                changeText += "Changed from transient to non-transient.";
72796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            else
72896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                changeText += "Changed from non-transient to transient.";
72996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.addModifiersChange(changeText);
73096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            differs = true;
73196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        }
73296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // Volatile or not
73396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (oldField.isVolatile_ != newField.isVolatile_) {
73496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String changeText = "";
73596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            if (oldField.isVolatile_)
73696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                changeText += "Changed from volatile to non-volatile.";
73796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            else
73896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                changeText += "Changed from non-volatile to volatile.";
73996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.addModifiersChange(changeText);
74096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            differs = true;
74196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        }
74296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // Change in value of the field
74396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (oldField.value_ != null &&
74496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            newField.value_ != null &&
74596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            oldField.value_.compareTo(newField.value_) != 0) {
74696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String changeText = "Changed in value from " + oldField.value_
74796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                + " to " + newField.value_ +".";
74896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.addModifiersChange(changeText);
74996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            differs = true;
75096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        }
75196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // Track changes in documentation
75296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (docChanged(oldField.doc_, newField.doc_)) {
75396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String fqName = pkgDiff.name_ + "." + classDiff.name_;
75496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String link1 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">";
75596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String link2 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + "." + newField.name_ + "\" class=\"hiddenlink\">";
75696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String id = pkgDiff.name_ + "." + classDiff.name_ + ".field." + newField.name_;
75796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            String title = link1 + "Class <b>" + classDiff.name_ + "</b></a>, " +
75896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                link2 + HTMLReportGenerator.simpleName(memberDiff.newType_) + " <b>" + newField.name_ + "</b></a>";
75996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            memberDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, oldField.doc_, newField.doc_, id, title);
76096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            differs = true;
76196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        }
76296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
76396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        // Other differences
76496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        String modifiersChange = oldField.modifiers_.diff(newField.modifiers_);
76596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        memberDiff.addModifiersChange(modifiersChange);
76696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (modifiersChange != null && modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) {
76796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            System.out.println("JDiff: warning: change from deprecated to undeprecated for class " + newClass.name_ + ", field " + newField.name_);
76896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        }
76996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        if (trace)
77096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                            System.out.println("    Field " + newField.name_ + " was changed");
77196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        classDiff.fieldsChanged.add(memberDiff);
77296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        differs = true;
77396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    }
77496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                } else if (oldField.inheritedFrom_ == null) {
77596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
77696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("    Field " + oldField.name_ + " was removed");
77796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    classDiff.fieldsRemoved.add(oldField);
77896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs = true;
77996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
78096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
78196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
78296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
78396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        // Find fields which were added in the new class
78496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        iter = newClass.fields_.iterator();
78596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
78696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            FieldAPI newField = (FieldAPI)(iter.next());
78796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            // Only concerned with locally defined fields
78896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (newField.inheritedFrom_ != null)
78996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                continue;
79096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            int idx = Collections.binarySearch(oldClass.fields_, newField);
79196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (idx < 0) {
79296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                // See comments above
79396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                int existsOld = oldClass.fields_.indexOf(newField);
79496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                if (existsOld != -1) {
79596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    // Don't mark a field as added if it was marked as changed
79696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                } else {
79796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    if (trace)
79896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                        System.out.println("    Field " + newField.name_ + " was added");
79996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    classDiff.fieldsAdded.add(newField);
80096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                    differs = true;
80196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                }
80296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            }
80396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        } // while (iter.hasNext())
80496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
80596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return differs;
80696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    } // compareFields()
80796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
80896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
80996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Decide if two blocks of documentation changed.
81096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *
81196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * @return true if both are non-null and differ,
81296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *              or if one is null and the other is not.
81396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
81496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public static boolean docChanged(String oldDoc, String newDoc) {
81596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (!HTMLReportGenerator.reportDocChanges)
81696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return false; // Don't even count doc changes as changes
81796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldDoc == null && newDoc != null)
81896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return true;
81996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldDoc != null && newDoc == null)
82096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return true;
82196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldDoc != null && newDoc != null && oldDoc.compareTo(newDoc) != 0)
82296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return true;
82396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return false;
82496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
82596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
82696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
82796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Decide if two elements changed where they were defined.
82896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *
82996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * @return 0 if both are null, or both are non-null and are the same.
83096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *         1 if the oldInherit was null and newInherit is non-null.
83196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *         2 if the oldInherit was non-null and newInherit is null.
83296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *         3 if the oldInherit was non-null and newInherit is non-null
83396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     *           and they differ.
83496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
83596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public static int changedInheritance(String oldInherit, String newInherit) {
83696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldInherit == null && newInherit == null)
83796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return 0;
83896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldInherit == null && newInherit != null)
83996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return 1;
84096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldInherit != null && newInherit == null)
84196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return 2;
84296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (oldInherit.compareTo(newInherit) == 0)
84396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return 0;
84496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        else
84596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return 3;
84696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
84796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
84896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
84996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Generate a link to the Javadoc page for the given method.
85096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
85196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public static String linkToClass(MethodAPI m, boolean useNew) {
85296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        String sig = m.getSignature();
85396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (sig.compareTo("void") == 0)
85496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            sig = "";
85596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return linkToClass(m.inheritedFrom_, m.name_, sig, useNew);
85696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
85796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
85896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
85996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Generate a link to the Javadoc page for the given field.
86096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
86196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public static String linkToClass(FieldAPI m, boolean useNew) {
86296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return linkToClass(m.inheritedFrom_, m.name_, null, useNew);
86396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
86496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
86596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
86696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Given the name of the class, generate a link to a relevant page.
86796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * This was originally for inheritance changes, so the JDiff page could
86896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * be a class changes page, or a section in a removed or added classes
86996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * table. Since there was no easy way to tell which type the link
87096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * should be, it is now just a link to the relevant Javadoc page.
87196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
87296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public static String linkToClass(String className, String memberName,
87396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                                     String memberType, boolean useNew) {
87496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (!useNew && HTMLReportGenerator.oldDocPrefix == null) {
87596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return "<tt>" + className + "</tt>"; // No link possible
87696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
87796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        API api = oldAPI_;
87896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        String prefix = HTMLReportGenerator.oldDocPrefix;
87996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (useNew) {
88096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            api = newAPI_;
88196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            prefix = HTMLReportGenerator.newDocPrefix;
88296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
88396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        ClassAPI cls = (ClassAPI)api.classes_.get(className);
88496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (cls == null) {
88596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (useNew)
88696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                System.out.println("Warning: class " + className + " not found in the new API when creating Javadoc link");
88796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            else
88896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                System.out.println("Warning: class " + className + " not found in the old API when creating Javadoc link");
88996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return "<tt>" + className + "</tt>";
89096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
89196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        int clsIdx = className.indexOf(cls.name_);
89296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        if (clsIdx != -1) {
89396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String pkgRef = className.substring(0, clsIdx);
89496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            pkgRef = pkgRef.replace('.', '/');
89596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            String res = "<a href=\"" + prefix + pkgRef + cls.name_ + ".html#" + memberName;
89696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (memberType != null)
89796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                res += "(" + memberType + ")";
89896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            res += "\" target=\"_top\">" + "<tt>" + cls.name_ + "</tt></a>";
89996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            return res;
90096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
90196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return "<tt>" + className + "</tt>";
90296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
90396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
90496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
90596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Return the number of methods which are locally defined.
90696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
90796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public int numLocalMethods(List methods) {
90896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        int res = 0;
90996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Iterator iter = methods.iterator();
91096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
91196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            MethodAPI m = (MethodAPI)(iter.next());
91296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (m.inheritedFrom_ == null)
91396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                res++;
91496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
91596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return res;
91696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
91796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
91896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /**
91996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     * Return the number of fields which are locally defined.
92096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project     */
92196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    public int numLocalFields(List fields) {
92296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        int res = 0;
92396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        Iterator iter = fields.iterator();
92496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        while (iter.hasNext()) {
92596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            FieldAPI f = (FieldAPI)(iter.next());
92696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project            if (f.inheritedFrom_ == null)
92796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project                res++;
92896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        }
92996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project        return res;
93096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    }
93196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project
93296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    /** Set to enable increased logging verbosity for debugging. */
93396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project    private boolean trace = false;
93496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project}
935