8297041: Remove the last remnants of sjavac

Reviewed-by: cstein, erikj, jjg
This commit is contained in:
Magnus Ihse Bursie 2022-11-17 09:20:22 +00:00
parent 636040f875
commit 4527dc67be
112 changed files with 707 additions and 11208 deletions

View File

@ -90,7 +90,7 @@
<li><a href="#ccache">Ccache</a></li>
<li><a href="#precompiled-headers">Precompiled Headers</a></li>
<li><a href="#icecc-icecream">Icecc / icecream</a></li>
<li><a href="#using-sjavac">Using sjavac</a></li>
<li><a href="#using-the-javac-server">Using the javac server</a></li>
<li><a href="#building-the-right-target">Building the Right Target</a></li>
</ul></li>
<li><a href="#troubleshooting">Troubleshooting</a><ul>
@ -819,8 +819,8 @@ ls build/linux-aarch64-server-release/</code></pre></li>
<h3 id="icecc-icecream">Icecc / icecream</h3>
<p><a href="http://github.com/icecc/icecream">icecc/icecream</a> is a simple way to setup a distributed compiler network. If you have multiple machines available for building the JDK, you can drastically cut individual build times by utilizing it.</p>
<p>To use, setup an icecc network, and install icecc on the build machine. Then run <code>configure</code> using <code>--enable-icecc</code>.</p>
<h3 id="using-sjavac">Using sjavac</h3>
<p>To speed up compilation of Java code, especially during incremental compilations, the sjavac server is automatically enabled in the configuration step by default. To explicitly enable or disable sjavac, use either <code>--enable-javac-server</code> or <code>--disable-javac-server</code>.</p>
<h3 id="using-the-javac-server">Using the javac server</h3>
<p>To speed up compilation of Java code, especially during incremental compilations, the javac server is automatically enabled in the configuration step by default. To explicitly enable or disable the javac server, use either <code>--enable-javac-server</code> or <code>--disable-javac-server</code>.</p>
<h3 id="building-the-right-target">Building the Right Target</h3>
<p>Selecting the proper target to build can have dramatic impact on build time. For normal usage, <code>jdk</code> or the default target is just fine. You only need to build <code>images</code> for shipping, or if your tests require it.</p>
<p>See also <a href="#using-fine-grained-make-targets">Using Fine-Grained Make Targets</a> on how to build an even smaller subset of the product.</p>

View File

@ -1333,12 +1333,12 @@ it.
To use, setup an icecc network, and install icecc on the build machine. Then
run `configure` using `--enable-icecc`.
### Using sjavac
### Using the javac server
To speed up compilation of Java code, especially during incremental compilations,
the sjavac server is automatically enabled in the configuration step by default.
To explicitly enable or disable sjavac, use either `--enable-javac-server`
or `--disable-javac-server`.
To speed up compilation of Java code, especially during incremental
compilations, the javac server is automatically enabled in the configuration
step by default. To explicitly enable or disable the javac server, use either
`--enable-javac-server` or `--disable-javac-server`.
### Building the Right Target

View File

@ -125,5 +125,20 @@ $(foreach m, $(INTERIM_LANGTOOLS_BASE_MODULES), \
)
################################################################################
# Setup the compilation of the javac server build tool. Technically, this is not
# really "interim" langtools, but just like it, it is needed henceforth for all
# java compilation using the interim compiler.
$(eval $(call SetupJavaCompilation, BUILD_JAVAC_SERVER, \
COMPILER := bootjdk, \
TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \
SRC := $(TOPDIR)/make/langtools/tools, \
INCLUDES := javacserver, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/langtools_javacserver_classes, \
))
TARGETS += $(BUILD_JAVAC_SERVER)
################################################################################
all: $(TARGETS)

View File

@ -324,7 +324,7 @@ else # HAS_SPEC=true
ifneq ($(PARALLEL_TARGETS), )
$(call PrepareFailureLogs)
$(call StartGlobalTimer)
$(call PrepareSmartJavac)
$(call PrepareJavacServer)
# JOBS will only be empty for a bootcycle-images recursive call
# or if specified via a make argument directly. In those cases
# treat it as NOT using jobs at all.
@ -339,7 +339,7 @@ else # HAS_SPEC=true
cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -j 1 -f make/Init.gmk \
HAS_SPEC=true on-failure ; \
exit $$exitcode ) )
$(call CleanupSmartJavac)
$(call CleanupJavacServer)
$(call StopGlobalTimer)
$(call ReportBuildTimes)
endif
@ -351,7 +351,7 @@ else # HAS_SPEC=true
endif
on-failure:
$(call CleanupSmartJavac)
$(call CleanupJavacServer)
$(call StopGlobalTimer)
$(call ReportBuildTimes)
$(call PrintFailureReports)
@ -364,11 +364,11 @@ else # HAS_SPEC=true
# Support targets for COMPARE_BUILD, used for makefile development
pre-compare-build:
$(call WaitForSmartJavacFinish)
$(call WaitForJavacServerFinish)
$(call PrepareCompareBuild)
post-compare-build:
$(call WaitForSmartJavacFinish)
$(call WaitForJavacServerFinish)
$(call CleanupCompareBuild)
$(call CompareBuildDoComparison)

View File

@ -493,15 +493,15 @@ else # $(HAS_SPEC)=true
# Remove any javac server logs and port files. This
# prevents a new make run to reuse the previous servers.
define PrepareSmartJavac
define PrepareJavacServer
$(if $(JAVAC_SERVER_DIR), \
$(RM) -r $(JAVAC_SERVER_DIR) 2> /dev/null && \
$(MKDIR) -p $(JAVAC_SERVER_DIR) \
)
endef
define CleanupSmartJavac
[ -f $(JAVAC_SERVER_DIR)/server.port ] && $(ECHO) Stopping sjavac server && \
define CleanupJavacServer
[ -f $(JAVAC_SERVER_DIR)/server.port ] && $(ECHO) Stopping javac server && \
$(TOUCH) $(JAVAC_SERVER_DIR)/server.port.stop; true
endef
@ -510,13 +510,13 @@ else # $(HAS_SPEC)=true
# move or remove the build output directory. Since we have no proper
# synchronization process, wait for a while and hope it helps. This is only
# used by build comparisons.
define WaitForSmartJavacFinish
define WaitForJavacServerFinish
$(if $(JAVAC_SERVER_DIR), \
sleep 5\
)
endef
else
define WaitForSmartJavacFinish
define WaitForJavacServerFinish
endef
endif

View File

@ -219,7 +219,7 @@ define SetupJavaCompilationBody
# Use java server if it is enabled, and the user does not want a specialized
# class path.
ifeq ($$(ENABLE_JAVAC_SERVER)+$$($1_CLASSPATH), true+)
$1_JAVAC := $$(INTERIM_LANGTOOLS_ARGS) -m jdk.compiler.interim/com.sun.tools.sjavac.Main
$1_JAVAC := $$(INTERIM_LANGTOOLS_ARGS) -cp $(BUILDTOOLS_OUTPUTDIR)/langtools_javacserver_classes javacserver.Main
# Create a configuration file with the needed information for the javac
# server to function properly.

View File

@ -1,22 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="sjavac" type="Application" factoryName="Application">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="MAIN_CLASS_NAME" value="com.sun.tools.sjavac.Main" />
<option name="VM_PARAMETERS" value='@XPATCH@ --add-exports=jdk.compiler/com.sun.tools.sjavac=ALL-UNNAMED' />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
<option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<module name="langtools" />
<envs />
<RunnerSettings RunnerId="Run" />
<ConfigurationWrapper RunnerId="Run" />
<method>
<option name="Make" enabled="false" />
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/make/ide/idea/langtools/build.xml" target="build-all-classes" />
</method>
</configuration>
</component>

View File

@ -59,7 +59,6 @@ full.version = ${release}+${build.number}
tool.javac.main.class=com.sun.tools.javac.Main
tool.javadoc.main.class=jdk.javadoc.internal.tool.Main
tool.javap.main.class=com.sun.tools.javap.Main
tool.sjavac.main.class=com.sun.tools.sjavac.Main
tool.jshell.main.class=jdk.internal.jshell.tool.JShellToolProvider
#test configuration:

View File

