NewDependencyCollector.java revision 2958:27da0c3ac83a
1/*
2 * Copyright (c) 2015, 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
26package com.sun.tools.sjavac.comp.dependencies;
27
28import java.util.Collection;
29import java.util.HashMap;
30import java.util.HashSet;
31import java.util.Map;
32import java.util.Set;
33import java.util.stream.Collectors;
34
35import javax.tools.JavaFileManager.Location;
36import javax.tools.JavaFileObject;
37import javax.tools.StandardLocation;
38
39import com.sun.source.util.TaskEvent;
40import com.sun.source.util.TaskListener;
41import com.sun.tools.javac.code.Symbol.ClassSymbol;
42import com.sun.tools.javac.util.Context;
43import com.sun.tools.javac.util.DefinedBy;
44import com.sun.tools.javac.util.DefinedBy.Api;
45import com.sun.tools.javac.util.Dependencies.GraphDependencies;
46import com.sun.tools.javac.util.Dependencies.GraphDependencies.CompletionNode;
47import com.sun.tools.javac.util.GraphUtils.Node;
48import com.sun.tools.sjavac.Util;
49import com.sun.tools.sjavac.comp.JavaFileObjectWithLocation;
50import com.sun.tools.sjavac.comp.PubAPIs;
51
52
53public class NewDependencyCollector implements TaskListener {
54
55    private final Context context;
56    private final Collection<JavaFileObject> explicitJFOs;
57
58    private Map<String, Map<String, Set<String>>> deps;
59    private Map<String, Map<String, Set<String>>> cpDeps;
60
61    public NewDependencyCollector(Context context,
62                                  Collection<JavaFileObject> explicitJFOs) {
63        this.context = context;
64        this.explicitJFOs = explicitJFOs;
65    }
66
67    @Override
68    @DefinedBy(Api.COMPILER_TREE)
69    public void finished(TaskEvent e) {
70        if (e.getKind() == TaskEvent.Kind.COMPILATION) {
71            collectPubApisOfDependencies(context, explicitJFOs);
72            deps = getDependencies(context, explicitJFOs, false);
73            cpDeps = getDependencies(context, explicitJFOs, true);
74        }
75    }
76
77    public Map<String, Map<String, Set<String>>> getDependencies(boolean cp) {
78        return cp ? cpDeps : deps;
79    }
80
81    private Set<CompletionNode> getDependencyNodes(Context context,
82                                                   Collection<JavaFileObject> explicitJFOs,
83                                                   boolean explicits) {
84        GraphDependencies deps = (GraphDependencies) GraphDependencies.instance(context);
85
86        return deps.getNodes()
87                   .stream()
88                   .filter(n -> n instanceof CompletionNode)
89                   .map(n -> (CompletionNode) n)
90                   .filter(n -> n.getClassSymbol().fullname != null)
91                   .filter(n -> explicits == explicitJFOs.contains(n.getClassSymbol().classfile))
92                   .collect(Collectors.toSet());
93    }
94
95    private void collectPubApisOfDependencies(Context context,
96                                              Collection<JavaFileObject> explicitJFOs) {
97        PubAPIs pubApis = PubAPIs.instance(context);
98        for (CompletionNode cDepNode : getDependencyNodes(context, explicitJFOs, false)) {
99            ClassSymbol cs = cDepNode.getClassSymbol().outermostClass();
100            Location loc = getLocationOf(cs);
101            // We're completely ignorant of PLATFORM_CLASS_PATH classes
102            if (loc == StandardLocation.CLASS_PATH || loc == StandardLocation.SOURCE_PATH)
103                pubApis.visitPubapi(cs);
104        }
105    }
106
107    private Location getLocationOf(ClassSymbol cs) {
108        JavaFileObject jfo = cs.outermostClass().classfile;
109        if (jfo instanceof JavaFileObjectWithLocation) {
110            return ((JavaFileObjectWithLocation<?>) jfo).getLocation();
111        }
112
113        // jfo is most likely on PLATFORM_CLASS_PATH.
114        // See notes in SmartFileManager::locWrap
115
116        return null;
117    }
118
119    // :Package -> fully qualified class name [from] -> set of fully qualified class names [to]
120    private Map<String, Map<String, Set<String>>> getDependencies(Context context,
121                                                                  Collection<JavaFileObject> explicitJFOs,
122                                                                  boolean cp) {
123        Map<String, Map<String, Set<String>>> result = new HashMap<>();
124
125        for (CompletionNode cnode : getDependencyNodes(context, explicitJFOs, true)) {
126
127            String fqDep = cnode.getClassSymbol().outermostClass().flatname.toString();
128            String depPkg = Util.pkgNameOfClassName(fqDep);
129
130            Map<String, Set<String>> depsForThisClass = result.get(depPkg);
131            if (depsForThisClass == null)
132                result.put(depPkg, depsForThisClass = new HashMap<>());
133
134            for (Node<?,?> depNode : cnode.getDependenciesByKind(GraphDependencies.Node.DependencyKind.REQUIRES)) {
135                boolean isCompletionNode = depNode instanceof CompletionNode;
136                if (isCompletionNode) {
137                    CompletionNode cDepNode = (CompletionNode) depNode;
138                    if (cDepNode == cnode)
139                        continue;
140                    if (cDepNode.getClassSymbol().fullname == null) // Anonymous class
141                        continue;
142                    Location depLoc = getLocationOf(cDepNode.getClassSymbol());
143                    boolean relevant = (cp  && depLoc == StandardLocation.CLASS_PATH)
144                                    || (!cp && depLoc == StandardLocation.SOURCE_PATH);
145                    if (!relevant)
146                        continue;
147
148                    Set<String> fqDeps = depsForThisClass.get(fqDep);
149                    if (fqDeps == null)
150                        depsForThisClass.put(fqDep, fqDeps = new HashSet<>());
151                    fqDeps.add(cDepNode.getClassSymbol().outermostClass().flatname.toString());
152                }
153            }
154        }
155        return result;
156    }
157
158}
159