Tue, 26 Feb 2013 09:04:19 +0000
8008436: javac should not issue a warning for overriding equals without hasCode if hashCode has been overriden by a superclass
Reviewed-by: jjg, mcimadamore
1 /*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.sun.tools.jdeps;
27 import com.sun.tools.classfile.Dependency.Location;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.SortedMap;
35 import java.util.SortedSet;
36 import java.util.TreeMap;
37 import java.util.TreeSet;
39 /**
40 * Dependency Analyzer.
41 */
42 public class Analyzer {
43 /**
44 * Type of the dependency analysis. Appropriate level of data
45 * will be stored.
46 */
47 public enum Type {
48 SUMMARY,
49 PACKAGE,
50 CLASS,
51 VERBOSE
52 };
54 private final Type type;
55 private final List<ArchiveDeps> results = new ArrayList<ArchiveDeps>();
56 private final Map<String, Archive> map = new HashMap<String, Archive>();
57 private final Archive NOT_FOUND
58 = new Archive(JdepsTask.getMessage("artifact.not.found"));
60 /**
61 * Constructs an Analyzer instance.
62 *
63 * @param type Type of the dependency analysis
64 */
65 public Analyzer(Type type) {
66 this.type = type;
67 }
69 /**
70 * Performs the dependency analysis on the given archives.
71 */
72 public void run(List<Archive> archives) {
73 for (Archive archive : archives) {
74 ArchiveDeps deps;
75 if (type == Type.CLASS || type == Type.VERBOSE) {
76 deps = new ClassVisitor(archive);
77 } else {
78 deps = new PackageVisitor(archive);
79 }
80 archive.visit(deps);
81 results.add(deps);
82 }
84 // set the required dependencies
85 for (ArchiveDeps result: results) {
86 for (Set<String> set : result.deps.values()) {
87 for (String target : set) {
88 Archive source = getArchive(target);
89 if (result.archive != source) {
90 if (!result.requiredArchives.contains(source)) {
91 result.requiredArchives.add(source);
92 }
93 // either a profile name or the archive name
94 String tname = getProfile(target);
95 if (tname.isEmpty()){
96 tname = source.toString();
97 }
98 if (!result.targetNames.contains(tname)) {
99 result.targetNames.add(tname);
100 }
101 }
102 }
103 }
104 }
105 }
107 public interface Visitor {
108 /**
109 * Visits a recorded dependency from origin to target which can be
110 * a fully-qualified classname, a package name, a profile or
111 * archive name depending on the Analyzer's type.
112 */
113 void visit(String origin, String target);
114 /**
115 * Visits the source archive to its destination archive of
116 * a recorded dependency.
117 */
118 void visit(Archive source, Archive dest);
119 }
121 public void visitSummary(Visitor v) {
122 for (ArchiveDeps r : results) {
123 for (Archive a : r.requiredArchives) {
124 v.visit(r.archive, a);
125 }
126 for (String name : r.targetNames) {
127 v.visit(r.archive.getFileName(), name);
128 }
129 }
130 }
132 public void visit(Visitor v) {
133 for (ArchiveDeps r: results) {
134 for (Archive a : r.requiredArchives) {
135 v.visit(r.archive, a);
136 }
137 for (String origin : r.deps.keySet()) {
138 for (String target : r.deps.get(origin)) {
139 // filter intra-dependency unless in verbose mode
140 if (type == Type.VERBOSE || getArchive(origin) != getArchive(target)) {
141 v.visit(origin, target);
142 }
143 }
144 }
145 }
146 }
148 public Archive getArchive(String name) {
149 return map.containsKey(name) ? map.get(name) : NOT_FOUND;
150 }
152 public String getArchiveName(String name) {
153 return getArchive(name).getFileName();
154 }
156 public String getProfile(String name) {
157 String pn = type == Type.CLASS ? packageOf(name) : name;
158 Archive source = map.get(name);
159 if (source != null && PlatformClassPath.contains(source)) {
160 String profile = PlatformClassPath.getProfileName(pn);
161 if (profile.isEmpty()) {
162 return "JDK internal API (" + source.getFileName() + ")";
163 }
164 return profile;
165 }
166 return "";
167 }
169 private abstract class ArchiveDeps implements Archive.Visitor {
170 final Archive archive;
171 final Set<Archive> requiredArchives;
172 final SortedSet<String> targetNames;
173 final SortedMap<String, SortedSet<String>> deps;
175 ArchiveDeps(Archive archive) {
176 this.archive = archive;
177 this.requiredArchives = new HashSet<Archive>();
178 this.targetNames = new TreeSet<String>();
179 this.deps = new TreeMap<String, SortedSet<String>>();
180 }
182 void add(String loc) {
183 Archive a = map.get(loc);
184 if (a == null) {
185 map.put(loc, archive);
186 } else if (a != archive) {
187 // duplicated class warning?
188 }
189 }
191 void add(String origin, String target) {
192 SortedSet<String> set = deps.get(origin);
193 if (set == null) {
194 set = new TreeSet<String>();
195 deps.put(origin, set);
196 }
197 if (!set.contains(target)) {
198 set.add(target);
199 }
200 }
202 public abstract void visit(Location o, Location t);
203 }
205 private class ClassVisitor extends ArchiveDeps {
206 ClassVisitor(Archive archive) {
207 super(archive);
208 }
209 public void visit(Location l) {
210 add(l.getClassName());
211 }
212 public void visit(Location o, Location t) {
213 add(o.getClassName(), t.getClassName());
214 }
215 }
217 private class PackageVisitor extends ArchiveDeps {
218 PackageVisitor(Archive archive) {
219 super(archive);
220 }
221 public void visit(Location o, Location t) {
222 add(packageOf(o), packageOf(t));
223 }
225 public void visit(Location l) {
226 add(packageOf(l));
227 }
229 private String packageOf(Location loc) {
230 String pkg = loc.getPackageName();
231 return pkg.isEmpty() ? "<unnamed>" : pkg;
232 }
233 }
235 private static String packageOf(String cn) {
236 int i = cn.lastIndexOf('.');
237 return (i > 0) ? cn.substring(0, i) : "<unnamed>";
238 }
239 }