@ -238,7 +238,6 @@
<build-tool name="javadoc"/>
<build-tool name="javap"/>
<build-tool name="jdeps"/>
<build-tool name="sjavac"/>
<build-tool name="jshell"/>
</target>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, 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
@ -23,7 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac;
package javacserver;
import java.io.FilterWriter;
import java.io.IOException;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@ -23,7 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac;
package javacserver;
import java.io.PrintWriter;
import java.io.StringWriter;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@ -23,14 +23,14 @@
* questions.
*/
package com.sun.tools.sjavac;
import static com.sun.tools.sjavac.options.Option.STARTSERVER;
package javacserver;
import java.util.Arrays;
import com.sun.tools.sjavac.client.ClientMain;
import com.sun.tools.sjavac.server.ServerMain;
import javacserver.client.ClientMain;
import javacserver.server.ServerMain;
import static javacserver.options.Option.STARTSERVER;
/**
* The application entry point of the smart javac wrapper tool.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2021, 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
@ -23,33 +23,34 @@
* questions.
*/
package com.sun.tools.sjavac.comp;
package javacserver;
import javax.tools.FileObject;
import javax.tools.ForwardingFileObject;
import javax.tools.JavaFileManager.Location;
/** Result codes.
*/
public enum Result {
OK(0), // Compilation completed with no errors.
ERROR(1), // Completed but reported errors.
CMDERR(2), // Bad command-line arguments
SYSERR(3), // System error or resource exhaustion.
ABNORMAL(4); // Compiler terminated abnormally
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;
Result(int exitCode) {
this.exitCode = exitCode;
}
public Location getLocation() {
return loc;
public static Result of(int exitcode) {
for (Result result : values()) {
if (result.exitCode == exitcode) {
return result;
}
}
return ABNORMAL;
}
public FileObject getDelegate() {
return fileObject;
public boolean isOK() {
return (exitCode == 0);
}
public String toString() {
return "FileObjectWithLocation[" + fileObject + "]";
}
public final int exitCode;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@ -23,21 +23,15 @@
* questions.
*/
package com.sun.tools.sjavac;
package javacserver;
import java.io.File;
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.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@ -50,30 +44,7 @@ import java.util.stream.Stream;
*/
public class Util {
public static String toFileSystemPath(String pkgId) {
if (pkgId == null || pkgId.length()==0) return null;
String pn;
if (pkgId.charAt(0) == ':') {
// When the module is the default empty module.
// Do not prepend the module directory, because there is none.
// Thus :java.foo.bar translates to java/foo/bar (or \)
pn = pkgId.substring(1).replace('.',File.separatorChar);
} else {
// There is a module. Thus jdk.base:java.foo.bar translates
// into jdk.base/java/foo/bar
int cp = pkgId.indexOf(':');
String mn = pkgId.substring(0,cp);
pn = mn+File.separatorChar+pkgId.substring(cp+1).replace('.',File.separatorChar);
}
return pn;
}
public static String justPackageName(String pkgName) {
int c = pkgName.indexOf(":");
if (c == -1)
throw new IllegalArgumentException("Expected ':' in package name (" + pkgName + ")");
return pkgName.substring(c+1);
}
public static String extractStringOption(String opName, String s) {
return extractStringOption(opName, s, null);
@ -96,17 +67,6 @@ public class Util {
return extractStringOptionWithDelimiter(opName, s, deflt, '\n').strip();
}
public static boolean extractBooleanOption(String opName, String s, boolean deflt) {
String str = extractStringOption(opName, s);
return "true".equals(str) ? true
: "false".equals(str) ? false
: deflt;
}
public static int extractIntOption(String opName, String s) {
return extractIntOption(opName, s, 0);
}
public static int extractIntOption(String opName, String s, int deflt) {
int p = s.indexOf(opName+"=");
if (p == -1) return deflt;
@ -120,47 +80,6 @@ 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:
* settings="--server:id=foo,portfile=bar"
* do settings = cleanOptions("--server:",Util.set("-portfile"),settings);
* now settings equals "--server:portfile=bar"
*
* @param allowedSubOptions A set of the allowed sub options, id portfile etc.
* @param s The option settings string.
*/
public static String cleanSubOptions(Set<String> allowedSubOptions, String s) {
StringBuilder sb = new StringBuilder();
StringTokenizer st = new StringTokenizer(s, ",");
while (st.hasMoreTokens()) {
String o = st.nextToken();
int p = o.indexOf('=');
if (p>0) {
String key = o.substring(0,p);
String val = o.substring(p+1);
if (allowedSubOptions.contains(key)) {
if (sb.length() > 0) sb.append(',');
sb.append(key+"="+val);
}
}
}
return sb.toString();
}
/**
* Convenience method to create a set with strings.
@ -191,17 +110,6 @@ public class Util {
return file;
}
/**
* Locate the setting for the server properties.
*/
public static String findServerSettings(String[] args) {
for (String s : args) {
if (s.startsWith("--server:")) {
return s;
}
}
return null;
}
public static <E> Set<E> union(Set<? extends E> s1,
Set<? extends E> s2) {
@ -224,11 +132,6 @@ public class Util {
return sw.toString();
}
// TODO: Remove when refactoring from java.io.File to java.nio.file.Path.
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);
@ -236,16 +139,6 @@ public class Util {
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.<T, I, T>toMap(indexFunction, o -> o));
}
public static String fileSuffix(Path file) {
String fileNameStr = file.getFileName().toString();
int dotIndex = fileNameStr.indexOf('.');
return dotIndex == -1 ? "" : fileNameStr.substring(dotIndex);
}
public static Stream<String> getLines(String str) {
return str.isEmpty()

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,19 +23,17 @@
* questions.
*/
package com.sun.tools.sjavac.client;
package javacserver.client;
import java.io.OutputStreamWriter;
import java.io.Writer;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.AutoFlushWriter;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.comp.SjavacImpl;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.server.Sjavac;
import javacserver.AutoFlushWriter;
import javacserver.Log;
import javacserver.Result;
import javacserver.comp.SjavacImpl;
import javacserver.options.Options;
import javacserver.server.Sjavac;
/**
* <p><b>This is NOT part of any supported API.
@ -65,11 +63,6 @@ public class ClientMain {
Log.setLogLevel(options.getLogLevel());
Log.debug("==========================================================");
Log.debug("Launching sjavac client with the following parameters:");
Log.debug(" " + options.getStateArgsString());
Log.debug("==========================================================");
// Prepare sjavac object
boolean useServer = options.getServerConf() != null;
Sjavac sjavac = useServer ? new SjavacClient(options) : new SjavacImpl();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, 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
@ -23,7 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac.client;
package javacserver.client;
import java.io.IOException;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,7 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac.client;
package javacserver.client;
import java.io.BufferedReader;
import java.io.IOException;
@ -40,14 +40,13 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.server.PortFile;
import com.sun.tools.sjavac.server.Sjavac;
import com.sun.tools.sjavac.server.SjavacServer;
import javacserver.Log;
import javacserver.Result;
import javacserver.Util;
import javacserver.options.Options;
import javacserver.server.PortFile;
import javacserver.server.Sjavac;
import javacserver.server.SjavacServer;
/**
* Sjavac implementation that delegates requests to a SjavacServer.
@ -62,7 +61,7 @@ public class SjavacClient implements Sjavac {
private PortFile portFile;
// The servercmd option specifies how the server part of sjavac is spawned.
// It should point to a com.sun.tools.sjavac.Main that supports --startserver
// It should point to a javacserver.Main that supports --startserver
private String serverCommand;
// Accept 120 seconds of inactivity before quitting.
@ -144,7 +143,7 @@ public class SjavacClient implements Sjavac {
}
if (type.equals(SjavacServer.LINE_TYPE_RC)) {
result = Main.Result.valueOf(content);
result = Result.valueOf(content);
}
}
} catch (PortFileInaccessibleException e) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,17 +23,17 @@
* questions.
*/
package com.sun.tools.sjavac.comp;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.server.Sjavac;
package javacserver.comp;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javacserver.Log;
import javacserver.Result;
import javacserver.server.Sjavac;
/**
* An sjavac implementation that limits the number of concurrent calls by
* wrapping invocations in Callables and delegating them to a FixedThreadPool.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,57 +23,56 @@
* questions.
*/
package com.sun.tools.sjavac.comp;
package javacserver.comp;
import com.sun.tools.sjavac.Log;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.stream.Stream;
import java.io.*;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.Main;
import javacserver.Log;
import javacserver.Result;
import javacserver.Util;
import javacserver.options.Option;
import javacserver.server.Sjavac;
/**
* The SmartWriter will cache the written data and when the writer is closed,
* then it will compare the cached data with the old_content string.
* If different, then it will write all the new content to the file.
* If not, the file is not touched.
* The sjavac implementation that interacts with javac and performs the actual
* compilation.
*
* <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 SmartWriter extends Writer {
public class SjavacImpl implements Sjavac {
String name;
JavaFileObject file;
String oldContent;
StringWriter newContent = new StringWriter();
boolean closed;
@Override
@SuppressWarnings("deprecated")
public Result compile(String[] args) {
// Direct logging to our byte array stream.
StringWriter strWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(strWriter);
// Prepare arguments
String[] passThroughArgs = Stream.of(args)
.filter(arg -> !arg.startsWith(Option.SERVER.arg))
.toArray(String[]::new);
// Compile
int exitcode = Main.compile(passThroughArgs, printWriter);
Result result = Result.of(exitcode);
// Process compiler output (which is always errors)
printWriter.flush();
Util.getLines(strWriter.toString()).forEach(Log::error);
return result;
public SmartWriter(JavaFileObject f, String s, String n) {
name = n;
file = f;
oldContent = s;
newContent = new StringWriter();
closed = false;
}
public void write(char[] chars, int i, int i1) {
newContent.write(chars, i, i1);
}
public void close() throws IOException {
if (closed) return;
closed = true;
String s = newContent.toString();
if (!oldContent.equals(s)) {
int p = file.getName().lastIndexOf(File.separatorChar);
try (Writer writer = file.openWriter()) {
writer.write(s);
}
Log.debug("Writing " + file.getName().substring(p + 1));
}
}
public void flush() throws IOException {
@Override
public void shutdown() {
// Nothing to clean up
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,7 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac.options;
package javacserver.options;
import java.util.Iterator;

View File

@ -0,0 +1,294 @@
/*
* Copyright (c) 1999, 2022, 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 javacserver.options;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
/**
* Various utility methods for processing Java tool command line arguments.
*
* <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 CommandLine {
/**
* Process Win32-style command files for the specified command line
* arguments and return the resulting arguments. A command file argument
* is of the form '@file' where 'file' is the name of the file whose
* contents are to be parsed for additional arguments. The contents of
* the command file are parsed using StreamTokenizer and the original
* '@file' argument replaced with the resulting tokens. Recursive command
* files are not supported. The '@' character itself can be quoted with
* the sequence '@@'.
* @param args the arguments that may contain @files
* @return the arguments, with @files expanded
* @throws IOException if there is a problem reading any of the @files
*/
public static List<String> parse(List<String> args) throws IOException {
List<String> newArgs = new ArrayList<>();
appendParsedCommandArgs(newArgs, args);
return newArgs;
}
private static void appendParsedCommandArgs(List<String> newArgs, List<String> args) throws IOException {
for (String arg : args) {
if (arg.length() > 1 && arg.charAt(0) == '@') {
arg = arg.substring(1);
if (arg.charAt(0) == '@') {
newArgs.add(arg);
} else {
loadCmdFile(arg, newArgs);
}
} else {
newArgs.add(arg);
}
}
}
/**
* Process the given environment variable and appends any Win32-style
* command files for the specified command line arguments and return
* the resulting arguments. A command file argument
* is of the form '@file' where 'file' is the name of the file whose
* contents are to be parsed for additional arguments. The contents of
* the command file are parsed using StreamTokenizer and the original
* '@file' argument replaced with the resulting tokens. Recursive command
* files are not supported. The '@' character itself can be quoted with
* the sequence '@@'.
* @param envVariable the env variable to process
* @param args the arguments that may contain @files
* @return the arguments, with environment variable's content and expansion of @files
* @throws IOException if there is a problem reading any of the @files
* @throws UnmatchedQuote
*/
public static List<String> parse(String envVariable, List<String> args)
throws IOException, UnmatchedQuote {
List<String> inArgs = new ArrayList<>();
appendParsedEnvVariables(inArgs, envVariable);
inArgs.addAll(args);
List<String> newArgs = new ArrayList<>();
appendParsedCommandArgs(newArgs, inArgs);
return newArgs;
}
private static void loadCmdFile(String name, List<String> args) throws IOException {
try (Reader r = Files.newBufferedReader(Paths.get(name), Charset.defaultCharset())) {
Tokenizer t = new Tokenizer(r);
String s;
while ((s = t.nextToken()) != null) {
args.add(s);
}
}
}
public static class Tokenizer {
private final Reader in;
private int ch;
public Tokenizer(Reader in) throws IOException {
this.in = in;
ch = in.read();
}
public String nextToken() throws IOException {
skipWhite();
if (ch == -1) {
return null;
}
StringBuilder sb = new StringBuilder();
char quoteChar = 0;
while (ch != -1) {
switch (ch) {
case ' ':
case '\t':
case '\f':
if (quoteChar == 0) {
return sb.toString();
}
sb.append((char) ch);
break;
case '\n':
case '\r':
return sb.toString();
case '\'':
case '"':
if (quoteChar == 0) {
quoteChar = (char) ch;
} else if (quoteChar == ch) {
quoteChar = 0;
} else {
sb.append((char) ch);
}
break;
case '\\':
if (quoteChar != 0) {
ch = in.read();
switch (ch) {
case '\n':
case '\r':
while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') {
ch = in.read();
}
continue;
case 'n':
ch = '\n';
break;
case 'r':
ch = '\r';
break;
case 't':
ch = '\t';
break;
case 'f':
ch = '\f';
break;
}
}
sb.append((char) ch);
break;
default:
sb.append((char) ch);
}
ch = in.read();
}
return sb.toString();
}
void skipWhite() throws IOException {
while (ch != -1) {
switch (ch) {
case ' ':
case '\t':
case '\n':
case '\r':
case '\f':
break;
case '#':
ch = in.read();
while (ch != '\n' && ch != '\r' && ch != -1) {
ch = in.read();
}
break;
default:
return;
}
ch = in.read();
}
}
}
@SuppressWarnings("fallthrough")
private static void appendParsedEnvVariables(List<String> newArgs, String envVariable)
throws UnmatchedQuote {
if (envVariable == null) {
return;
}
String in = System.getenv(envVariable);
if (in == null || in.trim().isEmpty()) {
return;
}
final char NUL = (char)0;
final int len = in.length();
int pos = 0;
StringBuilder sb = new StringBuilder();
char quote = NUL;
char ch;
loop:
while (pos < len) {
ch = in.charAt(pos);
switch (ch) {
case '\"': case '\'':
if (quote == NUL) {
quote = ch;
} else if (quote == ch) {
quote = NUL;
} else {
sb.append(ch);
}
pos++;
break;
case '\f': case '\n': case '\r': case '\t': case ' ':
if (quote == NUL) {
newArgs.add(sb.toString());
sb.setLength(0);
while (ch == '\f' || ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') {
pos++;
if (pos >= len) {
break loop;
}
ch = in.charAt(pos);
}
break;
}
// fall through
default:
sb.append(ch);
pos++;
}
}
if (sb.length() != 0) {
newArgs.add(sb.toString());
}
if (quote != NUL) {
throw new UnmatchedQuote(envVariable);
}
}
public static class UnmatchedQuote extends Exception {
private static final long serialVersionUID = 0;
public final String variableName;
UnmatchedQuote(String variable) {
this.variableName = variable;
}
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2014, 2022, 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 javacserver.options;
/**
* Sjavac options can be classified as:
*
* (1) relevant only for sjavac, such as --server
* (2) relevant for sjavac and javac, such as -d, or
* (3) relevant only for javac, such as -g.
*
* This enum represents all options from (1) and (2). Note that instances of
* this enum only entail static information about the option. For storage of
* option values, refer to Options.
*
* <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 enum Option {
SERVER("--server:", "Specify server configuration file of running server") {
@Override
protected void processMatching(ArgumentIterator iter, Options.ArgDecoderOptionHelper helper) {
helper.serverConf(iter.current().substring(arg.length()));
}
},
STARTSERVER("--startserver:", "Start server and use the given configuration file") {
@Override
protected void processMatching(ArgumentIterator iter, Options.ArgDecoderOptionHelper helper) {
helper.startServerConf(iter.current().substring(arg.length()));
}
};
public final String arg;
final String description;
private Option(String arg, String description) {
this.arg = arg;
this.description = description;
}
// Future cleanup: Change the "=" syntax to ":" syntax to be consistent and
// to follow the javac-option style.
public boolean hasOption() {
return arg.endsWith(":") || arg.endsWith("=");
}
/**
* Process current argument of argIter.
*
* It's final, since the option customization is typically done in
* processMatching.
*
* @param argIter Iterator to read current and succeeding arguments from.
* @param helper The helper to report back to.
* @return true iff the argument was processed by this option.
*/
public final boolean processCurrent(ArgumentIterator argIter,
Options.ArgDecoderOptionHelper helper) {
String fullArg = argIter.current(); // "-tr" or "-log=level"
if (hasOption() ? fullArg.startsWith(arg) : fullArg.equals(arg)) {
processMatching(argIter, helper);
return true;
}
// Did not match
return false;
}
/** Called by process if the current argument matches this option. */
protected abstract void processMatching(ArgumentIterator argIter,
Options.ArgDecoderOptionHelper helper);
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2014, 2022, 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 javacserver.options;
import java.util.List;
/**
* Instances of this class represent values for sjavac command line options.
*
* <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 Options {
private String logLevel = "info";
private boolean startServer = false;
// Server configuration string
private String serverConf;
/** Get the log level. */
public String getLogLevel() {
return logLevel;
}
/** Return true iff a new server should be started */
public boolean startServerFlag() {
return startServer;
}
/** Return the server configuration string. */
public String getServerConf() {
return serverConf;
}
/**
* Parses the given argument array and returns a corresponding Options
* instance.
*/
public static Options parseArgs(String... args) {
Options options = new Options();
options.new ArgDecoderOptionHelper().traverse(args);
return options;
}
// OptionHelper that records the traversed options in this Options instance.
public class ArgDecoderOptionHelper {
public void reportError(String msg) {
throw new IllegalArgumentException(msg);
}
public void serverConf(String conf) {
if (serverConf != null)
reportError("Can not specify more than one server configuration.");
else
serverConf = conf;
}
public void startServerConf(String conf) {
if (serverConf != null)
reportError("Can not specify more than one server configuration.");
else {
startServer = true;
serverConf = conf;
}
}
/**
* Traverses an array of arguments and performs the appropriate callbacks.
*
* @param args the arguments to traverse.
*/
void traverse(String[] args) {
Iterable<String> allArgs;
try {
allArgs = CommandLine.parse(List.of(args)); // Detect @file and load it as a command line.
} catch (java.io.IOException e) {
throw new IllegalArgumentException("Problem reading @"+e.getMessage());
}
ArgumentIterator argIter = new ArgumentIterator(allArgs);
nextArg:
while (argIter.hasNext()) {
String arg = argIter.next();
if (arg.startsWith("-")) {
for (Option opt : Option.values()) {
if (opt.processCurrent(argIter, this))
continue nextArg;
}
}
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,14 +23,14 @@
* questions.
*/
package com.sun.tools.sjavac.server;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.Log;
package javacserver.server;
import java.util.Timer;
import java.util.TimerTask;
import javacserver.Log;
import javacserver.Result;
/**
* An sjavac implementation that keeps track of idleness and shuts down the
* given Terminable upon idleness timeout.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@ -23,7 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac.server;
package javacserver.server;
import java.io.File;
import java.io.FileNotFoundException;
@ -35,9 +35,8 @@ import java.nio.channels.FileLock;
import java.nio.channels.FileLockInterruptionException;
import java.util.concurrent.Semaphore;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.client.PortFileInaccessibleException;
import javacserver.Log;
import javacserver.client.PortFileInaccessibleException;
/**
* The PortFile class mediates access to a short binary file containing the tcp/ip port (for the localhost)
@ -151,7 +150,6 @@ public class PortFile {
* If so, then we can acquire the tcp/ip port on localhost.
*/
public int getPort() {
Assert.check(containsPortInfo);
return serverPort;
}
@ -159,7 +157,6 @@ public class PortFile {
* If so, then we can acquire the server cookie.
*/
public long getCookie() {
Assert.check(containsPortInfo);
return serverCookie;
}
@ -167,7 +164,6 @@ public class PortFile {
* Store the values into the locked port file.
*/
public void setValues(int port, long cookie) throws IOException {
Assert.check(lock != null);
rwfile.seek(0);
// Write the magic nr that identifies a port file.
rwfile.writeInt(magicNr);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,14 +23,14 @@
* questions.
*/
package com.sun.tools.sjavac.server;
import com.sun.tools.sjavac.Log;
package javacserver.server;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javacserver.Log;
/**
* Monitors the presence of a port file and shuts down the given SjavacServer
* whenever the port file is deleted or invalidated.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,11 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac.server;
import com.sun.tools.javac.main.Main;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Util;
package javacserver.server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@ -35,7 +31,11 @@ import java.io.PrintWriter;
import java.net.Socket;
import java.nio.file.Path;
import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_RC;
import javacserver.Log;
import javacserver.Result;
import javacserver.Util;
import static javacserver.server.SjavacServer.LINE_TYPE_RC;
/**
@ -101,7 +101,7 @@ public class RequestHandler extends Thread {
checkInternalErrorLog();
// Perform compilation
Main.Result rc = sjavac.compile(args);
Result rc = sjavac.compile(args);
// Send return code back to client
out.println(LINE_TYPE_RC + ":" + rc.name());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,24 +23,18 @@
* questions.
*/
package com.sun.tools.sjavac.server;
package javacserver.server;
import java.io.FileWriter;
import java.io.FilterOutputStream;
import java.io.FilterWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Log.Level;
import com.sun.tools.sjavac.server.log.LazyInitFileLog;
import com.sun.tools.sjavac.server.log.LoggingOutputStream;
import javacserver.Log;
import javacserver.Result;
import javacserver.server.log.LazyInitFileLog;
import javacserver.server.log.LoggingOutputStream;
import static com.sun.tools.sjavac.Log.Level.ERROR;
import static com.sun.tools.sjavac.Log.Level.INFO;
import static javacserver.Log.Level.ERROR;
import static javacserver.Log.Level.INFO;
/**
* <p><b>This is NOT part of any supported API.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,12 +23,9 @@
* questions.
*/
package com.sun.tools.sjavac.server;
import com.sun.tools.javac.main.Main.Result;
import java.io.Writer;
package javacserver.server;
import javacserver.Result;
/**
* Interface of the SjavacImpl, the sjavac client and all wrappers such as

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022, 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
@ -23,13 +23,10 @@
* questions.
*/
package com.sun.tools.sjavac.server;
package javacserver.server;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@ -40,13 +37,11 @@ import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.client.PortFileInaccessibleException;
import com.sun.tools.sjavac.comp.PooledSjavac;
import com.sun.tools.sjavac.comp.SjavacImpl;
import javacserver.Log;
import javacserver.Result;
import javacserver.Util;
import javacserver.comp.PooledSjavac;
import javacserver.comp.SjavacImpl;
/**
* The JavacServer class contains methods both to setup a server that responds to requests and methods to connect to this server.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2022, 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
@ -23,7 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac.server;
package javacserver.server;
/**
* <p><b>This is NOT part of any supported API.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, 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
@ -23,9 +23,7 @@
* questions.
*/
package com.sun.tools.sjavac.server.log;
import com.sun.tools.sjavac.Log;
package javacserver.server.log;
import java.io.FileWriter;
import java.io.IOException;
@ -34,6 +32,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javacserver.Log;
public class LazyInitFileLog extends Log {
String baseFilename;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2022, 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
@ -23,15 +23,15 @@
* questions.
*/
package com.sun.tools.sjavac.server.log;
import com.sun.tools.sjavac.Log;
package javacserver.server.log;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javacserver.Log;
public class LoggingOutputStream extends FilterOutputStream {
private static final byte[] LINE_SEP = System.lineSeparator().getBytes();

View File

@ -214,8 +214,6 @@ public class ClassFinder {
}
if (fm instanceof JavacFileManager javacFileManager) {
useCtProps = javacFileManager.isDefaultBootClassPath() && javacFileManager.isSymbolFileEnabled();
} else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) {
useCtProps = !options.isSet("ignore.symbol.file");
} else {
useCtProps = false;
}

View File

@ -1,299 +0,0 @@
/*
* 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
* 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.File;
import java.util.Collections;
import java.util.HashMap;
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
* from a build. There are usually two build states, the previous one (prev),
* loaded from the javac_state file, and the current one (now).
*
* <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 BuildState {
private Map<String,Module> modules = new HashMap<>();
private Map<String,Package> packages = new HashMap<>();
private Map<String,Source> sources = new HashMap<>();
private Map<String,File> artifacts = new HashMap<>();
// Map from package to a set of packages that depend on said package.
private Map<String,Set<String>> dependents = new HashMap<>();
public Map<String,Module> modules() { return modules; }
public Map<String,Package> packages() { return packages; }
public Map<String,Source> sources() { return sources; }
public Map<String,File> artifacts() { return artifacts; }
public Map<String,Set<String>> dependents() { return dependents; }
/**
* Lookup a module from a name. Create the module if it does
* not exist yet.
*/
public Module lookupModule(String mod) {
Module m = modules.get(mod);
if (m == null) {
m = new Module(mod, "???");
modules.put(mod, m);
}
return m;
}
/**
* Find a module from a given package name. For example:
* The package name "base:java.lang" will fetch the module named "base".
* The package name ":java.net" will fetch the default module.
*/
Module findModuleFromPackageName(String pkg) {
int cp = pkg.indexOf(':');
Assert.check(cp != -1, "Could not find package name");
String mod = pkg.substring(0, cp);
return lookupModule(mod);
}
/**
* Store references to all packages, sources and artifacts for all modules
* into the build state. I.e. flatten the module tree structure
* into global maps stored in the BuildState for easy access.
*
* @param m The set of modules.
*/
public void flattenPackagesSourcesAndArtifacts(Map<String,Module> m) {
modules = m;
// Extract all the found packages.
for (Module i : modules.values()) {
for (Map.Entry<String,Package> j : i.packages().entrySet()) {
Package p = packages.get(j.getKey());
// Check that no two different packages are stored under same name.
Assert.check(p == null || p == j.getValue());
if (p == null) {
p = j.getValue();
packages.put(j.getKey(),j.getValue());
}
for (Map.Entry<String,Source> k : p.sources().entrySet()) {
Source s = sources.get(k.getKey());
// Check that no two different sources are stored under same name.
Assert.check(s == null || s == k.getValue());
if (s == null) {
s = k.getValue();
sources.put(k.getKey(), k.getValue());
}
}
for (Map.Entry<String,File> g : p.artifacts().entrySet()) {
File f = artifacts.get(g.getKey());
// Check that no two artifacts are stored under the same file.
Assert.check(f == null || f == g.getValue());
if (f == null) {
f = g.getValue();
artifacts.put(g.getKey(), g.getValue());
}
}
}
}
}
/**
* Store references to all artifacts found in the module tree into the maps
* stored in the build state.
*
* @param m The set of modules.
*/
public void flattenArtifacts(Map<String,Module> m) {
modules = m;
// Extract all the found packages.
for (Module i : modules.values()) {
for (Map.Entry<String,Package> j : i.packages().entrySet()) {
Package p = packages.get(j.getKey());
// Check that no two different packages are stored under same name.
Assert.check(p == null || p == j.getValue());
p = j.getValue();
packages.put(j.getKey(),j.getValue());
for (Map.Entry<String,File> g : p.artifacts().entrySet()) {
File f = artifacts.get(g.getKey());
// Check that no two artifacts are stored under the same file.
Assert.check(f == null || f == g.getValue());
artifacts.put(g.getKey(), g.getValue());
}
}
}
}
/**
* Calculate the package dependents (ie the reverse of the dependencies).
*/
public void calculateDependents() {
dependents = new HashMap<>();
for (String s : packages.keySet()) {
Package p = packages.get(s);
// 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.
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());
}
}
}
}
/**
* Verify that the setModules method above did the right thing when
* running through the {@literal module->package->source} structure.
*/
public void checkInternalState(String msg, boolean linkedOnly, Map<String,Source> srcs) {
boolean baad = false;
Map<String,Source> original = new HashMap<>();
Map<String,Source> calculated = new HashMap<>();
for (String s : sources.keySet()) {
Source ss = sources.get(s);
if (ss.isLinkedOnly() == linkedOnly) {
calculated.put(s,ss);
}
}
for (String s : srcs.keySet()) {
Source ss = srcs.get(s);
if (ss.isLinkedOnly() == linkedOnly) {
original.put(s,ss);
}
}
if (original.size() != calculated.size()) {
Log.error("INTERNAL ERROR "+msg+" original and calculated are not the same size!");
baad = true;
}
if (!original.keySet().equals(calculated.keySet())) {
Log.error("INTERNAL ERROR "+msg+" original and calculated do not have the same domain!");
baad = true;
}
if (!baad) {
for (String s : original.keySet()) {
Source s1 = original.get(s);
Source s2 = calculated.get(s);
if (s1 == null || s2 == null || !s1.equals(s2)) {
Log.error("INTERNAL ERROR "+msg+" original and calculated have differing elements for "+s);
}
baad = true;
}
}
if (baad) {
for (String s : original.keySet()) {
Source ss = original.get(s);
Source sss = calculated.get(s);
if (sss == null) {
Log.error("The file "+s+" does not exist in calculated tree of sources.");
}
}
for (String s : calculated.keySet()) {
Source ss = calculated.get(s);
Source sss = original.get(s);
if (sss == null) {
Log.error("The file "+s+" does not exist in original set of found sources.");
}
}
}
}
/**
* Load a module from the javac state file.
*/
public Module loadModule(String l) {
Module m = Module.load(l);
modules.put(m.name(), m);
return m;
}
/**
* Load a package from the javac state file.
*/
public Package loadPackage(Module lastModule, String l) {
Package p = Package.load(lastModule, l);
lastModule.addPackage(p);
packages.put(p.name(), p);
return p;
}
/**
* Load a source from the javac state file.
*/
public Source loadSource(Package lastPackage, String l, boolean is_generated) {
Source s = Source.load(lastPackage, l, is_generated);
lastPackage.addSource(s);
sources.put(s.name(), s);
return s;
}
/**
* During an incremental compile we need to copy the old javac state
* information about packages that were not recompiled.
*/
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;
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. (See JDK-8071904)
packages.put(pkg, pprev);
}
}
}

View File

@ -1,159 +0,0 @@
/*
* Copyright (c) 2001, 2016, 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.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
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.comp.CompilationService;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* The clean properties transform should not be necessary.
* Eventually we will cleanup the property file sources in the OpenJDK instead.
*
* <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 CleanProperties implements Transformer {
public void setExtra(String e) {
// Any extra information is ignored for clean properties.
}
public void setExtra(Options a) {
// Any extra information is ignored for clean properties.
}
public boolean transform(CompilationService sjavac,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<String,Set<String>> oldPackageDependencies,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
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) {
boolean rc = true;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = pkgName.replace('.',File.separatorChar);
for (URI u : pkgSrcs.get(pkgName)) {
File src = new File(u);
boolean r = clean(pkgName, pkgNameF, src, new File(destRoot), debugLevel,
packageArtifacts);
if (r == false) {
rc = false;
}
}
}
return rc;
}
boolean clean(String pkgName,
String pkgNameF,
File src,
File destRoot,
int debugLevel,
Map<String,Set<URI>> packageArtifacts) {
// Load the properties file.
Properties p = new Properties();
try {
p.load(new FileInputStream(src));
} catch (IOException e) {
Log.error("Error reading file "+src.getPath());
return false;
}
// Sort the properties in increasing key order.
List<String> sortedKeys = new ArrayList<>();
for (Object key : p.keySet()) {
sortedKeys.add((String)key);
}
Collections.sort(sortedKeys);
// Collect the properties into a string buffer.
StringBuilder data = new StringBuilder();
for (String key : sortedKeys) {
data.append(CompileProperties.escape(key))
.append(":")
.append(CompileProperties.escape((String) p.get(key)))
.append("\n");
}
String destFilename = destRoot.getPath()+File.separator+pkgNameF+File.separator+src.getName();
File dest = new File(destFilename);
// Make sure the dest directories exist.
if (!dest.getParentFile().isDirectory()) {
if (!dest.getParentFile().mkdirs()) {
Log.error("Could not create the directory "+dest.getParentFile().getPath());
return false;
}
}
Set<URI> as = packageArtifacts.get(pkgName);
if (as == null) {
as = new HashSet<>();
packageArtifacts.put(pkgName, as);
}
as.add(dest.toURI());
if (dest.exists() && dest.lastModified() > src.lastModified()) {
// A cleaned property file exists, and its timestamp is newer than the source.
// Assume that we do not need to clean!
// Thus we are done.
return true;
}
Log.info("Cleaning property file "+pkgNameF+File.separator+src.getName());
try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest)))) {
writer.write(data.toString());
} catch ( IOException e ) {
Log.error("Could not write file "+dest.getPath());
return false;
}
return true;
}
}

View File

@ -1,57 +0,0 @@
/*
* 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.net.URI;
import java.util.HashSet;
import java.util.Set;
/**
* A compile chunk is a list of sources/packages to be compiled. Possibly a subset of
* the total number of sources/packages to be compiled for this sjavac invocation.
*
* <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 CompileChunk implements Comparable<CompileChunk> {
public int numPackages;
public int numDependents;
public Set<URI> srcs = new HashSet<>();
public StringBuilder pkgNames = new StringBuilder();
public String pkgFromTos = "";
public int compareTo(CompileChunk c) {
if (numDependents == c.numDependents) return 0;
if (numDependents > c.numDependents) return -1;
return -1;
}
boolean equal(CompileChunk c) {
return numDependents == c.numDependents;
}
}

View File

@ -1,355 +0,0 @@
/*
* Copyright (c) 2012, 2019, 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.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.comp.CompilationService;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
import com.sun.tools.sjavac.server.CompilationSubResult;
import com.sun.tools.sjavac.server.SysInfo;
/**
* This transform compiles a set of packages containing Java sources.
* The compile request is divided into separate sets of source files.
* For each set a separate request thread is dispatched to a javac server
* and the meta data is accumulated. The number of sets correspond more or
* less to the number of cores. Less so now, than it will in the future.
*
* <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></p>
*/
public class CompileJavaPackages implements Transformer {
// The current limited sharing of data between concurrent JavaCompilers
// in the server will not give speedups above 3 cores. Thus this limit.
// We hope to improve this in the future.
static final int limitOnConcurrency = 3;
Options args;
public void setExtra(String e) {
}
public void setExtra(Options a) {
args = a;
}
public boolean transform(final CompilationService sjavac,
Map<String,Set<URI>> pkgSrcs,
final Set<URI> visibleSources,
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
final Map<String,Set<URI>> packageArtifacts,
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) {
Log.debug("Performing CompileJavaPackages transform...");
boolean rc = true;
boolean concurrentCompiles = true;
// Fetch the id.
final String id = String.valueOf(new Random().nextInt());
// Only keep portfile and sjavac settings..
//String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), sjavac.serverSettings());
SysInfo sysinfo = sjavac.getSysInfo();
int numMBytes = (int)(sysinfo.maxMemory / ((long)(1024*1024)));
Log.debug("Server reports "+numMBytes+"MiB of memory and "+sysinfo.numCores+" cores");
if (numCores <= 0) {
// Set the requested number of cores to the number of cores on the server.
numCores = sysinfo.numCores;
Log.debug("Number of jobs not explicitly set, defaulting to "+sysinfo.numCores);
} else if (sysinfo.numCores < numCores) {
// Set the requested number of cores to the number of cores on the server.
Log.debug("Limiting jobs from explicitly set "+numCores+" to cores available on server: "+sysinfo.numCores);
numCores = sysinfo.numCores;
} else {
Log.debug("Number of jobs explicitly set to "+numCores);
}
// More than three concurrent cores does not currently give a speedup, at least for compiling the jdk
// in the OpenJDK. This will change in the future.
int numCompiles = numCores;
if (numCores > limitOnConcurrency) numCompiles = limitOnConcurrency;
// Split the work up in chunks to compiled.
int numSources = 0;
for (String s : pkgSrcs.keySet()) {
Set<URI> ss = pkgSrcs.get(s);
numSources += ss.size();
}
int sourcesPerCompile = numSources / numCompiles;
// For 64 bit Java, it seems we can compile the OpenJDK 8800 files with a 1500M of heap
// in a single chunk, with reasonable performance.
// For 32 bit java, it seems we need 1G of heap.
// Number experimentally determined when compiling the OpenJDK.
// Includes space for reasonably efficient garbage collection etc,
// Calculating backwards gives us a requirement of
// 1500M/8800 = 175 KiB for 64 bit platforms
// and 1G/8800 = 119 KiB for 32 bit platform
// for each compile.....
int kbPerFile = 175;
String osarch = System.getProperty("os.arch");
String dataModel = System.getProperty("sun.arch.data.model");
if ("32".equals(dataModel)) {
// For 32 bit platforms, assume it is slightly smaller
// because of smaller object headers and pointers.
kbPerFile = 119;
}
int numRequiredMBytes = (kbPerFile*numSources)/1024;
Log.debug("For os.arch "+osarch+" the empirically determined heap required per file is "+kbPerFile+"KiB");
Log.debug("Server has "+numMBytes+"MiB of heap.");
Log.debug("Heuristics say that we need "+numRequiredMBytes+"MiB of heap for all source files.");
// Perform heuristics to see how many cores we can use,
// or if we have to the work serially in smaller chunks.
if (numMBytes < numRequiredMBytes) {
// Ouch, cannot fit even a single compile into the heap.
// Split it up into several serial chunks.
concurrentCompiles = false;
// Limit the number of sources for each compile to 500.
if (numSources < 500) {
numCompiles = 1;
sourcesPerCompile = numSources;
Log.debug("Compiling as a single source code chunk to stay within heap size limitations!");
} else if (sourcesPerCompile > 500) {
// This number is very low, and tuned to dealing with the OpenJDK
// where the source is >very< circular! In normal application,
// with less circularity the number could perhaps be increased.
numCompiles = numSources / 500;
sourcesPerCompile = numSources/numCompiles;
Log.debug("Compiling source as "+numCompiles+" code chunks serially to stay within heap size limitations!");
}
} else {
if (numCompiles > 1) {
// Ok, we can fit at least one full compilation on the heap.
float usagePerCompile = (float)numRequiredMBytes / ((float)numCompiles * (float)0.7);
int usage = (int)(usagePerCompile * (float)numCompiles);
Log.debug("Heuristics say that for "+numCompiles+" concurrent compiles we need "+usage+"MiB");
if (usage > numMBytes) {
// Ouch it does not fit. Reduce to a single chunk.
numCompiles = 1;
sourcesPerCompile = numSources;
// What if the relationship between number of compile_chunks and num_required_mbytes
// is not linear? Then perhaps 2 chunks would fit where 3 does not. Well, this is
// something to experiment upon in the future.
Log.debug("Limiting compile to a single thread to stay within heap size limitations!");
}
}
}
Log.debug("Compiling sources in "+numCompiles+" chunk(s)");
// Create the chunks to be compiled.
final CompileChunk[] compileChunks = createCompileChunks(pkgSrcs, oldPackageDependents,
numCompiles, sourcesPerCompile);
if (Log.isDebugging()) {
int cn = 1;
for (CompileChunk cc : compileChunks) {
Log.debug("Chunk "+cn+" for "+id+" ---------------");
cn++;
for (URI u : cc.srcs) {
Log.debug(""+u);
}
}
}
long start = System.currentTimeMillis();
// Prepare compilation calls
List<Callable<CompilationSubResult>> compilationCalls = new ArrayList<>();
final Object lock = new Object();
for (int i = 0; i < numCompiles; i++) {
CompileChunk cc = compileChunks[i];
if (cc.srcs.isEmpty()) {
continue;
}
String chunkId = id + "-" + String.valueOf(i);
Log log = Log.get();
compilationCalls.add(() -> {
Log.setLogForCurrentThread(log);
CompilationSubResult result = sjavac.compile("n/a",
chunkId,
args.prepJavacArgs(),
Collections.emptyList(),
cc.srcs,
visibleSources);
synchronized (lock) {
Util.getLines(result.stdout).forEach(Log::info);
Util.getLines(result.stderr).forEach(Log::error);
}
return result;
});
}
// Perform compilations and collect results
List<CompilationSubResult> subResults = new ArrayList<>();
List<Future<CompilationSubResult>> futs = new ArrayList<>();
ExecutorService exec = Executors.newFixedThreadPool(concurrentCompiles ? compilationCalls.size() : 1);
for (Callable<CompilationSubResult> compilationCall : compilationCalls) {
futs.add(exec.submit(compilationCall));
}
for (Future<CompilationSubResult> fut : futs) {
try {
subResults.add(fut.get());
} catch (ExecutionException ee) {
Log.error("Compilation failed: " + ee.getMessage());
Log.error(ee);
} catch (InterruptedException ie) {
Log.error("Compilation interrupted: " + ie.getMessage());
Log.error(ie);
Thread.currentThread().interrupt();
}
}
exec.shutdownNow();
// Process each sub result
for (CompilationSubResult subResult : subResults) {
for (String pkg : subResult.packageArtifacts.keySet()) {
Set<URI> pkgArtifacts = subResult.packageArtifacts.get(pkg);
packageArtifacts.merge(pkg, pkgArtifacts, Util::union);
}
for (String pkg : subResult.packageDependencies.keySet()) {
packageDependencies.putIfAbsent(pkg, new HashMap<>());
packageDependencies.get(pkg).putAll(subResult.packageDependencies.get(pkg));
}
for (String pkg : subResult.packageCpDependencies.keySet()) {
packageCpDependencies.putIfAbsent(pkg, new HashMap<>());
packageCpDependencies.get(pkg).putAll(subResult.packageCpDependencies.get(pkg));
}
for (String pkg : subResult.packagePubapis.keySet()) {
packagePubapis.merge(pkg, subResult.packagePubapis.get(pkg), PubApi::mergeTypes);
}
for (String pkg : subResult.dependencyPubapis.keySet()) {
dependencyPubapis.merge(pkg, subResult.dependencyPubapis.get(pkg), PubApi::mergeTypes);
}
// Check the return values.
if (subResult.result != Result.OK) {
rc = false;
}
}
long duration = System.currentTimeMillis() - start;
long minutes = duration/60000;
long seconds = (duration-minutes*60000)/1000;
Log.debug("Compilation of "+numSources+" source files took "+minutes+"m "+seconds+"s");
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!
* (Typically that chunk contains the java.lang package.) In the future
* we could perhaps improve the heuristics to put the sources into even more sensible chunks.
* Now the package are simple sorted in alphabetical order and chunked, then the chunks
* are sorted on how dependent they are.
*
* @param pkgSrcs The sources to compile.
* @param oldPackageDependents Old package dependents, if non-empty, used to sort the chunks.
* @param numCompiles The number of chunks.
* @param sourcesPerCompile The number of sources per chunk.
* @return
*/
CompileChunk[] createCompileChunks(Map<String,Set<URI>> pkgSrcs,
Map<String,Set<String>> oldPackageDependents,
int numCompiles,
int sourcesPerCompile) {
CompileChunk[] compileChunks = new CompileChunk[numCompiles];
for (int i=0; i<compileChunks.length; ++i) {
compileChunks[i] = new CompileChunk();
}
// Now go through the packages and spread out the source on the different chunks.
int ci = 0;
// Sort the packages
String[] packageNames = pkgSrcs.keySet().toArray(new String[0]);
Arrays.sort(packageNames);
String from = null;
for (String pkgName : packageNames) {
CompileChunk cc = compileChunks[ci];
Set<URI> s = pkgSrcs.get(pkgName);
if (cc.srcs.size()+s.size() > sourcesPerCompile && ci < numCompiles-1) {
from = null;
ci++;
cc = compileChunks[ci];
}
cc.numPackages++;
cc.srcs.addAll(s);
// Calculate nice package names to use as information when compiling.
String justPkgName = Util.justPackageName(pkgName);
// Fetch how many packages depend on this package from the old build state.
Set<String> ss = oldPackageDependents.get(pkgName);
if (ss != null) {
// Accumulate this information onto this chunk.
cc.numDependents += ss.size();
}
if (from == null || from.trim().equals("")) from = justPkgName;
cc.pkgNames.append(justPkgName+"("+s.size()+") ");
cc.pkgFromTos = from+" to "+justPkgName;
}
// If we are compiling serially, sort the chunks, so that the chunk (with the most dependents) (usually the chunk
// containing java.lang.Object, is to be compiled first!
// For concurrent compilation, this does not matter.
Arrays.sort(compileChunks);
return compileChunks;
}
}

View File

@ -1,231 +0,0 @@
/*
* Copyright (c) 2012, 2016, 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.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 com.sun.tools.sjavac.comp.CompilationService;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* Compile properties transform a properties file into a Java source file.
* Java has built in support for reading properties from either a text file
* in the source or a compiled java source file.
*
* <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 CompileProperties implements Transformer {
// Any extra information passed from the command line, for example if:
// -tr .proppp=com.sun.tools.javac.smart.CompileProperties,sun.util.resources.LocaleNamesBundle
// then extra will be "sun.util.resources.LocaleNamesBundle"
String extra;
public void setExtra(String e) {
extra = e;
}
public void setExtra(Options a) {
}
public boolean transform(CompilationService compilationService,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
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) {
boolean rc = true;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = Util.toFileSystemPath(pkgName);
for (URI u : pkgSrcs.get(pkgName)) {
File src = new File(u);
boolean r = compile(pkgName, pkgNameF, src, new File(destRoot), debugLevel,
packageArtifacts);
if (r == false) {
rc = false;
}
}
}
return rc;
}
boolean compile(String pkgName, String pkgNameF, File src, File destRoot, int debugLevel,
Map<String,Set<URI>> packageArtifacts)
{
String superClass = "java.util.ListResourceBundle";
if (extra != null) {
superClass = extra;
}
// Load the properties file.
Properties p = new Properties();
try {
p.load(new FileInputStream(src));
} catch (IOException e) {
Log.error("Error reading file "+src.getPath());
return false;
}
// Calculate the name of the Java source file to be generated.
int dp = src.getName().lastIndexOf(".");
String classname = src.getName().substring(0,dp);
// Sort the properties in increasing key order.
List<String> sortedKeys = new ArrayList<>();
for (Object key : p.keySet()) {
sortedKeys.add((String)key);
}
Collections.sort(sortedKeys);
Iterator<String> keys = sortedKeys.iterator();
// Collect the properties into a string buffer.
StringBuilder data = new StringBuilder();
while (keys.hasNext()) {
String key = keys.next();
data.append(" { \"" + escape(key) + "\", \"" +
escape((String)p.get(key)) + "\" },\n");
}
// Create dest file name. It is derived from the properties file name.
String destFilename = destRoot.getPath()+File.separator+pkgNameF+File.separator+classname+".java";
File dest = new File(destFilename);
// Make sure the dest directories exist.
if (!dest.getParentFile().isDirectory()) {
if (!dest.getParentFile().mkdirs()) {
Log.error("Could not create the directory "+dest.getParentFile().getPath());
return false;
}
}
Set<URI> as = packageArtifacts.get(pkgName);
if (as == null) {
as = new HashSet<>();
packageArtifacts.put(pkgName, as);
}
as.add(dest.toURI());
if (dest.exists() && dest.lastModified() > src.lastModified()) {
// A generated file exists, and its timestamp is newer than the source.
// Assume that we do not need to regenerate the dest file!
// Thus we are done.
return true;
}
String packageString = "package " + pkgNameF.replace(File.separatorChar,'.') + ";\n\n";
Log.info("Compiling property file "+pkgNameF+File.separator+src.getName());
try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest)))) {
MessageFormat format = new MessageFormat(FORMAT);
writer.write(format.format(new Object[] { packageString, classname, superClass, data }));
} catch ( IOException e ) {
Log.error("Could not write file "+dest.getPath());
return false;
}
return true;
}
private static final String FORMAT =
"{0}" +
"public final class {1} extends {2} '{'\n" +
" protected final Object[][] getContents() '{'\n" +
" return new Object[][] '{'\n" +
"{3}" +
" };\n" +
" }\n" +
"}\n";
public static String escape(String theString) {
int len = theString.length();
StringBuilder outBuffer = new StringBuilder(len*2);
for(int x=0; x<len; x++) {
char aChar = theString.charAt(x);
switch(aChar) {
case '\\':outBuffer.append('\\'); outBuffer.append('\\');
break;
case '\t':outBuffer.append('\\'); outBuffer.append('t');
break;
case '\n':outBuffer.append('\\'); outBuffer.append('n');
break;
case '\r':outBuffer.append('\\'); outBuffer.append('r');
break;
case '\f':outBuffer.append('\\'); outBuffer.append('f');
break;
default:
if ((aChar < 0x0020) || (aChar > 0x007e)) {
outBuffer.append('\\');
outBuffer.append('u');
outBuffer.append(toHex((aChar >> 12) & 0xF));
outBuffer.append(toHex((aChar >> 8) & 0xF));
outBuffer.append(toHex((aChar >> 4) & 0xF));
outBuffer.append(toHex( aChar & 0xF));
} else {
if (aChar == '"') {
outBuffer.append('\\');
}
outBuffer.append(aChar);
}
}
}
return outBuffer.toString();
}
private static char toHex(int nibble) {
return hexDigit[(nibble & 0xF)];
}
private static final char[] hexDigit = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
}

View File

@ -1,118 +0,0 @@
/*
* Copyright (c) 2012, 2021, 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.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.comp.CompilationService;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* The copy file transform simply copies a matching file from -src to -d .
* Such files are typically images, xml documents and other data files.
*
* <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 CopyFile implements Transformer {
public void setExtra(String e) {
}
public void setExtra(Options a) {
}
public boolean transform(CompilationService compilationService,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<String,Set<String>> oldPackageDependents,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
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)
{
boolean rc = true;
String dest_filename;
File dest;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = Util.toFileSystemPath(pkgName);
for (URI u : pkgSrcs.get(pkgName)) {
File src = new File(u);
File destDir;
destDir = new File(destRoot.getPath()+File.separator+pkgNameF);
dest_filename = destRoot.getPath()+File.separator+pkgNameF+File.separator+src.getName();
dest = new File(dest_filename);
if (!destDir.isDirectory()) {
if (!destDir.mkdirs()) {
Log.error("Error: The copier could not create the directory "+
destDir.getPath());
return false;
}
}
Set<URI> as = packageArtifacts.get(pkgName);
if (as == null) {
as = new HashSet<>();
packageArtifacts.put(pkgName, as);
}
as.add(dest.toURI());
if (dest.exists() && dest.lastModified() > src.lastModified()) {
// A copied file exists, and its timestamp is newer than the source.
continue;
}
Log.info("Copying "+pkgNameF+File.separator+src.getName());
try {
Files.copy(src.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
catch(IOException e){
Log.error("Could not copy the file "+src.getPath()+" to "+dest.getPath());
rc = false;
}
}
}
return rc;
}
}

View File

@ -1,974 +0,0 @@
/*
* Copyright (c) 2012, 2019, 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.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import java.nio.file.NoSuchFileException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
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.comp.CompilationService;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* The javac state class maintains the previous (prev) and the current (now)
* build states and everything else that goes into the javac_state file.
*
* <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 JavacState {
// The arguments to the compile. If not identical, then it cannot
// be an incremental build!
String theArgs;
// The number of cores limits how many threads are used for heavy concurrent work.
int numCores;
// The bin_dir/javac_state
private File javacState;
// The previous build state is loaded from javac_state
private BuildState prev;
// The current build state is constructed during the build,
// then saved as the new javac_state.
private BuildState now;
// Something has changed in the javac_state. It needs to be saved!
private boolean needsSaving;
// If this is a new javac_state file, then do not print unnecessary messages.
private boolean newJavacState;
// These are packages where something has changed and the package
// needs to be recompiled. Actions that trigger recompilation:
// * source belonging to the package has changed
// * artifact belonging to the package is lost, or its timestamp has been changed.
// * an unknown artifact has appeared, we simply delete it, but we also trigger a recompilation.
// * a package that is tainted, taints all packages that depend on it.
private Set<String> taintedPackages;
// After a compile, the pubapis are compared with the pubapis stored in the javac state file.
// Any packages where the pubapi differ are added to this set.
// Later we use this set and the dependency information to taint dependent packages.
private Set<String> packagesWithChangedPublicApis;
// When a module-info.java file is changed, taint the module,
// then taint all modules that depend on that that module.
// A module dependency can occur directly through a require, or
// indirectly through a module that does a public export for the first tainted module.
// When all modules are tainted, then taint all packages belonging to these modules.
// Then rebuild. It is perhaps possible (and valuable?) to do a more fine-grained examination of the
// change in module-info.java, but that will have to wait.
private Set<String> taintedModules;
// The set of all packages that has been recompiled.
// Copy over the javac_state for the packages that did not need recompilation,
// verbatim from the previous (prev) to the new (now) build state.
private Set<String> recompiledPackages;
// The output directories filled with tasty artifacts.
private File binDir, gensrcDir, headerDir, stateDir;
// The current status of the file system.
private Set<File> binArtifacts;
private Set<File> gensrcArtifacts;
private Set<File> headerArtifacts;
// The status of the sources.
Set<Source> removedSources = null;
Set<Source> addedSources = null;
Set<Source> modifiedSources = null;
// Visible sources for linking. These are the only
// ones that -sourcepath is allowed to see.
Set<URI> visibleSrcs;
// Setup transform that always exist.
private CompileJavaPackages compileJavaPackages = new CompileJavaPackages();
// Command line options.
private Options options;
JavacState(Options op, boolean removeJavacState) {
options = op;
numCores = options.getNumCores();
theArgs = options.getStateArgsString();
binDir = Util.pathToFile(options.getDestDir());
gensrcDir = Util.pathToFile(options.getGenSrcDir());
headerDir = Util.pathToFile(options.getHeaderDir());
stateDir = Util.pathToFile(options.getStateDir());
javacState = new File(stateDir, "javac_state");
if (removeJavacState && javacState.exists()) {
javacState.delete();
}
newJavacState = false;
if (!javacState.exists()) {
newJavacState = true;
// If there is no javac_state then delete the contents of all the artifact dirs!
// We do not want to risk building a broken incremental build.
// BUT since the makefiles still copy things straight into the bin_dir et al,
// we avoid deleting files here, if the option --permit-unidentified-classes was supplied.
if (!options.areUnidentifiedArtifactsPermitted()) {
deleteContents(binDir);
deleteContents(gensrcDir);
deleteContents(headerDir);
}
needsSaving = true;
}
prev = new BuildState();
now = new BuildState();
taintedPackages = new HashSet<>();
recompiledPackages = new HashSet<>();
packagesWithChangedPublicApis = new HashSet<>();
}
public BuildState prev() { return prev; }
public BuildState now() { return now; }
/**
* Remove args not affecting the state.
*/
static String[] removeArgsNotAffectingState(String[] args) {
String[] out = new String[args.length];
int j = 0;
for (int i = 0; i<args.length; ++i) {
if (args[i].equals("-j")) {
// Just skip it and skip following value
i++;
} else if (args[i].startsWith("--server:")) {
// Just skip it.
} else if (args[i].startsWith("--log=")) {
// Just skip it.
} else if (args[i].equals("--compare-found-sources")) {
// Just skip it and skip verify file name
i++;
} else {
// Copy argument.
out[j] = args[i];
j++;
}
}
String[] ret = new String[j];
System.arraycopy(out, 0, ret, 0, j);
return ret;
}
/**
* Specify which sources are visible to the compiler through -sourcepath.
*/
public void setVisibleSources(Map<String,Source> vs) {
visibleSrcs = new HashSet<>();
for (String s : vs.keySet()) {
Source src = vs.get(s);
visibleSrcs.add(src.file().toURI());
}
}
/**
* Returns true if this is an incremental build.
*/
public boolean isIncremental() {
return !prev.sources().isEmpty();
}
/**
* Find all artifacts that exists on disk.
*/
public void findAllArtifacts() {
binArtifacts = findAllFiles(binDir);
gensrcArtifacts = findAllFiles(gensrcDir);
headerArtifacts = findAllFiles(headerDir);
}
/**
* Lookup the artifacts generated for this package in the previous build.
*/
private Map<String,File> fetchPrevArtifacts(String pkg) {
Package p = prev.packages().get(pkg);
if (p != null) {
return p.artifacts();
}
return new HashMap<>();
}
/**
* Delete all prev artifacts in the currently tainted packages.
*/
public void deleteClassArtifactsInTaintedPackages() {
for (String pkg : taintedPackages) {
Map<String,File> arts = fetchPrevArtifacts(pkg);
for (File f : arts.values()) {
if (f.exists() && f.getName().endsWith(".class")) {
f.delete();
}
}
}
}
/**
* Mark the javac_state file to be in need of saving and as a side effect,
* it gets a new timestamp.
*/
private void needsSaving() {
needsSaving = true;
}
/**
* Save the javac_state file.
*/
public void save() throws IOException {
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.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 S dependent -> source dependency\n");
b.append("# D C dependent -> classpath dependency\n");
b.append("# I pubapi\n");
b.append("R ").append(theArgs).append("\n");
// Copy over the javac_state for the packages that did not need recompilation.
now.copyPackagesExcept(prev, recompiledPackages, new HashSet<String>());
// Save the packages, ie package names, dependencies, pubapis and artifacts!
// I.e. the lot.
Module.saveModules(now.modules(), b);
String s = b.toString();
out.write(s, 0, s.length());
}
}
/**
* Load a javac_state file.
*/
public static JavacState load(Options options) {
JavacState db = new JavacState(options, false);
Module lastModule = null;
Package lastPackage = null;
Source lastSource = null;
boolean noFileFound = false;
boolean foundCorrectVerNr = false;
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();
if (l==null) break;
if (l.length()>=3 && l.charAt(1) == ' ') {
char c = l.charAt(0);
if (c == 'M') {
lastModule = db.prev.loadModule(l);
} else
if (c == 'P') {
if (lastModule == null) { syntaxError = true; break; }
lastPackage = db.prev.loadPackage(lastModule, l);
} else
if (c == 'D') {
if (lastModule == null || lastPackage == null) { syntaxError = true; break; }
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.getPubApi().appendItem(l.substring(2)); // Strip "I "
} else
if (c == 'A') {
if (lastModule == null || lastPackage == null) { syntaxError = true; break; }
lastPackage.loadArtifact(l);
} else
if (c == 'S') {
if (lastModule == null || lastPackage == null) { syntaxError = true; break; }
lastSource = db.prev.loadSource(lastPackage, l, false);
} else
if (c == 'G') {
if (lastModule == null || lastPackage == null) { syntaxError = true; break; }
lastSource = db.prev.loadSource(lastPackage, l, true);
} else
if (c == 'R') {
String ncmdl = "R "+db.theArgs;
if (!l.equals(ncmdl)) {
newCommandLine = true;
}
} else
if (c == '#') {
if (l.startsWith("# javac_state ver ")) {
int sp = l.indexOf(" ", 18);
if (sp != -1) {
String ver = l.substring(18,sp);
if (!ver.equals("0.4")) {
break;
}
foundCorrectVerNr = true;
}
}
}
}
}
} catch (FileNotFoundException | NoSuchFileException e) {
// Silently create a new javac_state file.
noFileFound = true;
} catch (IOException e) {
Log.warn("Dropping old javac_state because of errors when reading it.");
db = new JavacState(options, true);
foundCorrectVerNr = true;
newCommandLine = false;
syntaxError = false;
}
if (foundCorrectVerNr == false && !noFileFound) {
Log.debug("Dropping old javac_state since it is of an old version.");
db = new JavacState(options, true);
} else
if (newCommandLine == true && !noFileFound) {
Log.debug("Dropping old javac_state since a new command line is used!");
db = new JavacState(options, true);
} else
if (syntaxError == true) {
Log.warn("Dropping old javac_state since it contains syntax errors.");
db = new JavacState(options, true);
}
db.prev.calculateDependents();
return db;
}
/**
* Mark a java package as tainted, ie it needs recompilation.
*/
public void taintPackage(String name, String because) {
if (!taintedPackages.contains(name)) {
if (because != null) Log.debug("Tainting "+Util.justPackageName(name)+" because "+because);
// It has not been tainted before.
taintedPackages.add(name);
needsSaving();
Package nowp = now.packages().get(name);
if (nowp != null) {
for (String d : nowp.dependents()) {
taintPackage(d, because);
}
}
}
}
/**
* This packages need recompilation.
*/
public Set<String> taintedPackages() {
return taintedPackages;
}
/**
* Clean out the tainted package set, used after the first round of compiles,
* prior to propagating dependencies.
*/
public void clearTaintedPackages() {
taintedPackages = new HashSet<>();
}
/**
* Go through all sources and check which have been removed, added or modified
* and taint the corresponding packages.
*/
public void checkSourceStatus(boolean check_gensrc) {
removedSources = calculateRemovedSources();
for (Source s : removedSources) {
if (!s.isGenerated() || check_gensrc) {
taintPackage(s.pkg().name(), "source "+s.name()+" was removed");
}
}
addedSources = calculateAddedSources();
for (Source s : addedSources) {
String msg = null;
if (isIncremental()) {
// When building from scratch, there is no point
// printing "was added" for every file since all files are added.
// However for an incremental build it makes sense.
msg = "source "+s.name()+" was added";
}
if (!s.isGenerated() || check_gensrc) {
taintPackage(s.pkg().name(), msg);
}
}
modifiedSources = calculateModifiedSources();
for (Source s : modifiedSources) {
if (!s.isGenerated() || check_gensrc) {
taintPackage(s.pkg().name(), "source "+s.name()+" was modified");
}
}
}
/**
* Acquire the compile_java_packages suffix rule for .java files.
*/
public Map<String,Transformer> getJavaSuffixRule() {
Map<String,Transformer> sr = new HashMap<>();
sr.put(".java", compileJavaPackages);
return sr;
}
/**
* If artifacts have gone missing, force a recompile of the packages
* they belong to.
*/
public void taintPackagesThatMissArtifacts() {
for (Package pkg : prev.packages().values()) {
for (File f : pkg.artifacts().values()) {
if (!f.exists()) {
// Hmm, the artifact on disk does not exist! Someone has removed it....
// Lets rebuild the package.
taintPackage(pkg.name(), ""+f+" is missing.");
}
}
}
}
/**
* Propagate recompilation through the dependency chains.
* Avoid re-tainting packages that have already been compiled.
*/
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(Collection::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() throws IOException {
// 1. Collect fully qualified names of all interesting classpath dependencies
Set<String> fqDependencies = new HashSet<>();
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;
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));
}
pubApiExtractor.close();
// 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;
}
}
}
}
/**
* Scan all output dirs for artifacts and remove those files (artifacts?)
* that are not recognized as such, in the javac_state file.
*/
public void removeUnidentifiedArtifacts() {
Set<File> allKnownArtifacts = new HashSet<>();
for (Package pkg : prev.packages().values()) {
for (File f : pkg.artifacts().values()) {
allKnownArtifacts.add(f);
}
}
// Do not forget about javac_state....
allKnownArtifacts.add(javacState);
for (File f : binArtifacts) {
if (!allKnownArtifacts.contains(f) &&
!options.isUnidentifiedArtifactPermitted(f.getAbsolutePath())) {
Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state.");
f.delete();
}
}
for (File f : headerArtifacts) {
if (!allKnownArtifacts.contains(f)) {
Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state.");
f.delete();
}
}
for (File f : gensrcArtifacts) {
if (!allKnownArtifacts.contains(f)) {
Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state.");
f.delete();
}
}
}
/**
* Remove artifacts that are no longer produced when compiling!
*/
public void removeSuperfluousArtifacts(Set<String> recentlyCompiled) {
// Nothing to do, if nothing was recompiled.
if (recentlyCompiled.size() == 0) return;
for (String pkg : now.packages().keySet()) {
// If this package has not been recompiled, skip the check.
if (!recentlyCompiled.contains(pkg)) continue;
Collection<File> arts = now.artifacts().values();
for (File f : fetchPrevArtifacts(pkg).values()) {
if (!arts.contains(f)) {
Log.debug("Removing "+f.getPath()+" since it is now superfluous!");
if (f.exists()) f.delete();
}
}
}
}
/**
* Return those files belonging to prev, but not now.
*/
private Set<Source> calculateRemovedSources() {
Set<Source> removed = new HashSet<>();
for (String src : prev.sources().keySet()) {
if (now.sources().get(src) == null) {
removed.add(prev.sources().get(src));
}
}
return removed;
}
/**
* Return those files belonging to now, but not prev.
*/
private Set<Source> calculateAddedSources() {
Set<Source> added = new HashSet<>();
for (String src : now.sources().keySet()) {
if (prev.sources().get(src) == null) {
added.add(now.sources().get(src));
}
}
return added;
}
/**
* Return those files where the timestamp is newer.
* If a source file timestamp suddenly is older than what is known
* about it in javac_state, then consider it modified, but print
* a warning!
*/
private Set<Source> calculateModifiedSources() {
Set<Source> modified = new HashSet<>();
for (String src : now.sources().keySet()) {
Source n = now.sources().get(src);
Source t = prev.sources().get(src);
if (prev.sources().get(src) != null) {
if (t != null) {
if (n.lastModified() > t.lastModified()) {
modified.add(n);
} else if (n.lastModified() < t.lastModified()) {
modified.add(n);
Log.warn("The source file "+n.name()+" timestamp has moved backwards in time.");
}
}
}
}
return modified;
}
/**
* Recursively delete a directory and all its contents.
*/
private void deleteContents(File dir) {
if (dir != null && dir.exists()) {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
deleteContents(f);
}
if (!options.isUnidentifiedArtifactPermitted(f.getAbsolutePath())) {
Log.debug("Removing "+f.getAbsolutePath());
f.delete();
}
}
}
}
/**
* Run the copy translator only.
*/
public void performCopying(File binDir, Map<String,Transformer> suffixRules) {
Map<String,Transformer> sr = new HashMap<>();
for (Map.Entry<String,Transformer> e : suffixRules.entrySet()) {
if (e.getValue().getClass().equals(CopyFile.class)) {
sr.put(e.getKey(), e.getValue());
}
}
perform(null, binDir, sr);
}
/**
* Run all the translators that translate into java source code.
* I.e. all translators that are not copy nor compile_java_source.
*/
public void performTranslation(File gensrcDir, Map<String,Transformer> suffixRules) {
Map<String,Transformer> sr = new HashMap<>();
for (Map.Entry<String,Transformer> e : suffixRules.entrySet()) {
Class<?> trClass = e.getValue().getClass();
if (trClass == CompileJavaPackages.class || trClass == CopyFile.class)
continue;
sr.put(e.getKey(), e.getValue());
}
perform(null, gensrcDir, sr);
}
/**
* Compile all the java sources. Return true, if it needs to be called again!
*/
public boolean performJavaCompilations(CompilationService sjavac,
Options args,
Set<String> recentlyCompiled,
boolean[] rcValue) {
Map<String,Transformer> suffixRules = new HashMap<>();
suffixRules.put(".java", compileJavaPackages);
compileJavaPackages.setExtra(args);
rcValue[0] = perform(sjavac, binDir, suffixRules);
recentlyCompiled.addAll(taintedPackages());
clearTaintedPackages();
boolean again = !packagesWithChangedPublicApis.isEmpty();
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?)
}
/**
* Store the source into the set of sources belonging to the given transform.
*/
private void addFileToTransform(Map<Transformer,Map<String,Set<URI>>> gs, Transformer t, Source s) {
Map<String,Set<URI>> fs = gs.get(t);
if (fs == null) {
fs = new HashMap<>();
gs.put(t, fs);
}
Set<URI> ss = fs.get(s.pkg().name());
if (ss == null) {
ss = new HashSet<>();
fs.put(s.pkg().name(), ss);
}
ss.add(s.file().toURI());
}
/**
* For all packages, find all sources belonging to the package, group the sources
* based on their transformers and apply the transformers on each source code group.
*/
private boolean perform(CompilationService sjavac,
File outputDir,
Map<String,Transformer> suffixRules) {
boolean rc = true;
// Group sources based on transforms. A source file can only belong to a single transform.
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 (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()) {
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<>());
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,
prev.dependents(),
outputDir.toURI(),
packageArtifacts,
packageDependencies,
packageCpDependencies,
packagePublicApis,
dependencyPublicApis,
0,
isIncremental(),
numCores);
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()) {
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, 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, false);
}
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.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(pkg).existsInJavacState()) {
// This is an incremental compile! The pubapi
// did change. Trigger recompilation of dependents.
packagesWithChangedPublicApis.add(pkg);
Log.debug("The API of " + Util.justPackageName(pkg) + " has changed!");
}
}
}
}
return rc;
}
/**
* Utility method to recursively find all files below a directory.
*/
private static Set<File> findAllFiles(File dir) {
Set<File> foundFiles = new HashSet<>();
if (dir == null) {
return foundFiles;
}
recurse(dir, foundFiles);
return foundFiles;
}
private static void recurse(File dir, Set<File> foundFiles) {
for (File f : dir.listFiles()) {
if (f.isFile()) {
foundFiles.add(f);
} else if (f.isDirectory()) {
recurse(f, foundFiles);
}
}
}
/**
* 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
// might be /cygdrive/c/.... which does not match c:\....
// We need to adjust our calculated sources to be identical, if
// necessary.
boolean mightNeedRewriting = File.pathSeparatorChar == ';';
if (makefileSourceList == null)
return;
Set<String> calculatedSources = new HashSet<>();
Set<String> listedSources = new HashSet<>();
// Create a set of filenames with full paths.
for (Source s : now.sources().values()) {
// Don't include link only sources when comparing sources to compile
if (!s.isLinkedOnly()) {
String path = s.file().getPath();
if (mightNeedRewriting)
path = Util.normalizeDriveLetter(path);
calculatedSources.add(path);
}
}
// Read in the file and create another set of filenames with full paths.
try(BufferedReader in = new BufferedReader(new FileReader(makefileSourceList))) {
for (;;) {
String l = in.readLine();
if (l==null) break;
l = l.trim();
if (mightNeedRewriting) {
if (l.indexOf(":") == 1 && l.indexOf("\\") == 2) {
// Everything a-ok, the format is already C:\foo\bar
} else if (l.indexOf(":") == 1 && l.indexOf("/") == 2) {
// The format is C:/foo/bar, rewrite into the above format.
l = l.replaceAll("/","\\\\");
} else if (l.charAt(0) == '/' && l.indexOf("/",1) != -1) {
// The format might be: /cygdrive/c/foo/bar, rewrite into the above format.
// Do not hardcode the name cygdrive here.
int slash = l.indexOf("/",1);
l = l.replaceAll("/","\\\\");
l = ""+l.charAt(slash+1)+":"+l.substring(slash+2);
}
if (Character.isLowerCase(l.charAt(0))) {
l = Character.toUpperCase(l.charAt(0))+l.substring(1);
}
}
listedSources.add(l);
}
} catch (FileNotFoundException | NoSuchFileException e) {
throw new ProblemException("Could not open "+makefileSourceList.getPath()+" since it does not exist!");
} catch (IOException e) {
throw new ProblemException("Could not read "+makefileSourceList.getPath());
}
for (String s : listedSources) {
if (!calculatedSources.contains(s)) {
throw new ProblemException("The makefile listed source "+s+" was not calculated by the smart javac wrapper!");
}
}
for (String s : calculatedSources) {
if (!listedSources.contains(s)) {
throw new ProblemException("The smart javac wrapper calculated source "+s+" was not listed by the makefiles!");
}
}
}
}

View File

@ -1,141 +0,0 @@
/*
* Copyright (c) 2012, 2021, 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.File;
import java.net.URI;
import java.util.HashMap;
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.
*
* <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 Module implements Comparable<Module> {
private String name;
private String dirname;
private Map<String,Package> packages = new HashMap<>();
private Map<String,Source> sources = new HashMap<>();
private Map<String,File> artifacts = new HashMap<>();
public Module(String n, String dn) {
name = n;
dirname = n;
}
public String name() { return name; }
public String dirname() { return dirname; }
public Map<String,Package> packages() { return packages; }
public Map<String,Source> sources() { return sources; }
public Map<String,File> artifacts() { return artifacts; }
@Override
public boolean equals(Object o) {
return (o instanceof Module module) && name.equals(module.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public int compareTo(Module o) {
return name.compareTo(o.name);
}
public void save(StringBuilder b) {
b.append("M ").append(name).append(":").append("\n");
Package.savePackages(packages, b);
}
public static Module load(String l) {
int cp = l.indexOf(':',2);
if (cp == -1) return null;
String name = l.substring(2,cp);
return new Module(name, "");
}
public static void saveModules(Map<String,Module> ms, StringBuilder b) {
for (Module m : ms.values()) {
m.save(b);
}
}
public void addPackage(Package p) {
packages.put(p.name(), p);
}
public Package lookupPackage(String pkg) {
// See JDK-8071904
Package p = packages.get(pkg);
if (p == null) {
p = new Package(this, pkg);
packages.put(pkg, p);
}
return p;
}
public void addSource(String pkg, Source src) {
Package p = lookupPackage(pkg);
src.setPackage(p);
p.addSource(src);
sources.put(src.file().getPath(), src);
}
public Source lookupSource(String path) {
return sources.get(path);
}
public void addArtifacts(String pkg, Set<URI> as) {
Package p = lookupPackage(pkg);
for (URI u : as) {
p.addArtifact(new File(u));
}
}
public void setDependencies(String pkg, Map<String, Set<String>> deps, boolean cp) {
lookupPackage(pkg).setDependencies(deps, cp);
}
public void setPubapi(String pkg, PubApi ps) {
Package p = lookupPackage(pkg);
p.setPubapi(ps);
}
public boolean hasPubapiChanged(String pkg, PubApi newPubApi) {
Package p = lookupPackage(pkg);
return p.hasPubApiChanged(newPubApi);
}
}

View File

@ -1,293 +0,0 @@
/*
* Copyright (c) 2012, 2022, 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.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
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.
* For example its sources, dependents, its pubapi and its artifacts.
*
* It might look odd that we track dependents/pubapi/artifacts on
* a package level, but it makes sense since recompiling a full package
* takes as long as recompiling a single java file in that package,
* if you take into account the startup time of the jvm.
*
* Also the dependency information will be much smaller (good for the javac_state file size)
* and it simplifies tracking artifact generation, you do not always know from which
* source a class file was generated, but you always know which package it belongs to.
*
* It is also educational to see package dependencies triggering recompilation of
* other packages. Even though the recompilation was perhaps not necessary,
* the visible recompilation of the dependent packages indicates how much circular
* dependencies your code has.
*
* <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 Package implements Comparable<Package> {
// The module this package belongs to. (There is a legacy module with an empty string name,
// used for all legacy sources.)
private Module mod;
// Name of this package, module:pkg
// ex1 jdk.base:java.lang
// ex2 :java.lang (when in legacy mode)
private String name;
// 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 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 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.
private Map<String,File> artifacts = new HashMap<>();
public Package(Module m, String n) {
int c = n.indexOf(":");
Assert.check(c != -1);
Assert.check(m.name().equals(m.name()));
name = n;
dirname = n.replace('.', File.separatorChar);
if (m.name().length() > 0) {
// There is a module here, prefix the module dir name to the path.
dirname = m.dirname()+File.separatorChar+dirname;
}
}
public Module mod() { return mod; }
public String name() { return name; }
public String dirname() { return dirname; }
public Map<String,Source> sources() { return sources; }
public Map<String,File> artifacts() { return artifacts; }
public PubApi getPubApi() { return pubApi; }
public Map<String,Set<String>> typeDependencies() { return dependencies; }
public Map<String,Set<String>> typeClasspathDependencies() { return cpDependencies; }
public Set<String> dependents() { return dependents; }
@Override
public boolean equals(Object o) {
return (o instanceof Package pac) && name.equals(pac.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public int compareTo(Package o) {
return name.compareTo(o.name);
}
public void addSource(Source s) {
sources.put(s.file().getPath(), s);
}
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);
}
/**
* 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.isEmpty();
}
public boolean hasPubApiChanged(PubApi newPubApi) {
return !newPubApi.isBackwardCompatibleWith(pubApi);
}
public void setPubapi(PubApi newPubApi) {
pubApi = newPubApi;
}
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) {
b.append("P ").append(name).append("\n");
Source.saveSources(sources, b);
saveDependencies(b);
savePubapi(b);
saveArtifacts(b);
}
public static Package load(Module module, String l) {
String name = l.substring(2);
return new Package(module, name);
}
public void saveDependencies(StringBuilder b) {
// 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));
}
}
// 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) {
pubApi.asListOfStrings()
.stream()
.flatMap(l -> Stream.of("I ", l, "\n"))
.forEach(b::append);
}
public static void savePackages(Map<String,Package> packages, StringBuilder b) {
List<String> sorted_packages = new ArrayList<>();
for (String key : packages.keySet() ) {
sorted_packages.add(key);
}
Collections.sort(sorted_packages);
for (String s : sorted_packages) {
Package p = packages.get(s);
p.save(b);
}
}
public void addArtifact(String a) {
artifacts.put(a, new File(a));
}
public void addArtifact(File f) {
artifacts.put(f.getPath(), f);
}
public void addArtifacts(Set<URI> as) {
for (URI u : as) {
addArtifact(new File(u));
}
}
public void setArtifacts(Set<URI> as) {
Assert.check(!artifacts.isEmpty());
artifacts = new HashMap<>();
addArtifacts(as);
}
public void loadArtifact(String l) {
// Find next space after "A ".
int dp = l.indexOf(' ',2);
String fn = l.substring(2,dp);
long last_modified = Long.parseLong(l.substring(dp+1));
File f = new File(fn);
if (f.exists() && f.lastModified() != last_modified) {
// Hmm, the artifact on disk does not have the same last modified
// timestamp as the information from the build database.
// We no longer trust the artifact on disk. Delete it.
// The smart javac wrapper will then rebuild the artifact.
Log.debug("Removing "+f.getPath()+" since its timestamp does not match javac_state.");
f.delete();
}
artifacts.put(f.getPath(), f);
}
public void saveArtifacts(StringBuilder b) {
List<File> sorted_artifacts = new ArrayList<>();
for (File f : artifacts.values()) {
sorted_artifacts.add(f);
}
Collections.sort(sorted_artifacts);
for (File f : sorted_artifacts) {
// The last modified information is only used
// to detect tampering with the output dir.
// If the outputdir has been modified, not by javac,
// then a mismatch will be detected in the last modified
// timestamps stored in the build database compared
// to the timestamps on disk and the artifact will be deleted.
b.append("A "+f.getPath()+" "+f.lastModified()+"\n");
}
}
/**
* Always clean out a tainted package before it is recompiled.
*/
public void deleteArtifacts() {
for (File a : artifacts.values()) {
a.delete();
}
}
}

