001/*
002 * Copyright (C) 2022 - 2024, 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 static io.github.ascopes.jct.utils.IterableUtils.requireAtLeastOne;
019
020import io.github.ascopes.jct.ex.JctCompilerException;
021import io.github.ascopes.jct.filemanagers.AnnotationProcessorDiscovery;
022import io.github.ascopes.jct.filemanagers.LoggingMode;
023import io.github.ascopes.jct.workspaces.Workspace;
024import java.io.UncheckedIOException;
025import java.nio.charset.Charset;
026import java.nio.charset.StandardCharsets;
027import java.util.Collection;
028import java.util.List;
029import java.util.Locale;
030import java.util.Set;
031import javax.annotation.processing.Processor;
032import javax.lang.model.SourceVersion;
033import org.apiguardian.api.API;
034import org.apiguardian.api.API.Status;
035import org.jspecify.annotations.Nullable;
036
037/**
038 * Base definition of a compiler that can be configured to perform a compilation run against
039 * sources.
040 *
041 * <p>JctCompiler objects are often a nexus that will manage configuring an underlying JSR-199
042 * compiler internally in a platform-agnostic way.
043 *
044 * @author Ashley Scopes
045 * @since 0.0.1
046 */
047@API(since = "0.0.1", status = Status.STABLE)
048public interface JctCompiler {
049
050  /**
051   * Default setting for deprecation warnings ({@code true}).
052   */
053  boolean DEFAULT_SHOW_DEPRECATION_WARNINGS = true;
054
055  /**
056   * Default setting for locale ({@link Locale#ROOT}).
057   */
058  Locale DEFAULT_LOCALE = Locale.ROOT;
059
060  /**
061   * Default setting for preview features ({@code false}).
062   */
063  boolean DEFAULT_PREVIEW_FEATURES = false;
064
065  /**
066   * Default setting for verbose logging ({@code false}).
067   */
068  boolean DEFAULT_VERBOSE = false;
069
070  /**
071   * Default setting for displaying warnings ({@code true}).
072   */
073  boolean DEFAULT_SHOW_WARNINGS = true;
074
075  /**
076   * Default setting for displaying warnings as errors ({@code false}).
077   */
078  boolean DEFAULT_FAIL_ON_WARNINGS = false;
079
080  /**
081   * Default setting for fixing modules being placed on the classpath by mistake ({@code true}).
082   */
083  boolean DEFAULT_FIX_JVM_MODULE_PATH_MISMATCH = true;
084
085  /**
086   * Default setting for inclusion of the current class path ({@code true}).
087   */
088  boolean DEFAULT_INHERIT_CLASS_PATH = true;
089
090  /**
091   * Default setting for inclusion of the current module path ({@code true}).
092   */
093  boolean DEFAULT_INHERIT_MODULE_PATH = true;
094
095  /**
096   * Default setting for inclusion of the system module path ({@code true}).
097   */
098  boolean DEFAULT_INHERIT_SYSTEM_MODULE_PATH = true;
099
100  /**
101   * Default setting for logging file manager operations ({@link LoggingMode#DISABLED}).
102   */
103  LoggingMode DEFAULT_FILE_MANAGER_LOGGING_MODE = LoggingMode.DISABLED;
104
105  /**
106   * Default setting for logging diagnostics ({@link LoggingMode#ENABLED}).
107   */
108  LoggingMode DEFAULT_DIAGNOSTIC_LOGGING_MODE = LoggingMode.ENABLED;
109
110  /**
111   * Default setting for the compilation mode to use
112   * ({@link CompilationMode#COMPILATION_AND_ANNOTATION_PROCESSING}).
113   */
114  CompilationMode DEFAULT_COMPILATION_MODE = CompilationMode.COMPILATION_AND_ANNOTATION_PROCESSING;
115
116  /**
117   * Default setting for how to apply annotation processor discovery when no processors are
118   * explicitly defined ({@link AnnotationProcessorDiscovery#INCLUDE_DEPENDENCIES}).
119   */
120  AnnotationProcessorDiscovery DEFAULT_ANNOTATION_PROCESSOR_DISCOVERY =
121      AnnotationProcessorDiscovery.INCLUDE_DEPENDENCIES;
122
123  /**
124   * Default charset to use for compiler logs ({@link StandardCharsets#UTF_8}).
125   */
126  Charset DEFAULT_LOG_CHARSET = StandardCharsets.UTF_8;
127
128  /**
129   * Default debugging info to include in the compilation (all possible info).
130   */
131  Set<DebuggingInfo> DEFAULT_DEBUGGING_INFO = DebuggingInfo.all();
132
133  /**
134   * Default preference for including reflective parameter information in compiled classes
135   * ({@code true}).
136   */
137  boolean DEFAULT_PARAMETER_INFO_ENABLED = true;
138
139  /**
140   * Invoke the compilation and return the compilation result.
141   *
142   * <p>The actual classes to compile will be dynamically discovered. If you wish to
143   * specify the specific classes to compile, see {@link #compile(Workspace, String...)} or
144   * {@link #compile(Workspace, Collection)}.
145   *
146   * @param workspace the workspace to compile.
147   * @return the compilation result.
148   * @throws JctCompilerException  if the compiler threw an unhandled exception. This should not
149   *                               occur for compilation failures generally.
150   * @throws IllegalStateException if no compilation units were found.
151   * @throws UncheckedIOException  if an IO error occurs.
152   * @see #compile(Workspace, String...)
153   * @see #compile(Workspace, Collection)
154   */
155  JctCompilation compile(Workspace workspace);
156
157  /**
158   * Invoke the compilation and return the compilation result.
159   *
160   * <p>Only classes matching the given class names will be compiled.
161   *
162   * <p>If you wish to let JCT determine which classes to compile dynamically, see
163   * {@link #compile(Workspace)} instead.
164   *
165   * <p>Note that nested instance/static nested classes cannot be specified individually
166   * here. To compile them, you must also compile their outer class that they are defined within.
167   *
168   * @param workspace            the workspace to compile.
169   * @param classNames           the class names to compile.
170   * @return the compilation result.
171   * @throws JctCompilerException  if the compiler threw an unhandled exception. This should not
172   *                               occur for compilation failures generally.
173   * @throws NullPointerException  if any class names are null, or if the array is null.
174   * @throws IllegalStateException if no compilation units were found.
175   * @throws UncheckedIOException  if an IO error occurs.
176   * @see #compile(Workspace)
177   * @see #compile(Workspace, Collection)
178   */
179  default JctCompilation compile(Workspace workspace, String... classNames) {
180    requireAtLeastOne(classNames, "classNames");
181    return compile(workspace, List.of(classNames));
182  }
183
184  /**
185   * Invoke the compilation and return the compilation result.
186   *
187   * <p>Only classes matching the given class names will be compiled.
188   *
189   * <p>If you wish to let JCT determine which classes to compile dynamically, see
190   * {@link #compile(Workspace)} instead.
191   *
192   * <p>Note that nested instance/static nested classes cannot be specified individually
193   * here. To compile them, you must also compile their outer class that they are defined within.
194   *
195   * @param workspace  the workspace to compile.
196   * @param classNames the class names to compile.
197   * @return the compilation result.
198   * @throws JctCompilerException     if the compiler threw an unhandled exception. This should not
199   *                                  occur for compilation failures usually.
200   * @throws NullPointerException     if the {@code classNames} collection contains any null values,
201   *                                  or if the collection itself is null.
202   * @throws IllegalArgumentException if the collection is empty.
203   * @throws IllegalStateException    if no compilation units were found.
204   * @throws UncheckedIOException     if an IO error occurs.
205   * @see #compile(Workspace)
206   * @see #compile(Workspace, String...)
207   */
208  JctCompilation compile(Workspace workspace, Collection<String> classNames);
209
210  /**
211   * Apply a given configurer to this compiler.
212   *
213   * <p>Configurers can be lambdas, method references, or objects.
214   *
215   * <pre><code>
216   *   // Using an object configurer
217   *   var werrorConfigurer = new JctCompilerConfigurer&lt;RuntimeException&gt;() {
218   *     {@literal @Override}
219   *     public void configure(JctCompiler compiler) {
220   *       compiler.failOnWarnings(true);
221   *     }
222   *   };
223   *   compiler.configure(werrorConfigurer);
224   *
225   *   // Using a lambda configurer
226   *   compiler.configure(c -&gt; c.verbose(true));
227   * </code></pre>
228   *
229   * <p>Configurers take a type parameter that corresponds to an exception type. This
230   * is the exception type that can be thrown by the configurer, or {@link RuntimeException} if no
231   * checked exception is thrown. This mechanism allows configurers to propagate checked exceptions
232   * to their caller where needed.
233   *
234   * <pre><code>
235   *   class FileFlagConfigurer implements JctCompilerConfigurer&lt;IOException&gt; {
236   *     private final Path path;
237   *
238   *     public FileFlagConfigurer(String... path) {
239   *       this(Path.of(path));
240   *     }
241   *
242   *     public FileFlagConfigurer(Path path) {
243   *       this.path = path;
244   *     }
245   *
246   *     {@literal @Override}
247   *     public void configure(JctCompiler compiler) throws IOException {
248   *       var flags = Files.lines(path)
249   *           .map(String::trim)
250   *           .filter(not(String::isBlank))
251   *           .toList();
252   *       compiler.addCompilerOptions(flags);
253   *     }
254   *   }
255   *
256   *   {@literal @Test}
257   *   void testSomething() throws IOException {
258   *     ...
259   *     compiler.configure(new FileFlagConfigurer("src", "test", "resources", "flags.txt"));
260   *     ...
261   *   }
262   * </code></pre>
263   *
264   * @param <E>        any exception that may be thrown.
265   * @param configurer the configurer to invoke.
266   * @return this compiler object for further call chaining.
267   * @throws E any exception that may be thrown by the configurer. If no checked exception is
268   *           thrown, then this should be treated as {@link RuntimeException}.
269   */
270  <E extends Exception> JctCompiler configure(JctCompilerConfigurer<E> configurer) throws E;
271
272  /**
273   * Get the friendly printable name of this compiler object.
274   *
275   * @return the name of the compiler.
276   */
277  String getName();
278
279  /**
280   * Set the friendly name of this compiler.
281   *
282   * <p>This will be used by the
283   * {@link io.github.ascopes.jct.junit.JavacCompilerTest JUnit5 support} to name unit test cases.
284   *
285   * @param name the name to set.
286   * @return this compiler object for further call chaining.
287   */
288  JctCompiler name(String name);
289
290  /**
291   * Get an <strong>immutable snapshot view</strong> of the current annotation processor options
292   * that are set.
293   *
294   * @return the current annotation processor options that are set.
295   */
296  List<String> getAnnotationProcessorOptions();
297
298  /**
299   * Add options to pass to any annotation processors.
300   *
301   * @param annotationProcessorOptions the options to pass.
302   * @return this compiler object for further call chaining.
303   */
304  JctCompiler addAnnotationProcessorOptions(Iterable<String> annotationProcessorOptions);
305
306  /**
307   * Add options to pass to any annotation processors.
308   *
309   * @param annotationProcessorOptions options to pass.
310   * @return this compiler object for further call chaining.
311   */
312  default JctCompiler addAnnotationProcessorOptions(String... annotationProcessorOptions) {
313    return addAnnotationProcessorOptions(List.of(annotationProcessorOptions));
314  }
315
316  /**
317   * Get an <strong>immutable snapshot view</strong> of the current annotation processors that are
318   * explicitly set to be run, in the order that they were provided to the compiler.
319   *
320   * @return the current annotation processors that are set.
321   */
322  List<Processor> getAnnotationProcessors();
323
324  /**
325   * Add annotation processors to invoke.
326   *
327   * <p><strong>Warning:</strong> This bypasses the discovery process of annotation processors
328   * provided in the annotation processor path and annotation processor module paths, as well as any
329   * other locations such as class paths and module paths.
330   *
331   * @param annotationProcessors the processors to invoke.
332   * @return this compiler object for further call chaining.
333   */
334  JctCompiler addAnnotationProcessors(Iterable<? extends Processor> annotationProcessors);
335
336  /**
337   * Add annotation processors to invoke.
338   *
339   * <p><strong>Warning:</strong> This bypasses the discovery process of annotation processors
340   * provided in the annotation processor path and annotation processor module paths, as well as any
341   * other locations such as class paths and module paths.
342   *
343   * @param annotationProcessors processors to invoke.
344   * @return this compiler object for further call chaining.
345   */
346  default JctCompiler addAnnotationProcessors(Processor... annotationProcessors) {
347    return addAnnotationProcessors(List.of(annotationProcessors));
348  }
349
350  /**
351   * Get an <strong>immutable snapshot view</strong> of the current compiler options that are set.
352   *
353   * @return the current compiler  options that are set.
354   */
355  List<String> getCompilerOptions();
356
357  /**
358   * Add command line options to pass to {@code javac}.
359   *
360   * @param compilerOptions the options to add.
361   * @return this compiler object for further call chaining.
362   */
363  JctCompiler addCompilerOptions(Iterable<String> compilerOptions);
364
365  /**
366   * Add command line options to pass to {@code javac}.
367   *
368   * @param compilerOptions options to add.
369   * @return this compiler object for further call chaining.
370   */
371  default JctCompiler addCompilerOptions(String... compilerOptions) {
372    return addCompilerOptions(List.of(compilerOptions));
373  }
374
375  /**
376   * Determine whether verbose logging is enabled or not.
377   *
378   * <p>Unless otherwise changed or specified, implementations should default to
379   * {@link #DEFAULT_VERBOSE}.
380   *
381   * <p>Note that enabling this is compiler-specific behaviour. There is no guarantee that the
382   * output target or the format or verbosity of output will be consistent between different
383   * compiler implementations.
384   *
385   * @return whether verbose logging is enabled or not.
386   */
387  boolean isVerbose();
388
389  /**
390   * Set whether to use verbose output or not.
391   *
392   * <p>Unless otherwise changed or specified, implementations should default to
393   * {@link #DEFAULT_VERBOSE}.
394   *
395   * <p>Note that enabling this is compiler-specific behaviour. There is no guarantee that the
396   * output target or the format or verbosity of output will be consistent between different
397   * compiler implementations.
398   *
399   * @param enabled {@code true} for verbose output, {@code false} for normal output.
400   * @return this compiler for further call chaining.
401   */
402  JctCompiler verbose(boolean enabled);
403
404  /**
405   * Determine whether preview features are enabled or not.
406   *
407   * <p>Unless otherwise changed or specified, implementations should default to
408   * {@link #DEFAULT_PREVIEW_FEATURES}.
409   *
410   * @return whether preview features are enabled or not.
411   */
412  boolean isPreviewFeatures();
413
414  /**
415   * Set whether to enable compiler preview features or not.
416   *
417   * <p>Unless otherwise changed or specified, implementations should default to
418   * {@link #DEFAULT_PREVIEW_FEATURES}.
419   *
420   * <p>Generally, this feature should be avoided if testing across multiple versions
421   * of Java, as preview features are often not finalised and may change without warning.
422   *
423   * @param enabled {@code true} to enable preview features, or {@code false} to disable them.
424   * @return this compiler object for further call chaining.
425   */
426  JctCompiler previewFeatures(boolean enabled);
427
428  /**
429   * Determine whether warnings are enabled or not.
430   *
431   * <p>Unless otherwise changed or specified, implementations should default to
432   * {@link #DEFAULT_SHOW_WARNINGS}.
433   *
434   * @return whether warnings are enabled or not.
435   */
436  boolean isShowWarnings();
437
438  /**
439   * Set whether to enable displaying warnings or not.
440   *
441   * <p>Unless otherwise changed or specified, implementations should default to
442   * {@link #DEFAULT_SHOW_WARNINGS}.
443   *
444   * @param enabled {@code true} to enable warnings. {@code false} to disable them.
445   * @return this compiler object for further call chaining.
446   */
447  JctCompiler showWarnings(boolean enabled);
448
449  /**
450   * Determine whether deprecation warnings are enabled or not.
451   *
452   * <p>Unless otherwise changed or specified, implementations should default to
453   * {@link #DEFAULT_SHOW_DEPRECATION_WARNINGS}.
454   *
455   * @return whether deprecation warnings are enabled or not.
456   */
457  boolean isShowDeprecationWarnings();
458
459  /**
460   * Set whether to enable deprecation warnings or not.
461   *
462   * <p>This is ignored if {@link #showWarnings(boolean)} is disabled.
463   *
464   * <p>Unless otherwise changed or specified, implementations should default to
465   * {@link #DEFAULT_SHOW_DEPRECATION_WARNINGS}.
466   *
467   * @param enabled {@code true} to enable deprecation warnings. {@code false} to disable them.
468   * @return this compiler object for further call chaining.
469   */
470  JctCompiler showDeprecationWarnings(boolean enabled);
471
472  /**
473   * Determine whether warnings are being treated as errors or not.
474   *
475   * <p>Unless otherwise changed or specified, implementations should default to
476   * {@link #DEFAULT_FAIL_ON_WARNINGS}.
477   *
478   * @return whether warnings are being treated as errors or not.
479   */
480  boolean isFailOnWarnings();
481
482  /**
483   * Set whether to enable treating warnings as errors or not.
484   *
485   * <p>Some compilers may call this flag something different, such as "{@code -Werror}".
486   *
487   * <p>This is ignored if {@link #showWarnings(boolean)} is disabled.
488   *
489   * <p>Unless otherwise changed or specified, implementations should default to
490   * {@link #DEFAULT_FAIL_ON_WARNINGS}.
491   *
492   * @param enabled {@code true} to enable treating warnings as errors. {@code false} to disable
493   *                them.
494   * @return this compiler object for further call chaining.
495   */
496  JctCompiler failOnWarnings(boolean enabled);
497
498  /**
499   * Get the compilation mode that is in use.
500   *
501   * <p>Unless otherwise changed or specified, implementations should default to
502   * {@link #DEFAULT_COMPILATION_MODE}.
503   *
504   * @return the compilation mode.
505   */
506  CompilationMode getCompilationMode();
507
508  /**
509   * Set the compilation mode to use for this compiler.
510   *
511   * <p>This allows you to override whether sources are compiled or annotation-processed
512   * without running the full compilation process. Tuning this may provide faster test cases in some
513   * situations.
514   *
515   * <p>Unless otherwise changed or specified, implementations should default to
516   * {@link #DEFAULT_COMPILATION_MODE}.
517   *
518   * @param compilationMode the compilation mode to use.
519   * @return this compiler object for further call chaining.
520   */
521  JctCompiler compilationMode(CompilationMode compilationMode);
522
523  /**
524   * Get the default release to use if no release or target version is specified.
525   *
526   * <p>This can <strong>not</strong> be configured generally, as it is defined by
527   * the internal compiler implementation.
528   *
529   * <p>Generally, this value will be an integer within a string. The value is
530   * represented as a string to allow supporting compilers which may use non-integer version
531   * numbers.
532   *
533   * @return the default release version to use.
534   */
535  String getDefaultRelease();
536
537  /**
538   * Get the effective release to use for the actual compilation.
539   *
540   * <p>Generally, this value will be an integer within a string. The value is
541   * represented as a string to allow supporting compilers which may use non-integer version
542   * numbers.
543   *
544   * <p>This may be determined from the {@link #getSource() source},
545   * {@link #getTarget() target}, {@link #getRelease() release}, and
546   * {@link #getDefaultRelease() default release.}
547   *
548   * @return the effective release.
549   */
550  String getEffectiveRelease();
551
552  /**
553   * Get the current release version that is set, or {@code null} if left to the compiler to decide.
554   * default.
555   *
556   * <p>Generally, this value will be an integer within a string. The value is
557   * represented as a string to allow supporting compilers which may use non-integer version
558   * numbers.
559   *
560   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
561   * default.
562   *
563   * @return the release version string, if set.
564   */
565  @Nullable
566  String getRelease();
567
568  /**
569   * Set the release version.
570   *
571   * <p>This will clear any source and target version that is set.
572   *
573   * <p>Generally, this value will be an integer within a string. The value is
574   * represented as a string to allow supporting compilers which may use non-integer version
575   * numbers.
576   *
577   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
578   * default.
579   *
580   * @param release the version to set.
581   * @return this compiler object for further call chaining.
582   */
583  JctCompiler release(@Nullable String release);
584
585  /**
586   * Set the release version.
587   *
588   * <p>This will clear any source and target version that is set.
589   *
590   * <p>Generally, this value will be an integer within a string. The value is
591   * represented as a string to allow supporting compilers which may use non-integer version
592   * numbers.
593   *
594   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
595   * default.
596   *
597   * @param release the version to set.
598   * @return this compiler object for further call chaining.
599   * @throws IllegalArgumentException      if the version is less than 0.
600   * @throws UnsupportedOperationException if the compiler does not support integer versions.
601   */
602  default JctCompiler release(int release) {
603    if (release < 0) {
604      throw new IllegalArgumentException("Cannot provide a release version less than 0");
605    }
606
607    return release(Integer.toString(release));
608  }
609
610  /**
611   * Set the release version.
612   *
613   * <p>This will clear any source and target version that is set.
614   *
615   * <p>Generally, this value will be an integer within a string. The value is
616   * represented as a string to allow supporting compilers which may use non-integer version
617   * numbers.
618   *
619   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
620   * default.
621   *
622   * @param release the version to set.
623   * @return this compiler object for further call chaining.
624   * @throws UnsupportedOperationException if the compiler does not support integer versions.
625   * @throws NullPointerException if the release is null.
626   */
627  default JctCompiler release(SourceVersion release) {
628    return release(Integer.toString(release.ordinal()));
629  }
630
631  /**
632   * Request that the compiler uses a language version that corresponds to the runtime language
633   * version in use on the current JVM.
634   *
635   * <p>For example, running this on JRE 19 would set the release to "19".
636   *
637   * <p>This calls {@link #release(int)} internally.
638   *
639   * @return this compiler object for further call chaining.
640   * @throws UnsupportedOperationException if the current JVM version does not correspond to a
641   *                                       supported Java release version in the compiler, or if the
642   *                                       compiler does not support integral version numbers.
643   * @since 1.1.0
644   */
645  @API(since = "1.1.0", status = Status.STABLE)
646  default JctCompiler useRuntimeRelease() {
647    return release(Runtime.version().feature());
648  }
649
650  /**
651   * Get the current source version that is set, or {@code null} if left to the compiler to decide.
652   * default.
653   *
654   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
655   * default.
656   *
657   * @return the source version string, if set.
658   */
659  @Nullable
660  String getSource();
661
662  /**
663   * Set the source version.
664   *
665   * <p>This will clear any release version that is set.
666   *
667   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
668   * default.
669   *
670   * <p>Source and target versions have mostly been replaced with the release version
671   * mechanism which controls both flags and can ensure other behaviours are consistent. This
672   * feature is still provided in case you have a specific use case that is not covered by this
673   * functionality.
674   *
675   * @param source the version to set.
676   * @return this compiler object for further call chaining.
677   */
678  JctCompiler source(@Nullable String source);
679
680  /**
681   * Set the source version.
682   *
683   * <p>This will clear any release version that is set.
684   *
685   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
686   * default.
687   *
688   * <p>Source and target versions have mostly been replaced with the release version
689   * mechanism which controls both flags and can ensure other behaviours are consistent. This
690   * feature is still provided in case you have a specific use case that is not covered by this
691   * functionality.
692   *
693   * @param source the version to set.
694   * @return this compiler object for further call chaining.
695   * @throws IllegalArgumentException      if the version is less than 0.
696   * @throws UnsupportedOperationException if the compiler does not support integer versions.
697   */
698  default JctCompiler source(int source) {
699    if (source < 0) {
700      throw new IllegalArgumentException("Cannot provide a source version less than 0");
701    }
702
703    return source(Integer.toString(source));
704  }
705
706  /**
707   * Set the source version.
708   *
709   * <p>This will clear any release version that is set.
710   *
711   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
712   * default.
713   *
714   * <p>Source and target versions have mostly been replaced with the release version
715   * mechanism which controls both flags and can ensure other behaviours are consistent. This
716   * feature is still provided in case you have a specific use case that is not covered by this
717   * functionality.
718   *
719   * @param source the version to set.
720   * @return this compiler object for further call chaining.
721   * @throws UnsupportedOperationException if the compiler does not support integer versions.
722   * @throws NullPointerException          if the source is null.
723   */
724  default JctCompiler source(SourceVersion source) {
725    return source(Integer.toString(source.ordinal()));
726  }
727
728  /**
729   * Get the current target version that is set, or {@code null} if left to the compiler default.
730   *
731   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
732   * default.
733   *
734   * @return the target version string, if set.
735   */
736  @Nullable
737  String getTarget();
738
739  /**
740   * Set the target version.
741   *
742   * <p>This will clear any release version that is set.
743   *
744   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
745   * default.
746   *
747   * <p>Source and target versions have mostly been replaced with the release version
748   * mechanism which controls both flags and can ensure other behaviours are consistent. This
749   * feature is still provided in case you have a specific use case that is not covered by this
750   * functionality.
751   *
752   * @param target the version to set.
753   * @return this compiler object for further call chaining.
754   */
755  JctCompiler target(@Nullable String target);
756
757  /**
758   * Set the target version.
759   *
760   * <p>This will clear any release version that is set.
761   *
762   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
763   * default.
764   *
765   * <p>Source and target versions have mostly been replaced with the release version
766   * mechanism which controls both flags and can ensure other behaviours are consistent. This
767   * feature is still provided in case you have a specific use case that is not covered by this
768   * functionality.
769   *
770   * @param target the version to set.
771   * @return this compiler object for further call chaining.
772   * @throws IllegalArgumentException      if the version is less than 0.
773   * @throws UnsupportedOperationException if the compiler does not support integer versions.
774   */
775  default JctCompiler target(int target) {
776    if (target < 0) {
777      throw new IllegalArgumentException("Cannot provide a target version less than 0");
778    }
779
780    return target(Integer.toString(target));
781  }
782
783  /**
784   * Set the target version.
785   *
786   * <p>This will clear any release version that is set.
787   *
788   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
789   * default.
790   *
791   * <p>Source and target versions have mostly been replaced with the release version
792   * mechanism which controls both flags and can ensure other behaviours are consistent. This
793   * feature is still provided in case you have a specific use case that is not covered by this
794   * functionality.
795   *
796   * @param target the version to set.
797   * @return this compiler object for further call chaining.
798   * @throws UnsupportedOperationException if the compiler does not support integer versions.
799   * @throws NullPointerException          if the target is null.
800   */
801  default JctCompiler target(SourceVersion target) {
802    return target(Integer.toString(target.ordinal()));
803  }
804
805  /**
806   * Get whether we will attempt to fix modules appearing on the classpath, or non-modules appearing
807   * on the module path.
808   *
809   * <p>This enables correct classpath and module path detection when the test pack is a module but
810   * the code being compiled in the test is not, and vice versa. We need this because many build
811   * systems decide whether to populate the {@code --module-path} or the {@code --classpath}
812   * with JPMS-enabled dependencies based on whether the project under compilation is a JPMS module
813   * itself.
814   *
815   * <p>This only applies if {@link #isInheritModulePath()} or {@link #isInheritClassPath()} is
816   * enabled, and only applies to the current JVM classpath and module path.
817   *
818   * <p>Unless otherwise changed or specified, implementations should default to
819   * {@link #DEFAULT_FIX_JVM_MODULE_PATH_MISMATCH}.
820   *
821   * @return {@code true} if enabled, or {@code false} if disabled.
822   */
823  boolean isFixJvmModulePathMismatch();
824
825  /**
826   * Get whether we will attempt to fix modules appearing on the classpath, or non-modules appearing
827   * on the module path.
828   *
829   * <p>Unless otherwise changed or specified, implementations should default to
830   * {@link #DEFAULT_FIX_JVM_MODULE_PATH_MISMATCH}.
831   *
832   * @param fixJvmModulePathMismatch whether to enable the mismatch fixing or not.
833   * @return this compiler object for further call chaining.
834   */
835  JctCompiler fixJvmModulePathMismatch(boolean fixJvmModulePathMismatch);
836
837  /**
838   * Get whether the class path is inherited from the active JVM or not.
839   *
840   * <p>Unless otherwise changed or specified, implementations should default to
841   * {@link #DEFAULT_INHERIT_CLASS_PATH}.
842   *
843   * @return whether the current class path is being inherited or not.
844   */
845  boolean isInheritClassPath();
846
847  /**
848   * Set whether the class path is inherited from the active JVM or not.
849   *
850   * <p>Unless otherwise changed or specified, implementations should default to
851   * {@link #DEFAULT_INHERIT_CLASS_PATH}.
852   *
853   * @param inheritClassPath {@code true} to include it, or {@code false} to exclude it.
854   * @return this compiler object for further call chaining.
855   */
856  JctCompiler inheritClassPath(boolean inheritClassPath);
857
858  /**
859   * Get whether the module path is inherited from the active JVM or not.
860   *
861   * <p>Unless otherwise changed or specified, implementations should default to
862   * {@link #DEFAULT_INHERIT_MODULE_PATH}.
863   *
864   * @return whether the module path is being inherited or not.
865   */
866  boolean isInheritModulePath();
867
868  /**
869   * Set whether the module path is inherited from the active JVM or not.
870   *
871   * <p>Unless otherwise changed or specified, implementations should default to
872   * {@link #DEFAULT_INHERIT_MODULE_PATH}.
873   *
874   * @param inheritModulePath {@code true} to include it, or {@code false} to exclude it.
875   * @return this compiler object for further call chaining.
876   */
877  JctCompiler inheritModulePath(boolean inheritModulePath);
878
879  /**
880   * Get whether the system module path is inherited from the active JVM or not.
881   *
882   * <p>Unless otherwise changed or specified, implementations should default to
883   * {@link #DEFAULT_INHERIT_SYSTEM_MODULE_PATH}.
884   *
885   * @return whether the system module path is being inherited or not.
886   */
887  boolean isInheritSystemModulePath();
888
889  /**
890   * Set whether the system module path is inherited from the active JVM or not.
891   *
892   * <p>Unless otherwise changed or specified, implementations should default to
893   * {@link #DEFAULT_INHERIT_SYSTEM_MODULE_PATH}.
894   *
895   * @param inheritSystemModulePath {@code true} to include it, or {@code false} to exclude it.
896   * @return this compiler object for further call chaining.
897   */
898  JctCompiler inheritSystemModulePath(boolean inheritSystemModulePath);
899
900  /**
901   * Get the output locale.
902   *
903   * <p>Unless otherwise changed or specified, implementations should default to
904   * {@link #DEFAULT_LOCALE}.
905   *
906   * @return the output locale to use.
907   */
908  Locale getLocale();
909
910  /**
911   * Set the output locale.
912   *
913   * <p>Unless otherwise changed or specified, implementations should default to
914   * {@link #DEFAULT_LOCALE}.
915   *
916   * @param locale the locale to use.
917   * @return this compiler for further call chaining.
918   */
919  JctCompiler locale(Locale locale);
920
921  /**
922   * Get the charset being used to write compiler logs with.
923   *
924   * <p>Unless otherwise changed or specified, implementations should default to
925   * {@link #DEFAULT_LOG_CHARSET}.
926   *
927   * @return the charset.
928   */
929  Charset getLogCharset();
930
931  /**
932   * Set the charset being used to write compiler logs with.
933   *
934   * <p>Unless otherwise changed or specified, implementations should default to
935   * {@link #DEFAULT_LOG_CHARSET}.
936   *
937   * @param logCharset the charset to use.
938   * @return this compiler for further call chaining.
939   */
940  JctCompiler logCharset(Charset logCharset);
941
942  /**
943   * Get the current file manager logging mode.
944   *
945   * <p>Unless otherwise changed or specified, implementations should default to
946   * {@link #DEFAULT_FILE_MANAGER_LOGGING_MODE}.
947   *
948   * @return the current file manager logging mode.
949   */
950  LoggingMode getFileManagerLoggingMode();
951
952  /**
953   * Set how to handle logging calls to underlying file managers.
954   *
955   * <p>Unless otherwise changed or specified, implementations should default to
956   * {@link #DEFAULT_FILE_MANAGER_LOGGING_MODE}.
957   *
958   * @param fileManagerLoggingMode the mode to use for file manager logging.
959   * @return this compiler for further call chaining.
960   */
961  JctCompiler fileManagerLoggingMode(LoggingMode fileManagerLoggingMode);
962
963  /**
964   * Get the current diagnostic logging mode.
965   *
966   * <p>Unless otherwise changed or specified, implementations should default to
967   * {@link #DEFAULT_DIAGNOSTIC_LOGGING_MODE}.
968   *
969   * @return the current diagnostic logging mode.
970   */
971  LoggingMode getDiagnosticLoggingMode();
972
973  /**
974   * Set how to handle diagnostic capture.
975   *
976   * <p>Unless otherwise changed or specified, implementations should default to
977   * {@link #DEFAULT_DIAGNOSTIC_LOGGING_MODE}.
978   *
979   * @param diagnosticLoggingMode the mode to use for diagnostic capture.
980   * @return this compiler for further call chaining.
981   */
982  JctCompiler diagnosticLoggingMode(LoggingMode diagnosticLoggingMode);
983
984  /**
985   * Get how to perform annotation processor discovery.
986   *
987   * <p>Unless otherwise changed or specified, implementations should default to
988   * {@link #DEFAULT_ANNOTATION_PROCESSOR_DISCOVERY}.
989   *
990   * <p>Specifying any annotation processors explicitly with
991   * {@link #addAnnotationProcessors(Iterable)} or
992   * {@link #addAnnotationProcessors(Processor...)} will bypass this setting, treating it
993   * as being disabled.
994   *
995   * @return the processor discovery mode to use.
996   */
997  AnnotationProcessorDiscovery getAnnotationProcessorDiscovery();
998
999  /**
1000   * Set how to perform annotation processor discovery.
1001   *
1002   * <p>Unless otherwise changed or specified, implementations should default to
1003   * {@link #DEFAULT_ANNOTATION_PROCESSOR_DISCOVERY}.
1004   *
1005   * <p>Specifying any annotation processors explicitly with
1006   * {@link #addAnnotationProcessors(Iterable)} or
1007   * {@link #addAnnotationProcessors(Processor...)} will bypass this setting, treating it
1008   * as being disabled.
1009   *
1010   * @param annotationProcessorDiscovery the processor discovery mode to use.
1011   * @return this compiler for further call chaining.
1012   */
1013  JctCompiler annotationProcessorDiscovery(
1014      AnnotationProcessorDiscovery annotationProcessorDiscovery);
1015
1016  /**
1017   * Get the debugging info that is enabled.
1018   *
1019   * <p>Unless otherwise changed or specified, implementations should default to
1020   * {@link #DEFAULT_DEBUGGING_INFO}.
1021   *
1022   * @return the set of debugging info flags that are enabled.
1023   * @since 3.0.0
1024   */
1025  Set<DebuggingInfo> getDebuggingInfo();
1026
1027  /**
1028   * Set the debugging info level to use.
1029   *
1030   * @param debuggingInfoFlags the set of debugging info flags to enable.
1031   * @return this compiler for further call chaining.
1032   * @since 3.0.0
1033   */
1034  JctCompiler debuggingInfo(Set<DebuggingInfo> debuggingInfoFlags);
1035
1036  /**
1037   * Determine if including reflective parameter info is enabled or not.
1038   *
1039   * <p>Unless otherwise changed or specified, implementations should default to
1040   * {@link #DEFAULT_PARAMETER_INFO_ENABLED}.
1041   *
1042   * @return the parameter info inclusion preference.
1043   * @since 3.0.0
1044   */
1045  boolean isParameterInfoEnabled();
1046
1047  /**
1048   * Set whether to include parameter reflective info by default in compiled classes or not.
1049   *
1050   * @param parameterInfoEnabled whether to include the parameter reflective info or not.
1051   * @return this compiler for further call chaining.
1052   * @since 3.0.0
1053   */
1054  JctCompiler parameterInfoEnabled(boolean parameterInfoEnabled);
1055}