Automated merge with http://hg.netbeans.org/main/contrib
authorTim Boudreau <tboudreau@netbeans.org>
Mon, 31 Aug 2015 15:31:15 -0400
changeset 18302b9b119679ed6
parent 18300 8fec1d668f4a
parent 18301 17413f763c78
child 18303 6fbd2e6ee661
child 18342 78f82539c7ba
Automated merge with http://hg.netbeans.org/main/contrib
     1.1 --- a/.hgignore	Mon Aug 31 12:40:19 2015 +0200
     1.2 +++ b/.hgignore	Mon Aug 31 15:31:15 2015 -0400
     1.3 @@ -242,3 +242,7 @@
     1.4  ^dew4nb/release/modules$
     1.5  ^project.jsjava/release/modules$
     1.6  
     1.7 +^callgraph/nbactions.xml$
     1.8 +^callgraph/nbproject/project.properties$
     1.9 +^callgraph/target$
    1.10 +
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/callgraph/README.md	Mon Aug 31 15:31:15 2015 -0400
     2.3 @@ -0,0 +1,52 @@
     2.4 +Callgraph
     2.5 +---------
     2.6 +
     2.7 +Callgraph is a standalone Java utility and programmatic API for generating text files which serve as input for building a graph of what calls what in all Java sources underneath a folder.  It can output what methods call what methods on what other classes, what packages call what other packages, or what classes call other classes, or all of the above, to provide different levels of granularity.
     2.8 +
     2.9 +It uses javac's API to analyze sources.
    2.10 +
    2.11 +It does not need library dependencies to be set up on the compiler's working classpath, since it only needs to resolve references between visible sources, and runs javac in IDE mode so unresolvable references are not treated as fatal errors.
    2.12 +
    2.13 +The folder(s) passed in need not be source roots - you can pass in the root folder of a tree of projects and it will find all Java sources below them.
    2.14 +
    2.15 +The `--maven` lineswitch will cause it to scan the passed folders for Maven projects, and use their `src/main/java` folders as roots (so test classes are not included in the resulting graphs, since typically you are looking for things that are most-used, and used-by-tests doesn't count at runtime).
    2.16 +
    2.17 +
    2.18 +Usage
    2.19 +-----
    2.20 +
    2.21 +```
    2.22 +Callgraph prints a graph of things that call each other in a tree of Java sources,
    2.23 +and can output graphs of what methods / classes / packages (or all of the above) call each other
    2.24 +within thatsource tree.
    2.25 +
    2.26 +Usage:
    2.27 +java -jar callgraph.jar [--noself | -n] [--simple | -s] [--maven | -m] [--methodgraph | -g methodgraph] [--exclude | -e exclude] [--packagegraph | -p packagegraph] [--classgraph | -c classgraph] [--quiet | -q] dir1 [dir2 dir3 ...]
    2.28 +
    2.29 +	--noself / -n :	Hide intra-class calls (i.e. if Foo.bar() calls Foo.baz(), don't include it)
    2.30 +	--simple / -s :	Use simple class names without the package (may confuse results if two classes have the same name)
    2.31 +	--maven / -m :	Find all maven projects that are children of the passed folders, and scan their src/main/java subfolders
    2.32 +	--methodgraph / -g :	Set the output file for the method call graph
    2.33 +	--exclude / -e :	Exclude any relationships where the fully qualified class name starts with any pattern in this comma-delimited list of strings, e.g. -e foo.bar,foo.baz
    2.34 +	--packagegraph / -p :	Set the output file for the package call graph
    2.35 +	--classgraph / -c :	Set the output file for the class call graph
    2.36 +	--quiet / -q :	Supress writing the graph to the standard output
    2.37 +Errors:
    2.38 +	No folders of Java sources specified
    2.39 +```
    2.40 +
    2.41 +
    2.42 +To-Do
    2.43 +-----
    2.44 +
    2.45 +### Limiting Memory Consumption
    2.46 +
    2.47 +On extremely large codebases (say, the entire NetBeans source base), the compile process may run out of memory.  This could be optimized by processing classes in batches (the mechanism for mapping javac `Element` objects to `SourceElement` objects would need to be changed so the trees from the java compile can be garbage collected), but this is not as simple as it sounds, since javac has to attribute the entire source tree, and references that not resolvable within a subset of the tree that is one batch would not show up.
    2.48 +
    2.49 +The right way to do this would be to run the parse phase, and then partition the tree based on input statements.  The parse p
    2.50 +
    2.51 +
    2.52 +### Ensure non-overlapping folders
    2.53 +
    2.54 +Ensure java files are not parsed twice if, say, `/foo/bar` and `/foo/bar/baz` are both passed as input folders.
    2.55 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/callgraph/pom.xml	Mon Aug 31 15:31:15 2015 -0400
     3.3 @@ -0,0 +1,108 @@
     3.4 +<?xml version="1.0" encoding="UTF-8"?>
     3.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     3.6 +    <modelVersion>4.0.0</modelVersion>
     3.7 +    <groupId>org.netbeans</groupId>
     3.8 +    <artifactId>callgraph</artifactId>
     3.9 +    <name>Callgraph Utility</name>
    3.10 +    <version>1.0</version>
    3.11 +    <packaging>jar</packaging>
    3.12 +    <properties>
    3.13 +        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    3.14 +        <maven.compiler.source>1.7</maven.compiler.source>
    3.15 +        <maven.compiler.target>1.7</maven.compiler.target>
    3.16 +    </properties>
    3.17 +    <build>
    3.18 +        <plugins>
    3.19 +            <plugin>
    3.20 +                <groupId>org.apache.maven.plugins</groupId>
    3.21 +                <artifactId>maven-jar-plugin</artifactId>
    3.22 +                <version>2.6</version>
    3.23 +                <configuration>
    3.24 +                    <archive>
    3.25 +                        <manifest>
    3.26 +                            <mainClass>org.netbeans.lib.callgraph.Callgraph</mainClass>
    3.27 +                        </manifest>
    3.28 +                    </archive>
    3.29 +                </configuration>
    3.30 +            </plugin>
    3.31 +            <plugin>
    3.32 +                <groupId>org.apache.maven.plugins</groupId>
    3.33 +                <artifactId>maven-assembly-plugin</artifactId>
    3.34 +                <version>2.5.5</version>
    3.35 +                <configuration>
    3.36 +                    <descriptorRefs>
    3.37 +                        <descriptorRef>jar-with-dependencies</descriptorRef>
    3.38 +                    </descriptorRefs>
    3.39 +                    <archive>
    3.40 +                        <index>true</index>
    3.41 +                        <manifest>
    3.42 +                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
    3.43 +                            <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
    3.44 +                            <addClasspath>true</addClasspath>
    3.45 +                            <classpathLayoutType>simple</classpathLayoutType>
    3.46 +                            <mainClass>org.netbeans.lib.callgraph.Callgraph</mainClass>
    3.47 +                        </manifest>
    3.48 +                    </archive>
    3.49 +                </configuration>
    3.50 +                <executions>
    3.51 +                    <execution>
    3.52 +                        <id>make-assembly</id>
    3.53 +                        <phase>package</phase>
    3.54 +                        <goals>
    3.55 +                            <goal>single</goal>
    3.56 +                        </goals>
    3.57 +                        <configuration>
    3.58 +                            <descriptorRefs>
    3.59 +                                <descriptorRef>jar-with-dependencies</descriptorRef>
    3.60 +                            </descriptorRefs>
    3.61 +                            <finalName>callgraph</finalName>
    3.62 +                            <appendAssemblyId>true</appendAssemblyId>
    3.63 +                        </configuration>
    3.64 +                    </execution>
    3.65 +                </executions>
    3.66 +            </plugin>
    3.67 +        </plugins>
    3.68 +    </build>
    3.69 +    <dependencies>
    3.70 +        <dependency>
    3.71 +            <groupId>org.netbeans.external</groupId>
    3.72 +            <artifactId>nb-javac-api</artifactId>
    3.73 +            <version>RELEASE80</version>
    3.74 +            <type>jar</type>
    3.75 +        </dependency>
    3.76 +        <dependency>
    3.77 +            <groupId>org.netbeans.external</groupId>
    3.78 +            <artifactId>nb-javac-impl</artifactId>
    3.79 +            <!--<scope>provided</scope>-->
    3.80 +            <version>RELEASE80</version>
    3.81 +            <type>jar</type>
    3.82 +        </dependency>
    3.83 +        <dependency>
    3.84 +            <groupId>junit</groupId>
    3.85 +            <artifactId>junit</artifactId>
    3.86 +            <version>4.12</version>
    3.87 +            <scope>test</scope>
    3.88 +        </dependency>
    3.89 +        <dependency>
    3.90 +            <groupId>org.hamcrest</groupId>
    3.91 +            <artifactId>hamcrest-core</artifactId>
    3.92 +            <version>1.3</version>
    3.93 +            <scope>test</scope>
    3.94 +        </dependency>
    3.95 +    </dependencies>
    3.96 +    <repositories>
    3.97 +        <repository>
    3.98 +            <id>netbeans</id>
    3.99 +            <name>NetBeans</name>
   3.100 +            <url>http://bits.netbeans.org/maven2/</url>
   3.101 +            <releases>
   3.102 +                <enabled>true</enabled>
   3.103 +                <updatePolicy>never</updatePolicy>
   3.104 +            </releases>
   3.105 +            <snapshots>
   3.106 +                <enabled>true</enabled>
   3.107 +                <updatePolicy>never</updatePolicy>
   3.108 +            </snapshots>
   3.109 +        </repository>
   3.110 +    </repositories>
   3.111 +</project>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/Arguments.java	Mon Aug 31 15:31:15 2015 -0400
     4.3 @@ -0,0 +1,601 @@
     4.4 +/* 
     4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 + *
     4.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
     4.8 + *
     4.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    4.10 + * Other names may be trademarks of their respective owners.
    4.11 + *
    4.12 + * The contents of this file are subject to the terms of either the GNU
    4.13 + * General Public License Version 2 only ("GPL") or the Common
    4.14 + * Development and Distribution License("CDDL") (collectively, the
    4.15 + * "License"). You may not use this file except in compliance with the
    4.16 + * License. You can obtain a copy of the License at
    4.17 + * http://www.netbeans.org/cddl-gplv2.html
    4.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    4.19 + * specific language governing permissions and limitations under the
    4.20 + * License.  When distributing the software, include this License Header
    4.21 + * Notice in each file and include the License file at
    4.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    4.23 + * particular file as subject to the "Classpath" exception as provided
    4.24 + * by Oracle in the GPL Version 2 section of the License file that
    4.25 + * accompanied this code. If applicable, add the following below the
    4.26 + * License Header, with the fields enclosed by brackets [] replaced by
    4.27 + * your own identifying information:
    4.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    4.29 + *
    4.30 + * Contributor(s):
    4.31 + *
    4.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    4.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    4.34 + * Microsystems, Inc. All Rights Reserved.
    4.35 + *
    4.36 + * If you wish your version of this file to be governed by only the CDDL
    4.37 + * or only the GPL Version 2, indicate your decision by adding
    4.38 + * "[Contributor] elects to include this software in this distribution
    4.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    4.40 + * single choice of license, a recipient has the option to distribute
    4.41 + * your version of this file under either the CDDL, the GPL Version 2 or
    4.42 + * to extend the choice of license to its licensees as provided above.
    4.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    4.44 + * Version 2 license, then the option applies only if the new code is
    4.45 + * made subject to such option by the copyright holder.
    4.46 + */
    4.47 +
    4.48 +package org.netbeans.lib.callgraph;
    4.49 +
    4.50 +import java.io.File;
    4.51 +import java.util.Collections;
    4.52 +import java.util.HashSet;
    4.53 +import java.util.Iterator;
    4.54 +import java.util.LinkedList;
    4.55 +import java.util.List;
    4.56 +import java.util.Set;
    4.57 +
    4.58 +/**
    4.59 + * Parses and validates command-line arguments.
    4.60 + *
    4.61 + * @author Tim Boudreau
    4.62 + */
    4.63 +final class Arguments implements CallgraphControl {
    4.64 +
    4.65 +    private Set<File> folders = new HashSet<>();
    4.66 +    private static final Command[] commands = new Command[]{
    4.67 +        new NoSelfReferencesCommand(),
    4.68 +        new ShortNamesCommand(),
    4.69 +        new MavenCommand(),
    4.70 +        new OutfileCommand(),
    4.71 +        new ExcludeCommand(),
    4.72 +        new PackageGraphFileCommand(),
    4.73 +        new ClassGraphFileCommand(),
    4.74 +        new OmitAbstractCommand(),
    4.75 +        new DisableEightBitStringsCommand(),
    4.76 +        new OmitAbstractCommand(),
    4.77 +        new QuietCommand(),
    4.78 +        new ReverseCommand(),
    4.79 +        new VerboseCommand()
    4.80 +    };
    4.81 +    private boolean noSelfReferences = false;
    4.82 +    private boolean shortNames = false;
    4.83 +    private boolean maven = false;
    4.84 +    private File outfile;
    4.85 +    private Set<String> exclude = new HashSet<>();
    4.86 +    private boolean quiet;
    4.87 +    private File classGraphFile;
    4.88 +    private File packageGraphFile;
    4.89 +    private boolean verbose;
    4.90 +    private boolean omitAbstract;
    4.91 +    private boolean disableEightBitStrings;
    4.92 +    private boolean reverse;
    4.93 +
    4.94 +    Arguments(String... args) {
    4.95 +        this(true, args);
    4.96 +    }
    4.97 +
    4.98 +    Arguments(boolean abortIfWillNotOutput, String... args) {
    4.99 +        List<String> unknownArguments = new LinkedList<>();
   4.100 +        List<String> errors = new LinkedList<>();
   4.101 +        for (int i = 0; i < args.length;) {
   4.102 +            int oldPos = i;
   4.103 +            for (Command c : commands) {
   4.104 +                try {
   4.105 +                    @SuppressWarnings("LeakingThisInConstructor")
   4.106 +                    int increment = c.parse(i, args, this);
   4.107 +                    if (increment > 0) {
   4.108 +                        i += increment;
   4.109 +                        break;
   4.110 +                    }
   4.111 +                } catch (IllegalArgumentException ex) {
   4.112 +                    errors.add(c.name + ": " + ex.getMessage());
   4.113 +                }
   4.114 +            }
   4.115 +            if (oldPos == i) {
   4.116 +                unknownArguments.add(args[i]);
   4.117 +                i++;
   4.118 +            }
   4.119 +        }
   4.120 +        Set<String> folders = new HashSet<>();
   4.121 +        for (String unknown : unknownArguments) {
   4.122 +            if (unknown.startsWith("-")) {
   4.123 +                // bad line switch
   4.124 +                errors.add("Unknown argument '" + unknown + "'");
   4.125 +            } else {
   4.126 +                folders.add(unknown);
   4.127 +            }
   4.128 +        }
   4.129 +        if (folders.isEmpty()) {
   4.130 +            errors.add("No folders of Java sources specified");
   4.131 +        } else {
   4.132 +            for (String folderName : folders) {
   4.133 +                File folder = new File(folderName);
   4.134 +                if (!folder.exists()) {
   4.135 +                    errors.add("Folder does not exist: " + folderName);
   4.136 +                } else if (!folder.isDirectory()) {
   4.137 +                    errors.add("Not a folder: " + folderName);
   4.138 +                } else {
   4.139 +                    this.folders.add(folder);
   4.140 +                }
   4.141 +            }
   4.142 +        }
   4.143 +        if (maven) {
   4.144 +            findMavenSubfolders(errors);
   4.145 +        }
   4.146 +        if (packageGraphFile != null) {
   4.147 +            File parent = packageGraphFile.getParentFile();
   4.148 +            if (!parent.exists() || !parent.isDirectory()) {
   4.149 +                errors.add("Parent folder for package graph output file does not exist: " + parent);
   4.150 +            }
   4.151 +        }
   4.152 +        if (classGraphFile != null) {
   4.153 +            File parent = classGraphFile.getParentFile();
   4.154 +            if (!parent.exists() || !parent.isDirectory()) {
   4.155 +                errors.add("Parent folder for class graph output file does not exist: " + parent);
   4.156 +            }
   4.157 +        }
   4.158 +        if (outfile != null) {
   4.159 +            File parent = outfile.getParentFile();
   4.160 +            if (!parent.exists() || !parent.isDirectory()) {
   4.161 +                errors.add("Parent folder for output file does not exist: " + parent);
   4.162 +            }
   4.163 +        } else if (abortIfWillNotOutput && quiet && packageGraphFile == null && classGraphFile == null) {
   4.164 +            errors.add("-q or --quiet specified, but no output file specified - would not produce any output at all");
   4.165 +        }
   4.166 +        // XXX check if any folders are children of each other?
   4.167 +        if (!errors.isEmpty()) {
   4.168 +            throw new InvalidArgumentsException(help(errors), errors);
   4.169 +        }
   4.170 +    }
   4.171 +
   4.172 +    private void findMavenSubfolders(List<String> errors) {
   4.173 +        Set<File> flds = new HashSet<>(this.folders);
   4.174 +        this.folders.clear();
   4.175 +        for (File f : flds) {
   4.176 +            recurseSubfoldersLookingForMavenProjects(f);
   4.177 +        }
   4.178 +        if (this.folders.isEmpty()) {
   4.179 +            errors.add("Did not find any maven projects (looked for pom.xml and src/main/java in all subfolders of folder list)");
   4.180 +        }
   4.181 +    }
   4.182 +
   4.183 +    private void recurseSubfoldersLookingForMavenProjects(File file) {
   4.184 +        if (file.isDirectory()) {
   4.185 +            if (hasPom(file)) {
   4.186 +                File sources = srcMainJavaFolder(file);
   4.187 +                if (sources != null) {
   4.188 +                    this.folders.add(sources);
   4.189 +                }
   4.190 +            }
   4.191 +            for (File child : file.listFiles()) {
   4.192 +                recurseSubfoldersLookingForMavenProjects(child);
   4.193 +            }
   4.194 +        }
   4.195 +    }
   4.196 +
   4.197 +    private boolean hasPom(File fld) {
   4.198 +        File pom = new File(fld, "pom.xml");
   4.199 +        return pom.exists() && pom.isFile() && pom.canRead();
   4.200 +    }
   4.201 +
   4.202 +    private File srcMainJavaFolder(File projectFolder) {
   4.203 +        File src = new File(projectFolder, "src");
   4.204 +        File main = new File(src, "main");
   4.205 +        File java = new File(main, "java");
   4.206 +        if (java.exists() && java.isDirectory()) {
   4.207 +            return java;
   4.208 +        }
   4.209 +        return null;
   4.210 +    }
   4.211 +
   4.212 +    public boolean isVerbose() {
   4.213 +        return verbose;
   4.214 +    }
   4.215 +
   4.216 +    public boolean isDisableEightBitStrings() {
   4.217 +        return disableEightBitStrings;
   4.218 +    }
   4.219 +
   4.220 +    public boolean isReverse() {
   4.221 +        return reverse;
   4.222 +    }
   4.223 +
   4.224 +    @Override
   4.225 +    public File methodGraphFile() {
   4.226 +        return outfile;
   4.227 +    }
   4.228 +
   4.229 +    @Override
   4.230 +    public Set<File> folders() {
   4.231 +        return Collections.unmodifiableSet(folders);
   4.232 +    }
   4.233 +
   4.234 +    @Override
   4.235 +    public boolean isSelfReferences() {
   4.236 +        return noSelfReferences == false;
   4.237 +    }
   4.238 +
   4.239 +    @Override
   4.240 +    public boolean isShortNames() {
   4.241 +        return shortNames;
   4.242 +    }
   4.243 +
   4.244 +    @Override
   4.245 +    public boolean isMaven() {
   4.246 +        return maven;
   4.247 +    }
   4.248 +
   4.249 +    @Override
   4.250 +    public File classGraphFile() {
   4.251 +        return classGraphFile;
   4.252 +    }
   4.253 +
   4.254 +    @Override
   4.255 +    public File packageGraphFile() {
   4.256 +        return packageGraphFile;
   4.257 +    }
   4.258 +
   4.259 +    @Override
   4.260 +    public Iterator<File> iterator() {
   4.261 +        return folders().iterator();
   4.262 +    }
   4.263 +
   4.264 +    @Override
   4.265 +    public Set<String> excludePrefixes() {
   4.266 +        return Collections.unmodifiableSet(exclude);
   4.267 +    }
   4.268 +
   4.269 +    public boolean isOmitAbstract() {
   4.270 +        return omitAbstract;
   4.271 +    }
   4.272 +
   4.273 +    public boolean isExcluded(String qname) {
   4.274 +        for (String ex : exclude) {
   4.275 +            if (qname.startsWith(ex)) {
   4.276 +                return true;
   4.277 +            }
   4.278 +        }
   4.279 +        return false;
   4.280 +    }
   4.281 +
   4.282 +    @Override
   4.283 +    public boolean isQuiet() {
   4.284 +        return quiet;
   4.285 +    }
   4.286 +
   4.287 +    private String help(List<String> errors) {
   4.288 +        StringBuilder sb = new StringBuilder("Callgraph prints a graph of things that call each other in a tree of Java sources,\n"
   4.289 +                + "and can output graphs of what methods / classes / packages (or all of the above) call each other\nwithin that"
   4.290 +                + "source tree."
   4.291 +                + "\n\nUsage:\njava -jar callgraph.jar ");
   4.292 +        for (Command c : commands) {
   4.293 +            if (c.optional) {
   4.294 +                sb.append('[');
   4.295 +            }
   4.296 +            sb.append("--").append(c.name).append(" | -").append(c.shortcut);
   4.297 +            if (c.takesArgument) {
   4.298 +                sb.append(" ").append(c.name);
   4.299 +            }
   4.300 +            if (c.optional) {
   4.301 +                sb.append(']');
   4.302 +            }
   4.303 +            sb.append(' ');
   4.304 +        }
   4.305 +        sb.append("dir1 [dir2 dir3 ...]");
   4.306 +        sb.append('\n');
   4.307 +        for (Command c : commands) {
   4.308 +            sb.append("\n\t");
   4.309 +            sb.append("--").append(c.name).append(" / -").append(c.shortcut).append(" :\t").append(c.help());
   4.310 +        }
   4.311 +        if (!errors.isEmpty()) {
   4.312 +            sb.append("\nErrors:\n");
   4.313 +            for (String err : errors) {
   4.314 +                sb.append('\t').append(err).append('\n');
   4.315 +            }
   4.316 +        }
   4.317 +        return sb.toString();
   4.318 +    }
   4.319 +
   4.320 +    private static abstract class Command {
   4.321 +
   4.322 +        protected final String name;
   4.323 +        protected final String shortcut;
   4.324 +        protected final boolean optional;
   4.325 +        private final boolean takesArgument;
   4.326 +
   4.327 +        Command(String name, String shortcut, boolean optional, boolean takesArgument) {
   4.328 +            this.name = name;
   4.329 +            this.shortcut = shortcut;
   4.330 +            this.optional = optional;
   4.331 +            this.takesArgument = takesArgument;
   4.332 +        }
   4.333 +
   4.334 +        public int parse(int position, String[] args, Arguments toSet) {
   4.335 +            boolean match = ("-" + shortcut).equals(args[position])
   4.336 +                    || ("--" + name).equals(args[position]);
   4.337 +            if (!match) {
   4.338 +                return 0;
   4.339 +            }
   4.340 +            return doParse(position, args, toSet);
   4.341 +        }
   4.342 +
   4.343 +        protected abstract int doParse(int i, String[] args, Arguments toSet);
   4.344 +
   4.345 +        protected abstract String help();
   4.346 +
   4.347 +        public String toString() {
   4.348 +            return name;
   4.349 +        }
   4.350 +    }
   4.351 +
   4.352 +    private static final class NoSelfReferencesCommand extends Command {
   4.353 +
   4.354 +        NoSelfReferencesCommand() {
   4.355 +            super(CMD_NOSELF, "n", true, false);
   4.356 +        }
   4.357 +
   4.358 +        @Override
   4.359 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.360 +            toSet.noSelfReferences = true;
   4.361 +            return 1;
   4.362 +        }
   4.363 +
   4.364 +        @Override
   4.365 +        protected String help() {
   4.366 +            return "Hide intra-class calls (i.e. if Foo.bar() calls Foo.baz(), don't include it)";
   4.367 +        }
   4.368 +    }
   4.369 +
   4.370 +    private static final class DisableEightBitStringsCommand extends Command {
   4.371 +
   4.372 +        DisableEightBitStringsCommand() {
   4.373 +            super(CMD_DISABLE_EIGHT_BIT_STRINGS, "u", true, false);
   4.374 +        }
   4.375 +
   4.376 +        @Override
   4.377 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.378 +            toSet.noSelfReferences = true;
   4.379 +            return 1;
   4.380 +        }
   4.381 +
   4.382 +        @Override
   4.383 +        protected String help() {
   4.384 +            return "Disable string memory optimizations - runs faster but may run out of memory";
   4.385 +        }
   4.386 +    }
   4.387 +
   4.388 +    private static final class ReverseCommand extends Command {
   4.389 +
   4.390 +        ReverseCommand() {
   4.391 +            super(CMD_REVERSE, "r", true, false);
   4.392 +        }
   4.393 +
   4.394 +        @Override
   4.395 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.396 +            toSet.reverse = true;
   4.397 +            return 1;
   4.398 +        }
   4.399 +
   4.400 +        @Override
   4.401 +        protected String help() {
   4.402 +            return "Reverse the edges of graph nodes";
   4.403 +        }
   4.404 +    }
   4.405 +
   4.406 +    private static final class ShortNamesCommand extends Command {
   4.407 +
   4.408 +        ShortNamesCommand() {
   4.409 +            super(CMD_SIMPLE, "s", true, false);
   4.410 +        }
   4.411 +
   4.412 +        @Override
   4.413 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.414 +            toSet.shortNames = true;
   4.415 +            return 1;
   4.416 +        }
   4.417 +
   4.418 +        @Override
   4.419 +        protected String help() {
   4.420 +            return "Use simple class names without the package (may confuse results if two classes have the same name)";
   4.421 +        }
   4.422 +    }
   4.423 +
   4.424 +    private static final class MavenCommand extends Command {
   4.425 +
   4.426 +        MavenCommand() {
   4.427 +            super(CMD_MAVEN, "m", true, false);
   4.428 +        }
   4.429 +
   4.430 +        @Override
   4.431 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.432 +            toSet.maven = true;
   4.433 +            return 1;
   4.434 +        }
   4.435 +
   4.436 +        @Override
   4.437 +        protected String help() {
   4.438 +            return "Find all maven projects that are children of the passed folders, and scan their src/main/java subfolders";
   4.439 +        }
   4.440 +    }
   4.441 +
   4.442 +    private static final class OmitAbstractCommand extends Command {
   4.443 +
   4.444 +        OmitAbstractCommand() {
   4.445 +            super(CMD_OMIT_ABSTRACT, "a", true, false);
   4.446 +        }
   4.447 +
   4.448 +        @Override
   4.449 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.450 +            toSet.omitAbstract = true;
   4.451 +            return 1;
   4.452 +        }
   4.453 +
   4.454 +        @Override
   4.455 +        protected String help() {
   4.456 +            return "Don't emit calls to abstract methods";
   4.457 +        }
   4.458 +    }
   4.459 +
   4.460 +    private static final class VerboseCommand extends Command {
   4.461 +
   4.462 +        VerboseCommand() {
   4.463 +            super(CMD_VERBOSE, "v", true, false);
   4.464 +        }
   4.465 +
   4.466 +        @Override
   4.467 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.468 +            toSet.verbose = true;
   4.469 +            return 1;
   4.470 +        }
   4.471 +
   4.472 +        @Override
   4.473 +        protected String help() {
   4.474 +            return "Print output about what is being processed";
   4.475 +        }
   4.476 +    }
   4.477 +
   4.478 +    private static final class QuietCommand extends Command {
   4.479 +
   4.480 +        QuietCommand() {
   4.481 +            super(CMD_QUIET, "q", true, false);
   4.482 +        }
   4.483 +
   4.484 +        @Override
   4.485 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.486 +            toSet.quiet = true;
   4.487 +            return 1;
   4.488 +        }
   4.489 +
   4.490 +        @Override
   4.491 +        protected String help() {
   4.492 +            return "Supress writing the graph to the standard output";
   4.493 +        }
   4.494 +    }
   4.495 +
   4.496 +    private static final class OutfileCommand extends Command {
   4.497 +
   4.498 +        OutfileCommand() {
   4.499 +            super(CMD_METHODGRAPH, "g", true, true);
   4.500 +        }
   4.501 +
   4.502 +        @Override
   4.503 +        protected int doParse(int index, String[] args, Arguments toSet) {
   4.504 +            if (args.length == index + 1) {
   4.505 +                throw new IllegalArgumentException("--outfile or -o present but no output file specified");
   4.506 +            }
   4.507 +            toSet.outfile = new File(args[index + 1]);
   4.508 +            return 2;
   4.509 +        }
   4.510 +
   4.511 +        @Override
   4.512 +        protected String help() {
   4.513 +            return "Set the output file for the method call graph";
   4.514 +        }
   4.515 +    }
   4.516 +
   4.517 +    private static final class ClassGraphFileCommand extends Command {
   4.518 +
   4.519 +        ClassGraphFileCommand() {
   4.520 +            super(CMD_CLASSGRAPH, "c", true, true);
   4.521 +        }
   4.522 +
   4.523 +        @Override
   4.524 +        protected int doParse(int index, String[] args, Arguments toSet) {
   4.525 +            if (args.length == index + 1) {
   4.526 +                throw new IllegalArgumentException("--outfile or -o present but no output file specified");
   4.527 +            }
   4.528 +            toSet.classGraphFile = new File(args[index + 1]);
   4.529 +            return 2;
   4.530 +        }
   4.531 +
   4.532 +        @Override
   4.533 +        protected String help() {
   4.534 +            return "Set the output file for the class call graph";
   4.535 +        }
   4.536 +    }
   4.537 +
   4.538 +    private static final class PackageGraphFileCommand extends Command {
   4.539 +
   4.540 +        PackageGraphFileCommand() {
   4.541 +            super(CMD_PACKAGEGRAPH, "p", true, true);
   4.542 +        }
   4.543 +
   4.544 +        @Override
   4.545 +        protected int doParse(int index, String[] args, Arguments toSet) {
   4.546 +            if (args.length == index + 1) {
   4.547 +                throw new IllegalArgumentException("--outfile or -o present but no output file specified");
   4.548 +            }
   4.549 +            toSet.packageGraphFile = new File(args[index + 1]);
   4.550 +            return 2;
   4.551 +        }
   4.552 +
   4.553 +        @Override
   4.554 +        protected String help() {
   4.555 +            return "Set the output file for the package call graph";
   4.556 +        }
   4.557 +    }
   4.558 +
   4.559 +    private static final class ExcludeCommand extends Command {
   4.560 +
   4.561 +        ExcludeCommand() {
   4.562 +            super("exclude", "e", true, true);
   4.563 +        }
   4.564 +
   4.565 +        @Override
   4.566 +        protected int doParse(int i, String[] args, Arguments toSet) {
   4.567 +            if (args.length == i + 1) {
   4.568 +                throw new IllegalArgumentException("--exclude or -e present but no exclusion list present");
   4.569 +            }
   4.570 +            for (String s : args[i + 1].split(",")) {
   4.571 +                toSet.exclude.add(s);
   4.572 +            }
   4.573 +            return 2;
   4.574 +        }
   4.575 +
   4.576 +        @Override
   4.577 +        protected String help() {
   4.578 +            return "Exclude any relationships where the fully qualified class name starts with any pattern in this comma-delimited list of strings, e.g. -e foo.bar,foo.baz";
   4.579 +        }
   4.580 +    }
   4.581 +
   4.582 +    static final class InvalidArgumentsException extends IllegalArgumentException {
   4.583 +
   4.584 +        private final List<String> errors;
   4.585 +
   4.586 +        InvalidArgumentsException(String msg, List<String> errors) {
   4.587 +            super(msg);
   4.588 +            this.errors = errors;
   4.589 +        }
   4.590 +
   4.591 +        public List<String> errors() {
   4.592 +            return errors;
   4.593 +        }
   4.594 +
   4.595 +        public boolean errorContains(String test) { //for tests
   4.596 +            for (String err : errors) {
   4.597 +                if (err.contains(test)) {
   4.598 +                    return true;
   4.599 +                }
   4.600 +            }
   4.601 +            return false;
   4.602 +        }
   4.603 +    }
   4.604 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/Callgraph.java	Mon Aug 31 15:31:15 2015 -0400
     5.3 @@ -0,0 +1,400 @@
     5.4 +/* 
     5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 + *
     5.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
     5.8 + *
     5.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    5.10 + * Other names may be trademarks of their respective owners.
    5.11 + *
    5.12 + * The contents of this file are subject to the terms of either the GNU
    5.13 + * General Public License Version 2 only ("GPL") or the Common
    5.14 + * Development and Distribution License("CDDL") (collectively, the
    5.15 + * "License"). You may not use this file except in compliance with the
    5.16 + * License. You can obtain a copy of the License at
    5.17 + * http://www.netbeans.org/cddl-gplv2.html
    5.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    5.19 + * specific language governing permissions and limitations under the
    5.20 + * License.  When distributing the software, include this License Header
    5.21 + * Notice in each file and include the License file at
    5.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    5.23 + * particular file as subject to the "Classpath" exception as provided
    5.24 + * by Oracle in the GPL Version 2 section of the License file that
    5.25 + * accompanied this code. If applicable, add the following below the
    5.26 + * License Header, with the fields enclosed by brackets [] replaced by
    5.27 + * your own identifying information:
    5.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    5.29 + *
    5.30 + * Contributor(s):
    5.31 + *
    5.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    5.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    5.34 + * Microsystems, Inc. All Rights Reserved.
    5.35 + *
    5.36 + * If you wish your version of this file to be governed by only the CDDL
    5.37 + * or only the GPL Version 2, indicate your decision by adding
    5.38 + * "[Contributor] elects to include this software in this distribution
    5.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    5.40 + * single choice of license, a recipient has the option to distribute
    5.41 + * your version of this file under either the CDDL, the GPL Version 2 or
    5.42 + * to extend the choice of license to its licensees as provided above.
    5.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    5.44 + * Version 2 license, then the option applies only if the new code is
    5.45 + * made subject to such option by the copyright holder.
    5.46 + */
    5.47 +
    5.48 +package org.netbeans.lib.callgraph;
    5.49 +
    5.50 +import org.netbeans.lib.callgraph.Arguments.InvalidArgumentsException;
    5.51 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_CLASSGRAPH;
    5.52 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_DISABLE_EIGHT_BIT_STRINGS;
    5.53 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_EXCLUDE;
    5.54 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_MAVEN;
    5.55 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_METHODGRAPH;
    5.56 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_NOSELF;
    5.57 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_OMIT_ABSTRACT;
    5.58 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_PACKAGEGRAPH;
    5.59 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_QUIET;
    5.60 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_REVERSE;
    5.61 +import static org.netbeans.lib.callgraph.CallgraphControl.CMD_SIMPLE;
    5.62 +import org.netbeans.lib.callgraph.io.JavaFilesIterator;
    5.63 +import org.netbeans.lib.callgraph.javac.JavacRunner;
    5.64 +import org.netbeans.lib.callgraph.javac.SourceElement;
    5.65 +import org.netbeans.lib.callgraph.javac.SourcesInfo;
    5.66 +import org.netbeans.lib.callgraph.util.MergeIterator;
    5.67 +import java.io.File;
    5.68 +import java.io.IOException;
    5.69 +import java.io.PrintStream;
    5.70 +import java.util.ArrayList;
    5.71 +import java.util.Collections;
    5.72 +import java.util.HashSet;
    5.73 +import java.util.Iterator;
    5.74 +import java.util.LinkedList;
    5.75 +import java.util.List;
    5.76 +import java.util.Set;
    5.77 +
    5.78 +/**
    5.79 + * Scans a source folder and runs javac against any Java sources present, and
    5.80 + * builds graphs of what calls what within those. The library classpath does not
    5.81 + * need to be set, and the folders do not need to be package roots - we are
    5.82 + * instructing javac to treat errors as non-fatal. The available sources will be
    5.83 + * attributed.
    5.84 + *
    5.85 + * @author Tim Boudreau
    5.86 + */
    5.87 +public final class Callgraph {
    5.88 +
    5.89 +    private boolean noself;
    5.90 +    private boolean maven;
    5.91 +    private boolean quiet;
    5.92 +    private boolean simple;
    5.93 +    private final Set<String> excludes = new HashSet<>();
    5.94 +    private final Set<File> folders = new HashSet<>();
    5.95 +    private File classgraphFile;
    5.96 +    private File methodgraphFile;
    5.97 +    private File packagegraphFile;
    5.98 +    private Listener listener;
    5.99 +    private boolean omitAbstract;
   5.100 +    private boolean useJavaStrings;
   5.101 +    private boolean reverse;
   5.102 +
   5.103 +    private Callgraph() {
   5.104 +    }
   5.105 +
   5.106 +    /**
   5.107 +     * Configure a Callgraph to build.
   5.108 +     *
   5.109 +     * @return A call graph to configure
   5.110 +     */
   5.111 +    public static Callgraph configure() {
   5.112 +        return new Callgraph();
   5.113 +    }
   5.114 +
   5.115 +    public static void main(String[] args) throws IOException {
   5.116 +        CallgraphControl arguments = null;
   5.117 +        try {
   5.118 +            arguments = new Arguments(args);
   5.119 +        } catch (InvalidArgumentsException ex) {
   5.120 +            // this will be a help message describing usage and the invalid
   5.121 +            // arguments
   5.122 +            System.err.println(ex.getMessage());
   5.123 +            System.exit(1);
   5.124 +        }
   5.125 +        assert arguments != null;
   5.126 +        invoke(arguments, arguments.isVerbose() ? new LoggingListener() : null);
   5.127 +    }
   5.128 +
   5.129 +    /**
   5.130 +     * Run javac and produce output.
   5.131 +     *
   5.132 +     * @param arguments The parsed arguments
   5.133 +     * @return The list of all methods found, sorted by qname
   5.134 +     * @throws IOException If i/o fails
   5.135 +     */
   5.136 +    static List<SourceElement> invoke(CallgraphControl arguments, Listener listener) throws IOException {
   5.137 +        SourcesInfo info = new SourcesInfo(arguments.isDisableEightBitStrings());
   5.138 +        // Build an iterable of all Java sources (without collecting them all ahead of time)
   5.139 +        List<Iterable<File>> iterables = new LinkedList<>();
   5.140 +        for (File folder : arguments) {
   5.141 +            iterables.add(JavaFilesIterator.iterable(folder));
   5.142 +        }
   5.143 +        // The thing that will run javac
   5.144 +        JavacRunner runner = new JavacRunner(info, MergeIterator.toIterable(iterables), listener);
   5.145 +        // run javac
   5.146 +        Set<SourceElement> allElements = runner.go();
   5.147 +
   5.148 +        List<SourceElement> all = new ArrayList<>(allElements);
   5.149 +        // Sort, so textual output is more human-friendly
   5.150 +        Collections.sort(all);
   5.151 +        // Now write files and print output
   5.152 +        if (!all.isEmpty()) {
   5.153 +            PrintStream outStream = createPrintStreamIfNotNull(arguments.methodGraphFile());
   5.154 +            PrintStream packageStream = createPrintStreamIfNotNull(arguments.packageGraphFile());
   5.155 +            PrintStream classStream = createPrintStreamIfNotNull(arguments.classGraphFile());
   5.156 +            // duplicate avoidance
   5.157 +            Set<CharSequence> emittedPackageLines = new HashSet<>();
   5.158 +            Set<CharSequence> emittedClassLines = new HashSet<>();
   5.159 +            try {
   5.160 +                // Iterate every method
   5.161 +                for (SourceElement sce : all) {
   5.162 +                    if (arguments.isExcluded(sce.qname().toString())) { // Ignore matches
   5.163 +                        continue;
   5.164 +                    }
   5.165 +                    List<SourceElement> outbounds = new ArrayList<>(arguments.isReverse() ? sce.getInboundReferences() : sce.getOutboundReferences());
   5.166 +                    Collections.sort(outbounds); // also sort connections
   5.167 +                    // Iterate the current method's connections
   5.168 +                    for (SourceElement outbound : outbounds) {
   5.169 +                        if (arguments.isExcluded(outbound.qname().toString())) { // Ignore matches
   5.170 +                            continue;
   5.171 +                        }
   5.172 +                        // If we are ignoring abstract methods, do that - has no effect on classes
   5.173 +                        if (arguments.isOmitAbstract() && (outbound.isAbstract() | sce.isAbstract())) {
   5.174 +                            continue;
   5.175 +                        }
   5.176 +                        // If the argument is set, ignore cases where it's a class' method
   5.177 +                        // referencing another method on that class
   5.178 +                        if (!arguments.isSelfReferences() && sce.typeName().equals(outbound.typeName())) {
   5.179 +                            continue;
   5.180 +                        }
   5.181 +                        CharSequence line;
   5.182 +                        // Build our line for the method graph output
   5.183 +                        if (arguments.isShortNames()) {
   5.184 +                            line = info.strings.concat(info.strings.QUOTE, sce.shortName(), info.strings.CLOSE_OPEN_QUOTE, outbound.shortName(), info.strings.QUOTE);
   5.185 +                        } else {
   5.186 +                            line = info.strings.concat(info.strings.QUOTE, sce.qname(), info.strings.CLOSE_OPEN_QUOTE, outbound.qname(), info.strings.QUOTE);
   5.187 +                        }
   5.188 +                        // Print to stdout
   5.189 +                        if (!arguments.isQuiet()) {
   5.190 +                            System.out.println(line);
   5.191 +                        }
   5.192 +                        // Write to file if necessary
   5.193 +                        if (outStream != null) {
   5.194 +                            outStream.println(line);
   5.195 +                        }
   5.196 +                        // Build the package graph output if necessary
   5.197 +                        if (packageStream != null) {
   5.198 +                            CharSequence pkg1 = sce.packageName();
   5.199 +                            CharSequence pkg2 = outbound.packageName();
   5.200 +                            if (!pkg1.equals(pkg2)) {
   5.201 +//                                CharSequence pkgLine = '"' + pkg1.toString() + "\" \"" + pkg2.toString() + '"';
   5.202 +                                CharSequence pkgLine = info.strings.concat(info.strings.QUOTE, pkg1, info.strings.CLOSE_OPEN_QUOTE, pkg2, info.strings.QUOTE);
   5.203 +                                if (!emittedPackageLines.contains(pkgLine)) {
   5.204 +                                    emittedPackageLines.add(pkgLine);
   5.205 +                                    packageStream.println(pkgLine);
   5.206 +                                }
   5.207 +                            }
   5.208 +                        }
   5.209 +                        // Build the class graph output if necessary
   5.210 +                        if (classStream != null) {
   5.211 +                            CharSequence type1 = sce.typeName();
   5.212 +                            CharSequence type2 = outbound.typeName();
   5.213 +                            if (!arguments.isShortNames()) {
   5.214 +                                type1 = info.strings.concat(sce.packageName(), info.strings.DOT, type1);
   5.215 +                                type2 = info.strings.concat(outbound.packageName(), info.strings.DOT, type2);
   5.216 +                            }
   5.217 +                            if (!type1.equals(type2)) {
   5.218 +                                CharSequence classLine = info.strings.concat(info.strings.QUOTE, type1, info.strings.CLOSE_OPEN_QUOTE, type2, info.strings.QUOTE);
   5.219 +                                if (!emittedClassLines.contains(classLine)) {
   5.220 +                                    emittedClassLines.add(classLine);
   5.221 +                                    classStream.println(classLine);
   5.222 +                                }
   5.223 +                            }
   5.224 +                        }
   5.225 +                    }
   5.226 +                }
   5.227 +            } finally {
   5.228 +                for (PrintStream ps : new PrintStream[]{outStream, packageStream, classStream}) {
   5.229 +                    if (ps != null) {
   5.230 +                        ps.close();
   5.231 +                    }
   5.232 +                }
   5.233 +            }
   5.234 +        }
   5.235 +        return all;
   5.236 +    }
   5.237 +
   5.238 +    private static PrintStream createPrintStreamIfNotNull(File outputFile) throws IOException {
   5.239 +        PrintStream outStream = null;
   5.240 +        if (outputFile != null) {
   5.241 +            if (!outputFile.exists()) {
   5.242 +                if (!outputFile.createNewFile()) {
   5.243 +                    throw new IllegalStateException("Could not create " + outputFile);
   5.244 +                }
   5.245 +            }
   5.246 +            outStream = new PrintStream(outputFile);
   5.247 +        }
   5.248 +        return outStream;
   5.249 +    }
   5.250 +
   5.251 +    public List<String> toCommandLineArguments() {
   5.252 +        List<String> args = new ArrayList<>();
   5.253 +        addBoolean(CMD_NOSELF, noself, args);
   5.254 +        addBoolean(CMD_MAVEN, maven, args);
   5.255 +        addBoolean(CMD_QUIET, quiet, args);
   5.256 +        addBoolean(CMD_SIMPLE, simple, args);
   5.257 +        addBoolean(CMD_REVERSE, reverse, args);
   5.258 +        addBoolean(CMD_DISABLE_EIGHT_BIT_STRINGS, useJavaStrings, args);
   5.259 +        addBoolean(CMD_OMIT_ABSTRACT, omitAbstract, args);
   5.260 +        if (!excludes.isEmpty()) {
   5.261 +            StringBuilder concat = new StringBuilder();
   5.262 +            for (Iterator<String> it = excludes.iterator(); it.hasNext();) {
   5.263 +                String next = it.next();
   5.264 +                concat.append(next);
   5.265 +                if (it.hasNext()) {
   5.266 +                    concat.append(",");
   5.267 +                }
   5.268 +            }
   5.269 +            args.add("--" + CMD_EXCLUDE);
   5.270 +            args.add(concat.toString());
   5.271 +        }
   5.272 +        addFile(CMD_CLASSGRAPH, classgraphFile, args);
   5.273 +        addFile(CMD_METHODGRAPH, methodgraphFile, args);
   5.274 +        addFile(CMD_PACKAGEGRAPH, packagegraphFile, args);
   5.275 +        for (File fld : folders) {
   5.276 +            args.add(fld.getAbsolutePath());
   5.277 +        }
   5.278 +        return args;
   5.279 +    }
   5.280 +
   5.281 +    CallgraphControl build() {
   5.282 +        List<String> args = toCommandLineArguments();
   5.283 +        // We use regular string processing so we get the argument validation
   5.284 +        String[] argList = args.toArray(new String[args.size()]);
   5.285 +        Arguments arguments = new Arguments(false, argList);
   5.286 +        return arguments;
   5.287 +    }
   5.288 +
   5.289 +    /**
   5.290 +     * Run this callgraph, writing output and returning the set of all methods
   5.291 +     * found, sorted in qname order. Call SourceElement.getInboundReferences()
   5.292 +     * and SourceElement.getOutboundReferences() to explore the graph.
   5.293 +     *
   5.294 +     * @return Sorted set of source elements
   5.295 +     * @throws IOException If i/o fails
   5.296 +     */
   5.297 +    public List<SourceElement> run() throws IOException {
   5.298 +        return Callgraph.invoke(build(), listener);
   5.299 +    }
   5.300 +
   5.301 +    private void addFile(String command, File file, List<String> args) {
   5.302 +        if (file != null) {
   5.303 +            args.add("--" + command);
   5.304 +            args.add(file.getAbsolutePath());
   5.305 +        }
   5.306 +    }
   5.307 +
   5.308 +    private void addBoolean(String command, boolean val, List<String> args) {
   5.309 +        if (val) {
   5.310 +            args.add("--" + command);
   5.311 +        }
   5.312 +    }
   5.313 +
   5.314 +    public Callgraph setListener(Listener listener) {
   5.315 +        this.listener = listener;
   5.316 +        return this;
   5.317 +    }
   5.318 +
   5.319 +    public Callgraph packageGraphOutput(File file) {
   5.320 +        packagegraphFile = file;
   5.321 +        return this;
   5.322 +    }
   5.323 +
   5.324 +    public Callgraph methodGraphOutput(File file) {
   5.325 +        methodgraphFile = file;
   5.326 +        return this;
   5.327 +    }
   5.328 +
   5.329 +    public Callgraph classGraphOutput(File file) {
   5.330 +        classgraphFile = file;
   5.331 +        return this;
   5.332 +    }
   5.333 +
   5.334 +    public Callgraph addSourceParent(File folder) {
   5.335 +        folders.add(folder);
   5.336 +        return this;
   5.337 +    }
   5.338 +
   5.339 +    public Callgraph excludePrefix(String prefix) {
   5.340 +        excludes.add(prefix);
   5.341 +        return this;
   5.342 +    }
   5.343 +
   5.344 +    public Callgraph useSimpleClassNames() {
   5.345 +        simple = true;
   5.346 +        return this;
   5.347 +    }
   5.348 +
   5.349 +    public Callgraph quiet() {
   5.350 +        quiet = true;
   5.351 +        return this;
   5.352 +    }
   5.353 +
   5.354 +    public Callgraph ignoreSelfReferences() {
   5.355 +        noself = true;
   5.356 +        return this;
   5.357 +    }
   5.358 +
   5.359 +    public Callgraph scanFoldersForMavenProjects() {
   5.360 +        maven = true;
   5.361 +        return this;
   5.362 +    }
   5.363 +
   5.364 +    public Callgraph reverse() {
   5.365 +        reverse = true;
   5.366 +        return this;
   5.367 +    }
   5.368 +
   5.369 +    public Callgraph useJavaStrings() {
   5.370 +        useJavaStrings = true;
   5.371 +        return this;
   5.372 +    }
   5.373 +
   5.374 +    public Callgraph omitAbstract() {
   5.375 +        omitAbstract = true;
   5.376 +        return this;
   5.377 +    }
   5.378 +
   5.379 +    private static final class LoggingListener implements Listener {
   5.380 +
   5.381 +        @Override
   5.382 +        public void onStart() {
   5.383 +            //do nothing
   5.384 +        }
   5.385 +
   5.386 +        @Override
   5.387 +        public void onFinish() {
   5.388 +            System.out.println("Done.");
   5.389 +        }
   5.390 +
   5.391 +        @Override
   5.392 +        public void onStartActivity(String activity, int steps) {
   5.393 +            if (steps > 0) {
   5.394 +                System.out.println(activity + " (" + steps + " steps)");
   5.395 +            }
   5.396 +        }
   5.397 +
   5.398 +        @Override
   5.399 +        public void onStep(String step) {
   5.400 +            System.out.println("\t" + step);
   5.401 +        }
   5.402 +    }
   5.403 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/CallgraphControl.java	Mon Aug 31 15:31:15 2015 -0400
     6.3 @@ -0,0 +1,100 @@
     6.4 +/* 
     6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 + *
     6.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
     6.8 + *
     6.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    6.10 + * Other names may be trademarks of their respective owners.
    6.11 + *
    6.12 + * The contents of this file are subject to the terms of either the GNU
    6.13 + * General Public License Version 2 only ("GPL") or the Common
    6.14 + * Development and Distribution License("CDDL") (collectively, the
    6.15 + * "License"). You may not use this file except in compliance with the
    6.16 + * License. You can obtain a copy of the License at
    6.17 + * http://www.netbeans.org/cddl-gplv2.html
    6.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    6.19 + * specific language governing permissions and limitations under the
    6.20 + * License.  When distributing the software, include this License Header
    6.21 + * Notice in each file and include the License file at
    6.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    6.23 + * particular file as subject to the "Classpath" exception as provided
    6.24 + * by Oracle in the GPL Version 2 section of the License file that
    6.25 + * accompanied this code. If applicable, add the following below the
    6.26 + * License Header, with the fields enclosed by brackets [] replaced by
    6.27 + * your own identifying information:
    6.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    6.29 + *
    6.30 + * Contributor(s):
    6.31 + *
    6.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    6.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    6.34 + * Microsystems, Inc. All Rights Reserved.
    6.35 + *
    6.36 + * If you wish your version of this file to be governed by only the CDDL
    6.37 + * or only the GPL Version 2, indicate your decision by adding
    6.38 + * "[Contributor] elects to include this software in this distribution
    6.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    6.40 + * single choice of license, a recipient has the option to distribute
    6.41 + * your version of this file under either the CDDL, the GPL Version 2 or
    6.42 + * to extend the choice of license to its licensees as provided above.
    6.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    6.44 + * Version 2 license, then the option applies only if the new code is
    6.45 + * made subject to such option by the copyright holder.
    6.46 + */
    6.47 +
    6.48 +package org.netbeans.lib.callgraph;
    6.49 +
    6.50 +import java.io.File;
    6.51 +import java.util.Iterator;
    6.52 +import java.util.Set;
    6.53 +
    6.54 +/**
    6.55 + * Settings for a call graph, implemented by Arguments
    6.56 + *
    6.57 + * @author Tim Boudreau
    6.58 + */
    6.59 +interface CallgraphControl extends Iterable<File> {
    6.60 +
    6.61 +    static final String CMD_NOSELF = "noself";
    6.62 +    static final String CMD_SIMPLE = "simple";
    6.63 +    static final String CMD_MAVEN = "maven";
    6.64 +    static final String CMD_PACKAGEGRAPH = "packagegraph";
    6.65 +    static final String CMD_METHODGRAPH = "methodgraph";
    6.66 +    static final String CMD_CLASSGRAPH = "classgraph";
    6.67 +    static final String CMD_QUIET = "quiet";
    6.68 +    static final String CMD_EXCLUDE = "exclude";
    6.69 +    static final String CMD_VERBOSE = "verbose";
    6.70 +    static final String CMD_OMIT_ABSTRACT = "omit_abstract";
    6.71 +    static final String CMD_DISABLE_EIGHT_BIT_STRINGS = "use_java_strings";
    6.72 +    static final String CMD_REVERSE = "reverse";
    6.73 +
    6.74 +    boolean isDisableEightBitStrings();
    6.75 +
    6.76 +    File classGraphFile();
    6.77 +
    6.78 +    Set<String> excludePrefixes();
    6.79 +
    6.80 +    Set<File> folders();
    6.81 +
    6.82 +    boolean isMaven();
    6.83 +
    6.84 +    boolean isQuiet();
    6.85 +
    6.86 +    boolean isSelfReferences();
    6.87 +
    6.88 +    boolean isShortNames();
    6.89 +
    6.90 +    Iterator<File> iterator();
    6.91 +
    6.92 +    File methodGraphFile();
    6.93 +
    6.94 +    File packageGraphFile();
    6.95 +
    6.96 +    boolean isExcluded(String qname);
    6.97 +
    6.98 +    boolean isVerbose();
    6.99 +
   6.100 +    boolean isOmitAbstract();
   6.101 +
   6.102 +    boolean isReverse();
   6.103 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/Listener.java	Mon Aug 31 15:31:15 2015 -0400
     7.3 @@ -0,0 +1,62 @@
     7.4 +/* 
     7.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     7.6 + *
     7.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
     7.8 + *
     7.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    7.10 + * Other names may be trademarks of their respective owners.
    7.11 + *
    7.12 + * The contents of this file are subject to the terms of either the GNU
    7.13 + * General Public License Version 2 only ("GPL") or the Common
    7.14 + * Development and Distribution License("CDDL") (collectively, the
    7.15 + * "License"). You may not use this file except in compliance with the
    7.16 + * License. You can obtain a copy of the License at
    7.17 + * http://www.netbeans.org/cddl-gplv2.html
    7.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    7.19 + * specific language governing permissions and limitations under the
    7.20 + * License.  When distributing the software, include this License Header
    7.21 + * Notice in each file and include the License file at
    7.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    7.23 + * particular file as subject to the "Classpath" exception as provided
    7.24 + * by Oracle in the GPL Version 2 section of the License file that
    7.25 + * accompanied this code. If applicable, add the following below the
    7.26 + * License Header, with the fields enclosed by brackets [] replaced by
    7.27 + * your own identifying information:
    7.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    7.29 + *
    7.30 + * Contributor(s):
    7.31 + *
    7.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    7.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    7.34 + * Microsystems, Inc. All Rights Reserved.
    7.35 + *
    7.36 + * If you wish your version of this file to be governed by only the CDDL
    7.37 + * or only the GPL Version 2, indicate your decision by adding
    7.38 + * "[Contributor] elects to include this software in this distribution
    7.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    7.40 + * single choice of license, a recipient has the option to distribute
    7.41 + * your version of this file under either the CDDL, the GPL Version 2 or
    7.42 + * to extend the choice of license to its licensees as provided above.
    7.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    7.44 + * Version 2 license, then the option applies only if the new code is
    7.45 + * made subject to such option by the copyright holder.
    7.46 + */
    7.47 +
    7.48 +package org.netbeans.lib.callgraph;
    7.49 +
    7.50 +/**
    7.51 + * For programmatically invoking Callgraph, this provides notifications that
    7.52 + * can be used in a progress UI.  Also used with --verbose.
    7.53 + *
    7.54 + * @author Tim Boudreau
    7.55 + */
    7.56 +public interface Listener {
    7.57 +
    7.58 +    void onStart();
    7.59 +
    7.60 +    void onFinish();
    7.61 +
    7.62 +    void onStartActivity(String activity, int steps);
    7.63 +
    7.64 +    void onStep(String step);
    7.65 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/io/JavaFilesIterator.java	Mon Aug 31 15:31:15 2015 -0400
     8.3 @@ -0,0 +1,175 @@
     8.4 +/* 
     8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 + *
     8.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
     8.8 + *
     8.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    8.10 + * Other names may be trademarks of their respective owners.
    8.11 + *
    8.12 + * The contents of this file are subject to the terms of either the GNU
    8.13 + * General Public License Version 2 only ("GPL") or the Common
    8.14 + * Development and Distribution License("CDDL") (collectively, the
    8.15 + * "License"). You may not use this file except in compliance with the
    8.16 + * License. You can obtain a copy of the License at
    8.17 + * http://www.netbeans.org/cddl-gplv2.html
    8.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    8.19 + * specific language governing permissions and limitations under the
    8.20 + * License.  When distributing the software, include this License Header
    8.21 + * Notice in each file and include the License file at
    8.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    8.23 + * particular file as subject to the "Classpath" exception as provided
    8.24 + * by Oracle in the GPL Version 2 section of the License file that
    8.25 + * accompanied this code. If applicable, add the following below the
    8.26 + * License Header, with the fields enclosed by brackets [] replaced by
    8.27 + * your own identifying information:
    8.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    8.29 + *
    8.30 + * Contributor(s):
    8.31 + *
    8.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    8.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    8.34 + * Microsystems, Inc. All Rights Reserved.
    8.35 + *
    8.36 + * If you wish your version of this file to be governed by only the CDDL
    8.37 + * or only the GPL Version 2, indicate your decision by adding
    8.38 + * "[Contributor] elects to include this software in this distribution
    8.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    8.40 + * single choice of license, a recipient has the option to distribute
    8.41 + * your version of this file under either the CDDL, the GPL Version 2 or
    8.42 + * to extend the choice of license to its licensees as provided above.
    8.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    8.44 + * Version 2 license, then the option applies only if the new code is
    8.45 + * made subject to such option by the copyright holder.
    8.46 + */
    8.47 +
    8.48 +package org.netbeans.lib.callgraph.io;
    8.49 +
    8.50 +import java.io.File;
    8.51 +import java.io.FileFilter;
    8.52 +import java.io.IOException;
    8.53 +import java.util.Arrays;
    8.54 +import java.util.Iterator;
    8.55 +import java.util.LinkedList;
    8.56 +
    8.57 +/**
    8.58 + * Iteratively reads directories and finds files, without pre-walking the
    8.59 + * file tree and building a giant array of Files - finds the next one
    8.60 + * on demand.
    8.61 + *
    8.62 + * @author Tim Boudreau
    8.63 + */
    8.64 +public class JavaFilesIterator implements Iterator<File>, FileFilter {
    8.65 +
    8.66 +    private final LinkedList<Iterator<File>> stack = new LinkedList<>();
    8.67 +    private File next;
    8.68 +
    8.69 +    public JavaFilesIterator(File root) throws IOException {
    8.70 +        Iterator<File> base = list(root);
    8.71 +        stack.push(base);
    8.72 +    }
    8.73 +
    8.74 +    public static Iterable<File> iterable(final File root) {
    8.75 +        return new Iterable<File>() {
    8.76 +
    8.77 +            @Override
    8.78 +            public Iterator<File> iterator() {
    8.79 +                try {
    8.80 +                    return new JavaFilesIterator(root);
    8.81 +                } catch (IOException ex) {
    8.82 +                    throw new IllegalStateException(root + "");
    8.83 +                }
    8.84 +            }
    8.85 +        };
    8.86 +    }
    8.87 +
    8.88 +    private Iterator<File> list(File root) {
    8.89 +        return new NamedIterator<>(root.getName(), Arrays.asList(root.listFiles(this)).iterator());
    8.90 +    }
    8.91 +
    8.92 +    private Iterator<File> current() {
    8.93 +        if (stack.isEmpty()) {
    8.94 +            return null;
    8.95 +        }
    8.96 +        Iterator<File> result = stack.peek();
    8.97 +        if (!result.hasNext()) {
    8.98 +            stack.pop();
    8.99 +            return current();
   8.100 +        }
   8.101 +        return result;
   8.102 +    }
   8.103 +
   8.104 +    private void findNext() {
   8.105 +        if (next != null) {
   8.106 +            return;
   8.107 +        }
   8.108 +        Iterator<File> iter = current();
   8.109 +        if (iter == null) {
   8.110 +            next = null;
   8.111 +            return;
   8.112 +        }
   8.113 +        File f = iter.next();
   8.114 +        if (f.isDirectory()) {
   8.115 +            stack.push(list(f));
   8.116 +            findNext();
   8.117 +        } else {
   8.118 +            next = f;
   8.119 +        }
   8.120 +    }
   8.121 +
   8.122 +    @Override
   8.123 +    public synchronized boolean hasNext() {
   8.124 +        findNext();
   8.125 +        return next != null;
   8.126 +    }
   8.127 +
   8.128 +    @Override
   8.129 +    public synchronized File next() {
   8.130 +        findNext();
   8.131 +        if (next == null) {
   8.132 +            throw new IndexOutOfBoundsException();
   8.133 +        }
   8.134 +        File nx = next;
   8.135 +        next = null;
   8.136 +        return nx;
   8.137 +    }
   8.138 +
   8.139 +    @Override
   8.140 +    public boolean accept(File file) {
   8.141 +        return (file.isDirectory() && !file.getName().startsWith(".")) || (file.isFile() && file.canRead() && file.getName().endsWith(".java"));
   8.142 +    }
   8.143 +
   8.144 +    @Override
   8.145 +    public void remove() {
   8.146 +        throw new UnsupportedOperationException("Not supported.");
   8.147 +    }
   8.148 +
   8.149 +    private static class NamedIterator<File> implements Iterator<File> {
   8.150 +
   8.151 +        private final String name;
   8.152 +        private final Iterator<File> del;
   8.153 +
   8.154 +        public NamedIterator(String name, Iterator<File> del) {
   8.155 +            this.name = name;
   8.156 +            this.del = del;
   8.157 +        }
   8.158 +
   8.159 +        @Override
   8.160 +        public boolean hasNext() {
   8.161 +            return del.hasNext();
   8.162 +        }
   8.163 +
   8.164 +        @Override
   8.165 +        public File next() {
   8.166 +            return del.next();
   8.167 +        }
   8.168 +
   8.169 +        public String toString() {
   8.170 +            return name;
   8.171 +        }
   8.172 +
   8.173 +        @Override
   8.174 +        public void remove() {
   8.175 +            del.remove();
   8.176 +        }
   8.177 +    }
   8.178 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/javac/ElementFinder.java	Mon Aug 31 15:31:15 2015 -0400
     9.3 @@ -0,0 +1,100 @@
     9.4 +/* 
     9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 + *
     9.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
     9.8 + *
     9.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    9.10 + * Other names may be trademarks of their respective owners.
    9.11 + *
    9.12 + * The contents of this file are subject to the terms of either the GNU
    9.13 + * General Public License Version 2 only ("GPL") or the Common
    9.14 + * Development and Distribution License("CDDL") (collectively, the
    9.15 + * "License"). You may not use this file except in compliance with the
    9.16 + * License. You can obtain a copy of the License at
    9.17 + * http://www.netbeans.org/cddl-gplv2.html
    9.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    9.19 + * specific language governing permissions and limitations under the
    9.20 + * License.  When distributing the software, include this License Header
    9.21 + * Notice in each file and include the License file at
    9.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    9.23 + * particular file as subject to the "Classpath" exception as provided
    9.24 + * by Oracle in the GPL Version 2 section of the License file that
    9.25 + * accompanied this code. If applicable, add the following below the
    9.26 + * License Header, with the fields enclosed by brackets [] replaced by
    9.27 + * your own identifying information:
    9.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    9.29 + *
    9.30 + * Contributor(s):
    9.31 + *
    9.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    9.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    9.34 + * Microsystems, Inc. All Rights Reserved.
    9.35 + *
    9.36 + * If you wish your version of this file to be governed by only the CDDL
    9.37 + * or only the GPL Version 2, indicate your decision by adding
    9.38 + * "[Contributor] elects to include this software in this distribution
    9.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    9.40 + * single choice of license, a recipient has the option to distribute
    9.41 + * your version of this file under either the CDDL, the GPL Version 2 or
    9.42 + * to extend the choice of license to its licensees as provided above.
    9.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    9.44 + * Version 2 license, then the option applies only if the new code is
    9.45 + * made subject to such option by the copyright holder.
    9.46 + */
    9.47 +
    9.48 +package org.netbeans.lib.callgraph.javac;
    9.49 +
    9.50 +import com.sun.source.tree.CompilationUnitTree;
    9.51 +import com.sun.source.tree.MethodTree;
    9.52 +import com.sun.source.tree.Tree;
    9.53 +import com.sun.source.util.TreePath;
    9.54 +import com.sun.source.util.TreeScanner;
    9.55 +import com.sun.source.util.Trees;
    9.56 +import java.lang.reflect.Modifier;
    9.57 +import javax.lang.model.element.Element;
    9.58 +import javax.lang.model.element.ElementKind;
    9.59 +import javax.lang.model.type.TypeMirror;
    9.60 +
    9.61 +/**
    9.62 + * Finds all methods.
    9.63 + * 
    9.64 + * @author Tim Boudreau
    9.65 + */
    9.66 +final class ElementFinder extends TreeScanner<Void, SourcesInfo> {
    9.67 +
    9.68 +    private final CompilationUnitTree cc;
    9.69 +    private final Trees trees;
    9.70 +
    9.71 +    public ElementFinder(CompilationUnitTree cc, Trees trees) {
    9.72 +        this.cc = cc;
    9.73 +        this.trees = trees;
    9.74 +    }
    9.75 +
    9.76 +    @Override
    9.77 +    public Void visitMethod(MethodTree tree, SourcesInfo info) {
    9.78 +        String nm = tree.getName().toString();
    9.79 +        addItem(tree, info, SourceElementKind.METHOD, nm);
    9.80 +        return super.visitMethod(tree, info);
    9.81 +    }
    9.82 +
    9.83 +    // uncomment to also deal in fields
    9.84 +    
    9.85 +//    @Override
    9.86 +//    public Void visitVariable(VariableTree tree, Set<SceneElement> set) {
    9.87 +//        String nm = tree.getName().toString();
    9.88 +//        addItem(tree, set, SceneObjectKind.FIELD, nm);
    9.89 +//        return super.visitVariable(tree, set);
    9.90 +//    }
    9.91 +    private void addItem(Tree tree, SourcesInfo info, SourceElementKind kind, String nm) {
    9.92 +        TreePath path = TreePath.getPath(cc, tree);
    9.93 +        Element el = trees.getElement(path);
    9.94 +        if (el != null && (el.getKind() == ElementKind.FIELD || el.getKind() == ElementKind.METHOD)) {
    9.95 +            boolean abstrakt = el.getKind() == ElementKind.METHOD && el.getModifiers().contains(Modifier.ABSTRACT);
    9.96 +            TypeMirror mirror = el.asType();
    9.97 +            String typeStr = mirror != null ? mirror.toString() : "void";
    9.98 +            SourceElement nue = new SourceElement(kind, path, nm, typeStr, info, abstrakt);
    9.99 +            info.allElements.add(nue);
   9.100 +            info.elements.put(el, nue);
   9.101 +        }
   9.102 +    }
   9.103 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/javac/JavacRunner.java	Mon Aug 31 15:31:15 2015 -0400
    10.3 @@ -0,0 +1,230 @@
    10.4 +/* 
    10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 + *
    10.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
    10.8 + *
    10.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   10.10 + * Other names may be trademarks of their respective owners.
   10.11 + *
   10.12 + * The contents of this file are subject to the terms of either the GNU
   10.13 + * General Public License Version 2 only ("GPL") or the Common
   10.14 + * Development and Distribution License("CDDL") (collectively, the
   10.15 + * "License"). You may not use this file except in compliance with the
   10.16 + * License. You can obtain a copy of the License at
   10.17 + * http://www.netbeans.org/cddl-gplv2.html
   10.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   10.19 + * specific language governing permissions and limitations under the
   10.20 + * License.  When distributing the software, include this License Header
   10.21 + * Notice in each file and include the License file at
   10.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   10.23 + * particular file as subject to the "Classpath" exception as provided
   10.24 + * by Oracle in the GPL Version 2 section of the License file that
   10.25 + * accompanied this code. If applicable, add the following below the
   10.26 + * License Header, with the fields enclosed by brackets [] replaced by
   10.27 + * your own identifying information:
   10.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   10.29 + *
   10.30 + * Contributor(s):
   10.31 + *
   10.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   10.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   10.34 + * Microsystems, Inc. All Rights Reserved.
   10.35 + *
   10.36 + * If you wish your version of this file to be governed by only the CDDL
   10.37 + * or only the GPL Version 2, indicate your decision by adding
   10.38 + * "[Contributor] elects to include this software in this distribution
   10.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   10.40 + * single choice of license, a recipient has the option to distribute
   10.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   10.42 + * to extend the choice of license to its licensees as provided above.
   10.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   10.44 + * Version 2 license, then the option applies only if the new code is
   10.45 + * made subject to such option by the copyright holder.
   10.46 + */
   10.47 +
   10.48 +package org.netbeans.lib.callgraph.javac;
   10.49 +
   10.50 +import org.netbeans.lib.callgraph.Listener;
   10.51 +import com.sun.source.tree.CompilationUnitTree;
   10.52 +import com.sun.tools.javac.api.JavacTaskImpl;
   10.53 +import com.sun.tools.javac.api.JavacTrees;
   10.54 +import java.io.File;
   10.55 +import java.io.IOException;
   10.56 +import java.nio.charset.Charset;
   10.57 +import java.util.ArrayList;
   10.58 +import java.util.Collections;
   10.59 +import java.util.Iterator;
   10.60 +import java.util.LinkedList;
   10.61 +import java.util.List;
   10.62 +import java.util.Locale;
   10.63 +import java.util.Set;
   10.64 +import javax.tools.Diagnostic;
   10.65 +import javax.tools.DiagnosticListener;
   10.66 +import javax.tools.JavaCompiler;
   10.67 +import javax.tools.JavaFileObject;
   10.68 +import javax.tools.StandardJavaFileManager;
   10.69 +import javax.tools.StandardLocation;
   10.70 +import javax.tools.ToolProvider;
   10.71 +
   10.72 +/**
   10.73 + * Runs javac with our visitors to construct the usage graph for each method.
   10.74 + *
   10.75 + * @author Tim Boudreau
   10.76 + */
   10.77 +public class JavacRunner {
   10.78 +
   10.79 +    private final DiagnosticListener diagnostics = new Diagnostics();
   10.80 +    private final Iterable<File> files;
   10.81 +    private final Iterable<? extends File> outdir = Collections.singleton(new File(System.getProperty("java.io.tmpdir")));
   10.82 +    private final Listener listener;
   10.83 +    private final SourcesInfo info;
   10.84 +
   10.85 +    public JavacRunner(SourcesInfo info, Iterable<File> files) {
   10.86 +        this(info, files, new NullListener());
   10.87 +    }
   10.88 +
   10.89 +    public JavacRunner(SourcesInfo info, Iterable<File> files, Listener listener) {
   10.90 +        this.files = files;
   10.91 +        this.listener = listener == null ? new NullListener() : listener;
   10.92 +        this.info = info;
   10.93 +    }
   10.94 +
   10.95 +    private Iterable<? extends JavaFileObject> javaFileObjects(StandardJavaFileManager m) {
   10.96 +        return new JavaFileObjectIterable(files, m);
   10.97 +    }
   10.98 +    
   10.99 +    /** Iterable that converts an Iterable<File> to an Iterable<JavaFileObject>
  10.100 +    */
  10.101 +    private static final class JavaFileObjectIterable implements Iterable<JavaFileObject> {
  10.102 +        private final Iterable<File> files;
  10.103 +        private final StandardJavaFileManager mgr;
  10.104 +
  10.105 +        public JavaFileObjectIterable(Iterable<File> files, final StandardJavaFileManager mgr) {
  10.106 +            this.files = files;
  10.107 +            this.mgr = mgr;
  10.108 +        }
  10.109 +
  10.110 +        @Override
  10.111 +        public Iterator<JavaFileObject> iterator() {
  10.112 +            final Iterator<File> fi = files.iterator();
  10.113 +            return new Iterator<JavaFileObject>() {
  10.114 +
  10.115 +                @Override
  10.116 +                public boolean hasNext() {
  10.117 +                    return fi.hasNext();
  10.118 +                }
  10.119 +
  10.120 +                @Override
  10.121 +                public JavaFileObject next() {
  10.122 +                    return mgr.getJavaFileObjects(fi.next()).iterator().next();
  10.123 +                }
  10.124 +
  10.125 +                @Override
  10.126 +                public void remove() {
  10.127 +                    throw new UnsupportedOperationException();
  10.128 +                }
  10.129 +            };
  10.130 +        }
  10.131 +    }
  10.132 +
  10.133 +    private List<String> options() {
  10.134 +        // Borrowed from NetBeans
  10.135 +        List<String> options = new ArrayList<>(9);
  10.136 +        options.add("-XDide");   // Javac runs inside the IDE
  10.137 +        options.add("-XDsave-parameter-names");   // Javac runs inside the IDE
  10.138 +        options.add("-XDsuppressAbortOnBadClassFile");   // When a class file cannot be read, produce an error type instead of failing with an exception
  10.139 +        options.add("-XDshouldStopPolicy=GENERATE");   // Parsing should not stop in phase where an error is found
  10.140 +        options.add("-g:source"); // Make the compiler maintian source file info
  10.141 +        options.add("-g:lines"); // Make the compiler maintain line table
  10.142 +        options.add("-g:vars");  // Make the compiler maintain local variables table
  10.143 +        options.add("-XDbreakDocCommentParsingOnError=false");  // Turn off compile fails for javadoc
  10.144 +        options.add("-proc:none"); // Do not try to run annotation processors
  10.145 +        return options;
  10.146 +    }
  10.147 +
  10.148 +    public Set<SourceElement> go() throws IOException {
  10.149 +        listener.onStart();
  10.150 +        try {
  10.151 +            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
  10.152 +
  10.153 +            StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, Locale.getDefault(),
  10.154 +                    Charset.forName("UTF-8"));
  10.155 +            fileManager.setLocation(StandardLocation.CLASS_OUTPUT, outdir);
  10.156 +            Iterable<? extends JavaFileObject> toCompile = javaFileObjects(fileManager);
  10.157 +
  10.158 +            JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null,
  10.159 +                    fileManager, diagnostics, options(), null, toCompile);
  10.160 +            return parse(task).allElements;
  10.161 +        } finally {
  10.162 +            listener.onFinish();
  10.163 +        }
  10.164 +    }
  10.165 +
  10.166 +    private SourcesInfo parse(JavacTaskImpl task) throws IOException {
  10.167 +        listener.onStartActivity("Finding and parsing Java sources", -1);
  10.168 +        JavacTrees trees = JavacTrees.instance(task.getContext());
  10.169 +        List<CompilationUnitTree> units = new LinkedList<>();
  10.170 +        // We need to cache these because calling parse() twice is an error
  10.171 +        for (CompilationUnitTree tree : task.parse()) {
  10.172 +            units.add(tree);
  10.173 +        }
  10.174 +        listener.onStartActivity("Attributing Java sources", -1);
  10.175 +        task.analyze(); // Run attribution - the compiler flags we have set will have it not abort on unresolvable classes
  10.176 +        try {
  10.177 +            try {
  10.178 +                listener.onStartActivity("Cataloging methods", units.size());
  10.179 +                // First pass, find all methods in all classes
  10.180 +                for (CompilationUnitTree tree : units) {
  10.181 +                    listener.onStep(tree.getSourceFile().getName());
  10.182 +                    ElementFinder elementFinder = new ElementFinder(tree, trees);
  10.183 +                    elementFinder.scan(tree, info);
  10.184 +                }
  10.185 +                listener.onStartActivity("Finding usages", units.size());
  10.186 +                // Second pass, run find usages on every method we found
  10.187 +                for (CompilationUnitTree tree : units) {
  10.188 +                    listener.onStep(tree.getSourceFile().getName());
  10.189 +                    UsageFinder usageFinder = new UsageFinder(tree, trees);
  10.190 +                    usageFinder.scan(tree, info);
  10.191 +                }
  10.192 +            } finally {
  10.193 +                task.finish();
  10.194 +            }
  10.195 +        } finally {
  10.196 +            info.close(); // discard references
  10.197 +        }
  10.198 +        return info;
  10.199 +    }
  10.200 +
  10.201 +    private static final class Diagnostics implements DiagnosticListener {
  10.202 +
  10.203 +        @Override
  10.204 +        public void report(Diagnostic diagnostic) {
  10.205 +            // Discard diagnostics - we're not actually compiling to class files,
  10.206 +            // so we don't care about deprecations (or even failures, since we
  10.207 +            // only need references from the classes to themselves).
  10.208 +        }
  10.209 +    }
  10.210 +
  10.211 +    private static final class NullListener implements Listener {
  10.212 +
  10.213 +        @Override
  10.214 +        public void onStart() {
  10.215 +
  10.216 +        }
  10.217 +
  10.218 +        @Override
  10.219 +        public void onFinish() {
  10.220 +
  10.221 +        }
  10.222 +
  10.223 +        @Override
  10.224 +        public void onStartActivity(String activity, int steps) {
  10.225 +
  10.226 +        }
  10.227 +
  10.228 +        @Override
  10.229 +        public void onStep(String step) {
  10.230 +
  10.231 +        }
  10.232 +    }
  10.233 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/javac/SourceElement.java	Mon Aug 31 15:31:15 2015 -0400
    11.3 @@ -0,0 +1,173 @@
    11.4 +/* 
    11.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    11.6 + *
    11.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
    11.8 + *
    11.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   11.10 + * Other names may be trademarks of their respective owners.
   11.11 + *
   11.12 + * The contents of this file are subject to the terms of either the GNU
   11.13 + * General Public License Version 2 only ("GPL") or the Common
   11.14 + * Development and Distribution License("CDDL") (collectively, the
   11.15 + * "License"). You may not use this file except in compliance with the
   11.16 + * License. You can obtain a copy of the License at
   11.17 + * http://www.netbeans.org/cddl-gplv2.html
   11.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   11.19 + * specific language governing permissions and limitations under the
   11.20 + * License.  When distributing the software, include this License Header
   11.21 + * Notice in each file and include the License file at
   11.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   11.23 + * particular file as subject to the "Classpath" exception as provided
   11.24 + * by Oracle in the GPL Version 2 section of the License file that
   11.25 + * accompanied this code. If applicable, add the following below the
   11.26 + * License Header, with the fields enclosed by brackets [] replaced by
   11.27 + * your own identifying information:
   11.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   11.29 + *
   11.30 + * Contributor(s):
   11.31 + *
   11.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   11.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   11.34 + * Microsystems, Inc. All Rights Reserved.
   11.35 + *
   11.36 + * If you wish your version of this file to be governed by only the CDDL
   11.37 + * or only the GPL Version 2, indicate your decision by adding
   11.38 + * "[Contributor] elects to include this software in this distribution
   11.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   11.40 + * single choice of license, a recipient has the option to distribute
   11.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   11.42 + * to extend the choice of license to its licensees as provided above.
   11.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   11.44 + * Version 2 license, then the option applies only if the new code is
   11.45 + * made subject to such option by the copyright holder.
   11.46 + */
   11.47 +
   11.48 +package org.netbeans.lib.callgraph.javac;
   11.49 +
   11.50 +import org.netbeans.lib.callgraph.util.EightBitStrings;
   11.51 +import com.sun.source.util.TreePath;
   11.52 +import java.util.Collections;
   11.53 +import java.util.HashSet;
   11.54 +import java.util.Set;
   11.55 +
   11.56 +/**
   11.57 + * Represents a method or field and the things that it references and that
   11.58 + * reference it.
   11.59 + *
   11.60 + * @author Tim Boudreau
   11.61 + */
   11.62 +public final class SourceElement implements Comparable<SourceElement> {
   11.63 +
   11.64 +    private final CharSequence name;
   11.65 +    private final Set<SourceElement> inbound = new HashSet<>();
   11.66 +    private final Set<SourceElement> outbound = new HashSet<>();
   11.67 +    private final SourceElementKind kind;
   11.68 +    private final CharSequence type;
   11.69 +    private final CharSequence typeName;
   11.70 +    private final CharSequence parameters;
   11.71 +    private final CharSequence packageName;
   11.72 +    private final CharSequence qname;
   11.73 +    private final CharSequence shortName;
   11.74 +    private final boolean abstrakt;
   11.75 +
   11.76 +    public SourceElement(SourceElementKind kind, TreePath handle, String name, String type, SourcesInfo info, boolean abstrakt) {
   11.77 +        this.name = info.strings.create(name);
   11.78 +        this.kind = kind;
   11.79 +        this.type = info.strings.create(type);
   11.80 +        // Derive the name and do not hang onto any objects from the Javac task,
   11.81 +        // or we will hold the whole compile in memory
   11.82 +        this.typeName = info.strings.create(info.nameOf(handle));
   11.83 +        parameters = info.strings.create(info.parametersOf(handle));
   11.84 +        packageName = info.strings.create(info.packageNameOf(handle));
   11.85 +        qname = info.strings.concat(packageName, info.strings.DOT, typeName(), info.strings.DOT, getName(), parameters());;
   11.86 +        shortName = info.strings.concat(typeName(), info.strings.DOT, getName(), parameters());
   11.87 +        this.abstrakt = abstrakt;
   11.88 +    }
   11.89 +
   11.90 +    public CharSequence getType() {
   11.91 +        return type;
   11.92 +    }
   11.93 +
   11.94 +    public CharSequence getName() {
   11.95 +        return name;
   11.96 +    }
   11.97 +
   11.98 +    public synchronized Set<SourceElement> getOutboundReferences() {
   11.99 +        return Collections.unmodifiableSet(outbound);
  11.100 +    }
  11.101 +
  11.102 +    public synchronized Set<SourceElement> getInboundReferences() {
  11.103 +        return Collections.unmodifiableSet(inbound);
  11.104 +    }
  11.105 +
  11.106 +    synchronized void addOutboundReference(SourceElement item) {
  11.107 +        if (item != this) {
  11.108 +            outbound.add(item);
  11.109 +        }
  11.110 +    }
  11.111 +
  11.112 +    synchronized void addInboundReference(SourceElement item) {
  11.113 +        if (item != this) {
  11.114 +            inbound.add(item);
  11.115 +        }
  11.116 +    }
  11.117 +
  11.118 +    public SourceElementKind kind() {
  11.119 +        return kind;
  11.120 +    }
  11.121 +
  11.122 +    public CharSequence typeName() {
  11.123 +        return typeName;
  11.124 +    }
  11.125 +
  11.126 +    public CharSequence packageName() {
  11.127 +        return packageName;
  11.128 +    }
  11.129 +
  11.130 +    public CharSequence parameters() {
  11.131 +        return parameters;
  11.132 +    }
  11.133 +    
  11.134 +    public boolean isAbstract() {
  11.135 +        return abstrakt;
  11.136 +    }
  11.137 +
  11.138 +    @Override
  11.139 +    public String toString() {
  11.140 +        return qname().toString();
  11.141 +    }
  11.142 +
  11.143 +    public CharSequence qname() {
  11.144 +        return qname;
  11.145 +    }
  11.146 +
  11.147 +    public CharSequence shortName() {
  11.148 +        return shortName;
  11.149 +    }
  11.150 +
  11.151 +    @Override
  11.152 +    public boolean equals(Object obj) {
  11.153 +        if (obj == null) {
  11.154 +            return false;
  11.155 +        }
  11.156 +        if (getClass() != obj.getClass()) {
  11.157 +            return false;
  11.158 +        }
  11.159 +        if (obj == this) {
  11.160 +            return true;
  11.161 +        }
  11.162 +        SourceElement other = (SourceElement) obj;
  11.163 +        return qname().equals(other.qname());
  11.164 +    }
  11.165 +
  11.166 +    int hash = 0;
  11.167 +    @Override
  11.168 +    public int hashCode() {
  11.169 +        return hash == 0 ? hash = 37 * qname().hashCode() : hash;
  11.170 +    }
  11.171 +
  11.172 +    @Override
  11.173 +    public int compareTo(SourceElement o) {
  11.174 +        return toString().compareTo(o.toString());
  11.175 +    }
  11.176 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/javac/SourceElementKind.java	Mon Aug 31 15:31:15 2015 -0400
    12.3 @@ -0,0 +1,54 @@
    12.4 +/* 
    12.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    12.6 + *
    12.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
    12.8 + *
    12.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   12.10 + * Other names may be trademarks of their respective owners.
   12.11 + *
   12.12 + * The contents of this file are subject to the terms of either the GNU
   12.13 + * General Public License Version 2 only ("GPL") or the Common
   12.14 + * Development and Distribution License("CDDL") (collectively, the
   12.15 + * "License"). You may not use this file except in compliance with the
   12.16 + * License. You can obtain a copy of the License at
   12.17 + * http://www.netbeans.org/cddl-gplv2.html
   12.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   12.19 + * specific language governing permissions and limitations under the
   12.20 + * License.  When distributing the software, include this License Header
   12.21 + * Notice in each file and include the License file at
   12.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   12.23 + * particular file as subject to the "Classpath" exception as provided
   12.24 + * by Oracle in the GPL Version 2 section of the License file that
   12.25 + * accompanied this code. If applicable, add the following below the
   12.26 + * License Header, with the fields enclosed by brackets [] replaced by
   12.27 + * your own identifying information:
   12.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   12.29 + *
   12.30 + * Contributor(s):
   12.31 + *
   12.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   12.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   12.34 + * Microsystems, Inc. All Rights Reserved.
   12.35 + *
   12.36 + * If you wish your version of this file to be governed by only the CDDL
   12.37 + * or only the GPL Version 2, indicate your decision by adding
   12.38 + * "[Contributor] elects to include this software in this distribution
   12.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   12.40 + * single choice of license, a recipient has the option to distribute
   12.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   12.42 + * to extend the choice of license to its licensees as provided above.
   12.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   12.44 + * Version 2 license, then the option applies only if the new code is
   12.45 + * made subject to such option by the copyright holder.
   12.46 + */
   12.47 +
   12.48 +package org.netbeans.lib.callgraph.javac;
   12.49 +
   12.50 +/**
   12.51 + * Defines the type of object a SourceElement describes.
   12.52 + *
   12.53 + * @author Tim Boudreau
   12.54 + */
   12.55 +public enum SourceElementKind {
   12.56 +    METHOD, FIELD;
   12.57 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/javac/SourcesInfo.java	Mon Aug 31 15:31:15 2015 -0400
    13.3 @@ -0,0 +1,146 @@
    13.4 +/* 
    13.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    13.6 + *
    13.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
    13.8 + *
    13.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   13.10 + * Other names may be trademarks of their respective owners.
   13.11 + *
   13.12 + * The contents of this file are subject to the terms of either the GNU
   13.13 + * General Public License Version 2 only ("GPL") or the Common
   13.14 + * Development and Distribution License("CDDL") (collectively, the
   13.15 + * "License"). You may not use this file except in compliance with the
   13.16 + * License. You can obtain a copy of the License at
   13.17 + * http://www.netbeans.org/cddl-gplv2.html
   13.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   13.19 + * specific language governing permissions and limitations under the
   13.20 + * License.  When distributing the software, include this License Header
   13.21 + * Notice in each file and include the License file at
   13.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   13.23 + * particular file as subject to the "Classpath" exception as provided
   13.24 + * by Oracle in the GPL Version 2 section of the License file that
   13.25 + * accompanied this code. If applicable, add the following below the
   13.26 + * License Header, with the fields enclosed by brackets [] replaced by
   13.27 + * your own identifying information:
   13.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   13.29 + *
   13.30 + * Contributor(s):
   13.31 + *
   13.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   13.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   13.34 + * Microsystems, Inc. All Rights Reserved.
   13.35 + *
   13.36 + * If you wish your version of this file to be governed by only the CDDL
   13.37 + * or only the GPL Version 2, indicate your decision by adding
   13.38 + * "[Contributor] elects to include this software in this distribution
   13.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   13.40 + * single choice of license, a recipient has the option to distribute
   13.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   13.42 + * to extend the choice of license to its licensees as provided above.
   13.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   13.44 + * Version 2 license, then the option applies only if the new code is
   13.45 + * made subject to such option by the copyright holder.
   13.46 + */
   13.47 +
   13.48 +package org.netbeans.lib.callgraph.javac;
   13.49 +
   13.50 +import static org.netbeans.lib.callgraph.javac.UsageFinder.CLASS_TREE_KINDS;
   13.51 +import org.netbeans.lib.callgraph.util.EightBitStrings;
   13.52 +import com.sun.source.tree.ClassTree;
   13.53 +import com.sun.source.tree.ExpressionTree;
   13.54 +import com.sun.source.tree.MethodTree;
   13.55 +import com.sun.source.tree.VariableTree;
   13.56 +import com.sun.source.util.TreePath;
   13.57 +import java.util.ArrayList;
   13.58 +import java.util.HashMap;
   13.59 +import java.util.HashSet;
   13.60 +import java.util.Iterator;
   13.61 +import java.util.List;
   13.62 +import java.util.Map;
   13.63 +import java.util.Set;
   13.64 +import javax.lang.model.element.Element;
   13.65 +
   13.66 +/**
   13.67 + * Container for shared state that is gathered during the parse and discarded
   13.68 + * after.
   13.69 + *
   13.70 + * @author Tim Boudreau
   13.71 + */
   13.72 +public final class SourcesInfo implements AutoCloseable {
   13.73 +
   13.74 +    public final Set<SourceElement> allElements = new HashSet<>();
   13.75 +    public final Map<Element, SourceElement> elements = new HashMap<>();
   13.76 +
   13.77 +    private final Map<ClassTree, List<ClassTree>> inners = new HashMap<>();
   13.78 +
   13.79 +    public final EightBitStrings strings;
   13.80 +
   13.81 +    public SourcesInfo(boolean eightBitStringsDisabled) {
   13.82 +        this.strings = new EightBitStrings(eightBitStringsDisabled);
   13.83 +    }
   13.84 +
   13.85 +    // XXX rewrite to not hold references to ClassTree, just names,
   13.86 +    // to reduce memory consumption - and verify that that actually
   13.87 +    // makes a difference (not sure how much of javac's compile tree
   13.88 +    // can be gc'd while the compile is ongoing).  Use something similar
   13.89 +    // to NetBeans' ElementHandle.  That might also make it possible to
   13.90 +    // restart the compile if memory consumption gets too large, if we
   13.91 +    // retain enough bookkeeping here.
   13.92 +    TreePath containingClassOf(TreePath path) {
   13.93 +        do {
   13.94 +            path = path.getParentPath();
   13.95 +        } while (path != null && !CLASS_TREE_KINDS.contains(path.getLeaf().getKind()));
   13.96 +        return path;
   13.97 +    }
   13.98 +
   13.99 +    String parametersOf(TreePath path) {
  13.100 +        if (path.getLeaf() instanceof MethodTree) {
  13.101 +            MethodTree method = (MethodTree) path.getLeaf();
  13.102 +            StringBuilder paramsString = new StringBuilder("(");
  13.103 +            for (Iterator<? extends VariableTree> it = method.getParameters().iterator(); it.hasNext();) {
  13.104 +                VariableTree variable = it.next();
  13.105 +                paramsString.append(variable.getType().toString());
  13.106 +                if (it.hasNext()) {
  13.107 +                    paramsString.append(',');
  13.108 +                }
  13.109 +            }
  13.110 +            return paramsString.append(")").toString();
  13.111 +        } else {
  13.112 +            return "";
  13.113 +        }
  13.114 +    }
  13.115 +
  13.116 +    String packageNameOf(TreePath path) {
  13.117 +        ExpressionTree pkgName = path.getCompilationUnit().getPackageName();
  13.118 +        return pkgName == null ? "<defaultPackage>" : pkgName.toString();
  13.119 +    }
  13.120 +
  13.121 +    String nameOf(TreePath tree) {
  13.122 +        TreePath containingClass = containingClassOf(tree);
  13.123 +        ClassTree clazz = (ClassTree) containingClass.getLeaf();
  13.124 +        String name = clazz.getSimpleName().toString();
  13.125 +        if (name.isEmpty()) {
  13.126 +            // Recursively generate $1, $2 names, handling the case of
  13.127 +            // mutiple nesting
  13.128 +            name = nameOf(containingClass);
  13.129 +            TreePath nestedIn = containingClassOf(containingClass);
  13.130 +            ClassTree nestingParent = (ClassTree) nestedIn.getLeaf();
  13.131 +            List<ClassTree> innerClasses = inners.get(nestingParent);
  13.132 +            if (innerClasses == null) {
  13.133 +                innerClasses = new ArrayList<>(3);
  13.134 +                inners.put(nestingParent, innerClasses);
  13.135 +            }
  13.136 +            innerClasses.add(clazz);
  13.137 +            name = name + ".$" + innerClasses.size();
  13.138 +        }
  13.139 +        return name;
  13.140 +    }
  13.141 +
  13.142 +    @Override
  13.143 +    public void close() {
  13.144 +        // Clear references to objects from the parse
  13.145 +        inners.clear();
  13.146 +        elements.clear();
  13.147 +        strings.clear();
  13.148 +    }
  13.149 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/javac/UsageFinder.java	Mon Aug 31 15:31:15 2015 -0400
    14.3 @@ -0,0 +1,118 @@
    14.4 +/* 
    14.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    14.6 + *
    14.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
    14.8 + *
    14.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   14.10 + * Other names may be trademarks of their respective owners.
   14.11 + *
   14.12 + * The contents of this file are subject to the terms of either the GNU
   14.13 + * General Public License Version 2 only ("GPL") or the Common
   14.14 + * Development and Distribution License("CDDL") (collectively, the
   14.15 + * "License"). You may not use this file except in compliance with the
   14.16 + * License. You can obtain a copy of the License at
   14.17 + * http://www.netbeans.org/cddl-gplv2.html
   14.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   14.19 + * specific language governing permissions and limitations under the
   14.20 + * License.  When distributing the software, include this License Header
   14.21 + * Notice in each file and include the License file at
   14.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   14.23 + * particular file as subject to the "Classpath" exception as provided
   14.24 + * by Oracle in the GPL Version 2 section of the License file that
   14.25 + * accompanied this code. If applicable, add the following below the
   14.26 + * License Header, with the fields enclosed by brackets [] replaced by
   14.27 + * your own identifying information:
   14.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   14.29 + *
   14.30 + * Contributor(s):
   14.31 + *
   14.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   14.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   14.34 + * Microsystems, Inc. All Rights Reserved.
   14.35 + *
   14.36 + * If you wish your version of this file to be governed by only the CDDL
   14.37 + * or only the GPL Version 2, indicate your decision by adding
   14.38 + * "[Contributor] elects to include this software in this distribution
   14.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   14.40 + * single choice of license, a recipient has the option to distribute
   14.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   14.42 + * to extend the choice of license to its licensees as provided above.
   14.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   14.44 + * Version 2 license, then the option applies only if the new code is
   14.45 + * made subject to such option by the copyright holder.
   14.46 + */
   14.47 +
   14.48 +package org.netbeans.lib.callgraph.javac;
   14.49 +
   14.50 +import com.sun.source.tree.CompilationUnitTree;
   14.51 +import com.sun.source.tree.IdentifierTree;
   14.52 +import com.sun.source.tree.MemberSelectTree;
   14.53 +import com.sun.source.tree.Tree;
   14.54 +import com.sun.source.tree.VariableTree;
   14.55 +import com.sun.source.util.TreePath;
   14.56 +import com.sun.source.util.TreeScanner;
   14.57 +import com.sun.source.util.Trees;
   14.58 +import java.util.EnumSet;
   14.59 +import java.util.Set;
   14.60 +import javax.lang.model.element.Element;
   14.61 +import javax.lang.model.element.ElementKind;
   14.62 +
   14.63 +/**
   14.64 + * Finds usages.
   14.65 + *
   14.66 + * @author Tim Boudreau
   14.67 + */
   14.68 +final class UsageFinder extends TreeScanner<Void, SourcesInfo> {
   14.69 +
   14.70 +    private final CompilationUnitTree cc;
   14.71 +    private final Trees trees;
   14.72 +    public static final Set<Tree.Kind> CLASS_TREE_KINDS = EnumSet.of(
   14.73 +            Tree.Kind.ANNOTATION_TYPE,
   14.74 +            Tree.Kind.CLASS,
   14.75 +            Tree.Kind.ENUM,
   14.76 +            Tree.Kind.INTERFACE);
   14.77 +
   14.78 +    public UsageFinder(CompilationUnitTree cc, Trees trees) {
   14.79 +        this.cc = cc;
   14.80 +        this.trees = trees;
   14.81 +    }
   14.82 +
   14.83 +    @Override
   14.84 +    public Void visitIdentifier(IdentifierTree tree, SourcesInfo data) {
   14.85 +        addElement(tree, data);
   14.86 +        return super.visitIdentifier(tree, data);
   14.87 +    }
   14.88 +
   14.89 +    @Override
   14.90 +    public Void visitVariable(VariableTree tree, SourcesInfo data) {
   14.91 +        addElement(tree, data);
   14.92 +        return super.visitVariable(tree, data);
   14.93 +    }
   14.94 +
   14.95 +    @Override
   14.96 +    public Void visitMemberSelect(MemberSelectTree tree, SourcesInfo data) {
   14.97 +        addElement(tree, data);
   14.98 +        return super.visitMemberSelect(tree, data);
   14.99 +    }
  14.100 +
  14.101 +    private void addElement(Tree tree, SourcesInfo map) {
  14.102 +        TreePath path = TreePath.getPath(cc, tree);
  14.103 +        Element el = trees.getElement(path);
  14.104 +        if (el == null || el.getKind() == ElementKind.PARAMETER) {
  14.105 +            return;
  14.106 +        }
  14.107 +        Element selectedElement = el;
  14.108 +        do {
  14.109 +            path = path.getParentPath();
  14.110 +        } while (path != null && path.getLeaf().getKind() != com.sun.source.tree.Tree.Kind.METHOD && !CLASS_TREE_KINDS.contains(path.getLeaf().getKind()));
  14.111 +        if (path != null && path.getLeaf().getKind() == com.sun.source.tree.Tree.Kind.METHOD) {
  14.112 +            Element enclosingElement = trees.getElement(path);
  14.113 +            SourceElement enclosing = map.elements.get(enclosingElement);
  14.114 +            SourceElement selected = map.elements.get(selectedElement);
  14.115 +            if (enclosing != null && selected != null) {
  14.116 +                enclosing.addOutboundReference(selected);
  14.117 +                selected.addInboundReference(enclosing);
  14.118 +            }
  14.119 +        }
  14.120 +    }
  14.121 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/util/EightBitStrings.java	Mon Aug 31 15:31:15 2015 -0400
    15.3 @@ -0,0 +1,352 @@
    15.4 +/* 
    15.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    15.6 + *
    15.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
    15.8 + *
    15.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   15.10 + * Other names may be trademarks of their respective owners.
   15.11 + *
   15.12 + * The contents of this file are subject to the terms of either the GNU
   15.13 + * General Public License Version 2 only ("GPL") or the Common
   15.14 + * Development and Distribution License("CDDL") (collectively, the
   15.15 + * "License"). You may not use this file except in compliance with the
   15.16 + * License. You can obtain a copy of the License at
   15.17 + * http://www.netbeans.org/cddl-gplv2.html
   15.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   15.19 + * specific language governing permissions and limitations under the
   15.20 + * License.  When distributing the software, include this License Header
   15.21 + * Notice in each file and include the License file at
   15.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   15.23 + * particular file as subject to the "Classpath" exception as provided
   15.24 + * by Oracle in the GPL Version 2 section of the License file that
   15.25 + * accompanied this code. If applicable, add the following below the
   15.26 + * License Header, with the fields enclosed by brackets [] replaced by
   15.27 + * your own identifying information:
   15.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   15.29 + *
   15.30 + * Contributor(s):
   15.31 + *
   15.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   15.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   15.34 + * Microsystems, Inc. All Rights Reserved.
   15.35 + *
   15.36 + * If you wish your version of this file to be governed by only the CDDL
   15.37 + * or only the GPL Version 2, indicate your decision by adding
   15.38 + * "[Contributor] elects to include this software in this distribution
   15.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   15.40 + * single choice of license, a recipient has the option to distribute
   15.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   15.42 + * to extend the choice of license to its licensees as provided above.
   15.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   15.44 + * Version 2 license, then the option applies only if the new code is
   15.45 + * made subject to such option by the copyright holder.
   15.46 + */
   15.47 +
   15.48 +package org.netbeans.lib.callgraph.util;
   15.49 +
   15.50 +import java.io.ByteArrayOutputStream;
   15.51 +import java.io.IOException;
   15.52 +import java.nio.ByteBuffer;
   15.53 +import java.nio.charset.CharacterCodingException;
   15.54 +import java.nio.charset.Charset;
   15.55 +import java.util.Arrays;
   15.56 +
   15.57 +/**
   15.58 + * byte[] backed string to cut memory consumption from Strings in half for most
   15.59 + * codebases, to reduce memory footprint to process larger codebases by using 8
   15.60 + * bits per character instead of 16.
   15.61 + *
   15.62 + * @author Tim Boudreau
   15.63 + */
   15.64 +public class EightBitStrings {
   15.65 +
   15.66 +    private static final Charset UTF = Charset.forName("UTF-8");
   15.67 +
   15.68 +    private final InternTable INTERN_TABLE = new InternTable();
   15.69 +    public final CharSequence DOT = create(".");
   15.70 +    public final CharSequence QUOTE = create("\"");
   15.71 +    public final CharSequence CLOSE_OPEN_QUOTE = create("\" \"");
   15.72 +
   15.73 +    private boolean disabled;
   15.74 +
   15.75 +    public EightBitStrings(boolean disabled) {
   15.76 +        this.disabled = disabled;
   15.77 +    }
   15.78 +
   15.79 +    public void clear() {
   15.80 +        INTERN_TABLE.dispose();
   15.81 +    }
   15.82 +
   15.83 +    public CharSequence create(CharSequence string) {
   15.84 +        if (disabled) {
   15.85 +            return string;
   15.86 +        }
   15.87 +        return INTERN_TABLE.intern(string);
   15.88 +    }
   15.89 +
   15.90 +    public CharSequence concat(CharSequence... seqs) {
   15.91 +        if (disabled) {
   15.92 +            StringBuilder sb = new StringBuilder();
   15.93 +            for (CharSequence c : seqs) {
   15.94 +                sb.append(c);
   15.95 +            }
   15.96 +            return sb.toString();
   15.97 +        }
   15.98 +        return new Concatenation(seqs);
   15.99 +    }
  15.100 +
  15.101 +    private static byte[] toBytes(CharSequence seq) {
  15.102 +        try {
  15.103 +            ByteArrayOutputStream out = new ByteArrayOutputStream();
  15.104 +            out.write(seq.toString().getBytes(UTF));
  15.105 +            return out.toByteArray();
  15.106 +        } catch (IOException ex) {
  15.107 +            throw new IllegalArgumentException(ex);
  15.108 +        }
  15.109 +    }
  15.110 +
  15.111 +    private static CharSequence toCharSequence(byte[] bytes) {
  15.112 +        try {
  15.113 +            return UTF.newDecoder().decode(ByteBuffer.wrap(bytes));
  15.114 +        } catch (CharacterCodingException ex) {
  15.115 +            throw new IllegalArgumentException(ex);
  15.116 +        }
  15.117 +    }
  15.118 +
  15.119 +    int internTableSize() {
  15.120 +        return INTERN_TABLE.last + 1;
  15.121 +    }
  15.122 +
  15.123 +    static class InternTable {
  15.124 +
  15.125 +        private static final int SIZE_INCREMENT = 50;
  15.126 +
  15.127 +        private int last = -1;
  15.128 +        private Entry[] entries = new Entry[SIZE_INCREMENT];
  15.129 +
  15.130 +        void dispose() {
  15.131 +            entries = new Entry[SIZE_INCREMENT];
  15.132 +            last = -1;
  15.133 +        }
  15.134 +
  15.135 +        Entry intern(CharSequence seq) {
  15.136 +            if (seq instanceof Entry) {
  15.137 +                return (Entry) seq;
  15.138 +            }
  15.139 +            // We are using an array and binary search to conserve memory
  15.140 +            // here.  This is slower than a HashMap (we sort on insert so
  15.141 +            // we can binary search later), but involves far fewer allocations
  15.142 +            Entry entry = new Entry(toBytes(seq), (short) seq.length());
  15.143 +            int offset = last == -1 ? -1 : Arrays.binarySearch(entries, 0, last + 1, entry);
  15.144 +            if (offset > 0) {
  15.145 +                return entries[offset];
  15.146 +            }
  15.147 +            if (last == entries.length - 1) {
  15.148 +                Entry[] nue = new Entry[entries.length + SIZE_INCREMENT];
  15.149 +                System.arraycopy(entries, 0, nue, 0, entries.length);
  15.150 +                entries = nue;
  15.151 +            }
  15.152 +            entries[++last] = entry;
  15.153 +            Arrays.sort(entries, 0, last + 1);
  15.154 +            return entry;
  15.155 +        }
  15.156 +
  15.157 +        private static final class Entry implements Comparable<CharSequence>, CharSequence {
  15.158 +
  15.159 +            private final byte[] bytes;
  15.160 +            private final short length;
  15.161 +
  15.162 +            public Entry(byte[] bytes, short length) {
  15.163 +                if (length < 0) {
  15.164 +                    throw new Error("String too large");
  15.165 +                }
  15.166 +                this.bytes = bytes;
  15.167 +                this.length = length;
  15.168 +            }
  15.169 +
  15.170 +            public int hashCode() {
  15.171 +                int h = 0;
  15.172 +                if (h == 0 && bytes.length > 0) {
  15.173 +                    CharSequence val = toChars();
  15.174 +                    int max = val.length();
  15.175 +                    for (int i = 0; i < max; i++) {
  15.176 +                        h = 31 * h + val.charAt(i);
  15.177 +                    }
  15.178 +                }
  15.179 +                return h;
  15.180 +            }
  15.181 +
  15.182 +            @Override
  15.183 +            public boolean equals(Object o) {
  15.184 +                if (o == null) {
  15.185 +                    return false;
  15.186 +                } else if (o == this) {
  15.187 +                    return true;
  15.188 +                } else if (o instanceof Entry) {
  15.189 +                    Entry other = (Entry) o;
  15.190 +                    if (other.bytes.length < bytes.length) {
  15.191 +                        return false;
  15.192 +                    }
  15.193 +                    return Arrays.equals(bytes, other.bytes);
  15.194 +                } else if (o instanceof CharSequence) {
  15.195 +                    return charSequencesEqual(this, (CharSequence) o);
  15.196 +                } else {
  15.197 +                    return false;
  15.198 +                }
  15.199 +            }
  15.200 +
  15.201 +            public int compare(Entry o) {
  15.202 +                if (o == this) {
  15.203 +                    return 0;
  15.204 +                }
  15.205 +                int max = Math.min(bytes.length, o.bytes.length);
  15.206 +                for (int i = 0; i < max; i++) {
  15.207 +                    if (bytes[i] > o.bytes[i]) {
  15.208 +                        return 1;
  15.209 +                    } else if (bytes[i] < o.bytes[i]) {
  15.210 +                        return -1;
  15.211 +                    }
  15.212 +                }
  15.213 +                if (bytes.length == o.bytes.length) {
  15.214 +                    return 0;
  15.215 +                } else if (bytes.length > o.bytes.length) {
  15.216 +                    return 1;
  15.217 +                } else {
  15.218 +                    return -1;
  15.219 +                }
  15.220 +            }
  15.221 +
  15.222 +            public String toString() {
  15.223 +                return new String(bytes, UTF);
  15.224 +            }
  15.225 +
  15.226 +            @Override
  15.227 +            public int length() {
  15.228 +                return length;
  15.229 +            }
  15.230 +
  15.231 +            CharSequence toChars() {
  15.232 +                return toCharSequence(bytes);
  15.233 +            }
  15.234 +
  15.235 +            @Override
  15.236 +            public char charAt(int index) {
  15.237 +                return toCharSequence(bytes).charAt(index);
  15.238 +            }
  15.239 +
  15.240 +            @Override
  15.241 +            public CharSequence subSequence(int start, int end) {
  15.242 +                return toCharSequence(bytes).subSequence(start, end);
  15.243 +            }
  15.244 +
  15.245 +            @Override
  15.246 +            public int compareTo(CharSequence o) {
  15.247 +                if (o instanceof Entry) {
  15.248 +                    return compare((Entry) o);
  15.249 +                }
  15.250 +                return toString().compareTo(o.toString());
  15.251 +            }
  15.252 +        }
  15.253 +    }
  15.254 +
  15.255 +    class Concatenation implements CharSequence {
  15.256 +
  15.257 +        private final InternTable.Entry[] entries;
  15.258 +
  15.259 +        Concatenation(CharSequence... entries) {
  15.260 +            this.entries = new InternTable.Entry[entries.length];
  15.261 +            for (int i = 0; i < entries.length; i++) {
  15.262 +                this.entries[i] = INTERN_TABLE.intern(entries[i]);
  15.263 +            }
  15.264 +        }
  15.265 +
  15.266 +        @Override
  15.267 +        public int length() {
  15.268 +            int result = 0;
  15.269 +            for (int i = 0; i < entries.length; i++) {
  15.270 +                result += entries[i].length;
  15.271 +            }
  15.272 +            return result;
  15.273 +        }
  15.274 +
  15.275 +        @Override
  15.276 +        public char charAt(int index) {
  15.277 +            int offset = 0;
  15.278 +            for (int i = 0; i < entries.length; i++) {
  15.279 +                if (index < offset + entries[i].length) {
  15.280 +                    offset += entries[i].length;
  15.281 +                    continue;
  15.282 +                }
  15.283 +                return entries[i].charAt(index - offset);
  15.284 +            }
  15.285 +            throw new IndexOutOfBoundsException(index + " of " + length() + " in " + this);
  15.286 +        }
  15.287 +
  15.288 +        @Override
  15.289 +        public CharSequence subSequence(int start, int end) {
  15.290 +            return INTERN_TABLE.intern(toString().subSequence(start, end));
  15.291 +        }
  15.292 +
  15.293 +        public String toString() {
  15.294 +            StringBuilder sb = new StringBuilder();
  15.295 +            for (InternTable.Entry e : entries) {
  15.296 +                sb.append(e);
  15.297 +            }
  15.298 +            return sb.toString();
  15.299 +        }
  15.300 +
  15.301 +        private int hash = 0;
  15.302 +
  15.303 +        public int hashCode() {
  15.304 +            int h = hash;
  15.305 +            if (h == 0 && length() > 0) {
  15.306 +                for (InternTable.Entry e : entries) {
  15.307 +                    CharSequence chars = e.toChars();
  15.308 +                    int max = chars.length();
  15.309 +                    for (int i = 0; i < max; i++) {
  15.310 +                        h = 31 * h + chars.charAt(i);
  15.311 +                    }
  15.312 +                }
  15.313 +                hash = h;
  15.314 +            }
  15.315 +            return h;
  15.316 +        }
  15.317 +
  15.318 +        public boolean equals(Object o) {
  15.319 +            if (o == this) {
  15.320 +                return true;
  15.321 +            } else if (o == null) {
  15.322 +                return false;
  15.323 +            } else if (o instanceof Concatenation) {
  15.324 +                Concatenation c = (Concatenation) o;
  15.325 +                if (c.entries.length != entries.length) {
  15.326 +                    return false;
  15.327 +                }
  15.328 +                for (int i = 0; i < entries.length; i++) {
  15.329 +                    if (!entries[i].equals(c.entries[i])) {
  15.330 +                        return false;
  15.331 +                    }
  15.332 +                }
  15.333 +                return true;
  15.334 +            } else if (o instanceof CharSequence) {
  15.335 +                return charSequencesEqual(this, (CharSequence) o);
  15.336 +            } else {
  15.337 +                return false;
  15.338 +            }
  15.339 +        }
  15.340 +    }
  15.341 +
  15.342 +    private static boolean charSequencesEqual(CharSequence a, CharSequence b) {
  15.343 +        int maxA = a.length();
  15.344 +        int maxB = b.length();
  15.345 +        if (maxA != maxB) {
  15.346 +            return false;
  15.347 +        }
  15.348 +        for (int i = 0; i < maxA; i++) {
  15.349 +            if (a.charAt(i) != b.charAt(i)) {
  15.350 +                return false;
  15.351 +            }
  15.352 +        }
  15.353 +        return true;
  15.354 +    }
  15.355 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/callgraph/src/main/java/org/netbeans/lib/callgraph/util/MergeIterator.java	Mon Aug 31 15:31:15 2015 -0400
    16.3 @@ -0,0 +1,112 @@
    16.4 +/* 
    16.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    16.6 + *
    16.7 + * Copyright (C) 1997-2015 Oracle and/or its affiliates. All rights reserved.
    16.8 + *
    16.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   16.10 + * Other names may be trademarks of their respective owners.
   16.11 + *
   16.12 + * The contents of this file are subject to the terms of either the GNU
   16.13 + * General Public License Version 2 only ("GPL") or the Common
   16.14 + * Development and Distribution License("CDDL") (collectively, the
   16.15 + * "License"). You may not use this file except in compliance with the
   16.16 + * License. You can obtain a copy of the License at
   16.17 + * http://www.netbeans.org/cddl-gplv2.html
   16.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   16.19 + * specific language governing permissions and limitations under the
   16.20 + * License.  When distributing the software, include this License Header
   16.21 + * Notice in each file and include the License file at
   16.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   16.23 + * particular file as subject to the "Classpath" exception as provided
   16.24 + * by Oracle in the GPL Version 2 section of the License file that
   16.25 + * accompanied this code. If applicable, add the following below the
   16.26 + * License Header, with the fields enclosed by brackets [] replaced by
   16.27 + * your own identifying information:
   16.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   16.29 + *
   16.30 + * Contributor(s):
   16.31 + *
   16.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   16.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
   16.34 + * Microsystems, Inc. All Rights Reserved.
   16.35 + *
   16.36 + * If you wish your version of this file to be governed by only the CDDL
   16.37 + * or only the GPL Version 2, indicate your decision by adding
   16.38 + * "[Contributor] elects to include this software in this distribution
   16.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   16.40 + * single choice of license, a recipient has the option to distribute
   16.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   16.42 + * to extend the choice of license to its licensees as provided above.
   16.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   16.44 + * Version 2 license, then the option applies only if the new code is
   16.45 + * made subject to such option by the copyright holder.
   16.46 + */
   16.47 +
   16.48 +package org.netbeans.lib.callgraph.util;
   16.49 +
   16.50 +import java.util.Collection;
   16.51 +import java.util.Iterator;
   16.52 +import java.util.LinkedList;
   16.53 +import java.util.NoSuchElementException;
   16.54 +
   16.55 +/**
   16.56 + * Merges multiple iterators into one.
   16.57 + *
   16.58 + * @author Tim Boudreau
   16.59 + * @param <T> The type
   16.60 + */
   16.61 +public final class MergeIterator<T> implements Iterator<T> {
   16.62 +
   16.63 +    private final LinkedList<Iterator<T>> iterators = new LinkedList<>();
   16.64 +
   16.65 +    MergeIterator(Collection<Iterable<T>> iterables) {
   16.66 +        for (Iterable<T> coll : iterables) {
   16.67 +            this.iterators.add(coll.iterator());
   16.68 +        }
   16.69 +    }
   16.70 +
   16.71 +    public static <T> Iterable<T> toIterable(final Collection<Iterable<T>> iterators) {
   16.72 +        return new Iterable<T>() {
   16.73 +            @Override
   16.74 +            public Iterator<T> iterator() {
   16.75 +                return new MergeIterator<T>(iterators);
   16.76 +            }
   16.77 +        };
   16.78 +    }
   16.79 +
   16.80 +    private Iterator<T> iter() {
   16.81 +        if (iterators.isEmpty()) {
   16.82 +            return null;
   16.83 +        }
   16.84 +        Iterator<T> result = iterators.get(0);
   16.85 +        if (!result.hasNext()) {
   16.86 +            iterators.remove(0);
   16.87 +            return iter();
   16.88 +        }
   16.89 +        return result;
   16.90 +    }
   16.91 +
   16.92 +    @Override
   16.93 +    public boolean hasNext() {
   16.94 +        Iterator<T> curr = iter();
   16.95 +        return curr == null ? false : curr.hasNext();
   16.96 +    }
   16.97 +
   16.98 +    @Override
   16.99 +    public T next() {
  16.100 +        Iterator<T> iter = iter();
  16.101 +        if (iter == null) {
  16.102 +            throw new NoSuchElementException();
  16.103 +        }
  16.104 +        return iter.next();
  16.105 +    }
  16.106 +
  16.107 +    @Override
  16.108 +    public void remove() {
  16.109 +        Iterator<T> iter = iter();
  16.110 +        if (iter == null) {
  16.111 +            throw new NoSuchElementException();
  16.112 +        }
  16.113 +        iter.remove();
  16.114 +    }
  16.115 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/callgraph/src/test/java/org/netbeans/lib/callgraph/ArgumentsTest.java	Mon Aug 31 15:31:15 2015 -0400
    17.3 @@ -0,0 +1,116 @@
    17.4 +package org.netbeans.lib.callgraph;
    17.5 +
    17.6 +import org.netbeans.lib.callgraph.CallgraphControl;
    17.7 +import org.netbeans.lib.callgraph.Arguments;
    17.8 +import org.netbeans.lib.callgraph.Callgraph;
    17.9 +import java.io.File;
   17.10 +import java.io.IOException;
   17.11 +import org.junit.Test;
   17.12 +import static org.junit.Assert.*;
   17.13 +
   17.14 +/**
   17.15 + * Tests argument parsing.
   17.16 + *
   17.17 + * @author Tim Boudreau
   17.18 + */
   17.19 +public class ArgumentsTest {
   17.20 +
   17.21 +    @Test
   17.22 +    public void testBooleanSwitches() {
   17.23 +        File tmpdir = new File(System.getProperty("java.io.tmpdir"));
   17.24 +        String tmp = tmpdir.getAbsolutePath();
   17.25 +
   17.26 +        Arguments args = new Arguments("-s", tmp);
   17.27 +        assertFalse(args.isMaven());
   17.28 +        assertTrue(args.isShortNames());
   17.29 +        assertTrue(args.isSelfReferences());
   17.30 +        assertTrue(args.folders().contains(new File(tmp)));
   17.31 +
   17.32 +        args = new Arguments("-n", tmp);
   17.33 +        assertFalse(args.isShortNames());
   17.34 +        assertFalse(args.isSelfReferences());
   17.35 +        assertTrue(args.folders().contains(new File(tmp)));
   17.36 +
   17.37 +        args = new Arguments("-n", "-g", tmp + File.separator + "out.txt", 
   17.38 +                "--exclude", "foo.bar,foo.baz", System.getProperty("java.io.tmpdir"));
   17.39 +        assertFalse(args.isShortNames());
   17.40 +        assertFalse(args.isSelfReferences());
   17.41 +        assertTrue(args.folders().contains(new File(tmp)));
   17.42 +        assertNotNull(args.methodGraphFile());
   17.43 +        assertEquals(new File(tmpdir, "out.txt"), args.methodGraphFile());
   17.44 +        assertFalse(args.excludePrefixes().isEmpty());
   17.45 +        assertTrue(args.excludePrefixes().contains("foo.bar"));
   17.46 +        assertTrue(args.excludePrefixes().contains("foo.baz"));
   17.47 +    }
   17.48 +
   17.49 +    @Test
   17.50 +    public void testBuilder() {
   17.51 +        File tmpdir = new File(System.getProperty("java.io.tmpdir"));
   17.52 +        String tmp = tmpdir.getAbsolutePath();
   17.53 +        CallgraphControl ctrl = Callgraph.configure().classGraphOutput(new File(tmpdir, "classes.txt"))
   17.54 +                .excludePrefix("foo.bar").excludePrefix("baz.quux")
   17.55 +                .ignoreSelfReferences().quiet().methodGraphOutput(new File(tmpdir, "methods.txt"))
   17.56 +                .addSourceParent(tmpdir).packageGraphOutput(new File(tmpdir, "pkgs.txt")).build();
   17.57 +    }
   17.58 +
   17.59 +    @Test(expected = Arguments.InvalidArgumentsException.class)
   17.60 +    public void testNoArguments() {
   17.61 +        new Arguments();
   17.62 +    }
   17.63 +
   17.64 +    @Test(expected = Arguments.InvalidArgumentsException.class)
   17.65 +    public void testQuietAndNoOuput() {
   17.66 +        new Arguments("-q", System.getProperty("java.io.tmpdir"));
   17.67 +    }
   17.68 +
   17.69 +    @Test(expected = Arguments.InvalidArgumentsException.class)
   17.70 +    public void testNonExistentFolder() {
   17.71 +        new Arguments("/" + System.currentTimeMillis());
   17.72 +    }
   17.73 +
   17.74 +    @Test
   17.75 +    public void testMavenScan() throws IOException {
   17.76 +        File tmp = new File(System.getProperty("java.io.tmpdir"));
   17.77 +        File dir = new File(tmp, ArgumentsTest.class.getSimpleName() + "_" + System.currentTimeMillis());
   17.78 +        File project1 = new File(dir, "prj");
   17.79 +        File project2 = new File(dir, "prj2");
   17.80 +        File pom1 = new File(project1, "pom.xml");
   17.81 +        File pom2 = new File(project2, "pom.xml");
   17.82 +
   17.83 +        File src1 = new File(project1, "src");
   17.84 +        File main1 = new File(src1, "main");
   17.85 +        File java1 = new File(main1, "java");
   17.86 +
   17.87 +        File src2 = new File(project2, "src");
   17.88 +        File main2 = new File(src2, "main");
   17.89 +        File java2 = new File(main2, "java");
   17.90 +
   17.91 +        assertTrue(java1.mkdirs());
   17.92 +        assertTrue(java2.mkdirs());
   17.93 +        pom1.createNewFile();
   17.94 +        pom2.createNewFile();
   17.95 +        try {
   17.96 +
   17.97 +            Arguments args = new Arguments("--maven", "-s", dir.getAbsolutePath());
   17.98 +            assertTrue(args.isMaven());
   17.99 +            assertTrue(args.isShortNames());
  17.100 +            assertTrue(args.isSelfReferences());
  17.101 +            assertTrue(args.folders().contains(java1));
  17.102 +            assertTrue(args.folders().contains(java2));
  17.103 +        } finally {
  17.104 +            // Clean up
  17.105 +            assertTrue(pom1.delete());
  17.106 +            assertTrue(pom2.delete());
  17.107 +            assertTrue(java1.delete());
  17.108 +            assertTrue(java2.delete());
  17.109 +            assertTrue(main1.delete());
  17.110 +            assertTrue(main2.delete());
  17.111 +            assertTrue(src1.delete());
  17.112 +            assertTrue(src2.delete());
  17.113 +            assertTrue(project1.delete());
  17.114 +            assertTrue(project2.delete());
  17.115 +            assertTrue(dir.delete());
  17.116 +        }
  17.117 +    }
  17.118 +
  17.119 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/callgraph/src/test/java/org/netbeans/lib/callgraph/util/SmallStringTest.java	Mon Aug 31 15:31:15 2015 -0400
    18.3 @@ -0,0 +1,87 @@
    18.4 +package org.netbeans.lib.callgraph.util;
    18.5 +
    18.6 +import org.netbeans.lib.callgraph.util.EightBitStrings;
    18.7 +import java.util.ArrayList;
    18.8 +import java.util.HashSet;
    18.9 +import java.util.List;
   18.10 +import java.util.Random;
   18.11 +import java.util.Set;
   18.12 +import org.junit.Test;
   18.13 +import static org.junit.Assert.*;
   18.14 +
   18.15 +/**
   18.16 + *
   18.17 + * @author tim
   18.18 + */
   18.19 +public class SmallStringTest {
   18.20 +
   18.21 +    @Test
   18.22 +    public void testCreate() {
   18.23 +        EightBitStrings strings = new EightBitStrings(false);
   18.24 +        CharSequence testOne = strings.create("A first test one");
   18.25 +        CharSequence testTwo = strings.create("A second test one");
   18.26 +        assertNotEquals(testOne, testTwo);
   18.27 +
   18.28 +        CharSequence hello = strings.create("Hello world");
   18.29 +        CharSequence hello2 = strings.create("Hello world");
   18.30 +        assertEquals(hello, hello2);
   18.31 +        assertSame(hello, hello2);
   18.32 +        assertEquals(hello.hashCode(), "Hello world".hashCode());
   18.33 +        assertEquals("Hello world", hello.toString());
   18.34 +        assertEquals("Hello world".length(), hello.length());
   18.35 +
   18.36 +        CharSequence worlds = strings.create("Hello worlds");
   18.37 +        assertNotEquals(hello2, worlds);
   18.38 +
   18.39 +        assertEquals(hello, "Hello world");
   18.40 +//        assertEquals("Hello world", hello);
   18.41 +    }
   18.42 +
   18.43 +    @Test
   18.44 +    public void testInterning() {
   18.45 +        EightBitStrings strings = new EightBitStrings(false);
   18.46 +        List<String> all = new ArrayList<>(500);
   18.47 +        List<CharSequence> seqs = new ArrayList<>();
   18.48 +        for (int i = 0; i < 500; i++) {
   18.49 +            String s = randomString(5 + r.nextInt(20));
   18.50 +            all.add(s);
   18.51 +            seqs.add(strings.create(s));
   18.52 +        }
   18.53 +        int size = strings.internTableSize();
   18.54 +        Set<CharSequence> xseqs = new HashSet<>(seqs);
   18.55 +        int oldSize = xseqs.size();
   18.56 +        for (String again : all) {
   18.57 +            CharSequence ss = strings.create(again);
   18.58 +            xseqs.add(ss);
   18.59 +            assertEquals(size, strings.internTableSize());
   18.60 +            assertEquals(oldSize, xseqs.size());
   18.61 +        }
   18.62 +    }
   18.63 +
   18.64 +    @Test
   18.65 +    public void testConcatenations() {
   18.66 +        EightBitStrings strings = new EightBitStrings(false);
   18.67 +        CharSequence concat = strings.concat("Hello ", "there ", "how ", "are ", "you?");
   18.68 +        CharSequence concat2 = strings.concat("Hello ", "there ", "how ", "are ", "you?");
   18.69 +        assertEquals("Hello there how are you?", concat.toString());
   18.70 +        assertEquals("Hello there how are you?".hashCode(), concat.toString().hashCode());
   18.71 +        assertEquals(concat, concat2);
   18.72 +
   18.73 +    }
   18.74 +
   18.75 +    private static String randomString(int len) {
   18.76 +        char[] c = new char[len];
   18.77 +        for (int i = 0; i < c.length; i++) {
   18.78 +            c[i] = randomChar();
   18.79 +        }
   18.80 +        return new String(c);
   18.81 +    }
   18.82 +
   18.83 +    private static char randomChar() {
   18.84 +        return alpha[r.nextInt(alpha.length)];
   18.85 +    }
   18.86 +
   18.87 +    static final Random r = new Random(320392);
   18.88 +    private static final char[] alpha = "abcdefghijklmnopqrstuvwxyz".toCharArray();
   18.89 +
   18.90 +}