View File

@ -1,41 +0,0 @@
/*
* 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;
/**
* Used to signal serious problems when running sjavac.
*
* <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 ProblemException extends Exception {
static final long serialVersionUID = -3387516993124229949L;
public ProblemException(String s) {
super(s);
}
}

View File

@ -1,95 +0,0 @@
/*
* 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.IOException;
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.code.Symtab;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Convert;
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.
final Context context;
final CompilationTask task;
final SmartFileManager fileManager;
/**
* 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();
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) {
Symtab syms = Symtab.instance(context);
ClassFinder cr = ClassFinder.instance(context);
Names ns = Names.instance(context);
Name n = ns.fromString(fullyQualifiedClassName);
ClassSymbol cs = cr.loadClass(syms.inferModule(Convert.packagePart(n)), n);
PubapiVisitor v = new PubapiVisitor();
v.visit(cs);
return v.getCollectedPubApi();
}
public void close() throws IOException {
fileManager.close();
}
}

View File

@ -1,308 +0,0 @@
/*
* Copyright (c) 2012, 2021, 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.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Set;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.regex.PatternSyntaxException;
/** A Source object maintains information about a source file.
* For example which package it belongs to and kind of source it is.
* The class also knows how to find source files (scanRoot) given include/exclude
* patterns and a root.
*
* <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 Source implements Comparable<Source> {
// The package the source belongs to.
private Package pkg;
// Name of this source file, relative its source root.
// For example: java/lang/Object.java
// Or if the source file is inside a module:
// jdk.base/java/lang/Object.java
private String name;
// What kind of file is this.
private String suffix;
// When this source file was last_modified
private long lastModified;
// The source File.
private File file;
// If the source is generated.
private boolean isGenerated;
// If the source is only linked to, not compiled.
private boolean linkedOnly;
@Override
public boolean equals(Object o) {
return (o instanceof Source source) && name.equals(source.name);
}
@Override
public int compareTo(Source o) {
return name.compareTo(o.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
public Source(Module m, String n, File f) {
name = n;
int dp = n.lastIndexOf(".");
if (dp != -1) {
suffix = n.substring(dp);
} else {
suffix = "";
}
file = f;
lastModified = f.lastModified();
linkedOnly = false;
}
public Source(Package p, String n, long lm) {
pkg = p;
name = n;
int dp = n.lastIndexOf(".");
if (dp != -1) {
suffix = n.substring(dp);
} else {
suffix = "";
}
file = null;
lastModified = lm;
linkedOnly = false;
int ls = n.lastIndexOf('/');
}
public String name() { return name; }
public String suffix() { return suffix; }
public Package pkg() { return pkg; }
public File file() { return file; }
public long lastModified() {
return lastModified;
}
public void setPackage(Package p) {
pkg = p;
}
public void markAsGenerated() {
isGenerated = true;
}
public boolean isGenerated() {
return isGenerated;
}
public void markAsLinkedOnly() {
linkedOnly = true;
}
public boolean isLinkedOnly() {
return linkedOnly;
}
private void save(StringBuilder b) {
String CL = linkedOnly?"L":"C";
String GS = isGenerated?"G":"S";
b.append(GS+" "+CL+" "+name+" "+file.lastModified()+"\n");
}
// Parse a line that looks like this:
// S C /code/alfa/A.java 1357631228000
public static Source load(Package lastPackage, String l, boolean isGenerated) {
int sp = l.indexOf(' ',4);
if (sp == -1) return null;
String name = l.substring(4,sp);
long last_modified = Long.parseLong(l.substring(sp+1));
boolean isLinkedOnly = false;
if (l.charAt(2) == 'L') {
isLinkedOnly = true;
} else if (l.charAt(2) == 'C') {
isLinkedOnly = false;
} else return null;
Source s = new Source(lastPackage, name, last_modified);
s.file = new File(name);
if (isGenerated) s.markAsGenerated();
if (isLinkedOnly) s.markAsLinkedOnly();
return s;
}
public static void saveSources(Map<String,Source> sources, StringBuilder b) {
List<String> sorted_sources = new ArrayList<>();
for (String key : sources.keySet()) {
sorted_sources.add(key);
}
Collections.sort(sorted_sources);
for (String key : sorted_sources) {
Source s = sources.get(key);
s.save(b);
}
}
/**
* Recurse into the directory root and find all files matching the excl/incl/exclfiles/inclfiles rules.
* Detects the existence of module-info.java files and presumes that the directory it resides in
* is the name of the current module.
*/
public static void scanRoot(File root,
Set<String> suffixes,
List<String> excludes,
List<String> includes,
Map<String,Source> foundFiles,
Map<String,Module> foundModules,
final Module currentModule,
boolean permitSourcesWithoutPackage,
boolean inGensrc,
boolean inLinksrc)
throws IOException, ProblemException {
if (root == null)
return;
FileSystem fs = root.toPath().getFileSystem();
if (includes.isEmpty()) {
includes = Collections.singletonList("**");
}
List<PathMatcher> includeMatchers = createPathMatchers(fs, includes);
List<PathMatcher> excludeMatchers = createPathMatchers(fs, excludes);
Files.walkFileTree(root.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path relToRoot = root.toPath().relativize(file);
if (includeMatchers.stream().anyMatch(im -> im.matches(relToRoot))
&& excludeMatchers.stream().noneMatch(em -> em.matches(relToRoot))
&& suffixes.contains(Util.fileSuffix(file))) {
// TODO: Test this.
Source existing = foundFiles.get(file);
if (existing != null) {
throw new IOException("You have already added the file "+file+" from "+existing.file().getPath());
}
existing = currentModule.lookupSource(file.toString());
if (existing != null) {
// Oops, the source is already added, could be ok, could be not, let's check.
if (inLinksrc) {
// So we are collecting sources for linking only.
if (existing.isLinkedOnly()) {
// Ouch, this one is also for linking only. Bad.
throw new IOException("You have already added the link only file " + file + " from " + existing.file().getPath());
}
// Ok, the existing source is to be compiled. Thus this link only is redundant
// since all compiled are also linked to. Continue to the next source.
// But we need to add the source, so that it will be visible to linking,
// if not the multi core compile will fail because a JavaCompiler cannot
// find the necessary dependencies for its part of the source.
foundFiles.put(file.toString(), existing);
} else {
// We are looking for sources to compile, if we find an existing to be compiled
// source with the same name, it is an internal error, since we must
// find the sources to be compiled before we find the sources to be linked to.
throw new IOException("Internal error: Double add of file " + file + " from " + existing.file().getPath());
}
} else {
//////////////////////////////////////////////////////////////
// Add source
Source s = new Source(currentModule, file.toString(), file.toFile());
if (inGensrc) {
s.markAsGenerated();
}
if (inLinksrc) {
s.markAsLinkedOnly();
}
String pkg = packageOfJavaFile(root.toPath(), file);
pkg = currentModule.name() + ":" + pkg;
foundFiles.put(file.toString(), s);
currentModule.addSource(pkg, s);
//////////////////////////////////////////////////////////////
}
}
return FileVisitResult.CONTINUE;
}
});
}
private static List<PathMatcher> createPathMatchers(FileSystem fs, List<String> patterns) {
List<PathMatcher> matchers = new ArrayList<>();
for (String pattern : patterns) {
try {
matchers.add(fs.getPathMatcher("glob:" + pattern));
} catch (PatternSyntaxException e) {
Log.error("Invalid pattern: " + pattern);
throw e;
}
}
return matchers;
}
private static String packageOfJavaFile(Path sourceRoot, Path javaFile) {
Path javaFileDir = javaFile.getParent();
Path packageDir = sourceRoot.relativize(javaFileDir);
List<String> separateDirs = new ArrayList<>();
for (Path pathElement : packageDir) {
separateDirs.add(pathElement.getFileName().toString());
}
return String.join(".", separateDirs);
}
@Override
public String toString() {
return String.format("%s[pkg: %s, name: %s, suffix: %s, file: %s, isGenerated: %b, linkedOnly: %b]",
getClass().getSimpleName(),
pkg,
name,
suffix,
file,
isGenerated,
linkedOnly);
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright (c) 2012, 2022, 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.Writer;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.comp.CompilationService;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
* The transform interface is used to transform content inside a package, from one form to another.
* Usually the output form is an unpredictable number of output files. (eg class files)
* but can also be an unpredictable number of generated source files (eg idl2java)
* or a single predictable output file (eg when copying, cleaning or compiling a properties file).
*
* <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 interface Transformer {
/**
* The transform method takes a set of package names, mapped to their source files and to the
* pubapis of the packages.
*
* The transform implementation must:
* store the names of the generated artifacts for each package into package_artifacts
* store found dependencies to other packages into the supplied set package_dependencies
* store the public api for a package into the supplied set package_pubapis
*
* Any benign messages as a result of running the transform
* are written into stdout, and errors are written to stderr.
*
* The debug_level can be 0=silent (only warnings and errors) 1=normal 2=verbose 3 or greater=debug
* setExtra is used to set the extra information information that can be passed on
* the command line to the smart javac wrapper.
*
* If sjavac is building incrementally from an existing javac_state, the var incremental is true.
*
* The transformer will only be called if some source in the package (or dependency) has
* a modified timestamp. Thus the transformer might get called with many sources, of which
* only one has changed. The transformer is allowed to regenerate all artifacts but
* a better transformer will only write those artifacts that need updating.
*
* However the transformer must verify that the existing artifacts really are there!
* and it must always update package_artifacts, package_dependencies, and package_pubapis correctly.
* This means that at least for Java source, it will always have to recompile the sources.
*
* The transformer is allowed to put files anywhere in the dest_root.
* An example of this is, can be the META-INF transformer that copy files
* below META-INF directories to the single META-INF directory below dest_root.
*
* False is returned if there was an error that prevented the transform.
* I.e. something was printed on stderr.
*
* If num_cores is set to a non-zero value. The transform should attempt to use no more than these
* number of threads for heavy work.
*/
boolean transform(CompilationService sjavac,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSources,
Map<String,Set<String>> oldPackageDependencies,
URI destRoot,
Map<String,Set<URI>> packageArtifacts,
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);
void setExtra(String e);
void setExtra(Options args);
}

View File

@ -1,171 +0,0 @@
/*
* Copyright (c) 2015, 2016, 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.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
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.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
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.sjavac.Log;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.comp.dependencies.NewDependencyCollector;
import com.sun.tools.sjavac.comp.dependencies.PublicApiCollector;
import com.sun.tools.sjavac.server.CompilationSubResult;
import com.sun.tools.sjavac.server.SysInfo;
/**
* <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 CompilationService {
public SysInfo getSysInfo() {
return new SysInfo(Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().maxMemory());
}
public CompilationSubResult compile(String protocolId,
String invocationId,
String[] args,
List<File> explicitSources,
Set<URI> sourcesToCompile,
Set<URI> visibleSources) {
JavacTool compiler = (JavacTool) ToolProvider.getSystemJavaCompiler();
try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
SmartFileManager sfm = new SmartFileManager(fm);
Context context = new Context();
Dependencies.GraphDependencies.preRegister(context);
// Now setup the actual compilation
CompilationSubResult compilationResult = new CompilationSubResult(Result.OK);
// 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
ListBuffer<File> sourcesToCompileFiles = new ListBuffer<>();
for (URI u : sourcesToCompile)
sourcesToCompileFiles.append(new File(u));
for (JavaFileObject jfo : fm.getJavaFileObjectsFromFiles(sourcesToCompileFiles))
explicitJFOs.append(SmartFileManager.locWrap(jfo, StandardLocation.SOURCE_PATH));
// Create a log to capture compiler output
StringWriter stderrLog = new StringWriter();
Result result;
PublicApiCollector pubApiCollector = new PublicApiCollector(context, explicitJFOs);
PathAndPackageVerifier papVerifier = new PathAndPackageVerifier();
NewDependencyCollector depsCollector = new NewDependencyCollector(context, explicitJFOs);
try {
if (explicitJFOs.size() > 0) {
sfm.setVisibleSources(visibleSources);
sfm.cleanArtifacts();
// Do the compilation!
JavacTaskImpl task =
(JavacTaskImpl) compiler.getTask(new PrintWriter(stderrLog),
sfm,
null,
Arrays.asList(args),
null,
explicitJFOs,
context);
sfm.setSymbolFileEnabled(!com.sun.tools.javac.util.Options.instance(context).isSet("ignore.symbol.file"));
task.addTaskListener(depsCollector);
task.addTaskListener(pubApiCollector);
task.addTaskListener(papVerifier);
logJavacInvocation(args);
result = task.doCall();
Log.debug("javac result: " + result);
sfm.flush();
} else {
result = Result.ERROR;
}
} catch (Exception e) {
Log.error(Util.getStackTrace(e));
stderrLog.append(Util.getStackTrace(e));
result = Result.ERROR;
}
compilationResult.packageArtifacts = sfm.getPackageArtifacts();
if (papVerifier.errorsDiscovered()) {
result = Result.ERROR;
}
compilationResult.packageDependencies = depsCollector.getDependencies(false);
compilationResult.packageCpDependencies = depsCollector.getDependencies(true);
compilationResult.packagePubapis = pubApiCollector.getPubApis(true);
compilationResult.dependencyPubapis = pubApiCollector.getPubApis(false);
compilationResult.stderr = stderrLog.toString();
compilationResult.result = result;
return compilationResult;
} catch (IOException e) {
throw new Error(e);
}
}
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);
}
}
}

View File

@ -1,67 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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) {
return (obj instanceof JavaFileObjectWithLocation<?> javaFileObjectWithLocation)
&& loc.equals(javaFileObjectWithLocation.loc)
&& fileObject.equals(javaFileObjectWithLocation.fileObject);
}
}

View File

@ -1,152 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.tools.JavaFileObject;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
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 {
// Stores the set of compilation units whose source file path does not
// match the package declaration.
Set<CompilationUnitTree> misplacedCompilationUnits = new HashSet<>();
@Override
@DefinedBy(Api.COMPILER_TREE)
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());
}
}
}
public boolean errorsDiscovered() {
return misplacedCompilationUnits.size() > 0;
}
/* Returns true if dir matches pkgName.
*
* Examples:
* (a/b/c, a.b.c) gives true
* (i/j/k, i.x.k) gives false
*
* Currently (x/a/b/c, a.b.c) also gives true. See JDK-8059598.
*/
private boolean checkPathAndPackage(Path dir, JCTree pkgName) {
Iterator<String> pathIter = new ParentIterator(dir);
Iterator<String> pkgIter = new EnclosingPkgIterator(pkgName);
while (pathIter.hasNext() && pkgIter.hasNext()) {
if (!pathIter.next().equals(pkgIter.next()))
return false;
}
return !pkgIter.hasNext(); /*&& !pathIter.hasNext() See JDK-8059598 */
}
/* Iterates over the names of the parents of the given path:
* Example: dir1/dir2/dir3 results in dir3 -> dir2 -> dir1
*/
private static class ParentIterator implements Iterator<String> {
Path next;
ParentIterator(Path initial) {
next = initial;
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public String next() {
String tmp = next.getFileName().toString();
next = next.getParent();
return tmp;
}
}
/* Iterates over the names of the enclosing packages:
* Example: pkg1.pkg2.pkg3 results in pkg3 -> pkg2 -> pkg1
*/
private static class EnclosingPkgIterator implements Iterator<String> {
JCTree next;
EnclosingPkgIterator(JCTree initial) {
next = initial;
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public String next() {
Name name;
if (next instanceof JCIdent identNext) {
name = identNext.name;
next = null;
} else {
JCFieldAccess fa = (JCFieldAccess) next;
name = fa.name;
next = fa.selected;
}
return name.toString();
}
}
}

View File

@ -1,108 +0,0 @@
/*
* 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());
}
}

View File

@ -1,172 +0,0 @@
/*
* Copyright (c) 2011, 2019, 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 static javax.lang.model.element.Modifier.PRIVATE;
import java.util.List;
import java.util.stream.Collectors;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementScanner14;
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.
*
* <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 PubapiVisitor extends ElementScanner14<Void, Void> {
private PubApi collectedApi = new PubApi();
private boolean isNonPrivate(Element e) {
return !e.getModifiers().contains(PRIVATE);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Void visitType(TypeElement e, Void p) {
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 (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 static final 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)
// then this class is never visible outside of the package anyway, so
// we are allowed to ignore it here.
return null;
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Void visitRecordComponent(RecordComponentElement e, Void p) {
PubVar v = new PubVar(e.getModifiers(),
TypeDesc.fromType(e.asType()),
e.toString(),
null);
collectedApi.recordComponents.put(v.identifier, v);
return null;
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Void visitExecutable(ExecutableElement e, Void p) {
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;
}
private List<PubApiTypeParam> getTypeParameters(List<? extends TypeParameterElement> elements) {
return elements.stream()
.map(e -> new PubApiTypeParam(e.getSimpleName().toString(), getTypeDescs(e.getBounds())))
.toList();
}
private List<TypeMirror> getParamTypes(ExecutableElement e) {
return e.getParameters()
.stream()
.map(VariableElement::asType)
.toList();
}
private List<TypeDesc> getTypeDescs(List<? extends TypeMirror> list) {
return list.stream()
.map(TypeDesc::fromType)
.toList();
}
public PubApi getCollectedPubApi() {
return collectedApi;
}
}

View File

@ -1,399 +0,0 @@
/*
* Copyright (c) 2014, 2022, 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.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.javac.util.Context;
import com.sun.tools.sjavac.JavacState;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Module;
import com.sun.tools.sjavac.ProblemException;
import com.sun.tools.sjavac.Source;
import com.sun.tools.sjavac.Transformer;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.options.Option;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.options.SourceLocation;
import com.sun.tools.sjavac.server.Sjavac;
import java.io.UncheckedIOException;
import javax.tools.JavaFileManager;
/**
* The sjavac implementation that interacts with javac and performs the actual
* compilation.
*
* <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 SjavacImpl implements Sjavac {
@Override
public Result compile(String[] args) {
Options options;
try {
options = Options.parseArgs(args);
} catch (IllegalArgumentException e) {
Log.error(e.getMessage());
return Result.CMDERR;
}
if (!validateOptions(options))
return Result.CMDERR;
if (srcDstOverlap(options.getSources(), options.getDestDir())) {
return Result.CMDERR;
}
if (!createIfMissing(options.getDestDir()))
return Result.ERROR;
Path stateDir = options.getStateDir();
if (stateDir != null && !createIfMissing(options.getStateDir()))
return Result.ERROR;
Path gensrc = options.getGenSrcDir();
if (gensrc != null && !createIfMissing(gensrc))
return Result.ERROR;
Path hdrdir = options.getHeaderDir();
if (hdrdir != null && !createIfMissing(hdrdir))
return Result.ERROR;
if (stateDir == null) {
// Prepare context. Direct logging to our byte array stream.
Context context = new Context();
StringWriter strWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(strWriter);
com.sun.tools.javac.util.Log.preRegister(context, printWriter);
JavacFileManager.preRegister(context);
// Prepare arguments
String[] passThroughArgs = Stream.of(args)
.filter(arg -> !arg.startsWith(Option.SERVER.arg))
.toArray(String[]::new);
// Compile
Result result = new Main("javac", printWriter).compile(passThroughArgs, context);
// Process compiler output (which is always errors)
printWriter.flush();
Util.getLines(strWriter.toString()).forEach(Log::error);
// Clean up
JavaFileManager fileManager = context.get(JavaFileManager.class);
if (fileManager instanceof JavacFileManager javacFileManager) {
try {
javacFileManager.close();
} catch (IOException es) {
throw new UncheckedIOException(es);
}
}
return result;
} else {
// Load the prev build state database.
JavacState javac_state = JavacState.load(options);
// Setup the suffix rules from the command line.
Map<String, Transformer> suffixRules = new HashMap<>();
// Handling of .java-compilation
suffixRules.putAll(javac_state.getJavaSuffixRule());
// Handling of -copy and -tr
suffixRules.putAll(options.getTranslationRules());
// All found modules are put here.
Map<String,Module> modules = new HashMap<>();
// We start out in the legacy empty no-name module.
// As soon as we stumble on a module-info.java file we change to that module.
Module current_module = new Module("", "");
modules.put("", current_module);
try {
// Find all sources, use the suffix rules to know which files are sources.
Map<String,Source> sources = new HashMap<>();
// Find the files, this will automatically populate the found modules
// with found packages where the sources are found!
findSourceFiles(options.getSources(),
suffixRules.keySet(),
sources,
modules,
current_module,
options.isDefaultPackagePermitted(),
false);
if (sources.isEmpty()) {
Log.error("Found nothing to compile!");
return Result.ERROR;
}
// Create a map of all source files that are available for linking. Both -src and
// -sourcepath point to such files. It is possible to specify multiple
// -sourcepath options to enable different filtering rules. If the
// filters are the same for multiple sourcepaths, they may be concatenated
// using :(;). Before sending the list of sourcepaths to javac, they are
// all concatenated. The list created here is used by the SmartFileWrapper to
// make sure only the correct sources are actually available.
// We might find more modules here as well.
Map<String,Source> sources_to_link_to = new HashMap<>();
List<SourceLocation> sourceResolutionLocations = new ArrayList<>();
sourceResolutionLocations.addAll(options.getSources());
sourceResolutionLocations.addAll(options.getSourceSearchPaths());
findSourceFiles(sourceResolutionLocations,
Collections.singleton(".java"),
sources_to_link_to,
modules,
current_module,
options.isDefaultPackagePermitted(),
true);
// Add the set of sources to the build database.
javac_state.now().flattenPackagesSourcesAndArtifacts(modules);
javac_state.now().checkInternalState("checking sources", false, sources);
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);
// Find all existing artifacts. Their timestamp will match the last modified timestamps stored
// in javac_state, simply because loading of the JavacState will clean out all artifacts
// that do not match the javac_state database.
javac_state.findAllArtifacts();
// Remove unidentified artifacts from the bin, gensrc and header dirs.
// (Unless we allow them to be there.)
// I.e. artifacts that are not known according to the build database (javac_state).
// For examples, files that have been manually copied into these dirs.
// Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp
// in javac_state) have already been removed when the javac_state was loaded.
if (!options.areUnidentifiedArtifactsPermitted()) {
javac_state.removeUnidentifiedArtifacts();
}
// 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.
javac_state.performCopying(Util.pathToFile(options.getDestDir()), suffixRules);
// Translate files, for example compile properties or compile idls.
javac_state.performTranslation(Util.pathToFile(gensrc), suffixRules);
// Add any potentially generated java sources to the tobe compiled list.
// (Generated sources must always have a package.)
Map<String,Source> generated_sources = new HashMap<>();
Source.scanRoot(Util.pathToFile(options.getGenSrcDir()),
Util.set(".java"),
Collections.emptyList(),
Collections.emptyList(),
generated_sources,
modules,
current_module,
false,
true,
false);
javac_state.now().flattenPackagesSourcesAndArtifacts(modules);
// Recheck the source files and their timestamps again.
javac_state.checkSourceStatus(true);
// Now do a safety check that the list of source files is identical
// to the list Make believes we are compiling. If we do not get this
// right, then incremental builds will fail with subtility.
// If any difference is detected, then we will fail hard here.
// This is an important safety net.
javac_state.compareWithMakefileList(Util.pathToFile(options.getSourceReferenceList()));
// Do the compilations, repeatedly until no tainted packages exist.
boolean again;
// Collect the name of all compiled packages.
Set<String> recently_compiled = new HashSet<>();
boolean[] rc = new boolean[1];
CompilationService compilationService = new CompilationService();
do {
if (round > 0)
printRound(round);
// Clean out artifacts in tainted packages.
javac_state.deleteClassArtifactsInTaintedPackages();
again = javac_state.performJavaCompilations(compilationService,
options,
recently_compiled,
rc);
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();
// Reflatten only the artifacts.
javac_state.now().flattenArtifacts(modules);
// Remove artifacts that were generated during the last compile, but not this one.
javac_state.removeSuperfluousArtifacts(recently_compiled);
}
return rc[0] ? Result.OK : Result.ERROR;
} catch (ProblemException e) {
// For instance make file list mismatch.
Log.error(e.getMessage());
Log.debug(e);
return Result.ERROR;
} catch (Exception e) {
Log.error(e);
return Result.ERROR;
}
}
}
@Override
public void shutdown() {
// Nothing to clean up
}
private static boolean validateOptions(Options options) {
String err = null;
if (options.getDestDir() == null) {
err = "Please specify output directory.";
} else if (options.isJavaFilesAmongJavacArgs()) {
err = "Sjavac does not handle explicit compilation of single .java files.";
} else if (!options.getImplicitPolicy().equals("none")) {
err = "The only allowed setting for sjavac is -implicit:none";
} else if (options.getSources().isEmpty() && options.getStateDir() != null) {
err = "You have to specify -src when using --state-dir.";
} else if (options.getTranslationRules().size() > 1
&& options.getGenSrcDir() == null) {
err = "You have translators but no gensrc dir (-s) specified!";
}
if (err != null)
Log.error(err);
return err == null;
}
private static boolean srcDstOverlap(List<SourceLocation> locs, Path dest) {
for (SourceLocation loc : locs) {
if (isOverlapping(loc.getPath(), dest)) {
Log.error("Source location " + loc.getPath() + " overlaps with destination " + dest);
return true;
}
}
return false;
}
private static boolean isOverlapping(Path p1, Path p2) {
p1 = p1.toAbsolutePath().normalize();
p2 = p2.toAbsolutePath().normalize();
return p1.startsWith(p2) || p2.startsWith(p1);
}
private static boolean createIfMissing(Path dir) {
if (Files.isDirectory(dir))
return true;
if (Files.exists(dir)) {
Log.error(dir + " is not a directory.");
return false;
}
try {
Files.createDirectories(dir);
} catch (IOException e) {
Log.error("Could not create directory: " + e.getMessage());
return false;
}
return true;
}
/** Find source files in the given source locations. */
public static void findSourceFiles(List<SourceLocation> sourceLocations,
Set<String> sourceTypes,
Map<String,Source> foundFiles,
Map<String, Module> foundModules,
Module currentModule,
boolean permitSourcesInDefaultPackage,
boolean inLinksrc)
throws IOException {
for (SourceLocation source : sourceLocations) {
source.findSourceFiles(sourceTypes,
foundFiles,
foundModules,
currentModule,
permitSourcesInDefaultPackage,
inLinksrc);
}
}
private static void printRound(int round) {
Log.debug("****************************************");
Log.debug("* Round " + round + " *");
Log.debug("****************************************");
}
}

View File

@ -1,275 +0,0 @@
/*
* Copyright (c) 2012, 2021, 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.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.tools.*;
import javax.tools.JavaFileObject.Kind;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.ListBuffer;
/**
* Intercepts reads and writes to the file system to gather
* information about what artifacts are generated.
*
* Traps writes to certain files, if the content written is identical
* to the existing file.
*
* Can also blind out the file manager from seeing certain files in the file system.
* Necessary to prevent javac from seeing some sources where the source path points.
*
* <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>
*/
@com.sun.tools.javac.api.ClientCodeWrapper.Trusted
public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager> {
// Set of sources that can be seen by javac.
Set<URI> visibleSources = new HashSet<>();
// Map from modulename:packagename to artifacts.
Map<String,Set<URI>> packageArtifacts = new HashMap<>();
public SmartFileManager(JavaFileManager fileManager) {
super(fileManager);
}
public void setVisibleSources(Set<URI> s) {
visibleSources = s;
}
public void cleanArtifacts() {
packageArtifacts = new HashMap<>();
}
/**
* Set whether or not to use ct.sym as an alternate to rt.jar.
*/
public void setSymbolFileEnabled(boolean b) {
if (!(fileManager instanceof JavacFileManager javacFileManager))
throw new IllegalStateException();
javacFileManager.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;
}
@Override @DefinedBy(Api.COMPILER)
public Iterable<JavaFileObject> list(Location location,
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 locWrapMany(files, location);
}
// Now filter!
ListBuffer<JavaFileObject> filteredFiles = new ListBuffer<>();
for (JavaFileObject f : files) {
URI uri = f.toUri();
String t = uri.toString();
if (t.startsWith("jar:")
|| t.endsWith(".class")
|| visibleSources.contains(uri)) {
filteredFiles.add(f);
}
}
return locWrapMany(filteredFiles, location);
}
@Override @DefinedBy(Api.COMPILER)
public JavaFileObject getJavaFileForInput(Location location,
String className,
Kind kind) throws IOException {
JavaFileObject file = super.getJavaFileForInput(location, className, kind);
file = locWrap(file, location);
if (file == null || visibleSources.isEmpty()) {
return file;
}
if (visibleSources.contains(file.toUri()) || isModuleInfo(file)) {
return file;
}
return null;
}
@Override @DefinedBy(Api.COMPILER)
public JavaFileObject getJavaFileForOutput(Location location,
String className,
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 = "";
if (dp != -1) {
pkg_name = className.substring(0, dp);
}
// When modules are in use, then the mod_name might be something like "jdk_base"
String mod_name = "";
addArtifact(mod_name+":"+pkg_name, file.toUri());
return file;
}
@Override @DefinedBy(Api.COMPILER)
public FileObject getFileForInput(Location location,
String packageName,
String relativeName) throws IOException {
FileObject file = super.getFileForInput(location, packageName, relativeName);
file = locWrap(file, location);
if (file == null || visibleSources.isEmpty()) {
return file;
}
if (visibleSources.contains(file.toUri()) || isModuleInfo(file)) {
return file;
}
return null;
}
private boolean isModuleInfo(FileObject fo) {
return (fo instanceof JavaFileObject javaFileObject)
&& (javaFileObject.isNameCompatible("module-info", Kind.SOURCE)
|| javaFileObject.isNameCompatible("module-info", Kind.CLASS));
}
@Override @DefinedBy(Api.COMPILER)
public FileObject getFileForOutput(Location location,
String packageName,
String relativeName,
FileObject sibling) throws IOException {
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) && superFile instanceof JavaFileObject) {
file = new SmartFileObject((JavaFileObject) file);
packageName = ":" + packageNameFromFileName(relativeName);
}
if (packageName.equals("")) {
packageName = ":";
}
addArtifact(packageName, file.toUri());
return file;
}
@Override @DefinedBy(Api.COMPILER)
public Location getLocationForModule(Location location, JavaFileObject fo) throws IOException {
return super.getLocationForModule(location, locUnwrap(fo));
}
private static String packageNameFromFileName(String fn) {
StringBuilder sb = new StringBuilder();
int p = fn.indexOf('_'), pp = 0;
while (p != -1) {
if (sb.length() > 0) sb.append('.');
sb.append(fn.substring(pp,p));
if (p == fn.length()-1) break;
pp = p+1;
p = fn.indexOf('_',pp);
}
return sb.toString();
}
void addArtifact(String pkgName, URI art) {
Set<URI> s = packageArtifacts.get(pkgName);
if (s == null) {
s = new HashSet<>();
packageArtifacts.put(pkgName, s);
}
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 javaFileObject)
return locWrap(javaFileObject, 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<?> fileObjectWithLocation)
return fileObjectWithLocation.getDelegate();
if (fo instanceof JavaFileObjectWithLocation<?> javaFileObjectWithLocation)
return javaFileObjectWithLocation.getDelegate();
return fo;
}
private static JavaFileObject locUnwrap(JavaFileObject fo) {
if (fo instanceof JavaFileObjectWithLocation<?> javaFileObjectWithLocation)
return javaFileObjectWithLocation.getDelegate();
return fo;
}
}

