8054717: SJavac should track changes in the public apis of classpath classes!

Added functionality for tracking changes in public APIs of classpath classes.

Reviewed-by: jlahoda, erikj
This commit is contained in:
Andreas Lundblad 2015-06-09 15:57:45 +02:00
parent 66dcce4334
commit 3a31593507
88 changed files with 2917 additions and 1990 deletions
langtools
src/jdk.compiler/share/classes/com/sun/tools/sjavac
test/tools/sjavac

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,12 +26,13 @@
package com.sun.tools.sjavac;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* The build state class captures the source code and generated artifacts
@ -77,7 +78,7 @@ public class BuildState {
*/
Module findModuleFromPackageName(String pkg) {
int cp = pkg.indexOf(':');
Assert.check(cp != -1);
Assert.check(cp != -1, "Could not find package name");
String mod = pkg.substring(0, cp);
return lookupModule(mod);
}
@ -154,21 +155,28 @@ public class BuildState {
*/
public void calculateDependents() {
dependents = new HashMap<>();
for (String s : packages.keySet()) {
Package p = packages.get(s);
for (String d : p.dependencies()) {
Set<String> ss = dependents.get(d);
if (ss == null) {
ss = new HashSet<>();
dependents.put(d, ss);
}
// Collect all dependencies of the classes in this package
Set<String> deps = p.typeDependencies() // maps fqName -> set of dependencies
.values()
.stream()
.reduce(Collections.emptySet(), Util::union);
// Now reverse the direction
for (String dep : deps) {
// Add the dependent information to the global dependent map.
ss.add(s);
Package dp = packages.get(d);
String depPkgStr = ":" + dep.substring(0, dep.lastIndexOf('.'));
dependents.merge(depPkgStr, Collections.singleton(s), Util::union);
// Also add the dependent information to the package specific map.
// Normally, you do not compile java.lang et al. Therefore
// there are several packages that p depends upon that you
// do not have in your state database. This is perfectly fine.
Package dp = packages.get(depPkgStr);
if (dp != null) {
// But this package did exist in the state database.
dp.addDependent(p.name());
@ -270,11 +278,21 @@ public class BuildState {
public void copyPackagesExcept(BuildState prev, Set<String> recompiled, Set<String> removed) {
for (String pkg : prev.packages().keySet()) {
// Do not copy recompiled or removed packages.
if (recompiled.contains(pkg) || removed.contains(pkg)) continue;
if (recompiled.contains(pkg) || removed.contains(pkg))
continue;
Module mnew = findModuleFromPackageName(pkg);
Package pprev = prev.packages().get(pkg);
// Even though we haven't recompiled this package, we may have
// information about its public API: It may be a classpath dependency
if (packages.containsKey(pkg)) {
pprev.setPubapi(PubApi.mergeTypes(pprev.getPubApi(),
packages.get(pkg).getPubApi()));
}
mnew.addPackage(pprev);
// Do not forget to update the flattened data.
// Do not forget to update the flattened data. (See JDK-8071904)
packages.put(pkg, pprev);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,17 +25,25 @@
package com.sun.tools.sjavac;
import java.io.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.server.Sjavac;
/**
@ -63,8 +71,10 @@ public class CleanProperties implements Transformer {
Map<String,Set<String>> oldPackageDependencies,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePublicApis,
Map<String, Map<String, Set<String>>> packageDependencies,
Map<String, Map<String, Set<String>>> packageCpDependencies,
Map<String, PubApi> packagePublicApis,
Map<String, PubApi> dependencyPublicApis,
int debugLevel,
boolean incremental,
int numCores,

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,10 +30,12 @@ import java.io.PrintStream;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.Sjavac;
import com.sun.tools.sjavac.server.SysInfo;
@ -73,21 +75,25 @@ public class CompileJavaPackages implements Transformer {
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
final Map<String,Set<URI>> packageArtifacts,
final Map<String,Set<String>> packageDependencies,
final Map<String,String> packagePubapis,
final Map<String,Map<String, Set<String>>> packageDependencies,
final Map<String,Map<String, Set<String>>> packageCpDependencies,
final Map<String, PubApi> packagePubapis,
final Map<String, PubApi> dependencyPubapis,
int debugLevel,
boolean incremental,
int numCores,
final PrintStream out,
final PrintStream err)
{
final PrintStream err) {
Log.debug("Performing CompileJavaPackages transform...");
boolean rc = true;
boolean concurrentCompiles = true;
// Fetch the id.
final String id = Util.extractStringOption("id", sjavac.serverSettings());
// Only keep portfile and sjavac settings..
String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), sjavac.serverSettings());
//String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), sjavac.serverSettings());
// Get maximum heap size from the server!
SysInfo sysinfo = sjavac.getSysInfo();
@ -210,20 +216,44 @@ public class CompileJavaPackages implements Transformer {
final CompileChunk cc = compileChunks[i];
// Pass the num_cores and the id (appended with the chunk number) to the server.
final String cleanedServerSettings = psServerSettings+",poolsize="+numCores+",id="+id+"-"+i;
Object lock = new Object();
requests[i] = new Thread() {
@Override
public void run() {
rn[ii] = sjavac.compile("n/a",
id + "-" + ii,
args.prepJavacArgs(),
Collections.<File>emptyList(),
cc.srcs,
visibleSources);
packageArtifacts.putAll(rn[ii].packageArtifacts);
packageDependencies.putAll(rn[ii].packageDependencies);
packagePubapis.putAll(rn[ii].packagePubapis);
id + "-" + ii,
args.prepJavacArgs(),
Collections.<File>emptyList(),
cc.srcs,
visibleSources);
// In the code below we have to keep in mind that two
// different compilation results may include results for
// the same package.
synchronized (lock) {
for (String pkg : rn[ii].packageArtifacts.keySet()) {
Set<URI> pkgArtifacts = rn[ii].packageArtifacts.get(pkg);
packageArtifacts.merge(pkg, pkgArtifacts, Util::union);
}
for (String pkg : rn[ii].packageDependencies.keySet()) {
packageDependencies.putIfAbsent(pkg, new HashMap<>());
packageDependencies.get(pkg).putAll(rn[ii].packageDependencies.get(pkg));
}
for (String pkg : rn[ii].packageCpDependencies.keySet()) {
packageCpDependencies.putIfAbsent(pkg, new HashMap<>());
packageCpDependencies.get(pkg).putAll(rn[ii].packageCpDependencies.get(pkg));
}
for (String pkg : rn[ii].packagePubapis.keySet()) {
packagePubapis.merge(pkg, rn[ii].packagePubapis.get(pkg), PubApi::mergeTypes);
}
for (String pkg : rn[ii].dependencyPubapis.keySet()) {
dependencyPubapis.merge(pkg, rn[ii].dependencyPubapis.get(pkg), PubApi::mergeTypes);
}
}
}
};
@ -278,7 +308,6 @@ public class CompileJavaPackages implements Transformer {
return rc;
}
/**
* Split up the sources into compile chunks. If old package dependents information
* is available, sort the order of the chunks into the most dependent first!
@ -294,9 +323,9 @@ public class CompileJavaPackages implements Transformer {
* @return
*/
CompileChunk[] createCompileChunks(Map<String,Set<URI>> pkgSrcs,
Map<String,Set<String>> oldPackageDependents,
int numCompiles,
int sourcesPerCompile) {
Map<String,Set<String>> oldPackageDependents,
int numCompiles,
int sourcesPerCompile) {
CompileChunk[] compileChunks = new CompileChunk[numCompiles];
for (int i=0; i<compileChunks.length; ++i) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,19 +25,27 @@
package com.sun.tools.sjavac;
import java.io.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Writer;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.server.Sjavac;
/**
@ -70,8 +78,10 @@ public class CompileProperties implements Transformer {
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePublicApis,
Map<String,Map<String, Set<String>>> packageDependencies,
Map<String,Map<String, Set<String>>> packageCpDependencies,
Map<String, PubApi> packagePublicApis,
Map<String, PubApi> dependencyPublicApis,
int debugLevel,
boolean incremental,
int numCores,

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,13 +25,20 @@
package com.sun.tools.sjavac;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.server.Sjavac;
/**
@ -58,8 +65,10 @@ public class CopyFile implements Transformer {
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePubapis,
Map<String,Map<String, Set<String>>> packageDependencies,
Map<String,Map<String, Set<String>>> packageCpDependencies,
Map<String, PubApi> packagePubapis,
Map<String, PubApi> dependencyPubapis,
int debugLevel,
boolean incremental,
int numCores,

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,11 +25,17 @@
package com.sun.tools.sjavac;
import java.io.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URI;
import java.nio.file.NoSuchFileException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@ -37,8 +43,10 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.server.Sjavac;
/**
@ -268,24 +276,25 @@ public class JavacState {
* Save the javac_state file.
*/
public void save() throws IOException {
if (!needsSaving) return;
if (!needsSaving)
return;
try (FileWriter out = new FileWriter(javacState)) {
StringBuilder b = new StringBuilder();
long millisNow = System.currentTimeMillis();
Date d = new Date(millisNow);
SimpleDateFormat df =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
b.append("# javac_state ver 0.3 generated "+millisNow+" "+df.format(d)+"\n");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
b.append("# javac_state ver 0.4 generated "+millisNow+" "+df.format(d)+"\n");
b.append("# This format might change at any time. Please do not depend on it.\n");
b.append("# R arguments\n");
b.append("# M module\n");
b.append("# P package\n");
b.append("# S C source_tobe_compiled timestamp\n");
b.append("# S L link_only_source timestamp\n");
b.append("# G C generated_source timestamp\n");
b.append("# A artifact timestamp\n");
b.append("# D dependency\n");
b.append("# D S dependant -> source dependency\n");
b.append("# D C dependant -> classpath dependency\n");
b.append("# I pubapi\n");
b.append("# R arguments\n");
b.append("R ").append(theArgs).append("\n");
// Copy over the javac_state for the packages that did not need recompilation.
@ -312,6 +321,8 @@ public class JavacState {
boolean newCommandLine = false;
boolean syntaxError = false;
Log.debug("Loading javac state file: " + db.javacState);
try (BufferedReader in = new BufferedReader(new FileReader(db.javacState))) {
for (;;) {
String l = in.readLine();
@ -327,11 +338,14 @@ public class JavacState {
} else
if (c == 'D') {
if (lastModule == null || lastPackage == null) { syntaxError = true; break; }
lastPackage.loadDependency(l);
char depType = l.charAt(2);
if (depType != 'S' && depType != 'C')
throw new RuntimeException("Bad dependency string: " + l);
lastPackage.parseAndAddDependency(l.substring(4), depType == 'C');
} else
if (c == 'I') {
if (lastModule == null || lastPackage == null) { syntaxError = true; break; }
lastPackage.loadPubapi(l);
lastPackage.getPubApi().appendItem(l.substring(2)); // Strip "I "
} else
if (c == 'A') {
if (lastModule == null || lastPackage == null) { syntaxError = true; break; }
@ -356,7 +370,7 @@ public class JavacState {
int sp = l.indexOf(" ", 18);
if (sp != -1) {
String ver = l.substring(18,sp);
if (!ver.equals("0.3")) {
if (!ver.equals("0.4")) {
break;
}
foundCorrectVerNr = true;
@ -488,11 +502,92 @@ public class JavacState {
* Propagate recompilation through the dependency chains.
* Avoid re-tainting packages that have already been compiled.
*/
public void taintPackagesDependingOnChangedPackages(Set<String> pkgs, Set<String> recentlyCompiled) {
public void taintPackagesDependingOnChangedPackages(Set<String> pkgsWithChangedPubApi, Set<String> recentlyCompiled) {
// For each to-be-recompiled-candidates...
for (Package pkg : new HashSet<>(prev.packages().values())) {
// Find out what it depends upon...
Set<String> deps = pkg.typeDependencies()
.values()
.stream()
.flatMap(s -> s.stream())
.collect(Collectors.toSet());
for (String dep : deps) {
String depPkg = ":" + dep.substring(0, dep.lastIndexOf('.'));
if (depPkg.equals(pkg.name()))
continue;
// Checking if that dependency has changed
if (pkgsWithChangedPubApi.contains(depPkg) && !recentlyCompiled.contains(pkg.name())) {
taintPackage(pkg.name(), "its depending on " + depPkg);
}
}
}
}
/**
* Compare the javac_state recorded public apis of packages on the classpath
* with the actual public apis on the classpath.
*/
public void taintPackagesDependingOnChangedClasspathPackages() {
// 1. Collect fully qualified names of all interesting classpath dependencies
Set<String> fqDependencies = new HashSet<>();
for (Package pkg : prev.packages().values()) {
for (String dep : pkg.dependencies()) {
if (pkgs.contains(dep) && !recentlyCompiled.contains(pkg.name())) {
taintPackage(pkg.name(), " its depending on "+dep);
// Check if this package was compiled. If it's presence is recorded
// because it was on the class path and we needed to save it's
// public api, it's not a candidate for tainting.
if (pkg.sources().isEmpty())
continue;
pkg.typeClasspathDependencies().values().forEach(fqDependencies::addAll);
}
// 2. Extract the public APIs from the on disk .class files
// (Reason for doing step 1 in a separate phase is to avoid extracting
// public APIs of the same class twice.)
PubApiExtractor pubApiExtractor = new PubApiExtractor(options);
Map<String, PubApi> onDiskPubApi = new HashMap<>();
for (String cpDep : fqDependencies) {
onDiskPubApi.put(cpDep, pubApiExtractor.getPubApi(cpDep));
}
// 3. Compare them with the public APIs as of last compilation (loaded from javac_state)
nextPkg:
for (Package pkg : prev.packages().values()) {
// Check if this package was compiled. If it's presence is recorded
// because it was on the class path and we needed to save it's
// public api, it's not a candidate for tainting.
if (pkg.sources().isEmpty())
continue;
Set<String> cpDepsOfThisPkg = new HashSet<>();
for (Set<String> cpDeps : pkg.typeClasspathDependencies().values())
cpDepsOfThisPkg.addAll(cpDeps);
for (String fqDep : cpDepsOfThisPkg) {
String depPkg = ":" + fqDep.substring(0, fqDep.lastIndexOf('.'));
PubApi prevPkgApi = prev.packages().get(depPkg).getPubApi();
// This PubApi directly lists the members of the class,
// i.e. [ MEMBER1, MEMBER2, ... ]
PubApi prevDepApi = prevPkgApi.types.get(fqDep).pubApi;
// In order to dive *into* the class, we need to add
// .types.get(fqDep).pubApi below.
PubApi currentDepApi = onDiskPubApi.get(fqDep).types.get(fqDep).pubApi;
if (!currentDepApi.isBackwardCompatibleWith(prevDepApi)) {
List<String> apiDiff = currentDepApi.diff(prevDepApi);
taintPackage(pkg.name(), "depends on classpath "
+ "package which has an updated package api: "
+ String.join("\n", apiDiff));
//Log.debug("========================================");
//Log.debug("------ PREV API ------------------------");
//prevDepApi.asListOfStrings().forEach(Log::debug);
//Log.debug("------ CURRENT API ---------------------");
//currentDepApi.asListOfStrings().forEach(Log::debug);
//Log.debug("========================================");
continue nextPkg;
}
}
}
@ -660,7 +755,6 @@ public class JavacState {
Map<String,Transformer> suffixRules = new HashMap<>();
suffixRules.put(".java", compileJavaPackages);
compileJavaPackages.setExtra(args);
rcValue[0] = perform(sjavac, binDir, suffixRules);
recentlyCompiled.addAll(taintedPackages());
clearTaintedPackages();
@ -668,6 +762,11 @@ public class JavacState {
taintPackagesDependingOnChangedPackages(packagesWithChangedPublicApis, recentlyCompiled);
packagesWithChangedPublicApis = new HashSet<>();
return again && rcValue[0];
// TODO: Figure out why 'again' checks packagesWithChangedPublicAPis.
// (It shouldn't matter if packages had changed pub apis as long as no
// one depends on them. Wouldn't it make more sense to let 'again'
// depend on taintedPackages?)
}
/**
@ -699,68 +798,101 @@ public class JavacState {
Map<Transformer,Map<String,Set<URI>>> groupedSources = new HashMap<>();
for (Source src : now.sources().values()) {
Transformer t = suffixRules.get(src.suffix());
if (t != null) {
if (t != null) {
if (taintedPackages.contains(src.pkg().name()) && !src.isLinkedOnly()) {
addFileToTransform(groupedSources, t, src);
}
}
}
// Go through the transforms and transform them.
for (Map.Entry<Transformer,Map<String,Set<URI>>> e : groupedSources.entrySet()) {
for (Map.Entry<Transformer, Map<String, Set<URI>>> e : groupedSources.entrySet()) {
Transformer t = e.getKey();
Map<String,Set<URI>> srcs = e.getValue();
// These maps need to be synchronized since multiple threads will be writing results into them.
Map<String,Set<URI>> packageArtifacts =
Collections.synchronizedMap(new HashMap<String,Set<URI>>());
Map<String,Set<String>> packageDependencies =
Collections.synchronizedMap(new HashMap<String,Set<String>>());
Map<String,String> packagePublicApis =
Collections.synchronizedMap(new HashMap<String, String>());
Map<String, Set<URI>> srcs = e.getValue();
// These maps need to be synchronized since multiple threads will be
// writing results into them.
Map<String, Set<URI>> packageArtifacts = Collections.synchronizedMap(new HashMap<>());
Map<String, Map<String, Set<String>>> packageDependencies = Collections.synchronizedMap(new HashMap<>());
Map<String, Map<String, Set<String>>> packageCpDependencies = Collections.synchronizedMap(new HashMap<>());
Map<String, PubApi> packagePublicApis = Collections.synchronizedMap(new HashMap<>());
Map<String, PubApi> dependencyPublicApis = Collections.synchronizedMap(new HashMap<>());
boolean r = t.transform(sjavac,
srcs,
visibleSrcs,
visibleClasses,
prev.dependents(),
outputDir.toURI(),
packageArtifacts,
packageDependencies,
packagePublicApis,
0,
isIncremental(),
numCores,
out,
err);
if (!r) rc = false;
boolean r = t.transform(sjavac,
srcs,
visibleSrcs,
visibleClasses,
prev.dependents(),
outputDir.toURI(),
packageArtifacts,
packageDependencies,
packageCpDependencies,
packagePublicApis,
dependencyPublicApis,
0,
isIncremental(),
numCores,
out,
err);
if (!r)
rc = false;
for (String p : srcs.keySet()) {
recompiledPackages.add(p);
}
// The transform is done! Extract all the artifacts and store the info into the Package objects.
for (Map.Entry<String,Set<URI>> a : packageArtifacts.entrySet()) {
for (Map.Entry<String, Set<URI>> a : packageArtifacts.entrySet()) {
Module mnow = now.findModuleFromPackageName(a.getKey());
mnow.addArtifacts(a.getKey(), a.getValue());
}
// Extract all the dependencies and store the info into the Package objects.
for (Map.Entry<String,Set<String>> a : packageDependencies.entrySet()) {
Set<String> deps = a.getValue();
for (Map.Entry<String, Map<String, Set<String>>> a : packageDependencies.entrySet()) {
Map<String, Set<String>> deps = a.getValue();
Module mnow = now.findModuleFromPackageName(a.getKey());
mnow.setDependencies(a.getKey(), deps);
mnow.setDependencies(a.getKey(), deps, false);
}
// Extract all the pubapis and store the info into the Package objects.
for (Map.Entry<String,String> a : packagePublicApis.entrySet()) {
Module mprev = prev.findModuleFromPackageName(a.getKey());
List<String> pubapi = Package.pubapiToList(a.getValue());
for (Map.Entry<String, Map<String, Set<String>>> a : packageCpDependencies.entrySet()) {
Map<String, Set<String>> deps = a.getValue();
Module mnow = now.findModuleFromPackageName(a.getKey());
mnow.setPubapi(a.getKey(), pubapi);
if (mprev.hasPubapiChanged(a.getKey(), pubapi)) {
mnow.setDependencies(a.getKey(), deps, true);
}
// This map contains the public api of the types that this
// compilation depended upon. This means that it may not contain
// full packages. In other words, we shouldn't remove knowledge of
// public apis but merge these with what we already have.
for (Map.Entry<String, PubApi> a : dependencyPublicApis.entrySet()) {
String pkg = a.getKey();
PubApi packagePartialPubApi = a.getValue();
Package pkgNow = now.findModuleFromPackageName(pkg).lookupPackage(pkg);
PubApi currentPubApi = pkgNow.getPubApi();
PubApi newPubApi = PubApi.mergeTypes(currentPubApi, packagePartialPubApi);
pkgNow.setPubapi(newPubApi);
// See JDK-8071904
if (now.packages().containsKey(pkg))
now.packages().get(pkg).setPubapi(newPubApi);
else
now.packages().put(pkg, pkgNow);
}
// The packagePublicApis cover entire packages (since sjavac compiles
// stuff on package level). This means that if a type is missing
// in the public api of a given package, it means that it has been
// removed. In other words, we should *set* the pubapi to whatever
// this map contains, and not merge it with what we already have.
for (Map.Entry<String, PubApi> a : packagePublicApis.entrySet()) {
String pkg = a.getKey();
PubApi newPubApi = a.getValue();
Module mprev = prev.findModuleFromPackageName(pkg);
Module mnow = now.findModuleFromPackageName(pkg);
mnow.setPubapi(pkg, newPubApi);
if (mprev.hasPubapiChanged(pkg, newPubApi)) {
// Aha! The pubapi of this package has changed!
// It can also be a new compile from scratch.
if (mprev.lookupPackage(a.getKey()).existsInJavacState()) {
if (mprev.lookupPackage(pkg).existsInJavacState()) {
// This is an incremental compile! The pubapi
// did change. Trigger recompilation of dependents.
packagesWithChangedPublicApis.add(a.getKey());
Log.info("The pubapi of "+Util.justPackageName(a.getKey())+" has changed!");
packagesWithChangedPublicApis.add(pkg);
Log.info("The API of " + Util.justPackageName(pkg) + " has changed!");
}
}
}
@ -791,17 +923,21 @@ public class JavacState {
}
/**
* Compare the calculate source list, with an explicit list, usually supplied from the makefile.
* Used to detect bugs where the makefile and sjavac have different opinions on which files
* should be compiled.
* Compare the calculate source list, with an explicit list, usually
* supplied from the makefile. Used to detect bugs where the makefile and
* sjavac have different opinions on which files should be compiled.
*/
public void compareWithMakefileList(File makefileSourceList) throws ProblemException {
// If we are building on win32 using for example cygwin the paths in the makefile source list
public void compareWithMakefileList(File makefileSourceList)
throws ProblemException {
// If we are building on win32 using for example cygwin the paths in the
// makefile source list
// might be /cygdrive/c/.... which does not match c:\....
// We need to adjust our calculated sources to be identical, if necessary.
// We need to adjust our calculated sources to be identical, if
// necessary.
boolean mightNeedRewriting = File.pathSeparatorChar == ';';
if (makefileSourceList == null) return;
if (makefileSourceList == null)
return;
Set<String> calculatedSources = new HashSet<>();
Set<String> listedSources = new HashSet<>();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,10 +28,11 @@ package com.sun.tools.sjavac;
import java.io.File;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* The module is the root of a set of packages/sources/artifacts.
* At the moment there is only one module in use, the empty/no-name/default module.
@ -86,8 +87,7 @@ public class Module implements Comparable<Module> {
return new Module(name, "");
}
public static void saveModules(Map<String,Module> ms, StringBuilder b)
{
public static void saveModules(Map<String,Module> ms, StringBuilder b) {
for (Module m : ms.values()) {
m.save(b);
}
@ -98,6 +98,7 @@ public class Module implements Comparable<Module> {
}
public Package lookupPackage(String pkg) {
// See JDK-8071904
Package p = packages.get(pkg);
if (p == null) {
p = new Package(this, pkg);
@ -124,18 +125,17 @@ public class Module implements Comparable<Module> {
}
}
public void setDependencies(String pkg, Set<String> deps) {
Package p = lookupPackage(pkg);
p.setDependencies(deps);
public void setDependencies(String pkg, Map<String, Set<String>> deps, boolean cp) {
lookupPackage(pkg).setDependencies(deps, cp);
}
public void setPubapi(String pkg, List<String> ps) {
public void setPubapi(String pkg, PubApi ps) {
Package p = lookupPackage(pkg);
p.setPubapi(ps);
}
public boolean hasPubapiChanged(String pkg, List<String> ps) {
public boolean hasPubapiChanged(String pkg, PubApi newPubApi) {
Package p = lookupPackage(pkg);
return p.hasPubapiChanged(ps);
return p.hasPubApiChanged(newPubApi);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,11 +31,16 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* The Package class maintains meta information about a package.
@ -71,12 +76,16 @@ public class Package implements Comparable<Package> {
// The directory path to the package. If the package belongs to a module,
// then that module's file system name is part of the path.
private String dirname;
// This package depends on these packages.
private Set<String> dependencies = new HashSet<>();
// This package has the following dependents, that depend on this package.
private Set<String> dependents = new HashSet<>();
// Fully qualified name of class in this package -> fully qualified name of dependency
private Map<String, Set<String>> dependencies = new TreeMap<>();
// Fully qualified name of class in this package -> fully qualified name of dependency on class path
private Map<String, Set<String>> cpDependencies = new TreeMap<>();
// This is the public api of this package.
private List<String> pubapi = new ArrayList<>();
private PubApi pubApi = new PubApi();
// Map from source file name to Source info object.
private Map<String,Source> sources = new HashMap<>();
// This package generated these artifacts.
@ -85,7 +94,6 @@ public class Package implements Comparable<Package> {
public Package(Module m, String n) {
int c = n.indexOf(":");
Assert.check(c != -1);
String mn = n.substring(0,c);
Assert.check(m.name().equals(m.name()));
name = n;
dirname = n.replace('.', File.separatorChar);
@ -100,9 +108,11 @@ public class Package implements Comparable<Package> {
public String dirname() { return dirname; }
public Map<String,Source> sources() { return sources; }
public Map<String,File> artifacts() { return artifacts; }
public List<String> pubapi() { return pubapi; }
public PubApi getPubApi() { return pubApi; }
public Map<String,Set<String>> typeDependencies() { return dependencies; }
public Map<String,Set<String>> typeClasspathDependencies() { return cpDependencies; }
public Set<String> dependencies() { return dependencies; }
public Set<String> dependents() { return dependents; }
@Override
@ -124,70 +134,48 @@ public class Package implements Comparable<Package> {
sources.put(s.file().getPath(), s);
}
public void addDependency(String d) {
dependencies.add(d);
private static Pattern DEP_PATTERN = Pattern.compile("(.*) -> (.*)");
public void parseAndAddDependency(String d, boolean cp) {
Matcher m = DEP_PATTERN.matcher(d);
if (!m.matches())
throw new IllegalArgumentException("Bad dependency string: " + d);
addDependency(m.group(1), m.group(2), cp);
}
public void addDependency(String fullyQualifiedFrom,
String fullyQualifiedTo,
boolean cp) {
Map<String, Set<String>> map = cp ? cpDependencies : dependencies;
if (!map.containsKey(fullyQualifiedFrom))
map.put(fullyQualifiedFrom, new HashSet<>());
map.get(fullyQualifiedFrom).add(fullyQualifiedTo);
}
public void addDependent(String d) {
dependents.add(d);
}
public void addPubapi(String p) {
pubapi.add(p);
}
/**
* Check if we have knowledge in the javac state that
* describe the results of compiling this package before.
*/
public boolean existsInJavacState() {
return artifacts.size() > 0 || pubapi.size() > 0;
return artifacts.size() > 0 || !pubApi.isEmpty();
}
public static List<String> pubapiToList(String ps)
{
String[] lines = ps.split("\n");
List<String> r = new ArrayList<>();
for (String l : lines) {
r.add(l);
}
return r;
public boolean hasPubApiChanged(PubApi newPubApi) {
return !newPubApi.isBackwardCompatibleWith(pubApi);
}
public boolean hasPubapiChanged(List<String> ps) {
Iterator<String> i = ps.iterator();
Iterator<String> j = pubapi.iterator();
int line = 0;
while (i.hasNext() && j.hasNext()) {
String is = i.next();
String js = j.next();
if (!is.equals(js)) {
Log.debug("Change in pubapi for package "+name+" line "+line);
Log.debug("Old: "+js);
Log.debug("New: "+is);
return true;
}
line++;
}
if ((i.hasNext() && !j.hasNext() ) ||
(!i.hasNext() && j.hasNext())) {
Log.debug("Change in pubapi for package "+name);
if (i.hasNext()) {
Log.debug("New has more lines!");
} else {
Log.debug("Old has more lines!");
}
return true;
}
return false;
public void setPubapi(PubApi newPubApi) {
pubApi = newPubApi;
}
public void setPubapi(List<String> ps) {
pubapi = ps;
}
public void setDependencies(Set<String> ds) {
dependencies = ds;
public void setDependencies(Map<String, Set<String>> ds, boolean cp) {
(cp ? cpDependencies : dependencies).clear();
for (String fullyQualifiedFrom : ds.keySet())
for (String fullyQualifiedTo : ds.get(fullyQualifiedFrom))
addDependency(fullyQualifiedFrom, fullyQualifiedTo, cp);
}
public void save(StringBuilder b) {
@ -203,31 +191,28 @@ public class Package implements Comparable<Package> {
return new Package(module, name);
}
public void loadDependency(String l) {
String n = l.substring(2);
addDependency(n);
}
public void loadPubapi(String l) {
String pi = l.substring(2);
addPubapi(pi);
}
public void saveDependencies(StringBuilder b) {
List<String> sorted_dependencies = new ArrayList<>();
for (String key : dependencies) {
sorted_dependencies.add(key);
// Dependencies where *to* is among sources
for (String fullyQualifiedFrom : dependencies.keySet()) {
for (String fullyQualifiedTo : dependencies.get(fullyQualifiedFrom)) {
b.append(String.format("D S %s -> %s%n", fullyQualifiedFrom, fullyQualifiedTo));
}
}
Collections.sort(sorted_dependencies);
for (String a : sorted_dependencies) {
b.append("D "+a+"\n");
// Dependencies where *to* is on class path
for (String fullyQualifiedFrom : cpDependencies.keySet()) {
for (String fullyQualifiedTo : cpDependencies.get(fullyQualifiedFrom)) {
b.append(String.format("D C %s -> %s%n", fullyQualifiedFrom, fullyQualifiedTo));
}
}
}
public void savePubapi(StringBuilder b) {
for (String l : pubapi) {
b.append("I "+l+"\n");
}
pubApi.asListOfStrings()
.stream()
.flatMap(l -> Stream.of("I ", l, "\n"))
.forEach(b::append);
}
public static void savePackages(Map<String,Package> packages, StringBuilder b) {

@ -0,0 +1,85 @@
/*
* Copyright (c) 2012-2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac;
import java.io.PrintWriter;
import java.util.Arrays;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.code.ClassFinder;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.sjavac.comp.PubapiVisitor;
import com.sun.tools.sjavac.comp.SmartFileManager;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
public class PubApiExtractor {
// Setup a compiler context for finding classes in the classpath
// and to execute annotation processors.
Context context;
CompilationTask task;
/**
* Setup a compilation context, used for reading public apis of classes on the classpath
* as well as annotation processors.
*/
public PubApiExtractor(Options options) {
JavacTool compiler = com.sun.tools.javac.api.JavacTool.create();
SmartFileManager fileManager = new SmartFileManager(compiler.getStandardFileManager(null, null, null));
context = new com.sun.tools.javac.util.Context();
String[] args = options.prepJavacArgs();
task = compiler.getTask(new PrintWriter(System.err),
fileManager,
null,
Arrays.asList(args),
null,
null,
context);
// Trigger a creation of the JavaCompiler, necessary to get a sourceCompleter for ClassFinder.
// The sourceCompleter is used for build situations where a classpath class references other classes
// that happens to be on the sourcepath.
JavaCompiler.instance(context);
// context.put(JavaFileManager.class, fileManager);
}
public PubApi getPubApi(String fullyQualifiedClassName) {
ClassFinder cr = ClassFinder.instance(context);
Names ns = Names.instance(context);
Name n = ns.fromString(fullyQualifiedClassName);
ClassSymbol cs = cr.loadClass(n);
PubapiVisitor v = new PubapiVisitor();
v.visit(cs);
return v.getCollectedPubApi();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -373,8 +373,6 @@ public class Source implements Comparable<Source> {
return currentModule;
}
private static boolean gurka = false;
static private void scanDirectory(File dir, int rootPrefix, File root,
Set<String> suffixes,
List<String> excludes, List<String> includes,

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,10 +27,11 @@ package com.sun.tools.sjavac;
import java.io.PrintStream;
import java.net.URI;
import java.util.Set;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.server.Sjavac;
/**
@ -89,8 +90,10 @@ public interface Transformer {
Map<String,Set<String>> oldPackageDependencies,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
Map<String,Set<String>> packageDependencies,
Map<String,String> packagePublicApis,
Map<String, Map<String, Set<String>>> packageDependencies, // Package name -> Fully Qualified Type [from] -> Set of fully qualified type [to]
Map<String, Map<String, Set<String>>> packageCpDependencies, // Package name -> Fully Qualified Type [from] -> Set of fully qualified type [to]
Map<String, PubApi> packagePublicApis,
Map<String, PubApi> dependencyApis,
int debugLevel,
boolean incremental,
int numCores,

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,9 +30,13 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Utilities.
@ -106,6 +110,20 @@ public class Util {
return v;
}
/**
* Extract the package name from a fully qualified class name.
*
* Example: Given "pkg.subpkg.A" this method returns ":pkg.subpkg".
* Given "C" this method returns ":".
*
* @returns package name of the given class name
*/
public static String pkgNameOfClassName(String fqClassName) {
int i = fqClassName.lastIndexOf('.');
String pkg = i == -1 ? "" : fqClassName.substring(0, i);
return ":" + pkg;
}
/**
* Clean out unwanted sub options supplied inside a primary option.
* For example to only had portfile remaining from:
@ -183,6 +201,13 @@ public class Util {
return union;
}
public static <E> Set<E> subtract(Set<? extends E> orig,
Set<? extends E> toSubtract) {
Set<E> difference = new HashSet<>(orig);
difference.removeAll(toSubtract);
return difference;
}
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
@ -193,4 +218,16 @@ public class Util {
public static File pathToFile(Path path) {
return path == null ? null : path.toFile();
}
public static <E> Set<E> intersection(Collection<? extends E> c1,
Collection<? extends E> c2) {
Set<E> intersection = new HashSet<E>(c1);
intersection.retainAll(c2);
return intersection;
}
public static <I, T> Map<I, T> indexBy(Collection<? extends T> c,
Function<? super T, ? extends I> indexFunction) {
return c.stream().collect(Collectors.toMap(indexFunction, o -> o));
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -93,6 +93,11 @@ public class ClientMain {
if (hdrdir != null && !createIfMissing(hdrdir))
return -1;
Log.debug("==========================================================");
Log.debug("Launching sjavac client with the following parameters:");
Log.debug(" " + options.getStateArgsString());
Log.debug("==========================================================");
// Load the prev build state database.
JavacState javac_state = JavacState.load(options, out, err);
@ -167,6 +172,9 @@ public class ClientMain {
javac_state.now().checkInternalState("checking linked sources", true, sources_to_link_to);
javac_state.setVisibleSources(sources_to_link_to);
int round = 0;
printRound(round);
// If there is any change in the source files, taint packages
// and mark the database in need of saving.
javac_state.checkSourceStatus(false);
@ -188,6 +196,10 @@ public class ClientMain {
// Go through all sources and taint all packages that miss artifacts.
javac_state.taintPackagesThatMissArtifacts();
// Check recorded classpath public apis. Taint packages that depend on
// classpath classes whose public apis have changed.
javac_state.taintPackagesDependingOnChangedClasspathPackages();
// Now clean out all known artifacts belonging to tainted packages.
javac_state.deleteClassArtifactsInTaintedPackages();
// Copy files, for example property files, images files, xml files etc etc.
@ -231,11 +243,22 @@ public class ClientMain {
}
do {
if (round > 0)
printRound(round);
// Clean out artifacts in tainted packages.
javac_state.deleteClassArtifactsInTaintedPackages();
again = javac_state.performJavaCompilations(sjavac, options, recently_compiled, rc);
if (!rc[0]) break;
if (!rc[0]) {
Log.debug("Compilation failed.");
break;
}
if (!again) {
Log.debug("Nothing left to do.");
}
round++;
} while (again);
Log.debug("No need to do another round.");
// Only update the state if the compile went well.
if (rc[0]) {
javac_state.save();
@ -323,4 +346,10 @@ public class ClientMain {
}
}
private static void printRound(int round) {
Log.debug("****************************************");
Log.debug("* Round " + round + " *");
Log.debug("****************************************");
}
}

@ -1,181 +0,0 @@
/*
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import javax.lang.model.element.Element;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
/** Utility class containing dependency information between packages
* and the pubapi for a package.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Dependencies {
protected static final Context.Key<Dependencies> dependenciesKey = new Context.Key<>();
// The log to be used for error reporting.
protected Log log;
// Map from package name to packages that the package depends upon.
protected Map<Name,Set<Name>> deps;
// This is the set of all packages that are supplied
// through the java files at the command line.
protected Set<Name> explicitPackages;
// Map from a package name to its public api.
// Will the Name encode the module in the future?
// If not, this will have to change to map from Module+Name to public api.
protected Map<Name,StringBuffer> publicApiPerClass;
public static Dependencies instance(Context context) {
Dependencies instance = context.get(dependenciesKey);
if (instance == null)
instance = new Dependencies(context);
return instance;
}
private Dependencies(Context context) {
context.put(dependenciesKey, this);
log = Log.instance(context);
deps = new HashMap<>();
explicitPackages = new HashSet<>();
publicApiPerClass = new HashMap<>();
}
/**
* Fetch the set of dependencies that are relevant to the compile
* that has just been performed. I.e. we are only interested in
* dependencies for classes that were explicitly compiled.
* @return
*/
public Map<String,Set<String>> getDependencies() {
Map<String,Set<String>> new_deps = new HashMap<>();
if (explicitPackages == null) return new_deps;
for (Name pkg : explicitPackages) {
Set<Name> set = deps.get(pkg);
if (set != null) {
Set<String> new_set = new_deps.get(pkg.toString());
if (new_set == null) {
new_set = new HashSet<>();
// Modules beware....
new_deps.put(":"+pkg.toString(), new_set);
}
for (Name d : set) {
new_set.add(":"+d.toString());
}
}
}
return new_deps;
}
static class CompareNames implements Comparator<Name> {
public int compare(Name a, Name b) {
return a.toString().compareTo(b.toString());
}
}
/**
* Convert the map from class names to their pubapi to a map
* from package names to their pubapi (which is the sorted concatenation
* of all the class pubapis)
*/
public Map<String,String> getPubapis() {
Map<String,String> publicApiPerPackage = new HashMap<>();
if (publicApiPerClass == null) return publicApiPerPackage;
Name[] keys = publicApiPerClass.keySet().toArray(new Name[0]);
Arrays.sort(keys, new CompareNames());
StringBuffer newPublicApi = new StringBuffer();
int i=0;
String prevPkg = "";
for (Name k : keys) {
String cn = k.toString();
String pn = "";
int dp = cn.lastIndexOf('.');
if (dp != -1) {
pn = cn.substring(0,dp);
}
if (!pn.equals(prevPkg)) {
if (!prevPkg.equals("")) {
// Add default module name ":"
publicApiPerPackage.put(":"+prevPkg, newPublicApi.toString());
}
newPublicApi = new StringBuffer();
prevPkg = pn;
}
newPublicApi.append(publicApiPerClass.get(k));
i++;
}
if (!prevPkg.equals(""))
publicApiPerPackage.put(":"+prevPkg, newPublicApi.toString());
return publicApiPerPackage;
}
/**
* Visit the api of a class and construct a pubapi string and
* store it into the pubapi_perclass map.
*/
public void visitPubapi(Element e) {
Name n = ((ClassSymbol)e).fullname;
Name p = ((ClassSymbol)e).packge().fullname;
StringBuffer sb = publicApiPerClass.get(n);
Assert.check(sb == null);
sb = new StringBuffer();
PubapiVisitor v = new PubapiVisitor(sb);
v.visit(e);
if (sb.length()>0) {
publicApiPerClass.put(n, sb);
}
explicitPackages.add(p);
}
/**
* Collect a dependency. curr_pkg is marked as depending on dep_pkg.
*/
public void collect(Name currPkg, Name depPkg) {
if (!currPkg.equals(depPkg)) {
Set<Name> theset = deps.get(currPkg);
if (theset==null) {
theset = new HashSet<>();
deps.put(currPkg, theset);
}
theset.add(depPkg);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,9 +22,33 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg14;
public class Cls14 {
public int[] getCls15() {
return null;
package com.sun.tools.sjavac.comp;
import javax.tools.FileObject;
import javax.tools.ForwardingFileObject;
import javax.tools.JavaFileManager.Location;
import com.sun.tools.javac.api.ClientCodeWrapper.Trusted;
@Trusted
public class FileObjectWithLocation<F extends FileObject> extends ForwardingFileObject<F> {
private final Location loc;
public FileObjectWithLocation(F delegate, Location loc) {
super(delegate);
this.loc = loc;
}
public Location getLocation() {
return loc;
}
public FileObject getDelegate() {
return fileObject;
}
public String toString() {
return "FileObjectWithLocation[" + fileObject + "]";
}
}

@ -0,0 +1,67 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import javax.tools.ForwardingJavaFileObject;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.ClientCodeWrapper.Trusted;
@Trusted
public class JavaFileObjectWithLocation<F extends JavaFileObject> extends ForwardingJavaFileObject<F> {
private final Location loc;
public JavaFileObjectWithLocation(F delegate, Location loc) {
super(delegate);
this.loc = loc;
}
public Location getLocation() {
return loc;
}
public F getDelegate() {
return fileObject;
}
public String toString() {
return "JavaFileObjectWithLocation[loc: " + loc + ", " + fileObject + "]";
}
@Override
public int hashCode() {
return loc.hashCode() ^ fileObject.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof JavaFileObjectWithLocation))
return false;
JavaFileObjectWithLocation<?> other = (JavaFileObjectWithLocation<?>) obj;
return loc.equals(other.loc) && fileObject.equals(other.fileObject);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,6 +41,7 @@ import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.Name;
import com.sun.tools.sjavac.Log;
public class PathAndPackageVerifier implements TaskListener {
@ -50,30 +51,37 @@ public class PathAndPackageVerifier implements TaskListener {
@Override
@DefinedBy(Api.COMPILER_TREE)
public void started(TaskEvent e) {
public void finished(TaskEvent e) {
if (e.getKind() == TaskEvent.Kind.ANALYZE) {
CompilationUnitTree cu = e.getCompilationUnit();
if (cu == null)
return;
JavaFileObject jfo = cu.getSourceFile();
if (jfo == null)
return; // No source file -> package doesn't matter
JCTree pkg = (JCTree) cu.getPackageName();
if (pkg == null)
return; // Default package. See JDK-8048144.
Path dir = Paths.get(jfo.toUri()).normalize().getParent();
if (!checkPathAndPackage(dir, pkg))
misplacedCompilationUnits.add(cu);
}
if (e.getKind() == TaskEvent.Kind.COMPILATION) {
for (CompilationUnitTree cu : misplacedCompilationUnits) {
Log.error("Misplaced compilation unit.");
Log.error(" Directory: " + Paths.get(cu.getSourceFile().toUri()).getParent());
Log.error(" Package: " + cu.getPackageName());
}
}
}
@Override
@DefinedBy(Api.COMPILER_TREE)
public void finished(TaskEvent e) {
if (e.getKind() != TaskEvent.Kind.ANALYZE)
return;
CompilationUnitTree cu = e.getCompilationUnit();
if (cu == null)
return;
JavaFileObject jfo = cu.getSourceFile();
if (jfo == null)
return; // No source file -> package doesn't matter
JCTree pkg = (JCTree) cu.getPackageName();
if (pkg == null)
return; // Default package. See JDK-8048144.
Path dir = Paths.get(jfo.toUri()).normalize().getParent();
if (!checkPathAndPackage(dir, pkg))
misplacedCompilationUnits.add(cu);
public boolean errorsDiscovered() {
return misplacedCompilationUnits.size() > 0;
}
/* Returns true if dir matches pkgName.
@ -94,10 +102,6 @@ public class PathAndPackageVerifier implements TaskListener {
return !pkgIter.hasNext(); /*&& !pathIter.hasNext() See JDK-8059598 */
}
public Set<CompilationUnitTree> getMisplacedCompilationUnits() {
return misplacedCompilationUnits;
}
/* Iterates over the names of the parents of the given path:
* Example: dir1/dir2/dir3 results in dir3 -> dir2 -> dir1
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,12 +29,9 @@ import java.net.URI;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.server.CompilationResult;
@ -58,28 +55,13 @@ public class PooledSjavac implements Sjavac {
public PooledSjavac(Sjavac delegate, int poolsize) {
Objects.requireNonNull(delegate);
this.delegate = delegate;
pool = Executors.newFixedThreadPool(poolsize, new ThreadFactory() {
AtomicInteger count = new AtomicInteger();
@Override
public Thread newThread(Runnable runnable) {
String cls = PooledSjavac.class.getSimpleName();
int num = count.incrementAndGet();
Thread t = new Thread(runnable, cls + "-" + num);
t.setDaemon(true);
return t;
}
});
pool = Executors.newFixedThreadPool(poolsize);
}
@Override
public SysInfo getSysInfo() {
try {
return pool.submit(new Callable<SysInfo>() {
@Override
public SysInfo call() throws Exception {
return delegate.getSysInfo();
}
}).get();
return pool.submit(() -> delegate.getSysInfo()).get();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error during getSysInfo", e);
@ -94,16 +76,13 @@ public class PooledSjavac implements Sjavac {
final Set<URI> sourcesToCompile,
final Set<URI> visibleSources) {
try {
return pool.submit(new Callable<CompilationResult>() {
@Override
public CompilationResult call() throws Exception {
return delegate.compile(protocolId,
invocationId,
args,
explicitSources,
sourcesToCompile,
visibleSources);
}
return pool.submit(() -> {
return delegate.compile(protocolId,
invocationId,
args,
explicitSources,
sourcesToCompile,
visibleSources);
}).get();
} catch (Exception e) {
e.printStackTrace();
@ -113,6 +92,7 @@ public class PooledSjavac implements Sjavac {
@Override
public void shutdown() {
Log.debug("Shutting down PooledSjavac");
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
@ -122,8 +102,6 @@ public class PooledSjavac implements Sjavac {
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
Log.error("ThreadPool did not terminate");
}
// Grace period for thread termination
Thread.sleep(1000);
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();

@ -0,0 +1,108 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* Utility class containing public API information.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class PubAPIs {
protected static final Context.Key<PubAPIs> pubApisKey = new Context.Key<>();
// The log to be used for error reporting.
protected Log log;
// Map from a class name to its public api.
// Will the Name encode the module in the future?
// If not, this will have to change to map from Module+Name to public api.
protected Map<ClassSymbol, PubApi> publicApiPerClass = new HashMap<>();
public static PubAPIs instance(Context context) {
PubAPIs instance = context.get(pubApisKey);
if (instance == null)
instance = new PubAPIs(context);
return instance;
}
private PubAPIs(Context context) {
context.put(pubApisKey, this);
log = Log.instance(context);
}
/**
* Convert the map from class names to their pubapi to a map
* from package names to their pubapi.
*/
public Map<String, PubApi> getPubapis(Collection<JavaFileObject> explicitJFOs, boolean explicits) {
// Maps ":java.lang" to a package level pub api (with only types on top level)
Map<String, PubApi> result = new HashMap<>();
for (ClassSymbol cs : publicApiPerClass.keySet()) {
boolean amongExplicits = explicitJFOs.contains(cs.sourcefile);
if (explicits != amongExplicits)
continue;
String pkg = ":" + cs.packge().fullname;
PubApi currentPubApi = result.getOrDefault(pkg, new PubApi());
result.put(pkg, PubApi.mergeTypes(currentPubApi, publicApiPerClass.get(cs)));
}
return result;
}
/**
* Visit the api of a class and construct a pubapi and
* store it into the pubapi_perclass map.
*/
@SuppressWarnings("deprecation")
public void visitPubapi(Element e) {
// Skip anonymous classes for now
if (e == null)
return;
PubapiVisitor v = new PubapiVisitor();
v.visit(e);
publicApiPerClass.put((ClassSymbol) e, v.getCollectedPubApi());
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,17 +25,28 @@
package com.sun.tools.sjavac.comp;
import java.util.Iterator;
import static javax.lang.model.element.Modifier.PRIVATE;
import java.util.List;
import javax.lang.model.element.Modifier;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementScanner9;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.pubapi.PubApiTypeParam;
import com.sun.tools.sjavac.pubapi.PubMethod;
import com.sun.tools.sjavac.pubapi.PubType;
import com.sun.tools.sjavac.pubapi.PubVar;
import com.sun.tools.sjavac.pubapi.TypeDesc;
/** Utility class that constructs a textual representation
* of the public api of a class.
@ -47,40 +58,67 @@ import com.sun.tools.javac.util.DefinedBy.Api;
*/
public class PubapiVisitor extends ElementScanner9<Void, Void> {
StringBuffer sb;
// Important that it is 1! Part of protocol over wire, silly yes.
// Fix please.
int indent = 1;
private PubApi collectedApi = new PubApi();
public PubapiVisitor(StringBuffer sb) {
this.sb = sb;
}
String depth(int l) {
return " ".substring(0, l);
private boolean isNonPrivate(Element e) {
return !e.getModifiers().contains(PRIVATE);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Void visitType(TypeElement e, Void p) {
if (e.getModifiers().contains(Modifier.PUBLIC)
|| e.getModifiers().contains(Modifier.PROTECTED))
{
sb.append(depth(indent) + "TYPE " + e.getQualifiedName() + "\n");
indent += 2;
Void v = super.visitType(e, p);
indent -= 2;
return v;
if (isNonPrivate(e)) {
PubApi prevApi = collectedApi;
collectedApi = new PubApi();
super.visitType(e, p);
if (!isAnonymous(e)) {
String name = ((ClassSymbol) e).flatname.toString();
PubType t = new PubType(e.getModifiers(),
name,
//e.getQualifiedName().toString(),
collectedApi);
prevApi.types.put(t.fqName, t);
}
collectedApi = prevApi;
}
return null;
}
private boolean isAnonymous(TypeElement e) {
return e.getQualifiedName().length() == 0;
}
private static String encodeChar(int c) {
return String.format("\\u%04x", c);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Void visitVariable(VariableElement e, Void p) {
if (e.getModifiers().contains(Modifier.PUBLIC)
|| e.getModifiers().contains(Modifier.PROTECTED)) {
sb.append(depth(indent)).append("VAR ")
.append(makeVariableString(e)).append("\n");
if (isNonPrivate(e)) {
Object constVal = e.getConstantValue();
String constValStr = null;
// TODO: This doesn't seem to be entirely accurate. What if I change
// from, say, 0 to 0L? (And the field is public final static so that
// it could get inlined.)
if (constVal != null) {
if (e.asType().toString().equals("char")) {
// What type is 'value'? Is it already a char?
char c = constVal.toString().charAt(0);
constValStr = "'" + encodeChar(c) + "'";
} else {
constValStr = constVal.toString()
.chars()
.mapToObj(PubapiVisitor::encodeChar)
.collect(Collectors.joining("", "\"", "\""));
}
}
PubVar v = new PubVar(e.getModifiers(),
TypeDesc.fromType(e.asType()),
e.toString(),
constValStr);
collectedApi.variables.put(v.identifier, v);
}
// Safe to not recurse here, because the only thing
// to visit here is the constructor of a variable declaration.
// If it happens to contain an anonymous inner class (which it might)
@ -91,70 +129,38 @@ public class PubapiVisitor extends ElementScanner9<Void, Void> {
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Void visitExecutable(ExecutableElement e, Void p) {
if (e.getModifiers().contains(Modifier.PUBLIC)
|| e.getModifiers().contains(Modifier.PROTECTED)) {
sb.append(depth(indent)).append("METHOD ")
.append(makeMethodString(e)).append("\n");
if (isNonPrivate(e)) {
PubMethod m = new PubMethod(e.getModifiers(),
getTypeParameters(e.getTypeParameters()),
TypeDesc.fromType(e.getReturnType()),
e.getSimpleName().toString(),
getTypeDescs(getParamTypes(e)),
getTypeDescs(e.getThrownTypes()));
collectedApi.methods.put(m.asSignatureString(), m);
}
return null;
}
/**
* Creates a String representation of a method element with everything
* necessary to track all public aspects of it in an API.
* @param e Element to create String for.
* @return String representation of element.
*/
protected String makeMethodString(ExecutableElement e) {
StringBuilder result = new StringBuilder();
for (Modifier modifier : e.getModifiers()) {
result.append(modifier.toString());
result.append(" ");
}
result.append(e.getReturnType().toString());
result.append(" ");
result.append(e.toString());
List<? extends TypeMirror> thrownTypes = e.getThrownTypes();
if (!thrownTypes.isEmpty()) {
result.append(" throws ");
for (Iterator<? extends TypeMirror> iterator = thrownTypes
.iterator(); iterator.hasNext();) {
TypeMirror typeMirror = iterator.next();
result.append(typeMirror.toString());
if (iterator.hasNext()) {
result.append(", ");
}
}
}
return result.toString();
private List<PubApiTypeParam> getTypeParameters(List<? extends TypeParameterElement> elements) {
return elements.stream()
.map(e -> new PubApiTypeParam(e.getSimpleName().toString(), getTypeDescs(e.getBounds())))
.collect(Collectors.toList());
}
/**
* Creates a String representation of a variable element with everything
* necessary to track all public aspects of it in an API.
* @param e Element to create String for.
* @return String representation of element.
*/
protected String makeVariableString(VariableElement e) {
StringBuilder result = new StringBuilder();
for (Modifier modifier : e.getModifiers()) {
result.append(modifier.toString());
result.append(" ");
}
result.append(e.asType().toString());
result.append(" ");
result.append(e.toString());
Object value = e.getConstantValue();
if (value != null) {
result.append(" = ");
if (e.asType().toString().equals("char")) {
int v = (int)value.toString().charAt(0);
result.append("'\\u"+Integer.toString(v,16)+"'");
} else {
result.append(value.toString());
}
}
return result.toString();
private List<TypeMirror> getParamTypes(ExecutableElement e) {
return e.getParameters()
.stream()
.map(VariableElement::asType)
.collect(Collectors.toList());
}
private List<TypeDesc> getTypeDescs(List<? extends TypeMirror> list) {
return list.stream()
.map(TypeDesc::fromType)
.collect(Collectors.toList());
}
public PubApi getCollectedPubApi() {
return collectedApi;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,24 +29,25 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Dependencies;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Options;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.comp.dependencies.DependencyCollector;
import com.sun.tools.sjavac.comp.dependencies.NewDependencyCollector;
import com.sun.tools.sjavac.comp.dependencies.PublicApiCollector;
import com.sun.tools.sjavac.server.CompilationResult;
import com.sun.tools.sjavac.server.Sjavac;
@ -76,86 +77,79 @@ public class SjavacImpl implements Sjavac {
List<File> explicitSources,
Set<URI> sourcesToCompile,
Set<URI> visibleSources) {
JavacTool compiler = JavacTool.create();
try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
SmartFileManager smartFileManager = new SmartFileManager(fileManager);
JavacTool compiler = (JavacTool) ToolProvider.getSystemJavaCompiler();
try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
SmartFileManager sfm = new SmartFileManager(fm);
Context context = new Context();
// Now setup the actual compilation....
Dependencies.GraphDependencies.preRegister(context);
// Now setup the actual compilation
CompilationResult compilationResult = new CompilationResult(0);
// First deal with explicit source files on cmdline and in at file.
ListBuffer<JavaFileObject> compilationUnits = new ListBuffer<>();
for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(explicitSources)) {
compilationUnits.append(i);
// First deal with explicit source files on cmdline and in at file
ListBuffer<JavaFileObject> explicitJFOs = new ListBuffer<>();
for (JavaFileObject jfo : fm.getJavaFileObjectsFromFiles(explicitSources)) {
explicitJFOs.append(SmartFileManager.locWrap(jfo, StandardLocation.SOURCE_PATH));
}
// Now deal with sources supplied as source_to_compile.
// Now deal with sources supplied as source_to_compile
ListBuffer<File> sourcesToCompileFiles = new ListBuffer<>();
for (URI u : sourcesToCompile) {
for (URI u : sourcesToCompile)
sourcesToCompileFiles.append(new File(u));
}
for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(sourcesToCompileFiles)) {
compilationUnits.append(i);
}
// Create a new logger.
for (JavaFileObject jfo : fm.getJavaFileObjectsFromFiles(sourcesToCompileFiles))
explicitJFOs.append(SmartFileManager.locWrap(jfo, StandardLocation.SOURCE_PATH));
// Create a new logger
StringWriter stdoutLog = new StringWriter();
StringWriter stderrLog = new StringWriter();
PrintWriter stdout = new PrintWriter(stdoutLog);
PrintWriter stderr = new PrintWriter(stderrLog);
com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
DependencyCollector depsCollector = new DependencyCollector();
PublicApiCollector pubApiCollector = new PublicApiCollector();
PublicApiCollector pubApiCollector = new PublicApiCollector(context, explicitJFOs);
PathAndPackageVerifier papVerifier = new PathAndPackageVerifier();
NewDependencyCollector depsCollector = new NewDependencyCollector(context, explicitJFOs);
try {
if (compilationUnits.size() > 0) {
smartFileManager.setVisibleSources(visibleSources);
smartFileManager.cleanArtifacts();
smartFileManager.setLog(stdout);
if (explicitJFOs.size() > 0) {
sfm.setVisibleSources(visibleSources);
sfm.cleanArtifacts();
sfm.setLog(stdout);
// Do the compilation!
JavacTaskImpl task =
(JavacTaskImpl) compiler.getTask(stderr,
smartFileManager,
sfm,
null,
Arrays.asList(args),
null,
compilationUnits,
explicitJFOs,
context);
smartFileManager.setSymbolFileEnabled(!Options.instance(context).isSet("ignore.symbol.file"));
sfm.setSymbolFileEnabled(!Options.instance(context).isSet("ignore.symbol.file"));
task.addTaskListener(depsCollector);
task.addTaskListener(pubApiCollector);
task.addTaskListener(papVerifier);
logJavacInvocation(args);
rc = task.doCall();
smartFileManager.flush();
Log.debug("javac returned with code " + rc);
sfm.flush();
}
} catch (Exception e) {
Log.error(Util.getStackTrace(e));
stderrLog.append(Util.getStackTrace(e));
rc = com.sun.tools.javac.main.Main.Result.ERROR;
}
compilationResult.packageArtifacts = smartFileManager.getPackageArtifacts();
compilationResult.packageArtifacts = sfm.getPackageArtifacts();
Dependencies deps = Dependencies.instance(context);
for (PackageSymbol from : depsCollector.getSourcePackages()) {
for (PackageSymbol to : depsCollector.getDependenciesForPkg(from))
deps.collect(from.fullname, to.fullname);
}
for (ClassSymbol cs : pubApiCollector.getClassSymbols())
deps.visitPubapi(cs);
if (papVerifier.getMisplacedCompilationUnits().size() > 0) {
for (CompilationUnitTree cu : papVerifier.getMisplacedCompilationUnits()) {
System.err.println("Misplaced compilation unit.");
System.err.println(" Directory: " + Paths.get(cu.getSourceFile().toUri()).getParent());
System.err.println(" Package: " + cu.getPackageName());
}
if (papVerifier.errorsDiscovered())
rc = com.sun.tools.javac.main.Main.Result.ERROR;
}
compilationResult.packageDependencies = deps.getDependencies();
compilationResult.packagePubapis = deps.getPubapis();
compilationResult.packageDependencies = depsCollector.getDependencies(false);
compilationResult.packageCpDependencies = depsCollector.getDependencies(true);
compilationResult.packagePubapis = pubApiCollector.getPubApis(true); // pubApis.getPubapis(explicitJFOs, true);
compilationResult.dependencyPubapis = pubApiCollector.getPubApis(false); // pubApis.getPubapis(explicitJFOs, false);
compilationResult.stdout = stdoutLog.toString();
compilationResult.stderr = stderrLog.toString();
compilationResult.returnCode = rc.exitCode;
@ -172,10 +166,22 @@ public class SjavacImpl implements Sjavac {
// ... maybe we should wait for any current request to finish?
}
@Override
public String serverSettings() {
return "";
}
private void logJavacInvocation(String[] args) {
Log.debug("Invoking javac with args");
Iterator<String> argIter = Arrays.asList(args).iterator();
while (argIter.hasNext()) {
String arg = argIter.next();
String line = " " + arg;
if (arg.matches("\\-(d|cp|classpath|sourcepath|source|target)")
&& argIter.hasNext()) {
line += " " + argIter.next();
}
Log.debug(line);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -91,6 +91,12 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
((JavacFileManager) fileManager).setSymbolFileEnabled(b);
}
@DefinedBy(Api.COMPILER)
public String inferBinaryName(Location location, JavaFileObject file) {
return super.inferBinaryName(location, locUnwrap(file));
}
public Map<String,Set<URI>> getPackageArtifacts() {
return packageArtifacts;
}
@ -100,10 +106,11 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
String packageName,
Set<Kind> kinds,
boolean recurse) throws IOException {
// TODO: Do this lazily by returning an iterable with a filtering Iterator
// Acquire the list of files.
Iterable<JavaFileObject> files = super.list(location, packageName, kinds, recurse);
if (visibleSources.isEmpty()) {
return files;
return locWrapMany(files, location);
}
// Now filter!
ListBuffer<JavaFileObject> filteredFiles = new ListBuffer<>();
@ -116,12 +123,8 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
filteredFiles.add(f);
}
}
return filteredFiles;
}
@Override @DefinedBy(Api.COMPILER)
public boolean hasLocation(Location location) {
return super.hasLocation(location);
return locWrapMany(filteredFiles, location);
}
@Override @DefinedBy(Api.COMPILER)
@ -129,6 +132,7 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
String className,
Kind kind) throws IOException {
JavaFileObject file = super.getJavaFileForInput(location, className, kind);
file = locWrap(file, location);
if (file == null || visibleSources.isEmpty()) {
return file;
}
@ -145,6 +149,7 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
Kind kind,
FileObject sibling) throws IOException {
JavaFileObject file = super.getJavaFileForOutput(location, className, kind, sibling);
file = locWrap(file, location);
if (file == null) return file;
int dp = className.lastIndexOf('.');
String pkg_name = "";
@ -162,6 +167,7 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
String packageName,
String relativeName) throws IOException {
FileObject file = super.getFileForInput(location, packageName, relativeName);
file = locWrap(file, location);
if (file == null || visibleSources.isEmpty()) {
return file;
}
@ -177,11 +183,12 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
String packageName,
String relativeName,
FileObject sibling) throws IOException {
FileObject file = super.getFileForOutput(location, packageName, relativeName, sibling);
FileObject superFile = super.getFileForOutput(location, packageName, relativeName, sibling);
FileObject file = locWrap(superFile, location);
if (file == null) return file;
if (location.equals(StandardLocation.NATIVE_HEADER_OUTPUT) &&
file instanceof JavaFileObject) {
file = new SmartFileObject((JavaFileObject)file, stdout);
if (location.equals(StandardLocation.NATIVE_HEADER_OUTPUT) && superFile instanceof JavaFileObject) {
file = new SmartFileObject((JavaFileObject) file, stdout);
packageName = ":" + packageNameFromFileName(relativeName);
}
if (packageName.equals("")) {
@ -191,7 +198,7 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
return file;
}
private String packageNameFromFileName(String fn) {
private static String packageNameFromFileName(String fn) {
StringBuilder sb = new StringBuilder();
int p = fn.indexOf('_'), pp = 0;
while (p != -1) {
@ -204,16 +211,6 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
return sb.toString();
}
@Override @DefinedBy(Api.COMPILER)
public void flush() throws IOException {
super.flush();
}
@Override @DefinedBy(Api.COMPILER)
public void close() throws IOException {
super.close();
}
void addArtifact(String pkgName, URI art) {
Set<URI> s = packageArtifacts.get(pkgName);
if (s == null) {
@ -222,4 +219,50 @@ public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager>
}
s.add(art);
}
public static JavaFileObject locWrap(JavaFileObject jfo, Location loc) {
// From sjavac's perspective platform classes are not interesting and
// there is no need to track the location for these file objects.
// Also, there exists some jfo instanceof checks which breaks if
// the jfos for platform classes are wrapped.
if (loc == StandardLocation.PLATFORM_CLASS_PATH)
return jfo;
return jfo == null ? null : new JavaFileObjectWithLocation<>(jfo, loc);
}
private static FileObject locWrap(FileObject fo, Location loc) {
if (fo instanceof JavaFileObject)
return locWrap((JavaFileObject) fo, loc);
return fo == null ? null : new FileObjectWithLocation<>(fo, loc);
}
@DefinedBy(Api.COMPILER)
@Override
public boolean isSameFile(FileObject a, FileObject b) {
return super.isSameFile(locUnwrap(a), locUnwrap(b));
}
private static ListBuffer<JavaFileObject> locWrapMany(Iterable<JavaFileObject> jfos,
Location loc) {
ListBuffer<JavaFileObject> locWrapped = new ListBuffer<>();
for (JavaFileObject f : jfos)
locWrapped.add(locWrap(f, loc));
return locWrapped;
}
private static FileObject locUnwrap(FileObject fo) {
if (fo instanceof FileObjectWithLocation<?>)
return ((FileObjectWithLocation<?>) fo).getDelegate();
if (fo instanceof JavaFileObjectWithLocation<?>)
return ((JavaFileObjectWithLocation<?>) fo).getDelegate();
return fo;
}
private static JavaFileObject locUnwrap(JavaFileObject fo) {
if (fo instanceof JavaFileObjectWithLocation<?>)
return ((JavaFileObjectWithLocation<?>) fo).getDelegate();
return fo;
}
}

@ -1,33 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp.dependencies;
import java.util.Set;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
interface Dependency {
Set<PackageSymbol> getPackages();
}

@ -1,76 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp.dependencies;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.sjavac.Util;
public class DependencyCollector implements TaskListener {
Map<PackageSymbol, Set<PackageSymbol>> collectedDependencies = new HashMap<>();
@Override
@DefinedBy(Api.COMPILER_TREE)
public void started(TaskEvent e) {
}
@Override
@DefinedBy(Api.COMPILER_TREE)
public void finished(TaskEvent e) {
if (e.getKind() == TaskEvent.Kind.ANALYZE) {
JCCompilationUnit cu = (JCCompilationUnit) e.getCompilationUnit();
PackageSymbol thisPkg = cu.packge;
if (thisPkg == null) {
// Compilation unit in default package. See JDK-8048144.
return;
}
DependencyScanner ds = new DependencyScanner();
cu.accept(ds);
Set<PackageSymbol> pkgDeps = ds.getResult()
.stream()
.flatMap(dep -> dep.getPackages().stream())
.collect(Collectors.toSet());
collectedDependencies.merge(thisPkg, pkgDeps, Util::union);
}
}
public Set<PackageSymbol> getSourcePackages() {
return collectedDependencies.keySet();
}
public Set<PackageSymbol> getDependenciesForPkg(PackageSymbol ps) {
return collectedDependencies.get(ps);
}
}

@ -1,84 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp.dependencies;
import java.util.HashSet;
import java.util.Set;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.TreeScanner;
class DependencyScanner extends TreeScanner {
public final Set<Dependency> dependencies = new HashSet<>();
private boolean isValidDependency(Type t) {
if (t == null || t.isPrimitiveOrVoid() || t.isErroneous())
return false;
TypeTag tag = t.getTag();
return tag != TypeTag.PACKAGE
&& tag != TypeTag.METHOD
&& tag != TypeTag.ARRAY
&& tag != TypeTag.TYPEVAR;
}
@Override
public void visitIdent(JCIdent tree) {
if (isValidDependency(tree.type))
dependencies.add(new TypeAndSupertypesDependency(tree.type.tsym));
super.visitIdent(tree);
}
@Override
public void visitSelect(JCFieldAccess tree) {
if (tree.getIdentifier().contentEquals("*")) {
Symbol sym = tree.selected instanceof JCIdent ? ((JCIdent) tree.selected).sym
: ((JCFieldAccess) tree.selected).sym;
if (sym instanceof ClassSymbol) {
ClassSymbol clsSym = (ClassSymbol) sym;
dependencies.add(new TypeAndSupertypesDependency(clsSym.type.tsym));
} else {
dependencies.add(new PackageDependency((PackageSymbol) sym));
}
} else if (tree.type != null && tree.type.hasTag(TypeTag.METHOD)) { // Method call? Depend on the result (even though we never access it elsewhere)
Type retType = tree.type.getReturnType();
if (isValidDependency(retType))
dependencies.add(new TypeAndSupertypesDependency(retType.tsym));
} else if (isValidDependency(tree.type)) {
dependencies.add(new TypeAndSupertypesDependency(tree.type.tsym));
}
super.visitSelect(tree);
}
public Set<Dependency> getResult() {
return dependencies;
}
}

@ -0,0 +1,158 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp.dependencies;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.Dependencies.GraphDependencies;
import com.sun.tools.javac.util.Dependencies.GraphDependencies.CompletionNode;
import com.sun.tools.javac.util.GraphUtils.Node;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.comp.JavaFileObjectWithLocation;
import com.sun.tools.sjavac.comp.PubAPIs;
public class NewDependencyCollector implements TaskListener {
private final Context context;
private final Collection<JavaFileObject> explicitJFOs;
private Map<String, Map<String, Set<String>>> deps;
private Map<String, Map<String, Set<String>>> cpDeps;
public NewDependencyCollector(Context context,
Collection<JavaFileObject> explicitJFOs) {
this.context = context;
this.explicitJFOs = explicitJFOs;
}
@Override
@DefinedBy(Api.COMPILER_TREE)
public void finished(TaskEvent e) {
if (e.getKind() == TaskEvent.Kind.COMPILATION) {
collectPubApisOfDependencies(context, explicitJFOs);
deps = getDependencies(context, explicitJFOs, false);
cpDeps = getDependencies(context, explicitJFOs, true);
}
}
public Map<String, Map<String, Set<String>>> getDependencies(boolean cp) {
return cp ? cpDeps : deps;
}
private Set<CompletionNode> getDependencyNodes(Context context,
Collection<JavaFileObject> explicitJFOs,
boolean explicits) {
GraphDependencies deps = (GraphDependencies) GraphDependencies.instance(context);
return deps.getNodes()
.stream()
.filter(n -> n instanceof CompletionNode)
.map(n -> (CompletionNode) n)
.filter(n -> n.getClassSymbol().fullname != null)
.filter(n -> explicits == explicitJFOs.contains(n.getClassSymbol().classfile))
.collect(Collectors.toSet());
}
private void collectPubApisOfDependencies(Context context,
Collection<JavaFileObject> explicitJFOs) {
PubAPIs pubApis = PubAPIs.instance(context);
for (CompletionNode cDepNode : getDependencyNodes(context, explicitJFOs, false)) {
ClassSymbol cs = cDepNode.getClassSymbol().outermostClass();
Location loc = getLocationOf(cs);
// We're completely ignorant of PLATFORM_CLASS_PATH classes
if (loc == StandardLocation.CLASS_PATH || loc == StandardLocation.SOURCE_PATH)
pubApis.visitPubapi(cs);
}
}
private Location getLocationOf(ClassSymbol cs) {
JavaFileObject jfo = cs.outermostClass().classfile;
if (jfo instanceof JavaFileObjectWithLocation) {
return ((JavaFileObjectWithLocation<?>) jfo).getLocation();
}
// jfo is most likely on PLATFORM_CLASS_PATH.
// See notes in SmartFileManager::locWrap
return null;
}
// :Package -> fully qualified class name [from] -> set of fully qualified class names [to]
private Map<String, Map<String, Set<String>>> getDependencies(Context context,
Collection<JavaFileObject> explicitJFOs,
boolean cp) {
Map<String, Map<String, Set<String>>> result = new HashMap<>();
for (CompletionNode cnode : getDependencyNodes(context, explicitJFOs, true)) {
String fqDep = cnode.getClassSymbol().outermostClass().flatname.toString();
String depPkg = Util.pkgNameOfClassName(fqDep);
Map<String, Set<String>> depsForThisClass = result.get(depPkg);
if (depsForThisClass == null)
result.put(depPkg, depsForThisClass = new HashMap<>());
for (Node<?,?> depNode : cnode.getDependenciesByKind(GraphDependencies.Node.DependencyKind.REQUIRES)) {
boolean isCompletionNode = depNode instanceof CompletionNode;
if (isCompletionNode) {
CompletionNode cDepNode = (CompletionNode) depNode;
if (cDepNode == cnode)
continue;
if (cDepNode.getClassSymbol().fullname == null) // Anonymous class
continue;
Location depLoc = getLocationOf(cDepNode.getClassSymbol());
boolean relevant = (cp && depLoc == StandardLocation.CLASS_PATH)
|| (!cp && depLoc == StandardLocation.SOURCE_PATH);
if (!relevant)
continue;
Set<String> fqDeps = depsForThisClass.get(fqDep);
if (fqDeps == null)
depsForThisClass.put(fqDep, fqDeps = new HashSet<>());
fqDeps.add(cDepNode.getClassSymbol().outermostClass().flatname.toString());
}
}
}
return result;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,40 +22,91 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp.dependencies;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.tools.JavaFileObject;
import com.sun.source.tree.Tree;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.comp.PubAPIs;
import com.sun.tools.sjavac.pubapi.PubApi;
public class PublicApiCollector implements TaskListener {
final Set<ClassSymbol> classSymbols = new HashSet<>();
private Context context;
private final Set<ClassSymbol> classSymbols = new HashSet<>();
private final Collection<JavaFileObject> explicitJFOs;
@Override
@DefinedBy(Api.COMPILER_TREE)
public void started(TaskEvent e) {
// Result collected upon compilation task finished
private Map<String, PubApi> explicitPubApis;
private Map<String, PubApi> nonExplicitPubApis;
public PublicApiCollector(Context context,
Collection<JavaFileObject> explicitJFOs) {
this.context = context;
this.explicitJFOs = explicitJFOs;
}
@Override
@DefinedBy(Api.COMPILER_TREE)
public void finished(TaskEvent e) {
if (e.getKind() == TaskEvent.Kind.ANALYZE) {
for (Tree t : e.getCompilationUnit().getTypeDecls()) {
if (t instanceof JCClassDecl) // Can also be a JCSkip
classSymbols.add(((JCClassDecl) t).sym);
}
switch (e.getKind()) {
case ANALYZE:
collectClassSymbols((JCCompilationUnit) e.getCompilationUnit());
break;
case COMPILATION:
Log.debug("Compilation finished");
Log.debug("Extracting pub APIs for the following symbols:");
for (ClassSymbol cs : classSymbols)
Log.debug(" " + cs.fullname);
extractPubApis();
// Save result for later retrieval. (Important that we do this
// before we return from this method, because we may not access
// symbols after compilation is finished.)
PubAPIs pa = PubAPIs.instance(context);
explicitPubApis = pa.getPubapis(explicitJFOs, true);
nonExplicitPubApis = pa.getPubapis(explicitJFOs, false);
Log.debug("done");
break;
}
}
public Set<ClassSymbol> getClassSymbols() {
return classSymbols;
private void collectClassSymbols(JCCompilationUnit cu) {
for (Tree t : cu.getTypeDecls()) {
if (t instanceof JCClassDecl) // Can also be a JCSkip
classSymbols.add(((JCClassDecl) t).sym);
}
}
private void extractPubApis() {
// To handle incremental builds (subsequent sjavac invocations) we need
// to keep track of the public API of what we depend upon.
//
// During the recompilation loop (within a single sjavac invocation) we
// need to keep track of public API of what we're compiling to decide if
// any dependants needs to be tainted.
PubAPIs pubApis = PubAPIs.instance(context);
classSymbols.forEach(pubApis::visitPubapi);
}
public Map<String, PubApi> getPubApis(boolean explicit) {
return explicit ? explicitPubApis : nonExplicitPubApis;
}
}

@ -1,75 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp.dependencies;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Type;
import static com.sun.tools.javac.code.Kinds.Kind.*;
public class TypeAndSupertypesDependency implements Dependency {
protected TypeSymbol type;
public TypeAndSupertypesDependency(TypeSymbol type) {
this.type = Objects.requireNonNull(type);
}
private Set<TypeSymbol> allSupertypes(TypeSymbol t) {
if (t == null)
return Collections.emptySet();
Set<TypeSymbol> result = new HashSet<>();
result.add(t);
if (t instanceof ClassSymbol) {
ClassSymbol cs = (ClassSymbol) t;
result.addAll(allSupertypes(cs.getSuperclass().tsym));
for (Type it : cs.getInterfaces())
result.addAll(allSupertypes(it.tsym));
}
return result;
}
@Override
public Set<PackageSymbol> getPackages() {
if (type.kind == ERR)
return Collections.emptySet();
if (type instanceof ClassSymbol) {
return allSupertypes(type).stream()
.map(TypeSymbol::packge)
.collect(Collectors.toSet());
}
throw new AssertionError("Could not get package name for " + type);
}
}

@ -316,9 +316,19 @@ public class Options {
args.add(concatenateSourceLocations(classSearchPaths));
}
// Enable dependency generation
args.add("-XDcompletionDeps=source,class");
// This can't be anything but 'none'. Enforced by sjavac main method.
args.add("-implicit:" + implicitPolicy);
// If this option is not used, Object for instance is erroneously
// picked up from PLATFORM_CLASS_PATH instead of CLASS_PATH.
//
// Discussing this further led to the decision of letting bootclasspath
// be a dummy (empty) directory when building the JDK.
//args.add("-XXuserPathsFirst");
// Append javac-options (i.e. pass through options not recognized by
// sjavac to javac.)
args.addAll(javacArgs);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,20 +22,33 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.comp.dependencies;
package com.sun.tools.sjavac.pubapi;
import java.util.Collections;
import java.util.Set;
import java.io.Serializable;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import javax.lang.model.type.TypeKind;
public class PackageDependency implements Dependency {
PackageSymbol ps;
public PackageDependency(PackageSymbol ps) {
this.ps = ps;
public class ArrayTypeDesc extends TypeDesc implements Serializable {
private static final long serialVersionUID = -1177329549163314996L;
TypeDesc compTypeDesc;
public ArrayTypeDesc(TypeDesc compTypeDesc) {
super(TypeKind.ARRAY);
this.compTypeDesc = compTypeDesc;
}
@Override
public Set<PackageSymbol> getPackages() {
return Collections.singleton(ps);
public boolean equals(Object obj) {
if (!super.equals(obj))
return false;
return compTypeDesc.equals(((ArrayTypeDesc) obj).compTypeDesc);
}
@Override
public int hashCode() {
return super.hashCode() ^ compTypeDesc.hashCode();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,9 +22,28 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg13;
public class Cls13 {
public pkg14.Cls14 getCls14() {
return null;
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import javax.lang.model.type.TypeKind;
import com.sun.tools.javac.util.StringUtils;
public class PrimitiveTypeDesc extends TypeDesc implements Serializable {
private static final long serialVersionUID = 6051065543149129106L;
public PrimitiveTypeDesc(TypeKind typeKind) {
super(typeKind);
if (!typeKind.isPrimitive() && typeKind != TypeKind.VOID)
throw new IllegalArgumentException("Only primitives or void accepted");
}
// This class has no fields, so the inherited hashCode and equals should do fine.
@Override
public String toString() {
return StringUtils.toLowerCase(typeKind.toString());
}
}

@ -0,0 +1,434 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.pubapi;
import static com.sun.tools.sjavac.Util.union;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.lang.model.element.Modifier;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.StringUtils;
public class PubApi implements Serializable {
private static final long serialVersionUID = 5926627347801986850L;
// Used to have Set here. Problem is that the objects are mutated during
// javac_state loading, causing them to change hash codes. We could probably
// change back to Set once javac_state loading is cleaned up.
public final Map<String, PubType> types = new HashMap<>();
public final Map<String, PubVar> variables = new HashMap<>();
public final Map<String, PubMethod> methods = new HashMap<>();
public PubApi() {
}
public PubApi(Collection<PubType> types,
Collection<PubVar> variables,
Collection<PubMethod> methods) {
types.forEach(this::addPubType);
variables.forEach(this::addPubVar);
methods.forEach(this::addPubMethod);
}
// Currently this is implemented as equality. This is far from optimal. It
// should preferably make sure that all previous methods are still available
// and no abstract methods are added. It should also be aware of inheritance
// of course.
public boolean isBackwardCompatibleWith(PubApi older) {
return equals(older);
}
private static String typeLine(PubType type) {
if (type.fqName.isEmpty())
throw new RuntimeException("empty class name " + type);
return String.format("TYPE %s%s", asString(type.modifiers), type.fqName);
}
private static String varLine(PubVar var) {
return String.format("VAR %s%s %s%s",
asString(var.modifiers),
TypeDesc.encodeAsString(var.type),
var.identifier,
var.getConstValue().map(v -> " = " + v).orElse(""));
}
private static String methodLine(PubMethod method) {
return String.format("METHOD %s%s%s %s(%s)%s",
asString(method.modifiers),
method.typeParams.isEmpty() ? "" : ("<" + method.typeParams.stream().map(PubApiTypeParam::asString).collect(Collectors.joining(",")) + "> "),
TypeDesc.encodeAsString(method.returnType),
method.identifier,
commaSeparated(method.paramTypes),
method.throwDecls.isEmpty()
? ""
: " throws " + commaSeparated(method.throwDecls));
}
public List<String> asListOfStrings() {
List<String> lines = new ArrayList<>();
// Types
types.values()
.stream()
.sorted(Comparator.comparing(PubApi::typeLine))
.forEach(type -> {
lines.add(typeLine(type));
for (String subline : type.pubApi.asListOfStrings())
lines.add(" " + subline);
});
// Variables
variables.values()
.stream()
.map(PubApi::varLine)
.sorted()
.forEach(lines::add);
// Methods
methods.values()
.stream()
.map(PubApi::methodLine)
.sorted()
.forEach(lines::add);
return lines;
}
@Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
PubApi other = (PubApi) obj;
return types.equals(other.types)
&& variables.equals(other.variables)
&& methods.equals(other.methods);
}
@Override
public int hashCode() {
return types.keySet().hashCode()
^ variables.keySet().hashCode()
^ methods.keySet().hashCode();
}
private static String commaSeparated(List<TypeDesc> typeDescs) {
return typeDescs.stream()
.map(TypeDesc::encodeAsString)
.collect(Collectors.joining(","));
}
// Create space separated list of modifiers (with a trailing space)
private static String asString(Set<Modifier> modifiers) {
return modifiers.stream()
.map(mod -> mod + " ")
.sorted()
.collect(Collectors.joining());
}
// Used to combine class PubApis to package level PubApis
public static PubApi mergeTypes(PubApi api1, PubApi api2) {
Assert.check(api1.methods.isEmpty(), "Can only merge types.");
Assert.check(api2.methods.isEmpty(), "Can only merge types.");
Assert.check(api1.variables.isEmpty(), "Can only merge types.");
Assert.check(api2.variables.isEmpty(), "Can only merge types.");
PubApi merged = new PubApi();
merged.types.putAll(api1.types);
merged.types.putAll(api2.types);
return merged;
}
// Used for line-by-line parsing
private PubType lastInsertedType = null;
private final static String MODIFIERS = Stream.of(Modifier.values())
.map(Modifier::name)
.map(StringUtils::toLowerCase)
.collect(Collectors.joining("|", "(", ")"));
private final static Pattern MOD_PATTERN = Pattern.compile("(" + MODIFIERS + " )*");
private final static Pattern METHOD_PATTERN = Pattern.compile("(?<ret>.+?) (?<name>\\S+)\\((?<params>.*)\\)( throws (?<throws>.*))?");
private final static Pattern VAR_PATTERN = Pattern.compile("VAR (?<modifiers>("+MODIFIERS+" )*)(?<type>.+?) (?<id>\\S+)( = (?<val>.*))?");
private final static Pattern TYPE_PATTERN = Pattern.compile("TYPE (?<modifiers>("+MODIFIERS+" )*)(?<fullyQualified>\\S+)");
public void appendItem(String l) {
try {
if (l.startsWith(" ")) {
lastInsertedType.pubApi.appendItem(l.substring(2));
return;
}
if (l.startsWith("METHOD")) {
l = l.substring("METHOD ".length());
Set<Modifier> modifiers = new HashSet<>();
Matcher modMatcher = MOD_PATTERN.matcher(l);
if (modMatcher.find()) {
String modifiersStr = modMatcher.group();
modifiers.addAll(parseModifiers(modifiersStr));
l = l.substring(modifiersStr.length());
}
List<PubApiTypeParam> typeParams = new ArrayList<>();
if (l.startsWith("<")) {
int closingPos = findClosingTag(l, 0);
String str = l.substring(1, closingPos);
l = l.substring(closingPos+1);
typeParams.addAll(parseTypeParams(splitOnTopLevelCommas(str)));
}
Matcher mm = METHOD_PATTERN.matcher(l);
if (!mm.matches())
throw new AssertionError("Could not parse return type, identifier, parameter types or throws declaration of method: " + l);
List<String> params = splitOnTopLevelCommas(mm.group("params"));
String th = Optional.ofNullable(mm.group("throws")).orElse("");
List<String> throwz = splitOnTopLevelCommas(th);
PubMethod m = new PubMethod(modifiers,
typeParams,
TypeDesc.decodeString(mm.group("ret")),
mm.group("name"),
parseTypeDescs(params),
parseTypeDescs(throwz));
addPubMethod(m);
return;
}
Matcher vm = VAR_PATTERN.matcher(l);
if (vm.matches()) {
addPubVar(new PubVar(parseModifiers(vm.group("modifiers")),
TypeDesc.decodeString(vm.group("type")),
vm.group("id"),
vm.group("val")));
return;
}
Matcher tm = TYPE_PATTERN.matcher(l);
if (tm.matches()) {
addPubType(new PubType(parseModifiers(tm.group("modifiers")),
tm.group("fullyQualified"),
new PubApi()));
return;
}
throw new AssertionError("No matching line pattern.");
} catch (Throwable e) {
throw new AssertionError("Could not parse API line: " + l, e);
}
}
public void addPubType(PubType t) {
types.put(t.fqName, t);
lastInsertedType = t;
}
public void addPubVar(PubVar v) {
variables.put(v.identifier, v);
}
public void addPubMethod(PubMethod m) {
methods.put(m.asSignatureString(), m);
}
private static List<TypeDesc> parseTypeDescs(List<String> strs) {
return strs.stream()
.map(TypeDesc::decodeString)
.collect(Collectors.toList());
}
private static List<PubApiTypeParam> parseTypeParams(List<String> strs) {
return strs.stream().map(PubApi::parseTypeParam).collect(Collectors.toList());
}
// Parse a type parameter string. Example input:
// identifier
// identifier extends Type (& Type)*
private static PubApiTypeParam parseTypeParam(String typeParamString) {
int extPos = typeParamString.indexOf(" extends ");
if (extPos == -1)
return new PubApiTypeParam(typeParamString, Collections.emptyList());
String identifier = typeParamString.substring(0, extPos);
String rest = typeParamString.substring(extPos + " extends ".length());
List<TypeDesc> bounds = parseTypeDescs(splitOnTopLevelChars(rest, '&'));
return new PubApiTypeParam(identifier, bounds);
}
public Set<Modifier> parseModifiers(String modifiers) {
if (modifiers == null)
return Collections.emptySet();
return Stream.of(modifiers.split(" "))
.map(String::trim)
.map(StringUtils::toUpperCase)
.filter(s -> !s.isEmpty())
.map(Modifier::valueOf)
.collect(Collectors.toSet());
}
// Find closing tag of the opening tag at the given 'pos'.
private static int findClosingTag(String l, int pos) {
while (true) {
pos = pos + 1;
if (l.charAt(pos) == '>')
return pos;
if (l.charAt(pos) == '<')
pos = findClosingTag(l, pos);
}
}
public List<String> splitOnTopLevelCommas(String s) {
return splitOnTopLevelChars(s, ',');
}
public static List<String> splitOnTopLevelChars(String s, char split) {
if (s.isEmpty())
return Collections.emptyList();
List<String> result = new ArrayList<>();
StringBuilder buf = new StringBuilder();
int depth = 0;
for (char c : s.toCharArray()) {
if (c == split && depth == 0) {
result.add(buf.toString().trim());
buf = new StringBuilder();
} else {
if (c == '<') depth++;
if (c == '>') depth--;
buf.append(c);
}
}
result.add(buf.toString().trim());
return result;
}
public boolean isEmpty() {
return types.isEmpty() && variables.isEmpty() && methods.isEmpty();
}
// Used for descriptive debug messages when figuring out what triggers
// recompilation.
public List<String> diff(PubApi prevApi) {
return diff("", prevApi);
}
private List<String> diff(String scopePrefix, PubApi prevApi) {
List<String> diffs = new ArrayList<>();
for (String typeKey : union(types.keySet(), prevApi.types.keySet())) {
PubType type = types.get(typeKey);
PubType prevType = prevApi.types.get(typeKey);
if (prevType == null) {
diffs.add("Type " + scopePrefix + typeKey + " was added");
} else if (type == null) {
diffs.add("Type " + scopePrefix + typeKey + " was removed");
} else {
// Check modifiers
if (!type.modifiers.equals(prevType.modifiers)) {
diffs.add("Modifiers for type " + scopePrefix + typeKey
+ " changed from " + prevType.modifiers + " to "
+ type.modifiers);
}
// Recursively check types pub API
diffs.addAll(type.pubApi.diff(prevType.pubApi));
}
}
for (String varKey : union(variables.keySet(), prevApi.variables.keySet())) {
PubVar var = variables.get(varKey);
PubVar prevVar = prevApi.variables.get(varKey);
if (prevVar == null) {
diffs.add("Variable " + scopePrefix + varKey + " was added");
} else if (var == null) {
diffs.add("Variable " + scopePrefix + varKey + " was removed");
} else {
if (!var.modifiers.equals(prevVar.modifiers)) {
diffs.add("Modifiers for var " + scopePrefix + varKey
+ " changed from " + prevVar.modifiers + " to "
+ var.modifiers);
}
if (!var.type.equals(prevVar.type)) {
diffs.add("Type of " + scopePrefix + varKey
+ " changed from " + prevVar.type + " to "
+ var.type);
}
if (!var.getConstValue().equals(prevVar.getConstValue())) {
diffs.add("Const value of " + scopePrefix + varKey
+ " changed from " + prevVar.getConstValue().orElse("<none>")
+ " to " + var.getConstValue().orElse("<none>"));
}
}
}
for (String methodKey : union(methods.keySet(), prevApi.methods.keySet())) {
PubMethod method = methods.get(methodKey);
PubMethod prevMethod = prevApi.methods.get(methodKey);
if (prevMethod == null) {
diffs.add("Method " + scopePrefix + methodKey + " was added");
} else if (method == null) {
diffs.add("Method " + scopePrefix + methodKey + " was removed");
} else {
if (!method.modifiers.equals(prevMethod.modifiers)) {
diffs.add("Modifiers for method " + scopePrefix + methodKey
+ " changed from " + prevMethod.modifiers + " to "
+ method.modifiers);
}
if (!method.typeParams.equals(prevMethod.typeParams)) {
diffs.add("Type parameters for method " + scopePrefix
+ methodKey + " changed from " + prevMethod.typeParams
+ " to " + method.typeParams);
}
if (!method.throwDecls.equals(prevMethod.throwDecls)) {
diffs.add("Throw decl for method " + scopePrefix + methodKey
+ " changed from " + prevMethod.throwDecls + " to "
+ " to " + method.throwDecls);
}
}
}
return diffs;
}
public String toString() {
return String.format("%s[types: %s, variables: %s, methods: %s]",
getClass().getSimpleName(),
types.values(),
variables.values(),
methods.values());
}
}

@ -0,0 +1,49 @@
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
public class PubApiTypeParam implements Serializable {
private static final long serialVersionUID = 8899204612014329162L;
private final String identifier;
private final List<TypeDesc> bounds;
public PubApiTypeParam(String identifier, List<TypeDesc> bounds) {
this.identifier = identifier;
this.bounds = bounds;
}
@Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
PubApiTypeParam other = (PubApiTypeParam) obj;
return identifier.equals(other.identifier)
&& bounds.equals(other.bounds);
}
@Override
public int hashCode() {
return identifier.hashCode() ^ bounds.hashCode();
}
public String asString() {
if (bounds.isEmpty())
return identifier;
String boundsStr = bounds.stream()
.map(TypeDesc::encodeAsString)
.collect(Collectors.joining(" & "));
return identifier + " extends " + boundsStr;
}
@Override
public String toString() {
return String.format("%s[id: %s, bounds: %s]",
getClass().getSimpleName(),
identifier,
bounds);
}
}

@ -0,0 +1,115 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.lang.model.element.Modifier;
public class PubMethod implements Serializable {
private static final long serialVersionUID = -7813050194553446243L;
Set<Modifier> modifiers;
List<PubApiTypeParam> typeParams;
TypeDesc returnType;
String identifier;
List<TypeDesc> paramTypes;
List<TypeDesc> throwDecls;
public PubMethod(Set<Modifier> modifiers,
List<PubApiTypeParam> typeParams,
TypeDesc returnType,
String identifier,
List<TypeDesc> paramTypes,
List<TypeDesc> throwDecls) {
this.modifiers = modifiers;
this.typeParams = typeParams;
this.returnType = returnType;
this.identifier = identifier;
this.paramTypes = paramTypes;
this.throwDecls = throwDecls;
}
// We need to include return type and type parameters to be sure to have
// different values for different methods. (A method can be overloaded with
// the only difference being the upper bound of the return type.)
public String asSignatureString() {
StringBuilder sb = new StringBuilder();
// <A extends String, Serializable, B extends List>
if (typeParams.size() > 0) {
sb.append(typeParams.stream()
.map(PubApiTypeParam::asString)
.collect(Collectors.joining(",", "<", "> ")));
}
sb.append(TypeDesc.encodeAsString(returnType));
sb.append(" ");
sb.append(identifier);
sb.append("(");
sb.append(paramTypes.stream()
.map(TypeDesc::encodeAsString)
.collect(Collectors.joining(",")));
sb.append(")");
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
PubMethod other = (PubMethod) obj;
return modifiers.equals(other.modifiers)
&& typeParams.equals(other.typeParams)
&& returnType.equals(other.returnType)
&& identifier.equals(other.identifier)
&& paramTypes.equals(other.paramTypes)
&& throwDecls.equals(other.throwDecls);
}
@Override
public int hashCode() {
return modifiers.hashCode()
^ typeParams.hashCode()
^ returnType.hashCode()
^ identifier.hashCode()
^ paramTypes.hashCode()
^ throwDecls.hashCode();
}
public String toString() {
return String.format("%s[modifiers: %s, typeParams: %s, retType: %s, identifier: %s, params: %s, throws: %s]",
getClass().getSimpleName(),
modifiers,
typeParams,
returnType,
identifier,
paramTypes,
throwDecls);
}
}

@ -0,0 +1,75 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import java.util.Set;
import javax.lang.model.element.Modifier;
public class PubType implements Serializable {
private static final long serialVersionUID = -7423416049253889793L;
public final Set<Modifier> modifiers;
public final String fqName;
public final PubApi pubApi;
public PubType(Set<Modifier> modifiers,
String fqName,
PubApi pubApi) {
this.modifiers = modifiers;
this.fqName = fqName;
this.pubApi = pubApi;
}
public String getFqName() {
return fqName.toString();
}
@Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
PubType other = (PubType) obj;
return modifiers.equals(other.modifiers)
&& fqName.equals(other.fqName)
&& pubApi.equals(other.pubApi);
}
@Override
public int hashCode() {
return modifiers.hashCode() ^ fqName.hashCode() ^ pubApi.hashCode();
}
@Override
public String toString() {
return String.format("%s[modifiers: %s, fqName: %s, pubApi: %s]",
getClass().getSimpleName(),
modifiers,
fqName,
pubApi);
}
}

@ -0,0 +1,87 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import java.util.Optional;
import java.util.Set;
import javax.lang.model.element.Modifier;
public class PubVar implements Serializable {
private static final long serialVersionUID = 5806536061153374575L;
public final Set<Modifier> modifiers;
public final TypeDesc type;
public final String identifier;
private final String constValue;
public PubVar(Set<Modifier> modifiers,
TypeDesc type,
String identifier,
String constValue) {
this.modifiers = modifiers;
this.type = type;
this.identifier = identifier;
this.constValue = constValue;
}
public String getIdentifier() {
return identifier;
}
@Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
PubVar other = (PubVar) obj;
return modifiers.equals(other.modifiers)
&& type.equals(other.type)
&& identifier.equals(other.identifier)
&& getConstValue().equals(other.getConstValue());
}
@Override
public int hashCode() {
return modifiers.hashCode()
^ type.hashCode()
^ identifier.hashCode()
^ getConstValue().hashCode();
}
public String toString() {
return String.format("%s[modifiers: %s, type: %s, identifier: %s, constValue: %s]",
getClass().getSimpleName(),
modifiers,
type,
identifier,
constValue);
}
public Optional<String> getConstValue() {
return Optional.ofNullable(constValue);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,9 +22,38 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg10;
public class Cls10 {
public pkg13.Cls13 getCls13() {
return null;
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import javax.lang.model.type.TypeKind;
public class ReferenceTypeDesc extends TypeDesc implements Serializable {
private static final long serialVersionUID = 3357616754544796372L;
// Example: "java.util.Vector<java.lang.String>"
String javaType;
public ReferenceTypeDesc(String javaType) {
super(TypeKind.DECLARED);
this.javaType = javaType;
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj))
return false;
return javaType.equals(((ReferenceTypeDesc) obj).javaType);
}
@Override
public int hashCode() {
return super.hashCode() ^ javaType.hashCode();
}
@Override
public String toString() {
return String.format("%s[type: %s]", getClass().getSimpleName(), javaType);
}
}

@ -0,0 +1,139 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ErrorType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.SimpleTypeVisitor9;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.StringUtils;
public abstract class TypeDesc implements Serializable {
private static final long serialVersionUID = -8201634143915519172L;
TypeKind typeKind;
public TypeDesc(TypeKind typeKind) {
this.typeKind = typeKind;
}
public static TypeDesc decodeString(String s) {
s = s.trim();
if (s.endsWith("[]")) {
String componentPart = s.substring(0, s.length()-2);
return new ArrayTypeDesc(decodeString(componentPart));
}
if (s.startsWith("#"))
return new TypeVarTypeDesc(s.substring(1));
if (s.matches("boolean|byte|char|double|float|int|long|short|void")) {
TypeKind tk = TypeKind.valueOf(StringUtils.toUpperCase(s));
return new PrimitiveTypeDesc(tk);
}
return new ReferenceTypeDesc(s);
}
public static String encodeAsString(TypeDesc td) {
if (td.typeKind.isPrimitive() || td.typeKind == TypeKind.VOID)
return StringUtils.toLowerCase(td.typeKind.toString());
if (td.typeKind == TypeKind.ARRAY)
return encodeAsString(((ArrayTypeDesc) td).compTypeDesc) + "[]";
if (td.typeKind == TypeKind.TYPEVAR)
return "#" + ((TypeVarTypeDesc) td).identifier;
if (td.typeKind == TypeKind.DECLARED)
return ((ReferenceTypeDesc) td).javaType.toString();
throw new AssertionError("Unhandled type: " + td.typeKind);
}
public static TypeDesc fromType(TypeMirror type) {
TypeVisitor<TypeDesc, Void> v = new SimpleTypeVisitor9<TypeDesc, Void>() {
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public TypeDesc visitArray(ArrayType t, Void p) {
return new ArrayTypeDesc(t.getComponentType().accept(this, p));
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public TypeDesc visitDeclared(DeclaredType t, Void p) {
return new ReferenceTypeDesc(((ClassType) t).tsym.flatName().toString());
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public TypeDesc visitNoType(NoType t, Void p) {
return new PrimitiveTypeDesc(TypeKind.VOID);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public TypeDesc visitTypeVariable(TypeVariable t, Void p) {
return new TypeVarTypeDesc(t.toString());
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public TypeDesc visitPrimitive(PrimitiveType t, Void p) {
return new PrimitiveTypeDesc(t.getKind());
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public TypeDesc visitError(ErrorType t, Void p) {
return new ReferenceTypeDesc("<error type>");
}
};
TypeDesc td = v.visit(type);
if (td == null)
throw new AssertionError("Unhandled type mirror: " + type + " (" + type.getClass() + ")");
return td;
}
@Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
return typeKind.equals(((TypeDesc) obj).typeKind);
}
@Override
public int hashCode() {
return typeKind.hashCode();
}
}

@ -0,0 +1,60 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import javax.lang.model.type.TypeKind;
public class TypeVarTypeDesc extends TypeDesc implements Serializable {
private static final long serialVersionUID = 3357616754544796373L;
String identifier; // Example: "T"
public TypeVarTypeDesc(String identifier) {
super(TypeKind.TYPEVAR);
this.identifier = identifier;
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj))
return false;
return identifier.equals(((TypeVarTypeDesc) obj).identifier);
}
@Override
public int hashCode() {
return super.hashCode() ^ identifier.hashCode();
}
@Override
public String toString() {
return String.format("%s[identifier: %s]",
getClass().getSimpleName(),
identifier);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,6 +31,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
*
* <p><b>This is NOT part of any supported API.
@ -47,8 +49,10 @@ public class CompilationResult implements Serializable {
public int returnCode;
public Map<String, Set<URI>> packageArtifacts = new HashMap<>();
public Map<String, Set<String>> packageDependencies = new HashMap<>();
public Map<String, String> packagePubapis = new HashMap<>();
public Map<String, Map<String, Set<String>>> packageDependencies = new HashMap<>();
public Map<String, Map<String, Set<String>>> packageCpDependencies = new HashMap<>();
public Map<String, PubApi> packagePubapis = new HashMap<>();
public Map<String, PubApi> dependencyPubapis = new HashMap<>();
public String stdout = "";
public String stderr = "";

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,8 @@ package com.sun.tools.sjavac.server;
import java.io.IOException;
import com.sun.tools.sjavac.Log;
/**
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
@ -36,6 +38,8 @@ import java.io.IOException;
public class ServerMain {
public static int run(String[] args) {
Log.initializeLog(System.out, System.err);
// Any options other than --startserver?
if (args.length > 1) {
System.err.println("When spawning a background server, only a single --startserver argument is allowed.");

@ -0,0 +1,214 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8054717
* @summary Make sure extraction of non-private APIs work as expected.
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper ToolBox
* @run main Wrapper ApiExtraction
*/
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PROTECTED;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.type.TypeKind;
import com.sun.tools.sjavac.PubApiExtractor;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PrimitiveTypeDesc;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.pubapi.PubMethod;
import com.sun.tools.sjavac.pubapi.PubType;
import com.sun.tools.sjavac.pubapi.PubVar;
import com.sun.tools.sjavac.pubapi.ReferenceTypeDesc;
public class ApiExtraction {
public static void main(String[] args) throws IOException {
String testSrc = String.join("\n",
"import java.util.*;",
"public final class TestClass extends Thread {",
// Fields with various combination of modifiers
" private String s1 = \"str 1\";",
" public String s2 = \"str 2\";",
" protected final String s3 = \"str 3\";",
" static String s4 = \"str 4\";",
// Methods with various combinations of types and modifiers
" protected void m1() {}",
" public static Map<Integer, List<String>> m2() {",
" return null;",
" }",
" final void m3(Set<Map<Integer, Map<String, String>>> s) {}",
// Some inner classes
" static class DummyInner1 implements Runnable {",
" protected int field;",
" public void run() {}",
" }",
" final class DummyInner2 { }",
"}");
// Create class file to extract API from
new ToolBox().new JavacTask().sources(testSrc).run();
// Extract PubApi
Options options = Options.parseArgs("-d", "bin", "-cp", ".");
PubApiExtractor pubApiExtr = new PubApiExtractor(options);
PubApi actualApi = pubApiExtr.getPubApi("TestClass");
// Validate result
PubApi expectedApi = getExpectedPubApi();
if (!expectedApi.equals(actualApi)) {
List<String> diffs = expectedApi.diff(actualApi);
System.out.println(diffs.size() + " differences found.");
for (String diff : diffs) {
System.out.println(diff);
}
throw new AssertionError("Actual API differs from expected API.");
}
}
private static PubApi getExpectedPubApi() {
ReferenceTypeDesc string = new ReferenceTypeDesc("java.lang.String");
// Fields
// (s1 is private and therefore not included)
PubVar s2 = new PubVar(setOf(PUBLIC), string, "s2", null);
PubVar s4 = new PubVar(setOf(STATIC), string, "s4", null);
PubVar s3 = new PubVar(setOf(PROTECTED, FINAL), string, "s3",
"\"\\u0073\\u0074\\u0072\\u0020\\u0033\"");
// Methods
PubMethod init = new PubMethod(setOf(PUBLIC),
emptyList(),
new PrimitiveTypeDesc(TypeKind.VOID),
"<init>",
emptyList(),
emptyList());
PubMethod clinit = new PubMethod(setOf(STATIC),
emptyList(),
new PrimitiveTypeDesc(TypeKind.VOID),
"<clinit>",
emptyList(),
emptyList());
PubMethod m1 = new PubMethod(setOf(PROTECTED),
emptyList(),
new PrimitiveTypeDesc(TypeKind.VOID),
"m1",
emptyList(),
emptyList());
PubMethod m2 = new PubMethod(setOf(PUBLIC, STATIC),
emptyList(),
new ReferenceTypeDesc("java.util.Map"),
"m2",
emptyList(),
emptyList());
PubMethod m3 = new PubMethod(setOf(FINAL),
emptyList(),
new PrimitiveTypeDesc(TypeKind.VOID),
"m3",
asList(new ReferenceTypeDesc("java.util.Set")),
emptyList());
// Complete class
PubType testClass = new PubType(setOf(PUBLIC, FINAL),
"TestClass",
new PubApi(asList(getDummyInner1(), getDummyInner2()),
asList(s2, s3, s4),
asList(init, clinit, m1, m2, m3)));
// Wrap in "package level" PubApi
return new PubApi(asList(testClass), emptyList(), emptyList());
}
private static PubType getDummyInner1() {
PubMethod init = new PubMethod(setOf(),
emptyList(),
new PrimitiveTypeDesc(TypeKind.VOID),
"<init>",
emptyList(),
emptyList());
PubMethod run = new PubMethod(setOf(PUBLIC),
emptyList(),
new PrimitiveTypeDesc(TypeKind.VOID),
"run",
emptyList(),
emptyList());
PubVar field = new PubVar(setOf(PROTECTED),
new PrimitiveTypeDesc(TypeKind.INT),
"field",
null);
return new PubType(setOf(STATIC),
"TestClass$DummyInner1",
new PubApi(emptyList(),
asList(field),
asList(init, run)));
}
private static PubType getDummyInner2() {
PubMethod init = new PubMethod(setOf(),
emptyList(),
new PrimitiveTypeDesc(TypeKind.VOID),
"<init>",
emptyList(),
emptyList());
return new PubType(setOf(FINAL),
"TestClass$DummyInner2",
new PubApi(emptyList(),
emptyList(),
asList(init)));
}
@SafeVarargs
private static <T> Set<T> setOf(T... elements) {
return new HashSet<>(asList(elements));
}
}

@ -0,0 +1,142 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8054717
* @summary Make sure changes of public API on classpath triggers recompilation
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper ToolBox
* @run main Wrapper ClasspathDependencies
*/
import static com.sun.tools.javac.util.Assert.check;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
public class ClasspathDependencies extends SjavacBase {
static final String server = "--server:portfile=testserver,background=false";
public static void main(String... args) throws Exception {
Path root = Paths.get(ClasspathDependencies.class.getSimpleName() + "Test");
delete(root);
Path src = root.resolve("src");
Path classes = root.resolve("classes");
Path srcDep = root.resolve("srcDep");
Path classesDep = root.resolve("classesDep");
////////////////////////////////////////////////////////////////////////
headline("Create a test dependency, Dep.class, and put it in the classpath dir");
String depCode = "package dep; public class Dep { public void m1() {} }";
toolbox.writeFile(srcDep.resolve("dep/Dep.java"), depCode);
int rc = compile(server, "-d", classesDep, srcDep);
check(rc == 0, "Compilation failed unexpectedly");
////////////////////////////////////////////////////////////////////////
headline("Compile and link against the Dep.class");
toolbox.writeFile(src.resolve("pkg/C.java"),
"package pkg;" +
"import dep.Dep;" +
"public class C { Dep dep; public void m() { new Dep().m1(); } }");
rc = compile(server, "-d", classes, src, "-cp", classesDep);
check(rc == 0, "Compilation failed unexpectedly");
FileTime modTime1 = Files.getLastModifiedTime(classes.resolve("pkg/C.class"));
////////////////////////////////////////////////////////////////////////
headline("Update dependency (without changing the public api)");
Thread.sleep(2000);
depCode = depCode.replaceAll("}$", "private void m2() {} }");
toolbox.writeFile(srcDep.resolve("dep/Dep.java"), depCode);
rc = compile(server, "-d", classesDep, srcDep);
check(rc == 0, "Compilation failed unexpectedly");
////////////////////////////////////////////////////////////////////////
headline("Make sure that this does not trigger recompilation of C.java");
rc = compile(server, "-d", classes, src, "-cp", classesDep);
check(rc == 0, "Compilation failed unexpectedly");
FileTime modTime2 = Files.getLastModifiedTime(classes.resolve("pkg/C.class"));
check(modTime1.equals(modTime2), "Recompilation erroneously triggered");
////////////////////////////////////////////////////////////////////////
headline("Update public API of dependency");
Thread.sleep(2000);
depCode = depCode.replace("m1()", "m1(String... arg)");
toolbox.writeFile(srcDep.resolve("dep/Dep.java"), depCode);
rc = compile(server, "-d", classesDep, srcDep);
check(rc == 0, "Compilation failed unexpectedly");
////////////////////////////////////////////////////////////////////////
headline("Make sure that recompilation of C.java is triggered");
rc = compile(server, "-d", classes, src, "-cp", classesDep);
check(rc == 0, "Compilation failed unexpectedly");
FileTime modTime3 = Files.getLastModifiedTime(classes.resolve("pkg/C.class"));
check(modTime2.compareTo(modTime3) < 0, "Recompilation not triggered");
}
static void headline(String str) {
System.out.println();
System.out.println(str);
System.out.println(str.replaceAll(".", "-"));
}
static void delete(Path root) throws IOException {
if (!Files.exists(root))
return;
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path f, BasicFileAttributes a)
throws IOException {
Files.delete(f);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e)
throws IOException {
if (e != null)
throw e;
if (!dir.equals(root))
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
}

@ -48,27 +48,33 @@ public class CompileCircularSources extends SJavacTester {
}
void test() throws Exception {
Files.createDirectory(BIN);
clean(TEST_ROOT);
Files.createDirectories(BIN);
clean(GENSRC, BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A { beta.B b; }");
"package alfa.omega; public class A { beta.B b; }");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; public class B { gamma.C c; }");
"package beta; public class B { gamma.C c; }");
tb.writeFile(GENSRC.resolve("gamma/C.java"),
"package gamma; public class C { alfa.omega.A a; }");
"package gamma; public class C { alfa.omega.A a; }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "3",
SERVER_ARG,"--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "3",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
"bin/beta/B.class",
"bin/gamma/C.class",
"bin/javac_state");
verifyThatFilesHaveBeenAdded(previous_bin_state,
new_bin_state,
BIN + "/alfa/omega/A.class",
BIN + "/beta/B.class",
BIN + "/gamma/C.class",
BIN + "/javac_state");
clean(GENSRC, BIN);
}
}

@ -49,22 +49,27 @@ public class CompileExcludingDependency extends SJavacTester {
// Verify that excluding classes from compilation but not from linking works
void test() throws Exception {
Files.createDirectory(BIN);
clean(TEST_ROOT);
Files.createDirectories(BIN);
clean(GENSRC,BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A { beta.B b; }");
"package alfa.omega; public class A { beta.B b; }");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; public class B { }");
"package beta; public class B { }");
compile("-x", "beta", "-src", "gensrc", "-x", "alfa/omega", "-sourcepath", "gensrc",
"-d", "bin", SERVER_ARG);
compile("-x", "beta",
"-src", GENSRC.toString(),
"-x", "alfa/omega",
"-sourcepath", GENSRC.toString(),
"-d", BIN.toString(),
SERVER_ARG);
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
"bin/javac_state");
BIN + "/alfa/omega/A.class",
BIN + "/javac_state");
clean(GENSRC, BIN);
}
}

@ -48,9 +48,13 @@ public class CompileWithAtFile extends SJavacTester {
}
void test() throws Exception {
clean(TEST_ROOT);
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("list.txt"),
"-if */alfa/omega/A.java\n-if */beta/B.java\ngensrc\n-d bin\n");
"-if */alfa/omega/A.java\n" +
"-if */beta/B.java\n" +
GENSRC + "\n" +
"-d " + BIN + "\n");
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; import beta.B; public class A { B b; }");
tb.writeFile(GENSRC.resolve("beta/B.java"),
@ -60,13 +64,14 @@ public class CompileWithAtFile extends SJavacTester {
Files.createDirectory(BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
compile("@gensrc/list.txt", "--server:portfile=testserver,background=false");
compile("@" + GENSRC + "/list.txt", "--server:portfile=testserver,background=false");
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/javac_state",
"bin/alfa/omega/A.class",
"bin/beta/B.class");
BIN + "/javac_state",
BIN + "/alfa/omega/A.class",
BIN + "/beta/B.class");
clean(GENSRC, BIN);
}
}

@ -51,35 +51,45 @@ public class CompileWithInvisibleSources extends SJavacTester {
// gensrc2 contains broken code in beta.B, thus exclude that package
// gensrc3 contains a proper beta.B
void test() throws Exception {
Files.createDirectory(BIN);
clean(TEST_ROOT);
Files.createDirectories(BIN);
clean(GENSRC, GENSRC2, GENSRC3, BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; import beta.B; import gamma.C; public class A { B b; C c; }");
"package alfa.omega; import beta.B; import gamma.C; public class A { B b; C c; }");
tb.writeFile(GENSRC2.resolve("beta/B.java"),
"package beta; public class B { broken");
"package beta; public class B { broken");
tb.writeFile(GENSRC2.resolve("gamma/C.java"),
"package gamma; public class C { }");
"package gamma; public class C { }");
tb.writeFile(GENSRC3.resolve("beta/B.java"),
"package beta; public class B { }");
"package beta; public class B { }");
compile("gensrc", "-x", "beta", "-sourcepath", "gensrc2",
"-sourcepath", "gensrc3", "-d", "bin", "-h", "headers", "-j", "1",
compile(GENSRC.toString(),
"-x", "beta",
"-sourcepath", GENSRC2.toString(),
"-sourcepath", GENSRC3.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG);
System.out.println("The first compile went well!");
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
"bin/javac_state");
BIN + "/alfa/omega/A.class",
BIN + "/javac_state");
System.out.println("----- Compile with exluded beta went well!");
clean(BIN);
compileExpectFailure("gensrc", "-sourcepath", "gensrc2", "-sourcepath", "gensrc3",
"-d", "bin", "-h", "headers", "-j", "1",
compileExpectFailure(GENSRC.toString(),
"-sourcepath", GENSRC2.toString(),
"-sourcepath", GENSRC3.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG);
System.out.println("----- Compile without exluded beta failed, as expected! Good!");

@ -50,33 +50,43 @@ public class CompileWithOverrideSources extends SJavacTester {
// Compile gensrc and gensrc2. However do not compile broken beta.B in gensrc,
// only compile ok beta.B in gensrc2
void test() throws Exception {
Files.createDirectory(BIN);
clean(TEST_ROOT);
Files.createDirectories(BIN);
clean(GENSRC, GENSRC2, GENSRC3, BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; import beta.B; import gamma.C; public class A { B b; C c; }");
"package alfa.omega; import beta.B; import gamma.C; public class A { B b; C c; }");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; public class B { broken");
"package beta; public class B { broken");
tb.writeFile(GENSRC.resolve("gamma/C.java"),
"package gamma; public class C { }");
"package gamma; public class C { }");
tb.writeFile(GENSRC2.resolve("beta/B.java"),
"package beta; public class B { }");
"package beta; public class B { }");
compile("-x", "beta", "gensrc", "gensrc2", "-d", "bin", "-h", "headers", "-j", "1",
compile("-x", "beta",
GENSRC.toString(),
GENSRC2.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG);
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
"bin/beta/B.class",
"bin/gamma/C.class",
"bin/javac_state");
BIN + "/alfa/omega/A.class",
BIN + "/beta/B.class",
BIN + "/gamma/C.class",
BIN + "/javac_state");
System.out.println("----- Compile with exluded beta went well!");
clean(BIN);
compileExpectFailure("gensrc", "gensrc2", "-d", "bin", "-h", "headers", "-j", "1",
compileExpectFailure(GENSRC.toString(),
GENSRC2.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG);
System.out.println("----- Compile without exluded beta failed, as expected! Good!");

@ -1,139 +0,0 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8056258 8048609
* @summary Ensures that the DependencyCollector covers various cases.
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.util
* jdk.compiler/com.sun.tools.sjavac.comp
* jdk.compiler/com.sun.tools.sjavac.comp.dependencies
* @build Wrapper ToolBox
* @run main Wrapper DependencyCollection
*/
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.sjavac.comp.SmartFileManager;
import com.sun.tools.sjavac.comp.dependencies.DependencyCollector;
public class DependencyCollection {
public static void main(String[] args) throws IOException {
Path src = Paths.get(ToolBox.testSrc, "test-input", "src");
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
try (StandardJavaFileManager fileManager = javac.getStandardFileManager(null, null, null)) {
SmartFileManager smartFileManager = new SmartFileManager(fileManager);
smartFileManager.setSymbolFileEnabled(false);
Iterable<? extends JavaFileObject> fileObjects =
fileManager.getJavaFileObjectsFromFiles(Arrays.asList(src.resolve("pkg/Test.java").toFile()));
JavacTaskImpl task = (JavacTaskImpl) javac.getTask(new PrintWriter(System.out),
smartFileManager,
null,
Arrays.asList("-d", "classes",
"-sourcepath", src.toAbsolutePath().toString()),
null,
fileObjects);
DependencyCollector depsCollector = new DependencyCollector();
task.addTaskListener(depsCollector);
task.doCall();
// Find pkg symbol
PackageSymbol pkg = findPkgSymbolWithName(depsCollector.getSourcePackages(), "pkg");
Set<PackageSymbol> foundDependencies = depsCollector.getDependenciesForPkg(pkg);
// Print dependencies
System.out.println("Found dependencies:");
foundDependencies.stream()
.sorted(Comparator.comparing(DependencyCollection::extractNumber))
.forEach(p -> System.out.println(" " + p));
// Check result
Set<Integer> found = foundDependencies.stream()
.map(DependencyCollection::extractNumber)
.collect(Collectors.toSet());
found.remove(-1); // Dependencies with no number (java.lang etc)
Set<Integer> expected = new HashSet<>();
for (int i = 2; i <= 30; i++) {
if (i == 15) continue; // Case 15 correspond to the type of a throw-away return value.
expected.add(i);
}
Set<Integer> missing = new HashSet<>(expected);
missing.removeAll(found);
if (missing.size() > 0) {
System.out.println("Missing dependencies:");
missing.forEach(i -> System.out.println(" Dependency " + i));
}
Set<Integer> unexpected = new HashSet<>(found);
unexpected.removeAll(expected);
if (unexpected.size() > 0) {
System.out.println("Unexpected dependencies found:");
unexpected.forEach(i -> System.out.println(" Dependency " + i));
}
if (missing.size() > 0 || unexpected.size() > 0)
throw new AssertionError("Missing and/or unexpected dependencies found.");
}
}
private static PackageSymbol findPkgSymbolWithName(Set<PackageSymbol> syms, String name) {
for (PackageSymbol ps : syms)
if (ps.fullname.toString().equals("pkg"))
return ps;
throw new AssertionError("Could not find package named \"pkg\".");
}
public static int extractNumber(PackageSymbol p) {
Matcher m = Pattern.compile("\\d+").matcher(p.fullname.toString());
if (!m.find())
return -1;
return Integer.parseInt(m.group());
}
}

@ -60,6 +60,7 @@ public class IncCompInheritance extends SjavacBase {
throw new AssertionError("Compilation failed unexpectedly");
// Remove method A.m
Thread.sleep(2500); // Make sure we get a new timestamp
String aModified = "package pkga; public class A { }";
toolbox.writeFile(src.resolve("pkga/A.java"), aModified);

@ -51,9 +51,10 @@ public class IncCompileChangeNative extends SJavacTester {
ToolBox tb = new ToolBox();
void test() throws Exception {
Files.createDirectory(GENSRC);
Files.createDirectory(BIN);
Files.createDirectory(HEADERS);
clean(TEST_ROOT);
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileDropAllNatives();
@ -70,21 +71,25 @@ public class IncCompileChangeNative extends SJavacTester {
System.out.println("\nIn incrementalCompileDropAllNatives() ");
System.out.println("Verify that beta_B.h is removed");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; import alfa.omega.A; public class B {"+
"private int b() { return A.DEFINITION; } }");
"package beta; import alfa.omega.A; " +
"public class B { private int b() { return A.DEFINITION; } }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/beta/B.class",
"bin/beta/BINT.class",
"bin/javac_state");
BIN + "/beta/B.class",
BIN + "/beta/BINT.class",
BIN + "/javac_state");
previous_bin_state = new_bin_state;
Map<String,Long> new_headers_state = collectState(HEADERS);
verifyThatFilesHaveBeenRemoved(previous_headers_state, new_headers_state,
"headers/beta_B.h");
HEADERS + "/beta_B.h");
previous_headers_state = new_headers_state;
}
@ -94,22 +99,26 @@ public class IncCompileChangeNative extends SJavacTester {
System.out.println("\nIn incrementalCompileAddNative() ");
System.out.println("Verify that beta_B.h is added again");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; import alfa.omega.A; public class B {"+
"private int b() { return A.DEFINITION; } "+
"@java.lang.annotation.Native final static int alfa = 42; }");
"package beta; import alfa.omega.A; public class B {"+
"private int b() { return A.DEFINITION; } "+
"@java.lang.annotation.Native final static int alfa = 42; }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/beta/B.class",
"bin/beta/BINT.class",
"bin/javac_state");
BIN + "/beta/B.class",
BIN + "/beta/BINT.class",
BIN + "/javac_state");
previous_bin_state = new_bin_state;
Map<String,Long> new_headers_state = collectState(HEADERS);
verifyThatFilesHaveBeenAdded(previous_headers_state, new_headers_state,
"headers/beta_B.h");
HEADERS + "/beta_B.h");
previous_headers_state = new_headers_state;
}
}

@ -51,9 +51,10 @@ public class IncCompileDropClasses extends SJavacTester {
ToolBox tb = new ToolBox();
void test() throws Exception {
Files.createDirectory(GENSRC);
Files.createDirectory(BIN);
Files.createDirectory(HEADERS);
clean(TEST_ROOT);
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileDroppingClasses();
@ -68,15 +69,19 @@ public class IncCompileDropClasses extends SJavacTester {
System.out.println("\nIn incrementalCompileDroppingClasses() ");
System.out.println("Testing that deleting AA.java deletes all generated inner class including AA.class");
removeFrom(GENSRC, "alfa/omega/AA.java");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenRemoved(previous_bin_state, new_bin_state,
"bin/alfa/omega/AA$1.class",
"bin/alfa/omega/AA$AAAA.class",
"bin/alfa/omega/AA$AAA.class",
"bin/alfa/omega/AAAAA.class",
"bin/alfa/omega/AA.class");
BIN + "/alfa/omega/AA$1.class",
BIN + "/alfa/omega/AA$AAAA.class",
BIN + "/alfa/omega/AA$AAA.class",
BIN + "/alfa/omega/AAAAA.class",
BIN + "/alfa/omega/AA.class");
previous_bin_state = new_bin_state;
Map<String,Long> new_headers_state = collectState(HEADERS);

@ -27,6 +27,7 @@
* @test
* @summary Verify that "alfa.omega.A a" does create a proper dependency
* @bug 8054689
* @ignore Requires dependency code to deal with in-method dependencies.
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
@ -38,8 +39,7 @@
* @run main Wrapper IncCompileFullyQualifiedRef
*/
import java.util.*;
import java.nio.file.*;
import java.util.Map;
public class IncCompileFullyQualifiedRef extends SJavacTester {
public static void main(String... args) throws Exception {
@ -48,36 +48,43 @@ public class IncCompileFullyQualifiedRef extends SJavacTester {
}
void test() throws Exception {
clean(TEST_ROOT);
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A { "+
" public final static int DEFINITION = 18; "+
" public void hello() { }"+
"}");
"package alfa.omega; public class A { "+
" public final static int DEFINITION = 18; "+
" public void hello() { }"+
"}");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; public class B { "+
" public void world() { alfa.omega.A a; }"+
"}");
"package beta; public class B { "+
" public void world() { alfa.omega.A a; }"+
"}");
compile("gensrc", "-d", "bin", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> previous_bin_state = collectState(BIN);
// Change pubapi of A, this should trigger a recompile of B.
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A { "+
" public final static int DEFINITION = 19; "+
" public void hello() { }"+
"}");
"package alfa.omega; public class A { "+
" public final static int DEFINITION = 19; "+
" public void hello() { }"+
"}");
compile("gensrc", "-d", "bin", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
"bin/beta/B.class",
"bin/javac_state");
BIN + "/alfa/omega/A.class",
BIN + "/beta/B.class",
BIN + "/javac_state");
clean(GENSRC,BIN);
}
}

@ -50,9 +50,10 @@ public class IncCompileNoChanges extends SJavacTester {
Map<String,Long> previous_headers_state;
void test() throws Exception {
Files.createDirectory(GENSRC);
Files.createDirectory(BIN);
Files.createDirectory(HEADERS);
clean(Paths.get(getClass().getSimpleName()));
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileNoChanges();
@ -66,8 +67,12 @@ public class IncCompileNoChanges extends SJavacTester {
previous_headers_state = collectState(HEADERS);
System.out.println("\nIn incrementalCompileNoChanges() ");
System.out.println("Testing that no change in sources implies no change in binaries");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyEqual(new_bin_state, previous_bin_state);
Map<String,Long> new_headers_state = collectState(HEADERS);

@ -51,9 +51,10 @@ public class IncCompileUpdateNative extends SJavacTester {
ToolBox tb = new ToolBox();
void test() throws Exception {
Files.createDirectory(GENSRC);
Files.createDirectory(BIN);
Files.createDirectory(HEADERS);
clean(TEST_ROOT);
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileChangeNative();
@ -69,22 +70,26 @@ public class IncCompileUpdateNative extends SJavacTester {
System.out.println("\nIn incrementalCompileChangeNative() ");
System.out.println("Verify that beta_B.h is rewritten again");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; import alfa.omega.A; public class B {"+
"private int b() { return A.DEFINITION; } "+
"@java.lang.annotation.Native final static int alfa = 43; }");
"package beta; import alfa.omega.A; public class B {"+
"private int b() { return A.DEFINITION; } "+
"@java.lang.annotation.Native final static int alfa = 43; }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/beta/B.class",
"bin/beta/BINT.class",
"bin/javac_state");
BIN + "/beta/B.class",
BIN + "/beta/BINT.class",
BIN + "/javac_state");
previous_bin_state = new_bin_state;
Map<String,Long> new_headers_state = collectState(HEADERS);
verifyNewerFiles(previous_headers_state, new_headers_state,
"headers/beta_B.h");
HEADERS + "/beta_B.h");
previous_headers_state = new_headers_state;
}
}

@ -24,6 +24,7 @@
/*
* @test
* @summary Verify incremental changes in gensrc are handled as expected
* @ignore Requires dependency code to deal with in-method dependencies.
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
@ -51,14 +52,13 @@ public class IncCompileWithChanges extends SJavacTester {
ToolBox tb = new ToolBox();
void test() throws Exception {
Files.createDirectory(GENSRC);
Files.createDirectory(BIN);
Files.createDirectory(HEADERS);
clean(TEST_ROOT);
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileWithChange();
clean(GENSRC, BIN, HEADERS);
}
/* Update A.java with a new timestamp and new final static definition.
@ -72,24 +72,29 @@ public class IncCompileWithChanges extends SJavacTester {
System.out.println("A.java updated to trigger a recompile");
System.out.println("Generated native header should not be updated since native api of B was not modified");
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A implements AINT { "+
"public final static int DEFINITION = 18; public void aint() { } private void foo() { } }");
"package alfa.omega; public class A implements AINT { " +
"public final static int DEFINITION = 18;" +
"public void aint() { } private void foo() { } }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
Map<String,Long> new_bin_state = collectState(BIN);
verifyNewerFiles(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
"bin/alfa/omega/AINT.class",
"bin/alfa/omega/AA$AAAA.class",
"bin/alfa/omega/AAAAA.class",
"bin/alfa/omega/AA$AAA.class",
"bin/alfa/omega/AA.class",
"bin/alfa/omega/AA$1.class",
"bin/beta/B.class",
"bin/beta/BINT.class",
"bin/javac_state");
BIN + "/alfa/omega/A.class",
BIN + "/alfa/omega/AINT.class",
BIN + "/alfa/omega/AA$AAAA.class",
BIN + "/alfa/omega/AAAAA.class",
BIN + "/alfa/omega/AA$AAA.class",
BIN + "/alfa/omega/AA.class",
BIN + "/alfa/omega/AA$1.class",
BIN + "/beta/B.class",
BIN + "/beta/BINT.class",
BIN + "/javac_state");
previous_bin_state = new_bin_state;
Map<String,Long> new_headers_state = collectState(HEADERS);

@ -83,6 +83,7 @@ public class JavacOptionPrep {
// Check the result
boolean destDirFound = false;
boolean userPathsFirst = false;
boolean headerDirFound = false;
boolean gensrcDirFound = false;
boolean classPathFound = false;
@ -95,6 +96,11 @@ public class JavacOptionPrep {
String option = javacArgIter.next();
// Ignore this option for now. When the file=... requirement goes
// away, this will be easier to handle.
if (option.startsWith("-XDcompletionDeps"))
continue;
switch (option) {
case "-classpath":
case "-cp":
@ -166,7 +172,6 @@ public class JavacOptionPrep {
if (!implicitNoneFound)
throw new AssertionError("\"-implicit:none\" not found.");
}
static void assertEquals(Object expected, Object actual) {

@ -38,12 +38,8 @@
* @run main Wrapper PermittedArtifact
*/
import java.lang.reflect.Method;
import java.util.*;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.charset.*;
import java.nio.file.Files;
import java.util.Map;
public class PermittedArtifact extends SJavacTester {
public static void main(String... args) throws Exception {
@ -53,26 +49,31 @@ public class PermittedArtifact extends SJavacTester {
//Verify that --permit-artifact=bin works
void test() throws Exception {
Files.createDirectory(BIN);
clean(TEST_ROOT);
Files.createDirectories(BIN);
clean(GENSRC, BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
new ToolBox().writeFile(GENSRC+"/alfa/omega/A.java",
"package alfa.omega; public class A { }");
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC + "/alfa/omega/A.java",
"package alfa.omega; public class A { }");
new ToolBox().writeFile(BIN+"/alfa/omega/AA.class",
"Ugh, a messy build system (tobefixed) wrote this class file, "
+ "sjavac must not delete it.");
tb.writeFile(BIN + "/alfa/omega/AA.class",
"Ugh, a messy build system (tobefixed) wrote this class file, " +
"sjavac must not delete it.");
compile("--log=debug", "--permit-artifact=bin/alfa/omega/AA.class",
"-src", "gensrc", "-d", "bin", SERVER_ARG);
compile("--log=debug",
"--permit-artifact=" + BIN + "/alfa/omega/AA.class",
"-src", GENSRC.toString(),
"-d", BIN.toString(),
SERVER_ARG);
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class",
"bin/alfa/omega/AA.class",
"bin/javac_state");
BIN + "/alfa/omega/A.class",
BIN + "/alfa/omega/AA.class",
BIN + "/javac_state");
clean(GENSRC, BIN);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,7 +25,6 @@ import java.util.*;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.charset.*;
import com.sun.tools.sjavac.Main;
@ -35,16 +34,18 @@ public class SJavacTester {
+ "portfile=testportfile,"
+ "background=false";
final Path TEST_ROOT = Paths.get(getClass().getSimpleName());
// Generated sources that will test aspects of sjavac
static final Path GENSRC = Paths.get("gensrc");
final Path GENSRC = TEST_ROOT.resolve("gensrc");
// Gensrc dirs used to test merging of serveral source roots.
static final Path GENSRC2 = Paths.get("gensrc2");
static final Path GENSRC3= Paths.get("gensrc3");
final Path GENSRC2 = TEST_ROOT.resolve("gensrc2");
final Path GENSRC3 = TEST_ROOT.resolve("gensrc3");
// Dir for compiled classes.
static final Path BIN = Paths.get("bin");
final Path BIN = TEST_ROOT.resolve("bin");
// Dir for c-header files.
Path HEADERS = Paths.get("headers");
final Path HEADERS = TEST_ROOT.resolve("headers");
// Remember the previous bin and headers state here.
Map<String,Long> previous_bin_state;
@ -54,10 +55,10 @@ public class SJavacTester {
System.out.println("\nInitial compile of gensrc.");
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("alfa/omega/AINT.java"),
"package alfa.omega; public interface AINT { void aint(); }");
"package alfa.omega; public interface AINT { void aint(); }");
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A implements AINT { "+
"public final static int DEFINITION = 17; public void aint() { } }");
"package alfa.omega; public class A implements AINT { "+
"public final static int DEFINITION = 17; public void aint() { } }");
tb.writeFile(GENSRC.resolve("alfa/omega/AA.java"),
"package alfa.omega;"+
"// A package private class, not contributing to the public api.\n"+
@ -79,13 +80,17 @@ public class SJavacTester {
" // from outside of this source file, therefore it is ok.\n"+
"}\n");
tb.writeFile(GENSRC.resolve("beta/BINT.java"),
"package beta;public interface BINT { void foo(); }");
"package beta;public interface BINT { void foo(); }");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; import alfa.omega.A; public class B {"+
"private int b() { return A.DEFINITION; } native void foo(); }");
"package beta; import alfa.omega.A; public class B {"+
"private int b() { return A.DEFINITION; } native void foo(); }");
compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
SERVER_ARG, "--log=debug");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"-j", "1",
SERVER_ARG,
"--log=debug");
}
void removeFrom(Path dir, String... args) throws IOException {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -37,7 +37,7 @@ public class SjavacBase {
*/
public static int compile(Object... args) throws ReflectiveOperationException {
// Use reflection to avoid a compile-time dependency on sjavac Main
System.err.println("compile: " + Arrays.toString(args));
System.out.println("compile: " + Arrays.toString(args));
Class<?> c = Class.forName("com.sun.tools.sjavac.Main");
Method m = c.getDeclaredMethod("go", String[].class);
String[] strArgs = new String[args.length];

@ -48,28 +48,29 @@ public class StateDir extends SJavacTester {
}
void test() throws Exception {
Path bar = Paths.get("bar");
Files.createDirectory(bar);
Files.createDirectory(BIN);
clean(GENSRC, BIN, bar);
clean(TEST_ROOT);
Path BAR = TEST_ROOT.resolve("bar");
Files.createDirectories(BAR);
Files.createDirectories(BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
Map<String,Long> previous_bar_state = collectState(bar);
Map<String,Long> previous_bar_state = collectState(BAR);
ToolBox tb = new ToolBox();
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A { }");
"package alfa.omega; public class A { }");
compile("--state-dir=bar", "-src", "gensrc", "-d", "bin",
compile("--state-dir=" + BAR,
"-src", GENSRC.toString(),
"-d", BIN.toString(),
SJavacTester.SERVER_ARG);
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
"bin/alfa/omega/A.class");
Map<String,Long> new_bar_state = collectState(bar);
BIN + "/alfa/omega/A.class");
Map<String,Long> new_bar_state = collectState(BAR);
verifyThatFilesHaveBeenAdded(previous_bar_state, new_bar_state,
"bar/javac_state");
clean(GENSRC, BIN, bar);
BAR + "/javac_state");
clean(GENSRC, BIN, BAR);
}
}

@ -1,28 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package nondependency.pkg26;
public class Cls26 {
}

@ -1,74 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// Use fully qualified names to avoid accidentally capturing dependencies in import statements.
package pkg;
import pkg2.*; // pkg2 as a whole
import pkg3.Cls3; // pkg3.Cls3
import pkg25.Cls25; // pkg25.Cls25
import nondependency.pkg26.Cls26; // pkg26.Cls26 (but not nondependency)
import pkg28.Cls28.Inner28; // pkg29.Cls28, pkg29.Cls28.Inner28
import static pkg29.Cls29.Inner29; // pkg29.Cls29, pkg29.Cls29.Inner29
import static pkg30.Cls30.*; // pkg30.Cls30 as a whole
@pkg5.Anno5 // pkg5.Anno5
public class Test<S extends pkg23.Cls23> // pkg23.Cls23
extends pkg4.Cls4/*extends pkg11.Cls11*/<pkg6.Cls6/*extends pkg12.Cls12*/> // pkg4.Cls4, pkg11.Cls11, pkg6.Cls6, pkg12.Cls12
implements pkg7.Cls7, pkg8.Cls8<pkg9.Cls9> { // pkg7.Cls7, pkg8.Cls8, pkg9.Cls9
pkg27.Cls27 cls27[][][] = new pkg27.Cls27[0][0][0]; // pkg27.Cls27
pkg2.Cls2 cls2;
pkg19.Cls19 f19; // pkg19.Cls19
public static void main(String[] args) { // java.lang.String
pkg10.Cls10 o = new pkg10.Cls10(); // pkg10.Cls10
o.getCls13().getCls14().getCls15(); // pkg13.Cls13, pkg14.Cls14, pkg15.Cls15
pkg23.Cls23.f24 = null; // pkg23.Cls23, pkg24.Cls24
}
static pkg16.Cls16 m1(pkg17.Cls17 o) { // pkg16.Cls16, pkg17.Cls17
return null;
}
public <T extends pkg18.Cls18> void m2() { // pkg18.Cls18
}
public <T> T m3() {
T t;
t = null;
return t;
}
@pkg20.Anno20(pkg21.Cls21.class) // pkg20.Anno20, pkg21.Cls21
private void m3(@pkg22.Anno22 String s) { // pkg22.Anno22
Runnable r = () -> { System.out.println("hello"); };
}
private void m4() throws Cls25 { // pkg25.Cls25
}
}

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg11; public class Cls11 { }

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg12; public class Cls12 { }

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg15; public class Cls15 { }

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg16; public class Cls16 { }

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg17; public class Cls17 { }

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg18; public class Cls18 { }

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg19; public class Cls19 { }

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg2; public class Cls2 { }

@ -1,28 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg20;
public @interface Anno20 {
Class<?> value();
}

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg21; public class Cls21 { }

@ -1,27 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg22;
public @interface Anno22 {
}

@ -1,28 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg23;
public class Cls23 {
public static pkg24.Cls24 f24;
}

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg24; public class Cls24 { }

@ -1,28 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg25;
public class Cls25 extends Throwable {
}

@ -1,26 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg27;
public class Cls27 {}

@ -1,28 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg28;
public class Cls28 {
public static class Inner28 {}
}

@ -1,28 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg29;
public class Cls29 {
public static class Inner29 {}
}

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg3; public class Cls3 { }

@ -1,28 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg30;
public class Cls30 {
}

@ -1,27 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg4;
public class Cls4<T> extends pkg11.Cls11 {
}

@ -1,27 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg5;
public @interface Anno5 {
}

@ -1,27 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg6;
public class Cls6 extends pkg12.Cls12 {
}

@ -1,27 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg7;
public interface Cls7 {
}

@ -1,27 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg8;
public interface Cls8<T> {
}

@ -1,25 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package pkg9; public class Cls9 { }