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