View File

@ -1,142 +0,0 @@
/*
* Copyright (c) 2012, 2016, 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.io.*;
import java.net.URI;
import java.nio.file.NoSuchFileException;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
/**
* The SmartFileObject will return an outputstream that cache the written data
* and compare the new content with the old content on disk. Only if they differ,
* will the file be updated.
*
* <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 SmartFileObject implements JavaFileObject {
JavaFileObject file;
public SmartFileObject(JavaFileObject r) {
file = r;
}
@Override
public boolean equals(Object other) {
return file.equals(other);
}
@Override
public int hashCode() {
return file.hashCode();
}
@DefinedBy(Api.COMPILER)
public Kind getKind() {
return file.getKind();
}
@DefinedBy(Api.COMPILER)
public boolean isNameCompatible(String simpleName, Kind kind) {
return file.isNameCompatible(simpleName, kind);
}
@DefinedBy(Api.COMPILER)
public URI toUri() {
return file.toUri();
}
@DefinedBy(Api.COMPILER)
public String getName() {
return file.getName();
}
@DefinedBy(Api.COMPILER)
public InputStream openInputStream() throws IOException {
return file.openInputStream();
}
@DefinedBy(Api.COMPILER)
public OutputStream openOutputStream() throws IOException {
return file.openOutputStream();
}
@DefinedBy(Api.COMPILER)
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return file.getCharContent(ignoreEncodingErrors);
}
static String lineseparator = System.getProperty("line.separator");
@DefinedBy(Api.COMPILER)
public Writer openWriter() throws IOException {
StringBuilder s = new StringBuilder();
try (BufferedReader r = new BufferedReader(file.openReader(true))) {
while (r.ready()) {
s.append(r.readLine()+lineseparator);
}
} catch (FileNotFoundException | NoSuchFileException e) {
// Perfectly ok.
}
return new SmartWriter(file, s.toString(), file.getName());
}
@DefinedBy(Api.COMPILER)
public long getLastModified() {
return file.getLastModified();
}
@DefinedBy(Api.COMPILER)
public boolean delete() {
return file.delete();
}
@DefinedBy(Api.COMPILER)
public Modifier getAccessLevel() {
return file.getAccessLevel();
}
@DefinedBy(Api.COMPILER)
public NestingKind getNestingKind() {
return file.getNestingKind();
}
@DefinedBy(Api.COMPILER)
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
return file.openReader(ignoreEncodingErrors);
}
}

View File

@ -1,197 +0,0 @@
/*
* Copyright (c) 2015, 2022, 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.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
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.Kinds.Kind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Type;
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()
.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<?> javaFileObjectWithLocation) {
return javaFileObjectWithLocation.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<>());
}
Set<String> fqDeps = depsForThisClass.get(fqDep);
if (fqDeps == null) {
depsForThisClass.put(fqDep, fqDeps = new HashSet<>());
}
for (Node<?,?> depNode : getAllDependencies(cnode)) {
CompletionNode cDepNode = (CompletionNode) depNode;
// Symbol is not regarded to depend on itself.
if (cDepNode == cnode) {
continue;
}
// Skip anonymous classes
if (cDepNode.getClassSymbol().fullname == null) {
continue;
}
if (isSymbolRelevant(cp, cDepNode.getClassSymbol())) {
fqDeps.add(cDepNode.getClassSymbol().outermostClass().flatname.toString());
}
}
// The completion dependency graph is not transitively closed for inheritance relations.
// For sjavac's purposes however, a class depends on its super-supertype, so below we
// make sure that we include supertypes.
for (ClassSymbol cs : allSupertypes(cnode.getClassSymbol())) {
if (isSymbolRelevant(cp, cs)) {
fqDeps.add(cs.outermostClass().flatname.toString());
}
}
}
return result;
}
public boolean isSymbolRelevant(boolean cp, ClassSymbol cs) {
Location csLoc = getLocationOf(cs);
Location relevantLocation = cp ? StandardLocation.CLASS_PATH : StandardLocation.SOURCE_PATH;
return csLoc == relevantLocation;
}
private Set<ClassSymbol> allSupertypes(TypeSymbol t) {
if (t == null || !(t instanceof ClassSymbol classSymbol)) {
return Collections.emptySet();
}
Set<ClassSymbol> result = new HashSet<>();
result.add(classSymbol);
result.addAll(allSupertypes(classSymbol.getSuperclass().tsym));
for (Type it : classSymbol.getInterfaces()) {
result.addAll(allSupertypes(it.tsym));
}
return result;
}
private Collection<? extends Node<?, ?>> getAllDependencies(CompletionNode cnode) {
return Stream.of(cnode.getSupportedDependencyKinds())
.flatMap(dk -> cnode.getDependenciesByKind(dk).stream())
.collect(Collectors.toSet());
}
}

View File

@ -1,112 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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.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 {
private Context context;
private final Set<ClassSymbol> classSymbols = new HashSet<>();
private final Collection<JavaFileObject> explicitJFOs;
// 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) {
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;
}
}
private void collectClassSymbols(JCCompilationUnit cu) {
for (Tree t : cu.getTypeDecls()) {
if (t instanceof JCClassDecl classDecl) // Can also be a JCSkip
classSymbols.add(classDecl.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;
}
}

View File

@ -1,383 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.options;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sun.tools.sjavac.CopyFile;
import com.sun.tools.sjavac.Transformer;
/**
* Sjavac options can be classified as:
*
* (1) relevant only for sjavac, such as --server
* (2) relevant for sjavac and javac, such as -d, or
* (3) relevant only for javac, such as -g.
*
* This enum represents all options from (1) and (2). Note that instances of
* this enum only entail static information about the option. For storage of
* option values, refer to com.sun.tools.sjavac.options.Options.
*
* <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 enum Option {
SRC("-src", "Location of source files to be compiled") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
List<Path> paths = getFileListArg(iter, helper);
if (paths != null)
helper.sourceRoots(paths);
}
},
SOURCE_PATH("--source-path", "Specify search path for sources.") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
List<Path> paths = getFileListArg(iter, helper);
if (paths != null)
helper.sourcepath(paths);
}
},
SOURCEPATH("-sourcepath", "An alias for -sourcepath") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
SOURCE_PATH.processMatching(iter, helper);
}
},
MODULE_PATH("--module-path", "Specify search path for modules.") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
List<Path> paths = getFileListArg(iter, helper);
if (paths != null)
helper.modulepath(paths);
}
},
P("-p", "An alias for --module-path") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
MODULE_PATH.processMatching(iter, helper);
}
},
CLASS_PATH("--class-path", "Specify search path for classes.") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
List<Path> paths = getFileListArg(iter, helper);
if (paths != null)
helper.classpath(paths);
}
},
CLASSPATH("-classpath", "An alias for -classpath.") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
CLASS_PATH.processMatching(iter, helper);
}
},
CP("-cp", "An alias for -classpath") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
CLASS_PATH.processMatching(iter, helper);
}
},
X("-x", "Exclude files matching the given pattern") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String pattern = getFilePatternArg(iter, helper);
if (pattern != null)
helper.exclude(pattern);
}
},
I("-i", "Include only files matching the given pattern") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String pattern = getFilePatternArg(iter, helper);
if (pattern != null)
helper.include(pattern);
}
},
TR("-tr", "Translate resources") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
if (!iter.hasNext()) {
helper.reportError(arg + " must be followed by a translation rule");
return;
}
String trArg = iter.next();
// Validate argument syntax. Examples:
// .prop=com.sun.tools.javac.smart.CompileProperties
// .idl=com.sun.corba.CompileIdl
// .g3=antlr.CompileGrammar,debug=true
String ident = "[a-zA-Z_][a-zA-Z0-9_]*";
Pattern p = Pattern.compile("(?<suffix>\\." + ident + ")=" +
"(?<class>" + ident + "(\\." + ident + ")*)" +
"(?<extra>,.*)?");
// Check syntax
Matcher m = p.matcher(trArg);
if (!m.matches()) {
helper.reportError("The string \"" + trArg + "\" is not a " +
"valid translate pattern");
return;
}
// Extract relevant parts
String suffix = m.group("suffix");
String classname = m.group("class");
String extra = m.group("extra");
// Valid suffix?
if (suffix.matches("\\.(class|java)")) {
helper.reportError("You cannot have a translator for " +
suffix + " files!");
return;
}
// Construct transformer
try {
Class<?> trCls = Class.forName(classname);
Transformer transformer =
(Transformer) trCls.getConstructor().newInstance();
transformer.setExtra(extra);
helper.addTransformer(suffix, transformer);
} catch (Exception e) {
helper.reportError("Cannot use " + classname +
" as a translator: " + e.getMessage());
}
}
},
COPY("-copy", "Copy resources") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
if (!iter.hasNext()) {
helper.reportError(arg + " must be followed by a resource type");
return;
}
String copyArg = iter.next();
// Validate argument syntax. Examples: .gif, .html
if (!copyArg.matches("\\.[a-zA-Z_][a-zA-Z0-9_]*")) {
helper.reportError("The string \"" + copyArg + "\" is not a " +
"valid resource type.");
return;
}
helper.addTransformer(copyArg, new CopyFile());
}
},
J("-j", "Number of cores") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
if (!iter.hasNext() || !iter.peek().matches("\\d+")) {
helper.reportError(arg + " must be followed by an integer");
return;
}
helper.numCores(Integer.parseInt(iter.next()));
}
},
SERVER("--server:", "Specify server configuration file of running server") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.serverConf(iter.current().substring(arg.length()));
}
},
STARTSERVER("--startserver:", "Start server and use the given configuration file") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.startServerConf(iter.current().substring(arg.length()));
}
},
IMPLICIT("-implicit:", "Specify how to treat implicitly referenced source code") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.implicit(iter.current().substring(arg.length()));
}
},
LOG("--log=", "Specify logging level") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.logLevel(iter.current().substring(arg.length()));
}
},
VERBOSE("-verbose", "Set verbosity level to \"info\"") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.logLevel("info");
}
},
PERMIT_ARTIFACT("--permit-artifact=", "Allow this artifact in destination directory") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String a = iter.current().substring(arg.length());
helper.permitArtifact(Paths.get(a).toFile().getAbsolutePath());
}
},
PERMIT_UNIDENTIFIED_ARTIFACTS("--permit-unidentified-artifacts", "Allow unidentified artifacts in destination directory") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.permitUnidentifiedArtifacts();
}
},
PERMIT_SOURCES_WITHOUT_PACKAGE("--permit-sources-without-package", "Permit sources in the default package") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.permitDefaultPackage();
}
},
COMPARE_FOUND_SOURCES("--compare-found-sources", "Compare found sources with given sources") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
Path referenceSourceList = getFileArg(iter, helper, true, false);
if (referenceSourceList != null)
helper.compareFoundSources(referenceSourceList);
}
},
D("-d", "Output destination directory") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
Path dir = getFileArg(iter, helper, false, true);
if (dir != null)
helper.destDir(dir);
}
},
S("-s", "Directory for generated sources") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
Path dir = getFileArg(iter, helper, false, true);
if (dir != null)
helper.generatedSourcesDir(dir);
}
},
H("-h", "Directory for header files") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
Path dir = getFileArg(iter, helper, false, true);
if (dir != null)
helper.headerDir(dir);
}
},
STATE_DIR("--state-dir=", "Directory used to store sjavac state and log files.") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String p = iter.current().substring(arg.length());
helper.stateDir(Paths.get(p));
}
};
public final String arg;
final String description;
private Option(String arg, String description) {
this.arg = arg;
this.description = description;
}
/** Retrieve and verify syntax of file list argument. */
List<Path> getFileListArg(ArgumentIterator iter, OptionHelper helper) {
if (!iter.hasNext()) {
helper.reportError(arg + " must be followed by a list of files " +
"separated by " + File.pathSeparator);
return null;
}
List<Path> result = new ArrayList<>();
for (String pathStr : iter.next().split(File.pathSeparator))
result.add(Paths.get(pathStr));
return result;
}
/** Retrieve and verify syntax of file argument. */
Path getFileArg(ArgumentIterator iter, OptionHelper helper, boolean fileAcceptable, boolean dirAcceptable) {
if (!iter.hasNext()) {
String errmsg = arg + " must be followed by ";
if (fileAcceptable && dirAcceptable) errmsg += "a file or directory.";
else if (fileAcceptable) errmsg += "a file.";
else if (dirAcceptable) errmsg += "a directory.";
else throw new IllegalArgumentException("File or directory must be acceptable.");
helper.reportError(errmsg);
return null;
}
return Paths.get(iter.next());
}
/** Retrieve the next file or package argument. */
String getFilePatternArg(ArgumentIterator iter, OptionHelper helper) {
if (!iter.hasNext()) {
helper.reportError(arg + " must be followed by a glob pattern.");
return null;
}
return iter.next();
}
// Future cleanup: Change the "=" syntax to ":" syntax to be consistent and
// to follow the javac-option style.
public boolean hasOption() {
return arg.endsWith(":") || arg.endsWith("=");
}
/**
* Process current argument of argIter.
*
* It's final, since the option customization is typically done in
* processMatching.
*
* @param argIter Iterator to read current and succeeding arguments from.
* @param helper The helper to report back to.
* @return true iff the argument was processed by this option.
*/
public final boolean processCurrent(ArgumentIterator argIter,
OptionHelper helper) {
String fullArg = argIter.current(); // "-tr" or "-log=level"
if (hasOption() ? fullArg.startsWith(arg) : fullArg.equals(arg)) {
processMatching(argIter, helper);
return true;
}
// Did not match
return false;
}
/** Called by process if the current argument matches this option. */
protected abstract void processMatching(ArgumentIterator argIter,
OptionHelper helper);
}

