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