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