View File

@ -1,161 +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.options;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import com.sun.tools.javac.main.CommandLine;
import com.sun.tools.sjavac.Transformer;
/**
* This class is used to decode sjavac options.
* See com.sun.tools.sjavac.options.Options for example usage.
*
* <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 abstract class OptionHelper {
/** Handle error */
public abstract void reportError(String msg);
/** Record a package exclusion pattern */
public abstract void exclude(String excl);
/** Record a package inclusion pattern */
public abstract void include(String incl);
/** Record a root of sources to be compiled */
public abstract void sourceRoots(List<Path> path);
/** Record a suffix + transformer */
public abstract void addTransformer(String suffix, Transformer tr);
/** Record a sourcepath to be used */
public abstract void sourcepath(List<Path> path);
/** Record a modulepath to be used */
public abstract void modulepath(List<Path> path);
/** Record a classpath to be used */
public abstract void classpath(List<Path> path);
/** Record the number of cores */
public abstract void numCores(int parseInt);
/** Record desired log level */
public abstract void logLevel(String level);
/** Record path for reference source list */
public abstract void compareFoundSources(Path referenceList);
/** Record a single permitted artifact */
public abstract void permitArtifact(String f);
/** Record the fact that unidentified artifacts are permitted */
public abstract void permitUnidentifiedArtifacts();
/** Record the fact that sources in the default package are permitted */
public abstract void permitDefaultPackage();
/** Record server configuration parameters */
public abstract void serverConf(String serverConf);
/** Record server launch configuration parameters */
public abstract void startServerConf(String serverConf);
/** Record some arguments to be passed on to javac */
public abstract void javacArg(String... arg);
/** Sets the destination directory for the compilation */
public abstract void destDir(Path dir);
/** Sets the directory for generated sources */
public abstract void generatedSourcesDir(Path genSrcDir);
/** Sets the directory for generated headers */
public abstract void headerDir(Path dir);
/** Sets the directory for state and log files generated by sjavac */
public abstract void stateDir(Path dir);
/** Sets the implicit policy */
public abstract void implicit(String policy);
/**
* Traverses an array of arguments and performs the appropriate callbacks.
*
* @param args the arguments to traverse.
*/
void traverse(String[] args) {
Iterable<String> allArgs;
try {
allArgs = CommandLine.parse(List.of(args)); // Detect @file and load it as a command line.
} catch (java.io.IOException e) {
throw new IllegalArgumentException("Problem reading @"+e.getMessage());
}
ArgumentIterator argIter = new ArgumentIterator(allArgs);
nextArg:
while (argIter.hasNext()) {
String arg = argIter.next();
if (arg.startsWith("-")) {
for (Option opt : Option.values()) {
if (opt.processCurrent(argIter, this))
continue nextArg;
}
javacArg(arg);
// Does this javac argument take an argument? If so, don't
// let it pass on to sjavac as a source root directory.
for (com.sun.tools.javac.main.Option javacOpt : com.sun.tools.javac.main.Option.values()) {
if (javacOpt.matches(arg)) {
boolean takesArgument = javacOpt.hasArg();
boolean separateToken = !arg.contains(":") && !arg.contains("=");
if (takesArgument && separateToken)
javacArg(argIter.next());
}
}
} else {
sourceRoots(Arrays.asList(Paths.get(arg)));
}
}
}
public static String unescapeCmdArg(String arg) {
return arg.replaceAll("%20", " ")
.replaceAll("%2C", ",");
}
}

