41 import java.util.Map; |
41 import java.util.Map; |
42 import java.util.Set; |
42 import java.util.Set; |
43 import java.util.TreeSet; |
43 import java.util.TreeSet; |
44 import java.util.function.Function; |
44 import java.util.function.Function; |
45 import java.util.stream.Collectors; |
45 import java.util.stream.Collectors; |
46 import static java.lang.module.ModuleDescriptor.Requires.Modifier.PUBLIC; |
46 import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE; |
47 |
47 |
48 /** |
48 /** |
49 * Generate the DOT file for a module graph for each module in the JDK |
49 * Generate the DOT file for a module graph for each module in the JDK |
50 * after transitive reduction. |
50 * after transitive reduction. |
51 */ |
51 */ |
170 |
170 |
171 // transitive reduction |
171 // transitive reduction |
172 Graph<String> graph = gengraph(cf); |
172 Graph<String> graph = gengraph(cf); |
173 descriptors.forEach(md -> { |
173 descriptors.forEach(md -> { |
174 String mn = md.name(); |
174 String mn = md.name(); |
175 Set<String> requiresPublic = md.requires().stream() |
175 Set<String> requiresTransitive = md.requires().stream() |
176 .filter(d -> d.modifiers().contains(PUBLIC)) |
176 .filter(d -> d.modifiers().contains(TRANSITIVE)) |
177 .map(d -> d.name()) |
177 .map(d -> d.name()) |
178 .collect(Collectors.toSet()); |
178 .collect(Collectors.toSet()); |
179 |
179 |
180 graph.adjacentNodes(mn).forEach(dn -> { |
180 graph.adjacentNodes(mn).forEach(dn -> { |
181 String attr = dn.equals("java.base") ? REQUIRES_BASE |
181 String attr = dn.equals("java.base") ? REQUIRES_BASE |
182 : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES); |
182 : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES); |
183 int w = weightOf(mn, dn); |
183 int w = weightOf(mn, dn); |
184 if (w > 1) |
184 if (w > 1) |
185 attr += "weight=" + w; |
185 attr += "weight=" + w; |
186 out.format(" \"%s\" -> \"%s\" [%s];%n", mn, dn, attr); |
186 out.format(" \"%s\" -> \"%s\" [%s];%n", mn, dn, attr); |
187 }); |
187 }); |
192 } |
192 } |
193 |
193 |
194 /** |
194 /** |
195 * Returns a Graph of the given Configuration after transitive reduction. |
195 * Returns a Graph of the given Configuration after transitive reduction. |
196 * |
196 * |
197 * Transitive reduction of requires public edge and requires edge have |
197 * Transitive reduction of requires transitive edge and requires edge have |
198 * to be applied separately to prevent the requires public edges |
198 * to be applied separately to prevent the requires transitive edges |
199 * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V) |
199 * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V) |
200 * in which V would not be re-exported from U. |
200 * in which V would not be re-exported from U. |
201 */ |
201 */ |
202 private Graph<String> gengraph(Configuration cf) { |
202 private Graph<String> gengraph(Configuration cf) { |
203 Graph.Builder<String> builder = new Graph.Builder<>(); |
203 Graph.Builder<String> builder = new Graph.Builder<>(); |
206 builder.addNode(mn); |
206 builder.addNode(mn); |
207 resolvedModule.reads().stream() |
207 resolvedModule.reads().stream() |
208 .map(ResolvedModule::name) |
208 .map(ResolvedModule::name) |
209 .forEach(target -> builder.addEdge(mn, target)); |
209 .forEach(target -> builder.addEdge(mn, target)); |
210 } |
210 } |
211 Graph<String> rpg = requiresPublicGraph(cf); |
211 Graph<String> rpg = requiresTransitiveGraph(cf); |
212 return builder.build().reduce(rpg); |
212 return builder.build().reduce(rpg); |
213 } |
213 } |
214 |
214 |
215 /** |
215 /** |
216 * Returns a Graph containing only requires public edges |
216 * Returns a Graph containing only requires transitive edges |
217 * with transitive reduction. |
217 * with transitive reduction. |
218 */ |
218 */ |
219 private Graph<String> requiresPublicGraph(Configuration cf) { |
219 private Graph<String> requiresTransitiveGraph(Configuration cf) { |
220 Graph.Builder<String> builder = new Graph.Builder<>(); |
220 Graph.Builder<String> builder = new Graph.Builder<>(); |
221 for (ResolvedModule resolvedModule : cf.modules()) { |
221 for (ResolvedModule resolvedModule : cf.modules()) { |
222 ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); |
222 ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); |
223 String mn = descriptor.name(); |
223 String mn = descriptor.name(); |
224 descriptor.requires().stream() |
224 descriptor.requires().stream() |
225 .filter(d -> d.modifiers().contains(PUBLIC)) |
225 .filter(d -> d.modifiers().contains(TRANSITIVE)) |
226 .map(d -> d.name()) |
226 .map(d -> d.name()) |
227 .forEach(d -> builder.addEdge(mn, d)); |
227 .forEach(d -> builder.addEdge(mn, d)); |
228 } |
228 } |
229 return builder.build().reduce(); |
229 return builder.build().reduce(); |
230 } |
230 } |