tboudreau@18301
|
1 |
/*
|
tboudreau@18301
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
tboudreau@18301
|
3 |
*
|
tboudreau@18374
|
4 |
* Copyright (C) 1997-2016 Oracle and/or its affiliates. All rights reserved.
|
tboudreau@18301
|
5 |
*
|
tboudreau@18301
|
6 |
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
|
tboudreau@18301
|
7 |
* Other names may be trademarks of their respective owners.
|
tboudreau@18301
|
8 |
*
|
tboudreau@18301
|
9 |
* The contents of this file are subject to the terms of either the GNU
|
tboudreau@18301
|
10 |
* General Public License Version 2 only ("GPL") or the Common
|
tboudreau@18301
|
11 |
* Development and Distribution License("CDDL") (collectively, the
|
tboudreau@18301
|
12 |
* "License"). You may not use this file except in compliance with the
|
tboudreau@18301
|
13 |
* License. You can obtain a copy of the License at
|
tboudreau@18301
|
14 |
* http://www.netbeans.org/cddl-gplv2.html
|
tboudreau@18301
|
15 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
|
tboudreau@18301
|
16 |
* specific language governing permissions and limitations under the
|
tboudreau@18301
|
17 |
* License. When distributing the software, include this License Header
|
tboudreau@18301
|
18 |
* Notice in each file and include the License file at
|
tboudreau@18301
|
19 |
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
|
tboudreau@18301
|
20 |
* particular file as subject to the "Classpath" exception as provided
|
tboudreau@18301
|
21 |
* by Oracle in the GPL Version 2 section of the License file that
|
tboudreau@18301
|
22 |
* accompanied this code. If applicable, add the following below the
|
tboudreau@18301
|
23 |
* License Header, with the fields enclosed by brackets [] replaced by
|
tboudreau@18301
|
24 |
* your own identifying information:
|
tboudreau@18301
|
25 |
* "Portions Copyrighted [year] [name of copyright owner]"
|
tboudreau@18301
|
26 |
*
|
tboudreau@18301
|
27 |
* Contributor(s):
|
tboudreau@18301
|
28 |
*
|
tboudreau@18301
|
29 |
* The Original Software is NetBeans. The Initial Developer of the Original
|
tboudreau@18301
|
30 |
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
|
tboudreau@18301
|
31 |
* Microsystems, Inc. All Rights Reserved.
|
tboudreau@18301
|
32 |
*
|
tboudreau@18301
|
33 |
* If you wish your version of this file to be governed by only the CDDL
|
tboudreau@18301
|
34 |
* or only the GPL Version 2, indicate your decision by adding
|
tboudreau@18301
|
35 |
* "[Contributor] elects to include this software in this distribution
|
tboudreau@18301
|
36 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a
|
tboudreau@18301
|
37 |
* single choice of license, a recipient has the option to distribute
|
tboudreau@18301
|
38 |
* your version of this file under either the CDDL, the GPL Version 2 or
|
tboudreau@18301
|
39 |
* to extend the choice of license to its licensees as provided above.
|
tboudreau@18301
|
40 |
* However, if you add GPL Version 2 code and therefore, elected the GPL
|
tboudreau@18301
|
41 |
* Version 2 license, then the option applies only if the new code is
|
tboudreau@18301
|
42 |
* made subject to such option by the copyright holder.
|
tboudreau@18301
|
43 |
*/
|
tboudreau@18301
|
44 |
package org.netbeans.lib.callgraph;
|
tboudreau@18301
|
45 |
|
tboudreau@18301
|
46 |
import org.netbeans.lib.callgraph.Arguments.InvalidArgumentsException;
|
tboudreau@18301
|
47 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_CLASSGRAPH;
|
tboudreau@18301
|
48 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_DISABLE_EIGHT_BIT_STRINGS;
|
tboudreau@18301
|
49 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_EXCLUDE;
|
tboudreau@18301
|
50 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_MAVEN;
|
tboudreau@18301
|
51 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_METHODGRAPH;
|
tboudreau@18301
|
52 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_NOSELF;
|
tboudreau@18301
|
53 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_OMIT_ABSTRACT;
|
tboudreau@18301
|
54 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_PACKAGEGRAPH;
|
tboudreau@18301
|
55 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_QUIET;
|
tboudreau@18301
|
56 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_REVERSE;
|
tboudreau@18301
|
57 |
import static org.netbeans.lib.callgraph.CallgraphControl.CMD_SIMPLE;
|
tboudreau@18301
|
58 |
import org.netbeans.lib.callgraph.io.JavaFilesIterator;
|
tboudreau@18301
|
59 |
import org.netbeans.lib.callgraph.javac.JavacRunner;
|
tboudreau@18301
|
60 |
import org.netbeans.lib.callgraph.javac.SourceElement;
|
tboudreau@18301
|
61 |
import org.netbeans.lib.callgraph.javac.SourcesInfo;
|
tboudreau@18301
|
62 |
import org.netbeans.lib.callgraph.util.MergeIterator;
|
tboudreau@18301
|
63 |
import java.io.File;
|
tboudreau@18301
|
64 |
import java.io.IOException;
|
tboudreau@18301
|
65 |
import java.io.PrintStream;
|
tboudreau@18301
|
66 |
import java.util.ArrayList;
|
tboudreau@18301
|
67 |
import java.util.Collections;
|
tboudreau@18301
|
68 |
import java.util.HashSet;
|
tboudreau@18301
|
69 |
import java.util.Iterator;
|
tboudreau@18301
|
70 |
import java.util.LinkedList;
|
tboudreau@18301
|
71 |
import java.util.List;
|
tboudreau@18301
|
72 |
import java.util.Set;
|
tboudreau@18372
|
73 |
import java.util.concurrent.atomic.AtomicReference;
|
tboudreau@18372
|
74 |
import java.util.function.Consumer;
|
tboudreau@18301
|
75 |
|
tboudreau@18301
|
76 |
/**
|
tboudreau@18301
|
77 |
* Scans a source folder and runs javac against any Java sources present, and
|
tboudreau@18301
|
78 |
* builds graphs of what calls what within those. The library classpath does not
|
tboudreau@18301
|
79 |
* need to be set, and the folders do not need to be package roots - we are
|
tboudreau@18301
|
80 |
* instructing javac to treat errors as non-fatal. The available sources will be
|
tboudreau@18301
|
81 |
* attributed.
|
tboudreau@18301
|
82 |
*
|
tboudreau@18301
|
83 |
* @author Tim Boudreau
|
tboudreau@18301
|
84 |
*/
|
tboudreau@18301
|
85 |
public final class Callgraph {
|
tboudreau@18301
|
86 |
|
tboudreau@18301
|
87 |
private boolean noself;
|
tboudreau@18301
|
88 |
private boolean maven;
|
tboudreau@18301
|
89 |
private boolean quiet;
|
tboudreau@18301
|
90 |
private boolean simple;
|
tboudreau@18301
|
91 |
private final Set<String> excludes = new HashSet<>();
|
tboudreau@18301
|
92 |
private final Set<File> folders = new HashSet<>();
|
tboudreau@18301
|
93 |
private File classgraphFile;
|
tboudreau@18301
|
94 |
private File methodgraphFile;
|
tboudreau@18301
|
95 |
private File packagegraphFile;
|
tboudreau@18301
|
96 |
private Listener listener;
|
tboudreau@18301
|
97 |
private boolean omitAbstract;
|
tboudreau@18301
|
98 |
private boolean useJavaStrings;
|
tboudreau@18301
|
99 |
private boolean reverse;
|
tboudreau@18301
|
100 |
|
tboudreau@18301
|
101 |
private Callgraph() {
|
tboudreau@18301
|
102 |
}
|
tboudreau@18301
|
103 |
|
tboudreau@18301
|
104 |
/**
|
tboudreau@18301
|
105 |
* Configure a Callgraph to build.
|
tboudreau@18301
|
106 |
*
|
tboudreau@18301
|
107 |
* @return A call graph to configure
|
tboudreau@18301
|
108 |
*/
|
tboudreau@18301
|
109 |
public static Callgraph configure() {
|
tboudreau@18301
|
110 |
return new Callgraph();
|
tboudreau@18301
|
111 |
}
|
tboudreau@18301
|
112 |
|
tboudreau@18301
|
113 |
public static void main(String[] args) throws IOException {
|
tboudreau@18301
|
114 |
CallgraphControl arguments = null;
|
tboudreau@18301
|
115 |
try {
|
tboudreau@18301
|
116 |
arguments = new Arguments(args);
|
tboudreau@18301
|
117 |
} catch (InvalidArgumentsException ex) {
|
tboudreau@18301
|
118 |
// this will be a help message describing usage and the invalid
|
tboudreau@18301
|
119 |
// arguments
|
tboudreau@18301
|
120 |
System.err.println(ex.getMessage());
|
tboudreau@18301
|
121 |
System.exit(1);
|
tboudreau@18301
|
122 |
}
|
tboudreau@18301
|
123 |
assert arguments != null;
|
tboudreau@18301
|
124 |
invoke(arguments, arguments.isVerbose() ? new LoggingListener() : null);
|
tboudreau@18301
|
125 |
}
|
tboudreau@18301
|
126 |
|
tboudreau@18301
|
127 |
/**
|
tboudreau@18301
|
128 |
* Run javac and produce output.
|
tboudreau@18301
|
129 |
*
|
tboudreau@18301
|
130 |
* @param arguments The parsed arguments
|
tboudreau@18301
|
131 |
* @return The list of all methods found, sorted by qname
|
tboudreau@18301
|
132 |
* @throws IOException If i/o fails
|
tboudreau@18301
|
133 |
*/
|
tboudreau@18301
|
134 |
static List<SourceElement> invoke(CallgraphControl arguments, Listener listener) throws IOException {
|
tboudreau@18374
|
135 |
SourcesInfo info = new SourcesInfo(arguments.isDisableEightBitStrings(), arguments.isAggressive());
|
tboudreau@18301
|
136 |
// Build an iterable of all Java sources (without collecting them all ahead of time)
|
tboudreau@18301
|
137 |
List<Iterable<File>> iterables = new LinkedList<>();
|
tboudreau@18301
|
138 |
for (File folder : arguments) {
|
tboudreau@18301
|
139 |
iterables.add(JavaFilesIterator.iterable(folder));
|
tboudreau@18301
|
140 |
}
|
tboudreau@18301
|
141 |
// The thing that will run javac
|
tboudreau@18301
|
142 |
JavacRunner runner = new JavacRunner(info, MergeIterator.toIterable(iterables), listener);
|
tboudreau@18372
|
143 |
AtomicReference<File> lastFile = new AtomicReference<>();
|
tboudreau@18372
|
144 |
Consumer<File> monitor = lastFile::set;
|
tboudreau@18301
|
145 |
// run javac
|
tboudreau@18372
|
146 |
Set<SourceElement> allElements = runner.go(monitor, lastFile);
|
tboudreau@18301
|
147 |
|
tboudreau@18301
|
148 |
List<SourceElement> all = new ArrayList<>(allElements);
|
tboudreau@18301
|
149 |
// Sort, so textual output is more human-friendly
|
tboudreau@18301
|
150 |
Collections.sort(all);
|
tboudreau@18301
|
151 |
// Now write files and print output
|
tboudreau@18301
|
152 |
if (!all.isEmpty()) {
|
tboudreau@18301
|
153 |
PrintStream outStream = createPrintStreamIfNotNull(arguments.methodGraphFile());
|
tboudreau@18301
|
154 |
PrintStream packageStream = createPrintStreamIfNotNull(arguments.packageGraphFile());
|
tboudreau@18301
|
155 |
PrintStream classStream = createPrintStreamIfNotNull(arguments.classGraphFile());
|
tboudreau@18301
|
156 |
// duplicate avoidance
|
tboudreau@18301
|
157 |
Set<CharSequence> emittedPackageLines = new HashSet<>();
|
tboudreau@18301
|
158 |
Set<CharSequence> emittedClassLines = new HashSet<>();
|
tboudreau@18374
|
159 |
List<Object> clazz = new ArrayList<>(5);
|
tboudreau@18374
|
160 |
CharSequence lastClass = null;
|
tboudreau@18374
|
161 |
|
tboudreau@18374
|
162 |
List<Object> pkg = new ArrayList<>(5);
|
tboudreau@18374
|
163 |
CharSequence lastPackage = null;
|
tboudreau@18374
|
164 |
|
tboudreau@18301
|
165 |
try {
|
tboudreau@18301
|
166 |
// Iterate every method
|
tboudreau@18374
|
167 |
outer:
|
tboudreau@18301
|
168 |
for (SourceElement sce : all) {
|
tboudreau@18301
|
169 |
if (arguments.isExcluded(sce.qname().toString())) { // Ignore matches
|
tboudreau@18301
|
170 |
continue;
|
tboudreau@18301
|
171 |
}
|
tboudreau@18301
|
172 |
List<SourceElement> outbounds = new ArrayList<>(arguments.isReverse() ? sce.getInboundReferences() : sce.getOutboundReferences());
|
tboudreau@18301
|
173 |
Collections.sort(outbounds); // also sort connections
|
tboudreau@18301
|
174 |
// Iterate the current method's connections
|
tboudreau@18374
|
175 |
List<Object> mth = new ArrayList<>(5);
|
tboudreau@18374
|
176 |
CharSequence currClazz = arguments.isShortNames() ? sce.typeName() : info.strings.concat(sce.packageName(), info.strings.DOT, sce.typeName());
|
tboudreau@18374
|
177 |
if (!currClazz.equals(lastClass)) {
|
tboudreau@18374
|
178 |
if (classStream != null) {
|
tboudreau@18374
|
179 |
writeLine(clazz, info, emittedClassLines, classStream);
|
tboudreau@18374
|
180 |
}
|
tboudreau@18374
|
181 |
clazz.clear();
|
tboudreau@18374
|
182 |
lastClass = currClazz;
|
tboudreau@18374
|
183 |
}
|
tboudreau@18374
|
184 |
if (clazz.isEmpty()) {
|
tboudreau@18374
|
185 |
clazz.add(currClazz);
|
tboudreau@18374
|
186 |
if (arguments.isExtendedProperties()) {
|
tboudreau@18374
|
187 |
clazz.add(sce.isAbstract());
|
tboudreau@18374
|
188 |
}
|
tboudreau@18374
|
189 |
}
|
tboudreau@18374
|
190 |
CharSequence currPkg = sce.packageName();
|
tboudreau@18374
|
191 |
if (pkg.isEmpty()) {
|
tboudreau@18374
|
192 |
pkg.add(currPkg);
|
tboudreau@18374
|
193 |
}
|
tboudreau@18374
|
194 |
if (!currPkg.equals(lastPackage)) {
|
tboudreau@18374
|
195 |
if (packageStream != null) {
|
tboudreau@18374
|
196 |
writeLine(pkg, info, emittedPackageLines, packageStream);
|
tboudreau@18374
|
197 |
}
|
tboudreau@18374
|
198 |
lastPackage = currPkg;
|
tboudreau@18374
|
199 |
pkg.clear();
|
tboudreau@18374
|
200 |
}
|
tboudreau@18301
|
201 |
for (SourceElement outbound : outbounds) {
|
tboudreau@18301
|
202 |
if (arguments.isExcluded(outbound.qname().toString())) { // Ignore matches
|
tboudreau@18301
|
203 |
continue;
|
tboudreau@18301
|
204 |
}
|
tboudreau@18301
|
205 |
// If we are ignoring abstract methods, do that - has no effect on classes
|
tboudreau@18301
|
206 |
if (arguments.isOmitAbstract() && (outbound.isAbstract() | sce.isAbstract())) {
|
tboudreau@18301
|
207 |
continue;
|
tboudreau@18301
|
208 |
}
|
tboudreau@18301
|
209 |
// If the argument is set, ignore cases where it's a class' method
|
tboudreau@18301
|
210 |
// referencing another method on that class
|
tboudreau@18301
|
211 |
if (!arguments.isSelfReferences() && sce.typeName().equals(outbound.typeName())) {
|
tboudreau@18301
|
212 |
continue;
|
tboudreau@18301
|
213 |
}
|
tboudreau@18374
|
214 |
if (outStream != null || !arguments.isQuiet()) {
|
tboudreau@18373
|
215 |
if (arguments.isShortNames()) {
|
tboudreau@18373
|
216 |
mth.add(outbound.shortName());
|
tboudreau@18373
|
217 |
} else {
|
tboudreau@18373
|
218 |
mth.add(outbound.qname());
|
tboudreau@18373
|
219 |
}
|
tboudreau@18374
|
220 |
if (arguments.isExtendedProperties()) {
|
tboudreau@18374
|
221 |
mth.add(outbound.isAbstract());
|
tboudreau@18374
|
222 |
}
|
tboudreau@18301
|
223 |
}
|
tboudreau@18301
|
224 |
// Build the package graph output if necessary
|
tboudreau@18301
|
225 |
if (packageStream != null) {
|
tboudreau@18374
|
226 |
if (!outbound.packageName().equals(currPkg) || arguments.isSelfReferences()) {
|
tboudreau@18374
|
227 |
pkg.add(outbound.packageName());
|
tboudreau@18301
|
228 |
}
|
tboudreau@18301
|
229 |
}
|
tboudreau@18301
|
230 |
// Build the class graph output if necessary
|
tboudreau@18301
|
231 |
if (classStream != null) {
|
tboudreau@18301
|
232 |
CharSequence type1 = sce.typeName();
|
tboudreau@18301
|
233 |
CharSequence type2 = outbound.typeName();
|
tboudreau@18301
|
234 |
if (!arguments.isShortNames()) {
|
tboudreau@18374
|
235 |
// type1 = info.strings.concat(sce.packageName(), info.strings.DOT, type1);
|
tboudreau@18301
|
236 |
type2 = info.strings.concat(outbound.packageName(), info.strings.DOT, type2);
|
tboudreau@18301
|
237 |
}
|
tboudreau@18374
|
238 |
if (!type1.equals(type2) && !clazz.contains(type2)) {
|
tboudreau@18374
|
239 |
clazz.add(type2);
|
tboudreau@18374
|
240 |
if (arguments.isExtendedProperties()) {
|
tboudreau@18374
|
241 |
clazz.add(outbound.isAbstract());
|
tboudreau@18301
|
242 |
}
|
tboudreau@18301
|
243 |
}
|
tboudreau@18301
|
244 |
}
|
tboudreau@18301
|
245 |
}
|
tboudreau@18374
|
246 |
if (!arguments.isQuiet() || outStream != null) {
|
tboudreau@18373
|
247 |
if (!mth.isEmpty()) {
|
tboudreau@18373
|
248 |
CharSequence nm = arguments.isShortNames() ? sce.shortName() : sce.qname();
|
tboudreau@18374
|
249 |
List<Object> l = mth;
|
tboudreau@18374
|
250 |
if (arguments.isExtendedProperties()) {
|
tboudreau@18374
|
251 |
mth.add(0, sce.isAbstract());
|
tboudreau@18374
|
252 |
}
|
tboudreau@18373
|
253 |
l.add(0, nm);
|
tboudreau@18373
|
254 |
CharSequence line = info.strings.concatQuoted(l);
|
tboudreau@18373
|
255 |
if (!arguments.isQuiet()) {
|
tboudreau@18373
|
256 |
System.out.println(line);
|
tboudreau@18373
|
257 |
}
|
tboudreau@18373
|
258 |
if (outStream != null) {
|
tboudreau@18373
|
259 |
outStream.println(line);
|
tboudreau@18373
|
260 |
}
|
tboudreau@18373
|
261 |
}
|
tboudreau@18373
|
262 |
}
|
tboudreau@18301
|
263 |
}
|
tboudreau@18374
|
264 |
if (classStream != null && !clazz.isEmpty()) {
|
tboudreau@18374
|
265 |
writeLine(clazz, info, emittedClassLines, classStream);
|
tboudreau@18374
|
266 |
}
|
tboudreau@18374
|
267 |
if (packageStream != null && !pkg.isEmpty()) {
|
tboudreau@18374
|
268 |
writeLine(pkg, info, emittedPackageLines, packageStream);
|
tboudreau@18374
|
269 |
}
|
tboudreau@18301
|
270 |
} finally {
|
tboudreau@18301
|
271 |
for (PrintStream ps : new PrintStream[]{outStream, packageStream, classStream}) {
|
tboudreau@18301
|
272 |
if (ps != null) {
|
tboudreau@18301
|
273 |
ps.close();
|
tboudreau@18301
|
274 |
}
|
tboudreau@18301
|
275 |
}
|
tboudreau@18301
|
276 |
}
|
tboudreau@18301
|
277 |
}
|
tboudreau@18301
|
278 |
return all;
|
tboudreau@18301
|
279 |
}
|
tboudreau@18374
|
280 |
private static void writeLine(List<Object> clazz, SourcesInfo info, Set<CharSequence> emittedClassLines, PrintStream classStream) {
|
tboudreau@18374
|
281 |
if (!clazz.isEmpty()) {
|
tboudreau@18374
|
282 |
CharSequence cs = info.strings.concatQuoted(clazz);
|
tboudreau@18374
|
283 |
if (!emittedClassLines.contains(cs)) {
|
tboudreau@18374
|
284 |
classStream.println(cs);
|
tboudreau@18374
|
285 |
emittedClassLines.add(cs);
|
tboudreau@18374
|
286 |
}
|
tboudreau@18374
|
287 |
}
|
tboudreau@18374
|
288 |
}
|
tboudreau@18301
|
289 |
|
tboudreau@18301
|
290 |
private static PrintStream createPrintStreamIfNotNull(File outputFile) throws IOException {
|
tboudreau@18301
|
291 |
PrintStream outStream = null;
|
tboudreau@18301
|
292 |
if (outputFile != null) {
|
tboudreau@18301
|
293 |
if (!outputFile.exists()) {
|
tboudreau@18301
|
294 |
if (!outputFile.createNewFile()) {
|
tboudreau@18301
|
295 |
throw new IllegalStateException("Could not create " + outputFile);
|
tboudreau@18301
|
296 |
}
|
tboudreau@18301
|
297 |
}
|
tboudreau@18301
|
298 |
outStream = new PrintStream(outputFile);
|
tboudreau@18301
|
299 |
}
|
tboudreau@18301
|
300 |
return outStream;
|
tboudreau@18301
|
301 |
}
|
tboudreau@18301
|
302 |
|
tboudreau@18301
|
303 |
public List<String> toCommandLineArguments() {
|
tboudreau@18301
|
304 |
List<String> args = new ArrayList<>();
|
tboudreau@18301
|
305 |
addBoolean(CMD_NOSELF, noself, args);
|
tboudreau@18301
|
306 |
addBoolean(CMD_MAVEN, maven, args);
|
tboudreau@18301
|
307 |
addBoolean(CMD_QUIET, quiet, args);
|
tboudreau@18301
|
308 |
addBoolean(CMD_SIMPLE, simple, args);
|
tboudreau@18301
|
309 |
addBoolean(CMD_REVERSE, reverse, args);
|
tboudreau@18301
|
310 |
addBoolean(CMD_DISABLE_EIGHT_BIT_STRINGS, useJavaStrings, args);
|
tboudreau@18301
|
311 |
addBoolean(CMD_OMIT_ABSTRACT, omitAbstract, args);
|
tboudreau@18301
|
312 |
if (!excludes.isEmpty()) {
|
tboudreau@18301
|
313 |
StringBuilder concat = new StringBuilder();
|
tboudreau@18301
|
314 |
for (Iterator<String> it = excludes.iterator(); it.hasNext();) {
|
tboudreau@18301
|
315 |
String next = it.next();
|
tboudreau@18301
|
316 |
concat.append(next);
|
tboudreau@18301
|
317 |
if (it.hasNext()) {
|
tboudreau@18301
|
318 |
concat.append(",");
|
tboudreau@18301
|
319 |
}
|
tboudreau@18301
|
320 |
}
|
tboudreau@18301
|
321 |
args.add("--" + CMD_EXCLUDE);
|
tboudreau@18301
|
322 |
args.add(concat.toString());
|
tboudreau@18301
|
323 |
}
|
tboudreau@18301
|
324 |
addFile(CMD_CLASSGRAPH, classgraphFile, args);
|
tboudreau@18301
|
325 |
addFile(CMD_METHODGRAPH, methodgraphFile, args);
|
tboudreau@18301
|
326 |
addFile(CMD_PACKAGEGRAPH, packagegraphFile, args);
|
tboudreau@18301
|
327 |
for (File fld : folders) {
|
tboudreau@18301
|
328 |
args.add(fld.getAbsolutePath());
|
tboudreau@18301
|
329 |
}
|
tboudreau@18301
|
330 |
return args;
|
tboudreau@18301
|
331 |
}
|
tboudreau@18301
|
332 |
|
tboudreau@18372
|
333 |
CallgraphControl build() throws IOException {
|
tboudreau@18301
|
334 |
List<String> args = toCommandLineArguments();
|
tboudreau@18301
|
335 |
// We use regular string processing so we get the argument validation
|
tboudreau@18301
|
336 |
String[] argList = args.toArray(new String[args.size()]);
|
tboudreau@18301
|
337 |
Arguments arguments = new Arguments(false, argList);
|
tboudreau@18301
|
338 |
return arguments;
|
tboudreau@18301
|
339 |
}
|
tboudreau@18301
|
340 |
|
tboudreau@18301
|
341 |
/**
|
tboudreau@18301
|
342 |
* Run this callgraph, writing output and returning the set of all methods
|
tboudreau@18301
|
343 |
* found, sorted in qname order. Call SourceElement.getInboundReferences()
|
tboudreau@18301
|
344 |
* and SourceElement.getOutboundReferences() to explore the graph.
|
tboudreau@18301
|
345 |
*
|
tboudreau@18301
|
346 |
* @return Sorted set of source elements
|
tboudreau@18301
|
347 |
* @throws IOException If i/o fails
|
tboudreau@18301
|
348 |
*/
|
tboudreau@18301
|
349 |
public List<SourceElement> run() throws IOException {
|
tboudreau@18301
|
350 |
return Callgraph.invoke(build(), listener);
|
tboudreau@18301
|
351 |
}
|
tboudreau@18301
|
352 |
|
tboudreau@18301
|
353 |
private void addFile(String command, File file, List<String> args) {
|
tboudreau@18301
|
354 |
if (file != null) {
|
tboudreau@18301
|
355 |
args.add("--" + command);
|
tboudreau@18301
|
356 |
args.add(file.getAbsolutePath());
|
tboudreau@18301
|
357 |
}
|
tboudreau@18301
|
358 |
}
|
tboudreau@18301
|
359 |
|
tboudreau@18301
|
360 |
private void addBoolean(String command, boolean val, List<String> args) {
|
tboudreau@18301
|
361 |
if (val) {
|
tboudreau@18301
|
362 |
args.add("--" + command);
|
tboudreau@18301
|
363 |
}
|
tboudreau@18301
|
364 |
}
|
tboudreau@18301
|
365 |
|
tboudreau@18301
|
366 |
public Callgraph setListener(Listener listener) {
|
tboudreau@18301
|
367 |
this.listener = listener;
|
tboudreau@18301
|
368 |
return this;
|
tboudreau@18301
|
369 |
}
|
tboudreau@18301
|
370 |
|
tboudreau@18301
|
371 |
public Callgraph packageGraphOutput(File file) {
|
tboudreau@18301
|
372 |
packagegraphFile = file;
|
tboudreau@18301
|
373 |
return this;
|
tboudreau@18301
|
374 |
}
|
tboudreau@18301
|
375 |
|
tboudreau@18301
|
376 |
public Callgraph methodGraphOutput(File file) {
|
tboudreau@18301
|
377 |
methodgraphFile = file;
|
tboudreau@18301
|
378 |
return this;
|
tboudreau@18301
|
379 |
}
|
tboudreau@18301
|
380 |
|
tboudreau@18301
|
381 |
public Callgraph classGraphOutput(File file) {
|
tboudreau@18301
|
382 |
classgraphFile = file;
|
tboudreau@18301
|
383 |
return this;
|
tboudreau@18301
|
384 |
}
|
tboudreau@18301
|
385 |
|
tboudreau@18301
|
386 |
public Callgraph addSourceParent(File folder) {
|
tboudreau@18301
|
387 |
folders.add(folder);
|
tboudreau@18301
|
388 |
return this;
|
tboudreau@18301
|
389 |
}
|
tboudreau@18301
|
390 |
|
tboudreau@18301
|
391 |
public Callgraph excludePrefix(String prefix) {
|
tboudreau@18301
|
392 |
excludes.add(prefix);
|
tboudreau@18301
|
393 |
return this;
|
tboudreau@18301
|
394 |
}
|
tboudreau@18301
|
395 |
|
tboudreau@18301
|
396 |
public Callgraph useSimpleClassNames() {
|
tboudreau@18301
|
397 |
simple = true;
|
tboudreau@18301
|
398 |
return this;
|
tboudreau@18301
|
399 |
}
|
tboudreau@18301
|
400 |
|
tboudreau@18301
|
401 |
public Callgraph quiet() {
|
tboudreau@18301
|
402 |
quiet = true;
|
tboudreau@18301
|
403 |
return this;
|
tboudreau@18301
|
404 |
}
|
tboudreau@18301
|
405 |
|
tboudreau@18301
|
406 |
public Callgraph ignoreSelfReferences() {
|
tboudreau@18301
|
407 |
noself = true;
|
tboudreau@18301
|
408 |
return this;
|
tboudreau@18301
|
409 |
}
|
tboudreau@18301
|
410 |
|
tboudreau@18301
|
411 |
public Callgraph scanFoldersForMavenProjects() {
|
tboudreau@18301
|
412 |
maven = true;
|
tboudreau@18301
|
413 |
return this;
|
tboudreau@18301
|
414 |
}
|
tboudreau@18301
|
415 |
|
tboudreau@18301
|
416 |
public Callgraph reverse() {
|
tboudreau@18301
|
417 |
reverse = true;
|
tboudreau@18301
|
418 |
return this;
|
tboudreau@18301
|
419 |
}
|
tboudreau@18301
|
420 |
|
tboudreau@18301
|
421 |
public Callgraph useJavaStrings() {
|
tboudreau@18301
|
422 |
useJavaStrings = true;
|
tboudreau@18301
|
423 |
return this;
|
tboudreau@18301
|
424 |
}
|
tboudreau@18301
|
425 |
|
tboudreau@18301
|
426 |
public Callgraph omitAbstract() {
|
tboudreau@18301
|
427 |
omitAbstract = true;
|
tboudreau@18301
|
428 |
return this;
|
tboudreau@18301
|
429 |
}
|
tboudreau@18301
|
430 |
|
tboudreau@18301
|
431 |
private static final class LoggingListener implements Listener {
|
tboudreau@18301
|
432 |
|
tboudreau@18301
|
433 |
@Override
|
tboudreau@18301
|
434 |
public void onStart() {
|
tboudreau@18301
|
435 |
//do nothing
|
tboudreau@18301
|
436 |
}
|
tboudreau@18301
|
437 |
|
tboudreau@18301
|
438 |
@Override
|
tboudreau@18301
|
439 |
public void onFinish() {
|
tboudreau@18301
|
440 |
System.out.println("Done.");
|
tboudreau@18301
|
441 |
}
|
tboudreau@18301
|
442 |
|
tboudreau@18301
|
443 |
@Override
|
tboudreau@18301
|
444 |
public void onStartActivity(String activity, int steps) {
|
tboudreau@18301
|
445 |
if (steps > 0) {
|
tboudreau@18301
|
446 |
System.out.println(activity + " (" + steps + " steps)");
|
tboudreau@18301
|
447 |
}
|
tboudreau@18301
|
448 |
}
|
tboudreau@18301
|
449 |
|
tboudreau@18301
|
450 |
@Override
|
tboudreau@18301
|
451 |
public void onStep(String step) {
|
tboudreau@18301
|
452 |
System.out.println("\t" + step);
|
tboudreau@18301
|
453 |
}
|
tboudreau@18301
|
454 |
}
|
tboudreau@18301
|
455 |
}
|