001/*
002 * Copyright (C) 2022 - 2023, the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *    http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.github.ascopes.jct.compilers;
017
018import io.github.ascopes.jct.containers.ModuleContainerGroup;
019import io.github.ascopes.jct.containers.OutputContainerGroup;
020import io.github.ascopes.jct.containers.PackageContainerGroup;
021import io.github.ascopes.jct.diagnostics.TraceDiagnostic;
022import io.github.ascopes.jct.filemanagers.JctFileManager;
023import java.util.List;
024import java.util.Set;
025import javax.tools.JavaFileObject;
026import javax.tools.StandardLocation;
027import org.apiguardian.api.API;
028import org.apiguardian.api.API.Status;
029
030/**
031 * The result of a compilation.
032 *
033 * <p>This provides access to a number of useful pieces of information
034 * including the file manager used for the compilation, compiler logs,
035 * and diagnostics.
036 *
037 * @author Ashley Scopes
038 * @since 0.0.1
039 */
040@API(since = "0.0.1", status = Status.STABLE)
041public interface JctCompilation {
042
043  /**
044   * Get the command line arguments that were passed to the compiler.
045   *
046   * @return the command line arguments.
047   */
048  @API(since = "0.5.0", status = Status.STABLE)
049  List<String> getArguments();
050
051  /**
052   * Determine if warnings were treated as errors.
053   *
054   * @return {@code true} if warnings were treated as errors, or {@code false} otherwise.
055   */
056  boolean isFailOnWarnings();
057
058  /**
059   * Determine if the compilation was successful or not.
060   *
061   * @return {@code true} if successful, or {@code false} if not successful.
062   */
063  boolean isSuccessful();
064
065  /**
066   * Determine if the compilation was a failure or not.
067   *
068   * @return {@code true} if not successful, or {@code false} if successful.
069   */
070  default boolean isFailure() {
071    return !isSuccessful();
072  }
073
074  /**
075   * Get the lines of output produced by the compiler, if any were captured.
076   *
077   * <p>This is separate to diagnostics.
078   *
079   * @return the lines of output.
080   */
081  List<String> getOutputLines();
082
083  /**
084   * Get the compilation units used in the compilation.
085   *
086   * @return the compilation units.
087   */
088  Set<JavaFileObject> getCompilationUnits();
089
090  /**
091   * Get the diagnostics that were reported by the compilation, in the order that they
092   * were reported.
093   *
094   * @return the diagnostics
095   */
096  List<TraceDiagnostic<JavaFileObject>> getDiagnostics();
097
098  /**
099   * Get the file manager that was used to store and manage files.
100   *
101   * <p>This can be used to obtain a classloader for any compiled sources,
102   * which can then be used to reflectively test what the compiler produced.
103   *
104   * @return the file manager.
105   */
106  JctFileManager getFileManager();
107
108  /**
109   * Get the output container group for class outputs.
110   *
111   * <p>This usually consists of any {@code *.class} files produced by the compiler,
112   * and is equivalent to {@code target/classes} in a Maven project.
113   *
114   * @return the output container group, or {@code null} if it does not exist.
115   */
116  default OutputContainerGroup getClassOutputs() {
117    return getFileManager().getOutputContainerGroup(StandardLocation.CLASS_OUTPUT);
118  }
119
120  /**
121   * Get the output container group for source outputs.
122   *
123   * <p>This consists of any generated source code created by annotation processors,
124   * and is equivalent to {@code target/generated-sources} in a Maven project.
125   *
126   * @return the output container group, or {@code null} if it does not exist.
127   */
128  default OutputContainerGroup getSourceOutputs() {
129    return getFileManager().getOutputContainerGroup(StandardLocation.SOURCE_OUTPUT);
130  }
131
132  /**
133   * Get the package container group for the class path.
134   *
135   * <p>This represents the class path used for compilation.
136   *
137   * @return the package container group, or {@code null} if it does not exist.
138   */
139  default PackageContainerGroup getClassPath() {
140    return getFileManager().getPackageContainerGroup(StandardLocation.CLASS_PATH);
141  }
142
143  /**
144   * Get the package container group for the source path.
145   *
146   * <p>This is equivalent to {@code src/main/java} and {@code src/main/resources}
147   * in a Maven project.
148   *
149   * @return the package container group, or {@code null} if it does not exist.
150   */
151  default PackageContainerGroup getSourcePath() {
152    return getFileManager().getPackageContainerGroup(StandardLocation.SOURCE_PATH);
153  }
154
155  /**
156   * Get the package container group for the annotation processor path.
157   *
158   * @return the package container group, or {@code null} if it does not exist.
159   */
160  default PackageContainerGroup getAnnotationProcessorPath() {
161    return getFileManager().getPackageContainerGroup(StandardLocation.ANNOTATION_PROCESSOR_PATH);
162  }
163
164  /**
165   * Get the module container group for the annotation processor module path.
166   *
167   * @return the module container group, or {@code null} if it does not exist.
168   */
169  default ModuleContainerGroup getAnnotationProcessorModulePath() {
170    return getFileManager()
171        .getModuleContainerGroup(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH);
172  }
173
174  /**
175   * Get the package container group for the platform class path (a.k.a. the bootstrap class path).
176   *
177   * <p>You generally do not need to use this. The platform class path mechanism has been mostly
178   * replaced by the use of the system modules path as of Java 11. It is simply provided for
179   * backwards compatibility.
180   *
181   * @return the package container group, or {@code null} if it does not exist.
182   */
183  default PackageContainerGroup getPlatformClassPath() {
184    return getFileManager().getPackageContainerGroup(StandardLocation.PLATFORM_CLASS_PATH);
185  }
186
187  /**
188   * Get the output container group for the native header file outputs.
189   *
190   * <p>If you invoke {@code javac} with the {@code -H} flag, then this represents the
191   * directory that C/C++ header file stubs for JNI are written to.
192   *
193   * @return the output container group, or {@code null} if it does not exist.
194   */
195  default OutputContainerGroup getNativeHeaderOutputs() {
196    return getFileManager().getOutputContainerGroup(StandardLocation.NATIVE_HEADER_OUTPUT);
197  }
198
199  /**
200   * Get the module container group for the module source path.
201   *
202   * <p>Many build tools do not provide a direct equivalent of this mechanism as of now, but
203   * this is a source path introduced in Java 9 that allows specifying multiple named JPMS
204   * modules to compile under a single compilation invocation.
205   *
206   * <p>For example, you may use this in a project to compile an API module, a default
207   * implementation module, and a module containing unit tests all together.
208   *
209   * @return the module container group, or {@code null} if it does not exist.
210   */
211  default ModuleContainerGroup getModuleSourcePath() {
212    return getFileManager().getModuleContainerGroup(StandardLocation.MODULE_SOURCE_PATH);
213  }
214
215  /**
216   * Get the module container group for the upgrade module path.
217   *
218   * <p>You generally will not need to use this, as this is a mechanism used to upgrade
219   * modules in-place incrementally with fixes without redistributing the entire application.
220   *
221   * @return the module container group, or {@code null} if it does not exist.
222   */
223  default ModuleContainerGroup getUpgradeModulePath() {
224    return getFileManager().getModuleContainerGroup(StandardLocation.UPGRADE_MODULE_PATH);
225  }
226
227  /**
228   * Get the module container group for all system modules that are part of the JDK distribution.
229   *
230   * <p>This will usually just point to the Java standard library.
231   *
232   * @return the module container group, or {@code null} if it does not exist.
233   */
234  default ModuleContainerGroup getSystemModules() {
235    return getFileManager().getModuleContainerGroup(StandardLocation.SYSTEM_MODULES);
236  }
237
238  /**
239   * Get the module container group for the module path.
240   *
241   * <p>This is equivalent to the class path, but holds any JPMS modules.
242   *
243   * @return the module container group, or {@code null} if it does not exist.
244   */
245  default ModuleContainerGroup getModulePath() {
246    return getFileManager().getModuleContainerGroup(StandardLocation.MODULE_PATH);
247  }
248
249  /**
250   * Get the module container group for the patch module path.
251   *
252   * <p>You generally will not need to use this. It consists of patchable module sources that
253   * can be used to inject additional classes into a module. This can be used for cases like
254   * unit tests where you wish to embed the unit test classes into the existing application
255   * module to exploit features such as package private access.
256   *
257   * @return the module container group, or {@code null} if it does not exist.
258   */
259  default ModuleContainerGroup getPatchModulePath() {
260    return getFileManager().getModuleContainerGroup(StandardLocation.PATCH_MODULE_PATH);
261  }
262}