View File

@ -1,521 +0,0 @@
/*
* Copyright (c) 2014, 2018, 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.options;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.StringJoiner;
import com.sun.tools.sjavac.Transformer;
import com.sun.tools.sjavac.Util;
/**
* Instances of this class represent values for sjavac command line options.
*
* <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 Options {
// Output directories
private Path destDir, genSrcDir, headerDir, stateDir;
// Input directories
private List<SourceLocation> sources = new ArrayList<>();
private List<SourceLocation> sourceSearchPaths = new ArrayList<>();
private List<SourceLocation> classSearchPaths = new ArrayList<>();
private List<SourceLocation> moduleSearchPaths = new ArrayList<>();
private String logLevel = "info";
private Set<String> permitted_artifacts = new HashSet<>();
private boolean permitUnidentifiedArtifacts = false;
private boolean permitSourcesInDefaultPackage = false;
private Path sourceReferenceList;
private int numCores = 4;
private String implicitPolicy = "none";
private List<String> javacArgs = new ArrayList<>();
private Map<String, Transformer> trRules = new HashMap<>();
private boolean startServer = false;
// Server configuration string
private String serverConf;
/** Get the policy for implicit classes */
public String getImplicitPolicy() {
return implicitPolicy;
}
/** Get the path for generated sources (or null if no such path is set) */
public Path getGenSrcDir() {
return genSrcDir;
}
/** Get the path for the destination directory */
public Path getDestDir() {
return destDir;
}
/** Get the path for the header directory (or null if no such path is set) */
public Path getHeaderDir() {
return headerDir;
}
/** Get the path for the state directory, defaults to destDir. */
public Path getStateDir() {
return stateDir;
}
/** Get all source locations for files to be compiled */
public List<SourceLocation> getSources() {
return sources;
}
/**
* Get all paths to search for classes in .java format. (Java-files in
* found here should not be compiled.
*/
public List<SourceLocation> getSourceSearchPaths() {
return sourceSearchPaths;
}
/** Get all paths to search for classes in. */
public List<SourceLocation> getClassSearchPath() {
return classSearchPaths;
}
/** Get all paths to search for modules in. */
public List<SourceLocation> getModuleSearchPaths() {
return moduleSearchPaths;
}
/** Get the log level. */
public String getLogLevel() {
return logLevel;
}
/** Returns true iff the artifact is permitted in the output dir. */
public boolean isUnidentifiedArtifactPermitted(String f) {
return permitted_artifacts.contains(f);
}
/** Returns true iff artifacts in the output directories should be kept,
* even if they would not be generated in a clean build. */
public boolean areUnidentifiedArtifactsPermitted() {
return permitUnidentifiedArtifacts;
}
/** Returns true iff sources in the default package should be permitted. */
public boolean isDefaultPackagePermitted() {
return permitSourcesInDefaultPackage;
}
/** Get the path to the list of reference sources (or null if none is set) */
public Path getSourceReferenceList() {
return sourceReferenceList;
}
/** Get the number of cores to be used by sjavac */
public int getNumCores() {
return numCores;
}
/** Returns all arguments relevant to javac but irrelevant to sjavac. */
public List<String> getJavacArgs() {
return javacArgs;
}
/**
* Get a map which maps suffixes to transformers (for example
* ".java" {@literal ->} CompileJavaPackages)
*/
public Map<String, Transformer> getTranslationRules() {
return trRules;
}
/** Return true iff a new server should be started */
public boolean startServerFlag() {
return startServer;
}
/** Return the server configuration string. */
public String getServerConf() {
return serverConf;
}
/**
* Parses the given argument array and returns a corresponding Options
* instance.
*/
public static Options parseArgs(String... args) {
Options options = new Options();
options.new ArgDecoderOptionHelper().traverse(args);
return options;
}
/** Returns true iff a .java file is among the javac arguments */
public boolean isJavaFilesAmongJavacArgs() {
for (String javacArg : javacArgs)
if (javacArg.endsWith(".java"))
return true;
return false;
}
/**
* Returns a string representation of the options that affect the result of
* the compilation. (Used for saving the state of the options used in a
* previous compile.)
*/
public String getStateArgsString() {
// Local utility class for collecting the arguments
class StateArgs {
private List<String> args = new ArrayList<>();
void addArg(Option opt) {
args.add(opt.arg);
}
void addArg(Option opt, Object val) {
addArg(opt);
args.add(val.toString());
}
void addSourceLocations(Option opt, List<SourceLocation> locs) {
for (SourceLocation sl : locs) {
for (String pkg : sl.includes) addArg(Option.I, pkg);
for (String pkg : sl.excludes) addArg(Option.X, pkg);
addArg(opt, sl.getPath());
}
}
String getResult() {
return String.join(" ", args);
}
public void addAll(Collection<String> toAdd) {
args.addAll(toAdd);
}
}
StateArgs args = new StateArgs();
// Directories
if (genSrcDir != null)
args.addArg(Option.S, genSrcDir.normalize());
if (headerDir != null)
args.addArg(Option.H, headerDir.normalize());
if (destDir != null)
args.addArg(Option.D, destDir.normalize());
if (stateDir != null)
args.addArg(Option.STATE_DIR, stateDir.normalize());
// Source roots
args.addSourceLocations(Option.SRC, sources);
args.addSourceLocations(Option.SOURCE_PATH, sourceSearchPaths);
args.addSourceLocations(Option.CLASS_PATH, classSearchPaths);
args.addSourceLocations(Option.MODULE_PATH, moduleSearchPaths);
// Boolean options
if (permitSourcesInDefaultPackage)
args.addArg(Option.PERMIT_SOURCES_WITHOUT_PACKAGE);
for (String f : permitted_artifacts) {
args.addArg(Option.PERMIT_ARTIFACT, f);
}
if (permitUnidentifiedArtifacts)
args.addArg(Option.PERMIT_UNIDENTIFIED_ARTIFACTS);
// Translation rules
for (Map.Entry<String, Transformer> tr : trRules.entrySet()) {
String val = tr.getKey() + "=" + tr.getValue().getClass().getName();
args.addArg(Option.TR, val);
}
// Javac args
args.addAll(javacArgs);
return args.getResult();
}
/** Extract the arguments to be passed on to javac. */
public String[] prepJavacArgs() {
List<String> args = new ArrayList<>();
// Output directories
args.add("-d");
args.add(destDir.toString());
if (getGenSrcDir() != null) {
args.add("-s");
args.add(genSrcDir.toString());
}
if (headerDir != null) {
args.add("-h");
args.add(headerDir.toString());
}
// Prep sourcepath
List<SourceLocation> sourcepath = new ArrayList<>();
sourcepath.addAll(sources);
sourcepath.addAll(sourceSearchPaths);
if (sourcepath.size() > 0) {
args.add("-sourcepath");
args.add(concatenateSourceLocations(sourcepath));
}
// Prep classpath
if (classSearchPaths.size() > 0) {
args.add("-classpath");
args.add(concatenateSourceLocations(classSearchPaths));
}
// Enable dependency generation
args.add("--debug=completionDeps=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);
return args.toArray(new String[args.size()]);
}
// Helper method to join a list of source locations separated by
// File.pathSeparator
private static String concatenateSourceLocations(List<SourceLocation> locs) {
StringJoiner joiner = new StringJoiner(java.io.File.pathSeparator);
for (SourceLocation loc : locs) {
joiner.add(loc.getPath().toString());
}
return joiner.toString();
}
// OptionHelper that records the traversed options in this Options instance.
private class ArgDecoderOptionHelper extends OptionHelper {
List<String> includes, excludes, includeFiles, excludeFiles;
{
resetFilters();
}
boolean headerProvided = false;
boolean genSrcProvided = false;
boolean stateProvided = false;
@Override
public void reportError(String msg) {
throw new IllegalArgumentException(msg);
}
@Override
public void sourceRoots(List<Path> paths) {
sources.addAll(createSourceLocations(paths));
}
@Override
public void exclude(String exclPattern) {
exclPattern = Util.normalizeDriveLetter(exclPattern);
excludes.add(exclPattern);
}
@Override
public void include(String inclPattern) {
inclPattern = Util.normalizeDriveLetter(inclPattern);
includes.add(inclPattern);
}
@Override
public void addTransformer(String suffix, Transformer tr) {
if (trRules.containsKey(suffix)) {
reportError("More than one transformer specified for " +
"suffix " + suffix + ".");
return;
}
trRules.put(suffix, tr);
}
@Override
public void sourcepath(List<Path> paths) {
sourceSearchPaths.addAll(createSourceLocations(paths));
}
@Override
public void modulepath(List<Path> paths) {
moduleSearchPaths.addAll(createSourceLocations(paths));
}
@Override
public void classpath(List<Path> paths) {
classSearchPaths.addAll(createSourceLocations(paths));
}
@Override
public void numCores(int n) {
numCores = n;
}
@Override
public void logLevel(String level) {
logLevel = level;
}
@Override
public void compareFoundSources(Path referenceList) {
sourceReferenceList = referenceList;
}
@Override
public void permitArtifact(String f) {
permitted_artifacts.add(f);
}
@Override
public void permitUnidentifiedArtifacts() {
permitUnidentifiedArtifacts = true;
}
@Override
public void permitDefaultPackage() {
permitSourcesInDefaultPackage = true;
}
@Override
public void serverConf(String conf) {
if (serverConf != null)
reportError("Can not specify more than one server configuration.");
else
serverConf = conf;
}
@Override
public void implicit(String policy) {
implicitPolicy = policy;
}
@Override
public void startServerConf(String conf) {
if (serverConf != null)
reportError("Can not specify more than one server configuration.");
else {
startServer = true;
serverConf = conf;
}
}
@Override
public void javacArg(String... arg) {
javacArgs.addAll(Arrays.asList(arg));
}
@Override
public void destDir(Path dir) {
if (destDir != null) {
reportError("Destination directory already specified.");
return;
}
destDir = dir.toAbsolutePath();
}
@Override
public void generatedSourcesDir(Path dir) {
if (genSrcProvided) {
reportError("Directory for generated sources already specified.");
return;
}
genSrcProvided = true;
genSrcDir = dir.toAbsolutePath();
}
@Override
public void headerDir(Path dir) {
if (headerProvided) {
reportError("Header directory already specified.");
return;
}
headerProvided = true;
headerDir = dir.toAbsolutePath();
}
@Override
public void stateDir(Path dir) {
if (stateProvided) {
reportError("State directory already specified.");
return;
}
stateProvided = true;
stateDir = dir.toAbsolutePath();
}
private List<SourceLocation> createSourceLocations(List<Path> paths) {
List<SourceLocation> result = new ArrayList<>();
for (Path path : paths) {
result.add(new SourceLocation(
path,
includes,
excludes));
}
resetFilters();
return result;
}
private void resetFilters() {
includes = new ArrayList<>();
excludes = new ArrayList<>();
includeFiles = new ArrayList<>();
excludeFiles = new ArrayList<>();
}
}
}

