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