diff --git a/.github/workflows/auto-author-assign.yml b/.github/workflows/auto-author-assign.yml
new file mode 100644
index 00000000000..febd4f8d1fd
--- /dev/null
+++ b/.github/workflows/auto-author-assign.yml
@@ -0,0 +1,14 @@
+name: Auto Author Assign
+
+on:
+ pull_request_target:
+ types: [ opened, reopened ]
+
+permissions:
+ pull-requests: write
+
+jobs:
+ assign-author:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: toshimaru/auto-author-assign@v2.1.0
\ No newline at end of file
diff --git a/.github/workflows/ci-dom-javac.yml b/.github/workflows/ci-dom-javac.yml
new file mode 100644
index 00000000000..8d39a81e6b4
--- /dev/null
+++ b/.github/workflows/ci-dom-javac.yml
@@ -0,0 +1,68 @@
+name: Continuous Integration with DOM/Javac
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}-dom
+ cancel-in-progress: true
+
+on:
+ push:
+ branches: [ 'dom-with-javac' ]
+ pull_request:
+ branches: [ 'dom-with-javac' ]
+
+jobs:
+ build-dom-javac:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install xmllint
+ shell: bash
+ run: |
+ sudo apt update
+ sudo apt install -y libxml2-utils
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ fetch-depth: 0
+ - name: Set up JDKs ☕
+ uses: actions/setup-java@v4
+ with:
+ java-version: |
+ 8
+ 17
+ 21
+ 23
+ 24
+ mvn-toolchain-id: |
+ JavaSE-1.8
+ JavaSE-17
+ JavaSE-21
+ JavaSE-23
+ JavaSE-24
+ distribution: 'temurin'
+ - name: Set up Maven
+ uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5
+ with:
+ maven-version: 3.9.9
+ - name: Build with Maven 🏗️
+ run: |
+ mvn install --batch-mode -DskipTests -Pbree-libs -Dtycho.buildqualifier.format="'z'yyyyMMdd-HHmm" -Dproject.build.sourceEncoding=UTF-8 -pl org.eclipse.jdt.core.javac,org.eclipse.jdt.core.javac.feature,org.eclipse.jdt.core.tests.model,org.eclipse.jdt.core.tests.compiler
+ mvn verify --batch-mode -f org.eclipse.jdt.core.tests.javac --fail-at-end -Ptest-on-javase-24 -Pbree-libs -DfailIfNoTests=false -DexcludedGroups=org.junit.Ignore -DproviderHint=junit47 -Papi-check -Dproject.build.sourceEncoding=UTF-8 -Dmaven.test.failure.ignore=true -Dmaven.test.error.ignore=true
+ - name: 'Upload Artifact'
+ if: success() || failure() # run this step even if previous step failed
+ uses: actions/upload-artifact@v4
+ with:
+ name: Test results
+ path: '*/target/surefire-reports/TEST-*.xml'
+ - name: Test Report
+ if: success() || failure() # run this step even if previous step failed
+ run: |
+ message="▶️ TESTS RUN: $(xmllint --xpath 'string(/testsuite/@tests)' */target/surefire-reports/TEST-*.xml | awk '{n += $1}; END{print n}' -)
+ ❌ FAILURES: $(xmllint --xpath 'string(/testsuite/@failures)' */target/surefire-reports/TEST-*.xml | awk '{n += $1}; END{print n}' -)
+ 💥 ERRORS: $(xmllint --xpath 'string(/testsuite/@errors)' */target/surefire-reports/TEST-*.xml | awk '{n += $1}; END{print n}' -)
+ 🛑 SKIPPED: $(xmllint --xpath 'string(/testsuite/@skipped)' */target/surefire-reports/TEST-*.xml | awk '{n += $1}; END{print n}' -)"
+ echo "$message"
+ echo "$message" >> $GITHUB_STEP_SUMMARY
+ - name: Publish Test Results
+ uses: EnricoMi/publish-unit-test-result-action@v2
+ if: always()
+ with:
+ files: '*/target/surefire-reports/TEST-*.xml'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4e6c8d27860..e034f59b5a3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,7 +5,7 @@ concurrency:
on:
push:
- branches: '**'
+ branches: ['**']
jobs:
event_file:
@@ -31,15 +31,17 @@ jobs:
8
17
21
+ 23
mvn-toolchain-id: |
JavaSE-1.8
JavaSE-17
JavaSE-21
+ JavaSE-23
distribution: 'temurin'
- name: Set up Maven
uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5
with:
- maven-version: 3.9.8
+ maven-version: 3.9.9
- name: Build with Maven 🏗️
run: |
mvn clean install --batch-mode -f org.eclipse.jdt.core.compiler.batch -DlocalEcjVersion=99.99
diff --git a/Jenkinsfile b/Jenkinsfile
index 7e3bd17d862..dd11c17c2a8 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -13,51 +13,34 @@ pipeline {
jdk 'openjdk-jdk24-latest'
}
stages {
- stage('Build') {
+ stage('javac specific tests') {
steps {
- sh """#!/bin/bash -x
-
- java -version
-
+ sh """#!/bin/bash -x
mkdir -p $WORKSPACE/tmp
unset JAVA_TOOL_OPTIONS
unset _JAVA_OPTIONS
-
- # The max heap should be specified for tycho explicitly
- # via configuration/argLine property in pom.xml
- # export MAVEN_OPTS="-Xmx2G"
-
- mvn clean install -f org.eclipse.jdt.core.compiler.batch -DlocalEcjVersion=99.99 -Dmaven.repo.local=$WORKSPACE/.m2/repository -DcompilerBaselineMode=disable -DcompilerBaselineReplace=none
-
- mvn -U clean verify --batch-mode --fail-at-end -Dmaven.repo.local=$WORKSPACE/.m2/repository \
- -Ptest-on-javase-24 -Pbree-libs -Papi-check -Pjavadoc -Pp2-repo \
- -Dmaven.test.failure.ignore=true \
- -Dcompare-version-with-baselines.skip=false \
+ # force qualifier to start with `z` so we identify it more easily and it always seem more recent than upstrea
+ mvn install -DskipTests -Djava.io.tmpdir=$WORKSPACE/tmp -Dmaven.repo.local=$WORKSPACE/.m2/repository \
+ -Pbree-libs \
+ -Dtycho.buildqualifier.format="'z'yyyyMMdd-HHmm" \
+ -Pp2-repo \
-Djava.io.tmpdir=$WORKSPACE/tmp -Dproject.build.sourceEncoding=UTF-8 \
- -Dtycho.surefire.argLine="--add-modules ALL-SYSTEM -Dcompliance=1.8,11,17,21,23,24 -Djdt.performance.asserts=disabled" \
- -DDetectVMInstallationsJob.disabled=true \
- -Dtycho.apitools.debug \
- -Dtycho.debug.artifactcomparator \
- -e \
- -Dcbi-ecj-version=99.99
- """
+ -pl org.eclipse.jdt.core.javac,org.eclipse.jdt.core.javac.feature,org.eclipse.jdt.core.tests.model,org.eclipse.jdt.core.tests.compiler,repository
+
+ mvn verify --batch-mode -f org.eclipse.jdt.core.tests.javac -Dmaven.repo.local=$WORKSPACE/.m2/repository \
+ --fail-at-end -Ptest-on-javase-24 -Pbree-libs \
+ -DfailIfNoTests=false -DexcludedGroups=org.junit.Ignore -DproviderHint=junit47 \
+ -Papi-check -Djava.io.tmpdir=$WORKSPACE/tmp -Dproject.build.sourceEncoding=UTF-8 \
+ -Dmaven.test.failure.ignore=true -Dmaven.test.error.ignore=true
+"""
}
post {
always {
archiveArtifacts artifacts: '*.log,*/target/work/data/.metadata/*.log,*/tests/target/work/data/.metadata/*.log,apiAnalyzer-workspace/.metadata/*.log,repository/target/repository/**,**/target/artifactcomparison/**', allowEmptyArchive: true
- // The following lines use the newest build on master that did not fail a reference
- // To not fail master build on failed test maven needs to be started with "-Dmaven.test.failure.ignore=true" it will then only marked unstable.
- // To not fail the build also "unstable: true" is used to only mark the build unstable instead of failing when qualityGates are missed
- // To accept unstable builds (test errors or new warnings introduced by third party changes) as reference using "ignoreQualityGate:true"
- // To only show warnings related to the PR on a PR using "publishAllIssues:false"
- discoverGitReferenceBuild referenceJob: 'eclipse.jdt.core-github/master'
- junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml'
- recordIssues publishAllIssues: false, ignoreQualityGate: true, enabledForFailure: true, tools: [
- eclipse(name: 'Compiler', pattern: '**/target/compilelogs/*.xml'),
- issues(name: 'API Tools', id: 'apitools', pattern: '**/target/apianalysis/*.xml'),
- ], qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]]
- recordIssues tools: [javaDoc(), mavenConsole()]
+ junit 'org.eclipse.jdt.core.tests.javac/target/surefire-reports/*.xml'
+ discoverGitReferenceBuild referenceJob: 'jdt-core-incubator/dom-with-javac'
+ //recordIssues ignoreQualityGate:true, tool: junitParser(pattern: 'org.eclipse.jdt.core.tests.javac/target/surefire-reports/*.xml'), qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]]
}
}
}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
index d8b29bda305..505947f5529 100644
--- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
@@ -143,6 +143,7 @@ public interface ClassFileConstants {
int MAJOR_VERSION_24 = 68;
int MAJOR_VERSION_0 = 44;
+ // Latest version supported by ECJ (not necessarily latest known Java version)
int MAJOR_LATEST_VERSION = MAJOR_VERSION_24;
int MINOR_VERSION_0 = 0;
@@ -179,6 +180,10 @@ public interface ClassFileConstants {
long JDK23 = ((long)ClassFileConstants.MAJOR_VERSION_23 << 16) + ClassFileConstants.MINOR_VERSION_0;
long JDK24 = ((long)ClassFileConstants.MAJOR_VERSION_24 << 16) + ClassFileConstants.MINOR_VERSION_0;
+ /**
+ *
+ * @return The latest JDK level supported by ECJ (can be different from the latest known JDK level)
+ */
public static long getLatestJDKLevel() {
return ((long)ClassFileConstants.MAJOR_LATEST_VERSION << 16) + ClassFileConstants.MINOR_VERSION_0;
}
diff --git a/org.eclipse.jdt.core.javac.feature/feature.xml b/org.eclipse.jdt.core.javac.feature/feature.xml
new file mode 100644
index 00000000000..90c9f421c94
--- /dev/null
+++ b/org.eclipse.jdt.core.javac.feature/feature.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/org.eclipse.jdt.core.javac/.classpath b/org.eclipse.jdt.core.javac/.classpath
new file mode 100644
index 00000000000..d9ae1d43738
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/.classpath
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.jdt.core.javac/.project b/org.eclipse.jdt.core.javac/.project
new file mode 100644
index 00000000000..1b611ff9d02
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/.project
@@ -0,0 +1,28 @@
+
+
+ org.eclipse.jdt.core.javac
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/org.eclipse.jdt.core.javac/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jdt.core.javac/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000000..99f26c0203a
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/org.eclipse.jdt.core.javac/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.javac/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..2619ff190f0
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,524 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
+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.notowning=org.eclipse.jdt.annotation.NotOwning
+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.annotation.owning=org.eclipse.jdt.annotation.Owning
+org.eclipse.jdt.core.compiler.annotation.resourceanalysis=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=24
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=24
+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.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=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+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.incompatibleOwningContract=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.insufficientResourceAnalysis=warning
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+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.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+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=ignore
+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=ignore
+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=ignore
+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=ignore
+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=error
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+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.unusedLambdaParameter=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=disabled
+org.eclipse.jdt.core.compiler.source=24
+org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns=false
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=true
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant=49
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=49
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=49
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=49
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=49
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=0
+org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=49
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assertion_message=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon=16
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_record_components=16
+org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow=20
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_annotations=0
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case_after_arrow=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags=false
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_line_comments=false
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.text_block_indentation=0
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator=false
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/org.eclipse.jdt.core.javac/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jdt.core.javac/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..d87cd32d4ce
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,152 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
+formatter_settings_version=23
+sp_cleanup.add_all=false
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+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.also_simplify_lambda=true
+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.array_with_curly=false
+sp_cleanup.arrays_fill=false
+sp_cleanup.bitwise_conditional_expression=false
+sp_cleanup.boolean_literal=false
+sp_cleanup.boolean_value_rather_than_comparison=false
+sp_cleanup.break_loop=false
+sp_cleanup.collection_cloning=false
+sp_cleanup.comparing_on_criteria=false
+sp_cleanup.comparison_statement=false
+sp_cleanup.controlflow_merge=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.convert_to_enhanced_for_loop_if_loop_var_used=false
+sp_cleanup.convert_to_switch_expressions=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.do_while_rather_than_while=false
+sp_cleanup.double_negation=false
+sp_cleanup.else_if=false
+sp_cleanup.embedded_if=false
+sp_cleanup.evaluate_nullable=false
+sp_cleanup.extract_increment=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.hash=false
+sp_cleanup.if_condition=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.instanceof=false
+sp_cleanup.instanceof_keyword=false
+sp_cleanup.invert_equals=false
+sp_cleanup.join=false
+sp_cleanup.lazy_logical_operator=false
+sp_cleanup.make_local_variable_final=true
+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.map_cloning=false
+sp_cleanup.merge_conditional_blocks=false
+sp_cleanup.multi_catch=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.no_string_creation=false
+sp_cleanup.no_super=false
+sp_cleanup.number_suffix=false
+sp_cleanup.objects_equals=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false
+sp_cleanup.operand_factorization=false
+sp_cleanup.organize_imports=true
+sp_cleanup.overridden_assignment=false
+sp_cleanup.overridden_assignment_move_decl=true
+sp_cleanup.plain_replacement=false
+sp_cleanup.precompile_regex=false
+sp_cleanup.primitive_comparison=false
+sp_cleanup.primitive_parsing=false
+sp_cleanup.primitive_rather_than_wrapper=false
+sp_cleanup.primitive_serialization=false
+sp_cleanup.pull_out_if_from_if_else=false
+sp_cleanup.pull_up_assignment=false
+sp_cleanup.push_down_negation=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.reduce_indentation=false
+sp_cleanup.redundant_comparator=false
+sp_cleanup.redundant_falling_through_block_end=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_modifiers=false
+sp_cleanup.remove_redundant_semicolons=false
+sp_cleanup.remove_redundant_type_arguments=false
+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_array_creation=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unnecessary_suppress_warnings=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_method_parameters=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.replace_deprecated_calls=false
+sp_cleanup.return_expression=false
+sp_cleanup.simplify_boolean_if_else=false
+sp_cleanup.simplify_lambda_expression_and_method_ref=false
+sp_cleanup.single_used_field=false
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.standard_comparison=false
+sp_cleanup.static_inner_class=false
+sp_cleanup.strictly_equal_or_different=false
+sp_cleanup.stringbuffer_to_stringbuilder=false
+sp_cleanup.stringbuilder=false
+sp_cleanup.stringbuilder_for_local_vars=true
+sp_cleanup.stringconcat_stringbuffer_stringbuilder=false
+sp_cleanup.stringconcat_to_textblock=false
+sp_cleanup.substring=false
+sp_cleanup.switch=false
+sp_cleanup.switch_for_instanceof_pattern=false
+sp_cleanup.system_property=false
+sp_cleanup.system_property_boolean=false
+sp_cleanup.system_property_file_encoding=false
+sp_cleanup.system_property_file_separator=false
+sp_cleanup.system_property_javaspecversion=false
+sp_cleanup.system_property_javaversion=false
+sp_cleanup.system_property_line_separator=false
+sp_cleanup.system_property_path_separator=false
+sp_cleanup.ternary_operator=false
+sp_cleanup.try_with_resource=false
+sp_cleanup.unlooped_while=false
+sp_cleanup.unreachable_block=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_autoboxing=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_directly_map_method=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_string_is_blank=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
+sp_cleanup.use_unboxing=false
+sp_cleanup.use_var=false
+sp_cleanup.useless_continue=false
+sp_cleanup.useless_return=false
+sp_cleanup.valueof_rather_than_instantiation=false
diff --git a/org.eclipse.jdt.core.javac/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.javac/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..9dd73c62dee
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Javac backend for JDT Core
+Bundle-Vendor: Eclipse JDT-LS
+Bundle-SymbolicName: org.eclipse.jdt.core.javac;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Fragment-Host: org.eclipse.jdt.core
+Automatic-Module-Name: org.eclipse.jdt.core.javac
+Require-Capability: osgi.ee; filter:="(&(osgi.ee=JavaSE)(version=24))"
+Import-Package: org.eclipse.core.resources,
+ org.eclipse.jdt.core.dom
+Export-Package: org.eclipse.jdt.internal.javac;x-friends:="org.eclipse.jdt.core.tests.javac",
+ org.eclipse.jdt.internal.javac.dom;x-friends:="org.eclipse.jdt.core.tests.javac"
diff --git a/org.eclipse.jdt.core.javac/META-INF/p2.inf b/org.eclipse.jdt.core.javac/META-INF/p2.inf
new file mode 100644
index 00000000000..780ba9735b3
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/META-INF/p2.inf
@@ -0,0 +1,93 @@
+instructions.configure=org.eclipse.equinox.p2.touchpoint.eclipse.addJvmArg(jvmArg:\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets.snippet=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED\n\
+--add-opens\n\
+java.base/sun.nio.ch=ALL-UNNAMED\n\
+--add-opens\n\
+jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED\n\
+--add-opens\n\
+java.compiler/javax.tools=ALL-UNNAMED\n\
+-DICompilationUnitResolver=org.eclipse.jdt.core.dom.JavacCompilationUnitResolver\n\
+-DAbstractImageBuilder.compilerFactory=org.eclipse.jdt.internal.javac.JavacCompilerFactory\n\
+-DCompilationUnit.DOM_BASED_OPERATIONS=true\n\
+-DICompletionEngineProvider=org.eclipse.jdt.core.dom.DOMCompletionEngineProvider\n\
+-DSourceIndexer.DOM_BASED_INDEXER=true\n\
+-DMatchLocator.DOM_BASED_MATCH=true\n\
+-DIJavaSearchDelegate=org.eclipse.jdt.internal.core.search.DOMJavaSearchDelegate\n\
+-Xss16m\
+);
+
+# See https://github.com/eclipse-equinox/p2/issues/572 about requirement for multiple instructions
+instructions.unconfigure=\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets.snippet=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:java.base/sun.nio.ch=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:--add-opens);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:java.compiler/javax.tools=ALL-UNNAMED);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-DICompilationUnitResolver=org.eclipse.jdt.core.dom.JavacCompilationUnitResolver);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-DAbstractImageBuilder.compilerFactory=org.eclipse.jdt.internal.javac.JavacCompilerFactory);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-DCompilationUnit.DOM_BASED_OPERATIONS=true);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-DCompilationUnit.codeComplete.DOM_BASED_OPERATIONS=true_);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-DSourceIndexer.DOM_BASED_INDEXER=true);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-DMatchLocator.DOM_BASED_MATCH=true);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-DIJavaSearchDelegate=org.eclipse.jdt.internal.core.search.DOMJavaSearchDelegate);\
+org.eclipse.equinox.p2.touchpoint.eclipse.removeJvmArg(jvmArg:-Xss16m);\
diff --git a/org.eclipse.jdt.core.javac/README.md b/org.eclipse.jdt.core.javac/README.md
new file mode 100644
index 00000000000..216df184191
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/README.md
@@ -0,0 +1,77 @@
+# Eclipse JDT over Javac
+
+This fragment contains a Javac backend (instead of ECJ) for JDT features:
+* error reporting/reconciling
+* build/compilation
+* indexing
+* code selection (Ctrl + click / hover)
+* code completion (requires JDT fork bundle + opt-out flag)
+* search/match (requires JDT fork bundle + opt-out flag)
+
+## ❓ Why?
+
+Some background...
+* These days, with more frequent and more features Java releases, it's becoming hard for JDT to **cope with new Java features on time** and **facilitate support for upcoming/preview features before Java is released so JDT can participate to consolidation of the spec**. Over recent releases, JDT has failed at providing the features on time. This is mostly because of the difficulty of maintaining the Eclipse compiler: compilers are difficult bits of code to maintain and it takes a lot of time to implement things well in them. There is no clear sign the situation can improve here.
+* The Eclipse compiler has always suffered from occasional **inconsistencies with Javac** which end-users fail at understanding. Sometimes, ECJ is right, sometimes Javac is; but for end-users and for the ecosystem, Javac is the reference implementation and it's behavior is what they perceive as the actual specification
+* JDT has a very strong ecosystem (JDT-LS, plugins) a tons of nice features, so it seems profitable to **keep relying higher-level JDT APIs, such as model or DOM** to remain compatible with the ecosystem
+
+🎯 The technical proposal here mostly to **allow Javac to be used at the lowest-level of JDT**, under the hood, to populate higher-level models that are used in many operations; named the JDT DOM and IJavaElement models. It is expected that if we can create a good DOM and IJavaElement structure with another strategy (eg using Javac API), then all higher level operations will remain working as well without modification.
+
+## 📥 Install on top of existing JDT in your Eclipse IDE
+
+Assuming you have Eclipse IDE well configured, just click the following link 👇 https://mickaelistria.github.io/redirctToEclipseIDECloneCommand/redirectToMarketplace.html?entryId=6444683
+
+**OR**
+
+Using the _Help > Install New Software_ dialog and pointing to https://ci.eclipse.org/ls/job/jdt-core-incubator/job/dom-with-javac/lastSuccessfulBuild/artifact/repository/target/repository/ p2 repository,
+install the _Javac backend for JDT_ artifact. Installing it will also tweak your `eclipse.ini` file to add the relevant options.
+
+Note that some required feature switches are not yet available in upstream JDT (see above) and thus will still default to ECJ.
+
+## ⌨️ Development
+
+### ⌨️ Contribute
+
+From a PDE-able IDE using a target platform that is suitable for JDT development (usually default case).
+
+You'll need to import the code of `org.eclipse.jdt.core` and `org.eclipse.jdt.core.javac` from this branch in your Eclipse workspace; and create a Launch Configuration of type "Eclipse Application" which does include the `org.eclipse.jdt.core` bundle. Go to _Arguments_ tab of this launch configuration, and add the following content to the _VM arguments_ list:
+
+```
+-DCompilationUnit.DOM_BASED_OPERATIONS=true -DICompletionProvider=org.eclipse.jdt.core.dom.DOMCompletionProvider -DSourceIndexer.DOM_BASED_INDEXER=true -DICompilationUnitResolver=org.eclipse.jdt.core.dom.JavacCompilationUnitResolver -DAbstractImageBuilder.compilerFactory=org.eclipse.jdt.internal.javac.JavacCompilerFactory --add-opens jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED --add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED --add-opens java.compiler/javax.tools=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED
+```
+
+Those arguments are automatically added to your eclipse.ini file when installing with p2.
+
+* `CompilationUnit.DOM_BASED_OPERATIONS=true`/`CompilationUnit.codeComplete.DOM_BASED_OPERATIONS` / `SourceIndexer.DOM_BASED_INDEXER=true` system properties enables some operations to use build and DOM instead of ECJ Parser (so if DOM comes from Javac, ECJ parser is not involved at all)
+* `--add-opens ...` as visible in the `org.eclipse.jdt.core.javac/META-INF/p2.inf` file to allow to access internal API of the JVM, including Javac ones
+* `ICompilationUnitResolver=org.eclipse.jdt.core.dom.JavacCompilationUnitResolver` system property enables using Javac instead of ECJ to create JDT DOM AST.
+* `AbstractImageBuilder.compilerFactory=org.eclipse.jdt.internal.javac.JavacCompilerFactory` system property instruct the builder to use Javac instead of ECJ to generate the .class file during build.
+
+Those properties can be set separately, which can useful when developing one particular aspect of this proposal, which property to set depends on what you want to focus on.
+
+### 📈 Progress
+
+* Refactorings in upstream JDT got merged in order to allow alternative (non-ECJ strategies) for
+ * reconciling model/errors using DOM ✔DONE
+ * generating DOM from alternative parser ✔DONE
+ * codeSelect ✔DONE
+ * indexing ✔DONE
+ * completion ⌨️IN PROGRESS
+ * search/match ⌨️IN PROGRESS
+ * compiler ✔DONE
+* Javac backend for
+ * producing Javac AST & Symbols ✔DONE (incl. annotation processing)
+ * Javac->JDT AST conversion ✔DONE (incl. annotation processing)
+ * binding conversion ✔DONE
+ * JavacCompiler ✔DONE
+
+
+🤔 What are the potential concerns:
+* **Memory cost** of retaining Javac contexts needs to be evaluated (can we get rid of the context earlier? Can we share subparts of the concerns across multiple files in the project?...)
+* It seems hard to find reusable parts from the **CompletionEngine**, although many proposals shouldn't really depend on the parser (so should be reusable)
+
+
+😧 What are the confirmed concerns:
+* **Null analysis** and some other **static analysis** are coded deep in ECJ and cannot be used with Javac. A solution can be to leverage another analysis engine (eg SpotBugs, SonarQube) deal with those features.
+* At the moment, Javac cannot be configured to **generate .class despite CompilationError** in them like ECJ can do to allow updating the target application even when some code is not complete yet
+ * We may actually be capable of hacking something like this in Eclipse/Javac integration (although it would be best to provide this directly in Javac), but running a 1st attempt of compilation, collecting errors, and then alterating the working copy of the source passed to Javac in case of error. More or less `if (diagnostics.anyMatch(getKind() == "error") { removeBrokenAST(diagnostic); injectAST("throw new CompilationError(diagnostic.getMessage()")`.
diff --git a/org.eclipse.jdt.core.javac/build.properties b/org.eclipse.jdt.core.javac/build.properties
new file mode 100644
index 00000000000..e3023e14e99
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ fragment.xml
diff --git a/org.eclipse.jdt.core.javac/fragment.xml b/org.eclipse.jdt.core.javac/fragment.xml
new file mode 100644
index 00000000000..30fd3fca6df
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/fragment.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.jdt.core.javac/pom.xml b/org.eclipse.jdt.core.javac/pom.xml
new file mode 100644
index 00000000000..c15318f6db3
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/pom.xml
@@ -0,0 +1,64 @@
+
+
+
+ 4.0.0
+
+ eclipse.jdt.core
+ org.eclipse.jdt
+ 4.37.0-SNAPSHOT
+
+ org.eclipse.jdt.core.javac
+ 1.0.0-SNAPSHOT
+ eclipse-plugin
+
+
+
+
+ org.eclipse.tycho
+ tycho-compiler-plugin
+
+ false
+ javac
+
+ --add-exports
+ java.base/java.lang=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED
+ --add-exports
+ jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED
+ --add-exports
+ jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets.snippet=ALL-UNNAMED
+ --add-exports
+ jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.taglets=ALL-UNNAMED
+ --add-exports
+ java.base/sun.nio.ch=ALL-UNNAMED
+
+
+
+
+
+
diff --git a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/DOMCompletionEngineProvider.java b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/DOMCompletionEngineProvider.java
new file mode 100644
index 00000000000..4279ffd1f9c
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/DOMCompletionEngineProvider.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2025 Red Hat, Inc. and others.
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.jdt.core.dom;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.CompletionRequestor;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.internal.codeassist.DOMCompletionEngine;
+import org.eclipse.jdt.internal.codeassist.ICompletionEngine;
+import org.eclipse.jdt.internal.codeassist.ICompletionEngineProvider;
+import org.eclipse.jdt.internal.core.SearchableEnvironment;
+
+public class DOMCompletionEngineProvider implements ICompletionEngineProvider {
+
+ @Override
+ public ICompletionEngine newCompletionEngine(SearchableEnvironment nameEnvironment, CompletionRequestor requestor,
+ Map settings, IJavaProject javaProject, WorkingCopyOwner owner, IProgressMonitor monitor) {
+ return new DOMCompletionEngine(nameEnvironment, requestor, settings, javaProject, owner, monitor);
+ }
+
+}
diff --git a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/GenericRecoveredTypeBinding.java b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/GenericRecoveredTypeBinding.java
new file mode 100644
index 00000000000..4ca30db827e
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/GenericRecoveredTypeBinding.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Red Hat, Inc. and others.
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.jdt.core.dom;
+
+public class GenericRecoveredTypeBinding extends RecoveredTypeBinding {
+
+ private ITypeBinding from;
+
+ public GenericRecoveredTypeBinding(BindingResolver resolver, Type type, ITypeBinding from) {
+ super(resolver, type);
+ this.from = from;
+ }
+
+ @Override
+ public boolean isParameterizedType() {
+ return false;
+ }
+
+ @Override
+ public boolean isGenericType() {
+ return super.isParameterizedType();
+ }
+
+ @Override
+ public ITypeBinding[] getTypeParameters() {
+ return TypeBinding.NO_TYPE_BINDINGS;
+ }
+
+ @Override
+ public ITypeBinding[] getTypeArguments() {
+ return super.getTypeParameters();
+ }
+
+ @Override
+ public IPackageBinding getPackage() {
+ return this.from.getPackage();
+ }
+
+}
diff --git a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java
new file mode 100644
index 00000000000..99db489fb54
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java
@@ -0,0 +1,2017 @@
+/*******************************************************************************
+ * Copyright (c) 2023,2025 Red Hat, Inc. and others.
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.jdt.core.dom;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeKind;
+
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.internal.javac.dom.JavacAnnotationBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacErrorMethodBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacErrorTypeBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacLambdaBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacMemberValuePairBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacMethodBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacModuleBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacPackageBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacTypeBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacTypeVariableBinding;
+import org.eclipse.jdt.internal.javac.dom.JavacVariableBinding;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.DocTreePath;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTrees;
+import com.sun.tools.javac.code.Attribute;
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.ClassFinder;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.CompletionFailure;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.ModuleSymbol;
+import com.sun.tools.javac.code.Symbol.PackageSymbol;
+import com.sun.tools.javac.code.Symbol.RootPackageSymbol;
+import com.sun.tools.javac.code.Symbol.TypeSymbol;
+import com.sun.tools.javac.code.Symbol.TypeVariableSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type.ArrayType;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.ErrorType;
+import com.sun.tools.javac.code.Type.ForAll;
+import com.sun.tools.javac.code.Type.JCNoType;
+import com.sun.tools.javac.code.Type.JCPrimitiveType;
+import com.sun.tools.javac.code.Type.JCVoidType;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.Type.ModuleType;
+import com.sun.tools.javac.code.Type.PackageType;
+import com.sun.tools.javac.code.Type.TypeVar;
+import com.sun.tools.javac.code.TypeTag;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.Modules;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCAnnotatedType;
+import com.sun.tools.javac.tree.JCTree.JCAnnotation;
+import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
+import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCLambda;
+import com.sun.tools.javac.tree.JCTree.JCLiteral;
+import com.sun.tools.javac.tree.JCTree.JCMemberReference;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
+import com.sun.tools.javac.tree.JCTree.JCNewArray;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
+import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
+import com.sun.tools.javac.tree.JCTree.JCTypeApply;
+import com.sun.tools.javac.tree.JCTree.JCTypeCast;
+import com.sun.tools.javac.tree.JCTree.JCTypeIntersection;
+import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
+import com.sun.tools.javac.tree.JCTree.JCTypeUnion;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.JCWildcard;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Names;
+
+/**
+ * Deals with creation of binding model, using the Symbols from Javac.
+ * @implNote Cannot move to another package because parent class is package visible only
+ */
+public class JavacBindingResolver extends BindingResolver {
+
+ private JavacTask javacTask; // TODO evaluate memory cost of storing the instance
+ // it will probably be better to run the `Enter` and then only extract interesting
+ // date from it.
+ public final Context context;
+ public Map symbolToDeclaration;
+ public final IJavaProject javaProject;
+ private JavacConverter converter;
+ boolean isRecoveringBindings = false;
+
+ public static class BindingKeyException extends Exception {
+ private static final long serialVersionUID = -4468681148041117634L;
+ public BindingKeyException(Throwable t) {
+ super(t);
+ }
+ public BindingKeyException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ public class Bindings {
+ private Map annotationBindings = new HashMap<>();
+ public JavacAnnotationBinding getAnnotationBinding(Compound ann, IBinding recipient) {
+ JavacAnnotationBinding newInstance = new JavacAnnotationBinding(ann, JavacBindingResolver.this, recipient) { };
+ annotationBindings.putIfAbsent(newInstance, newInstance);
+ return annotationBindings.get(newInstance);
+ }
+ //
+ private Map memberValuePairBindings = new HashMap<>();
+ public JavacMemberValuePairBinding getMemberValuePairBinding(MethodSymbol key, Attribute value) {
+ JavacMemberValuePairBinding newInstance = new JavacMemberValuePairBinding(key, value, JavacBindingResolver.this) { };
+ memberValuePairBindings.putIfAbsent(newInstance, newInstance);
+ return memberValuePairBindings.get(newInstance);
+ }
+ public JavacMemberValuePairBinding getDefaultMemberValuePairBinding(IMethodBinding defaultAnnotationMethod) {
+ if (!defaultAnnotationMethod.isAnnotationMember()) {
+ return null;
+ }
+ JavacMemberValuePairBinding newInstance = new JavacMemberValuePairBinding(defaultAnnotationMethod, JavacBindingResolver.this) { };
+ memberValuePairBindings.putIfAbsent(newInstance, newInstance);
+ return memberValuePairBindings.get(newInstance);
+ }
+ //
+ private Map methodBindings = new HashMap<>();
+ public JavacMethodBinding getMethodBinding(MethodType methodType, MethodSymbol sym,
+ com.sun.tools.javac.code.Type type,
+ boolean isSynthetic, boolean isDeclaration,
+ List typeArgs) {
+ if( isSynthetic ) {
+ return getSyntheticMethodBinding(methodType, sym, type, typeArgs);
+ } else {
+ return getMethodBinding(methodType, sym, type, isDeclaration, typeArgs);
+ }
+ }
+
+ public JavacMethodBinding getMethodBinding(MethodType methodType, MethodSymbol methodSymbol,
+ com.sun.tools.javac.code.Type parentType, boolean isDeclaration,
+ List resolvedTypeArgs) {
+ JavacMethodBinding newInstance = new JavacMethodBinding(methodType, methodSymbol, parentType, JavacBindingResolver.this, false, isDeclaration, resolvedTypeArgs) { };
+ return insertAndReturn(newInstance);
+ }
+ public JavacMethodBinding getSyntheticMethodBinding(MethodType methodType, MethodSymbol methodSymbol,
+ com.sun.tools.javac.code.Type parentType, List resolvedTypeArgs) {
+ JavacMethodBinding newInstance = new JavacMethodBinding(methodType, methodSymbol, parentType, JavacBindingResolver.this, true, false, resolvedTypeArgs) { };
+ return insertAndReturn(newInstance);
+ }
+ public JavacMethodBinding getErrorMethodBinding(MethodType methodType, Symbol originatingSymbol, List typeArgs) {
+ JavacMethodBinding newInstance = new JavacErrorMethodBinding(originatingSymbol, methodType, JavacBindingResolver.this) { };
+ return insertAndReturn(newInstance);
+ }
+ private JavacMethodBinding insertAndReturn(JavacMethodBinding newInstance) {
+ methodBindings.putIfAbsent(newInstance, newInstance);
+ return methodBindings.get(newInstance);
+ }
+ //
+ private Map moduleBindings = new HashMap<>();
+ public JavacModuleBinding getModuleBinding(ModuleType moduleType) {
+ JavacModuleBinding newInstance = new JavacModuleBinding(moduleType, JavacBindingResolver.this) { };
+ moduleBindings.putIfAbsent(newInstance, newInstance);
+ return moduleBindings.get(newInstance);
+ }
+ public JavacModuleBinding getModuleBinding(ModuleSymbol moduleSymbol) {
+ JavacModuleBinding newInstance = new JavacModuleBinding(moduleSymbol, JavacBindingResolver.this) { };
+ moduleBindings.putIfAbsent(newInstance, newInstance);
+ return moduleBindings.get(newInstance);
+ }
+ public JavacModuleBinding getModuleBinding(JCModuleDecl moduleDecl) {
+ JavacModuleBinding newInstance = new JavacModuleBinding(moduleDecl, JavacBindingResolver.this) { };
+ // Overwrite existing
+ moduleBindings.put(newInstance, newInstance);
+ return moduleBindings.get(newInstance);
+ }
+
+ //
+ private Map packageBindings = new HashMap<>();
+ public JavacPackageBinding getPackageBinding(PackageSymbol packageSymbol) {
+ if (!packageSymbol.exists()) {
+ return null;
+ }
+ if( packageSymbol.owner instanceof PackageSymbol parentPack) {
+ if( !(parentPack instanceof RootPackageSymbol) )
+ getPackageBinding(parentPack);
+ }
+ JavacPackageBinding newInstance = new JavacPackageBinding(packageSymbol, JavacBindingResolver.this) { };
+ return preferentiallyInsertPackageBinding(newInstance);
+ }
+ public JavacPackageBinding getPackageBinding(Name name) {
+ String n = packageNameToString(name);
+ if( n == null )
+ return null;
+ JavacPackageBinding newInstance = new JavacPackageBinding(n, JavacBindingResolver.this) {};
+ return preferentiallyInsertPackageBinding(newInstance);
+ }
+
+ public JavacPackageBinding findExistingPackageBinding(Name name) {
+ String n = name == null ? null : name.toString();
+ if( n == null )
+ return null;
+ JavacPackageBinding newInstance = new JavacPackageBinding(n, JavacBindingResolver.this) {};
+ String k = newInstance == null ? null : newInstance.getKey();
+ if( k != null ) {
+ JavacPackageBinding current = packageBindings.get(k);
+ return current;
+ }
+ return null;
+ }
+
+ private String packageNameToString(Name name) {
+ String n = null;
+ if( name instanceof QualifiedName )
+ n = name.toString();
+ else if( name instanceof SimpleName) {
+ if( name.getParent() instanceof QualifiedName qn) {
+ if( qn.getName() == name ) {
+ n = qn.toString();
+ } else if( qn.getQualifier() == name) {
+ n = name.toString();
+ }
+ }
+ }
+ return n;
+ }
+
+ private JavacPackageBinding preferentiallyInsertPackageBinding(JavacPackageBinding newest) {
+ // A package binding may be created while traversing something as simple as a name.
+ // The binding using name-only logic should be instantiated, but
+ // when a proper symbol is found, it should be added to that object.
+ if( newest != null ) {
+ JavacPackageBinding current = packageBindings.get(newest);
+ if( current == null ) {
+ packageBindings.putIfAbsent(newest, newest);
+ } else if( current.getPackageSymbol() == null && newest.getPackageSymbol() != null) {
+ current.setPackageSymbol(newest.getPackageSymbol());
+ }
+ return packageBindings.get(newest);
+ }
+ return null;
+ }
+ //
+ private Map typeBinding = new HashMap<>();
+ public JavacTypeBinding getTypeBinding(JCTree tree, com.sun.tools.javac.code.Type type) {
+ return getTypeBinding(type, tree instanceof JCClassDecl);
+ }
+
+ public JavacTypeBinding getTypeBinding(com.sun.tools.javac.code.Type type) {
+ if (type == null) {
+ return null;
+ }
+
+ boolean likelyGeneric = false;
+// if( type instanceof ClassType ct && ct.isParameterized()) {
+// List typeArgs = ct.getTypeArguments();
+// int size = typeArgs.size();
+// for( int i = 0; i < size && !likelyGeneric; i++ ) {
+// if( typeArgs.get(i) instanceof TypeVar) {
+// likelyGeneric = true;
+// }
+// }
+// }
+//
+ return getTypeBinding(type.baseType() /* remove metadata for constant values */, likelyGeneric);
+ }
+ public JavacTypeBinding getTypeBinding(com.sun.tools.javac.code.Type type, boolean isGeneric) {
+ return getTypeBinding(type, null, isGeneric);
+ }
+ public JavacTypeBinding getTypeBinding(com.sun.tools.javac.code.Type type, com.sun.tools.javac.code.Type[] alternatives, boolean isGeneric) {
+ if (type instanceof com.sun.tools.javac.code.Type.TypeVar typeVar) {
+ return getTypeVariableBinding(typeVar);
+ }
+ if (type == null || type == com.sun.tools.javac.code.Type.noType) {
+ return null;
+ }
+ if (type instanceof ErrorType errorType) {
+ var originalType = errorType.getOriginalType();
+ if (originalType != com.sun.tools.javac.code.Type.noType
+ && !(originalType instanceof com.sun.tools.javac.code.Type.MethodType)
+ && !(originalType instanceof com.sun.tools.javac.code.Type.ForAll)
+ && !(originalType instanceof com.sun.tools.javac.code.Type.ErrorType)) {
+ JavacTypeBinding newInstance = new JavacTypeBinding(originalType, type.tsym, alternatives, isGeneric, JavacBindingResolver.this) { };
+ typeBinding.putIfAbsent(newInstance, newInstance);
+ JavacTypeBinding jcb = typeBinding.get(newInstance);
+ jcb.setRecovered(true);
+ return jcb;
+ } else if (errorType.tsym instanceof ClassSymbol classErrorSymbol &&
+ Character.isJavaIdentifierStart(classErrorSymbol.getSimpleName().charAt(0))) {
+ // non usable original type: try symbol
+ JavacTypeBinding newInstance = new JavacTypeBinding(classErrorSymbol.type, classErrorSymbol, alternatives, isGeneric, JavacBindingResolver.this) { };
+ typeBinding.putIfAbsent(newInstance, newInstance);
+ JavacTypeBinding jcb = typeBinding.get(newInstance);
+ jcb.setRecovered(true);
+ return jcb;
+ }
+ // no type information we could recover from
+ return null;
+ }
+ if (!(type.tsym instanceof ClassSymbol sym && sym.classfile == null && sym.sourcefile == null)
+ && !type.isParameterized() && !type.isRaw() && type instanceof ClassType classType
+ && classType.interfaces_field == null) {
+ // workaround faulty case of TypeMismatchQuickfixText.testMismatchingReturnTypeOnGenericMethod
+ // interfaces/supertypes are not set which seem to imply that the compiler generated
+ // a dummy type object that's not suitable for a binding.
+ // Fail back to an hopefully better type
+ type = type.tsym.type;
+ }
+ JavacTypeBinding newInstance = new JavacTypeBinding(type, type.tsym, alternatives, isGeneric, JavacBindingResolver.this) { };
+ typeBinding.putIfAbsent(newInstance, newInstance);
+ return typeBinding.get(newInstance);
+ }
+ //
+ private Map typeVariableBindings = new HashMap<>();
+ public JavacTypeVariableBinding getTypeVariableBinding(TypeVar typeVar) {
+ JavacTypeVariableBinding newInstance = new JavacTypeVariableBinding(typeVar, (TypeVariableSymbol)typeVar.tsym, JavacBindingResolver.this) { };
+ typeVariableBindings.putIfAbsent(newInstance, newInstance);
+ return typeVariableBindings.get(newInstance);
+ }
+ //
+ private Map variableBindings = new HashMap<>();
+ public JavacVariableBinding getVariableBinding(VarSymbol varSymbol) {
+ if (varSymbol == null) {
+ return null;
+ }
+ JavacVariableBinding newInstance = new JavacVariableBinding(varSymbol, JavacBindingResolver.this) { };
+ variableBindings.putIfAbsent(newInstance, newInstance);
+ return variableBindings.get(newInstance);
+ }
+ //
+ private Map lambdaBindings = new HashMap<>();
+ public JavacLambdaBinding getLambdaBinding(JavacMethodBinding javacMethodBinding, LambdaExpression lambda) {
+ JavacLambdaBinding newInstance = new JavacLambdaBinding(javacMethodBinding, lambda);
+ lambdaBindings.putIfAbsent(newInstance, newInstance);
+ return lambdaBindings.get(newInstance);
+ }
+
+ public IBinding getBinding(final Symbol owner, final com.sun.tools.javac.code.Type type) {
+ Symbol recoveredSymbol = getRecoveredSymbol(type);
+ if (recoveredSymbol != null) {
+ return getBinding(recoveredSymbol, recoveredSymbol.type);
+ }
+ if (type != null && (type instanceof ErrorType || owner == null || owner.owner == null || owner.owner.type == com.sun.tools.javac.code.Type.noType)) {
+ if (type.getOriginalType() instanceof MethodType missingMethodType) {
+ return getErrorMethodBinding(missingMethodType, owner, null);
+ }
+ }
+ if (owner instanceof final PackageSymbol other) {
+ return getPackageBinding(other);
+ } else if (owner instanceof ModuleSymbol typeSymbol) {
+ return getModuleBinding(typeSymbol);
+ } else if (owner instanceof Symbol.TypeVariableSymbol typeVariableSymbol) {
+ if (type instanceof TypeVar typeVar) {
+ return getTypeVariableBinding(typeVar);
+ } else if (typeVariableSymbol.type instanceof TypeVar typeVar) {
+ return getTypeVariableBinding(typeVar);
+ }
+ // without the type there is not much we can do; fallthrough to null
+ } else if (owner instanceof TypeSymbol typeSymbol) {
+ return getTypeBinding(isTypeOfType(type) ? type : typeSymbol.type);
+ } else if (owner instanceof final MethodSymbol other) {
+ var methodType = type instanceof com.sun.tools.javac.code.Type.MethodType aMethodType ? aMethodType :
+ owner.type != null ? owner.type.asMethodType() :
+ null;
+ if (methodType != null) {
+ return getMethodBinding(methodType, other, null, false, null);
+ }
+ } else if (owner instanceof final VarSymbol other) {
+ return getVariableBinding(other);
+ }
+ return null;
+ }
+ public IBinding getBinding(String key) {
+ IBinding binding;
+ binding = this.annotationBindings.get(key);
+ if (binding != null) {
+ return binding;
+ }
+ binding = this.memberValuePairBindings.get(key);
+ if (binding != null) {
+ return binding;
+ }
+ binding = this.methodBindings.values()
+ .stream()
+ .filter(methodBindings -> key.equals(methodBindings.getKey()))
+ .findAny()
+ .orElse(null);
+ if (binding != null) {
+ return binding;
+ }
+ binding = this.moduleBindings.get(key);
+ if (binding != null) {
+ return binding;
+ }
+ binding = this.packageBindings.get(key);
+ if (binding != null) {
+ return binding;
+ }
+ binding = new ArrayList<>(this.typeBinding.values())
+ .stream()
+ .filter(typeBinding -> key.equals(typeBinding.getKey()))
+ .findAny()
+ .orElse(null);
+ if (binding != null) {
+ return binding;
+ }
+ return this.variableBindings.get(key);
+ }
+ }
+ public final Bindings bindings = new Bindings();
+ private WorkingCopyOwner owner;
+ private HashMap resolvedBindingsCache = new HashMap<>();
+ private List javacCompilationUnits;
+
+ public JavacBindingResolver(IJavaProject javaProject, JavacTask javacTask, Context context, JavacConverter converter, WorkingCopyOwner owner, List javacCompilationUnits) {
+ this.javacTask = javacTask;
+ this.context = context;
+ this.javaProject = javaProject;
+ this.converter = converter;
+ this.owner = owner;
+ this.javacCompilationUnits = javacCompilationUnits;
+ }
+
+ private void resolve() {
+ if (this.symbolToDeclaration != null) {
+ // already done and ready
+ return;
+ }
+ final JavacTask tmpTask = this.javacTask;
+ if( tmpTask == null ) {
+ return;
+ }
+ synchronized (tmpTask) { // prevents from multiple `analyze` for the same task
+ if( this.javacTask == null ) {
+ return;
+ }
+ boolean alreadyAnalyzed = this.converter.domToJavac.values().stream().map(TreeInfo::symbolFor).anyMatch(Objects::nonNull);
+ if (!alreadyAnalyzed) {
+ // symbols not already present: analyze
+ try {
+ Iterable extends Element> elements;
+ // long start = System.currentTimeMillis();
+ if (this.javacTask instanceof JavacTaskImpl javacTaskImpl) {
+ if (javacCompilationUnits != null && !javacCompilationUnits.isEmpty()) {
+ Iterable extends CompilationUnitTree> trees = javacCompilationUnits;
+ elements = javacTaskImpl.enter(trees);
+ } else {
+ elements = javacTaskImpl.enter();
+ }
+ elements = javacTaskImpl.analyze(elements);
+// long count = StreamSupport.stream(elements.spliterator(), false).count();
+// String name = elements.iterator().hasNext()
+// ? elements.iterator().next().getSimpleName().toString()
+// : "";
+// ILog.get().info("enter/analyze elements=" + count + ", took: "
+// + (System.currentTimeMillis() - start) + ", first=" + name);
+ } else {
+ elements = this.javacTask.analyze();
+// long count = StreamSupport.stream(elements.spliterator(), false).count();
+// String name = elements.iterator().hasNext()
+// ? elements.iterator().next().getSimpleName().toString()
+// : "";
+// ILog.get().info("analyze elements=" + count + ", took: " + (System.currentTimeMillis() - start)
+// + ", first=" + name);
+ }
+ } catch (IOException | Error | RuntimeException e) {
+ ILog.get().error(e.getMessage(), e);
+ }
+ }
+ // some cleanups to encourage garbage collection
+ JavacCompilationUnitResolver.cleanup(context);
+ }
+ this.javacTask = null;
+ synchronized (this) {
+ if (this.symbolToDeclaration == null) {
+ Map wipSymbolToDeclaration = new HashMap<>();
+ this.converter.domToJavac.forEach((jdt, javac) -> {
+ // We don't want FieldDeclaration (ref ASTConverterTest2.test0433)
+ if (jdt instanceof MethodDeclaration ||
+ jdt instanceof VariableDeclaration ||
+ jdt instanceof EnumConstantDeclaration ||
+ jdt instanceof AnnotationTypeMemberDeclaration ||
+ jdt instanceof AbstractTypeDeclaration ||
+ jdt instanceof AnonymousClassDeclaration ||
+ jdt instanceof TypeParameter) {
+ var symbol = TreeInfo.symbolFor(javac);
+ if (symbol != null) {
+ wipSymbolToDeclaration.put(symbol, jdt);
+ }
+ }
+ });
+ // prefill the binding so that they're already searchable by key
+ wipSymbolToDeclaration.keySet().forEach(sym -> this.bindings.getBinding(sym, null));
+ this.symbolToDeclaration = wipSymbolToDeclaration;
+ }
+ }
+ }
+
+ @Override
+ public ASTNode findDeclaringNode(IBinding binding) {
+ return findNode(getJavacSymbol(binding));
+ }
+
+ public IBinding findBinding(String bindingKey) {
+ return this.bindings.getBinding(bindingKey);
+ }
+
+ private void compoundListWithAction(HashSet list, Function f) {
+ Iterator it = new ArrayList(list).iterator();
+ while(it.hasNext()) {
+ String transformed = f.apply(it.next());
+ if( transformed != null && !list.contains(transformed)) {
+ list.add(transformed);
+ }
+ }
+ }
+
+ public IBinding findUnresolvedBinding(String bindingKey) {
+ boolean isUnresolved = bindingKey.startsWith("Q") || bindingKey.startsWith("+Q") || bindingKey.startsWith("-Q");
+ if( !isUnresolved) {
+ return findBinding(bindingKey);
+ }
+
+ final boolean bkExtends = bindingKey.startsWith("+");
+ final boolean bkSuper = bindingKey.startsWith("-");
+
+ String withoutSuperExtends = bindingKey.startsWith("+") || bindingKey.startsWith("-") ? bindingKey.substring(1) : bindingKey;
+
+ HashSet validNames = new HashSet();
+ validNames.add(bindingKey);
+ compoundListWithAction(validNames, x -> x.replaceAll("\\.", "/"));
+ compoundListWithAction(validNames, x -> x.endsWith(";") ? x.substring(0, x.length() - 1) : null);
+ compoundListWithAction(validNames, x -> x.startsWith("+") || x.startsWith("-") ? x.substring(1) : null);
+ compoundListWithAction(validNames, x -> x.lastIndexOf(".", x.length() - 1) != -1 ? x.substring(x.lastIndexOf(".") + 1) : null);
+ compoundListWithAction(validNames, x -> x.startsWith("Q") ? x.substring(1) : null);
+ compoundListWithAction(validNames, x -> x.contains(" x.startsWith("+Q") ? x.replaceAll("\\+Q", "? extends ") : null);
+ compoundListWithAction(validNames, x -> x.startsWith("-Q") ? x.replaceAll("-Q", "? super ") : null);
+ String bindingKeySimpleName = Signature.getSignatureSimpleName(withoutSuperExtends);
+ validNames.add(bindingKeySimpleName);
+
+ Collection c = new ArrayList<>(this.bindings.typeBinding.values());
+ int matchesKey = 0x80;
+ int matchesSimpleName = 0x40;
+ int matchesSuperExtends = 0x10;
+ record Pair(JavacTypeBinding binding, int weight) {};
+ List collector = new ArrayList();
+
+ c.stream().forEach(x -> {
+ int total = 0;
+ String k = x.getKey();
+ if( validNames.contains(k))
+ total += matchesKey;
+ String n = x.getName();
+ if( validNames.contains(n)) {
+ total += matchesSimpleName;
+ }
+ if( bkExtends || bkSuper ) {
+ if( x.isWildcardType() && x.getBound() != null ) {
+ if( bkExtends && x.isUpperbound()) {
+ total += matchesSuperExtends;
+ } else if( bkSuper && !x.isUpperbound() ) {
+ total += matchesSuperExtends;
+ }
+ }
+ }
+ if( total > 0 )
+ collector.add(new Pair(x, total));
+ });
+
+ Collections.sort(collector, (o1, o2) -> o2.weight - o1.weight);
+ return collector.size() > 0 ? collector.get(0).binding : null;
+ }
+
+ @Override
+ public ASTNode findDeclaringNode(String bindingKey) {
+ resolve();
+ IBinding binding = this.bindings.getBinding(bindingKey);
+ if (binding == null) {
+ return null;
+ }
+ return findDeclaringNode(binding);
+ }
+
+ private Symbol getJavacSymbol(IBinding binding) {
+ if (binding instanceof JavacMemberValuePairBinding valuePair) {
+ return getJavacSymbol(valuePair.method);
+ }
+ if (binding instanceof JavacAnnotationBinding annotation) {
+ return getJavacSymbol(annotation.getAnnotationType());
+ }
+ if (binding instanceof JavacMethodBinding method) {
+ return method.methodSymbol;
+ }
+ if (binding instanceof JavacPackageBinding packageBinding) {
+ return packageBinding.getPackageSymbol();
+ }
+ if (binding instanceof JavacTypeBinding type) {
+ return type.typeSymbol;
+ }
+ if (binding instanceof JavacVariableBinding variable) {
+ return variable.variableSymbol;
+ }
+ return null;
+ }
+
+ public ASTNode findNode(Symbol symbol) {
+ if (this.symbolToDeclaration != null) {
+ return this.symbolToDeclaration.get(symbol);
+ }
+ return null;
+ }
+
+ @Override
+ public ITypeBinding resolveType(Type type) {
+ if (type.getParent() instanceof ParameterizedType parameterized
+ && type.getLocationInParent() == ParameterizedType.TYPE_PROPERTY) {
+ // use parent type for this as it keeps generics info
+ return resolveType(parameterized);
+ }
+ resolve();
+ if (type.getParent() instanceof ArrayCreation arrayCreation) {
+ JCTree jcArrayCreation = this.converter.domToJavac.get(arrayCreation);
+ return this.bindings.getTypeBinding(((JCNewArray)jcArrayCreation).type);
+ }
+ JCTree jcTree = this.converter.domToJavac.get(type);
+ if (jcTree instanceof JCIdent ident && ident.type != null) {
+ if (ident.type instanceof PackageType) {
+ return null;
+ }
+ return this.bindings.getTypeBinding(ident.type);
+ }
+ if (jcTree instanceof JCFieldAccess access) {
+ IBinding b = this.getFieldAccessBinding(access);
+ return b instanceof ITypeBinding tb ? tb : null;
+ }
+ if (jcTree instanceof JCPrimitiveTypeTree primitive && primitive.type != null) {
+ return this.bindings.getTypeBinding(primitive.type);
+ }
+ if (jcTree instanceof JCArrayTypeTree arrayType && arrayType.type != null) {
+ return this.bindings.getTypeBinding(arrayType.type);
+ }
+ if (jcTree instanceof JCWildcard wcType && wcType.type != null) {
+ return this.bindings.getTypeBinding(wcType.type);
+ }
+ if (jcTree instanceof JCTypeApply jcta && jcta.type != null) {
+ var res = this.bindings.getTypeBinding(jcta.type);
+ if (res != null) {
+ return res;
+ }
+ if (jcta.getType().type instanceof ErrorType errorType) {
+ res = this.bindings.getTypeBinding(errorType.getOriginalType(), true);
+ if (res != null) {
+ return res;
+ }
+ }
+ if (jcta.getType().type != null) {
+ res = this.bindings.getTypeBinding(jcta.getType().type);
+ if (res != null) {
+ return res;
+ }
+ }
+ }
+ if (jcTree instanceof JCAnnotatedType annotated && annotated.type != null) {
+ return this.bindings.getTypeBinding(annotated.type);
+ }
+ if (jcTree instanceof JCTypeUnion unionType) {
+ com.sun.tools.javac.code.Type[] alternativesArray = new com.sun.tools.javac.code.Type[unionType.alternatives.size()];
+ for (int i = 0 ; i < alternativesArray.length; i++) {
+ alternativesArray[i] = unionType.alternatives.get(i).type;
+ }
+ return this.bindings.getTypeBinding(unionType.type, alternativesArray, false);
+ }
+ if (jcTree instanceof JCTypeIntersection intersectionType) {
+ com.sun.tools.javac.code.Type[] alternativesArray = new com.sun.tools.javac.code.Type[intersectionType.bounds.size()];
+ for (int i = 0 ; i < alternativesArray.length; i++) {
+ alternativesArray[i] = intersectionType.bounds.get(i).type;
+ }
+ return this.bindings.getTypeBinding(intersectionType.type, alternativesArray, false);
+ }
+
+// return this.flowResult.stream().map(env -> env.enclClass)
+// .filter(Objects::nonNull)
+// .map(decl -> decl.type)
+// .map(javacType -> javacType.tsym)
+// .filter(sym -> Objects.equals(type.toString(), sym.name.toString()))
+// .findFirst()
+// .map(symbol -> new JavacTypeBinding(symbol, this))
+// .orElse(null);
+// }
+// if (type instanceof QualifiedType qualifiedType) {
+// JCTree jcTree = this.converter.domToJavac.get(qualifiedType);
+// }
+ if (type instanceof PrimitiveType primitive) { // a type can be requested even if there is no token for it in JCTree
+ return resolveWellKnownType(primitive.getPrimitiveTypeCode().toString());
+ }
+ if (type.getAST().apiLevel() >= AST.JLS10 && type.isVar()) {
+ if (type.getParent() instanceof VariableDeclaration varDecl) {
+ IVariableBinding varBinding = resolveVariable(varDecl);
+ if (varBinding != null) {
+ return varBinding.getType();
+ }
+ }
+ if (type.getParent() instanceof VariableDeclarationStatement statement &&
+ this.converter.domToJavac.get(statement) instanceof JCVariableDecl jcDecl &&
+ jcDecl.type != null) {
+ return this.bindings.getTypeBinding(jcDecl.type);
+ }
+ }
+ // Recovery: sometime with Javac, there is no suitable type/symbol
+ // Workaround: use a RecoveredTypeBinding
+ // Caveats: cascade to other workarounds
+ return createRecoveredTypeBinding(type);
+ }
+
+ private RecoveredTypeBinding createRecoveredTypeBinding(Type type) {
+ return new RecoveredTypeBinding(this, type) {
+ @Override
+ public ITypeBinding getTypeDeclaration() {
+ if (isParameterizedType()) {
+ return new GenericRecoveredTypeBinding(JavacBindingResolver.this, type, this);
+ }
+ return super.getTypeDeclaration();
+ }
+ @Override
+ public IPackageBinding getPackage() {
+ if (type instanceof SimpleType simpleType && simpleType.getName() instanceof SimpleName) {
+ return JavacBindingResolver.this.converter.domToJavac
+ .values()
+ .stream()
+ .filter(CompilationUnit.class::isInstance)
+ .map(CompilationUnit.class::cast)
+ .map(CompilationUnit::getPackage)
+ .map(PackageDeclaration::resolveBinding)
+ .findAny()
+ .orElse(bindings.getPackageBinding(Symtab.instance(context).rootPackage));
+ }
+ return bindings.getPackageBinding(Symtab.instance(context).rootPackage);
+ }
+ };
+ }
+
+ @Override
+ ITypeBinding resolveType(AnnotationTypeDeclaration type) {
+ resolve();
+ JCTree javacNode = this.converter.domToJavac.get(type);
+ if (javacNode instanceof JCClassDecl jcClassDecl && jcClassDecl.type != null) {
+ return this.bindings.getTypeBinding(jcClassDecl.type);
+ }
+ return null;
+ }
+
+ @Override
+ ITypeBinding resolveType(RecordDeclaration type) {
+ resolve();
+ JCTree javacNode = this.converter.domToJavac.get(type);
+ if (javacNode instanceof JCClassDecl jcClassDecl && jcClassDecl.type != null) {
+ return this.bindings.getTypeBinding(jcClassDecl.type);
+ }
+ return null;
+ }
+
+
+ @Override
+ ITypeBinding resolveType(TypeDeclaration type) {
+ resolve();
+ JCTree javacNode = this.converter.domToJavac.get(type);
+ if (javacNode instanceof JCClassDecl jcClassDecl && (javacNode.type != null && "".equals(javacNode.type.toString()))) {
+ return new JavacErrorTypeBinding(javacNode.type, javacNode.type.tsym, null, true, JavacBindingResolver.this, jcClassDecl.sym);
+ }
+ if (javacNode instanceof JCClassDecl jcClassDecl && jcClassDecl.type != null) {
+ return this.bindings.getTypeBinding(jcClassDecl.type, true);
+ }
+ if (javacNode instanceof JCClassDecl jcClassDecl && jcClassDecl.sym != null && jcClassDecl.sym.type != null) {
+ return this.bindings.getTypeBinding(jcClassDecl.sym.type, true);
+ }
+ return null;
+ }
+
+ @Override
+ ITypeBinding resolveType(EnumDeclaration enumDecl) {
+ resolve();
+ JCTree javacNode = this.converter.domToJavac.get(enumDecl);
+ if (javacNode instanceof JCClassDecl jcClassDecl && jcClassDecl.type != null) {
+ return this.bindings.getTypeBinding(jcClassDecl.type, true);
+ }
+ return null;
+ }
+
+ @Override
+ ITypeBinding resolveType(AnonymousClassDeclaration anonymousClassDecl) {
+ resolve();
+ JCTree javacNode = this.converter.domToJavac.get(anonymousClassDecl);
+ if (javacNode instanceof JCClassDecl jcClassDecl && jcClassDecl.type != null) {
+ return this.bindings.getTypeBinding(jcClassDecl.type, true);
+ }
+ return null;
+ }
+ @Override
+ ITypeBinding resolveTypeParameter(TypeParameter typeParameter) {
+ resolve();
+ JCTree javacNode = this.converter.domToJavac.get(typeParameter);
+ if (javacNode instanceof JCTypeParameter jcClassDecl) {
+ return this.bindings.getTypeBinding(jcClassDecl.type);
+ }
+ return null;
+ }
+
+ @Override
+ IVariableBinding resolveField(FieldAccess fieldAccess) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(fieldAccess);
+ if (javacElement instanceof JCFieldAccess javacFieldAccess && javacFieldAccess.sym instanceof VarSymbol varSymbol) {
+ return this.bindings.getVariableBinding(varSymbol);
+ }
+ return null;
+ }
+
+ @Override
+ IVariableBinding resolveField(SuperFieldAccess fieldAccess) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(fieldAccess);
+ if (javacElement instanceof JCFieldAccess javacFieldAccess && javacFieldAccess.sym instanceof VarSymbol varSymbol) {
+ return this.bindings.getVariableBinding(varSymbol);
+ }
+ return null;
+ }
+
+ @Override
+ IMethodBinding resolveMethod(MethodInvocation method) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(method);
+ List typeArgs = null;
+ if (javacElement instanceof JCMethodInvocation javacMethodInvocation) {
+ typeArgs = List.of();
+ javacElement = javacMethodInvocation.getMethodSelect();
+ typeArgs = javacMethodInvocation.getTypeArguments().stream().map(jcExpr -> jcExpr.type).toList();
+ }
+ var type = javacElement.type;
+ // next condition matches `localMethod(this::missingMethod)`
+ if (javacElement instanceof JCIdent ident && type == null) {
+ ASTNode node = method;
+ while (node != null && !(node instanceof AbstractTypeDeclaration)) {
+ node = node.getParent();
+ }
+ if (node instanceof AbstractTypeDeclaration decl &&
+ this.converter.domToJavac.get(decl) instanceof JCClassDecl javacClassDecl &&
+ javacClassDecl.type instanceof ClassType classType &&
+ !classType.isErroneous()) {
+ type = classType;
+ }
+ if (type != null &&
+ type.tsym.members().findFirst(ident.getName(), MethodSymbol.class::isInstance) instanceof MethodSymbol methodSymbol &&
+ methodSymbol.type instanceof MethodType methodType) {
+ var res = this.bindings.getMethodBinding(methodType, methodSymbol, null, false, typeArgs);
+ if (res != null) {
+ return res;
+ }
+ }
+ }
+ var sym = javacElement instanceof JCIdent ident ? ident.sym :
+ javacElement instanceof JCFieldAccess fieldAccess ? fieldAccess.sym :
+ null;
+
+ // Let's handle error types first
+ if (type instanceof ErrorType errorType ) {
+ com.sun.tools.javac.code.Type original = errorType;
+ while(original instanceof ErrorType et && original != et.getOriginalType()) {
+ original = et.getOriginalType();
+ }
+
+ if( original instanceof ForAll fa) {
+ original = fa.asMethodType();
+ }
+ if( original instanceof MethodType methodType) {
+ if (sym.owner instanceof TypeSymbol typeSymbol) {
+ Iterator methods = typeSymbol.members().getSymbolsByName(sym.getSimpleName(), m -> m instanceof MethodSymbol && methodType.equals(m.type)).iterator();
+ if (methods.hasNext()) {
+ return this.bindings.getMethodBinding(methodType, (MethodSymbol)methods.next(), null, false, typeArgs);
+ }
+ }
+ return this.bindings.getErrorMethodBinding(methodType, sym, typeArgs);
+ }
+ }
+
+
+
+ if (type instanceof MethodType methodType && sym instanceof MethodSymbol methodSymbol) {
+ com.sun.tools.javac.code.Type parentType = null;
+ if (methodSymbol.owner instanceof ClassSymbol ownerClass && isTypeOfType(ownerClass.type)) {
+ if (ownerClass.type.isParameterized()
+ && method.getExpression() != null
+ && resolveExpressionType(method.getExpression()) instanceof JavacTypeBinding exprType) {
+ parentType = exprType.type;
+ } else {
+ parentType = ownerClass.type;
+ }
+ }
+ return this.bindings.getMethodBinding(methodType, methodSymbol, parentType, false, typeArgs);
+ }
+ if (type == null && sym instanceof MethodSymbol methodSym && methodSym.type instanceof ForAll methodTemplateType) {
+ // build type from template
+ Map resolutionMapping = new HashMap<>();
+ var templateParameters = methodTemplateType.getTypeVariables();
+ if( typeArgs != null ) {
+ for (int i = 0; i < typeArgs.size() && i < templateParameters.size(); i++) {
+ resolutionMapping.put(templateParameters.get(i), typeArgs.get(i));
+ }
+ }
+ MethodType methodType = new MethodType(
+ methodTemplateType.asMethodType().getParameterTypes().map(t -> applyType(t, resolutionMapping)),
+ applyType(methodTemplateType.asMethodType().getReturnType(), resolutionMapping),
+ methodTemplateType.asMethodType().getThrownTypes().map(t -> applyType(t, resolutionMapping)),
+ methodTemplateType.tsym);
+ return this.bindings.getMethodBinding(methodType, methodSym, methodSym.owner.type, false, typeArgs);
+ }
+ if (type == null && sym != null && sym.type.isErroneous()
+ && sym.owner.type instanceof ClassType classType) {
+ var parentTypeBinding = this.bindings.getTypeBinding(classType);
+ return Arrays.stream(parentTypeBinding.getDeclaredMethods())
+ .filter(binding -> binding.getName().equals(sym.getSimpleName().toString()))
+ .findAny()
+ .orElse(null);
+ }
+ if (type == null && sym instanceof MethodSymbol methodSymbol && methodSymbol.type instanceof MethodType
+ && javacElement instanceof JCFieldAccess selectedMethod
+ && selectedMethod.getExpression() != null
+ && selectedMethod.getExpression().type instanceof ClassType classType) {
+ // method is resolved, but type is not, probably because of invalid param
+ // workaround: check compatible method in selector
+ var parentTypeBinding = this.bindings.getTypeBinding(classType);
+ var res = Arrays.stream(parentTypeBinding.getDeclaredMethods())
+ .filter(binding -> binding instanceof JavacMethodBinding javacMethodBinding && javacMethodBinding.methodSymbol == methodSymbol)
+ .findAny()
+ .orElse(null);
+ if (res != null) {
+ return res;
+ }
+ }
+ if (sym instanceof MethodSymbol && sym.type instanceof MethodType) {
+ return (IMethodBinding)this.bindings.getBinding(sym, sym.type);
+ }
+ return null;
+ }
+
+ /**
+ * Derives an "applied" type replacing know TypeVar with their current value
+ * @param from The type to check for replacement of TypeVars
+ * @param resolutionMapping a dictionary defining which concrete type must replace TypeVar
+ * @return The derived "applied" type: recursively checks the type, replacing
+ * known {@link TypeVar} instances in those with their value defined in `resolutionMapping`
+ */
+ private static com.sun.tools.javac.code.Type applyType(com.sun.tools.javac.code.Type from, Map resolutionMapping) {
+ if (from instanceof TypeVar typeVar) {
+ var directMapping = resolutionMapping.get(from);
+ if (directMapping != null) {
+ return directMapping;
+ }
+ return typeVar;
+ }
+ if (from instanceof JCNoType || from instanceof JCVoidType ||
+ from instanceof JCPrimitiveType) {
+ return from;
+ }
+ if (from instanceof ClassType classType) {
+ var args = classType.getTypeArguments().map(typeArg -> applyType(typeArg, resolutionMapping));
+ if (Objects.equals(args, classType.getTypeArguments())) {
+ return classType;
+ }
+ return new ClassType(classType.getEnclosingType(), args, classType.tsym);
+ }
+ if (from instanceof ArrayType arrayType) {
+ var targetElemType = applyType(arrayType.elemtype, resolutionMapping);
+ if (Objects.equals(targetElemType, arrayType.elemtype)) {
+ return arrayType;
+ }
+ return new ArrayType(targetElemType, arrayType.tsym);
+ }
+ return from;
+ }
+
+ @Override
+ IMethodBinding resolveMethod(MethodDeclaration method) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(method);
+ if (javacElement instanceof JCMethodDecl methodDecl && !(methodDecl.type instanceof ErrorType)) {
+ if (methodDecl.type != null ) {
+ return this.bindings.getMethodBinding(methodDecl.type.asMethodType(), methodDecl.sym, null, true, null);
+ }
+ if (methodDecl.sym instanceof MethodSymbol methodSymbol && methodSymbol.type != null) {
+ return this.bindings.getMethodBinding(methodSymbol.type.asMethodType(), methodSymbol, null, true, null);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ IMethodBinding resolveMethod(LambdaExpression lambda) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(lambda);
+ if (javacElement instanceof JCLambda jcLambda) {
+ JavacTypeBinding typeBinding = this.bindings.getTypeBinding(jcLambda.type);
+ if (typeBinding != null && typeBinding.getFunctionalInterfaceMethod() instanceof JavacMethodBinding methodBinding) {
+ return this.bindings.getLambdaBinding(methodBinding, lambda);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ IMethodBinding resolveMethod(MethodReference methodReference) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(methodReference);
+ if (javacElement instanceof JCMemberReference memberRef && memberRef.sym instanceof MethodSymbol methodSymbol) {
+ List typeArgs = streamOfTreeType(memberRef.getTypeArguments());
+ if (memberRef.referentType != null && memberRef.referentType instanceof MethodType) {
+ return this.bindings.getMethodBinding(memberRef.referentType.asMethodType(), methodSymbol, null, false, typeArgs);
+ }
+ if (methodSymbol.type instanceof MethodType) {
+ return this.bindings.getMethodBinding(methodSymbol.type.asMethodType(), methodSymbol, null, false, typeArgs);
+ }
+ }
+ return null;
+ }
+
+ private List streamOfTreeType(List extends JCTree> items ) {
+ return items != null ? items.stream().map(x -> x.type).toList() : new ArrayList();
+ }
+
+ @Override
+ IMethodBinding resolveMember(AnnotationTypeMemberDeclaration member) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(member);
+ if (javacElement instanceof JCMethodDecl methodDecl) {
+ List typeArgs = streamOfTreeType(methodDecl.getTypeParameters());
+ return this.bindings.getMethodBinding(methodDecl.type.asMethodType(), methodDecl.sym, null, true, typeArgs);
+ }
+ return null;
+ }
+
+ @Override
+ IMethodBinding resolveConstructor(EnumConstantDeclaration enumConstantDeclaration) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(enumConstantDeclaration);
+ if( javacElement instanceof JCVariableDecl jcvd ) {
+ javacElement = jcvd.init;
+ }
+ if(javacElement instanceof JCNewClass jcExpr && !jcExpr.constructor.type.isErroneous()) {
+ List typeArgs = streamOfTreeType(jcExpr.typeargs);
+ return this.bindings.getMethodBinding(jcExpr.constructor.type.asMethodType(), (MethodSymbol)jcExpr.constructor, null, true, typeArgs);
+ }
+ return null;
+ }
+
+ @Override
+ IMethodBinding resolveConstructor(SuperConstructorInvocation expression) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(expression);
+ if (javacElement instanceof JCMethodInvocation javacMethodInvocation) {
+ javacElement = javacMethodInvocation.getMethodSelect();
+ }
+ if (javacElement instanceof JCIdent ident && ident.sym instanceof MethodSymbol methodSymbol) {
+ if (ident.type != null && (ident.type instanceof MethodType || ident.type instanceof ForAll)) {
+ return this.bindings.getMethodBinding(ident.type.asMethodType(), methodSymbol, null, false, null);
+ } else if (methodSymbol.asType() instanceof MethodType || methodSymbol.asType() instanceof ForAll) {
+ return this.bindings.getMethodBinding(methodSymbol.asType().asMethodType(), methodSymbol, null, false, null);
+ }
+ }
+ if (javacElement instanceof JCFieldAccess fieldAccess && fieldAccess.sym instanceof MethodSymbol methodSymbol) {
+ return this.bindings.getMethodBinding(fieldAccess.type.asMethodType(), methodSymbol, null, false, null);
+ }
+ return null;
+ }
+
+ @Override
+ IMethodBinding resolveMethod(SuperMethodInvocation method) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(method);
+ if (javacElement instanceof JCMethodInvocation javacMethodInvocation) {
+ javacElement = javacMethodInvocation.getMethodSelect();
+ }
+ if (javacElement instanceof JCIdent ident && ident.sym instanceof MethodSymbol methodSymbol) {
+ return this.bindings.getMethodBinding(ident.type.asMethodType(), methodSymbol, null, false, null);
+ }
+ if (javacElement instanceof JCFieldAccess fieldAccess && fieldAccess.sym instanceof MethodSymbol methodSymbol
+ && fieldAccess.type != null /* when there are syntax errors */) {
+ return this.bindings.getMethodBinding(fieldAccess.type.asMethodType(), methodSymbol, null, false, null);
+ }
+ return null;
+ }
+
+ IBinding resolveCached(ASTNode node, Function l) {
+ resolve();
+ // Avoid using `computeIfAbsent` because it throws
+ // ConcurrentModificationException when nesting calls
+ var res = resolvedBindingsCache.get(node);
+ if (res == null) {
+ res = l.apply(node);
+ resolvedBindingsCache.put(node, res);
+ }
+ return res;
+ }
+
+ @Override
+ IBinding resolveName(Name name) {
+ return resolveCached(name, (n) -> resolveNameImpl((Name)n));
+ }
+
+ private IBinding resolveNameImpl(Name name) {
+ resolve();
+ if (name.getParent() instanceof MemberRef memberRef) {
+ resolveReference(memberRef); // initialize symbols on Javadoc
+ }
+ if (name.getParent() instanceof MethodRef methodRef) {
+ resolveReference(methodRef);
+ }
+
+ // first, prefer parent if appropriate
+ ASTNode parent = name.getParent();
+ if (name.getLocationInParent() == QualifiedName.NAME_PROPERTY && parent instanceof QualifiedName qname &&
+ qname.getParent() instanceof SimpleType simpleType && simpleType.getLocationInParent() == ParameterizedType.TYPE_PROPERTY) {
+ var typeBinding = resolveType((ParameterizedType)simpleType.getParent());
+ if (typeBinding != null) {
+ return typeBinding;
+ }
+ }
+ if (name.getLocationInParent() == QualifiedType.NAME_PROPERTY &&
+ parent.getLocationInParent() == QualifiedType.QUALIFIER_PROPERTY) {
+ var typeBinding = resolveType((QualifiedType)parent);
+ return typeBinding.getTypeDeclaration(); // exclude params
+ }
+ if (name.getLocationInParent() == SimpleType.NAME_PROPERTY
+ || name.getLocationInParent() == QualifiedType.NAME_PROPERTY
+ || name.getLocationInParent() == NameQualifiedType.NAME_PROPERTY) { // case of "var"
+ return resolveType((Type)parent);
+ }
+ if (name.getLocationInParent() == MethodInvocation.NAME_PROPERTY && name.getParent() instanceof MethodInvocation method) {
+ return resolveMethod(method);
+ }
+
+ JCTree tree = this.converter.domToJavac.get(name);
+ if( tree != null ) {
+ var res = resolveNameToJavac(name, tree);
+ if (res != null) {
+ return res;
+ }
+ }
+ DocTreePath path = this.converter.findDocTreePath(name);
+ if (path != null) {
+ if (JavacTrees.instance(this.context).getElement(path) instanceof Symbol symbol) {
+ return this.bindings.getBinding(symbol, null);
+ }
+ }
+
+ PackageSymbol ps = findPackageSymbol(name);
+ if( ps != null && ps.exists()) {
+ return this.bindings.getPackageBinding(ps);
+ }
+ if( isPackageName(name)) {
+ return this.bindings.getPackageBinding(name);
+ }
+ if( tree instanceof JCIdent jcid && jcid.sym instanceof ClassSymbol && jcid.type instanceof ErrorType) {
+ IBinding b = this.bindings.findExistingPackageBinding(name);
+ if( b != null )
+ return b;
+ }
+
+ if (tree == null && (name.getFlags() & ASTNode.ORIGINAL) != 0) {
+ tree = this.converter.domToJavac.get(parent);
+ if( tree instanceof JCFieldAccess jcfa) {
+ if( jcfa.selected instanceof JCIdent jcid && jcid.toString().equals(name.toString())) {
+ tree = jcfa.selected;
+ }
+ var grandParent = parent.getParent();
+ if (grandParent instanceof ParameterizedType parameterized) {
+ var parameterizedType = resolveType(parameterized);
+ if (parameterizedType != null) {
+ return parameterizedType;
+ }
+
+ }
+ }
+ }
+ if( tree != null ) {
+ // Looks duplicate to top of method, but is not. Must remain.
+ IBinding ret = resolveNameToJavac(name, tree);
+ if (ret != null) {
+ return ret;
+ }
+ }
+ if (parent instanceof ImportDeclaration importDecl && importDecl.getName() == name) {
+ return resolveImport(importDecl);
+ }
+ if (parent instanceof QualifiedName parentName && parentName.getName() == name) {
+ return resolveNameImpl(parentName);
+ }
+ if( parent instanceof MethodRef mref && mref.getName() == name) {
+ return resolveReference(mref);
+ }
+ if( parent instanceof MemberRef mref && mref.getName() == name) {
+ return resolveReference(mref);
+ }
+ if (parent instanceof MethodInvocation methodInvocation && methodInvocation.getName() == name) {
+ return resolveMethod(methodInvocation);
+ }
+ if (parent instanceof MethodDeclaration methodDeclaration && methodDeclaration.getName() == name) {
+ return resolveMethod(methodDeclaration);
+ }
+ if (parent instanceof ExpressionMethodReference methodRef && methodRef.getName() == name) {
+ return resolveMethod(methodRef);
+ }
+ if (parent instanceof TypeMethodReference methodRef && methodRef.getName() == name) {
+ return resolveMethod(methodRef);
+ }
+ if (parent instanceof SuperMethodReference methodRef && methodRef.getName() == name) {
+ return resolveMethod(methodRef);
+ }
+ if (parent instanceof VariableDeclaration decl && decl.getName() == name) {
+ return resolveVariable(decl);
+ }
+ return null;
+ }
+
+ private boolean isPackageName(Name name) {
+ ASTNode working = name;
+ boolean insideQualifier = false;
+ while( working instanceof Name ) {
+ JCTree tree = this.converter.domToJavac.get(working);
+ if( tree instanceof JCFieldAccess jcfa) {
+ return jcfa.sym instanceof PackageSymbol psym && psym.exists();
+ }
+ if( working instanceof QualifiedName qnn) {
+ if( qnn.getQualifier() == working) {
+ insideQualifier = true;
+ }
+ }
+ working = working.getParent();
+ }
+ return insideQualifier;
+ }
+
+ private PackageSymbol findPackageSymbol(Name name) {
+ if( name instanceof SimpleName sn) {
+ ASTNode parent = sn.getParent();
+ if( parent instanceof QualifiedName qn) {
+ JCTree tree = this.converter.domToJavac.get(parent);
+ if( tree instanceof JCFieldAccess jcfa) {
+ if( qn.getQualifier().equals(name)) {
+ if( jcfa.selected instanceof JCIdent jcid && jcid.sym instanceof PackageSymbol pss)
+ return pss;
+ } else if( qn.getName().equals(name)) {
+ return jcfa.sym instanceof PackageSymbol pss ? pss : null;
+ }
+ }
+ }
+ }
+ if( name instanceof QualifiedName qn ) {
+ JCTree tree = this.converter.domToJavac.get(qn);
+ if( tree instanceof JCFieldAccess jcfa) {
+ return jcfa.sym instanceof PackageSymbol pss ? pss : null;
+ }
+ }
+ return null;
+ }
+
+ IBinding resolveNameToJavac(Name name, JCTree tree) {
+ boolean isTypeDeclaration = (name.getParent() instanceof AbstractTypeDeclaration typeDeclaration && typeDeclaration.getName() == name)
+ || (name.getParent() instanceof SimpleType type && type.getName() == name);
+ if( name.getParent() instanceof AnnotatableType st && st.getParent() instanceof ParameterizedType pt) {
+ if( st == pt.getType()) {
+ tree = this.converter.domToJavac.get(pt);
+ if (tree.type != null && !tree.type.isErroneous()) {
+ IBinding b = this.bindings.getTypeBinding(tree.type, isTypeDeclaration);
+ if( b != null ) {
+ return b;
+ }
+ }
+ }
+ }
+
+ if (tree instanceof JCIdent ident && ident.sym != null) {
+ if (ident.type instanceof ErrorType errorType
+ && errorType.getOriginalType() instanceof ErrorType
+ && !isRecoveringBindings()) {
+ return null;
+ }
+ if (isTypeDeclaration) {
+ return this.bindings.getTypeBinding(ident.type != null ? ident.type : ident.sym.type, true);
+ }
+ return this.bindings.getBinding(ident.sym, ident.type != null ? ident.type : ident.sym.type);
+ }
+ if (tree instanceof JCTypeApply variableDecl && variableDecl.type != null) {
+ return this.bindings.getTypeBinding(variableDecl.type);
+ }
+ if (tree instanceof JCFieldAccess fieldAccess) {
+ return this.getFieldAccessBinding(fieldAccess);
+ }
+ if (tree instanceof JCMethodInvocation methodInvocation && methodInvocation.meth.type != null) {
+ return this.bindings.getBinding(((JCFieldAccess)methodInvocation.meth).sym, methodInvocation.meth.type);
+ }
+ if (tree instanceof JCClassDecl classDecl && classDecl.sym != null) {
+ return this.bindings.getBinding(classDecl.sym, classDecl.type);
+ }
+ if (tree instanceof JCMethodDecl methodDecl && methodDecl.sym != null) {
+ return this.bindings.getBinding(methodDecl.sym, methodDecl.type);
+ }
+ if (tree instanceof JCVariableDecl variableDecl && variableDecl.sym != null) {
+ return this.bindings.getBinding(variableDecl.sym, variableDecl.type);
+ }
+ if (tree instanceof JCTypeParameter variableDecl && variableDecl.type != null && variableDecl.type.tsym != null) {
+ return this.bindings.getBinding(variableDecl.type.tsym, variableDecl.type);
+ }
+ if (tree instanceof JCModuleDecl variableDecl && variableDecl.sym != null && variableDecl.sym.type instanceof ModuleType) {
+ return this.bindings.getModuleBinding(variableDecl);
+ }
+ return null;
+ }
+
+ @Override
+ IVariableBinding resolveVariable(EnumConstantDeclaration enumConstant) {
+ resolve();
+ if (this.converter.domToJavac.get(enumConstant) instanceof JCVariableDecl decl) {
+ // the decl.type can be null when there are syntax errors
+ if ((decl.type != null && !decl.type.isErroneous()) || this.isRecoveringBindings()) {
+ return this.bindings.getVariableBinding(decl.sym);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ IVariableBinding resolveVariable(VariableDeclaration variable) {
+ resolve();
+ if (this.converter.domToJavac.get(variable) instanceof JCVariableDecl decl) {
+ // the decl.type can be null when there are syntax errors
+ if ((decl.type != null && !decl.type.isErroneous()) || this.isRecoveringBindings()) {
+ if (decl.name != Names.instance(this.context).error) { // cannot recover if name is error
+ return this.bindings.getVariableBinding(decl.sym);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IPackageBinding resolvePackage(PackageDeclaration decl) {
+ resolve();
+ if (this.converter.domToJavac.get(decl) instanceof JCPackageDecl jcPackageDecl) {
+ return this.bindings.getPackageBinding(jcPackageDecl.packge);
+ }
+ return null;
+ }
+
+ @Override
+ public ITypeBinding resolveExpressionType(Expression expr) {
+ resolve();
+ if (expr instanceof SimpleName name) {
+ IBinding binding = resolveName(name);
+ // binding can be null when the code has syntax errors
+ if (binding == null || (binding.isRecovered() && !this.isRecoveringBindings())) {
+ return null;
+ }
+ switch (binding) {
+ case IVariableBinding variableBinding: return variableBinding.getType();
+ case ITypeBinding typeBinding: return typeBinding;
+ case IMethodBinding methodBinding: return methodBinding.getReturnType();
+ default:
+ return null;
+ }
+ }
+ var jcTree = this.converter.domToJavac.get(expr);
+ if (jcTree instanceof JCExpression expression
+ && isTypeOfType(expression.type)
+ && !expression.type.isErroneous()) {
+ var res = this.bindings.getTypeBinding(expression.type);
+ if (res != null) {
+ return res;
+ }
+ }
+ if (jcTree instanceof JCMethodInvocation javacMethodInvocation) {
+ if (javacMethodInvocation.meth.type instanceof MethodType methodType) {
+ return this.bindings.getTypeBinding(methodType.getReturnType());
+ } else if (javacMethodInvocation.meth.type instanceof ErrorType errorType) {
+ if (errorType.getOriginalType() instanceof MethodType methodType) {
+ return this.bindings.getTypeBinding(methodType.getReturnType());
+ }
+ }
+ return null;
+ }
+ if (jcTree instanceof JCNewClass newClass
+ && newClass.type != null
+ && Symtab.instance(this.context).errSymbol == newClass.type.tsym) {
+ if (newClass.encl != null) {
+ String className = newClass.clazz instanceof JCTypeApply typeApply ? typeApply.clazz.toString() : newClass.clazz.toString();
+ ITypeBinding enclosingTypeBinding = resolveExpressionType(((ClassInstanceCreation)expr).getExpression());
+ List potentialTypes = Stream.of(enclosingTypeBinding.getDeclaredTypes()).filter(innerType -> {
+ String cleanedName = innerType.getName();
+ if (cleanedName.endsWith(">")) {
+ cleanedName = cleanedName.substring(0, cleanedName.lastIndexOf("<"));
+ }
+ return className.equals(cleanedName);
+ }).toList();
+ if (!potentialTypes.isEmpty()) {
+ return potentialTypes.get(0);
+ }
+ }
+ jcTree = newClass.getIdentifier();
+ }
+ if (jcTree instanceof JCFieldAccess jcFieldAccess) {
+ if (jcFieldAccess.type instanceof PackageType) {
+ return null;
+ }
+ if (expr instanceof SuperFieldAccess) {
+ return this.bindings.getTypeBinding(jcFieldAccess.selected.type);
+ }
+ if (jcFieldAccess.type != null && !jcFieldAccess.type.isErroneous()) {
+ return this.bindings.getTypeBinding(jcFieldAccess.type);
+ }
+ if (jcFieldAccess.sym != null) {
+ return this.bindings.getTypeBinding(jcFieldAccess.sym.type);
+ }
+ }
+ if (jcTree instanceof JCVariableDecl jcVariableDecl) {
+ if (jcVariableDecl.type != null) {
+ return this.bindings.getTypeBinding(jcVariableDecl.type);
+ } else {
+ return null;
+ }
+ }
+ if (jcTree instanceof JCTypeCast jcCast && jcCast.getType() != null) {
+ return this.bindings.getTypeBinding(jcCast.getType().type);
+ }
+ if (jcTree instanceof JCLiteral jcLiteral && jcLiteral.type != null && jcLiteral.type.isErroneous()) {
+ if (jcLiteral.typetag == TypeTag.CLASS) {
+ return resolveWellKnownType("java.lang.String");
+ } else if (jcLiteral.typetag == TypeTag.BOT) {
+ return this.bindings.getTypeBinding(com.sun.tools.javac.code.Symtab.instance(this.context).botType);
+ }
+ return resolveWellKnownType(jcLiteral.typetag.name().toLowerCase());
+ }
+ if (jcTree instanceof JCExpression jcExpr) {
+ if (jcExpr.type instanceof PackageType) {
+ return null;
+ }
+ Symbol recoveredSymbol = getRecoveredSymbol(jcExpr.type);
+ if (recoveredSymbol != null) {
+ IBinding recoveredBinding = this.bindings.getBinding(recoveredSymbol, recoveredSymbol.type);
+ return switch (recoveredBinding) {
+ case IVariableBinding variableBinding -> variableBinding.getType();
+ case ITypeBinding typeBinding -> typeBinding;
+ case IMethodBinding methodBinding -> methodBinding.getReturnType();
+ default -> null;
+ };
+ }
+ if (jcExpr.type != null) {
+ var res = this.bindings.getTypeBinding(jcExpr.type);
+ if (res != null) {
+ return res;
+ }
+ }
+ // workaround Javac missing bindings in some cases
+ if (expr instanceof ClassInstanceCreation classInstanceCreation) {
+ return classInstanceCreation.getType().resolveBinding();
+// return createRecoveredTypeBinding(classInstanceCreation.getType());
+ }
+ }
+ return null;
+ }
+
+ @Override
+ IMethodBinding resolveConstructor(ClassInstanceCreation expression) {
+ return (IMethodBinding)resolveCached(expression, (n) -> resolveConstructorImpl((ClassInstanceCreation)n));
+ }
+
+ /**
+ *
+ * @param t the type to check
+ * @return whether this is actually a type (returns
+ * {@code false} for things like {@link PackageType},
+ * {@link MethodType}...
+ */
+ public static boolean isTypeOfType(com.sun.tools.javac.code.Type t) {
+ return t == null ? false :
+ switch (t.getKind()) {
+ case PACKAGE, MODULE, EXECUTABLE, OTHER -> false;
+ default -> true;
+ };
+ }
+
+ private IMethodBinding resolveConstructorImpl(ClassInstanceCreation expression) {
+ resolve();
+ if (this.converter.domToJavac.get(expression) instanceof JCNewClass jcExpr) {
+ if (jcExpr.constructor != null && !jcExpr.constructor.type.isErroneous()) {
+ List javacTypeArgs =
+ jcExpr.getTypeArguments().stream().map(jc -> jc.type).toList();
+ return this.bindings.getMethodBinding(jcExpr.constructor.type.asMethodType(), (MethodSymbol)jcExpr.constructor, jcExpr.type, false, javacTypeArgs);
+ }
+ }
+ ITypeBinding type = resolveType(expression.getType());
+ if (type != null) {
+ List givenTypes = ((List)expression.arguments()).stream()
+ .map(this::resolveExpressionType)
+ .toList();
+ boolean hasTrailingNull;
+ boolean matchExactParamCount = false;
+ do {
+ hasTrailingNull = !givenTypes.isEmpty() && givenTypes.getLast() == null;
+ // try just checking by known args
+ // first filter by args count
+ var matchExactParamCountFinal = matchExactParamCount;
+ var finalGivenTypes = givenTypes;
+ var candidates = Arrays.stream(type.getDeclaredMethods())
+ .filter(IMethodBinding::isConstructor)
+ .filter(other -> matchExactParamCountFinal ? other.getParameterTypes().length == finalGivenTypes.size() : other.getParameterTypes().length >= finalGivenTypes.size())
+ .toList();
+ if (candidates.size() == 1) {
+ return candidates.get(0);
+ }
+ if (candidates.size() > 1 && expression.arguments().size() > 0) {
+ // then try filtering by arg types
+ var typeFilteredCandidates = candidates.stream()
+ .filter(other -> matchTypes(finalGivenTypes, other.getParameterTypes()))
+ .toList();
+ if (typeFilteredCandidates.size() == 1) {
+ return typeFilteredCandidates.get(0);
+ }
+ }
+ if (hasTrailingNull) {
+ givenTypes = givenTypes.subList(0, givenTypes.size() - 1);
+ matchExactParamCount = true;
+ }
+ } while (hasTrailingNull);
+ }
+ return null;
+ }
+
+ private boolean matchTypes(List givenTypes, ITypeBinding[] expectedTypes) {
+ for (int i = 0; i < Math.min(givenTypes.size(), expectedTypes.length); i++) {
+ ITypeBinding givenType = givenTypes.get(i);
+ ITypeBinding expectedType = expectedTypes[i];
+ if (givenType != null) {
+ if (!givenType.isAssignmentCompatible(expectedType)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ IMethodBinding resolveConstructor(ConstructorInvocation invocation) {
+ return (IMethodBinding)resolveCached(invocation, (n) -> resolveConstructorImpl((ConstructorInvocation)n));
+ }
+
+ private IMethodBinding resolveConstructorImpl(ConstructorInvocation invocation) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(invocation);
+ if (javacElement instanceof JCMethodInvocation javacMethodInvocation) {
+ javacElement = javacMethodInvocation.getMethodSelect();
+ }
+ if (javacElement instanceof JCIdent ident && ident.sym instanceof MethodSymbol methodSymbol) {
+ MethodType mt = ident.type != null && ident.type.getKind() == TypeKind.EXECUTABLE ? ident.type.asMethodType() : methodSymbol.type.asMethodType();
+ return this.bindings.getMethodBinding(mt, methodSymbol, null, false, null);
+ }
+ if (javacElement instanceof JCFieldAccess fieldAccess && fieldAccess.sym instanceof MethodSymbol methodSymbol) {
+ return this.bindings.getMethodBinding(fieldAccess.type.asMethodType(), methodSymbol, null, false, null);
+ }
+ return null;
+ }
+
+ public Types getTypes() {
+ return Types.instance(this.context);
+ }
+
+ @Override
+ IModuleBinding resolveModule(ModuleDeclaration module) {
+ return (IModuleBinding)resolveCached(module, (n) -> resolveModuleImpl((ModuleDeclaration)n));
+ }
+
+ private IBinding resolveModuleImpl(ModuleDeclaration module) {
+ resolve();
+ JCTree javacElement = this.converter.domToJavac.get(module);
+ if( javacElement instanceof JCModuleDecl jcmd) {
+ Object o = jcmd.sym.type;
+ if( o instanceof ModuleType mt ) {
+ return this.bindings.getModuleBinding(mt);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the constant value or the binding that a Javac attribute represents.
+ *
+ * See a detailed explanation of the returned value: {@link org.eclipse.jdt.core.dom.IMethodBinding#getDefaultValue()}
+ *
+ * @param attribute the javac attribute
+ * @return the constant value or the binding that a Javac attribute represents
+ */
+ public Object getValueFromAttribute(Attribute attribute) {
+ if (attribute == null) {
+ return null;
+ }
+ if (attribute instanceof Attribute.Constant constant) {
+ return constant.value;
+ } else if (attribute instanceof Attribute.Class clazz) {
+ return this.bindings.getTypeBinding(clazz.classType);
+ } else if (attribute instanceof Attribute.Enum enumm) {
+ return this.bindings.getVariableBinding(enumm.value);
+ } else if (attribute instanceof Attribute.Array array) {
+ return Stream.of(array.values) //
+ .map(nestedAttr -> {
+ if (nestedAttr instanceof Attribute.Constant constant) {
+ return constant.value;
+ } else if (nestedAttr instanceof Attribute.Class clazz) {
+ return this.bindings.getTypeBinding(clazz.classType);
+ } else if (nestedAttr instanceof Attribute.Enum enumerable) {
+ return this.bindings.getVariableBinding(enumerable.value);
+ }
+ throw new IllegalArgumentException("Unexpected attribute type: " + nestedAttr.getClass().getCanonicalName());
+ }).toArray(Object[]::new);
+ } else if( attribute instanceof Attribute.Error) {
+ return null;
+ }
+ throw new IllegalArgumentException("Unexpected attribute type: " + attribute.getClass().getCanonicalName());
+ }
+
+ @Override
+ IBinding resolveImport(ImportDeclaration importDeclaration) {
+ return resolveCached(importDeclaration, (n) -> resolveImportImpl((ImportDeclaration)n));
+ }
+
+ private IBinding resolveImportImpl(ImportDeclaration importDeclaration) {
+ var javac = this.converter.domToJavac.get(importDeclaration.getName());
+ if (javac instanceof JCFieldAccess fieldAccess) {
+ if (fieldAccess.sym != null) {
+ return this.bindings.getBinding(fieldAccess.sym, null);
+ }
+ if (importDeclaration.isStatic()) {
+ com.sun.tools.javac.code.Type type = fieldAccess.getExpression().type;
+ if (type != null) {
+ ITypeBinding typeBinding = this.bindings.getTypeBinding(type);
+ if (typeBinding != null) {
+ IBinding binding = Arrays.stream(typeBinding.getDeclaredMethods())
+ .filter(method -> Objects.equals(fieldAccess.getIdentifier().toString(), method.getName()))
+ .findAny()
+ .orElse(null);
+ if (binding == null) {
+ binding = Arrays.stream(typeBinding.getDeclaredFields()).filter(
+ field -> Objects.equals(fieldAccess.getIdentifier().toString(), field.getName()))
+ .findAny().orElse(null);
+ }
+ return binding;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ITypeBinding resolveWellKnownType(String typeName) {
+ resolve(); // could be skipped, but this method is used by ReconcileWorkingCopyOperation to generate errors
+ com.sun.tools.javac.code.Symtab symtab = com.sun.tools.javac.code.Symtab.instance(this.context);
+ com.sun.tools.javac.code.Type type = switch (typeName) {
+ case "byte", "java.lang.Byte" -> symtab.byteType;
+ case "char", "java.lang.Character" -> symtab.charType;
+ case "double", "java.lang.Double" -> symtab.doubleType;
+ case "float", "java.lang.Float" -> symtab.floatType;
+ case "int", "java.lang.Integer" -> symtab.intType;
+ case "long", "java.lang.Long" -> symtab.longType;
+ case "short", "java.lang.Short" -> symtab.shortType;
+ case "boolean", "java.lang.Boolean" -> symtab.booleanType;
+ case "void", "java.lang.Void" -> symtab.voidType;
+ case "java.lang.Object" -> symtab.objectType;
+ case "java.lang.String" -> symtab.stringType;
+ case "java.lang.StringBuffer" -> symtab.stringBufferType;
+ case "java.lang.Throwable" -> symtab.throwableType;
+ case "java.lang.Exception" -> symtab.exceptionType;
+ case "java.lang.RuntimeException" -> symtab.runtimeExceptionType;
+ case "java.lang.Error" -> symtab.errorType;
+ case "java.lang.Class" -> symtab.classType;
+ case "java.lang.Cloneable" -> symtab.cloneableType;
+ case "java.io.Serializable" -> symtab.serializableType;
+ default -> null;
+ };
+ if (type == null) {
+ ClassFinder finder = ClassFinder.instance(context);
+ Modules modules = Modules.instance(context);
+ Names names = Names.instance(context);
+ if (finder != null && modules != null && names != null) {
+ try {
+ ClassSymbol sym = finder.loadClass(modules.getDefaultModule(), names.fromString(typeName));
+ if (sym != null) {
+ type = sym.type;
+ }
+ } catch (CompletionFailure failure) {
+ // do nothing, class not found
+ }
+ }
+ }
+ return type != null ? this.bindings.getTypeBinding(type, true) : null;
+ }
+
+ @Override
+ IAnnotationBinding resolveAnnotation(Annotation annotation) {
+ return (IAnnotationBinding)resolveCached(annotation, (n) -> resolveAnnotationImpl((Annotation)n));
+ }
+
+ IAnnotationBinding resolveAnnotationImpl(Annotation annotation) {
+ resolve();
+ IBinding recipient = null;
+ if (annotation.getParent() instanceof AnnotatableType annotatable) {
+ recipient = annotatable.resolveBinding();
+ } else if (annotation.getParent() instanceof FieldDeclaration fieldDeclaration) {
+ recipient = ((VariableDeclarationFragment)fieldDeclaration.fragments().get(0)).resolveBinding();
+ } else if (annotation.getParent() instanceof TypeDeclaration td) {
+ recipient = td.resolveBinding();
+ }
+ var javac = this.converter.domToJavac.get(annotation);
+ if (javac instanceof JCAnnotation jcAnnotation) {
+ return this.bindings.getAnnotationBinding(jcAnnotation.attribute, recipient);
+ }
+ return null;
+ }
+ @Override
+ IMemberValuePairBinding resolveMemberValuePair(MemberValuePair memberValuePair) {
+ resolve();
+ if (this.converter.domToJavac.get(memberValuePair) instanceof JCAssign assign &&
+ assign.lhs instanceof JCIdent ident && ident.sym instanceof MethodSymbol methodSymbol) {
+ return this.bindings.getMemberValuePairBinding(methodSymbol, null);
+ }
+ return null;
+ }
+
+ @Override
+ IBinding resolveReference(MethodRef ref) {
+ return resolveCached(ref, (n) -> resolveReferenceImpl((MethodRef)n));
+ }
+
+ private IBinding resolveReferenceImpl(MethodRef ref) {
+ resolve();
+ DocTreePath path = this.converter.findDocTreePath(ref);
+ if (path != null ) {
+ Element e = JavacTrees.instance(this.context).getElement(path);
+ if(e instanceof Symbol symbol) {
+ IBinding r1 = this.bindings.getBinding(symbol, null);
+ return r1;
+ }
+ TreePath dt = path.getTreePath();
+ if( dt != null) {
+ Tree t = dt.getLeaf();
+ if( t instanceof JCMethodDecl jcmd) {
+ MethodSymbol ms = jcmd.sym;
+ IBinding r1 = ms == null ? null : this.bindings.getBinding(ms, jcmd.type);
+ return r1;
+ }
+ }
+ }
+ if( ref.parameters() != null && ref.parameters().size() == 0) {
+ // exhaustively search for a similar method ref
+ DocTreePath[] possible = this.converter.searchRelatedDocTreePath(ref);
+ if( possible != null ) {
+ for( int i = 0; i < possible.length; i++ ) {
+ Element e = JavacTrees.instance(this.context).getElement(possible[i]);
+ if(e instanceof Symbol symbol) {
+ IBinding r1 = this.bindings.getBinding(symbol, null);
+ if( r1 != null )
+ return r1;
+ }
+ }
+ }
+ }
+ //
+ return null;
+ }
+
+ private IBinding getFieldAccessBinding(JCFieldAccess fieldAccess) {
+ JCFieldAccess jcfa2 = (fieldAccess.sym == null && fieldAccess.selected instanceof JCFieldAccess jcfa3) ? jcfa3 : fieldAccess;
+ if( jcfa2.sym != null ) {
+ com.sun.tools.javac.code.Type typeToUse = jcfa2.type;
+ IBinding bRet = this.bindings.getBinding(jcfa2.sym, typeToUse);
+ if(bRet == null && jcfa2.selected instanceof JCTypeApply) {
+ // ??? no idea if this is a good answer
+ typeToUse = jcfa2.sym.type;
+ }
+
+ if( jcfa2 != fieldAccess && bRet instanceof ITypeBinding itb ) {
+ String fieldAccessIdentifier = fieldAccess.getIdentifier().toString();
+ // If we changed the field access, we need to go one generation lower
+ Function func = bindings -> {
+ for( int i = 0; i < bindings.length; i++ ) {
+ String childName = bindings[i].getName();
+ if( childName.equals(fieldAccessIdentifier)) {
+ return bindings[i];
+ }
+ }
+ return null;
+ };
+ IBinding ret = func.apply(itb.getDeclaredTypes());
+ if( ret != null )
+ return ret;
+ ret = func.apply(itb.getDeclaredFields());
+ if( ret != null )
+ return ret;
+ ret = func.apply(itb.getDeclaredMethods());
+ if( ret != null )
+ return ret;
+ }
+ return bRet;
+ }
+ return null;
+ }
+ @Override
+ IBinding resolveReference(MemberRef ref) {
+ return resolveCached(ref, (n) -> resolveReferenceImpl((MemberRef)n));
+ }
+
+ private IBinding resolveReferenceImpl(MemberRef ref) {
+ resolve();
+ DocTreePath path = this.converter.findDocTreePath(ref);
+ if (path != null && JavacTrees.instance(this.context).getElement(path) instanceof Symbol symbol) {
+ return this.bindings.getBinding(symbol, null);
+ }
+ return null;
+ }
+ private static Symbol getRecoveredSymbol(com.sun.tools.javac.code.Type type) {
+ if (type instanceof ErrorType) {
+ try {
+ Field candidateSymbolField = type.getClass().getField("candidateSymbol");
+ candidateSymbolField.setAccessible(true);
+
+ Object symbolFieldValue = candidateSymbolField.get(type);
+ if (symbolFieldValue instanceof Symbol symbol) {
+ return symbol;
+ }
+ } catch (NoSuchFieldException | IllegalAccessException unused) {
+ // fall through to null
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public WorkingCopyOwner getWorkingCopyOwner() {
+ return this.owner;
+ }
+
+ @Override
+ Object resolveConstantExpressionValue(Expression expression) {
+ JCTree jcTree = this.converter.domToJavac.get(expression);
+ if (jcTree instanceof JCLiteral literal) {
+ return literal.getValue();
+ }
+ if (jcTree == null && expression.getParent() != null) {
+ jcTree = this.converter.domToJavac.get(expression.getParent());
+ if (jcTree == null) {
+ return null;
+ }
+ }
+ return TreeInfo.symbolFor(jcTree) instanceof VarSymbol varSymbol ? varSymbol.getConstantValue() : null;
+ }
+ @Override
+ boolean resolveBoxing(Expression expression) {
+ // TODO need to handle many different things here, very rudimentary
+ if( expression.getParent() instanceof MethodInvocation mi) {
+ IMethodBinding mb = resolveMethod(mi);
+ int foundArg = -1;
+ if( mb != null ) {
+ for( int i = 0; i < mi.arguments().size() && foundArg == -1; i++ ) {
+ if( mi.arguments().get(i) == expression) {
+ foundArg = i;
+ }
+ }
+ if( foundArg != -1 ) {
+ ITypeBinding[] tbs = mb.getParameterTypes();
+ if( tbs.length > foundArg) {
+ ITypeBinding foundType = tbs[foundArg];
+ if( expression instanceof NumberLiteral nl) {
+ if( isBoxedVersion(nl, foundType)) {
+ return true;
+ }
+ } else {
+ if( expression instanceof MethodInvocation inner) {
+ JavacMethodBinding mbInner = (JavacMethodBinding)resolveMethod(inner);
+ ITypeBinding retTypeInner = mbInner == null ? null : mbInner.getReturnType();
+ if( isBoxedVersion(retTypeInner, foundType)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isBoxedVersion(NumberLiteral unboxed, ITypeBinding boxed) {
+ if( boxed instanceof JavacTypeBinding boxedBind ) {
+ String boxedString = boxedBind.typeSymbol == null ? null : boxedBind.typeSymbol.toString();
+ if("java.lang.Integer".equals(boxedString)
+ || "java.lang.Float".equals(boxedString)
+ || "java.lang.Double".equals(boxedString)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private Map boxingMap = null;
+ private boolean isBoxedVersion(ITypeBinding unboxed, ITypeBinding boxed) {
+ if( boxingMap == null ) {
+ Map m = new HashMap();
+ m.put("java.lang.Boolean", "boolean");
+ m.put("java.lang.Byte", "byte");
+ m.put("java.lang.Character", "char");
+ m.put("java.lang.Float", "float");
+ m.put("java.lang.Integer", "int");
+ m.put("java.lang.Long", "long");
+ m.put("java.lang.Short", "short");
+ m.put("java.lang.Double", "double");
+ boxingMap = m;
+ }
+ if( boxed instanceof JavacTypeBinding boxedBind && unboxed instanceof JavacTypeBinding unboxedBind) {
+ String boxedString = boxedBind.typeSymbol == null ? null : boxedBind.typeSymbol.toString();
+ String unboxedString = unboxedBind.typeSymbol == null ? null : unboxedBind.typeSymbol.toString();
+ // TODO very rudimentary, fix it, add more
+ if( boxingMap.get(boxedString) != null ) {
+ if( unboxedString.equals(boxingMap.get(boxedString))) {
+ return true;
+ }
+ }
+ // Alternate case, they might be converting some types
+ if( boxingMap.keySet().contains(boxedString) && boxingMap.values().contains(unboxedString)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ @Override
+ boolean resolveUnboxing(Expression expression) {
+ Type t = null;
+ if( expression instanceof ClassInstanceCreation cic ) {
+ t = cic.getType();
+ }
+ if( t != null && expression.getParent() instanceof MethodInvocation mi) {
+ int foundArg = -1;
+ if( mi != null ) {
+ for( int i = 0; i < mi.arguments().size() && foundArg == -1; i++ ) {
+ if( mi.arguments().get(i) == expression) {
+ foundArg = i;
+ }
+ }
+ if( foundArg != -1 ) {
+ IMethodBinding mb = resolveMethod(mi);
+ ITypeBinding[] tbs = mb.getParameterTypes();
+ if( tbs.length > foundArg) {
+ ITypeBinding unboxed = tbs[foundArg];
+ ITypeBinding boxed = resolveType(t);
+ if( isBoxedVersion(unboxed, boxed)) {
+ return true;
+ }
+ } else if( tbs.length > 0 && mb.isVarargs()) {
+ ITypeBinding lastArg = tbs[tbs.length - 1];
+ if( lastArg.isArray()) {
+ ITypeBinding el = lastArg.getElementType();
+ if( el.isPrimitive()) {
+ if( isBoxedVersion(el, resolveType(t))) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ return false;
+ }
+ public boolean isRecoveringBindings() {
+ return isRecoveringBindings;
+ }
+}
diff --git a/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacCompilationUnitResolver.java b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacCompilationUnitResolver.java
new file mode 100644
index 00000000000..1701dd9a825
--- /dev/null
+++ b/org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacCompilationUnitResolver.java
@@ -0,0 +1,1194 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Red Hat, Inc. and others.
+ *
+ * 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
+ *******************************************************************************/
+package org.eclipse.jdt.core.dom;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.ISourceType;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
+import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+import org.eclipse.jdt.internal.compiler.util.Util;
+import org.eclipse.jdt.internal.core.CancelableNameEnvironment;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.dom.ICompilationUnitResolver;
+import org.eclipse.jdt.internal.core.util.BindingKeyParser;
+import org.eclipse.jdt.internal.javac.CachingClassSymbolClassReader;
+import org.eclipse.jdt.internal.javac.CachingJDKPlatformArguments;
+import org.eclipse.jdt.internal.javac.CachingJarsJavaFileManager;
+import org.eclipse.jdt.internal.javac.JavacProblemConverter;
+import org.eclipse.jdt.internal.javac.JavacUtils;
+import org.eclipse.jdt.internal.javac.ProcessorConfig;
+import org.eclipse.jdt.internal.javac.UnusedProblemFactory;
+import org.eclipse.jdt.internal.javac.UnusedTreeScanner;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.api.MultiTaskListener;
+import com.sun.tools.javac.code.Symbol.PackageSymbol;
+import com.sun.tools.javac.comp.CompileStates.CompileState;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.main.Option;
+import com.sun.tools.javac.parser.JavadocTokenizer;
+import com.sun.tools.javac.parser.Scanner;
+import com.sun.tools.javac.parser.ScannerFactory;
+import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
+import com.sun.tools.javac.parser.Tokens.TokenKind;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Context.Key;
+import com.sun.tools.javac.util.DiagnosticSource;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+
+/**
+ * Allows to create and resolve DOM ASTs using Javac
+ * @implNote Cannot move to another package because parent class is package visible only
+ */
+public class JavacCompilationUnitResolver implements ICompilationUnitResolver {
+
+ public static final String MOCK_NAME_FOR_CLASSES = "whatever_InvalidNameWE_HOP3_n00ne_will_Ever_use_in_real_file.java";
+ public static final Key