View File

@ -1,119 +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.options;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Module;
import com.sun.tools.sjavac.ProblemException;
import com.sun.tools.sjavac.Source;
/**
* Represents a directory to be used for input to sjavac. (For instance a
* sourcepath or classpath.)
*
* <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 SourceLocation {
// Path to the root directory
private Path path;
// Package include / exclude patterns and file includes / excludes.
List<String> includes, excludes;
public SourceLocation(Path path,
List<String> includes,
List<String> excludes) {
this.path = path;
this.includes = includes;
this.excludes = excludes;
}
/**
* Finds all files with the given suffix that pass the include / exclude
* filters in this source location.
*
* @param suffixes The set of suffixes to search for
* @param foundFiles The map in which to store the found files
* @param foundModules The map in which to store the found modules
* @param currentModule The current module
* @param permitSourcesInDefaultPackage true if sources in default package
* are to be permitted
* @param inLinksrc true if in link source
*/
public void findSourceFiles(Set<String> suffixes,
Map<String, Source> foundFiles,
Map<String, Module> foundModules,
Module currentModule,
boolean permitSourcesInDefaultPackage,
boolean inLinksrc)
throws IOException {
try {
Source.scanRoot(path.toFile(),
suffixes,
excludes,
includes,
foundFiles,
foundModules,
currentModule,
permitSourcesInDefaultPackage,
false,
inLinksrc);
} catch (ProblemException e) {
e.printStackTrace();
}
}
/** Get the root directory of this source location */
public Path getPath() {
return path;
}
/** Get the package include patterns */
public List<String> getIncludes() {
return includes;
}
/** Get the package exclude patterns */
public List<String> getExcludes() {
return excludes;
}
@Override
public String toString() {
return String.format("%s[\"%s\", includes: %s, excludes: %s]",
getClass().getSimpleName(), path, includes, excludes);
}
}

View File

@ -1,55 +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.
*/
package com.sun.tools.sjavac.pubapi;
import java.io.Serializable;
import javax.lang.model.type.TypeKind;
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 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();
}
}

View File

@ -1,50 +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.
*/
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());
}
}

View File

@ -1,437 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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;
@SuppressWarnings("serial") // Types of instance fields are not Serializable
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 final Map<String, PubVar> recordComponents = 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 static final String MODIFIERS = Stream.of(Modifier.values())
.map(Modifier::name)
.map(StringUtils::toLowerCase)
.collect(Collectors.joining("|", "(", ")"));
private static final Pattern MOD_PATTERN = Pattern.compile("(" + MODIFIERS + " )*");
private static final Pattern METHOD_PATTERN = Pattern.compile("(?<ret>.+?) (?<name>\\S+)\\((?<params>.*)\\)( throws (?<throws>.*))?");
private static final Pattern VAR_PATTERN = Pattern.compile("VAR (?<modifiers>("+MODIFIERS+" )*)(?<type>.+?) (?<id>\\S+)( = (?<val>.*))?");
private static final 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)
.toList();
}
private static List<PubApiTypeParam> parseTypeParams(List<String> strs) {
return strs.stream().map(PubApi::parseTypeParam).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());
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (c) 2015, 2021, 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.stream.Collectors;
@SuppressWarnings("serial") // Types of instance fields are not Serializable
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);
}
}

View File

@ -1,117 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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;
@SuppressWarnings("serial") // Types of instance fields are not Serializable
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);
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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;
@SuppressWarnings("serial") // Types of instance fields are not Serializable
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);
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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;
@SuppressWarnings("serial") // Types of instance fields are not Serializable
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);
}
}

View File

@ -1,60 +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.
*/
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);
}
}

View File

@ -1,140 +0,0 @@
/*
* Copyright (c) 2014, 2019, 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.SimpleTypeVisitor14;
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 SimpleTypeVisitor14<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();
}
}

View File

@ -1,61 +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.
*/
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);
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2014, 2021, 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.server;
import java.io.Serializable;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.pubapi.PubApi;
/**
*
* <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>
*/
@SuppressWarnings("serial") // Types of instance fields are not Serializable
public class CompilationSubResult implements Serializable {
static final long serialVersionUID = 46739181113L;
public Result result;
public Map<String, Set<URI>> packageArtifacts = 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 = "";
public CompilationSubResult(Result result) {
this.result = result;
}
public void setResult(Result result) {
this.result = result;
}
}

View File

@ -1,56 +0,0 @@
/*
* 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.
*/
/**
* A utility class used to report information about the system
* where the javac server is running.
*
* <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></p>
*/
package com.sun.tools.sjavac.server;
import java.io.Serializable;
/**
* <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 SysInfo implements Serializable {
static final long serialVersionUID = -3096346807579L;
public int numCores;
public long maxMemory;
public SysInfo(int nc, long mm) {
numCores = nc;
maxMemory = mm;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@ -48,12 +48,12 @@ public class UnusedCPDuringDump {
OutputAnalyzer output = TestCommon.dump(dir.getPath(),
TestCommon.list("sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo",
"com/sun/tools/sjavac/client/ClientMain"),
"com/sun/tools/javac/main/Main"),
"-Xlog:class+path=info,class+load=debug");
TestCommon.checkDump(output,
"[class,load] sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo",
"for instance a 'jdk/internal/loader/ClassLoaders$PlatformClassLoader'",
"[class,load] com.sun.tools.sjavac.client.ClientMain",
"[class,load] com.sun.tools.javac.main.Main",
"for instance a 'jdk/internal/loader/ClassLoaders$AppClassLoader'");
String jsaOpt = "-XX:SharedArchiveFile=" + TestCommon.getCurrentArchiveName();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, 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
@ -45,7 +45,7 @@ public class JimageClassProtDomain {
"java.net.HttpCookie", "java.net.URL"},
{"Loading non-shared app module class first",
"com.sun.tools.sjavac.Util", "com.sun.tools.sjavac.Main"},
"com.sun.tools.jdeps.JdepsTask", "com.sun.tools.jdeps.Main"},
{"Loading non-shared ext module class first",
"com.sun.jndi.dns.Resolver", "com.sun.jndi.dns.DnsName"}};

View File

@ -56,18 +56,6 @@ tools/javac/modules/SourceInSymlinkTest.java
tools/javap/output/RepeatingTypeAnnotations.java 8057687 generic-all emit correct byte code an attributes for type annotations
###########################################################################
#
# sjavac
tools/sjavac/IncCompileFullyQualifiedRef.java 8152055 generic-all Requires dependency code to deal with in-method dependencies.
tools/sjavac/IncCompileWithChanges.java 8152055 generic-all Requires dependency code to deal with in-method dependencies.
tools/sjavac/ApiExtraction.java 8158002 generic-all Requires investigation
tools/sjavac/IgnoreSymbolFile.java 8158002 generic-all Requires investigation
tools/sjavac/ClasspathDependencies.java 8158002 generic-all Requires investigation
###########################################################################
#
# jdeps

View File

@ -63,10 +63,6 @@ langtools_jdeps = \
tools/all \
tools/jdeps
langtools_sjavac = \
tools/all \
tools/sjavac
langtools_all = \
jdk \
lib \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2022, 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
@ -68,7 +68,6 @@ public class NoStringToLower {
"com.sun.tools.javah",
"com.sun.tools.javap",
"com.sun.tools.jdeps",
"com.sun.tools.sjavac",
"jdk.javadoc"
};
for (String pkg: pkgs) {

View File

@ -71,8 +71,7 @@ import javax.tools.ToolProvider;
/**
* Utility methods and classes for writing jtreg tests for
* javac, javah, javap, and sjavac. (For javadoc support,
* see JavadocTester.)
* javac, javah, and javap. (For javadoc support, see JavadocTester.)
*
* <p>There is support for common file operations similar to
* shell commands like cat, cp, diff, mv, rm, grep.
@ -990,4 +989,3 @@ public class ToolBox {
}
}
}

View File

@ -1,217 +0,0 @@
/*
* Copyright (c) 2015, 2016, 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.
*
* 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.main
* jdk.compiler/com.sun.tools.sjavac
* jdk.compiler/com.sun.tools.sjavac.options
* jdk.compiler/com.sun.tools.sjavac.pubapi
* @build Wrapper toolbox.ToolBox toolbox.JavacTask
* @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;
import toolbox.JavacTask;
import toolbox.ToolBox;
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 JavacTask(new ToolBox()).sources(testSrc).run();
// Extract PubApi
Options options = Options.parseArgs("-d", "bin", "--state-dir=bin", "-cp", ".");
PubApiExtractor pubApiExtr = new PubApiExtractor(options);
PubApi actualApi = pubApiExtr.getPubApi("TestClass");
pubApiExtr.close();
// 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));
}
}

View File

@ -1,137 +0,0 @@
/*
* Copyright (c) 2015, 2016, 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.
*
* 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.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox toolbox.Assert
* @run main Wrapper ClasspathDependencies
*/
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;
import static toolbox.Assert.check;
public class ClasspathDependencies extends SjavacBase {
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("-d", classesDep, "--state-dir=" + 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("-d", classes, "--state-dir=" + 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("-d", classesDep, "--state-dir=" + classesDep, srcDep);
check(rc == 0, "Compilation failed unexpectedly");
////////////////////////////////////////////////////////////////////////
headline("Make sure that this does not trigger recompilation of C.java");
rc = compile("-d", classes, "--state-dir=" + 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("-d", classesDep, "--state-dir=" + classesDep, srcDep);
check(rc == 0, "Compilation failed unexpectedly");
////////////////////////////////////////////////////////////////////////
headline("Make sure that recompilation of C.java is triggered");
rc = compile("-d", classes, "--state-dir=" + 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;
}
});
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify that circular sources split on multiple cores can be compiled
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper CompileCircularSources
*/
import java.io.IOException;
import java.util.*;
import java.nio.file.*;
public class CompileCircularSources extends SJavacTester {
public static void main(String... args) throws Exception {
CompileCircularSources ccs = new CompileCircularSources();
ccs.test();
}
void test() throws Exception {
Files.createDirectories(BIN);
Files.createDirectories(GENSRC);
Map<String,Long> previous_bin_state = collectState(BIN);
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A { beta.B b; }");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; public class B { gamma.C c; }");
tb.writeFile(GENSRC.resolve("gamma/C.java"),
"package gamma; public class C { alfa.omega.A a; }");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"-h", HEADERS.toString(),
"--state-dir=" + BIN,
"-j", "3",
"--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");
}
}

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Tests compiling class A that depends on class B without compiling class B
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper CompileExcludingDependency
*/
import java.util.*;
import java.nio.file.*;
public class CompileExcludingDependency extends SJavacTester {
public static void main(String... args) throws Exception {
CompileExcludingDependency ced = new CompileExcludingDependency();
ced.test();
}
// Verify that excluding classes from compilation but not from linking works
void test() throws Exception {
Files.createDirectories(BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"package alfa.omega; public class A { beta.B b; }");
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; public class B { }");
compile("-x", "beta/*",
"-src", GENSRC.toString(),
"-x", "alfa/omega/*",
"-sourcepath", GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN);
Map<String,Long> new_bin_state = collectState(BIN);
verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
BIN + "/alfa/omega/A.class",
BIN + "/javac_state");
}
}

View File

