001/*
002 * Copyright (C) 2022 - 2024, the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *    http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.github.ascopes.jct.compilers;
017
018import static io.github.ascopes.jct.utils.IterableUtils.requireAtLeastOne;
019
020import io.github.ascopes.jct.ex.JctCompilerException;
021import io.github.ascopes.jct.filemanagers.AnnotationProcessorDiscovery;
022import io.github.ascopes.jct.filemanagers.LoggingMode;
023import io.github.ascopes.jct.workspaces.Workspace;
024import java.io.UncheckedIOException;
025import java.nio.charset.Charset;
026import java.nio.charset.StandardCharsets;
027import java.util.Collection;
028import java.util.List;
029import java.util.Locale;
030import java.util.Set;
031import javax.annotation.processing.Processor;
032import javax.lang.model.SourceVersion;
033import org.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  default JctCompiler release(SourceVersion release) {
625    return release(Integer.toString(release.ordinal()));
626  }
627
628  /**
629   * Request that the compiler uses a language version that corresponds to the runtime language
630   * version in use on the current JVM.
631   *
632   * <p>For example, running this on JRE 19 would set the release to "19".
633   *
634   * <p>This calls {@link #release(int)} internally.
635   *
636   * @return this compiler object for further call chaining.
637   * @throws UnsupportedOperationException if the current JVM version does not correspond to a
638   *                                       supported Java release version in the compiler, or if the
639   *                                       compiler does not support integral version numbers.
640   * @since 1.1.0
641   */
642  default JctCompiler useRuntimeRelease() {
643    return release(Runtime.version().feature());
644  }
645
646  /**
647   * Get the current source version that is set, or {@code null} if left to the compiler to decide.
648   * default.
649   *
650   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
651   * default.
652   *
653   * @return the source version string, if set.
654   */
655  @Nullable
656  String getSource();
657
658  /**
659   * Set the source version.
660   *
661   * <p>This will clear any release version that is set.
662   *
663   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
664   * default.
665   *
666   * <p>Source and target versions have mostly been replaced with the release version
667   * mechanism which controls both flags and can ensure other behaviours are consistent. This
668   * feature is still provided in case you have a specific use case that is not covered by this
669   * functionality.
670   *
671   * @param source the version to set.
672   * @return this compiler object for further call chaining.
673   */
674  JctCompiler source(@Nullable String source);
675
676  /**
677   * Set the source version.
678   *
679   * <p>This will clear any release version that is set.
680   *
681   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
682   * default.
683   *
684   * <p>Source and target versions have mostly been replaced with the release version
685   * mechanism which controls both flags and can ensure other behaviours are consistent. This
686   * feature is still provided in case you have a specific use case that is not covered by this
687   * functionality.
688   *
689   * @param source the version to set.
690   * @return this compiler object for further call chaining.
691   * @throws IllegalArgumentException      if the version is less than 0.
692   * @throws UnsupportedOperationException if the compiler does not support integer versions.
693   */
694  default JctCompiler source(int source) {
695    if (source < 0) {
696      throw new IllegalArgumentException("Cannot provide a source version less than 0");
697    }
698
699    return source(Integer.toString(source));
700  }
701
702  /**
703   * Set the source version.
704   *
705   * <p>This will clear any release version that is set.
706   *
707   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
708   * default.
709   *
710   * <p>Source and target versions have mostly been replaced with the release version
711   * mechanism which controls both flags and can ensure other behaviours are consistent. This
712   * feature is still provided in case you have a specific use case that is not covered by this
713   * functionality.
714   *
715   * @param source the version to set.
716   * @return this compiler object for further call chaining.
717   * @throws UnsupportedOperationException if the compiler does not support integer versions.
718   * @throws NullPointerException          if the source is null.
719   */
720  default JctCompiler source(SourceVersion source) {
721    return source(Integer.toString(source.ordinal()));
722  }
723
724  /**
725   * Get the current target version that is set, or {@code null} if left to the compiler default.
726   *
727   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
728   * default.
729   *
730   * @return the target version string, if set.
731   */
732  @Nullable
733  String getTarget();
734
735  /**
736   * Set the target version.
737   *
738   * <p>This will clear any release version that is set.
739   *
740   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
741   * default.
742   *
743   * <p>Source and target versions have mostly been replaced with the release version
744   * mechanism which controls both flags and can ensure other behaviours are consistent. This
745   * feature is still provided in case you have a specific use case that is not covered by this
746   * functionality.
747   *
748   * @param target the version to set.
749   * @return this compiler object for further call chaining.
750   */
751  JctCompiler target(@Nullable String target);
752
753  /**
754   * Set the target version.
755   *
756   * <p>This will clear any release version that is set.
757   *
758   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
759   * default.
760   *
761   * <p>Source and target versions have mostly been replaced with the release version
762   * mechanism which controls both flags and can ensure other behaviours are consistent. This
763   * feature is still provided in case you have a specific use case that is not covered by this
764   * functionality.
765   *
766   * @param target the version to set.
767   * @return this compiler object for further call chaining.
768   * @throws IllegalArgumentException      if the version is less than 0.
769   * @throws UnsupportedOperationException if the compiler does not support integer versions.
770   */
771  default JctCompiler target(int target) {
772    if (target < 0) {
773      throw new IllegalArgumentException("Cannot provide a target version less than 0");
774    }
775
776    return target(Integer.toString(target));
777  }
778
779  /**
780   * Set the target version.
781   *
782   * <p>This will clear any release version that is set.
783   *
784   * <p>Unless explicitly defined, the default setting is expected to be a sane compiler-specific
785   * default.
786   *
787   * <p>Source and target versions have mostly been replaced with the release version
788   * mechanism which controls both flags and can ensure other behaviours are consistent. This
789   * feature is still provided in case you have a specific use case that is not covered by this
790   * functionality.
791   *
792   * @param target the version to set.
793   * @return this compiler object for further call chaining.
794   * @throws UnsupportedOperationException if the compiler does not support integer versions.
795   * @throws NullPointerException          if the target is null.
796   */
797  default JctCompiler target(SourceVersion target) {
798    return target(Integer.toString(target.ordinal()));
799  }
800
801  /**
802   * Get whether we will attempt to fix modules appearing on the classpath, or non-modules appearing
803   * on the module path.
804   *
805   * <p>This enables correct classpath and module path detection when the test pack is a module but
806   * the code being compiled in the test is not, and vice versa. We need this because many build
807   * systems decide whether to populate the {@code --module-path} or the {@code --classpath}
808   * with JPMS-enabled dependencies based on whether the project under compilation is a JPMS module
809   * itself.
810   *
811   * <p>This only applies if {@link #isInheritModulePath()} or {@link #isInheritClassPath()} is
812   * enabled, and only applies to the current JVM classpath and module path.
813   *
814   * <p>Unless otherwise changed or specified, implementations should default to
815   * {@link #DEFAULT_FIX_JVM_MODULE_PATH_MISMATCH}.
816   *
817   * @return {@code true} if enabled, or {@code false} if disabled.
818   */
819  boolean isFixJvmModulePathMismatch();
820
821  /**
822   * Get whether we will attempt to fix modules appearing on the classpath, or non-modules appearing
823   * on the module path.
824   *
825   * <p>Unless otherwise changed or specified, implementations should default to
826   * {@link #DEFAULT_FIX_JVM_MODULE_PATH_MISMATCH}.
827   *
828   * @param fixJvmModulePathMismatch whether to enable the mismatch fixing or not.
829   * @return this compiler object for further call chaining.
830   */
831  JctCompiler fixJvmModulePathMismatch(boolean fixJvmModulePathMismatch);
832
833  /**
834   * Get whether the class path is inherited from the active JVM or not.
835   *
836   * <p>Unless otherwise changed or specified, implementations should default to
837   * {@link #DEFAULT_INHERIT_CLASS_PATH}.
838   *
839   * @return whether the current class path is being inherited or not.
840   */
841  boolean isInheritClassPath();
842
843  /**
844   * Set whether the class path is inherited from the active JVM or not.
845   *
846   * <p>Unless otherwise changed or specified, implementations should default to
847   * {@link #DEFAULT_INHERIT_CLASS_PATH}.
848   *
849   * @param inheritClassPath {@code true} to include it, or {@code false} to exclude it.
850   * @return this compiler object for further call chaining.
851   */
852  JctCompiler inheritClassPath(boolean inheritClassPath);
853
854  /**
855   * Get whether the module path is inherited from the active JVM or not.
856   *
857   * <p>Unless otherwise changed or specified, implementations should default to
858   * {@link #DEFAULT_INHERIT_MODULE_PATH}.
859   *
860   * @return whether the module path is being inherited or not.
861   */
862  boolean isInheritModulePath();
863
864  /**
865   * Set whether the module path is inherited from the active JVM or not.
866   *
867   * <p>Unless otherwise changed or specified, implementations should default to
868   * {@link #DEFAULT_INHERIT_MODULE_PATH}.
869   *
870   * @param inheritModulePath {@code true} to include it, or {@code false} to exclude it.
871   * @return this compiler object for further call chaining.
872   */
873  JctCompiler inheritModulePath(boolean inheritModulePath);
874
875  /**
876   * Get whether the system module path is inherited from the active JVM or not.
877   *
878   * <p>Unless otherwise changed or specified, implementations should default to
879   * {@link #DEFAULT_INHERIT_SYSTEM_MODULE_PATH}.
880   *
881   * @return whether the system module path is being inherited or not.
882   */
883  boolean isInheritSystemModulePath();
884
885  /**
886   * Set whether the system module path is inherited from the active JVM or not.
887   *
888   * <p>Unless otherwise changed or specified, implementations should default to
889   * {@link #DEFAULT_INHERIT_SYSTEM_MODULE_PATH}.
890   *
891   * @param inheritSystemModulePath {@code true} to include it, or {@code false} to exclude it.
892   * @return this compiler object for further call chaining.
893   */
894  JctCompiler inheritSystemModulePath(boolean inheritSystemModulePath);
895
896  /**
897   * Get the output locale.
898   *
899   * <p>Unless otherwise changed or specified, implementations should default to
900   * {@link #DEFAULT_LOCALE}.
901   *
902   * @return the output locale to use.
903   */
904  Locale getLocale();
905
906  /**
907   * Set the output locale.
908   *
909   * <p>Unless otherwise changed or specified, implementations should default to
910   * {@link #DEFAULT_LOCALE}.
911   *
912   * @param locale the locale to use.
913   * @return this compiler for further call chaining.
914   */
915  JctCompiler locale(Locale locale);
916
917  /**
918   * Get the charset being used to write compiler logs with.
919   *
920   * <p>Unless otherwise changed or specified, implementations should default to
921   * {@link #DEFAULT_LOG_CHARSET}.
922   *
923   * @return the charset.
924   */
925  Charset getLogCharset();
926
927  /**
928   * Set the charset being used to write compiler logs with.
929   *
930   * <p>Unless otherwise changed or specified, implementations should default to
931   * {@link #DEFAULT_LOG_CHARSET}.
932   *
933   * @param logCharset the charset to use.
934   * @return this compiler for further call chaining.
935   */
936  JctCompiler logCharset(Charset logCharset);
937
938  /**
939   * Get the current file manager logging mode.
940   *
941   * <p>Unless otherwise changed or specified, implementations should default to
942   * {@link #DEFAULT_FILE_MANAGER_LOGGING_MODE}.
943   *
944   * @return the current file manager logging mode.
945   */
946  LoggingMode getFileManagerLoggingMode();
947
948  /**
949   * Set how to handle logging calls to underlying file managers.
950   *
951   * <p>Unless otherwise changed or specified, implementations should default to
952   * {@link #DEFAULT_FILE_MANAGER_LOGGING_MODE}.
953   *
954   * @param fileManagerLoggingMode the mode to use for file manager logging.
955   * @return this compiler for further call chaining.
956   */
957  JctCompiler fileManagerLoggingMode(LoggingMode fileManagerLoggingMode);
958
959  /**
960   * Get the current diagnostic logging mode.
961   *
962   * <p>Unless otherwise changed or specified, implementations should default to
963   * {@link #DEFAULT_DIAGNOSTIC_LOGGING_MODE}.
964   *
965   * @return the current diagnostic logging mode.
966   */
967  LoggingMode getDiagnosticLoggingMode();
968
969  /**
970   * Set how to handle diagnostic capture.
971   *
972   * <p>Unless otherwise changed or specified, implementations should default to
973   * {@link #DEFAULT_DIAGNOSTIC_LOGGING_MODE}.
974   *
975   * @param diagnosticLoggingMode the mode to use for diagnostic capture.
976   * @return this compiler for further call chaining.
977   */
978  JctCompiler diagnosticLoggingMode(LoggingMode diagnosticLoggingMode);
979
980  /**
981   * Get how to perform annotation processor discovery.
982   *
983   * <p>Unless otherwise changed or specified, implementations should default to
984   * {@link #DEFAULT_ANNOTATION_PROCESSOR_DISCOVERY}.
985   *
986   * <p>Specifying any annotation processors explicitly with
987   * {@link #addAnnotationProcessors(Iterable)} or
988   * {@link #addAnnotationProcessors(Processor...)} will bypass this setting, treating it
989   * as being disabled.
990   *
991   * @return the processor discovery mode to use.
992   */
993  AnnotationProcessorDiscovery getAnnotationProcessorDiscovery();
994
995  /**
996   * Set how to perform annotation processor discovery.
997   *
998   * <p>Unless otherwise changed or specified, implementations should default to
999   * {@link #DEFAULT_ANNOTATION_PROCESSOR_DISCOVERY}.
1000   *
1001   * <p>Specifying any annotation processors explicitly with
1002   * {@link #addAnnotationProcessors(Iterable)} or
1003   * {@link #addAnnotationProcessors(Processor...)} will bypass this setting, treating it
1004   * as being disabled.
1005   *
1006   * @param annotationProcessorDiscovery the processor discovery mode to use.
1007   * @return this compiler for further call chaining.
1008   */
1009  JctCompiler annotationProcessorDiscovery(
1010      AnnotationProcessorDiscovery annotationProcessorDiscovery);
1011
1012  /**
1013   * Get the debugging info that is enabled.
1014   *
1015   * <p>Unless otherwise changed or specified, implementations should default to
1016   * {@link #DEFAULT_DEBUGGING_INFO}.
1017   *
1018   * @return the set of debugging info flags that are enabled.
1019   * @since 3.0.0
1020   */
1021  Set<DebuggingInfo> getDebuggingInfo();
1022
1023  /**
1024   * Set the debugging info level to use.
1025   *
1026   * @param debuggingInfoFlags the set of debugging info flags to enable.
1027   * @return this compiler for further call chaining.
1028   * @since 3.0.0
1029   */
1030  JctCompiler debuggingInfo(Set<DebuggingInfo> debuggingInfoFlags);
1031
1032  /**
1033   * Determine if including reflective parameter info is enabled or not.
1034   *
1035   * <p>Unless otherwise changed or specified, implementations should default to
1036   * {@link #DEFAULT_PARAMETER_INFO_ENABLED}.
1037   *
1038   * @return the parameter info inclusion preference.
1039   * @since 3.0.0
1040   */
1041  boolean isParameterInfoEnabled();
1042
1043  /**
1044   * Set whether to include parameter reflective info by default in compiled classes or not.
1045   *
1046   * @param parameterInfoEnabled whether to include the parameter reflective info or not.
1047   * @return this compiler for further call chaining.
1048   * @since 3.0.0
1049   */
1050  JctCompiler parameterInfoEnabled(boolean parameterInfoEnabled);
1051}