Tue, 17 Sep 2013 14:17:13 -0700
8024538: -Xdoclint + -Xprefer:source + incremental compilation == FAIL
Reviewed-by: darcy
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 = result.getTargetProfile(target);
95 if (tname.isEmpty()) {
96 tname = PlatformClassPath.contains(source)
97 ? "JDK internal API (" + source.getFileName() + ")"
98 : source.toString();
99 }
100 if (!result.targetNames.contains(tname)) {
101 result.targetNames.add(tname);
102 }
103 }
104 }
105 }
106 }
107 }
109 public interface Visitor {
110 /**
111 * Visits a recorded dependency from origin to target which can be
112 * a fully-qualified classname, a package name, a profile or
113 * archive name depending on the Analyzer's type.
114 */
115 void visit(String origin, String target, String profile);
116 /**
117 * Visits the source archive to its destination archive of
118 * a recorded dependency.
119 */
120 void visit(Archive source, Archive dest);
121 }
123 public void visitSummary(Visitor v) {
124 for (ArchiveDeps r : results) {
125 for (Archive a : r.requiredArchives) {
126 v.visit(r.archive, a);
127 }
128 for (String name : r.targetNames) {
129 v.visit(r.archive.getFileName(), name, name);
130 }
131 }
132 }
134 public void visit(Visitor v) {
135 for (ArchiveDeps r: results) {
136 for (Archive a : r.requiredArchives) {
137 v.visit(r.archive, a);
138 }
139 for (String origin : r.deps.keySet()) {
140 for (String target : r.deps.get(origin)) {
141 // filter intra-dependency unless in verbose mode
142 if (type == Type.VERBOSE || getArchive(origin) != getArchive(target)) {
143 v.visit(origin, target, r.getTargetProfile(target));
144 }
145 }
146 }
147 }
148 }
150 public Archive getArchive(String name) {
151 return map.containsKey(name) ? map.get(name) : NOT_FOUND;
152 }
154 /**
155 * Returns the file name of the archive for non-JRE class or
156 * internal JRE classes. It returns empty string for SE API.
157 */
158 public String getArchiveName(String target, String profile) {
159 Archive source = getArchive(target);
160 String name = source.getFileName();
161 if (PlatformClassPath.contains(source))
162 return profile.isEmpty() ? "JDK internal API (" + name + ")" : "";
163 return name;
164 }
166 private abstract class ArchiveDeps implements Archive.Visitor {
167 final Archive archive;
168 final Set<Archive> requiredArchives;
169 final SortedSet<String> targetNames;
170 final SortedMap<String, SortedSet<String>> deps;
172 ArchiveDeps(Archive archive) {
173 this.archive = archive;
174 this.requiredArchives = new HashSet<Archive>();
175 this.targetNames = new TreeSet<String>();
176 this.deps = new TreeMap<String, SortedSet<String>>();
177 }
179 void add(String loc) {
180 Archive a = map.get(loc);
181 if (a == null) {
182 map.put(loc, archive);
183 } else if (a != archive) {
184 // duplicated class warning?
185 }
186 }
188 void add(String origin, String target) {
189 SortedSet<String> set = deps.get(origin);
190 if (set == null) {
191 set = new TreeSet<String>();
192 deps.put(origin, set);
193 }
194 if (!set.contains(target)) {
195 set.add(target);
196 }
197 }
199 public abstract void visit(Location o, Location t);
200 public abstract String getTargetProfile(String target);
202 }
204 private class ClassVisitor extends ArchiveDeps {
205 ClassVisitor(Archive archive) {
206 super(archive);
207 }
208 public void visit(Location l) {
209 add(l.getClassName());
210 }
211 public void visit(Location o, Location t) {
212 add(o.getClassName(), t.getClassName());
213 }
214 public String getTargetProfile(String target) {
215 int i = target.lastIndexOf('.');
216 return (i > 0) ? Profiles.getProfileName(target.substring(0, i)) : "";
217 }
218 }
220 private class PackageVisitor extends ArchiveDeps {
221 PackageVisitor(Archive archive) {
222 super(archive);
223 }
224 public void visit(Location o, Location t) {
225 add(packageOf(o), packageOf(t));
226 }
227 public void visit(Location l) {
228 add(packageOf(l));
229 }
230 private String packageOf(Location loc) {
231 String pkg = loc.getPackageName();
232 return pkg.isEmpty() ? "<unnamed>" : pkg;
233 }
234 public String getTargetProfile(String target) {
235 return Profiles.getProfileName(target);
236 }
237 }
238 }