@ -1,72 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Test \@atfile with command line content
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper CompileWithAtFile
*/
import java.util.*;
import java.nio.file.*;
public class CompileWithAtFile extends SJavacTester {
public static void main(String... args) throws Exception {
CompileWithAtFile cwf = new CompileWithAtFile();
cwf.test();
}
void test() throws Exception {
tb.writeFile(GENSRC.resolve("list.txt"),
"-i alfa/omega/A.java\n" +
"-i beta/B.java\n" +
GENSRC + "\n" +
"-d " + BIN + "\n" +
"--state-dir=" + 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"),
"package beta; public class B { }");
tb.writeFile(GENSRC.resolve("beta/C.java"),
"broken");
Files.createDirectory(BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
compile("@" + GENSRC + "/list.txt");
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");
}
}

View File

@ -1,91 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify that we can make sources invisible to linking (sourcepath)
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper CompileWithInvisibleSources
*/
import java.util.*;
import java.nio.file.*;
public class CompileWithInvisibleSources extends SJavacTester {
public static void main(String... args) throws Exception {
CompileWithInvisibleSources cis = new CompileWithInvisibleSources();
cis.test();
}
// Compile gensrc and link against gensrc2 and gensrc3
// gensrc2 contains broken code in beta.B, thus exclude that package
// gensrc3 contains a proper beta.B
void test() throws Exception {
Files.createDirectories(BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"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");
tb.writeFile(GENSRC2.resolve("gamma/C.java"),
"package gamma; public class C { }");
tb.writeFile(GENSRC3.resolve("beta/B.java"),
"package beta; public class B { }");
compile(GENSRC.toString(),
"-x", "beta/*",
"-sourcepath", GENSRC2.toString(),
"-sourcepath", GENSRC3.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1");
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");
System.out.println("----- Compile with exluded beta went well!");
tb.cleanDirectory(BIN);
compileExpectFailure(GENSRC.toString(),
"-sourcepath", GENSRC2.toString(),
"-sourcepath", GENSRC3.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1");
System.out.println("----- Compile without exluded beta failed, as expected! Good!");
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary verify that we can override sources to be compiled
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper CompileWithOverrideSources
*/
import java.util.*;
import java.nio.file.*;
public class CompileWithOverrideSources extends SJavacTester {
public static void main(String... args) throws Exception {
CompileWithOverrideSources cos = new CompileWithOverrideSources();
cos.test();
}
// 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.createDirectories(BIN);
Map<String,Long> previous_bin_state = collectState(BIN);
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"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");
tb.writeFile(GENSRC.resolve("gamma/C.java"),
"package gamma; public class C { }");
tb.writeFile(GENSRC2.resolve("beta/B.java"),
"package beta; public class B { }");
compile("-x", "beta/*",
GENSRC.toString(),
GENSRC2.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1");
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");
System.out.println("----- Compile with exluded beta went well!");
tb.cleanDirectory(BIN);
compileExpectFailure(GENSRC.toString(),
GENSRC2.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1");
System.out.println("----- Compile without exluded beta failed, as expected! Good!");
}
}

View File

@ -1,67 +0,0 @@
/*
* Copyright (c) 2015, 2016, 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.
*
* 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 8144226
* @summary Ensures that excluded files are inaccessible (even for implicit
* compilation)
* @modules jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* jdk.compiler/com.sun.tools.sjavac.server
* @library /tools/lib
* @build Wrapper toolbox.ToolBox toolbox.Assert
* @run main Wrapper HiddenFiles
*/
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.sun.tools.javac.main.Main.Result;
import toolbox.Assert;
public class HiddenFiles extends SjavacBase {
public static void main(String[] ignore) throws Exception {
Path BIN = Paths.get("bin");
Path STATE_DIR = Paths.get("state-dir");
Path SRC = Paths.get("src");
Files.createDirectories(BIN);
Files.createDirectories(STATE_DIR);
toolbox.writeJavaFiles(SRC, "package pkg; class A { B b; }");
toolbox.writeJavaFiles(SRC, "package pkg; class B { }");
// This compilation should fail (return RC_FATAL) since A.java refers to B.java and B.java
// is excluded.
int rc = compile("-x", "pkg/B.java", SRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + STATE_DIR);
Assert.check(rc == Result.ERROR.exitCode, "Compilation succeeded unexpectedly.");
}
}

View File

@ -1,121 +0,0 @@
/*
* Copyright (c) 2014, 2019, 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.
*
* 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 8044131
* @summary Tests the hooks used for detecting idleness of the sjavac server.
* @modules jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac.server
* @build Wrapper
* @run main Wrapper IdleShutdown
*/
import java.util.concurrent.atomic.AtomicLong;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.sjavac.server.IdleResetSjavac;
import com.sun.tools.sjavac.server.Sjavac;
import com.sun.tools.sjavac.server.Terminable;
public class IdleShutdown {
final static long TEST_START = System.currentTimeMillis();
final static long TIMEOUT_MS = 3000;
public static void main(String[] args) throws InterruptedException {
final AtomicLong timeoutTimestamp = new AtomicLong(-1);
log("Starting IdleCallbackJavacService with timeout: " + TIMEOUT_MS);
Sjavac service = new IdleResetSjavac(
new NoopJavacService(),
new Terminable() {
public void shutdown(String msg) {
// Record the idle timeout time
log("Timeout detected");
timeoutTimestamp.set(System.currentTimeMillis());
}
},
TIMEOUT_MS);
// Make sure it didn't timeout immediately
if (timeoutTimestamp.get() != -1)
throw new AssertionError("Premature timeout detected.");
// Use Sjavac object and wait less than TIMEOUT_MS in between calls
Thread.sleep(TIMEOUT_MS - 1000);
log("Compiling");
service.compile(new String[0]);
Thread.sleep(TIMEOUT_MS - 1000);
log("Compiling");
service.compile(new String[0]);
if (timeoutTimestamp.get() != -1)
throw new AssertionError("Premature timeout detected.");
long expectedTimeout = System.currentTimeMillis() + TIMEOUT_MS;
// Wait for actual timeout
log("Awaiting idle timeout");
Thread.sleep(TIMEOUT_MS + 1000);
// Check result
if (timeoutTimestamp.get() == -1)
throw new AssertionError("Timeout never occurred");
long error = Math.abs(expectedTimeout - timeoutTimestamp.get());
log("Timeout error: " + error + " ms");
String timeoutFactorText = System.getProperty("test.timeout.factor", "1.0");
double timeoutFactor = Double.parseDouble(timeoutFactorText);
double allowedError = TIMEOUT_MS * 0.1 * timeoutFactor;
if (error > allowedError) {
throw new AssertionError("Timeout error too large, error is " + error +
" milliseconds, we allowed " + allowedError + " milliseconds");
}
log("Shutting down");
service.shutdown();
}
private static void log(String msg) {
long logTime = System.currentTimeMillis() - TEST_START;
System.out.printf("After %5d ms: %s%n", logTime, msg);
}
private static class NoopJavacService implements Sjavac {
@Override
public void shutdown() {
}
@Override
public Result compile(String[] args) {
// Attempt to trigger idle timeout during a call by sleeping
try {
Thread.sleep(TIMEOUT_MS + 1000);
} catch (InterruptedException e) {
}
return Result.OK;
}
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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 8047183
* @summary JDK build fails with sjavac enabled
* @modules jdk.compiler/com.sun.tools.sjavac
* @build Wrapper
* @run main Wrapper IgnoreSymbolFile
*/
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.Arrays;
public class IgnoreSymbolFile {
public static void main(String... args) throws Exception {
IgnoreSymbolFile test = new IgnoreSymbolFile();
test.run();
}
void run() throws Exception {
String body =
"package p;\n"
+ "import sun.reflect.annotation.*;\n"
+ "class X {\n"
+ " ExceptionProxy proxy;"
+ "}";
writeFile("src/p/X.java", body);
new File("classes").mkdirs();
int rc1 = compile("-d", "classes",
"--state-dir=classes",
"-Werror",
"src");
if (rc1 == 0)
error("compilation succeeded unexpectedly");
int rc2 = compile("-d", "classes",
"--state-dir=classes",
"-Werror",
"-XDignore.symbol.file=true",
"src");
if (rc2 != 0)
error("compilation failed unexpectedly: rc=" + rc2);
if (errors > 0)
throw new Exception(errors + " errors occurred");
}
int compile(String... args) throws ReflectiveOperationException {
// Use reflection to avoid a compile-time dependency on sjavac Main
System.err.println("compile: " + Arrays.toString(args));
Class<?> c = Class.forName("com.sun.tools.sjavac.Main");
Method m = c.getDeclaredMethod("go", String[].class);
int rc = (Integer) m.invoke(null, (Object) args);
System.err.println("rc=" + rc);
return rc;
}
void writeFile(String path, String body) throws IOException {
File f = new File(path);
if (f.getParentFile() != null)
f.getParentFile().mkdirs();
try (FileWriter w = new FileWriter(f)) {
w.write(body);
}
}
void error(String msg) {
System.err.println("Error: " + msg);
errors++;
}
int errors;
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Analysis of public API does not take super classes into account
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper IncCompInheritance
*/
import java.nio.file.Path;
import java.nio.file.Paths;
public class IncCompInheritance extends SjavacBase {
public static void main(String... args) throws Exception {
Path root = Paths.get(IncCompInheritance.class.getSimpleName() + "Test");
Path src = root.resolve("src");
Path classes = root.resolve("classes");
// Prep source files: A <- B <- C
String a = "package pkga; public class A { public void m() {} }";
String b = "package pkgb; public class B extends pkga.A {}";
String c = "package pkgc; public class C extends pkgb.B {{ new pkgb.B().m(); }}";
toolbox.writeFile(src.resolve("pkga/A.java"), a);
toolbox.writeFile(src.resolve("pkgb/B.java"), b);
toolbox.writeFile(src.resolve("pkgc/C.java"), c);
// Initial compile (should succeed)
int rc1 = compile("-d", classes, "--state-dir=" + classes, src);
if (rc1 != 0)
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);
// Incremental compile (C should now be recompiled even though it
// depends on A only through inheritance via B).
// Since A.m is removed, this should fail.
int rc2 = compile("-d", classes, "--state-dir=" + classes, src);
if (rc2 == 0)
throw new AssertionError("Compilation succeeded unexpectedly");
}
}

View File

@ -1,119 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify native files are removed when native method is removed
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper IncCompileChangeNative
*/
import java.util.*;
import java.nio.file.*;
public class IncCompileChangeNative extends SJavacTester {
public static void main(String... args) throws Exception {
IncCompileChangeNative cn = new IncCompileChangeNative();
cn.test();
}
// Remember the previous bin and headers state here.
Map<String,Long> previous_bin_state;
Map<String,Long> previous_headers_state;
void test() throws Exception {
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileDropAllNatives();
incrementalCompileAddNative();
}
// Update B.java with one less native method i.e. it has no longer any methods
// Verify that beta_B.h is removed
void incrementalCompileDropAllNatives() throws Exception {
previous_bin_state = collectState(BIN);
previous_headers_state = collectState(HEADERS);
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; } }");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1",
"--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");
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");
previous_headers_state = new_headers_state;
}
// Update the B.java with a final static annotated with @Native
// Verify that beta_B.h is added again
void incrementalCompileAddNative() throws Exception {
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; }");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1",
"--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");
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");
previous_headers_state = new_headers_state;
}
}

View File

@ -1,85 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify deletion of a source file results in dropping of all .class files including inner classes
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper IncCompileDropClasses
*/
import java.util.*;
import java.nio.file.*;
public class IncCompileDropClasses extends SJavacTester {
public static void main(String... args) throws Exception {
IncCompileDropClasses dc = new IncCompileDropClasses();
dc.test();
}
// Remember the previous bin and headers state here.
Map<String,Long> previous_bin_state;
Map<String,Long> previous_headers_state;
void test() throws Exception {
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileDroppingClasses();
}
// Testing that deleting AA.java deletes all generated inner class including AA.class
void incrementalCompileDroppingClasses() throws Exception {
previous_bin_state = collectState(BIN);
previous_headers_state = collectState(HEADERS);
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.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1",
"--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");
previous_bin_state = new_bin_state;
Map<String,Long> new_headers_state = collectState(HEADERS);
verifyEqual(previous_headers_state, new_headers_state);
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify that "alfa.omega.A a" does create a proper dependency
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @ignore Requires dependency code to deal with in-method dependencies.
* @build Wrapper toolbox.ToolBox
* @run main Wrapper IncCompileFullyQualifiedRef
*/
import java.util.Map;
import toolbox.ToolBox;
public class IncCompileFullyQualifiedRef extends SJavacTester {
public static void main(String... args) throws Exception {
IncCompileFullyQualifiedRef fr = new IncCompileFullyQualifiedRef();
fr.test();
}
void test() throws Exception {
clean(TEST_ROOT);
tb.writeFile(GENSRC.resolve("alfa/omega/A.java"),
"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; }"+
"}");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-j", "1",
"--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() { }"+
"}");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-j", "1",
"--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");
clean(GENSRC,BIN);
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify no change in sources implies no change in binaries
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper IncCompileNoChanges
*/
import java.util.*;
import java.nio.file.*;
public class IncCompileNoChanges extends SJavacTester {
public static void main(String... args) throws Exception {
IncCompileNoChanges nc = new IncCompileNoChanges();
nc.test();
}
// Remember the previous bin and headers state here.
Map<String,Long> previous_bin_state;
Map<String,Long> previous_headers_state;
void test() throws Exception {
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileNoChanges();
}
// Testing that no change in sources implies no change in binaries
void incrementalCompileNoChanges() throws Exception {
previous_bin_state = collectState(BIN);
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.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1",
"--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);
verifyEqual(previous_headers_state, new_headers_state);
}
}

View File

@ -1,90 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify native files are rewritten
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox
* @run main Wrapper IncCompileUpdateNative
*/
import java.util.*;
import java.nio.file.*;
public class IncCompileUpdateNative extends SJavacTester {
public static void main(String... args) throws Exception {
IncCompileUpdateNative un = new IncCompileUpdateNative();
un.test();
}
// Remember the previous bin and headers state here.
Map<String,Long> previous_bin_state;
Map<String,Long> previous_headers_state;
void test() throws Exception {
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileChangeNative();
}
// Update B.java with a new value for the final static annotated with @Native
// Verify that beta_B.h is rewritten again
void incrementalCompileChangeNative() throws Exception {
previous_bin_state = collectState(BIN);
previous_headers_state = collectState(HEADERS);
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; }");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1",
"--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");
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");
previous_headers_state = new_headers_state;
}
}

View File

@ -1,103 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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
* @summary Verify incremental changes in gensrc are handled as expected
* @bug 8054689
* @author Fredrik O
* @author sogoel (rewrite)
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @ignore Requires dependency code to deal with in-method dependencies.
* @build Wrapper toolbox.ToolBox
* @run main Wrapper IncCompileWithChanges
*/
import java.util.*;
import java.nio.file.*;
import toolbox.ToolBox;
public class IncCompileWithChanges extends SJavacTester {
public static void main(String... args) throws Exception {
IncCompileWithChanges wc = new IncCompileWithChanges();
wc.test();
}
// Remember the previous bin and headers state here.
Map<String,Long> previous_bin_state;
Map<String,Long> previous_headers_state;
void test() throws Exception {
clean(TEST_ROOT);
Files.createDirectories(GENSRC);
Files.createDirectories(BIN);
Files.createDirectories(HEADERS);
initialCompile();
incrementalCompileWithChange();
}
/* Update A.java with a new timestamp and new final static definition.
* This should trigger a recompile, not only of alfa, but also beta.
* Generated native header should not be updated since native api of B was not modified.
*/
void incrementalCompileWithChange() throws Exception {
previous_bin_state = collectState(BIN);
previous_headers_state = collectState(HEADERS);
System.out.println("\nIn incrementalCompileWithChange() ");
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() { } }");
compile(GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,
"-h", HEADERS.toString(),
"-j", "1",
"--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");
previous_bin_state = new_bin_state;
Map<String,Long> new_headers_state = collectState(HEADERS);
verifyEqual(new_headers_state, previous_headers_state);
}
}

View File

@ -1,169 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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 8037085
* @summary Ensures that sjavac can handle various exclusion patterns.
*
* @modules jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* jdk.compiler/com.sun.tools.sjavac.server
* @library /tools/lib
* @build Wrapper toolbox.ToolBox toolbox.Assert
* @run main Wrapper IncludeExcludePatterns
*/
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.sun.tools.javac.main.Main.Result;
import toolbox.Assert;
public class IncludeExcludePatterns extends SjavacBase {
final Path SRC = Paths.get("src");
final Path BIN = Paths.get("bin");
final Path STATE_DIR = Paths.get("state-dir");
// An arbitrarily but sufficiently complicated source tree.
final Path A = Paths.get("pkga/A.java");
final Path X1 = Paths.get("pkga/subpkg/Xx.java");
final Path Y = Paths.get("pkga/subpkg/subsubpkg/Y.java");
final Path B = Paths.get("pkgb/B.java");
final Path C = Paths.get("pkgc/C.java");
final Path X2 = Paths.get("pkgc/Xx.java");
final Path[] ALL_PATHS = {A, X1, Y, B, C, X2};
public static void main(String[] ignore) throws Exception {
new IncludeExcludePatterns().runTest();
}
public void runTest() throws IOException, ReflectiveOperationException {
Files.createDirectories(BIN);
Files.createDirectories(STATE_DIR);
for (Path p : ALL_PATHS) {
writeDummyClass(p);
}
// Single file
testPattern("pkga/A.java", A);
// Leading wild cards
testPattern("*/A.java", A);
testPattern("**/Xx.java", X1, X2);
testPattern("**x.java", X1, X2);
// Wild card in middle of path
testPattern("pkga/*/Xx.java", X1);
testPattern("pkga/**/Y.java", Y);
// Trailing wild cards
testPattern("pkga/*", A);
testPattern("pkga/**", A, X1, Y);
// Multiple wildcards
testPattern("pkga/*/*/Y.java", Y);
testPattern("**/*/**", X1, Y);
}
// Given "src/pkg/subpkg/A.java" this method returns "A"
String classNameOf(Path javaFile) {
return javaFile.getFileName()
.toString()
.replace(".java", "");
}
// Puts an empty (dummy) class definition in the given path.
void writeDummyClass(Path javaFile) throws IOException {
String pkg = javaFile.getParent().toString().replace(File.separatorChar, '.');
String cls = javaFile.getFileName().toString().replace(".java", "");
toolbox.writeFile(SRC.resolve(javaFile), "package " + pkg + "; class " + cls + " {}");
}
void testPattern(String filterArgs, Path... sourcesExpectedToBeVisible)
throws ReflectiveOperationException, IOException {
testFilter("-i " + filterArgs, Arrays.asList(sourcesExpectedToBeVisible));
Set<Path> complement = new HashSet<>(Arrays.asList(ALL_PATHS));
complement.removeAll(Arrays.asList(sourcesExpectedToBeVisible));
testFilter("-x " + filterArgs, complement);
}
void testFilter(String filterArgs, Collection<Path> sourcesExpectedToBeVisible)
throws IOException, ReflectiveOperationException {
System.out.println("Testing filter: " + filterArgs);
toolbox.cleanDirectory(BIN);
toolbox.cleanDirectory(STATE_DIR);
String args = filterArgs + " " + SRC
+ " -d " + BIN
+ " --state-dir=" + STATE_DIR;
int rc = compile((Object[]) args.split(" "));
// Compilation should always pass in these tests
Assert.check(rc == Result.OK.exitCode, "Compilation failed unexpectedly.");
// The resulting .class files should correspond to the visible source files
Set<Path> result = allFilesInDir(BIN);
Set<Path> expected = correspondingClassFiles(sourcesExpectedToBeVisible);
if (!result.equals(expected)) {
System.out.println("Result:");
printPaths(result);
System.out.println("Expected:");
printPaths(expected);
Assert.error("Test case failed: " + filterArgs);
}
}
void printPaths(Collection<Path> paths) {
paths.stream()
.sorted()
.forEachOrdered(p -> System.out.println(" " + p));
}
// Given "pkg/A.java, pkg/B.java" this method returns "bin/pkg/A.class, bin/pkg/B.class"
Set<Path> correspondingClassFiles(Collection<Path> javaFiles) {
return javaFiles.stream()
.map(javaFile -> javaFile.resolveSibling(classNameOf(javaFile) + ".class"))
.map(BIN::resolve)
.collect(Collectors.toSet());
}
Set<Path> allFilesInDir(Path p) throws IOException {
try (Stream<Path> files = Files.walk(p).filter(Files::isRegularFile)) {
return files.collect(Collectors.toSet());
}
}
}

View File

@ -1,179 +0,0 @@
/*
* Copyright (c) 2014, 2018, 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.
*
* 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 8035063
* @summary Tests the preparation of javac-arguments.
*
* @modules jdk.compiler/com.sun.tools.sjavac.options
* @build Wrapper
* @run main Wrapper JavacOptionPrep
*/
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Iterator;
import com.sun.tools.sjavac.options.Options;
public class JavacOptionPrep {
enum TestPath {
CP1, CP2, SRC1, SRC2, SOURCEPATH1, SOURCEPATH2;
public String toString() {
return name().toLowerCase();
}
}
private final static String SEP = File.pathSeparator;
public static void main(String[] unused) throws IOException {
for (TestPath p : TestPath.values())
Files.createDirectory(Paths.get(p.toString()));
// Test some various cases:
// - Paths combined with File.pathSeparator (CP1 / CP2)
// - Paths given as duplicate options (SOURCEPATH1 / SOURCEPATH2)
// - Sources provided by -src (SRC1)
// - Sources provided without preceding option (SRC2)
// - An unrecognized option which is to be passed on to javac
String sjavacArgs = "-cp " + TestPath.CP1 + SEP + TestPath.CP2 +
" -d dest" +
" -h header" +
" -sourcepath " + TestPath.SOURCEPATH1 +
" -src " + TestPath.SRC1 +
" -s gensrc" +
" -sourcepath " + TestPath.SOURCEPATH2 +
" " + TestPath.SRC2 +
" -unrecognized";
Options options = Options.parseArgs(sjavacArgs.split(" "));
// Extract javac-options
String[] javacArgs = options.prepJavacArgs();
// Check the result
boolean destDirFound = false;
boolean userPathsFirst = false;
boolean headerDirFound = false;
boolean gensrcDirFound = false;
boolean classPathFound = false;
boolean sourcePathFound = false;
boolean unrecognizedFound = false;
boolean implicitNoneFound = false;
Iterator<String> javacArgIter = Arrays.asList(javacArgs).iterator();
while (javacArgIter.hasNext()) {
String option = javacArgIter.next();
// Ignore this option for now. When the file=... requirement goes
// away, this will be easier to handle.
if (option.startsWith("--debug=completionDeps"))
continue;
switch (option) {
case "-classpath":
case "-cp":
classPathFound = true;
assertEquals(TestPath.CP1 + SEP + TestPath.CP2,
javacArgIter.next());
break;
case "-d":
destDirFound = true;
assertEquals(Paths.get("dest").toAbsolutePath().toString(),
javacArgIter.next());
break;
case "-h":
headerDirFound = true;
assertEquals(Paths.get("header").toAbsolutePath().toString(),
javacArgIter.next());
break;
case "-s":
gensrcDirFound = true;
assertEquals(Paths.get("gensrc").toAbsolutePath().toString(),
javacArgIter.next());
break;
case "-sourcepath":
sourcePathFound = true;
assertEquals(TestPath.SRC1 + SEP +
TestPath.SRC2 + SEP +
TestPath.SOURCEPATH1 + SEP +
TestPath.SOURCEPATH2,
javacArgIter.next());
break;
case "-unrecognized":
unrecognizedFound = true;
break;
case "-implicit:none":
implicitNoneFound = true;
break;
// Note that *which* files to actually compile is not dealt
// with by prepJavacArgs.
default:
throw new AssertionError("Unexpected option found: " + option);
}
}
if (!destDirFound)
throw new AssertionError("Dest directory not found.");
if (!headerDirFound)
throw new AssertionError("Header directory not found.");
if (!gensrcDirFound)
throw new AssertionError("Generated source directory not found.");
if (!classPathFound)
throw new AssertionError("Class path not found.");
if (!sourcePathFound)
throw new AssertionError("Source path not found.");
if (!unrecognizedFound)
throw new AssertionError("\"-unrecognized\" not found.");
if (!implicitNoneFound)
throw new AssertionError("\"-implicit:none\" not found.");
}
static void assertEquals(Object expected, Object actual) {
if (!expected.equals(actual))
throw new AssertionError("Expected " + expected + " but got " + actual);
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2015, 2016, 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.
*
* 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
* @summary Test --no-state option
* @bug 8135131
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.sjavac
* @build Wrapper toolbox.ToolBox toolbox.Assert
* @run main Wrapper NoState
*/
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;
import toolbox.Assert;
public class NoState extends SJavacTester {
public static void main(String... args) throws Exception {
new NoState().run();
}
public void run() throws Exception {
tb.writeFile(GENSRC.resolve("pkg/A.java"), "package pkg; class A {}");
Files.createDirectory(BIN);
compile("-d", BIN.toString(),
GENSRC + "/pkg/A.java");
// Make sure file was compiled
Assert.check(Files.exists(BIN.resolve("pkg/A.class")));
// Make sure we have no other files (such as a javac_state file) in the bin directory
Assert.check(countPathsInDir(BIN) == 1);
Assert.check(countPathsInDir(BIN.resolve("pkg")) == 1);
}
private long countPathsInDir(Path dir) throws IOException {
try (Stream<Path> files = Files.list(dir)) {
return files.count();
}
}
}

View File

@ -1,174 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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 8035063 8054465
* @summary Tests decoding of String[] into Options.
*
* @modules jdk.compiler/com.sun.tools.sjavac
* jdk.compiler/com.sun.tools.sjavac.client
* jdk.compiler/com.sun.tools.sjavac.comp
* jdk.compiler/com.sun.tools.sjavac.options
* @build Wrapper
* @run main Wrapper OptionDecoding
*/
import static util.OptionTestUtil.assertEquals;
import static util.OptionTestUtil.checkFilesFound;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sun.tools.sjavac.CopyFile;
import com.sun.tools.sjavac.Module;
import com.sun.tools.sjavac.Source;
import com.sun.tools.sjavac.client.ClientMain;
import com.sun.tools.sjavac.comp.SjavacImpl;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.options.SourceLocation;
public class OptionDecoding {
public static void main(String[] args) throws IOException {
testPaths();
testDupPaths();
testSimpleOptions();
testServerConf();
testSearchPaths();
testTranslationRules();
}
// Test decoding of output paths
static void testPaths() throws IOException {
final String H = "headers";
final String G = "gensrc";
final String D = "dest";
final String stateDir = "stateDir";
final String CMP = "srcRefList.txt";
Options options = Options.parseArgs("-h", H, "-s", G, "-d", D, "--state-dir=" + stateDir,
"--compare-found-sources", CMP);
assertEquals(Paths.get(H).toAbsolutePath(), options.getHeaderDir());
assertEquals(Paths.get(G).toAbsolutePath(), options.getGenSrcDir());
assertEquals(Paths.get(D).toAbsolutePath(), options.getDestDir());
assertEquals(Paths.get(stateDir).toAbsolutePath(), options.getStateDir());
assertEquals(Paths.get(CMP), options.getSourceReferenceList());
}
// Providing duplicate header / dest / gensrc paths should produce an error.
static void testDupPaths() throws IOException {
try {
Options.parseArgs("-h", "dir1", "-h", "dir2");
throw new RuntimeException("Duplicate header directories should fail.");
} catch (IllegalArgumentException iae) {
// Expected
}
try {
Options.parseArgs("-s", "dir1", "-s", "dir2");
throw new RuntimeException("Duplicate paths for generated sources should fail.");
} catch (IllegalArgumentException iae) {
// Expected
}
try {
Options.parseArgs("-d", "dir1", "-d", "dir2");
throw new RuntimeException("Duplicate destination directories should fail.");
} catch (IllegalArgumentException iae) {
// Expected
}
}
// Test basic options
static void testSimpleOptions() {
Options options = Options.parseArgs("-j", "17", "--log=debug");
assertEquals(17, options.getNumCores());
assertEquals("debug", options.getLogLevel());
assertEquals(false, options.isDefaultPackagePermitted());
assertEquals(false, options.areUnidentifiedArtifactsPermitted());
assertEquals(false, options.isUnidentifiedArtifactPermitted(Paths.get("bar.txt").toFile().getAbsolutePath()));
options = Options.parseArgs("--permit-unidentified-artifacts",
"--permit-artifact=bar.txt",
"--permit-sources-without-package");
assertEquals("info", options.getLogLevel());
assertEquals(true, options.isDefaultPackagePermitted());
assertEquals(true, options.areUnidentifiedArtifactsPermitted());
assertEquals(true, options.isUnidentifiedArtifactPermitted(Paths.get("bar.txt").toFile().getAbsolutePath()));
}
// Test server configuration options
static void testServerConf() {
Options options = Options.parseArgs("--server:someServerConfiguration");
assertEquals("someServerConfiguration", options.getServerConf());
assertEquals(false, options.startServerFlag());
options = Options.parseArgs("--startserver:someServerConfiguration");
assertEquals("someServerConfiguration", options.getServerConf());
assertEquals(true, options.startServerFlag());
}
// Test input paths
static void testSearchPaths() {
List<String> i, x, iF, xF;
i = x = iF = xF = new ArrayList<>();
SourceLocation dir1 = new SourceLocation(Paths.get("dir1"), i, x);
SourceLocation dir2 = new SourceLocation(Paths.get("dir2"), i, x);
String dir1_PS_dir2 = "dir1" + File.pathSeparator + "dir2";
Options options = Options.parseArgs("--source-path", dir1_PS_dir2);
assertEquals(options.getSourceSearchPaths(), Arrays.asList(dir1, dir2));
options = Options.parseArgs("--module-path", dir1_PS_dir2);
assertEquals(options.getModuleSearchPaths(), Arrays.asList(dir1, dir2));
options = Options.parseArgs("--class-path", dir1_PS_dir2);
assertEquals(options.getClassSearchPath(), Arrays.asList(dir1, dir2));
}
// Test -tr option
static void testTranslationRules() {
Class<?> cls = com.sun.tools.sjavac.CompileJavaPackages.class;
Options options = Options.parseArgs(
"-tr", ".exa=" + cls.getName(),
"-tr", ".exb=" + cls.getName(),
"-copy", ".html");
assertEquals(cls, options.getTranslationRules().get(".exa").getClass());
assertEquals(cls, options.getTranslationRules().get(".exb").getClass());
assertEquals(CopyFile.class, options.getTranslationRules().get(".html").getClass());
}
}

Some files were not shown because too many files have changed in this diff Show More