diff --git a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java index ecf85e7d265..d427c716531 100644 --- a/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java +++ b/org.eclipse.jdt.apt.core/src/org/eclipse/jdt/apt/core/internal/AptCompilationParticipant.java @@ -15,19 +15,26 @@ package org.eclipse.jdt.apt.core.internal; +import java.net.URI; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.apt.core.internal.generatedfile.GeneratedSourceFolderManager; import org.eclipse.jdt.apt.core.internal.util.FactoryPath; +import org.eclipse.jdt.apt.core.internal.util.FactoryPathUtil; import org.eclipse.jdt.apt.core.internal.util.TestCodeUtil; import org.eclipse.jdt.apt.core.util.AptConfig; import org.eclipse.jdt.core.ICompilationUnit; @@ -208,6 +215,45 @@ public void processAnnotations(BuildContext[] allfiles) { } } + @Override + public URI[] getAnnotationProcessorPaths(IJavaProject project, boolean isTest) { + List processorPaths = new ArrayList<>(); + FactoryPath factoryPath = FactoryPathUtil.getFactoryPath(project); + if (factoryPath == null) { + return null; + } + + factoryPath.getEnabledContainers().keySet().forEach(container -> { + if (container instanceof JarFactoryContainer jarContainer) { + if (jarContainer.exists()) { + processorPaths.add(jarContainer.getJarFile().toURI()); + } + } + }); + + if (!processorPaths.isEmpty()) { + return processorPaths.toArray(new URI[processorPaths.size()]); + } + + return null; + } + + @Override + public IContainer[] getGeneratedSourcePaths(IJavaProject project, boolean isTest) { + AptProject aptProject = AptPlugin.getAptProject(project); + if (aptProject == null) { + return null; + } + + GeneratedSourceFolderManager generatedSourceFolderManager = aptProject.getGeneratedSourceFolderManager(isTest); + if (generatedSourceFolderManager == null) { + return null; + } + + IFolder folder = generatedSourceFolderManager.getFolder(); + return folder == null? null : new IContainer[] { folder }; + } + @Override public void reconcile(ReconcileContext context){ final ICompilationUnit workingCopy = context.getWorkingCopy(); diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/.classpath b/org.eclipse.jdt.core.tests.builder.mockcompiler/.classpath new file mode 100644 index 00000000000..3628e336878 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/.project b/org.eclipse.jdt.core.tests.builder.mockcompiler/.project new file mode 100644 index 00000000000..96f07316a70 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/.project @@ -0,0 +1,26 @@ + + + org.eclipse.jdt.core.tests.builder.mockcompiler + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + + diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 00000000000..5a0ad22d2a7 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..68f70ab61d7 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,142 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/ +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullable.secondary= +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled +org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=warning +org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..ab1a6829885 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=false +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=false +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_modifiers=false +sp_cleanup.remove_redundant_semicolons=true +sp_cleanup.remove_redundant_type_arguments=true +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.update_ibm_copyright_to_current_year=true +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.builder.mockcompiler/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..802d4f8c7e7 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.jdt.core.tests.builder.mockcompiler; singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Fragment-Host: org.eclipse.jdt.core +Export-Package: org.eclipse.jdt.core.tests.builder.mockcompiler +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Eclipse-BundleShape: dir +Automatic-Module-Name: org.eclipse.jdt.core.tests.builder.mockcompiler diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/about.html b/org.eclipse.jdt.core.tests.builder.mockcompiler/about.html new file mode 100644 index 00000000000..164f781a8fd --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/about.html @@ -0,0 +1,36 @@ + + + + +About + + +

About This Content

+ +

November 30, 2017

+

License

+ +

+ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +

+ + + \ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/build.properties b/org.eclipse.jdt.core.tests.builder.mockcompiler/build.properties new file mode 100644 index 00000000000..cde1c74f7b8 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/build.properties @@ -0,0 +1,19 @@ +############################################################################### +# Copyright (c) 2024 Microsoft Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Microsoft Corporation - initial API and implementation +############################################################################### +bin.includes = about.html,\ + .,\ + META-INF/,\ + plugin.properties +source.. = src/ +output.. = bin/ +src.includes=about.html diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/plugin.properties b/org.eclipse.jdt.core.tests.builder.mockcompiler/plugin.properties new file mode 100644 index 00000000000..5921a7fb230 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/plugin.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2024 Microsoft Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Microsoft Corporation - initial API and implementation +############################################################################### +providerName=Eclipse.org +pluginName=Java Custom Compiler Tests diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/pom.xml b/org.eclipse.jdt.core.tests.builder.mockcompiler/pom.xml new file mode 100644 index 00000000000..be510b54702 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/pom.xml @@ -0,0 +1,25 @@ + + + + 4.0.0 + + tests-pom + org.eclipse.jdt + 4.33.0-SNAPSHOT + ../tests-pom/ + + org.eclipse.jdt.core.tests.builder.mockcompiler + 1.0.0-SNAPSHOT + eclipse-plugin + diff --git a/org.eclipse.jdt.core.tests.builder.mockcompiler/src/org/eclipse/jdt/core/tests/builder/mockcompiler/MockCompilerFactory.java b/org.eclipse.jdt.core.tests.builder.mockcompiler/src/org/eclipse/jdt/core/tests/builder/mockcompiler/MockCompilerFactory.java new file mode 100644 index 00000000000..e72e2d34b09 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder.mockcompiler/src/org/eclipse/jdt/core/tests/builder/mockcompiler/MockCompilerFactory.java @@ -0,0 +1,84 @@ +/******************************************************************************* +* Copyright (c) 2024 Microsoft Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package org.eclipse.jdt.core.tests.builder.mockcompiler; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; + +import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.CompilerConfiguration; +import org.eclipse.jdt.internal.compiler.ICompilerFactory; +import org.eclipse.jdt.internal.compiler.ICompilerRequestor; +import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; +import org.eclipse.jdt.internal.compiler.IProblemFactory; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +public class MockCompilerFactory implements ICompilerFactory { + public static Set> listeners = new HashSet<>(); + + @Override + public Compiler newCompiler(INameEnvironment environment, IErrorHandlingPolicy policy, + CompilerConfiguration compilerConfig, ICompilerRequestor requestor, IProblemFactory problemFactory) { + Compiler compiler = new MockCompiler(environment, policy, compilerConfig, requestor, problemFactory); + for (Consumer listener : listeners) { + listener.accept(compiler); + } + + return compiler; + } + + public static void addListener(Consumer listener) { + listeners.add(listener); + } + + public static void removeListener(Consumer listener) { + listeners.remove(listener); + } + + public static class MockCompiler extends org.eclipse.jdt.internal.compiler.Compiler { + public CompilerConfiguration compilerConfig; + + public MockCompiler(INameEnvironment environment, IErrorHandlingPolicy policy, CompilerConfiguration compilerConfig, + ICompilerRequestor requestor, IProblemFactory problemFactory) { + super(environment, policy, compilerConfig.compilerOptions(), requestor, problemFactory); + this.compilerConfig = compilerConfig; + } + + @Override + public void compile(ICompilationUnit[] sourceUnits) { + for (int i = 0; i < sourceUnits.length; i++) { + ICompilationUnit in = sourceUnits[i]; + CompilationResult result = new CompilationResult(in, i, sourceUnits.length, Integer.MAX_VALUE); + if (i == 0) { + CategorizedProblem problem = new DefaultProblem(in.getFileName(), + "Compilation error from MockCompiler", + 0, + new String[0], + ProblemSeverities.Error, + 0, 0, 0, 0); + result.problems = new CategorizedProblem[] { problem }; + result.problemCount = result.problems.length; + } + + this.requestor.acceptResult(result); + } + } + } +} diff --git a/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF index 218db4fd941..a6085beafa2 100644 --- a/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF @@ -6,6 +6,7 @@ Bundle-Version: 3.12.500.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: org.eclipse.jdt.core.tests.builder +Import-Package: org.eclipse.jdt.core.tests.builder.mockcompiler Require-Bundle: org.junit;bundle-version="3.8.1", org.eclipse.jdt.core;bundle-version="[3.36.0,4.0.0)", org.eclipse.jdt.core.tests.compiler;bundle-version="[3.4.0,4.0.0)", @@ -13,7 +14,8 @@ Require-Bundle: org.junit;bundle-version="3.8.1", org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)", org.eclipse.test.performance;bundle-version="[3.1.0,4.0.0)", org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional, - org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional + org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional, + org.eclipse.jdt.apt.core Bundle-RequiredExecutionEnvironment: JavaSE-17 Eclipse-BundleShape: dir Automatic-Module-Name: org.eclipse.jdt.core.tests.builder diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.classpath b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.classpath new file mode 100644 index 00000000000..e90d2ab51b7 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.factorypath b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.factorypath new file mode 100644 index 00000000000..cf12c6aae49 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.factorypath @@ -0,0 +1,4 @@ + + + + diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.project b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.project new file mode 100644 index 00000000000..7f251d1870a --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.project @@ -0,0 +1,19 @@ + + + autoValueSnippet + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + + + diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.apt.core.prefs b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 00000000000..74a3c0a0761 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=true +org.eclipse.jdt.apt.genSrcDir=.apt_generated +org.eclipse.jdt.apt.genTestSrcDir=.apt_generated_tests +org.eclipse.jdt.apt.reconcileEnabled=true diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..13bd0e37f06 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,16 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.processAnnotations=enabled +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-1.6.5.jar b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-1.6.5.jar new file mode 100644 index 00000000000..be17cd17333 Binary files /dev/null and b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-1.6.5.jar differ diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-annotations-1.6.5.jar b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-annotations-1.6.5.jar new file mode 100644 index 00000000000..f68a0136753 Binary files /dev/null and b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/libs/auto-value-annotations-1.6.5.jar differ diff --git a/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/src/Outer.java b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/src/Outer.java new file mode 100644 index 00000000000..335144144a0 --- /dev/null +++ b/org.eclipse.jdt.core.tests.builder/resources/autoValueSnippet/src/Outer.java @@ -0,0 +1,23 @@ +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class Outer { + + public static Outer create(Inner value) { + return new AutoValue_Outer(value); + } + + public abstract Inner inner(); + + @AutoValue + public abstract static class Inner { + + public static Inner create(String value) { + return new AutoValue_Outer_Inner(value); + } + + public abstract String value(); + + } + +} \ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java index db417116ddb..d87ec180c25 100644 --- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java +++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BasicBuildTests.java @@ -15,20 +15,47 @@ *******************************************************************************/ package org.eclipse.jdt.core.tests.builder; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; import junit.framework.*; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.jdt.core.compiler.*; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.tests.builder.mockcompiler.MockCompilerFactory; +import org.eclipse.jdt.core.tests.builder.mockcompiler.MockCompilerFactory.MockCompiler; import org.eclipse.jdt.core.tests.util.Util; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.CompilerConfiguration; import org.eclipse.jdt.internal.core.JavaModelManager; +import org.eclipse.jdt.internal.core.builder.AbstractImageBuilder; /** * Basic tests of the image builder. @@ -687,4 +714,216 @@ public void testBug549942() throws JavaModelException { org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.MAX_AT_ONCE = save; } } + + public void testCustomCompilerFactory() throws JavaModelException { + final String CUSTOM_COMPILER_VALUE = MockCompilerFactory.class.getName(); + try { + System.setProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY, CUSTOM_COMPILER_VALUE); + IPath projectPath = env.addProject("Project"); //$NON-NLS-1$ + env.addExternalJars(projectPath, Util.getJavaClassLibs()); + + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$ + + IPath root = env.addPackageFragmentRoot(projectPath, "src"); //$NON-NLS-1$ + env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$ + + IPath path = env.addClass(root, "p1", "Hello", //$NON-NLS-1$ //$NON-NLS-2$ + """ + package p1; + public class Hello { + public static void main(String args[]) { + System.out.println(\"Hello world\"); + } + } + """ + ); + + fullBuild(projectPath); + + expectingProblemsFor( + path, + "Problem : Compilation error from MockCompiler [ resource :
range : <0,1> category : <60> severity : <2>]" + ); + } finally { + System.clearProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY); + } + } + + public void testCustomerCompilerFactoryWithAP() throws Exception { + final String CUSTOM_COMPILER_VALUE = MockCompilerFactory.class.getName(); + List configs = new ArrayList<>(); + Consumer listener = (compiler) -> { + if (compiler instanceof MockCompiler mockCompiler) { + configs.add(mockCompiler.compilerConfig); + } + }; + File projectRoot = null; + IProject project = null; + try { + MockCompilerFactory.addListener(listener); + System.setProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY, CUSTOM_COMPILER_VALUE); + projectRoot = copyFiles("autoValueSnippet", true); + IPath dotProjectPath = new org.eclipse.core.runtime.Path(new File(projectRoot, IProjectDescription.DESCRIPTION_FILE_NAME).getAbsolutePath()); + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IProjectDescription descriptor = workspace.loadProjectDescription(dotProjectPath); + String projectName = descriptor.getName(); + project = workspace.getRoot().getProject(projectName); + project.create(descriptor, new NullProgressMonitor()); + project.open(IResource.NONE, new NullProgressMonitor()); + + // full build + project.build(IncrementalProjectBuilder.FULL_BUILD, null); + + // It creates compiler 4 times (MAIN full build, TEST full build, MAIN incremental build, TEST incremental build) + assertFalse(configs.isEmpty()); + CompilerConfiguration config = configs.get(0); + List processorPaths = config.annotationProcessorPaths(); + assertEquals(2, processorPaths.size()); + assertTrue(processorPaths.get(0).getPath().endsWith("auto-value-1.6.5.jar")); + assertTrue(processorPaths.get(1).getPath().endsWith("auto-value-annotations-1.6.5.jar")); + + List generatedSourcePaths = config.generatedSourcePaths(); + assertEquals(1, generatedSourcePaths.size()); + assertEquals(".apt_generated", generatedSourcePaths.get(0).getRawLocation().lastSegment()); + + List sourcePaths = config.sourcepaths(); + assertEquals(2, sourcePaths.size()); + + assertEquals("src", sourcePaths.get(0).getRawLocation().lastSegment()); + assertEquals(".apt_generated", sourcePaths.get(1).getRawLocation().lastSegment()); + + List classPaths = config.classpaths(); + assertEquals(2, classPaths.size()); + assertTrue(classPaths.get(0).getPath().endsWith("bin")); + assertTrue(classPaths.get(1).getPath().endsWith("auto-value-annotations-1.6.5.jar")); + + List moduleSourcePaths = config.moduleSourcepaths(); + assertEquals(0, moduleSourcePaths.size()); + + List modulePaths = config.modulepaths(); + assertEquals(0, modulePaths.size()); + + Map sourceOutputMapping = config.sourceOutputMapping(); + assertEquals(2, sourceOutputMapping.size()); + + IFile aptGeneratedFile = project.getFile(".apt_generated/AutoValue_Outer.java"); + assertFalse("The default APT generation should be disabled for custom compiler", aptGeneratedFile.exists()); + } finally { + MockCompilerFactory.removeListener(listener); + System.clearProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY); + if (project != null && project.exists()) { + project.close(new NullProgressMonitor()); + } + if (projectRoot != null) { + deleteDirectory(projectRoot.toPath()); + } + } + } + + private File copyFiles(String path, boolean reimportIfExists) throws IOException { + File from = new File(getSourceProjectDirectory(), path); + File to = new File(getWorkingProjectDirectory(), path); + if (to.exists()) { + if (!reimportIfExists) { + return to; + } + if (to.isFile()) { + Files.delete(to.toPath()); + } else { + deleteDirectory(to.toPath()); + } + } + + if (from.isDirectory()) { + copyDirectory(from.toPath(), to.toPath()); + } else { + Files.copy(from.toPath(), to.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + + return to; + } + + private File getSourceProjectDirectory() { + final String pluginId = "org.eclipse.jdt.core.tests.builder"; + String cwd = new File("").getAbsolutePath(); + if (cwd.endsWith(pluginId)) { + return new File("resources"); // run from current test plugin + } else { + return new File("../" + pluginId + "/resources"); // run from other test plugin + } + } + + private File getWorkingProjectDirectory() throws IOException { + File dir = new File("target", "workingProjects"); + if (!dir.exists()) { + dir.mkdirs(); + } + return dir; + } + + private static void deleteDirectory(Path path) throws IOException { + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + + private static void copyDirectory(Path sourceDirectory, Path targetDirectory) throws IOException { + Files.walk(sourceDirectory) + .forEach(sourcePath -> { + Path targetPath = targetDirectory.resolve(sourceDirectory.relativize(sourcePath)); + try { + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + // ignore + } + }); + } + + public void testFallbackForProblematicCompilerFactory() throws JavaModelException { + final String CUSTOM_COMPILER_VALUE = "x.y.NotFoundCompilerFactory"; + try { + System.setProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY, CUSTOM_COMPILER_VALUE); + IPath projectPath = env.addProject("Project"); //$NON-NLS-1$ + env.addExternalJars(projectPath, Util.getJavaClassLibs()); + + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$ + + IPath root = env.addPackageFragmentRoot(projectPath, "src"); //$NON-NLS-1$ + env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$ + + IPath path = env.addClass(root, "p1", "Hello", //$NON-NLS-1$ //$NON-NLS-2$ + """ + package p1; + public class Hello { + public static void main(String args[]) { + int unUsedVarable; + } + } + """ + ); + + fullBuild(projectPath); + + // If the custom compiler is not found, should fall back to the default ECJ + expectingProblemsFor( + path, + "Problem : The value of the local variable unUsedVarable is not used [ resource : range : <87,100> category : <120> severity : <1>]" + ); + } finally { + System.clearProperty(AbstractImageBuilder.COMPILER_FACTORY_KEY); + } + } + } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java index d64d91fa920..c50e705d23c 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java @@ -18,8 +18,10 @@ package org.eclipse.jdt.core.compiler; import java.io.ByteArrayInputStream; +import java.net.URI; import java.util.Optional; +import org.eclipse.core.resources.IContainer; import org.eclipse.jdt.core.IJavaProject; /** @@ -152,6 +154,35 @@ public void processAnnotations(BuildContext[] files) { // do nothing by default } +/** + * Requests the participant to supply the locations where to find annotation + * processors. If this is not specified, then the class path is searched for + * processors. + * + * @param project the project to participate in + * @param isTest whether the annotation processor path is for test code + * @return the annotation processor paths + * @since 3.38 + * @noreference Provisional API for experimental support for an alternative compiler. This method is not intended to be referenced by clients. + */ +public URI[] getAnnotationProcessorPaths(IJavaProject project, boolean isTest) { + return null; +} + +/** + * Requests the participant to supply the locations to place the generated + * source files. + * + * @param project the project to participate in + * @param isTest whether the generated source paths are for test code + * @return the locations to place the generated source files + * @since 3.38 + * @noreference Provisional API for experimental support for an alternative compiler. This method is not intended to be referenced by clients. + */ +public IContainer[] getGeneratedSourcePaths(IJavaProject project, boolean isTest) { + return null; +} + /** * Returns whether this participant is interested in post processing of generated bytecode. *

diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/CompilerConfiguration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/CompilerConfiguration.java new file mode 100644 index 00000000000..d104c1366b8 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/CompilerConfiguration.java @@ -0,0 +1,69 @@ +/******************************************************************************* +* Copyright (c) 2024 Microsoft Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package org.eclipse.jdt.internal.compiler; + +import java.net.URI; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; + +/** + * This class encapsulates the standard compiler options that can be + * used to compile Java files. It provides methods to set and retrieve + * various compiler options, including source paths, class paths, + * output directories, annotation processing options, and other compiler + * arguments. + * + * Clients typically use this class when opting for an alternative compiler + * like Javac to compile Java files. + * + * @since 3.38 + */ +public final record CompilerConfiguration( + /** + * List of file paths where the compiler can find source files. + */ + List sourcepaths, + /** + * List of file paths where the compiler can find source files for modules. + */ + List moduleSourcepaths, + /** + * List of file paths where the compiler can find user class files and annotation processors. + */ + List classpaths, + /** + * List of file paths where the compiler can find modules. + */ + List modulepaths, + /** + * Location to search for annotation processors. + */ + List annotationProcessorPaths, + /** + * Locations to place generated source files. + */ + List generatedSourcePaths, + /** + * The mapping of source files to output directories. + */ + Map sourceOutputMapping, + /** + * The compiler options used to control the compilation behavior. + * See {@link org.eclipse.jdt.internal.compiler.impl.CompilerOptions} for a list of available options. + */ + CompilerOptions compilerOptions) { +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DefaultCompilerFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DefaultCompilerFactory.java new file mode 100644 index 00000000000..a8353dbaddd --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DefaultCompilerFactory.java @@ -0,0 +1,26 @@ +/******************************************************************************* +* Copyright (c) 2024 Microsoft Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package org.eclipse.jdt.internal.compiler; + +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; + +public class DefaultCompilerFactory implements ICompilerFactory { + + @Override + public Compiler newCompiler(INameEnvironment environment, IErrorHandlingPolicy policy, + CompilerConfiguration compilerConfig, ICompilerRequestor requestor, IProblemFactory problemFactory) { + return new Compiler(environment, policy, compilerConfig.compilerOptions(), + requestor, problemFactory); + } +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ICompilerFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ICompilerFactory.java new file mode 100644 index 00000000000..96ad2a9e281 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ICompilerFactory.java @@ -0,0 +1,38 @@ +/******************************************************************************* +* Copyright (c) 2024 Microsoft Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package org.eclipse.jdt.internal.compiler; + +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; + +/** + * A factory used to produce a compiler to compile the Java files. + */ +public interface ICompilerFactory { + + /** + * Create a new compiler using the given name environment and compiler options. + * + * @param environment - the type system environment used for resolving types and packages + * @param policy - the error handling policy + * @param compilerConfig - the configuration to control the compiler behavior + * @param requestor - the requestor to receive and persist compilation results + * @param problemFactory - the factory to create problem descriptors + * @return the new compiler instance + */ + public Compiler newCompiler(final INameEnvironment environment, + final IErrorHandlingPolicy policy, + final CompilerConfiguration compilerConfig, + final ICompilerRequestor requestor, + final IProblemFactory problemFactory); +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java index fc2ea679229..0f739005059 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java @@ -15,6 +15,7 @@ package org.eclipse.jdt.internal.core.builder; import org.eclipse.core.runtime.*; +import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.resources.*; import org.eclipse.jdt.core.*; @@ -38,6 +39,8 @@ import static org.eclipse.jdt.internal.core.JavaModelManager.trace; import java.io.*; +import java.lang.reflect.*; +import java.net.URI; import java.util.*; /** @@ -85,6 +88,7 @@ public abstract class AbstractImageBuilder implements ICompilerRequestor, ICompi public final static Integer P_HIGH = Integer.valueOf(IMarker.PRIORITY_HIGH); public final static Integer P_NORMAL = Integer.valueOf(IMarker.PRIORITY_NORMAL); public final static Integer P_LOW = Integer.valueOf(IMarker.PRIORITY_LOW); +public final static String COMPILER_FACTORY_KEY = "AbstractImageBuilder.compilerFactory"; //$NON-NLS-1$ private final CompilationGroup compilationGroup; protected AbstractImageBuilder(JavaBuilder javaBuilder, boolean buildStarting, State newState, CompilationGroup compilationGroup) { @@ -573,12 +577,31 @@ protected Compiler newCompiler() { CompilerOptions compilerOptions = new CompilerOptions(projectOptions); compilerOptions.performMethodsFullRecovery = true; compilerOptions.performStatementsRecovery = true; - Compiler newCompiler = new Compiler( - this.nameEnvironment, - DefaultErrorHandlingPolicies.proceedWithAllProblems(), - compilerOptions, - this, - ProblemFactory.getProblemFactory(Locale.getDefault())); + + ICompilerFactory compilerFactory = null; + String compilerFactoryClassName = System.getProperty(COMPILER_FACTORY_KEY); + if (compilerFactoryClassName != null) { + try { + Class compilerFactoryClass = (Class) Class.forName(compilerFactoryClassName); + Constructor constructor = compilerFactoryClass.getDeclaredConstructor(); + compilerFactory = constructor.newInstance(); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException + | IllegalArgumentException | InstantiationException | InvocationTargetException e) { + ILog.get().error("Failed to initialize the custom compiler factory - " + compilerFactoryClassName, e); //$NON-NLS-1$ + } + } + + if (compilerFactory == null) { + compilerFactory = new DefaultCompilerFactory(); + } + + Compiler newCompiler = compilerFactory.newCompiler( + this.nameEnvironment, + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + prepareCompilerConfiguration(compilerOptions), + this, + ProblemFactory.getProblemFactory(Locale.getDefault())); + CompilerOptions options = newCompiler.options; // temporary code to allow the compiler to revert to a single thread String setting = System.getProperty("jdt.compiler.useSingleThread"); //$NON-NLS-1$ @@ -596,6 +619,79 @@ protected Compiler newCompiler() { return newCompiler; } +private CompilerConfiguration prepareCompilerConfiguration(CompilerOptions options) { + try { + List annotationProcessorPaths = new ArrayList<>(); + List generatedSourcePaths = new ArrayList<>(); + boolean isTest = this.compilationGroup == CompilationGroup.TEST; + if (this.javaBuilder.participants != null) { + for (CompilationParticipant participant : this.javaBuilder.participants) { + if (participant.isAnnotationProcessor()) { + URI[] paths = participant.getAnnotationProcessorPaths(this.javaBuilder.javaProject, isTest); + if (paths != null) { + annotationProcessorPaths.addAll(Arrays.asList(paths)); + } + IContainer[] generatedSrc = participant.getGeneratedSourcePaths(this.javaBuilder.javaProject, isTest); + if (generatedSrc != null) { + generatedSourcePaths.addAll(Arrays.asList(generatedSrc)); + } + } + } + } + + ClasspathLocation[] classpathLocations = this.nameEnvironment.binaryLocations; + Set classpaths = new LinkedHashSet<>(); + Set modulepaths = new LinkedHashSet<>(); + for (ClasspathLocation location : classpathLocations) { + if (location instanceof ClasspathDirectory cpDirectory) { + URI cpURI = cpDirectory.binaryFolder.getRawLocationURI(); + if (cpURI == null) { + continue; + } + if (cpDirectory.isOnModulePath) { + modulepaths.add(cpURI); + } else { + classpaths.add(cpURI); + } + } else if (location instanceof ClasspathJar cpJar) { + URI cpURI = URIUtil.toURI(cpJar.zipFilename, true); + if (cpJar.isOnModulePath) { + modulepaths.add(cpURI); + } else { + classpaths.add(cpURI); + } + } + } + + Map sourceOutputMapping = new HashMap<>(); + Set sourcepaths = new LinkedHashSet<>(); + Set moduleSourcepaths = new LinkedHashSet<>(); + ClasspathMultiDirectory[] srcLocations = this.nameEnvironment.sourceLocations; + for (ClasspathMultiDirectory sourceLocation : srcLocations) { + sourceOutputMapping.put(sourceLocation.sourceFolder, sourceLocation.binaryFolder); + if (sourceLocation.isOnModulePath) { + moduleSourcepaths.add(sourceLocation.sourceFolder); + } else { + sourcepaths.add(sourceLocation.sourceFolder); + } + } + + return new CompilerConfiguration( + List.copyOf(sourcepaths), + List.copyOf(moduleSourcepaths), + List.copyOf(classpaths), + List.copyOf(modulepaths), + annotationProcessorPaths, + generatedSourcePaths, + sourceOutputMapping, + options); + } catch (Exception e) { + ILog.get().error("Failed computing compiler configuration", e); //$NON-NLS-1$ + return new CompilerConfiguration( + null, null, null, null, null, null, null, options); + } +} + protected CompilationParticipantResult[] notifyParticipants(SourceFile[] unitsAboutToCompile) { CompilationParticipantResult[] results = new CompilationParticipantResult[unitsAboutToCompile.length]; for (int i = unitsAboutToCompile.length; --i >= 0;) @@ -666,10 +762,13 @@ protected void processAnnotations(CompilationParticipantResult[] results) { results[i].reset(foundAnnotations ? this.filesWithAnnotations.get(results[i].sourceFile) : null); } - // even if no files have annotations, must still tell every annotation processor in case the file used to have them - for (CompilationParticipant participant : this.javaBuilder.participants) - if (participant.isAnnotationProcessor()) - participant.processAnnotations(results); + boolean isEcjUsed = Compiler.class.equals(this.compiler.getClass()); + if (isEcjUsed) { + // even if no files have annotations, must still tell every annotation processor in case the file used to have them + for (CompilationParticipant participant : this.javaBuilder.participants) + if (participant.isAnnotationProcessor()) + participant.processAnnotations(results); + } processAnnotationResults(results); } diff --git a/pom.xml b/pom.xml index a29d500788c..d4982961eee 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,7 @@ org.eclipse.jdt.core org.eclipse.jdt.core.formatterapp org.eclipse.jdt.compiler.tool.tests + org.eclipse.jdt.core.tests.builder.mockcompiler org.eclipse.jdt.core.tests.builder org.eclipse.jdt.core.tests.compiler org.eclipse.jdt.core.tests.model