update jdt.core to I20221202-1800 for move of ecj to own project
+ move of ot-compiler sources
- adjust otdt package exports
+ add jdt.annotation optional requirement
diff --git a/org.eclipse.jdt.core.compiler.batch/.classpath b/org.eclipse.jdt.core.compiler.batch/.classpath
new file mode 100644
index 0000000..ae1b359
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+ <attributes>
+ <attribute name="module" value="true"/>
+ <attribute name="limit-modules" value="java.base"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.compiler.batch/.project b/org.eclipse.jdt.core.compiler.batch/.project
new file mode 100644
index 0000000..c5f33a4
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.jdt.core.compiler.batch</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jdt.core.compiler.batch/.settings/.api_filters b/org.eclipse.jdt.core.compiler.batch/.settings/.api_filters
new file mode 100644
index 0000000..a69e00e
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.settings/.api_filters
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jdt.core.compiler.batch" version="2">
+ <resource path="META-INF/MANIFEST.MF" type="org.eclipse.jdt.core.BuildJarIndex">
+ <filter id="305324134">
+ <message_arguments>
+ <message_argument value="org.eclipse.jdt.core.BuildJarIndex"/>
+ <message_argument value="org.eclipse.jdt.core.compiler.batch_3.33.0"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="META-INF/MANIFEST.MF" type="org.eclipse.jdt.core.CheckDebugAttributes">
+ <filter id="305324134">
+ <message_arguments>
+ <message_argument value="org.eclipse.jdt.core.CheckDebugAttributes"/>
+ <message_argument value="org.eclipse.jdt.core.compiler.batch_3.33.0"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java" type="org.eclipse.jdt.core.compiler.batch.BatchCompiler">
+ <filter id="1108344834">
+ <message_arguments>
+ <message_argument value="3.4"/>
+ <message_argument value="3.33"/>
+ <message_argument value="org.eclipse.jdt.core.compiler.batch.BatchCompiler"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..796937c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding//scripts/ecj.1=ISO-8859-1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..19d7cb9
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,395 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+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=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=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.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+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.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.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.uninternedIdentityComparison=enabled
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=warning
+org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+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_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+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_selector_in_method_invocation=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_type_declaration=16
+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.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=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_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_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_method_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.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.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=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=120
+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.format_guardian_clause_on_one_line=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_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=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+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_opening_brace_in_array_initializer=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_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=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_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_superinterfaces=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_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_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_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_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=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_binary_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_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_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_superinterfaces=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_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_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_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_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_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_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.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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+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_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+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.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..d05be54
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,113 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.format_comment=false
+cleanup.format_javadoc=true
+cleanup.format_multi_line_comment=true
+cleanup.format_single_line_comment=true
+cleanup.format_source_code=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.use_blocks=false
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=_Numbat
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_Jdtcore [built-in + Indent switch body + LineWidth\:120]
+formatter_settings_version=11
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.overrideannotation=true
+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=false
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=false
+sp_cleanup.add_missing_override_annotations_interface_methods=false
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_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_casts=false
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.update_ibm_copyright_to_current_year=true
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.pde.api.tools.prefs b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000..6f7536a
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,94 @@
+#Fri May 21 10:24:07 EDT 2010
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_JAVADOC_TAG=Warning
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Warning
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=false
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.pde.prefs b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..9251e60
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,35 @@
+#Fri May 21 10:24:08 EDT 2010
+compilers.f.unresolved-features=1
+compilers.f.unresolved-plugins=1
+compilers.incompatible-environment=1
+compilers.p.build=1
+compilers.p.build.bin.includes=1
+compilers.p.build.encodings=2
+compilers.p.build.java.compiler=2
+compilers.p.build.java.compliance=2
+compilers.p.build.missing.output=2
+compilers.p.build.output.library=2
+compilers.p.build.source.library=2
+compilers.p.build.src.includes=1
+compilers.p.deprecated=1
+compilers.p.discouraged-class=1
+compilers.p.internal=1
+compilers.p.missing-bundle-classpath-entries=2
+compilers.p.missing-packages=2
+compilers.p.missing-version-export-package=2
+compilers.p.missing-version-import-package=2
+compilers.p.missing-version-require-bundle=2
+compilers.p.no-required-att=0
+compilers.p.not-externalized-att=2
+compilers.p.unknown-attribute=1
+compilers.p.unknown-class=1
+compilers.p.unknown-element=1
+compilers.p.unknown-identifier=1
+compilers.p.unknown-resource=1
+compilers.p.unresolved-ex-points=1
+compilers.p.unresolved-import=0
+compilers.s.create-docs=false
+compilers.s.doc-folder=doc
+compilers.s.open-tags=1
+compilers.use-project=true
+eclipse.preferences.version=1
diff --git a/org.eclipse.jdt.core.compiler.batch/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.compiler.batch/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..0f72df9
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/META-INF/MANIFEST.MF
@@ -0,0 +1,48 @@
+Manifest-Version: 1.0
+Main-Class: org.eclipse.jdt.internal.compiler.batch.Main
+Bundle-ManifestVersion: 2
+Bundle-Name: Eclipse Compiler for Java(TM)
+Bundle-SymbolicName: org.eclipse.jdt.core.compiler.batch
+Bundle-Version: 3.33.0.qualifier
+Bundle-ClassPath: .
+Bundle-Vendor: Eclipse.org
+Automatic-Module-Name: org.eclipse.jdt.core.compiler.batch
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Require-Bundle: org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional;visibility:=reexport
+Export-Package: org.eclipse.jdt.core,
+ org.eclipse.jdt.core.compiler,
+ org.eclipse.jdt.core.compiler.batch,
+ org.eclipse.jdt.internal.antadapter;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.apt.dispatch;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.apt.model;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.apt.util;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.ast;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.batch;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.classfmt;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.codegen;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.env;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.flow;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.impl;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.lookup;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.parser;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.parser.diagnose;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.problem;x-friends:="org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.tool;x-friends:="org.eclipse.jdt.compiler.tool.tests,org.eclipse.jdt.core",
+ org.eclipse.jdt.internal.compiler.util;x-friends:="org.eclipse.jdt.core.internal.tools,org.eclipse.jdt.core",
+ org.eclipse.objectteams.otdt.internal.core.compiler.ast;x-friends:="org.eclipse.jdt.core,org.eclipse.jdt.core.tests.compiler",
+ org.eclipse.objectteams.otdt.internal.core.compiler.bytecode;x-friends:="org.eclipse.objectteams.otdt.compiler.adaptor",
+ org.eclipse.objectteams.otdt.internal.core.compiler.control;x-friends:="org.eclipse.objectteams.otdt.tests,org.eclipse.objectteams.otdt.apt",
+ org.eclipse.objectteams.otdt.internal.core.compiler.lifting;x-friends:="org.eclipse.objectteams.otdt.compiler.adaptor",
+ org.eclipse.objectteams.otdt.internal.core.compiler.lookup;x-friends:="org.eclipse.objectteams.otdt.compiler.adaptor",
+ org.eclipse.objectteams.otdt.internal.core.compiler.mappings;x-internal:=true,
+ org.eclipse.objectteams.otdt.internal.core.compiler.model;x-friends:="org.eclipse.objectteams.otdt.apt",
+ org.eclipse.objectteams.otdt.internal.core.compiler.problem;x-internal:=true,
+ org.eclipse.objectteams.otdt.internal.core.compiler.smap;x-friends:="org.eclipse.objectteams.otdt.tests",
+ org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance;x-friends:="org.eclipse.objectteams.otdt.compiler.adaptor",
+ org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer;x-internal:=true,
+ org.eclipse.objectteams.otdt.internal.core.compiler.util;x-internal:=true,
+ org.eclipse.objectteams.otdt.core.compiler;x-friends:="org.eclipse.jdt.core,org.eclipse.objectteams.otdt",
+ org.eclipse.objectteams.otdt.core.exceptions;x-friends:="org.eclipse.jdt.core",
+ META-INF.services
diff --git a/org.eclipse.jdt.core.compiler.batch/META-INF/eclipse.inf b/org.eclipse.jdt.core.compiler.batch/META-INF/eclipse.inf
new file mode 100644
index 0000000..4dc37a0
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/META-INF/eclipse.inf
@@ -0,0 +1,2 @@
+jarprocessor.exclude.children=true
+jarprocessor.exclude.pack=true
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.compiler.batch/META-INF/services/javax.tools.JavaCompiler b/org.eclipse.jdt.core.compiler.batch/META-INF/services/javax.tools.JavaCompiler
new file mode 100644
index 0000000..7fb91cf
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/META-INF/services/javax.tools.JavaCompiler
@@ -0,0 +1 @@
+org.eclipse.jdt.internal.compiler.tool.EclipseCompiler #Eclipse compiler
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.compiler.batch/about.html b/org.eclipse.jdt.core.compiler.batch/about.html
new file mode 100644
index 0000000..164f781
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>About</title>
+</head>
+<body lang="EN-US">
+ <h2>About This Content</h2>
+
+ <p>November 30, 2017</p>
+ <h3>License</h3>
+
+ <p>
+ The Eclipse Foundation makes available all content in this plug-in
+ ("Content"). Unless otherwise indicated below, the Content
+ is provided to you under the terms and conditions of the Eclipse
+ Public License Version 2.0 ("EPL"). A copy of the EPL is
+ available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ </p>
+
+ <p>
+ If you did not receive this Content directly from the Eclipse
+ Foundation, the Content is being redistributed by another party
+ ("Redistributor") and different terms and conditions may
+ apply to your use of any object code in the Content. Check the
+ Redistributor's license that was provided with the Content. If no such
+ license exists, contact the Redistributor. Unless otherwise indicated
+ below, the terms and conditions of the EPL still apply to any source
+ code in the Content and such source code may be obtained at <a
+ href="http://www.eclipse.org/">http://www.eclipse.org</a>.
+ </p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.compiler.batch/build.properties b/org.eclipse.jdt.core.compiler.batch/build.properties
new file mode 100644
index 0000000..a57901f
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/build.properties
@@ -0,0 +1,24 @@
+###############################################################################
+# Copyright (c) 2000, 2022 IBM Corporation 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
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+customBuildCallbacks=customBuildCallbacks.xml
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html
+src.includes = about.html,\
+ META-INF/services/,\
+ META-INF/eclipse.inf,\
+ grammar/
+jars.extra.classpath = lib/javax18api.jar,platform:/plugin/org.apache.ant/lib/ant.jar
diff --git a/org.eclipse.jdt.core/grammar/java.g b/org.eclipse.jdt.core.compiler.batch/grammar/java.g
similarity index 100%
rename from org.eclipse.jdt.core/grammar/java.g
rename to org.eclipse.jdt.core.compiler.batch/grammar/java.g
diff --git a/org.eclipse.jdt.core.compiler.batch/lib/javax18api.jar b/org.eclipse.jdt.core.compiler.batch/lib/javax18api.jar
new file mode 100644
index 0000000..65c0b11
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/lib/javax18api.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.compiler.batch/pom.xml b/org.eclipse.jdt.core.compiler.batch/pom.xml
new file mode 100644
index 0000000..141fd75
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/pom.xml
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2012, 2021 Eclipse Foundation and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Igor Fedorenko - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>eclipse.jdt.core</artifactId>
+ <groupId>org.eclipse.jdt</groupId>
+ <version>4.27.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.eclipse.jdt.core.compiler.batch</artifactId>
+ <version>3.33.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+
+ <properties>
+ <defaultSigning-excludeInnerJars>true</defaultSigning-excludeInnerJars>
+ <code.ignoredWarnings>-warn:+fieldHiding,-unavoidableGenericProblems</code.ignoredWarnings>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>prepare-package</phase>
+ <configuration>
+ <target>
+ <replace token="bundle_qualifier," value="${buildQualifier}," dir="${project.build.directory}/classes">
+ <include name="org/eclipse/jdt/internal/compiler/batch/messages.properties"/>
+ </replace>
+ <replace token="bundle_version" value="${unqualifiedVersion}" dir="${project.build.directory}/classes">
+ <include name="org/eclipse/jdt/internal/compiler/batch/messages.properties"/>
+ </replace>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- XXX ???
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-batch-compiler-source</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/scripts/source</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${project.basedir}/scripts/source</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ -->
+ <!-- XXX ???
+ <plugin>
+ <groupId>org.eclipse.tycho.extras</groupId>
+ <artifactId>tycho-custom-bundle-plugin</artifactId>
+ <version>${tycho.version}</version>
+ <executions>
+ <execution>
+ <id>batch-compiler-src</id>
+ <phase>package</phase>
+ <goals>
+ <goal>custom-bundle</goal>
+ </goals>
+ <configuration>
+ <archive>
+ <addMavenDescriptor>false</addMavenDescriptor>
+ </archive>
+ <bundleLocation>${project.build.directory}/scripts/source</bundleLocation>
+ <classifier>batch-compiler-src</classifier>
+ <fileSets>
+ <fileSet>
+ <directory>${project.basedir}/batch</directory>
+ <excludes>
+ <exclude>org/eclipse/jdt/internal/compiler/batch/messages.properties</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}/classes</directory>
+ <includes>
+ <include>org/eclipse/jdt/internal/compiler/batch/messages.properties</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/compiler</directory>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/antadapter</directory>
+ <excludes>
+ <exclude>org/eclipse/jdt/core/CheckDebugAttributes.java</exclude>
+ <exclude>org/eclipse/jdt/core/BuildJarIndex.java</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/../org.eclipse.jdt.compiler.tool/src</directory>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/../org.eclipse.jdt.compiler.apt/src</directory>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/scripts</directory>
+ <includes>
+ <include>about.html</include>
+ <include>build.xml</include>
+ <include>ecj.1</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}</directory>
+ <includes>
+ <include>scripts/binary/**</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/../org.eclipse.jdt.compiler.tool/lib</directory>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+ </configuration>
+ </execution>
+ <execution>
+ <id>batch-compiler</id>
+ <phase>package</phase>
+ <goals>
+ <goal>custom-bundle</goal>
+ </goals>
+ <configuration>
+ <archive>
+ <addMavenDescriptor>false</addMavenDescriptor>
+ </archive>
+ <bundleLocation>${project.basedir}/scripts/binary</bundleLocation>
+ <classifier>batch-compiler</classifier>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}/jdtCompilerAdapter.jar-classes</directory>
+ <includes>
+ <include>META-INF/eclipse.inf</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.basedir}/scripts</directory>
+ <includes>
+ <include>about.html</include>
+ <include>ecj.1</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.directory}/classes</directory>
+ <includes>
+ <include>org/eclipse/jdt/internal/compiler/**</include>
+ <include>org/eclipse/jdt/core/compiler/**</include>
+ </includes>
+ <excludes>
+ <exclude>**/package.htm*</exclude>
+ <exclude>org/eclipse/jdt/core/compiler/CompilationParticipant*.class</exclude>
+ <exclude>org/eclipse/jdt/core/compiler/BuildContext.class</exclude>
+ <exclude>org/eclipse/jdt/core/compiler/IScanner.class</exclude>
+ <exclude>org/eclipse/jdt/core/compiler/ITerminalSymbols*.class</exclude>
+ <exclude>org/eclipse/jdt/core/compiler/ReconcileContext*.class</exclude>
+ <exclude>org/eclipse/jdt/internal/compiler/DocumentElementParser*.class</exclude>
+ <exclude>org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.class</exclude>
+ <exclude>org/eclipse/jdt/internal/compiler/ISourceElementRequestor*.class</exclude>
+ <exclude>org/eclipse/jdt/internal/compiler/SourceElementParser*.class</exclude>
+ <exclude>org/eclipse/jdt/internal/compiler/SourceElementRequestorAdapter*.class</exclude>
+ <exclude>org/eclipse/jdt/internal/compiler/SourceJavadocParser*.class</exclude>
+ <exclude>org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter*.class</exclude>
+ </excludes>
+ </fileSet>
+ </fileSets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ -->
+ <plugin>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>tycho-p2-plugin</artifactId>
+ <version>${tycho.version}</version>
+ <configuration>
+ <baselineMode>warn</baselineMode>
+ <baselineReplace>common</baselineReplace>
+ </configuration>
+ <executions>
+ <execution>
+ <id>attached-p2-metadata</id>
+ <phase>package</phase>
+ <goals>
+ <goal>p2-metadata</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>3.2.0</version>
+ <executions>
+ <!--
+ Replace '\' Windows file separators by '/' in order to expand the new property 'compiler-message-properties'
+ into a string literal in Maven Enforcer rule 'evaluateBeanshell' further below
+ -->
+ <execution>
+ <id>compiler-message-properties</id>
+ <goals>
+ <goal>regex-property</goal>
+ </goals>
+ <configuration>
+ <name>compiler-message-properties</name>
+ <value>${project.basedir}/src/org/eclipse/jdt/internal/compiler/batch/messages.properties</value>
+ <regex>\\</regex>
+ <replacement>/</replacement>
+ <failIfNoMatch>false</failIfNoMatch>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>no-tabs-in-compiler-messages</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <evaluateBeanshell>
+ <message>
+ Compiler message resource file ${compiler-message-properties} must not contain tab characters, please use spaces instead!
+ </message>
+ <condition><![CDATA[
+ FileReader fileReader = new FileReader("${compiler-message-properties}");
+ BufferedReader bufferReader = new BufferedReader(fileReader);
+ boolean containsTab = false;
+ String line;
+ while((line = bufferReader.readLine()) != null) {
+ if (line.contains("\t")) {
+ if (!containsTab) {
+ System.out.println("Lines containing tab characters detected in resource file:");
+ containsTab = true;
+ }
+ System.out.println(line);
+ }
+ }
+ fileReader.close();
+ bufferReader.close();
+ !containsTab
+ ]]></condition>
+ </evaluateBeanshell>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/org.eclipse.jdt.core/scripts/GenerateParserScript.java b/org.eclipse.jdt.core.compiler.batch/scripts/GenerateParserScript.java
similarity index 98%
rename from org.eclipse.jdt.core/scripts/GenerateParserScript.java
rename to org.eclipse.jdt.core.compiler.batch/scripts/GenerateParserScript.java
index 8089bf8..d510395 100644
--- a/org.eclipse.jdt.core/scripts/GenerateParserScript.java
+++ b/org.eclipse.jdt.core.compiler.batch/scripts/GenerateParserScript.java
@@ -23,7 +23,7 @@
public static void main(String[] args) throws IOException, InterruptedException {
File grammarDir = new File("../grammar");
- File parserDir = new File("../compiler/org/eclipse/jdt/internal/compiler/parser");
+ File parserDir = new File("../src/org/eclipse/jdt/internal/compiler/parser");
String jikespg = System.getProperty("JIKESPG");
assertTrue(jikespg != null);
diff --git a/org.eclipse.jdt.core/scripts/build-parser.launch b/org.eclipse.jdt.core.compiler.batch/scripts/build-parser.launch
similarity index 83%
rename from org.eclipse.jdt.core/scripts/build-parser.launch
rename to org.eclipse.jdt.core.compiler.batch/scripts/build-parser.launch
index 55abf6b..4896c04 100644
--- a/org.eclipse.jdt.core/scripts/build-parser.launch
+++ b/org.eclipse.jdt.core.compiler.batch/scripts/build-parser.launch
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ant.AntLaunchConfigurationType">
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
- <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser" type="2"/> </resources>}"/>
+ <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser" type="2"/> </resources>}"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
- <listEntry value="/eclipse.jdt.core/org.eclipse.jdt.core/scripts/build-parser.xml"/>
+ <listEntry value="/eclipse.jdt.core/org.eclipse.jdt.core.compiler.batch/scripts/build-parser.xml"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="1"/>
@@ -12,9 +12,9 @@
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.ant.internal.launching.remote.InternalAntRunner"/>
- <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jdt.core"/>
+ <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jdt.core.compiler.batch"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
- <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/org.eclipse.jdt.core/scripts/build-parser.xml}"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/org.eclipse.jdt.core.compiler.batch/scripts/build-parser.xml}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-DJIKESPG=${JIKESPG}"/>
<stringAttribute key="process_factory_id" value="org.eclipse.ant.ui.remoteAntProcessFactory"/>
</launchConfiguration>
diff --git a/org.eclipse.jdt.core/scripts/build-parser.xml b/org.eclipse.jdt.core.compiler.batch/scripts/build-parser.xml
similarity index 98%
rename from org.eclipse.jdt.core/scripts/build-parser.xml
rename to org.eclipse.jdt.core.compiler.batch/scripts/build-parser.xml
index 8d7c2a1..db649fc 100644
--- a/org.eclipse.jdt.core/scripts/build-parser.xml
+++ b/org.eclipse.jdt.core.compiler.batch/scripts/build-parser.xml
@@ -24,7 +24,6 @@
<javac srcdir="${basedir}" includes="GenerateParserScript.java" destdir="${basedir}"
classpath="${basedir}/../bin"
debuglevel="lines,source"
- debug="true"
source="1.8"
target="1.8">
<compilerarg/>
diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/JDTCompilerAdapter.java
similarity index 100%
rename from org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/JDTCompilerAdapter.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CategorizedProblem.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/CategorizedProblem.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CategorizedProblem.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/CategorizedProblem.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/CharOperation.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/CharOperation.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CompilationProgress.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/CompilationProgress.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CompilationProgress.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/CompilationProgress.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/IProblem.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/IProblem.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/InvalidInputException.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/InvalidInputException.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/InvalidInputException.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/InvalidInputException.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/SubwordMatcher.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/SubwordMatcher.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/SubwordMatcher.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/SubwordMatcher.java
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java
similarity index 100%
rename from org.eclipse.jdt.core/batch/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/core/compiler/batch/package.html b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/batch/package.html
similarity index 100%
rename from org.eclipse.jdt.core/batch/org/eclipse/jdt/core/compiler/batch/package.html
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/batch/package.html
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/package.html b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/package.html
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/package.html
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/package.html
diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/AntAdapterMessages.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/antadapter/AntAdapterMessages.java
similarity index 100%
rename from org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/AntAdapterMessages.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/antadapter/AntAdapterMessages.java
diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/messages.properties b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/antadapter/messages.properties
similarity index 100%
rename from org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/messages.properties
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/antadapter/messages.properties
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ASTVisitor.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ASTVisitor.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/AbstractAnnotationProcessorManager.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/AbstractAnnotationProcessorManager.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/AbstractAnnotationProcessorManager.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/AbstractAnnotationProcessorManager.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFile.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFilePool.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFilePool.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFilePool.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ClassFilePool.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/CompilationResult.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/CompilationResult.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/Compiler.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/Compiler.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ConfigurableOption.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ConfigurableOption.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ConfigurableOption.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ConfigurableOption.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/DefaultErrorHandlingPolicies.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/GenericAstVisitor.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/GenericAstVisitor.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/GenericAstVisitor.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/GenericAstVisitor.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ICompilerRequestor.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IDebugRequestor.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/IDebugRequestor.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IDebugRequestor.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/IDebugRequestor.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/IErrorHandlingPolicy.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblemFactory.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/IProblemFactory.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/IProblemFactory.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/IProblemFactory.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ProcessTaskManager.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ProcessTaskManager.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ProcessTaskManager.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ProcessTaskManager.java
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ReadManager.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ReadManager.java
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ReadManager.java
rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ReadManager.java
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java
new file mode 100644
index 0000000..9e18a74
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java
@@ -0,0 +1,290 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2020 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.apt.model.ElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.Factory;
+import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.RecordComponent;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * This class is used to visit the JDT compiler internal AST to discover annotations,
+ * in the course of dispatching to annotation processors.
+ */
+public class AnnotationDiscoveryVisitor extends ASTVisitor {
+ final BaseProcessingEnvImpl _env;
+ final Factory _factory;
+ /**
+ * Collects a many-to-many map of annotation types to
+ * the elements they appear on.
+ */
+ final ManyToMany<TypeElement, Element> _annoToElement;
+
+ public AnnotationDiscoveryVisitor(BaseProcessingEnvImpl env) {
+ _env = env;
+ _factory = env.getFactory();
+ _annoToElement = new ManyToMany<>();
+ }
+
+ @Override
+ public boolean visit(Argument argument, BlockScope scope) {
+ Annotation[] annotations = argument.annotations;
+ ReferenceContext referenceContext = scope.referenceContext();
+ if (referenceContext instanceof AbstractMethodDeclaration) {
+ MethodBinding binding = ((AbstractMethodDeclaration) referenceContext).binding;
+ if (binding != null) {
+ TypeDeclaration typeDeclaration = scope.referenceType();
+ typeDeclaration.binding.resolveTypesFor(binding);
+ if (argument.binding != null) {
+ argument.binding = new AptSourceLocalVariableBinding(argument.binding, binding);
+ }
+ }
+ if (annotations != null && argument.binding != null) {
+ this.resolveAnnotations(
+ scope,
+ annotations,
+ argument.binding);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
+ Annotation[] annotations = constructorDeclaration.annotations;
+ if (annotations != null) {
+ MethodBinding constructorBinding = constructorDeclaration.binding;
+ if (constructorBinding == null) {
+ return false;
+ }
+ ((SourceTypeBinding) constructorBinding.declaringClass).resolveTypesFor(constructorBinding);
+ this.resolveAnnotations(
+ constructorDeclaration.scope,
+ annotations,
+ constructorBinding);
+ }
+
+ TypeParameter[] typeParameters = constructorDeclaration.typeParameters;
+ if (typeParameters != null) {
+ int typeParametersLength = typeParameters.length;
+ for (int i = 0; i < typeParametersLength; i++) {
+ typeParameters[i].traverse(this, constructorDeclaration.scope);
+ }
+ }
+
+ Argument[] arguments = constructorDeclaration.arguments;
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ for (int i = 0; i < argumentLength; i++) {
+ arguments[i].traverse(this, constructorDeclaration.scope);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
+ Annotation[] annotations = fieldDeclaration.annotations;
+ if (annotations != null) {
+ FieldBinding fieldBinding = fieldDeclaration.binding;
+ if (fieldBinding == null) {
+ return false;
+ }
+ ((SourceTypeBinding) fieldBinding.declaringClass).resolveTypeFor(fieldBinding);
+ if (fieldDeclaration.binding == null) {
+ return false;
+ }
+ this.resolveAnnotations(scope, annotations, fieldBinding);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(RecordComponent recordComponent, BlockScope scope) {
+ Annotation[] annotations = recordComponent.annotations;
+ if (annotations != null) {
+ RecordComponentBinding recordComponentBinding = recordComponent.binding;
+ if (recordComponentBinding == null) {
+ return false;
+ }
+ ((SourceTypeBinding) recordComponentBinding.declaringRecord).resolveTypeFor(recordComponentBinding);
+ if (recordComponent.binding == null) {
+ return false;
+ }
+ this.resolveAnnotations(scope, annotations, recordComponentBinding);
+ }
+ return false;
+ }
+ @Override
+ public boolean visit(TypeParameter typeParameter, ClassScope scope) {
+ Annotation[] annotations = typeParameter.annotations;
+ if (annotations != null) {
+ TypeVariableBinding binding = typeParameter.binding;
+ if (binding == null) {
+ return false;
+ }
+ this.resolveAnnotations(scope.referenceContext.initializerScope, annotations, binding);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(TypeParameter typeParameter, BlockScope scope) {
+ Annotation[] annotations = typeParameter.annotations;
+ if (annotations != null) {
+ TypeVariableBinding binding = typeParameter.binding;
+ if (binding == null) {
+ return false;
+ }
+ // when we get here, it is guaranteed that class type parameters are connected, but method type parameters may not be.
+ MethodBinding methodBinding = (MethodBinding) binding.declaringElement;
+ ((SourceTypeBinding) methodBinding.declaringClass).resolveTypesFor(methodBinding);
+ this.resolveAnnotations(scope, annotations, binding);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
+ Annotation[] annotations = methodDeclaration.annotations;
+ if (annotations != null) {
+ MethodBinding methodBinding = methodDeclaration.binding;
+ if (methodBinding == null) {
+ return false;
+ }
+ ((SourceTypeBinding) methodBinding.declaringClass).resolveTypesFor(methodBinding);
+ this.resolveAnnotations(
+ methodDeclaration.scope,
+ annotations,
+ methodBinding);
+ }
+
+ TypeParameter[] typeParameters = methodDeclaration.typeParameters;
+ if (typeParameters != null) {
+ int typeParametersLength = typeParameters.length;
+ for (int i = 0; i < typeParametersLength; i++) {
+ typeParameters[i].traverse(this, methodDeclaration.scope);
+ }
+ }
+
+ Argument[] arguments = methodDeclaration.arguments;
+ if (arguments != null) {
+ int argumentLength = arguments.length;
+ for (int i = 0; i < argumentLength; i++) {
+ arguments[i].traverse(this, methodDeclaration.scope);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
+ SourceTypeBinding binding = memberTypeDeclaration.binding;
+ if (binding == null) {
+ return false;
+ }
+ Annotation[] annotations = memberTypeDeclaration.annotations;
+ if (annotations != null) {
+ this.resolveAnnotations(
+ memberTypeDeclaration.staticInitializerScope,
+ annotations,
+ binding);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
+ SourceTypeBinding binding = typeDeclaration.binding;
+ if (binding == null) {
+ return false;
+ }
+ Annotation[] annotations = typeDeclaration.annotations;
+ if (annotations != null) {
+ this.resolveAnnotations(
+ typeDeclaration.staticInitializerScope,
+ annotations,
+ binding);
+ }
+ return true;
+ }
+ @Override
+ public boolean visit(ModuleDeclaration module, CompilationUnitScope scope) {
+ ModuleBinding binding = module.binding;
+ if (binding == null) {
+ return false;
+ }
+ //module.resolveTypeDirectives(scope);
+ // The above call also resolvesAnnotations <=== actually this doesn't populate _annoToElement which is what we need
+
+ Annotation[] annotations = module.annotations;
+ if (annotations != null) {
+ this.resolveAnnotations(module.scope,
+ annotations,
+ binding);
+ }
+ return true;
+ }
+
+ private void resolveAnnotations(BlockScope scope, Annotation[] annotations, Binding currentBinding) {
+
+ int length = annotations == null ? 0 : annotations.length;
+ if (length == 0)
+ return;
+
+ boolean old = scope.insideTypeAnnotation;
+ scope.insideTypeAnnotation = true;
+ currentBinding.getAnnotationTagBits();
+ scope.insideTypeAnnotation = old;
+ ElementImpl element = (ElementImpl) _factory.newElement(currentBinding);
+ AnnotationBinding [] annotationBindings = element.getPackedAnnotationBindings(); // discovery is never in terms of repeating annotation.
+ for (AnnotationBinding binding : annotationBindings) {
+ ReferenceBinding annotationType = binding.getAnnotationType();
+ if (binding != null
+ && Annotation.isAnnotationTargetAllowed(scope, annotationType, currentBinding)
+ ) { // binding should be resolved, but in case it's not, ignore it: it could have been wrapped into a container.
+ TypeElement anno = (TypeElement)_factory.newElement(annotationType);
+ _annoToElement.put(anno, element);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java
new file mode 100644
index 0000000..ae557e3
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2007 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
+
+public class AptProblem extends DefaultProblem {
+
+ // The batch compiler does not depend on org.eclipse.jdt.apt.pluggable.core; this
+ // is just an arbitrary string to it, namespace notwithstanding. However, the IDE
+ // cares about the fact that this string is registered as a marker ID by the
+ // org.eclipse.jdt.apt.pluggable.core plug-in.
+ private static final String MARKER_ID = "org.eclipse.jdt.apt.pluggable.core.compileProblem"; //$NON-NLS-1$
+
+ /** May be null, if it was not possible to identify problem context */
+ public final ReferenceContext _referenceContext;
+
+ public AptProblem(
+ ReferenceContext referenceContext,
+ char[] originatingFileName,
+ String message,
+ int id,
+ String[] stringArguments,
+ int severity,
+ int startPosition,
+ int endPosition,
+ int line,
+ int column)
+ {
+ super(originatingFileName,
+ message,
+ id,
+ stringArguments,
+ severity,
+ startPosition,
+ endPosition,
+ line,
+ column);
+ _referenceContext = referenceContext;
+ }
+
+ @Override
+ public int getCategoryID() {
+ return CAT_UNSPECIFIED;
+ }
+
+ @Override
+ public String getMarkerType() {
+ return MARKER_ID;
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java
new file mode 100644
index 0000000..9976019
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2018 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * This class is the central dispatch point for Java 6 annotation processing.
+ * This is created and configured by the JDT core; specifics depend on how
+ * compilation is being performed, ie from the command line, via the Tool
+ * interface, or within the IDE. This class manages the discovery of annotation
+ * processors and other information spanning multiple rounds of processing;
+ * context that is valid only within a single round is managed by
+ * {@link RoundDispatcher}. There may be multiple instances of this class;
+ * there is in general one of these for every Compiler that has annotation
+ * processing enabled. Within the IDE there will typically be one for every
+ * Java project, because each project potentially has a separate processor path.
+ *
+ * TODO: do something useful with _supportedOptions and _supportedAnnotationTypes.
+ */
+public abstract class BaseAnnotationProcessorManager extends AbstractAnnotationProcessorManager
+ implements IProcessorProvider
+{
+
+ protected PrintWriter _out;
+ protected PrintWriter _err;
+ protected BaseProcessingEnvImpl _processingEnv;
+ public boolean _isFirstRound = true;
+
+ /**
+ * The list of processors that have been loaded so far. A processor on this
+ * list has been initialized, but may not yet have been called to process().
+ */
+ protected List<ProcessorInfo> _processors = new ArrayList<>();
+
+ // Tracing
+ protected boolean _printProcessorInfo = false;
+ protected boolean _printRounds = false;
+ protected int _round;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configure(org.eclipse.jdt.internal.compiler.batch.Main, java.lang.String[])
+ */
+ @Override
+ public void configure(Object batchCompiler, String[] options) {
+ // Implemented by BatchAnnotationProcessorManager.
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configureFromPlatform(org.eclipse.jdt.internal.compiler.Compiler, java.lang.Object)
+ */
+ @Override
+ public void configureFromPlatform(Compiler compiler, Object compilationUnitLocator, Object javaProject, boolean isTestCode) {
+ // Implemented by IdeAnnotationProcessorManager.
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<ProcessorInfo> getDiscoveredProcessors() {
+ return _processors;
+ }
+
+ @Override
+ public ICompilationUnit[] getDeletedUnits() {
+ return _processingEnv.getDeletedUnits();
+ }
+
+ @Override
+ public ICompilationUnit[] getNewUnits() {
+ return _processingEnv.getNewUnits();
+ }
+
+ @Override
+ public ReferenceBinding[] getNewClassFiles() {
+ return _processingEnv.getNewClassFiles();
+ }
+
+ @Override
+ public void reset() {
+ _processingEnv.reset();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setErr(java.io.PrintWriter)
+ */
+ @Override
+ public void setErr(PrintWriter err) {
+ _err = err;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setOut(java.io.PrintWriter)
+ */
+ @Override
+ public void setOut(PrintWriter out) {
+ _out = out;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setProcessors(java.lang.Object[])
+ */
+ @Override
+ public void setProcessors(Object[] processors) {
+ // Only meaningful in batch mode.
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * A single "round" of processing, in the sense implied in
+ * {@link javax.annotation.processing.Processor}.
+ * <p>
+ * The Java 6 Processor spec contains ambiguities about how processors that support "*" are
+ * handled. Eclipse tries to match Sun's implementation in javac. What that actually does is
+ * analogous to inspecting the set of annotions found in the root units and adding an
+ * "imaginary" annotation if the set is empty. Processors are then called in order of discovery;
+ * for each processor, the intersection between the set of root annotations and the set of
+ * annotations the processor supports is calculated, and if it is non-empty, the processor is
+ * called. If the processor returns <code>true</code> then the intersection (including the
+ * imaginary annotation if one exists) is removed from the set of root annotations and the loop
+ * continues, until the set is empty. Of course, the imaginary annotation is not actually
+ * included in the set of annotations passed in to the processor. A processor's process() method
+ * is not called until its intersection set is non-empty, but thereafter it is called on every
+ * round. Note that even if a processor is not called in the first round, if it is called in
+ * subsequent rounds, it will be called in the order in which the processors were discovered,
+ * rather than being added to the end of the list.
+ */
+ @Override
+ public void processAnnotations(CompilationUnitDeclaration[] units, ReferenceBinding[] referenceBindings, boolean isLastRound) {
+ if (units != null) {
+ for (CompilationUnitDeclaration declaration : units) {
+ if (declaration != null && declaration.scope != null) {
+ ModuleBinding m = declaration.scope.module();
+ if (m != null) {
+ _processingEnv._current_module = m;
+ break;
+ }
+ }
+ }
+ }
+ RoundEnvImpl roundEnv = new RoundEnvImpl(units, referenceBindings, isLastRound, _processingEnv);
+ PrintWriter out = _out; // closable resource not manages in this class
+ PrintWriter traceProcessorInfo = _printProcessorInfo ? out : null;
+ PrintWriter traceRounds = _printRounds ? out : null;
+ if (traceRounds != null) {
+ traceRounds.println("Round " + ++_round + ':'); //$NON-NLS-1$
+ }
+ RoundDispatcher dispatcher = new RoundDispatcher(
+ this, roundEnv, roundEnv.getRootAnnotations(), traceProcessorInfo, traceRounds);
+ dispatcher.round();
+ if (_isFirstRound) {
+ _isFirstRound = false;
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java
new file mode 100644
index 0000000..647e8a4
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2020 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - derived base class from BatchMessagerImpl
+ *
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic.Kind;
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.apt.model.AnnotationMemberValue;
+import org.eclipse.jdt.internal.compiler.apt.model.AnnotationMirrorImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.ExecutableElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.ModuleElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.VariableElementImpl;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+import org.eclipse.jdt.internal.compiler.util.Util;
+
+public class BaseMessagerImpl {
+
+ static final String[] NO_ARGUMENTS = new String[0];
+
+ /**
+ * Create a CategorizedProblem that can be reported to an ICompilerRequestor, etc.
+ *
+ * @param e the element against which to report the message. If the element is not
+ * in the set of elements being compiled in the current round, the reference context
+ * and filename will be set to null.
+ * @return
+ */
+ public static AptProblem createProblem(Kind kind, CharSequence msg, Element e,
+ AnnotationMirror a, AnnotationValue v) {
+ ReferenceContext referenceContext = null;
+ Annotation[] elementAnnotations = null;
+ int startPosition = 0;
+ int endPosition = 0;
+ if (e != null) {
+ switch(e.getKind()) {
+ case MODULE:
+ ModuleElementImpl moduleElementImpl = (ModuleElementImpl) e;
+ Binding moduleBinding = moduleElementImpl._binding;
+ if (moduleBinding instanceof SourceModuleBinding) {
+ SourceModuleBinding sourceModuleBinding = (SourceModuleBinding) moduleBinding;
+ CompilationUnitDeclaration unitDeclaration = (CompilationUnitDeclaration) sourceModuleBinding.scope.referenceContext();
+ referenceContext = unitDeclaration;
+ elementAnnotations = unitDeclaration.moduleDeclaration.annotations;
+ startPosition = unitDeclaration.moduleDeclaration.sourceStart;
+ endPosition = unitDeclaration.moduleDeclaration.sourceEnd;
+ }
+ break;
+ case ANNOTATION_TYPE :
+ case INTERFACE :
+ case CLASS :
+ case ENUM :
+ TypeElementImpl typeElementImpl = (TypeElementImpl) e;
+ Binding typeBinding = typeElementImpl._binding;
+ if (typeBinding instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) typeBinding;
+ TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext();
+ referenceContext = typeDeclaration;
+ elementAnnotations = typeDeclaration.annotations;
+ startPosition = typeDeclaration.sourceStart;
+ endPosition = typeDeclaration.sourceEnd;
+ }
+ break;
+ case PACKAGE :
+ // nothing to do: there is no reference context for a package
+ break;
+ case CONSTRUCTOR :
+ case METHOD :
+ ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e;
+ Binding binding = executableElementImpl._binding;
+ if (binding instanceof MethodBinding) {
+ MethodBinding methodBinding = (MethodBinding) binding;
+ AbstractMethodDeclaration sourceMethod = methodBinding.sourceMethod();
+ if (sourceMethod != null) {
+ referenceContext = sourceMethod;
+ elementAnnotations = sourceMethod.annotations;
+ startPosition = sourceMethod.sourceStart;
+ endPosition = sourceMethod.sourceEnd;
+ }
+ }
+ break;
+ case ENUM_CONSTANT :
+ break;
+ case EXCEPTION_PARAMETER :
+ break;
+ case FIELD :
+ case PARAMETER :
+ VariableElementImpl variableElementImpl = (VariableElementImpl) e;
+ binding = variableElementImpl._binding;
+ if (binding instanceof FieldBinding) {
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ FieldDeclaration fieldDeclaration = fieldBinding.sourceField();
+ if (fieldDeclaration != null) {
+ ReferenceBinding declaringClass = fieldBinding.declaringClass;
+ if (declaringClass instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) declaringClass;
+ TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext();
+ referenceContext = typeDeclaration;
+ }
+ elementAnnotations = fieldDeclaration.annotations;
+ startPosition = fieldDeclaration.sourceStart;
+ endPosition = fieldDeclaration.sourceEnd;
+ }
+ } else if (binding instanceof AptSourceLocalVariableBinding){
+ AptSourceLocalVariableBinding parameterBinding = (AptSourceLocalVariableBinding) binding;
+ LocalDeclaration parameterDeclaration = parameterBinding.declaration;
+ if (parameterDeclaration != null) {
+ MethodBinding methodBinding = parameterBinding.methodBinding;
+ if (methodBinding != null) {
+ referenceContext = methodBinding.sourceMethod();
+ }
+ elementAnnotations = parameterDeclaration.annotations;
+ startPosition = parameterDeclaration.sourceStart;
+ endPosition = parameterDeclaration.sourceEnd;
+ }
+ }
+ break;
+ case INSTANCE_INIT :
+ case STATIC_INIT :
+ break;
+ case LOCAL_VARIABLE :
+ break;
+ case TYPE_PARAMETER :
+ default:
+ break;
+ }
+ }
+ StringBuilder builder = new StringBuilder();
+ if (msg != null) {
+ builder.append(msg);
+ }
+ if (a != null && elementAnnotations != null) {
+ AnnotationBinding annotationBinding = ((AnnotationMirrorImpl) a)._binding;
+ Annotation annotation = findAnnotation(elementAnnotations, annotationBinding);
+ if (annotation != null) {
+ startPosition = annotation.sourceStart;
+ endPosition = annotation.sourceEnd;
+ if (v != null && v instanceof AnnotationMemberValue) {
+ MethodBinding methodBinding = ((AnnotationMemberValue) v).getMethodBinding();
+ MemberValuePair[] memberValuePairs = annotation.memberValuePairs();
+ MemberValuePair memberValuePair = null;
+ for (int i = 0; memberValuePair == null && i < memberValuePairs.length; i++) {
+ if (methodBinding == memberValuePairs[i].binding) {
+ memberValuePair = memberValuePairs[i];
+ }
+ }
+ if (memberValuePair != null) {
+ startPosition = memberValuePair.sourceStart;
+ endPosition = memberValuePair.sourceEnd;
+ }
+ }
+ }
+ }
+ int lineNumber = 0;
+ int columnNumber = 1;
+ char[] fileName = null;
+ if (referenceContext != null) {
+ CompilationResult result = referenceContext.compilationResult();
+ fileName = result.fileName;
+ int[] lineEnds = null;
+ lineNumber = startPosition >= 0
+ ? Util.getLineNumber(startPosition, lineEnds = result.getLineSeparatorPositions(), 0, lineEnds.length-1)
+ : 0;
+ columnNumber = startPosition >= 0
+ ? Util.searchColumnNumber(result.getLineSeparatorPositions(), lineNumber,startPosition)
+ : 0;
+ }
+ int severity;
+ switch(kind) {
+ case ERROR :
+ severity = ProblemSeverities.Error;
+ break;
+ case NOTE :
+ case OTHER:
+ severity = ProblemSeverities.Info;
+ break;
+ default :
+ severity = ProblemSeverities.Warning;
+ break;
+ }
+ return new AptProblem(
+ referenceContext,
+ fileName,
+ String.valueOf(builder),
+ 0,
+ NO_ARGUMENTS,
+ severity,
+ startPosition,
+ endPosition,
+ lineNumber,
+ columnNumber);
+ }
+
+ private static Annotation findAnnotation(Annotation[] elementAnnotations, AnnotationBinding annotationBinding) {
+ for (int i = 0; i < elementAnnotations.length; i++) {
+ Annotation annotation = findAnnotation(elementAnnotations[i], annotationBinding);
+ if (annotation != null) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+
+ private static Annotation findAnnotation(Annotation elementAnnotation, AnnotationBinding annotationBinding) {
+ if (annotationBinding == elementAnnotation.getCompilerAnnotation()) {
+ return elementAnnotation;
+ }
+
+ MemberValuePair[] memberValuePairs = elementAnnotation.memberValuePairs();
+ for (MemberValuePair mvp : memberValuePairs) {
+ Expression v = mvp.value;
+ if (v instanceof Annotation) {
+ Annotation a = findAnnotation((Annotation) v, annotationBinding);
+ if (a != null) {
+ return a;
+ }
+ } else if (v instanceof ArrayInitializer) {
+ Expression[] expressions = ((ArrayInitializer) v).expressions;
+ for (Expression e : expressions) {
+ if (e instanceof Annotation) {
+ Annotation a = findAnnotation((Annotation) e, annotationBinding);
+ if (a != null) {
+ return a;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public BaseMessagerImpl() {
+ super();
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java
new file mode 100644
index 0000000..bb48a0b
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2021 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.apt.model.ElementsImpl;
+import org.eclipse.jdt.internal.compiler.apt.model.Factory;
+import org.eclipse.jdt.internal.compiler.apt.model.TypesImpl;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Implementation of ProcessingEnvironment that is common to batch and IDE environments.
+ */
+public abstract class BaseProcessingEnvImpl implements ProcessingEnvironment {
+
+ // Initialized in subclasses:
+ protected Filer _filer;
+ protected Messager _messager;
+ protected Map<String, String> _processorOptions;
+ protected Compiler _compiler;
+
+ // Initialized in this base class:
+ protected Elements _elementUtils;
+ protected Types _typeUtils;
+ private List<ICompilationUnit> _addedUnits;
+ private List<ReferenceBinding> _addedClassFiles;
+ private List<ICompilationUnit> _deletedUnits;
+ private boolean _errorRaised;
+ private Factory _factory;
+ public ModuleBinding _current_module;
+
+ public BaseProcessingEnvImpl() {
+ _addedUnits = new ArrayList<>();
+ _addedClassFiles = new ArrayList<>();
+ _deletedUnits = new ArrayList<>();
+ _elementUtils = ElementsImpl.create(this);
+ _typeUtils = new TypesImpl(this);
+ _factory = new Factory(this);
+ _errorRaised = false;
+ }
+
+ public void addNewUnit(ICompilationUnit unit) {
+ _addedUnits.add(unit);
+ }
+
+ public void addNewClassFile(ReferenceBinding binding) {
+ _addedClassFiles.add(binding);
+ }
+
+ public Compiler getCompiler() {
+ return _compiler;
+ }
+
+ public ICompilationUnit[] getDeletedUnits() {
+ ICompilationUnit[] result = new ICompilationUnit[_deletedUnits.size()];
+ _deletedUnits.toArray(result);
+ return result;
+ }
+
+ public ICompilationUnit[] getNewUnits() {
+ ICompilationUnit[] result = new ICompilationUnit[_addedUnits.size()];
+ _addedUnits.toArray(result);
+ return result;
+ }
+
+ @Override
+ public Elements getElementUtils() {
+ return _elementUtils;
+ }
+
+ @Override
+ public Filer getFiler() {
+ return _filer;
+ }
+
+ @Override
+ public Messager getMessager() {
+ return _messager;
+ }
+
+ @Override
+ public Map<String, String> getOptions() {
+ return _processorOptions;
+ }
+
+ @Override
+ public Types getTypeUtils() {
+ return _typeUtils;
+ }
+
+ public LookupEnvironment getLookupEnvironment() {
+ return _compiler.lookupEnvironment;
+ }
+
+ @Override
+ public SourceVersion getSourceVersion() {
+ if (this._compiler.options.sourceLevel <= ClassFileConstants.JDK1_5) {
+ return SourceVersion.RELEASE_5;
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK1_6) {
+ return SourceVersion.RELEASE_6;
+ }
+ try {
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK1_7) {
+ return SourceVersion.valueOf("RELEASE_7"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK1_8) {
+ return SourceVersion.valueOf("RELEASE_8"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK9) {
+ return SourceVersion.valueOf("RELEASE_9"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK10) {
+ return SourceVersion.valueOf("RELEASE_10"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK11) {
+ return SourceVersion.valueOf("RELEASE_11"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK12) {
+ return SourceVersion.valueOf("RELEASE_12"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK13) {
+ return SourceVersion.valueOf("RELEASE_13"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK14) {
+ return SourceVersion.valueOf("RELEASE_14"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK15) {
+ return SourceVersion.valueOf("RELEASE_15"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK16) {
+ return SourceVersion.valueOf("RELEASE_16"); //$NON-NLS-1$
+ }
+ if (this._compiler.options.sourceLevel == ClassFileConstants.JDK17) {
+ return SourceVersion.valueOf("RELEASE_17"); //$NON-NLS-1$
+ }
+ } catch(IllegalArgumentException e) {
+ // handle call on a JDK 6
+ return SourceVersion.RELEASE_6;
+ }
+ // handle call on a JDK 6 by default
+ return SourceVersion.RELEASE_6;
+ }
+
+ /**
+ * Called when AnnotationProcessorManager has retrieved the list of
+ * newly generated compilation units (ie, once per round)
+ */
+ public void reset() {
+ _addedUnits.clear();
+ _addedClassFiles.clear();
+ _deletedUnits.clear();
+ }
+
+ /**
+ * Has an error been raised in any of the rounds of processing in this build?
+ * @return
+ */
+ public boolean errorRaised()
+ {
+ return _errorRaised;
+ }
+
+ /**
+ * Set or clear the errorRaised flag. Typically this will be set by the Messager
+ * when an error has been raised, and it will never be cleared.
+ */
+ public void setErrorRaised(boolean b)
+ {
+ _errorRaised = true;
+ }
+
+ public Factory getFactory()
+ {
+ return _factory;
+ }
+
+ public ReferenceBinding[] getNewClassFiles() {
+ ReferenceBinding[] result = new ReferenceBinding[_addedClassFiles.size()];
+ _addedClassFiles.toArray(result);
+ return result;
+ }
+ /*
+ * This overrides ProcessingEnvironment, but can't declare so since
+ * we are still compiling against JDK 8.
+ */
+ public boolean isPreviewEnabled() {
+ return this._compiler.options.enablePreviewFeatures;
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java
new file mode 100644
index 0000000..ebc85e1
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2017 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+
+import javax.annotation.processing.Processor;
+import javax.lang.model.SourceVersion;
+import javax.tools.JavaFileManager;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+
+import org.eclipse.jdt.internal.compiler.batch.Main;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+/**
+ * Java 6 annotation processor manager used when compiling from the command line
+ * or via the javax.tools.JavaCompiler interface.
+ * @see org.eclipse.jdt.internal.apt.pluggable.core.dispatch.IdeAnnotationProcessorManager
+ */
+public class BatchAnnotationProcessorManager extends BaseAnnotationProcessorManager
+{
+
+ /**
+ * Processors that have been set by calling CompilationTask.setProcessors().
+ */
+ private List<Processor> _setProcessors = null;
+ private Iterator<Processor> _setProcessorIter = null;
+
+ /**
+ * Processors named with the -processor option on the command line.
+ */
+ private List<String> _commandLineProcessors;
+ private Iterator<String> _commandLineProcessorIter = null;
+
+ private ServiceLoader<Processor> _serviceLoader = null;
+ private Iterator<Processor> _serviceLoaderIter;
+
+ private ClassLoader _procLoader;
+
+ // Set this to true in order to trace processor discovery when -XprintProcessorInfo is specified
+ private final static boolean VERBOSE_PROCESSOR_DISCOVERY = true;
+ private boolean _printProcessorDiscovery = false;
+
+ /**
+ * Zero-arg constructor so this object can be easily created via reflection.
+ * A BatchAnnotationProcessorManager cannot be used until its
+ * {@link #configure(Object, String[])} method has been called.
+ */
+ public BatchAnnotationProcessorManager()
+ {
+ }
+
+ @Override
+ public void configure(Object batchCompiler, String[] commandLineArguments) {
+ if (null != _processingEnv) {
+ throw new IllegalStateException(
+ "Calling configure() more than once on an AnnotationProcessorManager is not supported"); //$NON-NLS-1$
+ }
+ BatchProcessingEnvImpl processingEnv = new BatchProcessingEnvImpl(this, (Main) batchCompiler, commandLineArguments);
+ _processingEnv = processingEnv;
+ @SuppressWarnings("resource") // fileManager is not opened here
+ JavaFileManager fileManager = processingEnv.getFileManager();
+ if (fileManager instanceof StandardJavaFileManager) {
+ Iterable<? extends File> location = null;
+ if (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0) {
+ location = ((StandardJavaFileManager) fileManager).getLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH);
+ }
+ if (location != null) {
+ _procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH);
+ } else {
+ _procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH);
+ }
+ } else {
+ // Fall back to old code
+ _procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH);
+ }
+ parseCommandLine(commandLineArguments);
+ _round = 0;
+ }
+
+ /**
+ * If a -processor option was specified in command line arguments,
+ * parse it into a list of qualified classnames.
+ * @param commandLineArguments contains one string for every space-delimited token on the command line
+ */
+ private void parseCommandLine(String[] commandLineArguments) {
+ List<String> commandLineProcessors = null;
+ for (int i = 0; i < commandLineArguments.length; ++i) {
+ String option = commandLineArguments[i];
+ if ("-XprintProcessorInfo".equals(option)) { //$NON-NLS-1$
+ _printProcessorInfo = true;
+ _printProcessorDiscovery = VERBOSE_PROCESSOR_DISCOVERY;
+ }
+ else if ("-XprintRounds".equals(option)) { //$NON-NLS-1$
+ _printRounds = true;
+ }
+ else if ("-processor".equals(option)) { //$NON-NLS-1$
+ commandLineProcessors = new ArrayList<>();
+ String procs = commandLineArguments[++i];
+ commandLineProcessors.addAll(Arrays.asList(procs.split(","))); //$NON-NLS-1$
+ break;
+ }
+ }
+ _commandLineProcessors = commandLineProcessors;
+ if (null != _commandLineProcessors) {
+ _commandLineProcessorIter = _commandLineProcessors.iterator();
+ }
+ }
+
+ @Override
+ public ProcessorInfo discoverNextProcessor() {
+ if (null != _setProcessors) {
+ // If setProcessors() was called, use that list until it's empty and then stop.
+ if (_setProcessorIter.hasNext()) {
+ Processor p = _setProcessorIter.next();
+ p.init(_processingEnv);
+ ProcessorInfo pi = new ProcessorInfo(p);
+ _processors.add(pi);
+ if (_printProcessorDiscovery && null != _out) {
+ _out.println("API specified processor: " + pi); //$NON-NLS-1$
+ }
+ return pi;
+ }
+ return null;
+ }
+
+ if (null != _commandLineProcessors) {
+ // If there was a -processor option, iterate over processor names,
+ // creating and initializing processors, until no more names are found, then stop.
+ if (_commandLineProcessorIter.hasNext()) {
+ String proc = _commandLineProcessorIter.next();
+ try {
+ Class<?> clazz = _procLoader.loadClass(proc);
+ Object o = clazz.getDeclaredConstructor().newInstance();
+ Processor p = (Processor) o;
+ p.init(_processingEnv);
+ ProcessorInfo pi = new ProcessorInfo(p);
+ _processors.add(pi);
+ if (_printProcessorDiscovery && null != _out) {
+ _out.println("Command line specified processor: " + pi); //$NON-NLS-1$
+ }
+ return pi;
+ } catch (Exception e) {
+ // TODO: better error handling
+ throw new AbortCompilation(null, e);
+ }
+ }
+ return null;
+ }
+
+ // if no processors were explicitly specified with setProcessors()
+ // or the command line, search the processor path with ServiceLoader.
+ if (null == _serviceLoader ) {
+ _serviceLoader = ServiceLoader.load(Processor.class, _procLoader);
+ _serviceLoaderIter = _serviceLoader.iterator();
+ }
+ try {
+ if (_serviceLoaderIter.hasNext()) {
+ Processor p = _serviceLoaderIter.next();
+ p.init(_processingEnv);
+ ProcessorInfo pi = new ProcessorInfo(p);
+ _processors.add(pi);
+ if (_printProcessorDiscovery && null != _out) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Discovered processor service "); //$NON-NLS-1$
+ sb.append(pi);
+ sb.append("\n supporting "); //$NON-NLS-1$
+ sb.append(pi.getSupportedAnnotationTypesAsString());
+ sb.append("\n in "); //$NON-NLS-1$
+ sb.append(getProcessorLocation(p));
+ _out.println(sb.toString());
+ }
+ return pi;
+ }
+ } catch (ServiceConfigurationError e) {
+ // TODO: better error handling
+ throw new AbortCompilation(null, e);
+ }
+ return null;
+ }
+
+ /**
+ * Used only for debugging purposes. Generates output like "file:jar:D:/temp/jarfiles/myJar.jar!/".
+ * Surely this code already exists in several hundred other places?
+ * @return the location whence a processor class was loaded.
+ */
+ private String getProcessorLocation(Processor p) {
+ // Get the classname in a form that can be passed to ClassLoader.getResource(),
+ // e.g., "pa/pb/pc/Outer$Inner.class"
+ boolean isMember = false;
+ Class<?> outerClass = p.getClass();
+ StringBuilder innerName = new StringBuilder();
+ while (outerClass.isMemberClass()) {
+ innerName.insert(0, outerClass.getSimpleName());
+ innerName.insert(0, '$');
+ isMember = true;
+ outerClass = outerClass.getEnclosingClass();
+ }
+ String path = outerClass.getName();
+ path = path.replace('.', '/');
+ if (isMember) {
+ path = path + innerName;
+ }
+ path = path + ".class"; //$NON-NLS-1$
+
+ // Find the URL for the class resource and strip off the resource name itself
+ String location = _procLoader.getResource(path).toString();
+ if (location.endsWith(path)) {
+ location = location.substring(0, location.length() - path.length());
+ }
+ return location;
+ }
+
+ @Override
+ public void reportProcessorException(Processor p, Exception e) {
+ // TODO: if (verbose) report the processor
+ throw new AbortCompilation(null, e);
+ }
+
+ @Override
+ public void setProcessors(Object[] processors) {
+ if (!_isFirstRound) {
+ throw new IllegalStateException("setProcessors() cannot be called after processing has begun"); //$NON-NLS-1$
+ }
+ // Cast all the processors here, rather than failing later.
+ // But don't call init() until the processor is actually needed.
+ _setProcessors = new ArrayList<>(processors.length);
+ for (Object o : processors) {
+ Processor p = (Processor)o;
+ _setProcessors.add(p);
+ }
+ _setProcessorIter = _setProcessors.iterator();
+
+ // processors set this way take precedence over anything on the command line
+ _commandLineProcessors = null;
+ _commandLineProcessorIter = null;
+ }
+
+ @Override
+ protected void cleanUp() {
+ // the classloader needs to be kept open between rounds, close it at the end:
+ if (this._procLoader instanceof URLClassLoader) {
+ try {
+ ((URLClassLoader) this._procLoader).close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java
new file mode 100644
index 0000000..b731cc0
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2018 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * philippe.marschall@netcetera.ch - Fix for 338370
+ * IBM Corporation - Fix for validating relative name
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.util.HashSet;
+
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.FilerException;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.JavaFileManager.Location;
+
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Implementation of Filer used when compilation is driven by command line
+ * or by Tool interface. This version does not need to keep track of
+ * dependencies.
+ */
+public class BatchFilerImpl implements Filer {
+
+ protected final BaseAnnotationProcessorManager _dispatchManager;
+ protected final BatchProcessingEnvImpl _env;
+ protected final JavaFileManager _fileManager;
+ protected final HashSet<URI> _createdFiles;
+
+ public BatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env)
+ {
+ _dispatchManager = dispatchManager;
+ _fileManager = env._fileManager;
+ _env = env;
+ _createdFiles = new HashSet<>();
+ }
+
+ public void addNewUnit(ICompilationUnit unit) {
+ _env.addNewUnit(unit);
+ }
+
+ public void addNewClassFile(ReferenceBinding binding) {
+ _env.addNewClassFile(binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#createClassFile(java.lang.CharSequence, javax.lang.model.element.Element[])
+ */
+ @Override
+ public JavaFileObject createClassFile(CharSequence name,
+ Element... originatingElements) throws IOException {
+ JavaFileObject jfo = _fileManager.getJavaFileForOutput(
+ StandardLocation.CLASS_OUTPUT, name.toString(), JavaFileObject.Kind.CLASS, null);
+ URI uri = jfo.toUri();
+ if (_createdFiles.contains(uri)) {
+ throw new FilerException("Class file already created : " + name); //$NON-NLS-1$
+ }
+
+ _createdFiles.add(uri);
+ return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#createResource(javax.tools.JavaFileManager.Location, java.lang.CharSequence, java.lang.CharSequence, javax.lang.model.element.Element[])
+ */
+ @Override
+ public FileObject createResource(Location location, CharSequence pkg,
+ CharSequence relativeName, Element... originatingElements)
+ throws IOException {
+ validateName(relativeName);
+ FileObject fo = _fileManager.getFileForOutput(
+ location, pkg.toString(), relativeName.toString(), null);
+ URI uri = fo.toUri();
+ if (_createdFiles.contains(uri)) {
+ throw new FilerException("Resource already created : " + location + '/' + pkg + '/' + relativeName); //$NON-NLS-1$
+ }
+
+ _createdFiles.add(uri);
+ return fo;
+ }
+
+ private static void validateName(CharSequence relativeName) {
+ int length = relativeName.length();
+ if (length == 0) {
+ throw new IllegalArgumentException("relative path cannot be empty"); //$NON-NLS-1$
+ }
+ String path = relativeName.toString();
+ if (path.indexOf('\\') != -1) {
+ // normalize the path with '/'
+ path = path.replace('\\', '/');
+ }
+ if (path.charAt(0) == '/') {
+ throw new IllegalArgumentException("relative path is absolute"); //$NON-NLS-1$
+ }
+ boolean hasDot = false;
+ for (int i = 0; i < length; i++) {
+ switch(path.charAt(i)) {
+ case '/' :
+ if (hasDot) {
+ throw new IllegalArgumentException("relative name " + relativeName + " is not relative"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ break;
+ case '.' :
+ hasDot = true;
+ break;
+ default:
+ hasDot = false;
+ }
+ }
+ if (hasDot) {
+ throw new IllegalArgumentException("relative name " + relativeName + " is not relative"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#createSourceFile(java.lang.CharSequence, javax.lang.model.element.Element[])
+ */
+ @Override
+ public JavaFileObject createSourceFile(CharSequence name,
+ Element... originatingElements) throws IOException {
+ String moduleAndPkgString = name.toString();
+ int slash = moduleAndPkgString.indexOf('/');
+ String mod = null;
+ if (slash != -1) {
+ name = moduleAndPkgString.substring(slash + 1, name.length());
+ mod = moduleAndPkgString.substring(0, slash);
+ }
+ TypeElement typeElement = _env._elementUtils.getTypeElement(name);
+ if (typeElement != null) {
+ throw new FilerException("Source file already exists : " + moduleAndPkgString); //$NON-NLS-1$
+ }
+ Location location = mod == null ? StandardLocation.SOURCE_OUTPUT : _fileManager.getLocationForModule(StandardLocation.SOURCE_OUTPUT, mod);
+ JavaFileObject jfo = _fileManager.getJavaFileForOutput(location, name.toString(), JavaFileObject.Kind.SOURCE, null);
+ URI uri = jfo.toUri();
+ if (_createdFiles.contains(uri)) {
+ throw new FilerException("Source file already created : " + name); //$NON-NLS-1$
+ }
+
+ _createdFiles.add(uri);
+ // hook the file object's writers to create compilation unit and add to addedUnits()
+ return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Filer#getResource(javax.tools.JavaFileManager.Location, java.lang.CharSequence, java.lang.CharSequence)
+ */
+ @Override
+ public FileObject getResource(Location location, CharSequence pkg,
+ CharSequence relativeName) throws IOException {
+ validateName(relativeName);
+ FileObject fo = _fileManager.getFileForInput(
+ location, pkg.toString(), relativeName.toString());
+ if (fo == null) {
+ throw new FileNotFoundException("Resource does not exist : " + location + '/' + pkg + '/' + relativeName); //$NON-NLS-1$
+ }
+ URI uri = fo.toUri();
+ if (_createdFiles.contains(uri)) {
+ throw new FilerException("Resource already created : " + location + '/' + pkg + '/' + relativeName); //$NON-NLS-1$
+ }
+ return fo;
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java
new file mode 100644
index 0000000..7a713fe
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2006-2009 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic.Kind;
+
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.internal.compiler.batch.Main;
+
+/**
+ * An implementation of Messager that reports messages via the Compiler
+ */
+public class BatchMessagerImpl extends BaseMessagerImpl implements Messager {
+
+ private final Main _compiler;
+ private final BaseProcessingEnvImpl _processingEnv;
+
+ public BatchMessagerImpl(BaseProcessingEnvImpl processingEnv, Main compiler) {
+ _compiler = compiler;
+ _processingEnv = processingEnv;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg) {
+ printMessage(kind, msg, null, null, null);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg, Element e) {
+ printMessage(kind, msg, e, null, null);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg, Element e,
+ AnnotationMirror a) {
+ printMessage(kind, msg, e, a, null);
+
+ }
+
+ /* (non-Javadoc)
+ * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationValue)
+ */
+ @Override
+ public void printMessage(Kind kind, CharSequence msg, Element e,
+ AnnotationMirror a, AnnotationValue v) {
+ if (kind == Kind.ERROR) {
+ _processingEnv.setErrorRaised(true);
+ }
+ CategorizedProblem problem = createProblem(kind, msg, e, a, v);
+ if (problem != null) {
+ this._compiler.addExtraProblems(problem);
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
new file mode 100644
index 0000000..cbf8abe
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.lang.reflect.Field;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.tools.JavaFileManager;
+
+import org.eclipse.jdt.internal.compiler.apt.util.EclipseFileManager;
+import org.eclipse.jdt.internal.compiler.batch.Main;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+/**
+ * The implementation of ProcessingEnvironment that is used when compilation is
+ * driven by the command line or by the Tool interface. This environment uses
+ * the JavaFileManager provided by the compiler.
+ * @see org.eclipse.jdt.internal.apt.pluggable.core.dispatch.IdeProcessingEnvImpl
+ */
+public class BatchProcessingEnvImpl extends BaseProcessingEnvImpl {
+
+ protected final BaseAnnotationProcessorManager _dispatchManager;
+ protected final JavaFileManager _fileManager;
+ protected final Main _compilerOwner;
+
+ public BatchProcessingEnvImpl(BaseAnnotationProcessorManager dispatchManager, Main batchCompiler,
+ String[] commandLineArguments)
+ {
+ super();
+ _compilerOwner = batchCompiler;
+ _compiler = batchCompiler.batchCompiler;
+ _dispatchManager = dispatchManager;
+ Class<?> c = null;
+ try {
+ c = Class.forName("org.eclipse.jdt.internal.compiler.tool.EclipseCompilerImpl"); //$NON-NLS-1$
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ Field field = null;
+ JavaFileManager javaFileManager = null;
+ if (c != null) {
+ try {
+ field = c.getField("fileManager"); //$NON-NLS-1$
+ } catch (SecurityException e) {
+ // ignore
+ } catch (IllegalArgumentException e) {
+ // ignore
+ } catch (NoSuchFieldException e) {
+ // ignore
+ }
+ }
+ if (field != null) {
+ try {
+ javaFileManager = (JavaFileManager) field.get(batchCompiler);
+ } catch (IllegalArgumentException e) {
+ // ignore
+ } catch (IllegalAccessException e) {
+ // ignore
+ }
+ }
+ if (javaFileManager != null) {
+ _fileManager = javaFileManager;
+ } else {
+ String encoding = (String) batchCompiler.options.get(CompilerOptions.OPTION_Encoding);
+ Charset charset = encoding != null ? Charset.forName(encoding) : null;
+ JavaFileManager manager = new EclipseFileManager(batchCompiler.compilerLocale, charset);
+ ArrayList<String> options = new ArrayList<>();
+ options.addAll(Arrays.asList(commandLineArguments));
+ for (Iterator<String> iterator = options.iterator(); iterator.hasNext(); ) {
+ manager.handleOption(iterator.next(), iterator);
+ }
+ _fileManager = manager;
+ }
+ _processorOptions = Collections.unmodifiableMap(parseProcessorOptions(commandLineArguments));
+ _filer = new BatchFilerImpl(_dispatchManager, this);
+ _messager = new BatchMessagerImpl(this, _compilerOwner);
+ }
+
+ /**
+ * Parse the -A command line arguments so that they can be delivered to
+ * processors with {@link javax.annotation.processing.ProcessingEnvironment#getOptions()}. In Sun's Java 6
+ * version of javac, unlike in the Java 5 apt tool, only the -A options are
+ * passed to processors, not the other command line options; that behavior
+ * is repeated here.
+ * @param args the equivalent of the args array from the main() method.
+ * @return a map of key to value, or key to null if there is no value for
+ * a particular key. The "-A" is stripped from the key, so a command-line
+ * argument like "-Afoo=bar" will result in an entry with key "foo" and
+ * value "bar".
+ */
+ private Map<String, String> parseProcessorOptions(String[] args) {
+ Map<String, String> options = new LinkedHashMap<>();
+ for (String arg : args) {
+ if (!arg.startsWith("-A")) { //$NON-NLS-1$
+ continue;
+ }
+ int equals = arg.indexOf('=');
+ if (equals == 2) {
+ // option begins "-A=" - not valid
+ Exception e = new IllegalArgumentException("-A option must have a key before the equals sign"); //$NON-NLS-1$
+ throw new AbortCompilation(null, e);
+ }
+ if (equals == arg.length() - 1) {
+ // option ends with "=" - not valid
+ options.put(arg.substring(2, equals), null);
+ } else if (equals == -1) {
+ // no value
+ options.put(arg.substring(2), null);
+ } else {
+ // value and key
+ options.put(arg.substring(2, equals), arg.substring(equals + 1));
+ }
+ }
+ return options;
+ }
+
+ public JavaFileManager getFileManager() {
+ return _fileManager;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return _compilerOwner.compilerLocale;
+ }
+
+ public boolean shouldIgnoreOptionalProblems(char[] fileName) {
+ return Main.shouldIgnoreOptionalProblems(this._compilerOwner.ignoreOptionalProblemsFromFolders, fileName);
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java
new file mode 100644
index 0000000..b06e9f9
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2014 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import javax.tools.ForwardingJavaFileObject;
+import javax.tools.JavaFileObject;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * A delegating JavaFileObject that hooks the close() methods of the Writer
+ * or OutputStream objects that it produces, and notifies the annotation
+ * dispatch manager when a new compilation unit is produced.
+ */
+public class HookedJavaFileObject extends
+ ForwardingJavaFileObject<JavaFileObject>
+{
+ // A delegating Writer that passes all commands to its contained Writer,
+ // but hooks close() to notify the annotation dispatch manager of the new unit.
+ private class ForwardingWriter extends Writer {
+ private final Writer _w;
+ ForwardingWriter(Writer w) {
+ _w = w;
+ }
+ @Override
+ public Writer append(char c) throws IOException {
+ return _w.append(c);
+ }
+ @Override
+ public Writer append(CharSequence csq, int start, int end)
+ throws IOException {
+ return _w.append(csq, start, end);
+ }
+ @Override
+ public Writer append(CharSequence csq) throws IOException {
+ return _w.append(csq);
+ }
+ // This is the only interesting method - it has to notify the
+ // dispatch manager of the new file.
+ @Override
+ public void close() throws IOException {
+ _w.close();
+ closed();
+ }
+ @Override
+ public void flush() throws IOException {
+ _w.flush();
+ }
+ @Override
+ public void write(char[] cbuf) throws IOException {
+ _w.write(cbuf);
+ }
+ @Override
+ public void write(int c) throws IOException {
+ _w.write(c);
+ }
+ @Override
+ public void write(String str, int off, int len)
+ throws IOException {
+ _w.write(str, off, len);
+ }
+ @Override
+ public void write(String str) throws IOException {
+ _w.write(str);
+ }
+ @Override
+ public void write(char[] cbuf, int off, int len)
+ throws IOException {
+ _w.write(cbuf, off, len);
+ }
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return new ForwardingWriter(this._w);
+ }
+ @Override
+ public int hashCode() {
+ return _w.hashCode();
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ForwardingWriter other = (ForwardingWriter) obj;
+ if (_w == null) {
+ if (other._w != null)
+ return false;
+ } else if (!_w.equals(other._w))
+ return false;
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "ForwardingWriter wrapping " + _w.toString(); //$NON-NLS-1$
+ }
+ }
+
+ // A delegating Writer that passes all commands to its contained Writer,
+ // but hooks close() to notify the annotation dispatch manager of the new unit.
+ private class ForwardingOutputStream extends OutputStream {
+ private final OutputStream _os;
+
+ ForwardingOutputStream(OutputStream os) {
+ _os = os;
+ }
+
+ @Override
+ public void close() throws IOException {
+ _os.close();
+ closed();
+ }
+ @Override
+ public void flush() throws IOException {
+ _os.flush();
+ }
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ _os.write(b, off, len);
+ }
+ @Override
+ public void write(byte[] b) throws IOException {
+ _os.write(b);
+ }
+ @Override
+ public void write(int b) throws IOException {
+ _os.write(b);
+ }
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return new ForwardingOutputStream(this._os);
+ }
+ @Override
+ public int hashCode() {
+ return _os.hashCode();
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ForwardingOutputStream other = (ForwardingOutputStream) obj;
+ if (_os == null) {
+ if (other._os != null)
+ return false;
+ } else if (!_os.equals(other._os))
+ return false;
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "ForwardingOutputStream wrapping " + _os.toString(); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * The Filer implementation that we need to notify when a new file is created.
+ */
+ protected final BatchFilerImpl _filer;
+
+ /**
+ * The name of the file that is created; this is passed to the CompilationUnit constructor,
+ * and ultimately to the java.io.File constructor, so it is a normal pathname, just like
+ * what would be on the compiler command line.
+ */
+ protected final String _fileName;
+
+
+
+ /**
+ * A compilation unit is created when the writer or stream is closed. Only do this once.
+ */
+ private boolean _closed = false;
+
+ private String _typeName;
+
+ public HookedJavaFileObject(JavaFileObject fileObject, String fileName, String typeName, BatchFilerImpl filer) {
+ super(fileObject);
+ _filer = filer;
+ _fileName = fileName;
+ _typeName = typeName;
+ }
+
+ @SuppressWarnings("resource") // ForwardingOutputStream forwards close() too
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return new ForwardingOutputStream(super.openOutputStream());
+ }
+
+ @SuppressWarnings("resource") // ForwardingWriter forwards close() too
+ @Override
+ public Writer openWriter() throws IOException {
+ return new ForwardingWriter(super.openWriter());
+ }
+
+ protected void closed() {
+ if (!_closed) {
+ _closed = true;
+ //TODO: support encoding
+ switch(this.getKind()) {
+ case SOURCE :
+ CompilationUnit unit = new CompilationUnit(null, _fileName, null /* encoding */, null, this._filer._env.shouldIgnoreOptionalProblems(_fileName.toCharArray()), null);
+ _filer.addNewUnit(unit);
+ break;
+ case CLASS :
+ IBinaryType binaryType = null;
+ try {
+ binaryType = ClassFileReader.read(_fileName);
+ } catch (ClassFormatException e) {
+ /* When the annotation processor produces garbage, javac seems to show some resilience, by hooking the source type,
+ which since is resolved can answer annotations during discovery - Not sure if this sanctioned by the spec, to be taken
+ up with Oracle. Here we mimic the bug, see that addNewClassFile is simply collecting ReferenceBinding's, so adding
+ a SourceTypeBinding works just fine.
+ */
+ ReferenceBinding type = this._filer._env._compiler.lookupEnvironment.getType(CharOperation.splitOn('.', _typeName.toCharArray()));
+ if (type != null)
+ _filer.addNewClassFile(type);
+ } catch (IOException e) {
+ // ignore
+ }
+ if (binaryType != null) {
+ char[] name = binaryType.getName();
+ ReferenceBinding type = this._filer._env._compiler.lookupEnvironment.getType(CharOperation.splitOn('/', name));
+ if (type != null && type.isValidBinding()) {
+ if (type.isBinaryBinding()) {
+ _filer.addNewClassFile(type);
+ } else {
+ BinaryTypeBinding binaryBinding = new BinaryTypeBinding(type.getPackage(), binaryType, this._filer._env._compiler.lookupEnvironment, true);
+ if (binaryBinding != null)
+ _filer.addNewClassFile(binaryBinding);
+ }
+ }
+ }
+ break;
+ case HTML:
+ case OTHER:
+ break;
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java
new file mode 100644
index 0000000..5e88da3
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.util.List;
+
+import javax.annotation.processing.Processor;
+
+/**
+ * Implementors know how to discover annotation processors, and maintain a list of processors that
+ * have been discovered and initialized so far.
+ */
+public interface IProcessorProvider {
+
+ /**
+ * Return the next processor that can be discovered, according to the order and discovery rules
+ * of the provider (see, for instance, {@link Processor}.
+ * @return a ProcessorInfo wrapping an initialized Processor, or <code>null</code> if there are
+ * no more processors to be discovered.
+ */
+ ProcessorInfo discoverNextProcessor();
+
+ /**
+ * @return the list of all processors that have been discovered so far. This list will grow when
+ * {@link #discoverNextProcessor()} is called.
+ */
+ List<ProcessorInfo> getDiscoveredProcessors();
+
+ /**
+ * Called when a processor throws an exception. This may abort compilation, throw an
+ * unchecked exception, etc; the caller should not assume that this method will return.
+ *
+ * @param p the processor, if known, or null if not.
+ * @param e
+ */
+ void reportProcessorException(Processor p, Exception e);
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java
new file mode 100644
index 0000000..c33a945
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.processing.Processor;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Cached information associated with a {@link Processor} in the context
+ * of annotation processor dispatch.
+ * <p>
+ * This class supports inclusion in a collection by implementing
+ * equals() and hashCode(). Its concept of identity is based on
+ * the class object of the Processor that it wraps; so, for instance,
+ * it is not possible to have a Set that contains more than one
+ * instance of a particular Processor class. In fact, it is possible
+ * to have more than one instance of a Processor if there are multiple
+ * build threads, but within the context of a particular dispatch
+ * manager, there will only be one of any given Processor class.
+ */
+public class ProcessorInfo {
+ final Processor _processor;
+ final Set<String> _supportedOptions;
+ final SourceVersion _supportedSourceVersion;
+
+ private final Pattern _supportedAnnotationTypesPattern;
+ private final boolean _supportsStar;
+ private boolean _hasBeenCalled;
+
+ /**
+ * Create a ProcessorInfo wrapping a particular Processor. The Processor must already have been
+ * initialized (that is,
+ * {@link Processor#init(javax.annotation.processing.ProcessingEnvironment)} must already have
+ * been called). Its getSupportedXXX() methods will be called and the results will be cached.
+ */
+ public ProcessorInfo(Processor p)
+ {
+ _processor = p;
+ _hasBeenCalled = false;
+ _supportedSourceVersion = p.getSupportedSourceVersion();
+ _supportedOptions = p.getSupportedOptions();
+ Set<String> supportedAnnotationTypes = p.getSupportedAnnotationTypes();
+
+ boolean supportsStar = false;
+ if (null != supportedAnnotationTypes && !supportedAnnotationTypes.isEmpty()) {
+ StringBuilder regex = new StringBuilder();
+ Iterator<String> iName = supportedAnnotationTypes.iterator();
+ while (true) {
+ String name = iName.next();
+ supportsStar |= "*".equals(name); //$NON-NLS-1$
+ String escapedName1 = name.replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$
+ String escapedName2 = escapedName1.replace("*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$
+ regex.append(escapedName2);
+ if (!iName.hasNext()) {
+ break;
+ }
+ regex.append('|');
+ }
+ _supportedAnnotationTypesPattern = Pattern.compile(regex.toString());
+ }
+ else {
+ _supportedAnnotationTypesPattern = null;
+ }
+ _supportsStar = supportsStar;
+ }
+
+ /**
+ * Compute the subset of <code>annotations</code> that are described by <code>annotationTypes</code>,
+ * and determine whether the processor should be called. A processor will be called if it has
+ * any annotations to process, or if it supports "*", or if it was called in a previous round.
+ * If the return value of this method is true once for a given processor, then it will always be true on
+ * subsequent calls.
+ *
+ * @param annotations a set of annotation types
+ * @param result an empty modifiable set, which upon return will contain a subset of <code>annotations</code>, which may be empty but will not be null.
+ * @return true if the processor should be called on this round.
+ */
+ public boolean computeSupportedAnnotations(Set<TypeElement> annotations, Set<TypeElement> result)
+ {
+ if (null != annotations && !annotations.isEmpty() && null != _supportedAnnotationTypesPattern) {
+ for (TypeElement annotation : annotations) {
+ Matcher matcher = _supportedAnnotationTypesPattern.matcher(annotation.getQualifiedName().toString());
+ if (matcher.matches()) {
+ result.add(annotation);
+ }
+ }
+ }
+ boolean call = _hasBeenCalled || _supportsStar || !result.isEmpty();
+ _hasBeenCalled |= call;
+ return call;
+ }
+
+ /**
+ * @return true if the processor included "*" among its list of supported annotations.
+ */
+ public boolean supportsStar()
+ {
+ return _supportsStar;
+ }
+
+ /**
+ * Must be called at the beginning of a build to ensure that no information is
+ * carried over from the previous build. In particular, processors are
+ * required to be called on every round after the round in which they are
+ * first called; this method resets the "has been called" flag.
+ */
+ public void reset()
+ {
+ _hasBeenCalled = false;
+ }
+
+ @Override
+ public int hashCode() {
+ return _processor.getClass().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ProcessorInfo other = (ProcessorInfo) obj;
+ if (!_processor.getClass().equals(other._processor.getClass()))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString()
+ {
+ return _processor.getClass().getName();
+ }
+
+ /**
+ * @return a string representing the set of supported annotation types, in a format
+ * suitable for debugging. The format is unspecified and subject to change.
+ */
+ public String getSupportedAnnotationTypesAsString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ Iterator<String> iAnnots = _processor.getSupportedAnnotationTypes().iterator();
+ boolean hasNext = iAnnots.hasNext();
+ while (hasNext) {
+ sb.append(iAnnots.next());
+ hasNext = iAnnots.hasNext();
+ if (hasNext) {
+ sb.append(',');
+ }
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+}
+
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java
new file mode 100644
index 0000000..84d4d26
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Manages context during a single round of annotation processing.
+ */
+public class RoundDispatcher {
+
+ private final Set<TypeElement> _unclaimedAnnotations;
+ private final RoundEnvironment _roundEnv;
+ private final IProcessorProvider _provider;
+ private boolean _searchForStar = false;
+ private final PrintWriter _traceProcessorInfo;
+ private final PrintWriter _traceRounds;
+
+ /**
+ * Processors discovered so far. This list may grow during the
+ * course of a round, as additional processors are discovered.
+ */
+ private final List<ProcessorInfo> _processors;
+
+ /**
+ * @param rootAnnotations a possibly empty but non-null set of annotations on the
+ * root compilation units of this round. A local copy of the set will be made, to
+ * avoid modifying the set passed in.
+ * @param traceProcessorInfo a PrintWriter that processor trace output will be sent
+ * to, or null if tracing is not desired.
+ * @param traceRounds
+ */
+ public RoundDispatcher(
+ IProcessorProvider provider,
+ RoundEnvironment env,
+ Set<TypeElement> rootAnnotations,
+ PrintWriter traceProcessorInfo,
+ PrintWriter traceRounds)
+ {
+ _provider = provider;
+ _processors = provider.getDiscoveredProcessors();
+ _roundEnv = env;
+ _unclaimedAnnotations = new HashSet<>(rootAnnotations);
+ _traceProcessorInfo = traceProcessorInfo;
+ _traceRounds = traceRounds;
+ }
+
+ /**
+ * Handle a complete round, dispatching to all appropriate processors.
+ */
+ public void round()
+ {
+ if (null != _traceRounds) {
+ StringBuilder sbElements = new StringBuilder();
+ sbElements.append("\tinput files: {"); //$NON-NLS-1$
+ Iterator<? extends Element> iElements = _roundEnv.getRootElements().iterator();
+ boolean hasNext = iElements.hasNext();
+ while (hasNext) {
+ sbElements.append(iElements.next());
+ hasNext = iElements.hasNext();
+ if (hasNext) {
+ sbElements.append(',');
+ }
+ }
+ sbElements.append('}');
+ _traceRounds.println(sbElements.toString());
+
+ StringBuilder sbAnnots = new StringBuilder();
+ sbAnnots.append("\tannotations: ["); //$NON-NLS-1$
+ Iterator<TypeElement> iAnnots = _unclaimedAnnotations.iterator();
+ hasNext = iAnnots.hasNext();
+ while (hasNext) {
+ sbAnnots.append(iAnnots.next());
+ hasNext = iAnnots.hasNext();
+ if (hasNext) {
+ sbAnnots.append(',');
+ }
+ }
+ sbAnnots.append(']');
+ _traceRounds.println(sbAnnots.toString());
+
+ _traceRounds.println("\tlast round: " + _roundEnv.processingOver()); //$NON-NLS-1$
+ }
+
+ // If there are no root annotations, try to find a processor that claims "*"
+ _searchForStar = _unclaimedAnnotations.isEmpty();
+
+ // Iterate over all the already-found processors, giving each one a chance at the unclaimed
+ // annotations. If a processor is called at all, it is called on every subsequent round
+ // including the final round, but it may be called with an empty set of annotations.
+ for (ProcessorInfo pi : _processors) {
+ handleProcessor(pi);
+ }
+
+ // If there are any unclaimed annotations, or if there were no root annotations and
+ // we have not yet run into a processor that claimed "*", continue discovery.
+ while (_searchForStar || !_unclaimedAnnotations.isEmpty()) {
+ ProcessorInfo pi = _provider.discoverNextProcessor();
+ if (null == pi) {
+ // There are no more processors to be discovered.
+ break;
+ }
+ handleProcessor(pi);
+ }
+
+ // TODO: If !unclaimedAnnos.isEmpty(), issue a warning.
+ }
+
+ /**
+ * Evaluate a single processor. Depending on the unclaimed annotations,
+ * the annotations this processor supports, and whether it has already been
+ * called in a previous round, possibly call its process() method.
+ */
+ private void handleProcessor(ProcessorInfo pi)
+ {
+ try {
+ Set<TypeElement> annotationsToProcess = new HashSet<>();
+ boolean shouldCall = pi.computeSupportedAnnotations(
+ _unclaimedAnnotations, annotationsToProcess);
+ if (shouldCall) {
+ boolean claimed = pi._processor.process(annotationsToProcess, _roundEnv);
+ if (null != _traceProcessorInfo && !_roundEnv.processingOver()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Processor "); //$NON-NLS-1$
+ sb.append(pi._processor.getClass().getName());
+ sb.append(" matches ["); //$NON-NLS-1$
+ Iterator<TypeElement> i = annotationsToProcess.iterator();
+ boolean hasNext = i.hasNext();
+ while (hasNext) {
+ sb.append(i.next());
+ hasNext = i.hasNext();
+ if (hasNext) {
+ sb.append(' ');
+ }
+ }
+ sb.append("] and returns "); //$NON-NLS-1$
+ sb.append(claimed);
+ _traceProcessorInfo.println(sb.toString());
+ }
+ if (claimed) {
+ // The processor claimed its annotations.
+ _unclaimedAnnotations.removeAll(annotationsToProcess);
+ if (pi.supportsStar()) {
+ _searchForStar = false;
+ }
+ }
+ }
+ } catch (Throwable e) {
+ // If a processor throws an exception (as opposed to reporting an error),
+ // report it and abort compilation by throwing AbortCompilation.
+ _provider.reportProcessorException(pi._processor, new Exception(e));
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java
new file mode 100644
index 0000000..3f8515c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java
@@ -0,0 +1,257 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2019 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * IBM Corporation - Fix for bug 328575
+ * het@google.com - Bug 415274 - Annotation processing throws a NPE in getElementsAnnotatedWith()
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.dispatch;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+
+import org.eclipse.jdt.internal.compiler.apt.model.Factory;
+import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl;
+import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+
+public class RoundEnvImpl implements RoundEnvironment
+{
+ private final BaseProcessingEnvImpl _processingEnv;
+ private final boolean _isLastRound;
+ private final CompilationUnitDeclaration[] _units;
+ private final ManyToMany<TypeElement, Element> _annoToUnit;
+ private final ReferenceBinding[] _binaryTypes;
+ private final Factory _factory;
+ private Set<Element> _rootElements = null;
+
+ public RoundEnvImpl(CompilationUnitDeclaration[] units, ReferenceBinding[] binaryTypeBindings, boolean isLastRound, BaseProcessingEnvImpl env) {
+ _processingEnv = env;
+ _isLastRound = isLastRound;
+ _units = units;
+ _factory = _processingEnv.getFactory();
+
+ // Discover the annotations that will be passed to Processor.process()
+ AnnotationDiscoveryVisitor visitor = new AnnotationDiscoveryVisitor(_processingEnv);
+ if (_units != null) {
+ for (CompilationUnitDeclaration unit : _units) {
+ unit.scope.environment.suppressImportErrors = true;
+ unit.traverse(visitor, unit.scope);
+ unit.scope.environment.suppressImportErrors = false;
+ }
+ }
+ _annoToUnit = visitor._annoToElement;
+ if (binaryTypeBindings != null) collectAnnotations(binaryTypeBindings);
+ _binaryTypes = binaryTypeBindings;
+ }
+
+ private void collectAnnotations(ReferenceBinding[] referenceBindings) {
+ for (ReferenceBinding referenceBinding : referenceBindings) {
+ // collect all annotations from the binary types
+ if (referenceBinding instanceof ParameterizedTypeBinding) {
+ referenceBinding = ((ParameterizedTypeBinding) referenceBinding).genericType();
+ }
+ AnnotationBinding[] annotationBindings = Factory.getPackedAnnotationBindings(referenceBinding.getAnnotations());
+ for (AnnotationBinding annotationBinding : annotationBindings) {
+ TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
+ Element element = _factory.newElement(referenceBinding);
+ _annoToUnit.put(anno, element);
+ }
+ FieldBinding[] fieldBindings = referenceBinding.fields();
+ for (FieldBinding fieldBinding : fieldBindings) {
+ annotationBindings = Factory.getPackedAnnotationBindings(fieldBinding.getAnnotations());
+ for (AnnotationBinding annotationBinding : annotationBindings) {
+ TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
+ Element element = _factory.newElement(fieldBinding);
+ _annoToUnit.put(anno, element);
+ }
+ }
+ MethodBinding[] methodBindings = referenceBinding.methods();
+ for (MethodBinding methodBinding : methodBindings) {
+ annotationBindings = Factory.getPackedAnnotationBindings(methodBinding.getAnnotations());
+ for (AnnotationBinding annotationBinding : annotationBindings) {
+ TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType());
+ Element element = _factory.newElement(methodBinding);
+ _annoToUnit.put(anno, element);
+ }
+ }
+ ReferenceBinding[] memberTypes = referenceBinding.memberTypes();
+ collectAnnotations(memberTypes);
+ }
+ }
+
+ /**
+ * Return the set of annotation types that were discovered on the root elements.
+ * This does not include inherited annotations, only those directly on the root
+ * elements.
+ * @return a set of annotation types, possibly empty.
+ */
+ public Set<TypeElement> getRootAnnotations()
+ {
+ return Collections.unmodifiableSet(_annoToUnit.getKeySet());
+ }
+
+ @Override
+ public boolean errorRaised()
+ {
+ return _processingEnv.errorRaised();
+ }
+
+ /**
+ * From the set of root elements and their enclosed elements, return the subset that are annotated
+ * with {@code a}. If {@code a} is annotated with the {@link java.lang.annotation.Inherited}
+ * annotation, include those elements that inherit the annotation from their superclasses.
+ * Note that {@link java.lang.annotation.Inherited} only applies to classes (i.e. TypeElements).
+ */
+ @Override
+ public Set<? extends Element> getElementsAnnotatedWith(TypeElement a)
+ {
+ if (a.getKind() != ElementKind.ANNOTATION_TYPE) {
+ throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$
+ }
+ Binding annoBinding = ((TypeElementImpl)a)._binding;
+ if (0 != (annoBinding.getAnnotationTagBits() & TagBits.AnnotationInherited)) {
+ Set<Element> annotatedElements = new HashSet<>(_annoToUnit.getValues(a));
+ // For all other root elements that are TypeElements, and for their recursively enclosed
+ // types, add each element if it has a superclass are annotated with 'a'
+ ReferenceBinding annoTypeBinding = (ReferenceBinding) annoBinding;
+ for (TypeElement element : ElementFilter.typesIn(getRootElements())) {
+ ReferenceBinding typeBinding = (ReferenceBinding)((TypeElementImpl)element)._binding;
+ addAnnotatedElements(annoTypeBinding, typeBinding, annotatedElements);
+ }
+ return Collections.unmodifiableSet(annotatedElements);
+ }
+ return Collections.unmodifiableSet(_annoToUnit.getValues(a));
+ }
+
+ /**
+ * For every type in types that is a class and that is annotated with anno, either directly or by inheritance,
+ * add that type to result. Recursively descend on each types's child classes as well.
+ * @param anno the compiler binding for an annotation type
+ * @param type a type, not necessarily a class
+ * @param result must be a modifiable Set; will accumulate annotated classes
+ */
+ private void addAnnotatedElements(ReferenceBinding anno, ReferenceBinding type, Set<Element> result) {
+ if (type.isClass()) {
+ if (inheritsAnno(type, anno)) {
+ result.add(_factory.newElement(type));
+ }
+ }
+ for (ReferenceBinding element : type.memberTypes()) {
+ addAnnotatedElements(anno, element, result);
+ }
+ }
+
+ /**
+ * Check whether an element has a superclass that is annotated with an @Inherited annotation.
+ * @param element must be a class (not an interface, enum, etc.).
+ * @param anno must be an annotation type, and must be @Inherited
+ * @return true if element has a superclass that is annotated with anno
+ */
+ private boolean inheritsAnno(ReferenceBinding element, ReferenceBinding anno) {
+ ReferenceBinding searchedElement = element;
+ do {
+ if (searchedElement instanceof ParameterizedTypeBinding) {
+ searchedElement = ((ParameterizedTypeBinding) searchedElement).genericType();
+ }
+ AnnotationBinding[] annos = Factory.getPackedAnnotationBindings(searchedElement.getAnnotations());
+ for (AnnotationBinding annoBinding : annos) {
+ if (annoBinding.getAnnotationType() == anno) { //$IDENTITY-COMPARISON$
+ // element is annotated with anno
+ return true;
+ }
+ }
+ } while (null != (searchedElement = searchedElement.superclass()));
+ return false;
+ }
+
+ @Override
+ public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a)
+ {
+ String canonicalName = a.getCanonicalName();
+ if (canonicalName == null) {
+ // null for anonymous and local classes or an array of those
+ throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$
+ }
+ TypeElement annoType = _processingEnv.getElementUtils().getTypeElement(canonicalName);
+ if (annoType == null) {
+ return Collections.emptySet();
+ }
+ return getElementsAnnotatedWith(annoType);
+ }
+
+ @Override
+ public Set<? extends Element> getRootElements()
+ {
+ if (_units == null) {
+ return Collections.emptySet();
+ }
+ if (_rootElements == null) {
+ Set<Element> elements = new HashSet<>(_units.length);
+ for (CompilationUnitDeclaration unit : _units) {
+ if (unit.moduleDeclaration != null && unit.moduleDeclaration.binding != null) {
+ Element m = _factory.newElement(unit.moduleDeclaration.binding);
+ elements.add(m);
+ continue;
+ }
+ if (null == unit.scope || null == unit.scope.topLevelTypes)
+ continue;
+ for (SourceTypeBinding binding : unit.scope.topLevelTypes) {
+ Element element = _factory.newElement(binding);
+ if (null == element) {
+ throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + binding); //$NON-NLS-1$
+ }
+ elements.add(element);
+ }
+ }
+ if (this._binaryTypes != null) {
+ for (ReferenceBinding typeBinding : _binaryTypes) {
+ Element element = _factory.newElement(typeBinding);
+ if (null == element) {
+ throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + typeBinding); //$NON-NLS-1$
+ }
+ elements.add(element);
+ ModuleBinding binding = typeBinding.module();
+ if (binding != null) {
+ Element m = _factory.newElement(binding);
+ elements.add(m);
+ }
+ }
+ }
+ _rootElements = elements;
+ }
+ return _rootElements;
+ }
+
+ @Override
+ public boolean processingOver()
+ {
+ return _isLastRound;
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java
new file mode 100644
index 0000000..6687e7b
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2017 Vladimir Piskarev 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
+ *
+ * Contributors:
+ * Vladimir Piskarev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+
+public class AnnotationMemberValue extends AnnotationValueImpl {
+
+ private final MethodBinding _methodBinding;
+
+ /**
+ * @param value
+ * The JDT representation of a compile-time constant. See
+ * {@link org.eclipse.jdt.internal.compiler.lookup.ElementValuePair#getValue()} for possible object types:
+ * <ul>
+ * <li>{@link org.eclipse.jdt.internal.compiler.impl.Constant} for member
+ * of primitive type or String</li>
+ * <li>{@link org.eclipse.jdt.internal.compiler.lookup.TypeBinding} for a member value of type
+ * {@link java.lang.Class}</li>
+ * <li>{@link org.eclipse.jdt.internal.compiler.lookup.FieldBinding} for an enum constant</li>
+ * <li>{@link org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding} for an annotation instance</li>
+ * <li><code>Object[]</code> for a member value of array type, where the
+ * array entries are one of the above</li>
+ * </ul>
+ * @param methodBinding the method binding that defined this member value pair
+ */
+ public AnnotationMemberValue(BaseProcessingEnvImpl env, Object value, MethodBinding methodBinding) {
+ super(env, value, methodBinding.returnType);
+ _methodBinding = methodBinding;
+ }
+
+ /**
+ * @return the method binding that defined this member value pair.
+ */
+ public MethodBinding getMethodBinding() {
+ return _methodBinding;
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java
new file mode 100644
index 0000000..5b9fd1c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java
@@ -0,0 +1,561 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * het@google.com - Bug 441790
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.MirroredTypeException;
+import javax.lang.model.type.MirroredTypesException;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+public class AnnotationMirrorImpl implements AnnotationMirror, InvocationHandler {
+
+ public final BaseProcessingEnvImpl _env;
+ public final AnnotationBinding _binding;
+
+ /* package */ AnnotationMirrorImpl(BaseProcessingEnvImpl env, AnnotationBinding binding) {
+ _env = env;
+ _binding = binding;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AnnotationMirrorImpl) {
+ if (this._binding == null) {
+ return ((AnnotationMirrorImpl) obj)._binding == null;
+ }
+ return equals(this._binding, ((AnnotationMirrorImpl) obj)._binding);
+ }
+ return obj == null ? false : obj.equals(this); // obj could be wrapped by a proxy.
+ }
+
+ private static boolean equals(AnnotationBinding annotationBinding, AnnotationBinding annotationBinding2) {
+ if (annotationBinding.getAnnotationType() != annotationBinding2.getAnnotationType()) return false; //$IDENTITY-COMPARISON$
+ final ElementValuePair[] elementValuePairs = annotationBinding.getElementValuePairs();
+ final ElementValuePair[] elementValuePairs2 = annotationBinding2.getElementValuePairs();
+ final int length = elementValuePairs.length;
+ if (length != elementValuePairs2.length) return false;
+ loop: for (int i = 0; i < length; i++) {
+ ElementValuePair pair = elementValuePairs[i];
+ // loop on the given pair to make sure one will match
+ for (int j = 0; j < length; j++) {
+ ElementValuePair pair2 = elementValuePairs2[j];
+ if (pair.binding == pair2.binding) {
+ if (pair.value == null) {
+ if (pair2.value == null) {
+ continue loop;
+ }
+ return false;
+ } else {
+ if (pair2.value == null) return false;
+ if (pair2.value instanceof Object[] && pair.value instanceof Object[]) {
+ if (!Arrays.equals((Object[]) pair.value, (Object[]) pair2.value)) {
+ return false;
+ }
+ } else if (!pair2.value.equals(pair.value)){
+ return false;
+ }
+ }
+ continue loop;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public DeclaredType getAnnotationType() {
+ return (DeclaredType) _env.getFactory().newTypeMirror(_binding.getAnnotationType());
+ }
+
+ /**
+ * @return all the members of this annotation mirror that have explicit values.
+ * Default values are not included.
+ */
+ @Override
+ public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValues() {
+ if (this._binding == null) {
+ return Collections.emptyMap();
+ }
+ ElementValuePair[] pairs = _binding.getElementValuePairs();
+ Map<ExecutableElement, AnnotationValue> valueMap =
+ new LinkedHashMap<>(pairs.length);
+ for (ElementValuePair pair : pairs) {
+ MethodBinding method = pair.getMethodBinding();
+ if (method == null) {
+ // ideally we should be able to create a fake ExecutableElementImpl
+ continue;
+ }
+ ExecutableElement e = new ExecutableElementImpl(_env, method);
+ AnnotationValue v = new AnnotationMemberValue(_env, pair.getValue(), method);
+ valueMap.put(e, v);
+ }
+ return Collections.unmodifiableMap(valueMap);
+ }
+
+ /**
+ * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(AnnotationMirror)
+ * @return all the members of this annotation mirror that have explicit or default
+ * values.
+ */
+ public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults() {
+ if (this._binding == null) {
+ return Collections.emptyMap();
+ }
+ ElementValuePair[] pairs = _binding.getElementValuePairs();
+ ReferenceBinding annoType = _binding.getAnnotationType();
+ Map<ExecutableElement, AnnotationValue> valueMap =
+ new LinkedHashMap<>();
+ for (MethodBinding method : annoType.methods()) {
+ // if binding is in ElementValuePair list, then get value from there
+ boolean foundExplicitValue = false;
+ for (int i = 0; i < pairs.length; ++i) {
+ MethodBinding explicitBinding = pairs[i].getMethodBinding();
+ if (method == explicitBinding) {
+ ExecutableElement e = new ExecutableElementImpl(_env, explicitBinding);
+ AnnotationValue v = new AnnotationMemberValue(_env, pairs[i].getValue(), explicitBinding);
+ valueMap.put(e, v);
+ foundExplicitValue = true;
+ break;
+ }
+ }
+ // else get default value if one exists
+ if (!foundExplicitValue) {
+ Object defaultVal = method.getDefaultValue();
+ if (null != defaultVal) {
+ ExecutableElement e = new ExecutableElementImpl(_env, method);
+ AnnotationValue v = new AnnotationMemberValue(_env, defaultVal, method);
+ valueMap.put(e, v);
+ }
+ }
+ }
+ return Collections.unmodifiableMap(valueMap);
+ }
+
+ @Override
+ public int hashCode() {
+ if (this._binding == null) return this._env.hashCode();
+ return this._binding.hashCode();
+ }
+
+ /*
+ * Used by getAnnotation(), which returns a reflective proxy of the annotation class. When processors then
+ * invoke methods such as value() on the annotation proxy, this method is called.
+ * <p>
+ * A challenge here is that the processor was not necessarily compiled against the same annotation
+ * definition that the compiler is looking at right now, not to mention that the annotation itself
+ * may be defective in source. So the actual type of the value may be quite different than the
+ * type expected by the caller, which will result in a ClassCastException, which is ugly for the
+ * processor to try to catch. So we try to catch and correct this type mismatch where possible.
+ * <p>
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+ {
+ if (this._binding == null) return null;
+ final String methodName = method.getName();
+ if ( args == null || args.length == 0 ) {
+ if( methodName.equals("hashCode") ) { //$NON-NLS-1$
+ return Integer.valueOf(hashCode());
+ }
+ else if( methodName.equals("toString") ) { //$NON-NLS-1$
+ return toString();
+ }
+ else if( methodName.equals("annotationType")) { //$NON-NLS-1$
+ return proxy.getClass().getInterfaces()[0];
+ }
+ }
+ else if ( args.length == 1 && methodName.equals("equals") ) { //$NON-NLS-1$
+ return Boolean.valueOf(equals(args[0]));
+ }
+
+ // If it's not one of the above methods, it must be an annotation member, so it cannot take any arguments
+ if ( args != null && args.length != 0 ) {
+ throw new NoSuchMethodException("method " + method.getName() + formatArgs(args) + " does not exist on annotation " + toString()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ final MethodBinding methodBinding = getMethodBinding(methodName);
+ if ( methodBinding == null ) {
+ throw new NoSuchMethodException("method " + method.getName() + "() does not exist on annotation" + toString()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ Object actualValue = null;
+ boolean foundMethod = false;
+ ElementValuePair[] pairs = _binding.getElementValuePairs();
+ for (ElementValuePair pair : pairs) {
+ if (methodName.equals(new String(pair.getName()))) {
+ actualValue = pair.getValue();
+ foundMethod = true;
+ break;
+ }
+ }
+ if (!foundMethod) {
+ // couldn't find explicit value; see if there's a default
+ actualValue = methodBinding.getDefaultValue();
+ }
+ Class<?> expectedType = method.getReturnType();
+ TypeBinding actualType = methodBinding.returnType;
+ return getReflectionValue(actualValue, actualType, expectedType);
+ }
+
+ @Override
+ public String toString() {
+ TypeMirror decl = getAnnotationType();
+ StringBuilder sb = new StringBuilder();
+ sb.append('@');
+ sb.append(decl.toString());
+ Map<? extends ExecutableElement, ? extends AnnotationValue> values = getElementValues();
+ if (!values.isEmpty()) {
+ sb.append('(');
+ boolean first = true;
+ for (Entry<? extends ExecutableElement, ? extends AnnotationValue> e : values.entrySet()) {
+ if (!first) {
+ sb.append(", "); //$NON-NLS-1$
+ }
+ first = false;
+ sb.append(e.getKey().getSimpleName());
+ sb.append(" = "); //$NON-NLS-1$
+ sb.append(e.getValue().toString());
+ }
+ sb.append(')');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Used for constructing exception message text.
+ * @return a string like "(a, b, c)".
+ */
+ private String formatArgs(final Object[] args)
+ {
+ // estimate that each class name (plus the separators) is 10 characters long plus 2 for "()".
+ final StringBuilder builder = new StringBuilder(args.length * 8 + 2 );
+ builder.append('(');
+ for( int i=0; i<args.length; i++ )
+ {
+ if( i > 0 )
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(args[i].getClass().getName());
+ }
+ builder.append(')');
+ return builder.toString();
+ }
+
+ /**
+ * Find a particular annotation member by name.
+ * @return a compiler method binding, or null if no member was found.
+ */
+ private MethodBinding getMethodBinding(String name) {
+ ReferenceBinding annoType = _binding.getAnnotationType();
+ MethodBinding[] methods = annoType.getMethods(name.toCharArray());
+ for (MethodBinding method : methods) {
+ // annotation members have no parameters
+ if (method.parameters.length == 0) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Convert an annotation member value from JDT into Reflection, and from whatever its actual type
+ * is into whatever type the reflective invoker of a method is expecting.
+ * <p>
+ * Only certain types are permitted as member values. Specifically, a member must be a constant,
+ * and must be either a primitive type, String, Class, an enum constant, an annotation, or an
+ * array of any of those. Multidimensional arrays are not permitted.
+ *
+ * @param actualValue the value as represented by {@link ElementValuePair#getValue()}
+ * @param actualType the return type of the corresponding {@link MethodBinding}
+ * @param expectedType the type that the reflective method invoker is expecting
+ * @return an object of the expected type representing the annotation member value,
+ * or an appropriate dummy value (such as null) if no value is available
+ */
+ private Object getReflectionValue(Object actualValue, TypeBinding actualType, Class<?> expectedType)
+ {
+ if (null == expectedType) {
+ // With no expected type, we can't even guess at a conversion
+ return null;
+ }
+ if (null == actualValue) {
+ // Return a type-appropriate equivalent of null
+ return Factory.getMatchingDummyValue(expectedType);
+ }
+ if (expectedType.isArray()) {
+ if (Class.class.equals(expectedType.getComponentType())) {
+ // package Class[]-valued return as a MirroredTypesException
+ if (actualType.isArrayType() && ((ArrayBinding)actualType).leafComponentType.erasure().id == TypeIds.T_JavaLangClass) {
+
+ Object[] bindings;
+ if(actualValue instanceof Object[]) {
+ bindings = (Object[]) actualValue;
+ } else if(actualValue instanceof TypeBinding) {
+ // when a single class element is passed to array: @AnnotationType(Something.class)
+ bindings = new Object[] {actualValue};
+ } else {
+ bindings = null;
+ }
+
+ if(bindings != null) {
+ List<TypeMirror> mirrors = new ArrayList<>(bindings.length);
+ for (int i = 0; i < bindings.length; ++i) {
+ if (bindings[i] instanceof TypeBinding) {
+ mirrors.add(_env.getFactory().newTypeMirror((TypeBinding)bindings[i]));
+ }
+ }
+ throw new MirroredTypesException(mirrors);
+ }
+ }
+ // TODO: actual value is not a TypeBinding[]. Should we return a TypeMirror[] around an ErrorType?
+ return null;
+ }
+ // Handle arrays of types other than Class, e.g., int[], MyEnum[], ...
+ return convertJDTArrayToReflectionArray(actualValue, actualType, expectedType);
+ }
+ else if (Class.class.equals(expectedType)) {
+ // package the Class-valued return as a MirroredTypeException
+ if (actualValue instanceof TypeBinding) {
+ TypeMirror mirror = _env.getFactory().newTypeMirror((TypeBinding)actualValue);
+ throw new MirroredTypeException(mirror);
+ }
+ else {
+ // TODO: actual value is not a TypeBinding. Should we return a TypeMirror around an ErrorType?
+ return null;
+ }
+ }
+ else {
+ // Handle unitary values of type other than Class, e.g., int, MyEnum, ...
+ return convertJDTValueToReflectionType(actualValue, actualType, expectedType);
+ }
+ }
+
+ /**
+ * Convert an array of JDT types as obtained from ElementValuePair.getValue()
+ * (e.g., an Object[] containing IntConstant elements) to the type expected by
+ * a reflective method invocation (e.g., int[]).
+ * <p>
+ * This does not handle arrays of Class, but it does handle primitives, enum constants,
+ * and types such as String.
+ * @param jdtValue the actual value returned by ElementValuePair.getValue() or MethodBinding.getDefault()
+ * @param jdtType the return type of the annotation method binding
+ * @param expectedType the type that the invoker of the method is expecting; must be an array type
+ * @return an Object which is, e.g., an int[]; or null, if an array cannot be created.
+ */
+ private Object convertJDTArrayToReflectionArray(Object jdtValue, TypeBinding jdtType, Class<?> expectedType)
+ {
+ assert null != expectedType && expectedType.isArray();
+ if (!jdtType.isArrayType()) {
+ // the compiler says that the type binding isn't an array type; this probably means
+ // that there's some sort of syntax error.
+ return null;
+ }
+ Object[] jdtArray;
+ // See bug 261969: it's legal to pass a solo element for an array-typed value
+ if (jdtValue != null && !(jdtValue instanceof Object[])) {
+ // Create an array of the expected type
+ jdtArray = (Object[]) Array.newInstance(jdtValue.getClass(), 1);
+ jdtArray[0] = jdtValue;
+ } else {
+ jdtArray = (Object[])jdtValue;
+ }
+ TypeBinding jdtLeafType = jdtType.leafComponentType();
+ Class<?> expectedLeafType = expectedType.getComponentType();
+ final int length = jdtArray.length;
+ final Object returnArray = Array.newInstance(expectedLeafType, length);
+ for (int i = 0; i < length; ++i) {
+ Object jdtElementValue = jdtArray[i];
+ if (expectedLeafType.isPrimitive() || String.class.equals(expectedLeafType)) {
+ if (jdtElementValue instanceof Constant) {
+ if (boolean.class.equals(expectedLeafType)) {
+ Array.setBoolean(returnArray, i, ((Constant)jdtElementValue).booleanValue());
+ }
+ else if (byte.class.equals(expectedLeafType)) {
+ Array.setByte(returnArray, i, ((Constant)jdtElementValue).byteValue());
+ }
+ else if (char.class.equals(expectedLeafType)) {
+ Array.setChar(returnArray, i, ((Constant)jdtElementValue).charValue());
+ }
+ else if (double.class.equals(expectedLeafType)) {
+ Array.setDouble(returnArray, i, ((Constant)jdtElementValue).doubleValue());
+ }
+ else if (float.class.equals(expectedLeafType)) {
+ Array.setFloat(returnArray, i, ((Constant)jdtElementValue).floatValue());
+ }
+ else if (int.class.equals(expectedLeafType)) {
+ Array.setInt(returnArray, i, ((Constant)jdtElementValue).intValue());
+ }
+ else if (long.class.equals(expectedLeafType)) {
+ Array.setLong(returnArray, i, ((Constant)jdtElementValue).longValue());
+ }
+ else if (short.class.equals(expectedLeafType)) {
+ Array.setShort(returnArray, i, ((Constant)jdtElementValue).shortValue());
+ }
+ else if (String.class.equals(expectedLeafType)) {
+ Array.set(returnArray, i, ((Constant)jdtElementValue).stringValue());
+ }
+ }
+ else {
+ // Primitive or string is expected, but our actual value cannot be coerced into one.
+ // TODO: if the actual value is an array of primitives, should we unpack the first one?
+ Factory.setArrayMatchingDummyValue(returnArray, i, expectedLeafType);
+ }
+ }
+ else if (expectedLeafType.isEnum()) {
+ Object returnVal = null;
+ if (jdtLeafType != null && jdtLeafType.isEnum() && jdtElementValue instanceof FieldBinding) {
+ FieldBinding binding = (FieldBinding)jdtElementValue;
+ try {
+ Field returnedField = null;
+ returnedField = expectedLeafType.getField( new String(binding.name) );
+ if (null != returnedField) {
+ returnVal = returnedField.get(null);
+ }
+ }
+ catch (NoSuchFieldException nsfe) {
+ // return null
+ }
+ catch (IllegalAccessException iae) {
+ // return null
+ }
+ }
+ Array.set(returnArray, i, returnVal);
+ }
+ else if (expectedLeafType.isAnnotation()) {
+ // member value is expected to be an annotation type. Wrap it in an Annotation proxy.
+ Object returnVal = null;
+ if (jdtLeafType.isAnnotationType() && jdtElementValue instanceof AnnotationBinding) {
+ AnnotationMirrorImpl annoMirror =
+ (AnnotationMirrorImpl)_env.getFactory().newAnnotationMirror((AnnotationBinding)jdtElementValue);
+ returnVal = Proxy.newProxyInstance(expectedLeafType.getClassLoader(),
+ new Class[]{ expectedLeafType }, annoMirror );
+ }
+ Array.set(returnArray, i, returnVal);
+ }
+ else {
+ Array.set(returnArray, i, null);
+ }
+ }
+ return returnArray;
+ }
+
+ /**
+ * Convert a JDT annotation value as obtained from ElementValuePair.getValue()
+ * (e.g., IntConstant, FieldBinding, etc.) to the type expected by a reflective
+ * method invocation (e.g., int, an enum constant, etc.).
+ * @return a value of type {@code expectedType}, or a dummy value of that type if
+ * the actual value cannot be converted.
+ */
+ private Object convertJDTValueToReflectionType(Object jdtValue, TypeBinding actualType, Class<?> expectedType) {
+ if (expectedType.isPrimitive() || String.class.equals(expectedType)) {
+ if (jdtValue instanceof Constant) {
+ if (boolean.class.equals(expectedType)) {
+ return ((Constant)jdtValue).booleanValue();
+ }
+ else if (byte.class.equals(expectedType)) {
+ return ((Constant)jdtValue).byteValue();
+ }
+ else if (char.class.equals(expectedType)) {
+ return ((Constant)jdtValue).charValue();
+ }
+ else if (double.class.equals(expectedType)) {
+ return ((Constant)jdtValue).doubleValue();
+ }
+ else if (float.class.equals(expectedType)) {
+ return ((Constant)jdtValue).floatValue();
+ }
+ else if (int.class.equals(expectedType)) {
+ return ((Constant)jdtValue).intValue();
+ }
+ else if (long.class.equals(expectedType)) {
+ return ((Constant)jdtValue).longValue();
+ }
+ else if (short.class.equals(expectedType)) {
+ return ((Constant)jdtValue).shortValue();
+ }
+ else if (String.class.equals(expectedType)) {
+ return ((Constant)jdtValue).stringValue();
+ }
+ }
+ // Primitive or string is expected, but our actual value cannot be coerced into one.
+ // TODO: if the actual value is an array of primitives, should we unpack the first one?
+ return Factory.getMatchingDummyValue(expectedType);
+ }
+ else if (expectedType.isEnum()) {
+ Object returnVal = null;
+ if (actualType != null && actualType.isEnum() && jdtValue instanceof FieldBinding) {
+
+ FieldBinding binding = (FieldBinding)jdtValue;
+ try {
+ Field returnedField = null;
+ returnedField = expectedType.getField( new String(binding.name) );
+ if (null != returnedField) {
+ returnVal = returnedField.get(null);
+ }
+ }
+ catch (NoSuchFieldException nsfe) {
+ // return null
+ }
+ catch (IllegalAccessException iae) {
+ // return null
+ }
+ }
+ return null == returnVal ? Factory.getMatchingDummyValue(expectedType) : returnVal;
+ }
+ else if (expectedType.isAnnotation()) {
+ // member value is expected to be an annotation type. Wrap it in an Annotation proxy.
+ if (actualType.isAnnotationType() && jdtValue instanceof AnnotationBinding) {
+ AnnotationMirrorImpl annoMirror =
+ (AnnotationMirrorImpl)_env.getFactory().newAnnotationMirror((AnnotationBinding)jdtValue);
+ return Proxy.newProxyInstance(expectedType.getClassLoader(),
+ new Class[]{ expectedType }, annoMirror );
+ }
+ else {
+ // No way to cast a non-annotation value to an annotation type; return null to caller
+ return null;
+ }
+ }
+ else {
+ return Factory.getMatchingDummyValue(expectedType);
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java
new file mode 100644
index 0000000..5ed405d
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2017 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * het@google.com - Bug 441790
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.DoubleConstant;
+import org.eclipse.jdt.internal.compiler.impl.FloatConstant;
+import org.eclipse.jdt.internal.compiler.impl.LongConstant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
+import org.eclipse.jdt.internal.compiler.util.Util;
+
+public class AnnotationValueImpl implements AnnotationValue, TypeIds {
+
+ /*
+ * Additions to T_* constants in TypeIds.
+ */
+ private static final int T_AnnotationMirror = -1;
+ private static final int T_EnumConstant = -2;
+ private static final int T_ClassObject = -3;
+ private static final int T_ArrayType = -4;
+
+ private final BaseProcessingEnvImpl _env;
+
+ /**
+ * The annotation value, as it would be returned by
+ * {@link #getValue()}. For instance, an Integer (for an int
+ * constant), a VariableElement (for an enum constant), or
+ * a List<AnnotationValueImpl> containing multiple such (for an array type).
+ */
+ private final Object _value;
+
+ /**
+ * The type stored in _value, represented as a T_* value from {@link TypeIds}
+ * or one of the additional T_* values defined in this class.
+ */
+ private final int _kind;
+
+ /**
+ * @param value
+ * The JDT representation of a compile-time constant. See
+ * {@link org.eclipse.jdt.internal.compiler.lookup.ElementValuePair#getValue()} for possible object types:
+ * <ul>
+ * <li>{@link org.eclipse.jdt.internal.compiler.impl.Constant} for member
+ * of primitive type or String</li>
+ * <li>{@link TypeBinding} for a member value of type
+ * {@link java.lang.Class}</li>
+ * <li>{@link FieldBinding} for an enum constant</li>
+ * <li>{@link AnnotationBinding} for an annotation instance</li>
+ * <li><code>Object[]</code> for a member value of array type, where the
+ * array entries are one of the above</li>
+ * </ul>
+ * @param type
+ * The JDT representation of the type of the constant, as determined
+ * by the return type of the element. This is needed because the type
+ * of the value may have been widened (e.g., byte to int) by the compiler
+ * and we need to call the proper visitor. This is used only for base types.
+ * If it is null or not a BaseTypeBinding, it is ignored and the type is
+ * determined from the type of the value.
+ */
+ public AnnotationValueImpl(BaseProcessingEnvImpl env, Object value, TypeBinding type) {
+ _env = env;
+ int kind[] = new int[1];
+ if (type == null) {
+ _value = convertToMirrorType(value, type, kind);
+ _kind = kind[0];
+ } else if (type.isArrayType()) {
+ List<AnnotationValue> convertedValues = null;
+ TypeBinding valueType = ((ArrayBinding)type).elementsType();
+ if (value instanceof Object[]) {
+ Object[] values = (Object[])value;
+ convertedValues = new ArrayList<>(values.length);
+ for (Object oneValue : values) {
+ convertedValues.add(new AnnotationValueImpl(_env, oneValue, valueType));
+ }
+ } else {
+ convertedValues = new ArrayList<>(1);
+ convertedValues.add(new AnnotationValueImpl(_env, value, valueType));
+ }
+ _value = Collections.unmodifiableList(convertedValues);
+ _kind = T_ArrayType;
+ } else {
+ _value = convertToMirrorType(value, type, kind);
+ _kind = kind[0];
+ }
+ }
+
+ /**
+ * Convert the JDT representation of a single constant into its javax.lang.model
+ * representation. For instance, convert a StringConstant into a String, or
+ * a FieldBinding into a VariableElement. This does not handle the case where
+ * value is an Object[].
+ * @param value the JDT object
+ * @param type the return type of the annotation member. If null or not a
+ * BaseTypeBinding, this is ignored and the value is inspected to determine type.
+ * @param kind an int array whose first element will be set to the type of the
+ * converted object, represented with T_* values from TypeIds or from this class.
+ * @return
+ */
+ private Object convertToMirrorType(Object value, TypeBinding type, int kind[]) {
+ if (type == null) {
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ } else if (type instanceof BaseTypeBinding || type.id == TypeIds.T_JavaLangString) {
+ if (value == null) {
+ if (type instanceof BaseTypeBinding
+ || type.id == TypeIds.T_JavaLangString) {
+ // return a string with error in it to reflect a value that could not be resolved
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ } else if (type.isAnnotationType()) {
+ kind[0] = T_AnnotationMirror;
+ return _env.getFactory().newAnnotationMirror(null);
+ }
+ } else if (value instanceof Constant) {
+ if (type instanceof BaseTypeBinding) {
+ kind[0] = ((BaseTypeBinding)type).id;
+ }
+ else if (type.id == TypeIds.T_JavaLangString) {
+ kind[0] = ((Constant)value).typeID();
+ } else {
+ // error case
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ switch (kind[0]) {
+ case T_boolean:
+ return ((Constant)value).booleanValue();
+ case T_byte:
+ return ((Constant)value).byteValue();
+ case T_char:
+ return ((Constant)value).charValue();
+ case T_double:
+ return ((Constant)value).doubleValue();
+ case T_float:
+ return ((Constant)value).floatValue();
+ case T_int:
+ try {
+ if (value instanceof LongConstant
+ || value instanceof DoubleConstant
+ || value instanceof FloatConstant) {
+ // error case
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ return ((Constant)value).intValue();
+ } catch (ShouldNotImplement e) {
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ case T_JavaLangString:
+ return ((Constant)value).stringValue();
+ case T_long:
+ return ((Constant)value).longValue();
+ case T_short:
+ return ((Constant)value).shortValue();
+ }
+ }
+ } else if (type.isEnum()) {
+ if (value instanceof FieldBinding) {
+ kind[0] = T_EnumConstant;
+ return _env.getFactory().newElement((FieldBinding) value);
+ } else {
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+ } else if (type.isAnnotationType()) {
+ if (value instanceof AnnotationBinding) {
+ kind[0] = T_AnnotationMirror;
+ return _env.getFactory().newAnnotationMirror((AnnotationBinding) value);
+ }
+ } else if (value instanceof TypeBinding) {
+ kind[0] = T_ClassObject;
+ return _env.getFactory().newTypeMirror((TypeBinding) value);
+ }
+ // error case
+ kind[0] = TypeIds.T_JavaLangString;
+ return "<error>"; //$NON-NLS-1$
+ }
+
+ @SuppressWarnings("unchecked") // Need to cast Object _value to a List<AnnotationValue>
+ @Override
+ public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
+ switch (_kind) {
+ case TypeIds.T_boolean:
+ return v.visitBoolean((Boolean)_value, p);
+ case TypeIds.T_byte:
+ return v.visitByte((Byte)_value, p);
+ case TypeIds.T_char:
+ return v.visitChar((Character)_value, p);
+ case TypeIds.T_double:
+ return v.visitDouble((Double)_value, p);
+ case TypeIds.T_float:
+ return v.visitFloat((Float)_value, p);
+ case TypeIds.T_int:
+ return v.visitInt((Integer)_value, p);
+ case TypeIds.T_JavaLangString:
+ return v.visitString((String)_value, p);
+ case TypeIds.T_long:
+ return v.visitLong((Long)_value, p);
+ case TypeIds.T_short:
+ return v.visitShort((Short)_value, p);
+ case T_EnumConstant:
+ return v.visitEnumConstant((VariableElement)_value, p);
+ case T_ClassObject:
+ return v.visitType((TypeMirror)_value, p);
+ case T_AnnotationMirror:
+ return v.visitAnnotation((AnnotationMirror)_value, p);
+ case T_ArrayType:
+ return v.visitArray((List<AnnotationValue>)_value, p);
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public Object getValue() {
+ return _value;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AnnotationValueImpl) {
+ return this._value.equals(((AnnotationValueImpl) obj)._value);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return this._value.hashCode() + this._kind;
+ }
+
+ @Override
+ public String toString() {
+ if (_value == null) {
+ return "null"; //$NON-NLS-1$
+ } else if (_value instanceof String) {
+ String value = (String) _value;
+ StringBuffer sb = new StringBuffer();
+ sb.append('"');
+ for (int i = 0; i < value.length(); i++) {
+ Util.appendEscapedChar(sb, value.charAt(i), true);
+ }
+ sb.append('"');
+ return sb.toString();
+ } else if (_value instanceof Character) {
+ StringBuffer sb = new StringBuffer();
+ sb.append('\'');
+ Util.appendEscapedChar(sb, ((Character) _value).charValue(), false);
+ sb.append('\'');
+ return sb.toString();
+ } else if (_value instanceof VariableElement) {
+ VariableElement enumDecl = (VariableElement) _value;
+ return enumDecl.asType().toString() + "." + enumDecl.getSimpleName(); //$NON-NLS-1$
+ } else if (_value instanceof Collection) {
+ // It must be Collection<AnnotationValue>
+ @SuppressWarnings("unchecked")
+ Collection<AnnotationValue> values = (Collection<AnnotationValue>) _value;
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ boolean first = true;
+ for (AnnotationValue annoValue : values) {
+ if (!first) {
+ sb.append(", "); //$NON-NLS-1$
+ }
+ first = false;
+ sb.append(annoValue.toString());
+ }
+ sb.append('}');
+ return sb.toString();
+ } else if (_value instanceof TypeMirror) {
+ return _value.toString() + ".class"; //$NON-NLS-1$
+ } else {
+ return _value.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java
new file mode 100644
index 0000000..d0ec21c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2014 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+
+/**
+ * Implementation of ArrayType, which represents an array of some type.
+ */
+public class ArrayTypeImpl extends TypeMirrorImpl implements ArrayType {
+
+ ArrayTypeImpl(BaseProcessingEnvImpl env, ArrayBinding binding) {
+ super(env, binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ArrayType#getComponentType()
+ */
+ @Override
+ public TypeMirror getComponentType() {
+ return _env.getFactory().newTypeMirror(((ArrayBinding)_binding).elementsType());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitArray(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings() {
+ AnnotationBinding[] oldies = ((ArrayBinding)_binding).getTypeAnnotations();
+ AnnotationBinding[] newbies = Binding.NO_ANNOTATIONS;
+ // Strip out the annotations on sub arrays
+ for (int i = 0, length = oldies == null ? 0 : oldies.length; i < length; i++) {
+ if (oldies[i] == null) {
+ System.arraycopy(oldies, 0, newbies = new AnnotationBinding[i], 0, i);
+ return newbies;
+ }
+ }
+ return newbies;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.ARRAY;
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java
new file mode 100644
index 0000000..e59d198
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2018 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of DeclaredType, which refers to a particular usage or instance of a type.
+ * Contrast with {@link javax.lang.model.element.TypeElement}, which is an element that potentially defines a family
+ * of DeclaredTypes.
+ */
+public class DeclaredTypeImpl extends TypeMirrorImpl implements DeclaredType {
+
+ private final ElementKind _elementKindHint;
+
+ /* package */ DeclaredTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding) {
+ super(env, binding);
+ _elementKindHint = null;
+ }
+
+ /**
+ * Create a DeclaredType that knows in advance what kind of element to produce from asElement().
+ * This is useful in the case where the type binding is to an unresolved type, but we know
+ * from context what type it is - e.g., an annotation type.
+ */
+ /* package */ DeclaredTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding, ElementKind elementKindHint) {
+ super(env, binding);
+ _elementKindHint = elementKindHint;
+ }
+
+ @Override
+ public Element asElement() {
+ TypeBinding prototype = null;
+ if (_binding instanceof TypeBinding) {
+ prototype = ((TypeBinding) _binding).prototype();
+ }
+ if (prototype != null) {
+ return _env.getFactory().newElement(prototype, _elementKindHint);
+ }
+ // The JDT compiler does not distinguish between type elements and declared types
+ return _env.getFactory().newElement((ReferenceBinding)_binding, _elementKindHint);
+ }
+
+ @Override
+ public TypeMirror getEnclosingType() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ ReferenceBinding enclosingType = binding.enclosingType();
+ if (enclosingType != null) {
+ return _env.getFactory().newTypeMirror(enclosingType);
+ }
+ return _env.getFactory().getNoType(TypeKind.NONE);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see javax.lang.model.type.DeclaredType#getTypeArguments()
+ * @see javax.lang.model.element.TypeElement#getTypeParameters().
+ */
+ @Override
+ public List<? extends TypeMirror> getTypeArguments() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ if (binding.isParameterizedType()) {
+ ParameterizedTypeBinding ptb = (ParameterizedTypeBinding)_binding;
+ TypeBinding[] arguments = ptb.arguments;
+ int length = arguments == null ? 0 : arguments.length;
+ if (length == 0) return Collections.emptyList();
+ List<TypeMirror> args = new ArrayList<>(length);
+ for (TypeBinding arg : arguments) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ if (binding.isGenericType()) {
+ TypeVariableBinding[] typeVariables = binding.typeVariables();
+ List<TypeMirror> args = new ArrayList<>(typeVariables.length);
+ for (TypeBinding arg : typeVariables) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitDeclared(this, p);
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.DECLARED;
+ }
+
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java
new file mode 100644
index 0000000..a9669d9
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2017 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Element represents any defined Java language element - a package,
+ * a method, a class or interface. Contrast with DeclaredType.
+ */
+public abstract class ElementImpl
+ implements javax.lang.model.element.Element, IElementInfo
+{
+ public final BaseProcessingEnvImpl _env;
+ public final Binding _binding;
+
+ protected ElementImpl(BaseProcessingEnvImpl env, Binding binding) {
+ _env = env;
+ _binding = binding;
+ }
+
+ @Override
+ public TypeMirror asType() {
+ return _env.getFactory().newTypeMirror(_binding);
+ }
+
+ /**
+ * @return the set of compiler annotation bindings on this element
+ */
+ protected abstract AnnotationBinding[] getAnnotationBindings();
+
+ /* Package any repeating annotations into containers, return others as is.
+ In the compiler bindings repeating annotations are left in as is, hence
+ this step. The return value would match what one would expect to see in
+ a class file.
+ */
+ public final AnnotationBinding [] getPackedAnnotationBindings() {
+ return Factory.getPackedAnnotationBindings(getAnnotationBindings());
+ }
+
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
+ A annotation = _env.getFactory().getAnnotation(getPackedAnnotationBindings(), annotationClass);
+ if (annotation != null || this.getKind() != ElementKind.CLASS || annotationClass.getAnnotation(Inherited.class) == null)
+ return annotation;
+
+ ElementImpl superClass = (ElementImpl) _env.getFactory().newElement(((ReferenceBinding) this._binding).superclass());
+ return superClass == null ? null : superClass.getAnnotation(annotationClass);
+ }
+
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return _env.getFactory().getAnnotationMirrors(getPackedAnnotationBindings());
+ }
+
+ @Override
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ A [] annotations = _env.getFactory().getAnnotationsByType(Factory.getUnpackedAnnotationBindings(getPackedAnnotationBindings()), annotationType);
+ if (annotations.length != 0 || this.getKind() != ElementKind.CLASS || annotationType.getAnnotation(Inherited.class) == null)
+ return annotations;
+
+ ElementImpl superClass = (ElementImpl) _env.getFactory().newElement(((ReferenceBinding) this._binding).superclass());
+ return superClass == null ? annotations : superClass.getAnnotationsByType(annotationType);
+ }
+
+ @Override
+ public Set<Modifier> getModifiers() {
+ // Most subclasses implement this; this default is appropriate for
+ // PackageElement and TypeParameterElement.
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Name getSimpleName() {
+ return new NameImpl(_binding.shortReadableName());
+ }
+
+ @Override
+ public int hashCode() {
+ return _binding.hashCode();
+ }
+
+ // TODO: equals() implemented as == of JDT bindings. Valid within
+ // a single Compiler instance; breaks in IDE if processors cache values.
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ElementImpl other = (ElementImpl) obj;
+ if (_binding == null) {
+ if (other._binding != null)
+ return false;
+ } else if (_binding != other._binding)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return _binding.toString();
+ }
+
+ @Override
+ public String getFileName() {
+ // Subclasses should override and return something of value
+ return null;
+ }
+
+ /**
+ * @return the package containing this element. The package of a PackageElement is itself.
+ */
+ PackageElement getPackage() {
+ return null;
+ }
+
+ /**
+ * Subclassed by VariableElementImpl, TypeElementImpl, and ExecutableElementImpl.
+ * This base implementation suffices for other types.
+ * @see javax.lang.model.util.Elements#hides
+ * @return true if this element hides {@code hidden}
+ */
+ public boolean hides(Element hidden)
+ {
+ return false;
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java
new file mode 100644
index 0000000..8d0a0d1
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java
@@ -0,0 +1,739 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2022 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Fix for bug 341494
+ * IBM Corporation - Fix for bug 328575
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Javadoc;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+
+/**
+ * Utilities for working with java8 and earlier language elements.
+ * There is one of these for every ProcessingEnvironment.
+ *
+ * @see ElementsImpl9
+ */
+public class ElementsImpl implements Elements {
+
+ // Used for parsing Javadoc comments: matches initial delimiter, followed by whitespace
+ private static final Pattern INITIAL_DELIMITER = Pattern.compile("^\\s*/\\*+"); //$NON-NLS-1$
+
+ protected final BaseProcessingEnvImpl _env;
+
+ /*
+ * The processing env creates and caches an ElementsImpl. Other clients should
+ * not create their own; they should ask the env for it.
+ */
+ protected ElementsImpl(BaseProcessingEnvImpl env) {
+ _env = env;
+ }
+
+ public static ElementsImpl create(BaseProcessingEnvImpl env) {
+ return (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) <= 0)? new ElementsImpl(env): new ElementsImpl9(env);
+ }
+
+ /**
+ * Return all the annotation mirrors on this element, including inherited annotations.
+ * Annotations are inherited only if the annotation type is meta-annotated with @Inherited,
+ * and the annotation is on a class: e.g., annotations are not inherited for interfaces, methods,
+ * or fields.
+ */
+ @Override
+ public List<? extends AnnotationMirror> getAllAnnotationMirrors(Element e) {
+ // if e is a class, walk up its superclass hierarchy looking for @Inherited annotations not already in the list
+ if (e.getKind() == ElementKind.CLASS && e instanceof TypeElementImpl) {
+ List<AnnotationBinding> annotations = new ArrayList<>();
+ // A class can only have one annotation of a particular annotation type.
+ Set<ReferenceBinding> annotationTypes = new HashSet<>();
+ ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)e)._binding;
+ boolean checkIfInherited = false;
+ while (null != binding) {
+ if (binding instanceof ParameterizedTypeBinding) {
+ binding = ((ParameterizedTypeBinding) binding).genericType();
+ }
+ for (AnnotationBinding annotation : Factory.getPackedAnnotationBindings(binding.getAnnotations())) {
+ if (annotation == null) continue;
+ ReferenceBinding annotationType = annotation.getAnnotationType();
+ if (checkIfInherited && (annotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0)
+ continue;
+ if (!annotationTypes.contains(annotationType)) {
+ annotationTypes.add(annotationType);
+ annotations.add(annotation);
+ }
+ }
+ binding = binding.superclass();
+ checkIfInherited = true;
+ }
+ List<AnnotationMirror> list = new ArrayList<>(annotations.size());
+ for (AnnotationBinding annotation : annotations) {
+ list.add(_env.getFactory().newAnnotationMirror(annotation));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ else {
+ return e.getAnnotationMirrors();
+ }
+ }
+
+ /**
+ * Compute a list of all the visible entities in this type. Specifically:
+ * <ul>
+ * <li>All nested types declared in this type, including interfaces and enums</li>
+ * <li>All protected or public nested types declared in this type's superclasses
+ * and superinterfaces, that are not hidden by a name collision</li>
+ * <li>All methods declared in this type, including constructors but not
+ * including static or instance initializers, and including abstract
+ * methods and unimplemented methods declared in interfaces</li>
+ * <li>All protected or public methods declared in this type's superclasses,
+ * that are not overridden by another method, but not including constructors
+ * or initializers. Includes abstract methods and methods declared in
+ * superinterfaces but not implemented</li>
+ * <li>All fields declared in this type, including constants</li>
+ * <li>All non-private fields declared in this type's superclasses and
+ * superinterfaces, that are not hidden by a name collision.</li>
+ * </ul>
+ */
+ @Override
+ public List<? extends Element> getAllMembers(TypeElement type) {
+ if (null == type || !(type instanceof TypeElementImpl)) {
+ return Collections.emptyList();
+ }
+ ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)type)._binding;
+ // Map of element simple name to binding
+ Map<String, ReferenceBinding> types = new HashMap<>();
+ // Javac implementation does not take field name collisions into account
+ List<FieldBinding> fields = new ArrayList<>();
+ // For methods, need to compare parameters, not just names
+ Map<String, Set<MethodBinding>> methods = new HashMap<>();
+ Set<ReferenceBinding> superinterfaces = new LinkedHashSet<>();
+ boolean ignoreVisibility = true;
+ while (null != binding) {
+ addMembers(binding, ignoreVisibility, types, fields, methods);
+ Set<ReferenceBinding> newfound = new LinkedHashSet<>();
+ collectSuperInterfaces(binding, superinterfaces, newfound);
+ for (ReferenceBinding superinterface : newfound) {
+ addMembers(superinterface, false, types, fields, methods);
+ }
+ superinterfaces.addAll(newfound);
+ binding = binding.superclass();
+ ignoreVisibility = false;
+ }
+ List<Element> allMembers = new ArrayList<>();
+ for (ReferenceBinding nestedType : types.values()) {
+ allMembers.add(_env.getFactory().newElement(nestedType));
+ }
+ for (FieldBinding field : fields) {
+ allMembers.add(_env.getFactory().newElement(field));
+ }
+ for (Set<MethodBinding> sameNamedMethods : methods.values()) {
+ for (MethodBinding method : sameNamedMethods) {
+ allMembers.add(_env.getFactory().newElement(method));
+ }
+ }
+ return allMembers;
+ }
+
+ /**
+ * Recursively depth-first walk the tree of superinterfaces of a type, collecting
+ * all the unique superinterface bindings. (Note that because of generics, a type may
+ * have multiple unique superinterface bindings corresponding to the same interface
+ * declaration.)
+ * @param existing bindings already in this set will not be re-added or recursed into
+ * @param newfound newly found bindings will be added to this set
+ */
+ private void collectSuperInterfaces(ReferenceBinding type,
+ Set<ReferenceBinding> existing, Set<ReferenceBinding> newfound) {
+ for (ReferenceBinding superinterface : type.superInterfaces()) {
+ if (!existing.contains(superinterface) && !newfound.contains(superinterface)) {
+ newfound.add(superinterface);
+ collectSuperInterfaces(superinterface, existing, newfound);
+ }
+ }
+ }
+
+ /**
+ * Add the members of a type to the maps of subtypes, fields, and methods. Add only those
+ * which are non-private and which are not overridden by an already-discovered member.
+ * For fields, add them all; javac implementation does not take field hiding into account.
+ * @param binding the type whose members will be added to the lists
+ * @param ignoreVisibility if true, all members will be added regardless of whether they
+ * are private, overridden, etc.
+ * @param types a map of type simple name to type binding
+ * @param fields a list of field bindings
+ * @param methods a map of method simple name to set of method bindings with that name
+ */
+ private void addMembers(ReferenceBinding binding, boolean ignoreVisibility, Map<String, ReferenceBinding> types,
+ List<FieldBinding> fields, Map<String, Set<MethodBinding>> methods)
+ {
+ for (ReferenceBinding subtype : binding.memberTypes()) {
+ if (ignoreVisibility || !subtype.isPrivate()) {
+ String name = new String(subtype.sourceName());
+ if (null == types.get(name)) {
+ types.put(name, subtype);
+ }
+ }
+ }
+ for (FieldBinding field : binding.fields()) {
+ if (ignoreVisibility || !field.isPrivate()) {
+ fields.add(field);
+ }
+ }
+ for (MethodBinding method : binding.methods()) {
+ if (!method.isSynthetic() && (ignoreVisibility || (!method.isPrivate() && !method.isConstructor()))) {
+ String methodName = new String(method.selector);
+ Set<MethodBinding> sameNamedMethods = methods.get(methodName);
+ if (null == sameNamedMethods) {
+ // New method name. Create a set for it and add it to the list.
+ // We don't expect many methods with same name, so only 4 slots:
+ sameNamedMethods = new HashSet<>(4);
+ methods.put(methodName, sameNamedMethods);
+ sameNamedMethods.add(method);
+ }
+ else {
+ // We already have a method with this name. Is this method overridden?
+ boolean unique = true;
+ if (!ignoreVisibility) {
+ for (MethodBinding existing : sameNamedMethods) {
+ MethodVerifier verifier = _env.getLookupEnvironment().methodVerifier();
+ if (verifier.doesMethodOverride(existing, method)) {
+ unique = false;
+ break;
+ }
+ }
+ }
+ if (unique) {
+ sameNamedMethods.add(method);
+ }
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getBinaryName(javax.lang.model.element.TypeElement)
+ */
+ @Override
+ public Name getBinaryName(TypeElement type) {
+ TypeElementImpl typeElementImpl = (TypeElementImpl) type;
+ ReferenceBinding referenceBinding = (ReferenceBinding) typeElementImpl._binding;
+ return new NameImpl(
+ CharOperation.replaceOnCopy(referenceBinding.constantPoolName(), '/', '.'));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getConstantExpression(java.lang.Object)
+ */
+ @Override
+ public String getConstantExpression(Object value) {
+ if (!(value instanceof Integer)
+ && !(value instanceof Byte)
+ && !(value instanceof Float)
+ && !(value instanceof Double)
+ && !(value instanceof Long)
+ && !(value instanceof Short)
+ && !(value instanceof Character)
+ && !(value instanceof String)
+ && !(value instanceof Boolean)) {
+ throw new IllegalArgumentException("Not a valid wrapper type : " + value.getClass()); //$NON-NLS-1$
+ }
+ if (value instanceof Character) {
+ StringBuilder builder = new StringBuilder();
+ builder.append('\'').append(value).append('\'');
+ return String.valueOf(builder);
+ } else if (value instanceof String) {
+ StringBuilder builder = new StringBuilder();
+ builder.append('\"').append(value).append('\"');
+ return String.valueOf(builder);
+ } else if (value instanceof Float) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(value).append('f');
+ return String.valueOf(builder);
+ } else if (value instanceof Long) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(value).append('L');
+ return String.valueOf(builder);
+ } else if (value instanceof Short) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("(short)").append(value); //$NON-NLS-1$
+ return String.valueOf(builder);
+ } else if (value instanceof Byte) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("(byte)0x"); //$NON-NLS-1$
+ int intValue = ((Byte) value).byteValue();
+ String hexString = Integer.toHexString(intValue & 0xFF);
+ if (hexString.length() < 2) {
+ builder.append('0');
+ }
+ builder.append(hexString);
+ return String.valueOf(builder);
+ }
+ return String.valueOf(value);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getDocComment(javax.lang.model.element.Element)
+ */
+ @Override
+ public String getDocComment(Element e) {
+ char[] unparsed = getUnparsedDocComment(e);
+ return formatJavadoc(unparsed);
+ }
+
+ /**
+ * Return the entire javadoc comment on e, including the comment characters and whitespace
+ * @param e an Element of any sort, possibly with a javadoc comment.
+ * @return a String, or null if the comment is not available
+ */
+ private char[] getUnparsedDocComment(Element e)
+ {
+ Javadoc javadoc = null;
+ ReferenceContext referenceContext = null;
+ switch(e.getKind()) {
+ case ANNOTATION_TYPE :
+ case CLASS :
+ case ENUM :
+ case INTERFACE :
+ case RECORD :
+ TypeElementImpl typeElementImpl = (TypeElementImpl) e;
+ ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding;
+ if (referenceBinding instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) referenceBinding;
+ referenceContext = sourceTypeBinding.scope.referenceContext;
+ javadoc = ((TypeDeclaration) referenceContext).javadoc;
+ }
+ break;
+ case PACKAGE :
+ // might need to handle javadoc of package-info.java file
+ PackageElementImpl packageElementImpl = (PackageElementImpl) e;
+ PackageBinding packageBinding = (PackageBinding) packageElementImpl._binding;
+ char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME);
+ ReferenceBinding type = this._env.getLookupEnvironment().getType(compoundName);
+ if (type != null && type.isValidBinding() && (type instanceof SourceTypeBinding)) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type;
+ referenceContext = sourceTypeBinding.scope.referenceContext;
+ javadoc = ((TypeDeclaration) referenceContext).javadoc;
+ }
+ break;
+ case CONSTRUCTOR :
+ case METHOD :
+ ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e;
+ MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding;
+ AbstractMethodDeclaration sourceMethod = methodBinding.sourceMethod();
+ if (sourceMethod != null) {
+ javadoc = sourceMethod.javadoc;
+ referenceContext = sourceMethod;
+ }
+ break;
+ case RECORD_COMPONENT :
+ case ENUM_CONSTANT :
+ case FIELD :
+ VariableElementImpl variableElementImpl = (VariableElementImpl) e;
+ FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding;
+ FieldDeclaration sourceField = fieldBinding.sourceField();
+ if (sourceField != null) {
+ javadoc = sourceField.javadoc;
+ if (fieldBinding.declaringClass instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) fieldBinding.declaringClass;
+ referenceContext = sourceTypeBinding.scope.referenceContext;
+ }
+ }
+ break;
+ default:
+ return null;
+ }
+ if (javadoc != null && referenceContext != null) {
+ char[] contents = referenceContext.compilationResult().getCompilationUnit().getContents();
+ if (contents != null) {
+ return CharOperation.subarray(contents, javadoc.sourceStart, javadoc.sourceEnd - 1);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Strip the comment characters from a javadoc comment. Assume the comment is already
+ * missing its closing delimiter.
+ *
+ * Javac's behavior with regard to tab expansion and trimming of whitespace and
+ * asterisks is bizarre and undocumented. We do our best here to emulate it.
+ */
+ private static String formatJavadoc(char[] unparsed)
+ {
+ if (unparsed == null || unparsed.length < 5) { // delimiters take 5 chars
+ return null;
+ }
+
+ String[] lines = new String(unparsed).split("\n"); //$NON-NLS-1$
+ Matcher delimiterMatcher = INITIAL_DELIMITER.matcher(lines[0]);
+ if (!delimiterMatcher.find()) {
+ return null;
+ }
+ int iOpener = delimiterMatcher.end();
+ lines[0] = lines[0].substring(iOpener);
+ if (lines.length == 1) {
+ // single-line comment. Should trim(), but javac doesn't.
+ // we should however remove the starting whitespaces
+ StringBuilder sb = new StringBuilder();
+ char[] chars = lines[0].toCharArray();
+ boolean startingWhitespaces = true;
+ for (char c : chars) {
+ if (Character.isWhitespace(c))
+ if (startingWhitespaces) {
+ continue;
+ } else {
+ sb.append(c);
+ } else {
+ startingWhitespaces = false;
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ // if the first line ends with spaces after the /** then we want to insert a line separator
+ int firstLine = lines[0].trim().length() > 0 ? 0 : 1;
+
+ // If the last line is now empty, skip it
+ int lastLine = lines[lines.length - 1].trim().length() > 0 ? lines.length - 1 : lines.length - 2;
+
+ StringBuilder sb = new StringBuilder();
+ if (lines[0].length() != 0 && firstLine == 1) {
+ // insert a line separator only if the remaining chars on the line are whitespaces
+ sb.append('\n');
+ }
+ boolean preserveLineSeparator = lines[0].length() == 0;
+ for (int line = firstLine; line <= lastLine; ++line) {
+ char[] chars = lines[line].toCharArray();
+ int starsIndex = getStars(chars);
+ int leadingWhitespaces = 0;
+ boolean recordLeadingWhitespaces = true;
+ for (int i = 0, max = chars.length; i < max; i++) {
+ char c = chars[i];
+ switch(c) {
+ case ' ' :
+ if (starsIndex == -1) {
+ if (recordLeadingWhitespaces) {
+ leadingWhitespaces++;
+ } else {
+ sb.append(c);
+ }
+ } else if (i >= starsIndex) {
+ sb.append(c);
+ }
+ break;
+ default :
+ // convert leadingwhitespaces to spaces
+ recordLeadingWhitespaces = false;
+ if (leadingWhitespaces != 0) {
+ int numberOfTabs = leadingWhitespaces / 8;
+ if (numberOfTabs != 0) {
+ for (int j = 0, max2 = numberOfTabs; j < max2; j++) {
+ sb.append(" "); //$NON-NLS-1$
+ }
+ if ((leadingWhitespaces % 8) >= 1) {
+ sb.append(' ');
+ }
+ } else if (line != 0) {
+ // we don't want to preserve the leading spaces for the first line
+ for (int j = 0, max2 = leadingWhitespaces; j < max2; j++) {
+ sb.append(' ');
+ }
+ }
+ leadingWhitespaces = 0;
+ sb.append(c);
+ } else if (c == '\t') {
+ if (i >= starsIndex) {
+ sb.append(c);
+ }
+ } else if (c != '*' || i > starsIndex) {
+ sb.append(c);
+ }
+ }
+ }
+
+ // append a newline at the end of each line except the last, even if we skipped the last entirely
+ int end = lines.length - 1;
+ if (line < end) {
+ sb.append('\n');
+ } else if (preserveLineSeparator && line == end) {
+ sb.append('\n');
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the index of the last leading stars on this line, -1 if none.
+ *
+ * @param line the given line
+ * @return the computed index
+ */
+ private static int getStars(char[] line) {
+ loop: for (int i = 0, max = line.length; i < max; i++) {
+ char c = line[i];
+ if (!Character.isWhitespace(c)) {
+ if (c == '*') {
+ // only whitespaces before the first star
+ // consume all stars and return the last index
+ for (int j = i + 1; j < max; j++) {
+ if (line[j] != '*') {
+ return j;
+ }
+ }
+ return max - 1;
+ }
+ // no need to continue
+ break loop;
+ }
+ }
+ return -1;
+ }
+ /**
+ * @return all the annotation instance's explicitly set values, plus default values
+ * for all the annotation members that are not explicitly set but that have
+ * defaults. By comparison, {@link AnnotationMirror#getElementValues()} only
+ * returns the explicitly set values.
+ * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(javax.lang.model.element.AnnotationMirror)
+ */
+ @Override
+ public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults(
+ AnnotationMirror a) {
+ return ((AnnotationMirrorImpl)a).getElementValuesWithDefaults();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getName(java.lang.CharSequence)
+ */
+ @Override
+ public Name getName(CharSequence cs) {
+ return new NameImpl(cs);
+ }
+
+ @Override
+ public PackageElement getPackageElement(CharSequence name) {
+ LookupEnvironment le = _env.getLookupEnvironment(); // FIXME(SHMOD): does this lookup need to be module-aware?
+ if (name.length() == 0) {
+ return (PackageElement) _env.getFactory().newElement(le.defaultPackage);
+ }
+ char[] packageName = name.toString().toCharArray();
+ PackageBinding packageBinding = le.createPackage(CharOperation.splitOn('.', packageName));
+ if (packageBinding == null) {
+ return null;
+ }
+ return (PackageElement) _env.getFactory().newElement(packageBinding);
+ }
+
+ @Override
+ public PackageElement getPackageOf(Element type) {
+ switch(type.getKind()) {
+ case ANNOTATION_TYPE :
+ case CLASS :
+ case ENUM :
+ case INTERFACE :
+ case RECORD :
+ TypeElementImpl typeElementImpl = (TypeElementImpl) type;
+ ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(referenceBinding.fPackage);
+ case PACKAGE :
+ return (PackageElement) type;
+ case CONSTRUCTOR :
+ case METHOD :
+ ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) type;
+ MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(methodBinding.declaringClass.fPackage);
+ case ENUM_CONSTANT :
+ case FIELD :
+ case RECORD_COMPONENT :
+ VariableElementImpl variableElementImpl = (VariableElementImpl) type;
+ FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(fieldBinding.declaringClass.fPackage);
+ case PARAMETER :
+ variableElementImpl = (VariableElementImpl) type;
+ LocalVariableBinding localVariableBinding = (LocalVariableBinding) variableElementImpl._binding;
+ return (PackageElement) _env.getFactory().newElement(localVariableBinding.declaringScope.classScope().referenceContext.binding.fPackage);
+ case EXCEPTION_PARAMETER :
+ case INSTANCE_INIT :
+ case OTHER :
+ case STATIC_INIT :
+ case TYPE_PARAMETER :
+ case LOCAL_VARIABLE :
+ return null;
+ default:
+ break;
+ }
+ // unreachable
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#getTypeElement(java.lang.CharSequence)
+ */
+ @Override
+ public TypeElement getTypeElement(CharSequence name) {
+ LookupEnvironment le = _env.getLookupEnvironment();
+ final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray());
+ ReferenceBinding binding = le.getType(compoundName);
+ // If we didn't find the binding, maybe it's a nested type;
+ // try finding the top-level type and then working downwards.
+ if (null == binding) {
+ ReferenceBinding topLevelBinding = null;
+ int topLevelSegments = compoundName.length;
+ while (--topLevelSegments > 0) {
+ char[][] topLevelName = new char[topLevelSegments][];
+ for (int i = 0; i < topLevelSegments; ++i) {
+ topLevelName[i] = compoundName[i];
+ }
+ topLevelBinding = le.getType(topLevelName);
+ if (null != topLevelBinding) {
+ break;
+ }
+ }
+ if (null == topLevelBinding) {
+ return null;
+ }
+ binding = topLevelBinding;
+ for (int i = topLevelSegments; null != binding && i < compoundName.length; ++i) {
+ binding = binding.getMemberType(compoundName[i]);
+ }
+ }
+ if (null == binding) {
+ return null;
+ }
+ if((binding.tagBits & TagBits.HasMissingType) != 0) {
+ return null;
+ }
+ return new TypeElementImpl(_env, binding, null);
+ }
+
+ /* (non-Javadoc)
+ * Element A hides element B if: A and B are both fields, both nested types, or both methods; and
+ * the enclosing element of B is a superclass or superinterface of the enclosing element of A.
+ * See JLS 8.3 (for hiding of fields), 8.4.8.2 (hiding of class methods), and 8.5 (for hiding of member types).
+ * @see javax.lang.model.util.Elements#hides(javax.lang.model.element.Element, javax.lang.model.element.Element)
+ */
+ @Override
+ public boolean hides(Element hider, Element hidden) {
+ if (hidden == null) {
+ // required by API spec
+ throw new NullPointerException();
+ }
+ return ((ElementImpl)hider).hides(hidden);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#isDeprecated(javax.lang.model.element.Element)
+ */
+ @Override
+ public boolean isDeprecated(Element e) {
+ if (!(e instanceof ElementImpl)) {
+ return false;
+ }
+ return (((ElementImpl)e)._binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0;
+ }
+
+ /* (non-Javadoc)
+ * See JLS 8.4.8.1 for discussion of hiding of methods
+ * @see javax.lang.model.util.Elements#overrides(javax.lang.model.element.ExecutableElement, javax.lang.model.element.ExecutableElement, javax.lang.model.element.TypeElement)
+ */
+ @Override
+ public boolean overrides(ExecutableElement overrider, ExecutableElement overridden,
+ TypeElement type) {
+ if (overridden == null || type == null) {
+ throw new NullPointerException();
+ }
+ return ((ExecutableElementImpl)overrider).overrides(overridden, type);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Elements#printElements(java.io.Writer, javax.lang.model.element.Element[])
+ */
+ @Override
+ public void printElements(Writer w, Element... elements) {
+ String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
+ for (Element element : elements) {
+ try {
+ w.write(element.toString());
+ w.write(lineSeparator);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ try {
+ w.flush();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ @Override
+ public boolean isFunctionalInterface(TypeElement type) {
+ if (type != null && type.getKind() == ElementKind.INTERFACE) {
+ ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl) type)._binding;
+ if (binding instanceof SourceTypeBinding) {
+ return binding.isFunctionalInterface(((SourceTypeBinding) binding).scope);
+ }
+ }
+ return false;
+ }
+ @Override
+ public boolean isAutomaticModule(ModuleElement module) {
+ ModuleBinding binding = ((ModuleElementImpl) module).binding;
+ return binding != null ? binding.isAutomatic() : false;
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl9.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl9.java
new file mode 100644
index 0000000..b47dc55
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl9.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2021 BEA Systems, 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
+ *
+ * Contributors:
+ * Igor Fedorenko - extracted from ElementsImpl
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.lang.model.AnnotatedConstruct;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfModule;
+
+/**
+ * Utilities for working with java9 language elements.
+ * There is one of these for every ProcessingEnvironment.
+ */
+public class ElementsImpl9 extends ElementsImpl {
+
+ public ElementsImpl9(BaseProcessingEnvImpl env) {
+ super(env);
+ }
+
+ @Override
+ public TypeElement getTypeElement(CharSequence name) {
+ final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray());
+ Set<? extends ModuleElement> allModuleElements = getAllModuleElements();
+ for (ModuleElement moduleElement : allModuleElements) {
+ TypeElement t = getTypeElement(compoundName, ((ModuleElementImpl) moduleElement).binding);
+ if (t != null) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public TypeElement getTypeElement(ModuleElement module, CharSequence name) {
+ ModuleBinding mBinding = ((ModuleElementImpl) module).binding;
+ final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray());
+ return getTypeElement(compoundName, mBinding);
+ }
+
+ private TypeElement getTypeElement(final char[][] compoundName, ModuleBinding mBinding) {
+ LookupEnvironment le = mBinding == null ? _env.getLookupEnvironment() : mBinding.environment;
+ ReferenceBinding binding = mBinding == null ? le.getType(compoundName) : le.getType(compoundName, mBinding);
+ // If we didn't find the binding, maybe it's a nested type;
+ // try finding the top-level type and then working downwards.
+ if (null == binding) {
+ ReferenceBinding topLevelBinding = null;
+ int topLevelSegments = compoundName.length;
+ while (--topLevelSegments > 0) {
+ char[][] topLevelName = new char[topLevelSegments][];
+ for (int i = 0; i < topLevelSegments; ++i) {
+ topLevelName[i] = compoundName[i];
+ }
+ topLevelBinding = le.getType(topLevelName);
+ if (null != topLevelBinding) {
+ break;
+ }
+ }
+ if (null == topLevelBinding) {
+ return null;
+ }
+ binding = topLevelBinding;
+ for (int i = topLevelSegments; null != binding && i < compoundName.length; ++i) {
+ binding = binding.getMemberType(compoundName[i]);
+ }
+ }
+ if (null == binding) {
+ return null;
+ }
+ if ((binding.tagBits & TagBits.HasMissingType) != 0) {
+ return null;
+ }
+ return new TypeElementImpl(_env, binding, null);
+ }
+
+
+ @Override
+ public Origin getOrigin(Element e) {
+ return Origin.EXPLICIT;
+ }
+
+ @Override
+ public Origin getOrigin(AnnotatedConstruct c, AnnotationMirror a) {
+ return Origin.EXPLICIT;
+ }
+
+ @Override
+ public Origin getOrigin(ModuleElement m, ModuleElement.Directive directive) {
+ return Origin.EXPLICIT;
+ }
+
+ @Override
+ public boolean isBridge(ExecutableElement e) {
+ MethodBinding methodBinding = (MethodBinding) ((ExecutableElementImpl) e)._binding;
+ return methodBinding.isBridge();
+ }
+
+ @Override
+ public ModuleElement getModuleOf(Element elem) {
+ if (elem instanceof ModuleElement) {
+ return (ModuleElement) elem;
+ }
+ Element parent = elem.getEnclosingElement();
+ while (parent != null) {
+ if (parent instanceof ModuleElement) {
+ return (ModuleElement) parent;
+ }
+ parent = parent.getEnclosingElement();
+ }
+ return null;
+ }
+
+ @Override
+ public ModuleElement getModuleElement(CharSequence name) {
+ LookupEnvironment lookup = _env.getLookupEnvironment();
+ ModuleBinding binding = lookup.getModule(name.length() == 0 ? ModuleBinding.UNNAMED : name.toString().toCharArray());
+ //TODO: Surely there has to be a better way than calling toString().toCharArray()?
+ if (binding == null) {
+ return null;
+ }
+ return new ModuleElementImpl(_env, binding);
+ }
+
+ @Override
+ public Set<? extends ModuleElement> getAllModuleElements() {
+ LookupEnvironment lookup = _env.getLookupEnvironment();
+ HashtableOfModule knownModules = lookup.knownModules;
+ ModuleBinding[] modules = knownModules.valueTable;
+ if (modules == null || modules.length == 0) {
+ return Collections.emptySet();
+ }
+ Set<ModuleElement> mods = new HashSet<>(modules.length);
+ for (ModuleBinding moduleBinding : modules) {
+ if (moduleBinding == null)
+ continue;
+ ModuleElement element = (ModuleElement) _env.getFactory().newElement(moduleBinding);
+ mods.add(element);
+ }
+ mods.add((ModuleElement) _env.getFactory().newElement(lookup.UnNamedModule));
+ return mods;
+ }
+
+ @Override
+ public
+ PackageElement getPackageElement(ModuleElement module, CharSequence name) {
+ ModuleBinding mBinding = ((ModuleElementImpl) module).binding;
+ final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray());
+ PackageBinding p = null;
+ if (mBinding != null) {
+ p = mBinding.getVisiblePackage(compoundName);
+ } else {
+ p = _env.getLookupEnvironment().createPackage(compoundName);
+ }
+ if (p == null || !p.isValidBinding())
+ return null;
+ return (PackageElement) _env.getFactory().newElement(p);
+ }
+ @Override
+ public boolean isAutomaticModule(ModuleElement module) {
+ ModuleBinding mBinding = ((ModuleElementImpl) module).binding;
+ return mBinding.isAutomatic();
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java
new file mode 100644
index 0000000..1031488
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2017 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+
+/**
+ * Element corresponding to the Error type mirror
+ */
+public class ErrorTypeElement extends TypeElementImpl {
+
+ ErrorTypeElement(BaseProcessingEnvImpl env, ReferenceBinding binding) {
+ super(env, binding, null);
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getInterfaces()
+ */
+ @Override
+ public List<? extends TypeMirror> getInterfaces() {
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getNestingKind()
+ */
+ @Override
+ public NestingKind getNestingKind() {
+ return NestingKind.TOP_LEVEL;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getQualifiedName()
+ */
+ @Override
+ public Name getQualifiedName() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ char[] qName;
+ if (binding.isMemberType()) {
+ qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.');
+ CharOperation.replace(qName, '$', '.');
+ } else {
+ qName = CharOperation.concatWith(binding.compoundName, '.');
+ }
+ return new NameImpl(qName);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getSuperclass()
+ */
+ @Override
+ public TypeMirror getSuperclass() {
+ return this._env.getFactory().getNoType(TypeKind.NONE);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.TypeElement#getTypeParameters()
+ */
+ @Override
+ public List<? extends TypeParameterElement> getTypeParameters() {
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#asType()
+ */
+ @Override
+ public TypeMirror asType() {
+ return this._env.getFactory().getErrorType((ReferenceBinding) this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getAnnotation(java.lang.Class)
+ */
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getAnnotationMirrors()
+ */
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return Collections.emptyList();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ return (A[]) Array.newInstance(annotationType, 0);
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getEnclosedElements()
+ */
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getEnclosingElement()
+ */
+ @Override
+ public Element getEnclosingElement() {
+ return this._env.getFactory().newPackageElement(this._env.getLookupEnvironment().defaultPackage);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getKind()
+ */
+ @Override
+ public ElementKind getKind() {
+ return ElementKind.CLASS;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getModifiers()
+ */
+ @Override
+ public Set<Modifier> getModifiers() {
+ return Collections.emptySet();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Element#getSimpleName()
+ */
+ @Override
+ public Name getSimpleName() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ return new NameImpl(binding.sourceName());
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java
new file mode 100644
index 0000000..9ada225
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of the {@link ErrorType} interface.
+ */
+public class ErrorTypeImpl extends DeclaredTypeImpl implements ErrorType {
+
+ /* package */ ErrorTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding) {
+ super(env, binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.DeclaredType#asElement()
+ */
+ @Override
+ public Element asElement() {
+ return this._env.getFactory().newElement((ReferenceBinding) this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.DeclaredType#getEnclosingType()
+ */
+ @Override
+ public TypeMirror getEnclosingType() {
+ return NoTypeImpl.NO_TYPE_NONE;
+ }
+
+ @Override
+ public List<? extends TypeMirror> getTypeArguments() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ if (binding.isParameterizedType()) {
+ ParameterizedTypeBinding ptb = (ParameterizedTypeBinding)_binding;
+ TypeBinding[] arguments = ptb.arguments;
+ int length = arguments == null ? 0 : arguments.length;
+ if (length == 0) return Collections.emptyList();
+ List<TypeMirror> args = new ArrayList<>(length);
+ for (TypeBinding arg : arguments) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ if (binding.isGenericType()) {
+ TypeVariableBinding[] typeVariables = binding.typeVariables();
+ List<TypeMirror> args = new ArrayList<>(typeVariables.length);
+ for (TypeBinding arg : typeVariables) {
+ args.add(_env.getFactory().newTypeMirror(arg));
+ }
+ return Collections.unmodifiableList(args);
+ }
+ return Collections.emptyList();
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitError(this, p);
+ }
+
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return Factory.EMPTY_ANNOTATION_MIRRORS;
+ }
+
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ return (A[]) Array.newInstance(annotationType, 0);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.ERROR;
+ }
+
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java
new file mode 100644
index 0000000..fd32623
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java
@@ -0,0 +1,333 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Jesper Steen Moller - Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationHolder;
+import org.eclipse.jdt.internal.compiler.lookup.AptBinaryLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+public class ExecutableElementImpl extends ElementImpl implements
+ ExecutableElement {
+
+ private Name _name = null;
+
+ /* package */ ExecutableElementImpl(BaseProcessingEnvImpl env, MethodBinding binding) {
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitExecutable(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((MethodBinding)_binding).getAnnotations();
+ }
+
+ @Override
+ public AnnotationValue getDefaultValue() {
+ MethodBinding binding = (MethodBinding)_binding;
+ Object defaultValue = binding.getDefaultValue();
+ if (defaultValue != null) return new AnnotationMemberValue(_env, defaultValue, binding);
+ return null;
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (null == binding.declaringClass) {
+ return null;
+ }
+ return _env.getFactory().newElement(binding.declaringClass);
+ }
+
+ @Override
+ public String getFileName() {
+ ReferenceBinding dc = ((MethodBinding)_binding).declaringClass;
+ char[] name = dc.getFileName();
+ if (name == null)
+ return null;
+ return new String(name);
+ }
+
+ @Override
+ public ElementKind getKind() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (binding.isConstructor()) {
+ return ElementKind.CONSTRUCTOR;
+ }
+ else if (CharOperation.equals(binding.selector, TypeConstants.CLINIT)) {
+ return ElementKind.STATIC_INIT;
+ }
+ else if (CharOperation.equals(binding.selector, TypeConstants.INIT)) {
+ return ElementKind.INSTANCE_INIT;
+ }
+ else {
+ return ElementKind.METHOD;
+ }
+ }
+
+ @Override
+ public Set<Modifier> getModifiers() {
+ MethodBinding binding = (MethodBinding)_binding;
+ return Factory.getModifiers(binding.modifiers, getKind());
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (null == binding.declaringClass) {
+ return null;
+ }
+ return _env.getFactory().newPackageElement(binding.declaringClass.fPackage);
+ }
+
+ @Override
+ public List<? extends VariableElement> getParameters() {
+ MethodBinding binding = (MethodBinding)_binding;
+ int length = binding.parameters == null ? 0 : binding.parameters.length;
+ if (0 != length) {
+ AbstractMethodDeclaration methodDeclaration = binding.sourceMethod();
+ List<VariableElement> params = new ArrayList<>(length);
+ if (methodDeclaration != null) {
+ for (Argument argument : methodDeclaration.arguments) {
+ VariableElement param = new VariableElementImpl(_env, argument.binding);
+ params.add(param);
+ }
+ } else {
+ // binary method
+ AnnotationBinding[][] parameterAnnotationBindings = null;
+ AnnotationHolder annotationHolder = binding.declaringClass.retrieveAnnotationHolder(binding, false);
+ if (annotationHolder != null) {
+ parameterAnnotationBindings = annotationHolder.getParameterAnnotations();
+ }
+ // we need to filter the synthetic arguments
+ int i = 0;
+ for (TypeBinding typeBinding : binding.parameters) {
+ char name[] = binding.parameterNames.length > i ? binding.parameterNames[i] : null;
+ if (name == null) {
+ StringBuilder builder = new StringBuilder("arg");//$NON-NLS-1$
+ builder.append(i);
+ name = String.valueOf(builder).toCharArray();
+ }
+ VariableElement param = new VariableElementImpl(_env,
+ new AptBinaryLocalVariableBinding(
+ name,
+ typeBinding,
+ 0,
+ parameterAnnotationBindings != null ? parameterAnnotationBindings[i] : null,
+ binding));
+ params.add(param);
+ i++;
+ }
+ }
+ return Collections.unmodifiableList(params);
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public TypeMirror getReturnType() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (binding.returnType == null) {
+ return null;
+ }
+ else return _env.getFactory().newTypeMirror(binding.returnType);
+ }
+
+ @Override
+ public Name getSimpleName() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (_name == null) {
+ _name = new NameImpl(binding.selector);
+ }
+ return _name;
+ }
+
+ @Override
+ public List<? extends TypeMirror> getThrownTypes() {
+ MethodBinding binding = (MethodBinding)_binding;
+ if (binding.thrownExceptions.length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeMirror> list = new ArrayList<>(binding.thrownExceptions.length);
+ for (ReferenceBinding exception : binding.thrownExceptions) {
+ list.add(_env.getFactory().newTypeMirror(exception));
+ }
+ return list;
+ }
+
+ @Override
+ public List<? extends TypeParameterElement> getTypeParameters() {
+ MethodBinding binding = (MethodBinding)_binding;
+ TypeVariableBinding[] variables = binding.typeVariables();
+ if (variables.length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeParameterElement> params = new ArrayList<>(variables.length);
+ for (TypeVariableBinding variable : variables) {
+ params.add(_env.getFactory().newTypeParameterElement(variable, this));
+ }
+ return Collections.unmodifiableList(params);
+ }
+
+ @Override
+ public boolean hides(Element hidden)
+ {
+ if (!(hidden instanceof ExecutableElementImpl)) {
+ return false;
+ }
+ MethodBinding hiderBinding = (MethodBinding)_binding;
+ MethodBinding hiddenBinding = (MethodBinding)((ExecutableElementImpl)hidden)._binding;
+ if (hiderBinding == hiddenBinding) {
+ return false;
+ }
+ if (hiddenBinding.isPrivate()) {
+ return false;
+ }
+ // See JLS 8.4.8: hiding only applies to static methods
+ if (!hiderBinding.isStatic() || !hiddenBinding.isStatic()) {
+ return false;
+ }
+ // check names
+ if (!CharOperation.equals(hiddenBinding.selector, hiderBinding.selector)) {
+ return false;
+ }
+ // check parameters
+ if (!_env.getLookupEnvironment().methodVerifier().isMethodSubsignature(hiderBinding, hiddenBinding)) {
+ return false;
+ }
+ return null != hiderBinding.declaringClass.findSuperTypeOriginatingFrom(hiddenBinding.declaringClass);
+ }
+
+ @Override
+ public boolean isVarArgs() {
+ return ((MethodBinding) _binding).isVarargs();
+ }
+
+ /**
+ * Return true if this method overrides {@code overridden} in the context of {@code type}. For
+ * instance, consider
+ * <pre>
+ * interface A { void f(); }
+ * class B { void f() {} }
+ * class C extends B implements I { }
+ * </pre>
+ * In the context of B, B.f() does not override A.f(); they are unrelated. But in the context of
+ * C, B.f() does override A.f(). That is, the copy of B.f() that C inherits overrides A.f().
+ * This is equivalent to considering two questions: first, does C inherit B.f(); if so, does
+ * the inherited C.f() override A.f(). If B.f() were private, for instance, then in the context
+ * of C it would still not override A.f().
+ *
+ * @see javax.lang.model.util.Elements#overrides(ExecutableElement, ExecutableElement, TypeElement)
+ * @jls3 8.4.8 Inheritance, Overriding, and Hiding
+ * @jls3 9.4.1 Inheritance and Overriding
+ */
+ public boolean overrides(ExecutableElement overridden, TypeElement type)
+ {
+ MethodBinding overriddenBinding = (MethodBinding)((ExecutableElementImpl) overridden)._binding;
+ ReferenceBinding overriderContext = (ReferenceBinding)((TypeElementImpl)type)._binding;
+ if ((MethodBinding)_binding == overriddenBinding
+ || overriddenBinding.isStatic()
+ || overriddenBinding.isPrivate()
+ || ((MethodBinding)_binding).isStatic()) {
+ return false;
+ }
+ char[] selector = ((MethodBinding)_binding).selector;
+ if (!CharOperation.equals(selector, overriddenBinding.selector))
+ return false;
+
+ // Construct a binding to the equivalent of this (the overrider) as it would be inherited by 'type'.
+ // Can only do this if 'type' is descended from the overrider.
+ // Second clause of the AND is required to match a peculiar javac behavior.
+ if (null == overriderContext.findSuperTypeOriginatingFrom(((MethodBinding)_binding).declaringClass) &&
+ null == ((MethodBinding)_binding).declaringClass.findSuperTypeOriginatingFrom(overriderContext)) {
+ return false;
+ }
+ MethodBinding overriderBinding = new MethodBinding((MethodBinding)_binding, overriderContext);
+ if (overriderBinding.isPrivate()) {
+ // a private method can never override another method. The other method would either be
+ // private itself, in which case it would not be visible; or this would be a restriction
+ // of access, which is a compile-time error.
+ return false;
+ }
+
+ TypeBinding match = overriderBinding.declaringClass.findSuperTypeOriginatingFrom(overriddenBinding.declaringClass);
+ if (!(match instanceof ReferenceBinding)) return false;
+
+ org.eclipse.jdt.internal.compiler.lookup.MethodBinding[] superMethods = ((ReferenceBinding)match).getMethods(selector);
+ LookupEnvironment lookupEnvironment = _env.getLookupEnvironment();
+ if (lookupEnvironment == null) return false;
+ MethodVerifier methodVerifier = lookupEnvironment.methodVerifier();
+ for (int i = 0, length = superMethods.length; i < length; i++) {
+ if (superMethods[i].original() == overriddenBinding) {
+ return methodVerifier.doesMethodOverride(overriderBinding, superMethods[i]);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public TypeMirror getReceiverType() {
+ return _env.getFactory().getReceiverType((MethodBinding) _binding);
+ }
+
+ @Override
+ public boolean isDefault() {
+ if (_binding != null) {
+ return ((MethodBinding)_binding).isDefaultMethod();
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java
new file mode 100644
index 0000000..841c425
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2016 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of the ExecutableType
+ *
+ */
+public class ExecutableTypeImpl extends TypeMirrorImpl implements ExecutableType {
+
+ ExecutableTypeImpl(BaseProcessingEnvImpl env, MethodBinding binding) {
+ super(env, binding);
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getParameterTypes()
+ */
+ @Override
+ public List<? extends TypeMirror> getParameterTypes() {
+ MethodBinding binding = (MethodBinding) this._binding;
+ TypeBinding[] parameters = binding.parameters;
+ int length = parameters.length;
+ boolean isEnumConstructor = binding.isConstructor()
+ && binding.declaringClass.isEnum()
+ && binding.declaringClass.isBinaryBinding()
+ && ((binding.modifiers & ExtraCompilerModifiers.AccGenericSignature) == 0);
+ if (isEnumConstructor) {
+ ArrayList<TypeMirror> list = new ArrayList<>();
+ for (int i = 0; i < length; i++) {
+ list.add(_env.getFactory().newTypeMirror(parameters[i]));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ if (length != 0) {
+ ArrayList<TypeMirror> list = new ArrayList<>();
+ for (TypeBinding typeBinding : parameters) {
+ list.add(_env.getFactory().newTypeMirror(typeBinding));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ return Collections.emptyList();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getReturnType()
+ */
+ @Override
+ public TypeMirror getReturnType() {
+ return _env.getFactory().newTypeMirror(((MethodBinding) this._binding).returnType);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings() {
+ return ((MethodBinding) this._binding).returnType.getTypeAnnotations();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getThrownTypes()
+ */
+ @Override
+ public List<? extends TypeMirror> getThrownTypes() {
+ ArrayList<TypeMirror> list = new ArrayList<>();
+ ReferenceBinding[] thrownExceptions = ((MethodBinding) this._binding).thrownExceptions;
+ if (thrownExceptions.length != 0) {
+ for (ReferenceBinding referenceBinding : thrownExceptions) {
+ list.add(_env.getFactory().newTypeMirror(referenceBinding));
+ }
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.ExecutableType#getTypeVariables()
+ */
+ @Override
+ public List<? extends TypeVariable> getTypeVariables() {
+ ArrayList<TypeVariable> list = new ArrayList<>();
+ TypeVariableBinding[] typeVariables = ((MethodBinding) this._binding).typeVariables();
+ if (typeVariables.length != 0) {
+ for (TypeVariableBinding typeVariableBinding : typeVariables) {
+ list.add((TypeVariable) _env.getFactory().newTypeMirror(typeVariableBinding));
+ }
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitExecutable(this, p);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.EXECUTABLE;
+ }
+
+ @Override
+ public TypeMirror getReceiverType() {
+ return _env.getFactory().getReceiverType((MethodBinding) _binding);
+ }
+ @Override
+ public String toString() {
+ return new String(((MethodBinding) this._binding).returnType.readableName());
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
new file mode 100644
index 0000000..b3a40e4
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
@@ -0,0 +1,924 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2020 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342598
+ * IBM Corporation - Java 8 support
+ * het@google.com - Bug 427943 - The method org.eclipse.jdt.internal.compiler.apt.model.Factory.getPrimitiveType does not throw IllegalArgumentException
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.NullType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
+
+/**
+ * Creates javax.lang.model wrappers around JDT internal compiler bindings.
+ */
+public class Factory {
+
+ // using auto-boxing to take advantage of caching, if any.
+ // the dummy value picked here falls within the caching range.
+ public static final Byte DUMMY_BYTE = 0;
+ public static final Character DUMMY_CHAR = '0';
+ public static final Double DUMMY_DOUBLE = 0d;
+ public static final Float DUMMY_FLOAT = 0f;
+ public static final Integer DUMMY_INTEGER = 0;
+ public static final Long DUMMY_LONG = 0l;
+ public static final Short DUMMY_SHORT = 0;
+
+ private final BaseProcessingEnvImpl _env;
+ public static List<? extends AnnotationMirror> EMPTY_ANNOTATION_MIRRORS = Collections.emptyList();
+
+ /**
+ * This object should only be constructed by the BaseProcessingEnvImpl.
+ */
+ public Factory(BaseProcessingEnvImpl env) {
+ _env = env;
+ }
+
+ /**
+ * Convert an array of compiler annotation bindings into a list of AnnotationMirror
+ * @return a non-null, possibly empty, unmodifiable list.
+ */
+ public List<? extends AnnotationMirror> getAnnotationMirrors(AnnotationBinding[] annotations) {
+ if (null == annotations || 0 == annotations.length) {
+ return Collections.emptyList();
+ }
+ List<AnnotationMirror> list = new ArrayList<>(annotations.length);
+ for (AnnotationBinding annotation : annotations) {
+ if (annotation == null) continue;
+ list.add(newAnnotationMirror(annotation));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ @SuppressWarnings("unchecked") // for the cast to A
+ public <A extends Annotation> A[] getAnnotationsByType(AnnotationBinding[] annoInstances, Class<A> annotationClass) {
+ A[] result = getAnnotations(annoInstances, annotationClass, false);
+ return result == null ? (A[]) Array.newInstance(annotationClass, 0) : result;
+ }
+
+
+ public <A extends Annotation> A getAnnotation(AnnotationBinding[] annoInstances, Class<A> annotationClass) {
+ A[] result = getAnnotations(annoInstances, annotationClass, true);
+ return result == null ? null : result[0];
+ }
+
+ @SuppressWarnings("unchecked") // for cast of newProxyInstance() to A
+ private <A extends Annotation> A[] getAnnotations(AnnotationBinding[] annoInstances, Class<A> annotationClass, boolean justTheFirst) {
+ if(annoInstances == null || annoInstances.length == 0 || annotationClass == null )
+ return null;
+
+ String annoTypeName = annotationClass.getName();
+ if(annoTypeName == null ) return null;
+
+ List<A> list = new ArrayList<>(annoInstances.length);
+ for(AnnotationBinding annoInstance : annoInstances) {
+ if (annoInstance == null)
+ continue;
+
+ AnnotationMirrorImpl annoMirror = createAnnotationMirror(annoTypeName, annoInstance);
+ if (annoMirror != null) {
+ list.add((A)Proxy.newProxyInstance(annotationClass.getClassLoader(), new Class[]{ annotationClass }, annoMirror));
+ if (justTheFirst) break;
+ }
+ }
+ A [] result = (A[]) Array.newInstance(annotationClass, list.size());
+ return list.size() > 0 ? (A[]) list.toArray(result) : null;
+ }
+
+ private AnnotationMirrorImpl createAnnotationMirror(String annoTypeName, AnnotationBinding annoInstance) {
+ ReferenceBinding binding = annoInstance.getAnnotationType();
+ if (binding != null && binding.isAnnotationType() ) {
+ char[] qName;
+ if (binding.isMemberType()) {
+ annoTypeName = annoTypeName.replace('$', '.');
+ qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.');
+ CharOperation.replace(qName, '$', '.');
+ } else {
+ qName = CharOperation.concatWith(binding.compoundName, '.');
+ }
+ if(annoTypeName.equals(new String(qName)) ){
+ return (AnnotationMirrorImpl)_env.getFactory().newAnnotationMirror(annoInstance);
+ }
+ }
+ return null;
+ }
+
+ private static void appendModifier(Set<Modifier> result, int modifiers, int modifierConstant, Modifier modifier) {
+ if ((modifiers & modifierConstant) != 0) {
+ result.add(modifier);
+ }
+ }
+
+ private static void decodeModifiers(Set<Modifier> result, int modifiers, int[] checkBits) {
+ if (checkBits == null) return;
+ for (int i = 0, max = checkBits.length; i < max; i++) {
+ switch(checkBits[i]) {
+ case ClassFileConstants.AccPublic :
+ appendModifier(result, modifiers, checkBits[i], Modifier.PUBLIC);
+ break;
+ case ClassFileConstants.AccProtected:
+ appendModifier(result, modifiers, checkBits[i], Modifier.PROTECTED);
+ break;
+ case ClassFileConstants.AccPrivate :
+ appendModifier(result, modifiers, checkBits[i], Modifier.PRIVATE);
+ break;
+ case ClassFileConstants.AccAbstract :
+ appendModifier(result, modifiers, checkBits[i], Modifier.ABSTRACT);
+ break;
+ case ExtraCompilerModifiers.AccDefaultMethod :
+ try {
+ appendModifier(result, modifiers, checkBits[i], Modifier.valueOf("DEFAULT")); //$NON-NLS-1$
+ } catch(IllegalArgumentException iae) {
+ // Don't have JDK 1.8, just ignore and proceed.
+ }
+ break;
+ case ClassFileConstants.AccStatic :
+ appendModifier(result, modifiers, checkBits[i], Modifier.STATIC);
+ break;
+ case ClassFileConstants.AccFinal :
+ appendModifier(result, modifiers, checkBits[i], Modifier.FINAL);
+ break;
+ case ClassFileConstants.AccSynchronized :
+ appendModifier(result, modifiers, checkBits[i], Modifier.SYNCHRONIZED);
+ break;
+ case ClassFileConstants.AccNative :
+ appendModifier(result, modifiers, checkBits[i], Modifier.NATIVE);
+ break;
+ case ClassFileConstants.AccStrictfp :
+ appendModifier(result, modifiers, checkBits[i], Modifier.STRICTFP);
+ break;
+ case ClassFileConstants.AccTransient :
+ appendModifier(result, modifiers, checkBits[i], Modifier.TRANSIENT);
+ break;
+ case ClassFileConstants.AccVolatile :
+ appendModifier(result, modifiers, checkBits[i], Modifier.VOLATILE);
+ break;
+ case ExtraCompilerModifiers.AccNonSealed :
+ try {
+ appendModifier(result, modifiers, checkBits[i], Modifier.valueOf("NON_SEALED")); //$NON-NLS-1$
+ } catch(IllegalArgumentException iae) {
+ // Don't have JDK 15, just ignore and proceed.
+ }
+ break;
+ case ExtraCompilerModifiers.AccSealed :
+ try {
+ appendModifier(result, modifiers, checkBits[i], Modifier.valueOf("SEALED")); //$NON-NLS-1$
+ } catch(IllegalArgumentException iae) {
+ // Don't have JDK 15, just ignore and proceed.
+ }
+ break;
+ }
+ }
+ }
+
+ public static Object getMatchingDummyValue(final Class<?> expectedType){
+ if( expectedType.isPrimitive() ){
+ if(expectedType == boolean.class)
+ return Boolean.FALSE;
+ else if( expectedType == byte.class )
+ return DUMMY_BYTE;
+ else if( expectedType == char.class )
+ return DUMMY_CHAR;
+ else if( expectedType == double.class)
+ return DUMMY_DOUBLE;
+ else if( expectedType == float.class )
+ return DUMMY_FLOAT;
+ else if( expectedType == int.class )
+ return DUMMY_INTEGER;
+ else if( expectedType == long.class )
+ return DUMMY_LONG;
+ else if(expectedType == short.class)
+ return DUMMY_SHORT;
+ else // expectedType == void.class. can this happen?
+ return DUMMY_INTEGER; // anything would work
+ }
+ else
+ return null;
+ }
+
+ public TypeMirror getReceiverType(MethodBinding binding) {
+ if (binding != null) {
+ if (binding.receiver != null) {
+ return _env.getFactory().newTypeMirror(binding.receiver);
+ }
+ if (binding.declaringClass != null) {
+ if (!binding.isStatic() && (!binding.isConstructor() || binding.declaringClass.isMemberType())) {
+ return _env.getFactory().newTypeMirror(binding.declaringClass);
+ }
+ }
+ }
+ return NoTypeImpl.NO_TYPE_NONE;
+ }
+
+ public static Set<Modifier> getModifiers(int modifiers, ElementKind kind) {
+ return getModifiers(modifiers, kind, false);
+ }
+ /**
+ * Convert from the JDT's ClassFileConstants flags to the Modifier enum.
+ */
+ public static Set<Modifier> getModifiers(int modifiers, ElementKind kind, boolean isFromBinary)
+ {
+ EnumSet<Modifier> result = EnumSet.noneOf(Modifier.class);
+ switch(kind) {
+ case CONSTRUCTOR :
+ case METHOD :
+ // modifiers for methods
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccAbstract,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccSynchronized,
+ ClassFileConstants.AccNative,
+ ClassFileConstants.AccStrictfp,
+ ExtraCompilerModifiers.AccDefaultMethod
+ });
+ break;
+ case FIELD :
+ case ENUM_CONSTANT :
+ // for fields
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccTransient,
+ ClassFileConstants.AccVolatile
+ });
+ break;
+ case ENUM :
+ if (isFromBinary) {
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccAbstract,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccStrictfp,
+ ExtraCompilerModifiers.AccSealed,
+ });
+ } else {
+ // enum from source cannot be explicitly abstract
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccStrictfp,
+ ExtraCompilerModifiers.AccSealed,
+ });
+ }
+ break;
+ case ANNOTATION_TYPE :
+ case INTERFACE :
+ case CLASS :
+ case RECORD :
+ // for type
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.AccPublic,
+ ClassFileConstants.AccProtected,
+ ClassFileConstants.AccAbstract,
+ ClassFileConstants.AccFinal,
+ ClassFileConstants.AccPrivate,
+ ClassFileConstants.AccStatic,
+ ClassFileConstants.AccStrictfp,
+ ExtraCompilerModifiers.AccSealed,
+ ExtraCompilerModifiers.AccNonSealed
+ });
+ break;
+ case MODULE :
+ decodeModifiers(result, modifiers, new int[] {
+ ClassFileConstants.ACC_OPEN,
+ ClassFileConstants.ACC_TRANSITIVE
+ });
+ default:
+ break;
+ }
+ return Collections.unmodifiableSet(result);
+ }
+
+ public AnnotationMirror newAnnotationMirror(AnnotationBinding binding)
+ {
+ return new AnnotationMirrorImpl(_env, binding);
+ }
+
+ /**
+ * Create a new element that knows what kind it is even if the binding is unresolved.
+ */
+ public Element newElement(Binding binding, ElementKind kindHint) {
+ if (binding == null)
+ return null;
+ switch (binding.kind()) {
+ case Binding.FIELD:
+ case Binding.LOCAL:
+ case Binding.RECORD_COMPONENT:
+ case Binding.VARIABLE:
+ return new VariableElementImpl(_env, (VariableBinding) binding);
+ case Binding.TYPE:
+ case Binding.GENERIC_TYPE:
+ ReferenceBinding referenceBinding = (ReferenceBinding)binding;
+ if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) {
+ return new ErrorTypeElement(this._env, referenceBinding);
+ }
+ if (CharOperation.equals(referenceBinding.sourceName, TypeConstants.PACKAGE_INFO_NAME)) {
+ return newPackageElement(referenceBinding.fPackage);
+ }
+ return new TypeElementImpl(_env, referenceBinding, kindHint);
+ case Binding.METHOD:
+ return new ExecutableElementImpl(_env, (MethodBinding)binding);
+ case Binding.RAW_TYPE:
+ case Binding.PARAMETERIZED_TYPE:
+ return new TypeElementImpl(_env, ((ParameterizedTypeBinding)binding).genericType(), kindHint);
+ case Binding.PACKAGE:
+ return newPackageElement((PackageBinding)binding);
+ case Binding.TYPE_PARAMETER:
+ return new TypeParameterElementImpl(_env, (TypeVariableBinding)binding);
+ // TODO: fill in the rest of these
+ case Binding.MODULE:
+ return new ModuleElementImpl(_env, (ModuleBinding) binding);
+ case Binding.IMPORT:
+ case Binding.ARRAY_TYPE:
+ case Binding.BASE_TYPE:
+ case Binding.WILDCARD_TYPE:
+ case Binding.INTERSECTION_TYPE:
+ throw new UnsupportedOperationException("NYI: binding type " + binding.kind()); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ public Element newElement(Binding binding) {
+ return newElement(binding, null);
+ }
+
+ /**
+ * Convenience method - equivalent to {@code (PackageElement)Factory.newElement(binding)}
+ */
+ public PackageElement newPackageElement(PackageBinding binding)
+ {
+ if (binding != null && binding.enclosingModule != null) {
+ binding = binding.getIncarnation(binding.enclosingModule);
+ }
+ if (binding == null) {
+ return null;
+ }
+ return new PackageElementImpl(_env, binding);
+ }
+
+ public NullType getNullType() {
+ return NoTypeImpl.NULL_TYPE;
+ }
+
+ public NoType getNoType(TypeKind kind)
+ {
+ switch (kind) {
+ case NONE:
+ return NoTypeImpl.NO_TYPE_NONE;
+ case VOID:
+ return NoTypeImpl.NO_TYPE_VOID;
+ case PACKAGE:
+ return NoTypeImpl.NO_TYPE_PACKAGE;
+ case MODULE:
+ return new NoTypeImpl(kind);
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Get a type mirror object representing the specified primitive type kind.
+ * @throw IllegalArgumentException if a non-primitive TypeKind is requested
+ */
+ public PrimitiveTypeImpl getPrimitiveType(TypeKind kind)
+ {
+ switch (kind) {
+ case BOOLEAN:
+ return PrimitiveTypeImpl.BOOLEAN;
+ case BYTE:
+ return PrimitiveTypeImpl.BYTE;
+ case CHAR:
+ return PrimitiveTypeImpl.CHAR;
+ case DOUBLE:
+ return PrimitiveTypeImpl.DOUBLE;
+ case FLOAT:
+ return PrimitiveTypeImpl.FLOAT;
+ case INT:
+ return PrimitiveTypeImpl.INT;
+ case LONG:
+ return PrimitiveTypeImpl.LONG;
+ case SHORT:
+ return PrimitiveTypeImpl.SHORT;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public PrimitiveTypeImpl getPrimitiveType(BaseTypeBinding binding) {
+ AnnotationBinding[] annotations = binding.getTypeAnnotations();
+ if (annotations == null || annotations.length == 0) {
+ return getPrimitiveType(PrimitiveTypeImpl.getKind(binding));
+ }
+ return new PrimitiveTypeImpl(_env, binding);
+ }
+
+ /**
+ * Given a binding of uncertain type, try to create the right sort of TypeMirror for it.
+ */
+ public TypeMirror newTypeMirror(Binding binding) {
+ switch (binding.kind()) {
+ case Binding.FIELD:
+ case Binding.LOCAL:
+ case Binding.RECORD_COMPONENT:
+ case Binding.VARIABLE:
+ // For variables, return the type of the variable
+ return newTypeMirror(((VariableBinding)binding).type);
+
+ case Binding.PACKAGE:
+ return getNoType(TypeKind.PACKAGE);
+
+ case Binding.IMPORT:
+ throw new UnsupportedOperationException("NYI: import type " + binding.kind()); //$NON-NLS-1$
+
+ case Binding.METHOD:
+ return new ExecutableTypeImpl(_env, (MethodBinding) binding);
+
+ case Binding.TYPE:
+ case Binding.RAW_TYPE:
+ case Binding.GENERIC_TYPE:
+ case Binding.PARAMETERIZED_TYPE:
+ ReferenceBinding referenceBinding = (ReferenceBinding) binding;
+ if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) {
+ return getErrorType(referenceBinding);
+ }
+ return new DeclaredTypeImpl(_env, (ReferenceBinding)binding);
+
+ case Binding.ARRAY_TYPE:
+ return new ArrayTypeImpl(_env, (ArrayBinding)binding);
+
+ case Binding.BASE_TYPE:
+ BaseTypeBinding btb = (BaseTypeBinding)binding;
+ switch (btb.id) {
+ case TypeIds.T_void:
+ return getNoType(TypeKind.VOID);
+ case TypeIds.T_null:
+ return getNullType();
+ default:
+ return getPrimitiveType(btb);
+ }
+
+ case Binding.WILDCARD_TYPE:
+ case Binding.INTERSECTION_TYPE: // TODO compatible, but shouldn't it really be an intersection type?
+ return new WildcardTypeImpl(_env, (WildcardBinding) binding);
+
+ case Binding.TYPE_PARAMETER:
+ return new TypeVariableImpl(_env, (TypeVariableBinding) binding);
+ case Binding.MODULE:
+ return getNoType(TypeKind.MODULE);
+ }
+ return null;
+ }
+
+ /**
+ * @param declaringElement the class, method, etc. that is parameterized by this parameter.
+ */
+ public TypeParameterElement newTypeParameterElement(TypeVariableBinding variable, Element declaringElement)
+ {
+ return new TypeParameterElementImpl(_env, variable, declaringElement);
+ }
+
+ public ErrorType getErrorType(ReferenceBinding binding) {
+ return new ErrorTypeImpl(this._env, binding);
+ }
+
+ /**
+ * This method is derived from code in org.eclipse.jdt.apt.core.
+ *
+ * This method is designed to be invoked by the invocation handler and anywhere that requires
+ * a AnnotationValue (AnnotationMirror member values and default values from annotation member).
+ *
+ * Regardless of the path, there are common primitive type conversion that needs to take place.
+ * The type conversions respect the type widening and narrowing rules from JLS 5.1.2 and 5.1.2.
+ *
+ * The only question remains is what is the type of the return value when the type conversion fails?
+ * When <code>avoidReflectException</code> is set to <code>true</code>
+ * Return <code>false</code> if the expected type is <code>boolean</code>
+ * Return numeric 0 for all numeric primitive types and '0' for <code>char</code>
+ *
+ * Otherwise:
+ * Return the value unchanged.
+ *
+ * In the invocation handler case:
+ * The value returned by {@link java.lang.reflect.InvocationHandler#invoke}
+ * will be converted into the expected type by the {@link java.lang.reflect.Proxy}.
+ * If the value and the expected type does not agree, and the value is not null,
+ * a ClassCastException will be thrown. A NullPointerException will result if the
+ * expected type is a primitive type and the value is null.
+ * This behavior causes annotation processors a lot of pain and the decision is
+ * to not throw such unchecked exception. In the case where a ClassCastException or
+ * NullPointerException will be thrown return some dummy value. Otherwise, return
+ * the original value.
+ * Chosen dummy values:
+ * Return <code>false</code> if the expected type is <code>boolean</code>
+ * Return numeric 0 for all numeric primitive types and '0' for <code>char</code>
+ *
+ * This behavior is triggered by setting <code>avoidReflectException</code> to <code>true</code>
+ *
+ * Note: the new behavior deviates from what's documented in
+ * {@link java.lang.reflect.InvocationHandler#invoke} and also deviates from
+ * Sun's implementation.
+ *
+ * @param value the current value from the annotation instance.
+ * @param expectedType the expected type of the value.
+ *
+ */
+ public static Object performNecessaryPrimitiveTypeConversion(
+ final Class<?> expectedType,
+ final Object value,
+ final boolean avoidReflectException)
+ {
+ assert expectedType.isPrimitive() : "expectedType is not a primitive type: " + expectedType.getName(); //$NON-NLS-1$
+ if( value == null)
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : null;
+ // apply widening conversion based on JLS 5.1.2 and 5.1.3
+ final String typeName = expectedType.getName();
+ final char expectedTypeChar = typeName.charAt(0);
+ final int nameLen = typeName.length();
+ // widening byte -> short, int, long, float or double
+ // narrowing byte -> char
+ if( value instanceof Byte )
+ {
+ final byte b = ((Byte)value).byteValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return value; // exact match.
+ else
+ return avoidReflectException ? Boolean.FALSE : value;
+ case 'c':
+ return Character.valueOf((char) b); // narrowing.
+ case 'd':
+ return Double.valueOf(b); // widening.
+ case 'f':
+ return Float.valueOf(b); // widening.
+ case 'i':
+ return Integer.valueOf(b); // widening.
+ case 'l':
+ return Long.valueOf(b); // widening.
+ case 's':
+ return Short.valueOf(b); // widening.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ // widening short -> int, long, float, or double
+ // narrowing short -> byte or char
+ else if( value instanceof Short )
+ {
+ final short s = ((Short)value).shortValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return Byte.valueOf((byte) s); // narrowing.
+ else
+ return avoidReflectException ? Boolean.FALSE : value; // completely wrong.
+ case 'c':
+ return Character.valueOf((char) s); // narrowing.
+ case 'd':
+ return Double.valueOf(s); // widening.
+ case 'f':
+ return Float.valueOf(s); // widening.
+ case 'i':
+ return Integer.valueOf(s); // widening.
+ case 'l':
+ return Long.valueOf(s); // widening.
+ case 's':
+ return value; // exact match
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ // widening char -> int, long, float, or double
+ // narrowing char -> byte or short
+ else if( value instanceof Character )
+ {
+ final char c = ((Character)value).charValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return Byte.valueOf((byte) c); // narrowing.
+ else
+ return avoidReflectException ? Boolean.FALSE : value; // completely wrong.
+ case 'c':
+ return value; // exact match
+ case 'd':
+ return Double.valueOf(c); // widening.
+ case 'f':
+ return Float.valueOf(c); // widening.
+ case 'i':
+ return Integer.valueOf(c); // widening.
+ case 'l':
+ return Long.valueOf(c); // widening.
+ case 's':
+ return Short.valueOf((short) c); // narrowing.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+
+ // widening int -> long, float, or double
+ // narrowing int -> byte, short, or char
+ else if( value instanceof Integer )
+ {
+ final int i = ((Integer)value).intValue();
+ switch( expectedTypeChar )
+ {
+ case 'b':
+ if(nameLen == 4) // byte
+ return Byte.valueOf((byte) i); // narrowing.
+ else
+ return avoidReflectException ? Boolean.FALSE : value; // completely wrong.
+ case 'c':
+ return Character.valueOf((char) i); // narrowing
+ case 'd':
+ return Double.valueOf(i); // widening.
+ case 'f':
+ return Float.valueOf(i); // widening.
+ case 'i':
+ return value; // exact match
+ case 'l':
+ return Long.valueOf(i); // widening.
+ case 's':
+ return Short.valueOf((short) i); // narrowing.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ // widening long -> float or double
+ else if( value instanceof Long )
+ {
+ final long l = ((Long)value).longValue();
+ switch( expectedTypeChar )
+ {
+ case 'b': // both byte and boolean
+ case 'c':
+ case 'i':
+ case 's':
+ // completely wrong.
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value;
+ case 'd':
+ return Double.valueOf(l); // widening.
+ case 'f':
+ return Float.valueOf(l); // widening.
+ case 'l':
+ return value; // exact match.
+
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+
+ // widening float -> double
+ else if( value instanceof Float )
+ {
+ final float f = ((Float)value).floatValue();
+ switch( expectedTypeChar )
+ {
+ case 'b': // both byte and boolean
+ case 'c':
+ case 'i':
+ case 's':
+ case 'l':
+ // completely wrong.
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value;
+ case 'd':
+ return Double.valueOf(f); // widening.
+ case 'f':
+ return value; // exact match.
+ default:
+ throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$
+ }
+ }
+ else if( value instanceof Double ){
+ if(expectedTypeChar == 'd' )
+ return value; // exact match
+ else{
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong.
+ }
+ }
+ else if( value instanceof Boolean ){
+ if( expectedTypeChar == 'b' && nameLen == 7) // "boolean".length() == 7
+ return value;
+ else
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong.
+ }
+ else // can't convert
+ return avoidReflectException ? getMatchingDummyValue(expectedType) : value;
+ }
+
+ /**
+ * Set an element of an array to the appropriate dummy value type
+ * @param array
+ * @param i
+ * @param expectedLeafType
+ */
+ public static void setArrayMatchingDummyValue(Object array, int i, Class<?> expectedLeafType)
+ {
+ if (boolean.class.equals(expectedLeafType)) {
+ Array.setBoolean(array, i, false);
+ }
+ else if (byte.class.equals(expectedLeafType)) {
+ Array.setByte(array, i, DUMMY_BYTE);
+ }
+ else if (char.class.equals(expectedLeafType)) {
+ Array.setChar(array, i, DUMMY_CHAR);
+ }
+ else if (double.class.equals(expectedLeafType)) {
+ Array.setDouble(array, i, DUMMY_DOUBLE);
+ }
+ else if (float.class.equals(expectedLeafType)) {
+ Array.setFloat(array, i, DUMMY_FLOAT);
+ }
+ else if (int.class.equals(expectedLeafType)) {
+ Array.setInt(array, i, DUMMY_INTEGER);
+ }
+ else if (long.class.equals(expectedLeafType)) {
+ Array.setLong(array, i, DUMMY_LONG);
+ }
+ else if (short.class.equals(expectedLeafType)) {
+ Array.setShort(array, i, DUMMY_SHORT);
+ }
+ else {
+ Array.set(array, i, null);
+ }
+ }
+
+ /* Wrap repeating annotations into their container, return an array of bindings.
+ Incoming array is not modified. The resulting array may be null but will not contain null
+ entries.
+ */
+ public static AnnotationBinding [] getPackedAnnotationBindings(AnnotationBinding [] annotations) {
+
+ int length = annotations == null ? 0 : annotations.length;
+ if (length == 0)
+ return annotations;
+
+ AnnotationBinding[] repackagedBindings = annotations; // only replicate if repackaging.
+ for (int i = 0; i < length; i++) {
+ AnnotationBinding annotation = repackagedBindings[i];
+ if (annotation == null) continue;
+ ReferenceBinding annotationType = annotation.getAnnotationType();
+ if (!annotationType.isRepeatableAnnotationType())
+ continue;
+ ReferenceBinding containerType = annotationType.containerAnnotationType();
+ if (containerType == null)
+ continue; // FUBAR.
+ MethodBinding [] values = containerType.getMethods(TypeConstants.VALUE);
+ if (values == null || values.length != 1)
+ continue; // FUBAR.
+ MethodBinding value = values[0];
+ if (value.returnType == null || value.returnType.dimensions() != 1 || TypeBinding.notEquals(value.returnType.leafComponentType(), annotationType))
+ continue; // FUBAR
+
+ // We have a kosher repeatable annotation with a kosher containing type. See if actually repeats.
+ List<AnnotationBinding> containees = null;
+ for (int j = i + 1; j < length; j++) {
+ AnnotationBinding otherAnnotation = repackagedBindings[j];
+ if (otherAnnotation == null) continue;
+ if (otherAnnotation.getAnnotationType() == annotationType) { //$IDENTITY-COMPARISON$
+ if (repackagedBindings == annotations)
+ System.arraycopy(repackagedBindings, 0, repackagedBindings = new AnnotationBinding[length], 0, length);
+ repackagedBindings[j] = null; // so it is not double packed.
+ if (containees == null) {
+ containees = new ArrayList<>();
+ containees.add(annotation);
+ }
+ containees.add(otherAnnotation);
+ }
+ }
+ if (containees != null) {
+ ElementValuePair [] elementValuePairs = new ElementValuePair [] { new ElementValuePair(TypeConstants.VALUE, containees.toArray(), value) };
+ repackagedBindings[i] = new AnnotationBinding(containerType, elementValuePairs);
+ }
+ }
+
+ int finalTally = 0;
+ for (int i = 0; i < length; i++) {
+ if (repackagedBindings[i] != null)
+ finalTally++;
+ }
+
+ if (repackagedBindings == annotations && finalTally == length) {
+ return annotations;
+ }
+
+ annotations = new AnnotationBinding [finalTally];
+ for (int i = 0, j = 0; i < length; i++) {
+ if (repackagedBindings[i] != null)
+ annotations[j++] = repackagedBindings[i];
+ }
+ return annotations;
+ }
+
+ /* Unwrap container annotations into the repeated annotations, return an array of bindings that includes the container and the containees.
+ */
+ public static AnnotationBinding [] getUnpackedAnnotationBindings(AnnotationBinding [] annotations) {
+
+ int length = annotations == null ? 0 : annotations.length;
+ if (length == 0)
+ return annotations;
+
+ List<AnnotationBinding> unpackedAnnotations = new ArrayList<>();
+ for (int i = 0; i < length; i++) {
+ AnnotationBinding annotation = annotations[i];
+ if (annotation == null) continue;
+ unpackedAnnotations.add(annotation);
+ ReferenceBinding annotationType = annotation.getAnnotationType();
+
+ MethodBinding [] values = annotationType.getMethods(TypeConstants.VALUE);
+ if (values == null || values.length != 1)
+ continue;
+ MethodBinding value = values[0];
+
+ if (value.returnType.dimensions() != 1)
+ continue;
+
+ TypeBinding containeeType = value.returnType.leafComponentType();
+ if (containeeType == null || !containeeType.isAnnotationType() || !containeeType.isRepeatableAnnotationType())
+ continue;
+
+ if (containeeType.containerAnnotationType() != annotationType) //$IDENTITY-COMPARISON$
+ continue;
+
+ // We have a kosher container: unwrap the contained annotations.
+ ElementValuePair [] elementValuePairs = annotation.getElementValuePairs();
+ for (ElementValuePair elementValuePair : elementValuePairs) {
+ if (CharOperation.equals(elementValuePair.getName(), TypeConstants.VALUE)) {
+ Object [] containees = (Object []) elementValuePair.getValue();
+ for (Object object : containees) {
+ unpackedAnnotations.add((AnnotationBinding) object);
+ }
+ break;
+ }
+ }
+ }
+ return unpackedAnnotations.toArray(new AnnotationBinding [unpackedAnnotations.size()]);
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java
new file mode 100644
index 0000000..dc0327a
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+/**
+ * Additional information available for Elements that are implemented
+ * within the Eclipse APT framework.
+ * @see javax.lang.model.element.Element
+ * @since 3.3
+ */
+public interface IElementInfo {
+ /**
+ * Get the project-relative path to the source file that contains this element.
+ * If the element is a PackageElement, the "source file" is package-info.java.
+ * If the element is not recognized or does not exist in the project for some
+ * reason, returns null.
+ * @return the project-relative path, or null.
+ */
+ public String getFileName();
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java
new file mode 100644
index 0000000..04fbde7
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * Copyright (c) 2018, 2020 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+public class ModuleElementImpl extends ElementImpl implements ModuleElement {
+
+ ModuleBinding binding;
+ private List<Directive> directives;
+ private static List<Directive> EMPTY_DIRECTIVES = Collections.emptyList();
+
+ /**
+ * In general, clients should call
+ * {@link Factory#newDeclaredType(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)} or
+ * {@link Factory#newElement(org.eclipse.jdt.internal.compiler.lookup.Binding)}
+ * to create new instances.
+ */
+ ModuleElementImpl(BaseProcessingEnvImpl env, ModuleBinding binding) {
+ super(env, binding);
+ this.binding = binding;
+ }
+
+ @Override
+ public ElementKind getKind() {
+ return ElementKind.MODULE;
+ }
+
+ @Override
+ public Set<Modifier> getModifiers() {
+ int modifiers = this.binding.modifiers;
+ return Factory.getModifiers(modifiers, getKind(), false);
+ }
+
+ @Override
+ public Name getQualifiedName() {
+ return new NameImpl(this.binding.moduleName);
+ }
+
+ @Override
+ public Name getSimpleName() {
+ char[] simpleName = this.binding.moduleName;
+ for(int i = simpleName.length-1;i>=0;i--) {
+ if(simpleName[i] == '.') {
+ simpleName = Arrays.copyOfRange(simpleName, i+1, simpleName.length);
+ break;
+ }
+ }
+ return new NameImpl(simpleName);
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ ModuleBinding module = this.binding;
+ Set<PlainPackageBinding> unique = new HashSet<>();
+ for (PlainPackageBinding p : module.declaredPackages.values()) {
+ if (!p.hasCompilationUnit(true))
+ continue;
+ unique.add(p);
+ }
+ if (module.isUnnamed()) {
+ PlainPackageBinding def = module.environment.defaultPackage;
+ // FIXME: Does it have any impact for unnamed modules - default package combo?
+ if (def != null && def.hasCompilationUnit(true)) {
+ unique.add(def);
+ }
+ } else {
+ for (PlainPackageBinding pBinding : this.binding.getExports()) {
+ unique.add(pBinding);
+ }
+ for (PlainPackageBinding pBinding : this.binding.getOpens()) {
+ unique.add(pBinding);
+ }
+ }
+ List<Element> enclosed = new ArrayList<>(unique.size());
+ for (PlainPackageBinding p : unique) {
+ PackageElement pElement = (PackageElement) _env.getFactory().newElement(p);
+ enclosed.add(pElement);
+ }
+ return Collections.unmodifiableList(enclosed);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return (this.binding.modifiers & ClassFileConstants.ACC_OPEN) != 0;
+ }
+
+ @Override
+ public boolean isUnnamed() {
+ return this.binding.moduleName.length == 0;
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ // As of today, modules have no enclosing element
+ return null;
+ }
+
+ @Override
+ public List<? extends Directive> getDirectives() {
+ if (isUnnamed()) {
+ return EMPTY_DIRECTIVES;
+ }
+ if (this.directives == null)
+ this.directives = new ArrayList<>();
+
+ PlainPackageBinding[] packs = this.binding.getExports();
+ for (PlainPackageBinding exp : packs) {
+ this.directives.add(new ExportsDirectiveImpl(exp));
+ }
+ Set<ModuleBinding> transitive = new HashSet<>();
+ for (ModuleBinding mBinding : this.binding.getRequiresTransitive()) {
+ transitive.add(mBinding);
+ }
+ ModuleBinding[] required = this.binding.getRequires();
+ for (ModuleBinding mBinding : required) {
+ if (transitive.contains(mBinding)) {
+ this.directives.add(new RequiresDirectiveImpl(mBinding, true));
+ } else {
+ this.directives.add(new RequiresDirectiveImpl(mBinding, false));
+ }
+ }
+
+ TypeBinding[] tBindings = this.binding.getUses();
+ for (TypeBinding tBinding : tBindings) {
+ this.directives.add(new UsesDirectiveImpl(tBinding));
+ }
+ tBindings = this.binding.getServices();
+ for (TypeBinding tBinding : tBindings) {
+ this.directives.add(new ProvidesDirectiveImpl(tBinding));
+ }
+ packs = this.binding.getOpens();
+ for (PlainPackageBinding exp : packs) {
+ this.directives.add(new OpensDirectiveImpl(exp));
+ }
+ return this.directives;
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> visitor, P param) {
+ return visitor.visitModule(this, param);
+ }
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings() {
+ return ((ModuleBinding) _binding).getAnnotations();
+ }
+
+ abstract class PackageDirectiveImpl {
+ PackageBinding binding;
+ List<ModuleElement> targets;
+
+ PackageDirectiveImpl(PackageBinding pBinding) {
+ this.binding = pBinding;
+ }
+
+ public PackageElement getPackage() {
+ return _env.getFactory().newPackageElement(binding);
+ }
+
+ public List<? extends ModuleElement> getTargetModules(String[] restrictions) {
+ if(this.targets != null) {
+ return targets;
+ }
+ if (restrictions.length == 0) {
+ return (this.targets = null);
+ }
+ List<ModuleElement> targets = new ArrayList<>(restrictions.length);
+ for (String string : restrictions) {
+ ModuleBinding target = ModuleElementImpl.this.binding.environment.getModule(string.toCharArray());
+ if (target != null) {
+ ModuleElement element = ((ModuleElement) _env.getFactory().newElement(target));
+ targets.add(element);
+ }
+ }
+ return (this.targets = Collections.unmodifiableList(targets));
+ }
+ }
+
+ class ExportsDirectiveImpl extends PackageDirectiveImpl implements ModuleElement.ExportsDirective {
+
+ ExportsDirectiveImpl(PackageBinding pBinding) {
+ super(pBinding);
+ }
+
+ @Override
+ public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) {
+ return visitor.visitExports(this, param);
+ }
+
+ @Override
+ public javax.lang.model.element.ModuleElement.DirectiveKind getKind() {
+ return DirectiveKind.EXPORTS;
+ }
+
+ @Override
+ public PackageElement getPackage() {
+ return _env.getFactory().newPackageElement(binding);
+ }
+ @Override
+ public List<? extends ModuleElement> getTargetModules() {
+ if(this.targets != null) {
+ return targets;
+ }
+ return getTargetModules(ModuleElementImpl.this.binding.getExportRestrictions(this.binding));
+ }
+
+ }
+
+ class RequiresDirectiveImpl implements ModuleElement.RequiresDirective {
+ ModuleBinding dependency;
+ boolean transitive;
+
+ RequiresDirectiveImpl(ModuleBinding dependency, boolean transitive) {
+ this.dependency = dependency;
+ this.transitive = transitive;
+ }
+
+ @Override
+ public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) {
+ return visitor.visitRequires(this, param);
+ }
+
+ @Override
+ public javax.lang.model.element.ModuleElement.DirectiveKind getKind() {
+ return DirectiveKind.REQUIRES;
+ }
+
+ @Override
+ public ModuleElement getDependency() {
+ return (ModuleElement) _env.getFactory().newElement(dependency, ElementKind.MODULE);
+ }
+
+ @Override
+ public boolean isStatic() {
+ // TODO: Yet to see this in ModuleBinding. Check again.
+ return false;
+ }
+
+ @Override
+ public boolean isTransitive() {
+ return this.transitive;
+ }
+ }
+
+ class OpensDirectiveImpl extends PackageDirectiveImpl implements ModuleElement.OpensDirective {
+
+ OpensDirectiveImpl(PackageBinding pBinding) {
+ super(pBinding);
+ }
+
+ @Override
+ public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) {
+ return visitor.visitOpens(this, param);
+ }
+
+ @Override
+ public javax.lang.model.element.ModuleElement.DirectiveKind getKind() {
+ return DirectiveKind.OPENS;
+ }
+ @Override
+ public List<? extends ModuleElement> getTargetModules() {
+ if(this.targets != null) {
+ return targets;
+ }
+ return getTargetModules(ModuleElementImpl.this.binding.getOpenRestrictions(this.binding));
+ }
+ }
+
+ class UsesDirectiveImpl implements ModuleElement.UsesDirective {
+ TypeBinding binding = null;
+
+ UsesDirectiveImpl(TypeBinding binding) {
+ this.binding = binding;
+ }
+
+ @Override
+ public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) {
+ return visitor.visitUses(this, param);
+ }
+
+ @Override
+ public DirectiveKind getKind() {
+ return DirectiveKind.USES;
+ }
+
+ @Override
+ public TypeElement getService() {
+ return (TypeElement) _env.getFactory().newElement(binding);
+ }
+
+ }
+
+ class ProvidesDirectiveImpl implements ModuleElement.ProvidesDirective {
+
+ TypeBinding service;
+ public List<? extends TypeElement> implementations;
+
+ ProvidesDirectiveImpl(TypeBinding service) {
+ this.service = service;
+ }
+
+ @Override
+ public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) {
+ return visitor.visitProvides(this, param);
+ }
+
+ @Override
+ public DirectiveKind getKind() {
+ return DirectiveKind.PROVIDES;
+ }
+
+ @Override
+ public List<? extends TypeElement> getImplementations() {
+ if (this.implementations != null)
+ return this.implementations;
+
+ TypeBinding[] implementations2 = ModuleElementImpl.this.binding.getImplementations(this.service);
+ if (implementations2.length == 0) {
+ return (this.implementations = Collections.emptyList());
+ }
+
+ List<TypeElement> list = new ArrayList<>(implementations2.length);
+ Factory factory = _env.getFactory();
+ for (TypeBinding type: implementations2) {
+ TypeElement element = (TypeElement) factory.newElement(type);
+ list.add(element);
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ @Override
+ public TypeElement getService() {
+ return (TypeElement) _env.getFactory().newElement(this.service);
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java
new file mode 100644
index 0000000..828e231
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.element.Name;
+
+/**
+ * A String-based implementation of the type used to return strings in javax.lang.model.
+ */
+public class NameImpl implements Name {
+
+ private final String _name;
+
+ /** nullary constructor is prohibited */
+ @SuppressWarnings("unused")
+ private NameImpl()
+ {
+ _name = null;
+ }
+
+ public NameImpl(CharSequence cs)
+ {
+ _name = cs.toString();
+ }
+
+ public NameImpl(char[] chars)
+ {
+ _name = String.valueOf(chars);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.element.Name#contentEquals(java.lang.CharSequence)
+ */
+ @Override
+ public boolean contentEquals(CharSequence cs) {
+ return _name.equals(cs.toString());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.CharSequence#charAt(int)
+ */
+ @Override
+ public char charAt(int index) {
+ return _name.charAt(index);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.CharSequence#length()
+ */
+ @Override
+ public int length() {
+ return _name.length();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.CharSequence#subSequence(int, int)
+ */
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return _name.subSequence(start, end);
+ }
+
+ @Override
+ public String toString() {
+ return _name;
+ }
+
+ @Override
+ public int hashCode() {
+ return _name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final NameImpl other = (NameImpl) obj;
+ return _name.equals(other._name);
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java
new file mode 100644
index 0000000..884b710
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.NullType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+/**
+ * An implementation of NoType, which is used to represent certain pseudo-types.
+ * @see NoType
+ */
+public class NoTypeImpl extends TypeMirrorImpl implements NoType, NullType
+{
+ private final TypeKind _kind;
+
+ public static final NoType NO_TYPE_NONE = new NoTypeImpl(TypeKind.NONE);
+ public static final NoType NO_TYPE_VOID = new NoTypeImpl(TypeKind.VOID, TypeBinding.VOID);
+ public static final NoType NO_TYPE_PACKAGE = new NoTypeImpl(TypeKind.PACKAGE);
+ public static final NullType NULL_TYPE = new NoTypeImpl(TypeKind.NULL, TypeBinding.NULL);
+ public static final Binding NO_TYPE_BINDING = new Binding() {
+ @Override
+ public int kind() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public char[] readableName() {
+ throw new IllegalStateException();
+ }
+ };
+
+ public NoTypeImpl(TypeKind kind) {
+ super(null, NO_TYPE_BINDING);
+ _kind = kind;
+ }
+ public NoTypeImpl(TypeKind kind, Binding binding) {
+ super(null, binding);
+ _kind = kind;
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p)
+ {
+ switch(this.getKind())
+ {
+ case NULL :
+ return v.visitNull(this, p);
+ default:
+ return v.visitNoType(this, p);
+ }
+ }
+
+ @Override
+ public TypeKind getKind()
+ {
+ return _kind;
+ }
+
+ @Override
+ public String toString()
+ {
+ switch (_kind) {
+ default:
+ case NONE:
+ return "none"; //$NON-NLS-1$
+ case NULL:
+ return "null"; //$NON-NLS-1$
+ case VOID:
+ return "void"; //$NON-NLS-1$
+ case PACKAGE:
+ return "package"; //$NON-NLS-1$
+ case MODULE:
+ return "module"; //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return Factory.EMPTY_ANNOTATION_MIRRORS;
+ }
+
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ return (A[]) Array.newInstance(annotationType, 0);
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java
new file mode 100644
index 0000000..79a2bd5
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2017 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+
+/**
+ * Implementation of PackageElement, which represents a package
+ */
+public class PackageElementImpl extends ElementImpl implements PackageElement {
+
+ PackageElementImpl(BaseProcessingEnvImpl env, PackageBinding binding) {
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitPackage(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ PackageBinding packageBinding = (PackageBinding) this._binding;
+ char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME);
+ ReferenceBinding type = packageBinding.environment.getType(compoundName);
+ AnnotationBinding[] annotations = null;
+ if (type != null && type.isValidBinding()) {
+ annotations = type.getAnnotations();
+ }
+ return annotations;
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ PackageBinding binding = (PackageBinding)_binding;
+ LookupEnvironment environment = binding.environment;
+ char[][][] typeNames = null;
+ INameEnvironment nameEnvironment = binding.environment.nameEnvironment;
+ if (nameEnvironment instanceof FileSystem) {
+ typeNames = ((FileSystem) nameEnvironment).findTypeNames(binding.compoundName);
+ }
+ HashSet<Element> set = new HashSet<>();
+ Set<ReferenceBinding> types = new HashSet<>();
+ if (typeNames != null) {
+ for (char[][] typeName : typeNames) {
+ if (typeName == null) continue;
+ ReferenceBinding type = environment.getType(typeName);
+ if (type == null || type.isMemberType()) continue;
+ if (type.isValidBinding()) {
+ Element newElement = _env.getFactory().newElement(type);
+ if (newElement.getKind() != ElementKind.PACKAGE) {
+ set.add(newElement);
+ types.add(type);
+ }
+ }
+ }
+ }
+ if (binding.knownTypes != null) {
+ ReferenceBinding[] knownTypes = binding.knownTypes.valueTable;
+ for (ReferenceBinding referenceBinding : knownTypes) {
+ if (referenceBinding != null && referenceBinding.isValidBinding() && referenceBinding.enclosingType() == null) {
+ if (!types.contains(referenceBinding)) {
+ Element newElement = _env.getFactory().newElement(referenceBinding);
+ if (newElement.getKind() != ElementKind.PACKAGE)
+ set.add(newElement);
+ }
+ }
+ }
+ }
+ ArrayList<Element> list = new ArrayList<>(set.size());
+ list.addAll(set);
+ return Collections.unmodifiableList(list);
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ if (super._env.getCompiler().options.sourceLevel < ClassFileConstants.JDK9) {
+ return null;
+ }
+ PackageBinding pBinding = (PackageBinding) _binding;
+ ModuleBinding module = pBinding.enclosingModule;
+ if (module == null)
+ return null;
+ return new ModuleElementImpl(_env, module);
+ }
+
+ @Override
+ public ElementKind getKind() {
+ return ElementKind.PACKAGE;
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ return this;
+ }
+
+ @Override
+ public Name getSimpleName() {
+ char[][] compoundName = ((PackageBinding)_binding).compoundName;
+ int length = compoundName.length;
+ if (length == 0) {
+ return new NameImpl(CharOperation.NO_CHAR);
+ }
+ return new NameImpl(compoundName[length - 1]);
+ }
+
+ @Override
+ public Name getQualifiedName() {
+ return new NameImpl(CharOperation.concatWith(((PackageBinding)_binding).compoundName, '.'));
+ }
+
+ @Override
+ public boolean isUnnamed() {
+ PackageBinding binding = (PackageBinding)_binding;
+ return binding.compoundName == CharOperation.NO_CHAR_CHAR;
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java
new file mode 100644
index 0000000..8f4021a
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2014 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+/**
+ *
+ * @since 3.3
+ */
+public class PrimitiveTypeImpl extends TypeMirrorImpl implements PrimitiveType {
+
+ public final static PrimitiveTypeImpl BOOLEAN = new PrimitiveTypeImpl(TypeBinding.BOOLEAN);
+ public final static PrimitiveTypeImpl BYTE = new PrimitiveTypeImpl(TypeBinding.BYTE);
+ public final static PrimitiveTypeImpl CHAR = new PrimitiveTypeImpl(TypeBinding.CHAR);
+ public final static PrimitiveTypeImpl DOUBLE = new PrimitiveTypeImpl(TypeBinding.DOUBLE);
+ public final static PrimitiveTypeImpl FLOAT = new PrimitiveTypeImpl(TypeBinding.FLOAT);
+ public final static PrimitiveTypeImpl INT = new PrimitiveTypeImpl(TypeBinding.INT);
+ public final static PrimitiveTypeImpl LONG = new PrimitiveTypeImpl(TypeBinding.LONG);
+ public final static PrimitiveTypeImpl SHORT = new PrimitiveTypeImpl(TypeBinding.SHORT);
+
+ /**
+ * Clients should call {@link Factory#getPrimitiveType(TypeKind)},
+ * rather than creating new objects.
+ */
+ private PrimitiveTypeImpl(BaseTypeBinding binding) {
+ // Primitive types do not need an environment!
+ super(null, binding);
+ }
+
+ PrimitiveTypeImpl(BaseProcessingEnvImpl env, BaseTypeBinding binding) {
+ // From Java 8, base type bindings can hold annotations and hence need the environment.
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p)
+ {
+ return v.visitPrimitive(this, p);
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return getKind((BaseTypeBinding)_binding);
+ }
+
+ public static TypeKind getKind(BaseTypeBinding binding) {
+ switch (binding.id) {
+ case TypeIds.T_boolean:
+ return TypeKind.BOOLEAN;
+ case TypeIds.T_byte:
+ return TypeKind.BYTE;
+ case TypeIds.T_char:
+ return TypeKind.CHAR;
+ case TypeIds.T_double:
+ return TypeKind.DOUBLE;
+ case TypeIds.T_float:
+ return TypeKind.FLOAT;
+ case TypeIds.T_int:
+ return TypeKind.INT;
+ case TypeIds.T_long:
+ return TypeKind.LONG;
+ case TypeIds.T_short:
+ return TypeKind.SHORT;
+ default:
+ throw new IllegalArgumentException("BaseTypeBinding of unexpected id " + binding.id); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java
new file mode 100644
index 0000000..06c36f8
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2020, 2021 IBM Corporation.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.RecordComponentElement;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+
+public class RecordComponentElementImpl extends VariableElementImpl implements RecordComponentElement {
+
+ protected RecordComponentElementImpl(BaseProcessingEnvImpl env, RecordComponentBinding binding) {
+ super(env, binding);
+ }
+
+ @Override
+ public ElementKind getKind() {
+ return ElementKind.RECORD_COMPONENT;
+ }
+
+ @Override
+ public ExecutableElement getAccessor() {
+ RecordComponentBinding comp = (RecordComponentBinding) this._binding;
+ ReferenceBinding binding = comp.declaringRecord;
+ if (binding instanceof SourceTypeBinding) {
+ MethodBinding accessor = ((SourceTypeBinding) binding).getRecordComponentAccessor(comp.name);
+ return new ExecutableElementImpl(_env, accessor);
+ }
+ return null;
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> visitor, P param) {
+ return visitor.visitRecordComponent(this, param);
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
new file mode 100644
index 0000000..435b19c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
@@ -0,0 +1,398 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2021 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.RecordComponentElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+public class TypeElementImpl extends ElementImpl implements TypeElement {
+
+ /**
+ * Compares Element instances possibly returned by
+ * {@link TypeElement#getEnclosedElements()} based on their source location, if available.
+ *
+ */
+ private static final class SourceLocationComparator implements Comparator<Element> {
+ private final IdentityHashMap<ElementImpl, Integer> sourceStartCache = new IdentityHashMap<>();
+
+ @Override
+ public int compare(Element o1, Element o2) {
+ ElementImpl e1 = (ElementImpl) o1;
+ ElementImpl e2 = (ElementImpl) o2;
+
+ return getSourceStart(e1) - getSourceStart(e2);
+ }
+
+ private int getSourceStart(ElementImpl e) {
+ Integer value = sourceStartCache.get(e);
+
+ if (value == null) {
+ value = determineSourceStart(e);
+ sourceStartCache.put(e, value);
+ }
+
+ return value;
+ }
+
+ private int determineSourceStart(ElementImpl e) {
+ switch(e.getKind()) {
+ case ANNOTATION_TYPE :
+ case INTERFACE :
+ case CLASS :
+ case ENUM :
+ case RECORD :
+ TypeElementImpl typeElementImpl = (TypeElementImpl) e;
+ Binding typeBinding = typeElementImpl._binding;
+ if (typeBinding instanceof SourceTypeBinding) {
+ SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) typeBinding;
+ TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext();
+ return typeDeclaration.sourceStart;
+ }
+ break;
+ case CONSTRUCTOR :
+ case METHOD :
+ ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e;
+ Binding binding = executableElementImpl._binding;
+ if (binding instanceof MethodBinding) {
+ MethodBinding methodBinding = (MethodBinding) binding;
+ return methodBinding.sourceStart();
+ }
+ break;
+ case ENUM_CONSTANT :
+ case FIELD :
+ case RECORD_COMPONENT :
+ VariableElementImpl variableElementImpl = (VariableElementImpl) e;
+ binding = variableElementImpl._binding;
+ if (binding instanceof FieldBinding) {
+ FieldBinding fieldBinding = (FieldBinding) binding;
+ FieldDeclaration fieldDeclaration = fieldBinding.sourceField();
+ if (fieldDeclaration != null) {
+ return fieldDeclaration.sourceStart;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -1;
+ }
+ }
+
+ private final ElementKind _kindHint;
+
+ /**
+ * In general, clients should call {@link Factory#newDeclaredType(ReferenceBinding)} or
+ * {@link Factory#newElement(org.eclipse.jdt.internal.compiler.lookup.Binding)} to
+ * create new instances.
+ */
+ TypeElementImpl(BaseProcessingEnvImpl env, ReferenceBinding binding, ElementKind kindHint) {
+ super(env, binding);
+ _kindHint = kindHint;
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitType(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((ReferenceBinding)_binding).getAnnotations();
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ List<Element> enclosed = new ArrayList<>(binding.fieldCount() + binding.methods().length + binding.memberTypes().length);
+ for (MethodBinding method : binding.methods()) {
+ ExecutableElement executable = new ExecutableElementImpl(_env, method);
+ enclosed.add(executable);
+ }
+ for (FieldBinding field : binding.fields()) {
+ // TODO no field should be excluded according to the JLS
+ if (!field.isSynthetic()) {
+ VariableElement variable = new VariableElementImpl(_env, field);
+ enclosed.add(variable);
+ }
+ }
+ if (binding.isRecord()) {
+ RecordComponentBinding[] components = binding.components();
+ for (RecordComponentBinding comp : components) {
+ RecordComponentElement rec = new RecordComponentElementImpl(_env, comp);
+ enclosed.add(rec);
+ }
+ }
+ for (ReferenceBinding memberType : binding.memberTypes()) {
+ TypeElement type = new TypeElementImpl(_env, memberType, null);
+ enclosed.add(type);
+ }
+ Collections.sort(enclosed, new SourceLocationComparator());
+ return Collections.unmodifiableList(enclosed);
+ }
+
+ @Override
+ public List<? extends RecordComponentElement> getRecordComponents() {
+ if (_binding instanceof SourceTypeBinding) {
+ SourceTypeBinding binding = (SourceTypeBinding) _binding;
+ List<RecordComponentElement> enclosed = new ArrayList<>();
+ for (RecordComponentBinding comp : binding.components()) {
+ RecordComponentElement variable = new RecordComponentElementImpl(_env, comp);
+ enclosed.add(variable);
+ }
+ Collections.sort(enclosed, new SourceLocationComparator());
+ return Collections.unmodifiableList(enclosed);
+ }
+ // TODO: Add code for BinaryTypeBinding, which, as of now doesn't seem to contain components
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<? extends TypeMirror> getPermittedSubclasses() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ if (binding.isSealed()) {
+ List<TypeMirror> permitted = new ArrayList<>();
+ for (ReferenceBinding type : binding.permittedTypes()) {
+ TypeMirror typeMirror = _env.getFactory().newTypeMirror(type);
+ permitted.add(typeMirror);
+ }
+ return Collections.unmodifiableList(permitted);
+ }
+ return Collections.emptyList();
+ }
+ @Override
+ public Element getEnclosingElement() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ ReferenceBinding enclosingType = binding.enclosingType();
+ if (null == enclosingType) {
+ // this is a top level type; get its package
+ return _env.getFactory().newPackageElement(binding.fPackage);
+ }
+ else {
+ return _env.getFactory().newElement(binding.enclosingType());
+ }
+ }
+
+ @Override
+ public String getFileName() {
+ char[] name = ((ReferenceBinding)_binding).getFileName();
+ if (name == null)
+ return null;
+ return new String(name);
+ }
+
+ @Override
+ public List<? extends TypeMirror> getInterfaces() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ if (null == binding.superInterfaces() || binding.superInterfaces().length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeMirror> interfaces = new ArrayList<>(binding.superInterfaces().length);
+ for (ReferenceBinding interfaceBinding : binding.superInterfaces()) {
+ TypeMirror interfaceType = _env.getFactory().newTypeMirror(interfaceBinding);
+ if (interfaceType.getKind() == TypeKind.ERROR) {
+ if (this._env.getSourceVersion().compareTo(SourceVersion.RELEASE_6) > 0) {
+ // for jdk 7 and above, add error types
+ interfaces.add(interfaceType);
+ }
+ } else {
+ interfaces.add(interfaceType);
+ }
+ }
+ return Collections.unmodifiableList(interfaces);
+ }
+
+ @Override
+ public ElementKind getKind() {
+ if (null != _kindHint) {
+ return _kindHint;
+ }
+ ReferenceBinding refBinding = (ReferenceBinding)_binding;
+ // The order of these comparisons is important: e.g., enum is subset of class
+ if (refBinding.isEnum()) {
+ return ElementKind.ENUM;
+ }
+ else if (refBinding.isRecord()) {
+ return ElementKind.RECORD;
+ }
+ else if (refBinding.isAnnotationType()) {
+ return ElementKind.ANNOTATION_TYPE;
+ }
+ else if (refBinding.isInterface()) {
+ return ElementKind.INTERFACE;
+ }
+ else if (refBinding.isClass()) {
+ return ElementKind.CLASS;
+ }
+ else {
+ throw new IllegalArgumentException("TypeElement " + new String(refBinding.shortReadableName()) + //$NON-NLS-1$
+ " has unexpected attributes " + refBinding.modifiers); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Set<Modifier> getModifiers()
+ {
+ ReferenceBinding refBinding = (ReferenceBinding)_binding;
+ int modifiers = refBinding.modifiers;
+ if (refBinding.isInterface() && refBinding.isNestedType()) {
+ modifiers |= ClassFileConstants.AccStatic;
+ }
+
+ return Factory.getModifiers(modifiers, getKind(), refBinding.isBinaryBinding());
+ }
+
+ @Override
+ public NestingKind getNestingKind() {
+ ReferenceBinding refBinding = (ReferenceBinding)_binding;
+ if (refBinding.isAnonymousType()) {
+ return NestingKind.ANONYMOUS;
+ } else if (refBinding.isLocalType()) {
+ return NestingKind.LOCAL;
+ } else if (refBinding.isMemberType()) {
+ return NestingKind.MEMBER;
+ }
+ return NestingKind.TOP_LEVEL;
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ return _env.getFactory().newPackageElement(binding.fPackage);
+ }
+
+ @Override
+ public Name getQualifiedName() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ char[] qName;
+ if (binding.isMemberType()) {
+ qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.');
+ CharOperation.replace(qName, '$', '.');
+ } else {
+ qName = CharOperation.concatWith(binding.compoundName, '.');
+ }
+ return new NameImpl(qName);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.apt.model.ElementImpl#getSimpleName()
+ * @return last segment of name, e.g. for pa.pb.X.Y return Y.
+ */
+ @Override
+ public Name getSimpleName()
+ {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ return new NameImpl(binding.sourceName());
+ }
+
+ @Override
+ public TypeMirror getSuperclass() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ ReferenceBinding superBinding = binding.superclass();
+ if (null == superBinding || binding.isInterface()) {
+ return _env.getFactory().getNoType(TypeKind.NONE);
+ }
+ // superclass of a type must be a DeclaredType
+ return _env.getFactory().newTypeMirror(superBinding);
+ }
+
+ @Override
+ public List<? extends TypeParameterElement> getTypeParameters() {
+ ReferenceBinding binding = (ReferenceBinding)_binding;
+ TypeVariableBinding[] variables = binding.typeVariables();
+ if (variables.length == 0) {
+ return Collections.emptyList();
+ }
+ List<TypeParameterElement> params = new ArrayList<>(variables.length);
+ for (TypeVariableBinding variable : variables) {
+ params.add(_env.getFactory().newTypeParameterElement(variable, this));
+ }
+ return Collections.unmodifiableList(params);
+ }
+
+ @Override
+ public boolean hides(Element hidden)
+ {
+ if (!(hidden instanceof TypeElementImpl)) {
+ return false;
+ }
+ ReferenceBinding hiddenBinding = (ReferenceBinding)((TypeElementImpl)hidden)._binding;
+ if (hiddenBinding.isPrivate()) {
+ return false;
+ }
+ ReferenceBinding hiderBinding = (ReferenceBinding)_binding;
+ if (TypeBinding.equalsEquals(hiddenBinding, hiderBinding)) {
+ return false;
+ }
+ if (!hiddenBinding.isMemberType() || !hiderBinding.isMemberType()) {
+ return false;
+ }
+ if (!CharOperation.equals(hiddenBinding.sourceName, hiderBinding.sourceName)) {
+ return false;
+ }
+ return null != hiderBinding.enclosingType().findSuperTypeOriginatingFrom(hiddenBinding.enclosingType());
+ }
+
+ @Override
+ public String toString() {
+ ReferenceBinding binding = (ReferenceBinding) this._binding;
+ char[] concatWith = CharOperation.concatWith(binding.compoundName, '.');
+ if (binding.isNestedType()) {
+ CharOperation.replace(concatWith, '$', '.');
+ return new String(concatWith);
+ }
+ return new String(concatWith);
+
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java
new file mode 100644
index 0000000..14218e9
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2014 BEA Systems, 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
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+/**
+ * Implementation of a TypeMirror. TypeMirror represents a type, including
+ * types that have no declaration, such as primitives (int, boolean) and
+ * types that are specializations of declarations (List<String>).
+ */
+public class TypeMirrorImpl implements TypeMirror {
+
+ // Caution: _env will be NULL for unannotated primitive types (PrimitiveTypeImpl).
+ protected final BaseProcessingEnvImpl _env;
+ protected final Binding _binding;
+
+ /* package */ TypeMirrorImpl(BaseProcessingEnvImpl env, Binding binding) {
+ _env = env;
+ _binding = binding;
+ }
+
+ /* package */ Binding binding() {
+ return _binding;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visit(this, p);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ switch (_binding.kind()) {
+ // case Binding.TYPE:
+ // case Binding.RAW_TYPE:
+ // case Binding.GENERIC_TYPE:
+ // case Binding.PARAMETERIZED_TYPE:
+ // handled by DeclaredTypeImpl, etc.
+ // case Binding.BASE_TYPE: handled by PrimitiveTypeImpl
+ // case Binding.METHOD: handled by ExecutableTypeImpl
+ // case Binding.PACKAGE: handled by NoTypeImpl
+ // case Binding.WILDCARD_TYPE: handled by WildcardTypeImpl
+ // case Binding.ARRAY_TYPE: handled by ArrayTypeImpl
+ // case Binding.TYPE_PARAMETER: handled by TypeVariableImpl
+ // TODO: fill in the rest of these
+ case Binding.FIELD:
+ case Binding.LOCAL:
+ case Binding.RECORD_COMPONENT:
+ case Binding.VARIABLE:
+ case Binding.IMPORT:
+ throw new IllegalArgumentException("Invalid binding kind: " + _binding.kind()); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_binding == null) ? 0 : _binding.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof TypeMirrorImpl))
+ return false;
+ final TypeMirrorImpl other = (TypeMirrorImpl) obj;
+ return _binding == other._binding;
+ }
+
+ /* Package any repeating annotations into containers, return others as is.
+ In the compiler bindings repeating annotations are left in as is, hence
+ this step. The return value would match what one would expect to see in
+ a class file.
+ */
+ public final AnnotationBinding [] getPackedAnnotationBindings() {
+ return Factory.getPackedAnnotationBindings(getAnnotationBindings());
+ }
+
+ protected AnnotationBinding[] getAnnotationBindings() {
+ return ((TypeBinding)_binding).getTypeAnnotations();
+ }
+
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ return _env == null ? Factory.EMPTY_ANNOTATION_MIRRORS :
+ _env.getFactory().getAnnotationMirrors(getPackedAnnotationBindings());
+ }
+
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return _env == null ? null : _env.getFactory().getAnnotation(getPackedAnnotationBindings(), annotationType);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ if (_env == null)
+ return (A[]) Array.newInstance(annotationType, 0);
+ return _env.getFactory().getAnnotationsByType(Factory.getUnpackedAnnotationBindings(getPackedAnnotationBindings()), annotationType);
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java
new file mode 100644
index 0000000..6e0ab70
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * IBM Corporation - fix for 342470
+ * IBM Corporation - fix for 342598
+ * IBM Corporation - Java 8 support
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeMirror;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ *
+ */
+public class TypeParameterElementImpl extends ElementImpl implements TypeParameterElement
+{
+ private final Element _declaringElement;
+
+ // Cache the bounds, because they're expensive to compute
+ private List<? extends TypeMirror> _bounds = null;
+
+ /* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding, Element declaringElement) {
+ super(env, binding);
+ _declaringElement = declaringElement;
+ }
+
+ /* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) {
+ super(env, binding);
+ _declaringElement = _env.getFactory().newElement(binding.declaringElement);
+ }
+
+ @Override
+ public List<? extends TypeMirror> getBounds()
+ {
+ if (null == _bounds) {
+ _bounds = calculateBounds();
+ }
+ return _bounds;
+ }
+
+ // This code is drawn from org.eclipse.jdt.core.dom.TypeBinding.getTypeBounds()
+ private List<? extends TypeMirror> calculateBounds() {
+ TypeVariableBinding typeVariableBinding = (TypeVariableBinding)_binding;
+ ReferenceBinding varSuperclass = typeVariableBinding.superclass();
+ TypeBinding firstClassOrArrayBound = typeVariableBinding.firstBound;
+ int boundsLength = 0;
+ boolean isFirstBoundATypeVariable = false;
+ if (firstClassOrArrayBound != null) {
+ if (firstClassOrArrayBound.isTypeVariable()) {
+ isFirstBoundATypeVariable = true;
+ }
+ if (TypeBinding.equalsEquals(firstClassOrArrayBound, varSuperclass)) {
+ boundsLength++;
+ if (firstClassOrArrayBound.isTypeVariable()) {
+ isFirstBoundATypeVariable = true;
+ }
+ } else if (firstClassOrArrayBound.isArrayType()) { // capture of ? extends/super arrayType
+ boundsLength++;
+ } else {
+ firstClassOrArrayBound = null;
+ }
+ }
+ ReferenceBinding[] superinterfaces = typeVariableBinding.superInterfaces();
+ int superinterfacesLength = 0;
+ if (superinterfaces != null) {
+ superinterfacesLength = superinterfaces.length;
+ boundsLength += superinterfacesLength;
+ }
+ List<TypeMirror> typeBounds = new ArrayList<>(boundsLength);
+ if (boundsLength != 0) {
+ if (firstClassOrArrayBound != null) {
+ TypeMirror typeBinding = _env.getFactory().newTypeMirror(firstClassOrArrayBound);
+ if (typeBinding == null) {
+ return Collections.emptyList();
+ }
+ typeBounds.add(typeBinding);
+ }
+ // we need to filter out remaining bounds if the first bound is a type variable
+ if (superinterfaces != null && !isFirstBoundATypeVariable) {
+ for (int i = 0; i < superinterfacesLength; i++) {
+ TypeMirror typeBinding = _env.getFactory().newTypeMirror(superinterfaces[i]);
+ if (typeBinding == null) {
+ return Collections.emptyList();
+ }
+ typeBounds.add(typeBinding);
+ }
+ }
+ } else {
+ // at least we must add java.lang.Object
+ typeBounds.add(_env.getFactory().newTypeMirror(_env.getLookupEnvironment().getType(LookupEnvironment.JAVA_LANG_OBJECT)));
+ }
+ return Collections.unmodifiableList(typeBounds);
+ }
+
+ @Override
+ public Element getGenericElement()
+ {
+ return _declaringElement;
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitTypeParameter(this, p);
+ }
+
+ /*
+ * (non-Javadoc)
+ * Java supports annotations on type parameters from JLS8
+ * @see javax.lang.model.element.Element#getAnnotationMirrors()
+ */
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((TypeVariableBinding)_binding).getTypeAnnotations();
+ }
+
+ private boolean shouldEmulateJavacBug() {
+ if (_env.getLookupEnvironment().globalOptions.emulateJavacBug8031744) {
+ AnnotationBinding [] annotations = getAnnotationBindings();
+ for (int i = 0, length = annotations.length; i < length; i++) {
+ ReferenceBinding firstAnnotationType = annotations[i].getAnnotationType();
+ for (int j = i+1; j < length; j++) {
+ ReferenceBinding secondAnnotationType = annotations[j].getAnnotationType();
+ if (firstAnnotationType == secondAnnotationType) //$IDENTITY-COMPARISON$
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public List<? extends AnnotationMirror> getAnnotationMirrors() {
+ if (shouldEmulateJavacBug())
+ return Collections.emptyList();
+ return super.getAnnotationMirrors();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked") // for the cast to A
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
+ if (shouldEmulateJavacBug())
+ return (A[]) Array.newInstance(annotationType, 0);
+ return super.getAnnotationsByType(annotationType);
+ }
+
+ @Override
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ if (shouldEmulateJavacBug())
+ return null;
+ return super.getAnnotation(annotationType);
+ }
+
+ /*
+ * (non-Javadoc)
+ * Always return an empty list; type parameters do not enclose other elements.
+ * @see javax.lang.model.element.Element#getEnclosedElements()
+ */
+ @Override
+ public List<? extends Element> getEnclosedElements()
+ {
+ return Collections.emptyList();
+ }
+
+ /*
+ * (non-Javadoc)
+ * Always return null.
+ * @see javax.lang.model.element.Element#getEnclosingElement()
+ */
+ @Override
+ public Element getEnclosingElement()
+ {
+ return getGenericElement();
+ }
+
+ @Override
+ public ElementKind getKind()
+ {
+ return ElementKind.TYPE_PARAMETER;
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ // TODO what is the package of a type parameter?
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return new String(_binding.readableName());
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java
new file mode 100644
index 0000000..21ad258
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2013 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.TypeVisitor;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+
+/**
+ * Implementation of TypeVariable
+ */
+public class TypeVariableImpl extends TypeMirrorImpl implements TypeVariable {
+
+ TypeVariableImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) {
+ super(env, binding);
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeVariable#asElement()
+ */
+ @Override
+ public Element asElement() {
+ return _env.getFactory().newElement(this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeVariable#getLowerBound()
+ */
+ @Override
+ public TypeMirror getLowerBound() {
+ // TODO might be more complex than this
+ return this._env.getFactory().getNullType();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeVariable#getUpperBound()
+ */
+ @Override
+ public TypeMirror getUpperBound() {
+ TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this._binding;
+ TypeBinding firstBound = typeVariableBinding.firstBound;
+ ReferenceBinding[] superInterfaces = typeVariableBinding.superInterfaces;
+ if (firstBound == null || superInterfaces.length == 0) {
+ // no explicit bound
+ return _env.getFactory().newTypeMirror(typeVariableBinding.upperBound());
+ }
+ if (firstBound != null && superInterfaces.length == 1 && TypeBinding.equalsEquals(superInterfaces[0], firstBound)) {
+ // only one bound that is an interface
+ return _env.getFactory().newTypeMirror(typeVariableBinding.upperBound());
+ }
+ return this._env.getFactory().newTypeMirror((TypeVariableBinding) this._binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object)
+ */
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitTypeVariable(this, p);
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.TYPEVAR;
+ }
+
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
new file mode 100644
index 0000000..370cacd
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
@@ -0,0 +1,584 @@
+/*******************************************************************************
+ * Copyright (c) 2007 - 2017 BEA Systems, 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
+ *
+ * Contributors:
+ * Walter Harley - initial API and implementation
+ * IBM Corporation - fix for 342598, 382590
+ * Jean-Marie Henaff <jmhenaff@google.com> (Google) - Bug 481555
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.NullType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.Types;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
+
+/**
+ * Utilities for working with types (as opposed to elements).
+ * There is one of these for every ProcessingEnvironment.
+ */
+public class TypesImpl implements Types {
+
+ private final BaseProcessingEnvImpl _env;
+
+ /*
+ * The processing env creates and caches a TypesImpl. Other clients should
+ * not create their own; they should ask the env for it.
+ */
+ public TypesImpl(BaseProcessingEnvImpl env) {
+ _env = env;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.util.Types#asElement(javax.lang.model.type.TypeMirror)
+ */
+ @Override
+ public Element asElement(TypeMirror t) {
+ switch(t.getKind()) {
+ case DECLARED :
+ case TYPEVAR :
+ return _env.getFactory().newElement(((TypeMirrorImpl)t).binding());
+ default:
+ break;
+ }
+ return null;
+ }
+
+ @Override
+ public TypeMirror asMemberOf(DeclaredType containing, Element element) {
+ // throw new UnsupportedOperationException("NYI: TypesImpl.asMemberOf("
+ // + containing + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ // //$NON-NLS-3$
+ ElementImpl elementImpl = (ElementImpl) element;
+ DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
+ ReferenceBinding referenceBinding = (ReferenceBinding) declaredTypeImpl._binding;
+ TypeMirror typeMirror;
+
+ switch (element.getKind()) {
+ case CONSTRUCTOR:
+ case METHOD:
+ typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
+ @Override
+ public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
+ MethodBinding methodBinding = ((MethodBinding) memberBinding);
+ for (MethodBinding method : typeBinding.methods()) {
+ if (CharOperation.equals(method.selector, methodBinding.selector)
+ && (method.original() == methodBinding
+ || method.areParameterErasuresEqual(methodBinding))) {
+ return TypesImpl.this._env.getFactory().newTypeMirror(method);
+ }
+ }
+ return null;
+ }
+ });
+
+ if (typeMirror != null) {
+ return typeMirror;
+ }
+ break;
+ case TYPE_PARAMETER:
+ typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
+ @Override
+ public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
+ if (typeBinding instanceof ParameterizedTypeBinding) {
+ TypeVariableBinding variableBinding = ((TypeVariableBinding) memberBinding);
+ ReferenceBinding binding = ((ParameterizedTypeBinding) typeBinding).genericType();
+ if (variableBinding.declaringElement == binding) { // check in advance avoid looking into type parameters unnecessarily.
+ TypeVariableBinding[] typeVariables = binding.typeVariables();
+ TypeBinding[] typeArguments = ((ParameterizedTypeBinding) typeBinding).typeArguments();
+ if (typeVariables.length == typeArguments.length) {
+ for(int i = 0; i < typeVariables.length; i++) {
+ if (typeVariables[i] == memberBinding) {
+ return TypesImpl.this._env.getFactory().newTypeMirror(typeArguments[i]);
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+ });
+
+ if (typeMirror != null) {
+ return typeMirror;
+ }
+ break;
+ case FIELD:
+ case ENUM_CONSTANT:
+ case RECORD_COMPONENT:
+ typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
+ @Override
+ public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
+ VariableBinding variableBinding = (VariableBinding) memberBinding;
+ for (FieldBinding field : typeBinding.fields()) {
+ if (CharOperation.equals(field.name, variableBinding.name)) {
+ return TypesImpl.this._env.getFactory().newTypeMirror(field);
+ }
+ }
+ return null;
+ }
+ });
+
+ if (typeMirror != null) {
+ return typeMirror;
+ }
+ break;
+ case ENUM:
+ case ANNOTATION_TYPE:
+ case INTERFACE:
+ case CLASS:
+ case RECORD:
+ typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
+ @Override
+ public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
+ ReferenceBinding elementBinding = (ReferenceBinding) memberBinding;
+ // If referenceBinding is a ParameterizedTypeBinding, this
+ // will return only ParameterizedTypeBindings
+ // for member types, even if the member happens to be a
+ // static nested class. That's probably a bug;
+ // static nested classes are not parameterized by their
+ // outer class.
+ for (ReferenceBinding memberReferenceBinding : typeBinding.memberTypes()) {
+ if (CharOperation.equals(elementBinding.compoundName, memberReferenceBinding.compoundName)) {
+ return TypesImpl.this._env.getFactory().newTypeMirror(memberReferenceBinding);
+ }
+ }
+ return null;
+ }
+ });
+
+ if (typeMirror != null) {
+ return typeMirror;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
+ " has unrecognized element kind " + element.getKind()); //$NON-NLS-1$
+ }
+ throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
+ " is not a member of the containing type " + containing + //$NON-NLS-1$
+ " nor any of its superclasses"); //$NON-NLS-1$
+ }
+
+ private static interface MemberInTypeFinder {
+ TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding);
+ }
+
+ private TypeMirror findMemberInHierarchy(ReferenceBinding typeBinding, Binding memberBinding,
+ MemberInTypeFinder finder) {
+ TypeMirror result = null;
+
+ if (typeBinding == null) {
+ return null;
+ }
+
+ result = finder.find(typeBinding, memberBinding);
+ if (result != null) {
+ return result;
+ }
+
+ result = findMemberInHierarchy(typeBinding.superclass(), memberBinding, finder);
+ if (result != null) {
+ return result;
+ }
+
+ for (ReferenceBinding superInterface : typeBinding.superInterfaces()) {
+ result = findMemberInHierarchy(superInterface, memberBinding, finder);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
+ private void validateRealType(TypeMirror t) {
+ switch (t.getKind()) {
+ case EXECUTABLE:
+ case PACKAGE:
+ case MODULE:
+ throw new IllegalArgumentException(
+ "Executable, package and module are illegal argument for Types.contains(..)"); //$NON-NLS-1$
+ default:
+ break;
+ }
+ }
+ private void validateRealTypes(TypeMirror t1, TypeMirror t2) {
+ validateRealType(t1);
+ validateRealType(t2);
+ }
+
+ @Override
+ public TypeElement boxedClass(PrimitiveType p) {
+ PrimitiveTypeImpl primitiveTypeImpl = (PrimitiveTypeImpl) p;
+ BaseTypeBinding baseTypeBinding = (BaseTypeBinding)primitiveTypeImpl._binding;
+ TypeBinding boxed = _env.getLookupEnvironment().computeBoxingType(baseTypeBinding);
+ return (TypeElement) _env.getFactory().newElement(boxed);
+ }
+
+ @Override
+ public TypeMirror capture(TypeMirror t) {
+ validateRealType(t);
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
+ if (typeMirrorImpl._binding instanceof ParameterizedTypeBinding) {
+ throw new UnsupportedOperationException("NYI: TypesImpl.capture(...)"); //$NON-NLS-1$
+ }
+ return t;
+ }
+
+ @Override
+ public boolean contains(TypeMirror t1, TypeMirror t2) {
+ validateRealTypes(t1, t2);
+ throw new UnsupportedOperationException("NYI: TypesImpl.contains(" + t1 + ", " + t2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ @Override
+ public List<? extends TypeMirror> directSupertypes(TypeMirror t) {
+ validateRealType(t);
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
+ Binding binding = typeMirrorImpl._binding;
+ if (binding instanceof ReferenceBinding) {
+ ReferenceBinding referenceBinding = (ReferenceBinding) binding;
+ ArrayList<TypeMirror> list = new ArrayList<>();
+ ReferenceBinding superclass = referenceBinding.superclass();
+ if (superclass != null) {
+ list.add(this._env.getFactory().newTypeMirror(superclass));
+ }
+ for (ReferenceBinding interfaceBinding : referenceBinding.superInterfaces()) {
+ list.add(this._env.getFactory().newTypeMirror(interfaceBinding));
+ }
+ return Collections.unmodifiableList(list);
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public TypeMirror erasure(TypeMirror t) {
+ validateRealType(t);
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
+ Binding binding = typeMirrorImpl._binding;
+ if (binding instanceof ReferenceBinding) {
+ TypeBinding type = ((ReferenceBinding) binding).erasure();
+ if (type.isGenericType()) {
+ type = _env.getLookupEnvironment().convertToRawType(type, false);
+ }
+ return _env.getFactory().newTypeMirror(type);
+ }
+ if (binding instanceof ArrayBinding) {
+ TypeBinding typeBinding = (TypeBinding) binding;
+ TypeBinding leafType = typeBinding.leafComponentType().erasure();
+ if (leafType.isGenericType()) {
+ leafType = _env.getLookupEnvironment().convertToRawType(leafType, false);
+ }
+ return _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createArrayType(leafType,
+ typeBinding.dimensions()));
+ }
+ return t;
+ }
+
+ @Override
+ public ArrayType getArrayType(TypeMirror componentType) {
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) componentType;
+ TypeBinding typeBinding = (TypeBinding) typeMirrorImpl._binding;
+ return (ArrayType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createArrayType(
+ typeBinding.leafComponentType(),
+ typeBinding.dimensions() + 1));
+ }
+
+ /*
+ * (non-Javadoc)
+ * Create a type instance by parameterizing a type element. If the element is a member type,
+ * its container won't be parameterized (if it needs to be, you would need to use the form of
+ * getDeclaredType that takes a container TypeMirror). If typeArgs is empty, and typeElem
+ * is not generic, then you should use TypeElem.asType(). If typeArgs is empty and typeElem
+ * is generic, this method will create the raw type.
+ */
+ @Override
+ public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
+ int typeArgsLength = typeArgs.length;
+ TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem;
+ ReferenceBinding elementBinding = (ReferenceBinding) typeElementImpl._binding;
+ TypeVariableBinding[] typeVariables = elementBinding.typeVariables();
+ int typeVariablesLength = typeVariables.length;
+ if (typeArgsLength == 0) {
+ if (elementBinding.isGenericType()) {
+ // per javadoc,
+ return (DeclaredType) _env.getFactory().newTypeMirror(this._env.getLookupEnvironment().createRawType(elementBinding, null));
+ }
+ return (DeclaredType)typeElem.asType();
+ } else if (typeArgsLength != typeVariablesLength) {
+ throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$
+ }
+ TypeBinding[] typeArguments = new TypeBinding[typeArgsLength];
+ for (int i = 0; i < typeArgsLength; i++) {
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i];
+ Binding binding = typeMirrorImpl._binding;
+ if (!(binding instanceof TypeBinding)) {
+ throw new IllegalArgumentException("Invalid type argument: " + typeMirrorImpl); //$NON-NLS-1$
+ }
+ typeArguments[i] = (TypeBinding) binding;
+ }
+
+ ReferenceBinding enclosing = elementBinding.enclosingType();
+ if (enclosing != null) {
+ enclosing = this._env.getLookupEnvironment().createRawType(enclosing, null);
+ }
+
+ return (DeclaredType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createParameterizedType(elementBinding, typeArguments, enclosing));
+ }
+
+ /* (non-Javadoc)
+ * Create a specific type from a member element. The containing type can be parameterized,
+ * e.g. Outer<String>.Inner, but it cannot be generic, i.e., Outer<T>.Inner. It only makes
+ * sense to use this method when the member element is parameterized by its container; so,
+ * for example, it makes sense for an inner class but not for a static member class.
+ * Otherwise you should just use getDeclaredType(TypeElement, TypeMirror ...), if you need
+ * to specify type arguments, or TypeElement.asType() directly, if not.
+ */
+ @Override
+ public DeclaredType getDeclaredType(DeclaredType containing, TypeElement typeElem,
+ TypeMirror... typeArgs) {
+ int typeArgsLength = typeArgs.length;
+ TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem;
+ ReferenceBinding elementBinding = (ReferenceBinding) typeElementImpl._binding;
+ TypeVariableBinding[] typeVariables = elementBinding.typeVariables();
+ int typeVariablesLength = typeVariables.length;
+ DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
+ ReferenceBinding enclosingType = (ReferenceBinding) declaredTypeImpl._binding;
+ if (typeArgsLength == 0) {
+ if (elementBinding.isGenericType()) {
+ // e.g., Outer.Inner<T> but T is not specified
+ // Per javadoc on interface, must return the raw type Outer.Inner
+ return (DeclaredType) _env.getFactory().newTypeMirror(
+ _env.getLookupEnvironment().createRawType(elementBinding, enclosingType));
+ } else {
+ // e.g., Outer<Long>.Inner
+ ParameterizedTypeBinding ptb = _env.getLookupEnvironment().createParameterizedType(elementBinding, null, enclosingType);
+ return (DeclaredType) _env.getFactory().newTypeMirror(ptb);
+ }
+ } else if (typeArgsLength != typeVariablesLength) {
+ throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$
+ }
+ TypeBinding[] typeArguments = new TypeBinding[typeArgsLength];
+ for (int i = 0; i < typeArgsLength; i++) {
+ TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i];
+ Binding binding = typeMirrorImpl._binding;
+ if (!(binding instanceof TypeBinding)) {
+ throw new IllegalArgumentException("Invalid type for a type arguments : " + typeMirrorImpl); //$NON-NLS-1$
+ }
+ typeArguments[i] = (TypeBinding) binding;
+ }
+ return (DeclaredType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createParameterizedType(elementBinding, typeArguments, enclosingType));
+ }
+
+ @Override
+ public NoType getNoType(TypeKind kind) {
+ return _env.getFactory().getNoType(kind);
+ }
+
+ @Override
+ public NullType getNullType() {
+ return _env.getFactory().getNullType();
+ }
+
+ @Override
+ public PrimitiveType getPrimitiveType(TypeKind kind) {
+ return _env.getFactory().getPrimitiveType(kind);
+ }
+
+ @Override
+ public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) {
+ if (extendsBound != null && superBound != null) {
+ throw new IllegalArgumentException("Extends and super bounds cannot be set at the same time"); //$NON-NLS-1$
+ }
+ if (extendsBound != null) {
+ TypeMirrorImpl extendsBoundMirrorType = (TypeMirrorImpl) extendsBound;
+ TypeBinding typeBinding = (TypeBinding) extendsBoundMirrorType._binding;
+ return (WildcardType) _env.getFactory().newTypeMirror(
+ this._env.getLookupEnvironment().createWildcard(
+ null,
+ 0,
+ typeBinding,
+ null,
+ Wildcard.EXTENDS));
+ }
+ if (superBound != null) {
+ TypeMirrorImpl superBoundMirrorType = (TypeMirrorImpl) superBound;
+ TypeBinding typeBinding = (TypeBinding) superBoundMirrorType._binding;
+ return new WildcardTypeImpl(_env, this._env.getLookupEnvironment().createWildcard(
+ null,
+ 0,
+ typeBinding,
+ null,
+ Wildcard.SUPER));
+ }
+ return new WildcardTypeImpl(_env, this._env.getLookupEnvironment().createWildcard(
+ null,
+ 0,
+ null,
+ null,
+ Wildcard.UNBOUND));
+ }
+
+ /* (non-Javadoc)
+ * @return true if a value of type t1 can be assigned to a variable of type t2, i.e., t2 = t1.
+ */
+ @Override
+ public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
+ validateRealTypes(t1, t2);
+ if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
+ return false;
+ }
+ Binding b1 = ((TypeMirrorImpl)t1).binding();
+ Binding b2 = ((TypeMirrorImpl)t2).binding();
+ if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
+ // package, method, import, etc.
+ throw new IllegalArgumentException();
+ }
+ if (((TypeBinding)b1).isCompatibleWith((TypeBinding)b2)) {
+ return true;
+ }
+
+ TypeBinding convertedType = _env.getLookupEnvironment().computeBoxingType((TypeBinding)b1);
+ return null != convertedType && convertedType.isCompatibleWith((TypeBinding)b2);
+ }
+
+ @Override
+ public boolean isSameType(TypeMirror t1, TypeMirror t2) {
+ if (t1 instanceof NoTypeImpl) {
+ if (t2 instanceof NoTypeImpl) {
+ return ((NoTypeImpl) t1).getKind() == ((NoTypeImpl) t2).getKind();
+ }
+ return false;
+ } else if (t2 instanceof NoTypeImpl) {
+ return false;
+ }
+ if (t1.getKind() == TypeKind.WILDCARD || t2.getKind() == TypeKind.WILDCARD) {
+ // Wildcard types are never equal, according to the spec of this method
+ return false;
+ }
+ if (t1 == t2) {
+ return true;
+ }
+ if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
+ return false;
+ }
+ Binding b1 = ((TypeMirrorImpl)t1).binding();
+ Binding b2 = ((TypeMirrorImpl)t2).binding();
+
+ if (b1 == b2) {
+ return true;
+ }
+ if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
+ return false;
+ }
+ TypeBinding type1 = ((TypeBinding) b1);
+ TypeBinding type2 = ((TypeBinding) b2);
+ if (TypeBinding.equalsEquals(type1, type2))
+ return true;
+ return CharOperation.equals(type1.computeUniqueKey(), type2.computeUniqueKey());
+ }
+
+ @Override
+ public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
+ MethodBinding methodBinding1 = (MethodBinding) ((ExecutableTypeImpl) m1)._binding;
+ MethodBinding methodBinding2 = (MethodBinding) ((ExecutableTypeImpl) m2)._binding;
+ if (!CharOperation.equals(methodBinding1.selector, methodBinding2.selector))
+ return false;
+ return methodBinding1.areParameterErasuresEqual(methodBinding2) && methodBinding1.areTypeVariableErasuresEqual(methodBinding2);
+ }
+
+ /* (non-Javadoc)
+ * @return true if t1 is a subtype of t2, or if t1 == t2.
+ */
+ @Override
+ public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
+ validateRealTypes(t1, t2);
+ if (t1 instanceof NoTypeImpl) {
+ if (t2 instanceof NoTypeImpl) {
+ return ((NoTypeImpl) t1).getKind() == ((NoTypeImpl) t2).getKind();
+ }
+ return false;
+ } else if (t2 instanceof NoTypeImpl) {
+ return false;
+ }
+ if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
+ throw new IllegalArgumentException();
+ }
+ if (t1 == t2) {
+ return true;
+ }
+ Binding b1 = ((TypeMirrorImpl)t1).binding();
+ Binding b2 = ((TypeMirrorImpl)t2).binding();
+ if (b1 == b2) {
+ return true;
+ }
+ if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
+ // package, method, import, etc.
+ throw new IllegalArgumentException();
+ }
+ if (b1.kind() == Binding.BASE_TYPE || b2.kind() == Binding.BASE_TYPE) {
+ if (b1.kind() != b2.kind()) {
+ return false;
+ }
+ else {
+ // for primitives, compatibility implies subtype
+ return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2);
+ }
+ }
+ return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2);
+ }
+
+ @Override
+ public PrimitiveType unboxedType(TypeMirror t) {
+ if (!(((TypeMirrorImpl)t)._binding instanceof ReferenceBinding)) {
+ // Not an unboxable type - could be primitive, array, not a type at all, etc.
+ throw new IllegalArgumentException("Given type mirror cannot be unboxed"); //$NON-NLS-1$
+ }
+ ReferenceBinding boxed = (ReferenceBinding)((TypeMirrorImpl)t)._binding;
+ TypeBinding unboxed = _env.getLookupEnvironment().computeBoxingType(boxed);
+ if (unboxed.kind() != Binding.BASE_TYPE) {
+ // No boxing conversion was found
+ throw new IllegalArgumentException();
+ }
+ return (PrimitiveType) _env.getFactory().newTypeMirror((BaseTypeBinding)unboxed);
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java
new file mode 100644
index 0000000..9a4c8c2
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.VariableElement;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptBinaryLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
+import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
+
+/**
+ * Implementation of VariableElement, which represents a a field, enum constant,
+ * method or constructor parameter, local variable, or exception parameter.
+ */
+public class VariableElementImpl extends ElementImpl implements VariableElement {
+
+ /**
+ * @param binding might be a FieldBinding (for a field) or a LocalVariableBinding (for a method param)
+ */
+ VariableElementImpl(BaseProcessingEnvImpl env, VariableBinding binding) {
+ super(env, binding);
+ }
+
+ @Override
+ public <R, P> R accept(ElementVisitor<R, P> v, P p)
+ {
+ return v.visitVariable(this, p);
+ }
+
+ @Override
+ protected AnnotationBinding[] getAnnotationBindings()
+ {
+ return ((VariableBinding)_binding).getAnnotations();
+ }
+
+ @Override
+ public Object getConstantValue() {
+ VariableBinding variableBinding = (VariableBinding) _binding;
+ Constant constant = variableBinding.constant();
+ if (constant == null || constant == Constant.NotAConstant) return null;
+ TypeBinding type = variableBinding.type;
+ switch (type.id) {
+ case TypeIds.T_boolean:
+ return constant.booleanValue();
+ case TypeIds.T_byte:
+ return constant.byteValue();
+ case TypeIds.T_char:
+ return constant.charValue();
+ case TypeIds.T_double:
+ return constant.doubleValue();
+ case TypeIds.T_float:
+ return constant.floatValue();
+ case TypeIds.T_int:
+ return constant.intValue();
+ case TypeIds.T_JavaLangString:
+ return constant.stringValue();
+ case TypeIds.T_long:
+ return constant.longValue();
+ case TypeIds.T_short:
+ return constant.shortValue();
+ }
+ return null;
+ }
+
+ @Override
+ public List<? extends Element> getEnclosedElements() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Element getEnclosingElement() {
+ if (_binding instanceof FieldBinding) {
+ return _env.getFactory().newElement(((FieldBinding)_binding).declaringClass);
+ }
+ else if (_binding instanceof AptSourceLocalVariableBinding){
+ return _env.getFactory().newElement(((AptSourceLocalVariableBinding) _binding).methodBinding);
+ } else if (_binding instanceof AptBinaryLocalVariableBinding) {
+ return _env.getFactory().newElement(((AptBinaryLocalVariableBinding) _binding).methodBinding);
+ } else if (_binding instanceof RecordComponentBinding) {
+ return _env.getFactory().newElement(((RecordComponentBinding)_binding).declaringRecord);
+ }
+ return null;
+ }
+
+ @Override
+ public ElementKind getKind() {
+ if (_binding instanceof FieldBinding) {
+ if ((((FieldBinding) _binding).modifiers & ClassFileConstants.AccEnum) != 0) {
+ return ElementKind.ENUM_CONSTANT;
+ }
+ else {
+ return ElementKind.FIELD;
+ }
+ }
+ else {
+ return ElementKind.PARAMETER;
+ }
+ }
+
+ @Override
+ public Set<Modifier> getModifiers()
+ {
+ if (_binding instanceof VariableBinding) {
+ return Factory.getModifiers(((VariableBinding)_binding).modifiers, getKind());
+ }
+ return Collections.emptySet();
+ }
+
+ @Override
+ PackageElement getPackage()
+ {
+ if (_binding instanceof FieldBinding) {
+ PackageBinding pkgBinding = ((FieldBinding)_binding).declaringClass.fPackage;
+ return _env.getFactory().newPackageElement(pkgBinding);
+ }
+ else {
+ // TODO: what is the package of a method parameter?
+ throw new UnsupportedOperationException("NYI: VariableElmentImpl.getPackage() for method parameter"); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Name getSimpleName() {
+ return new NameImpl(((VariableBinding)_binding).name);
+ }
+
+ @Override
+ public boolean hides(Element hiddenElement)
+ {
+ if (_binding instanceof FieldBinding) {
+ if (!(((ElementImpl)hiddenElement)._binding instanceof FieldBinding)) {
+ return false;
+ }
+ FieldBinding hidden = (FieldBinding)((ElementImpl)hiddenElement)._binding;
+ if (hidden.isPrivate()) {
+ return false;
+ }
+ FieldBinding hider = (FieldBinding)_binding;
+ if (hidden == hider) {
+ return false;
+ }
+ if (!CharOperation.equals(hider.name, hidden.name)) {
+ return false;
+ }
+ return null != hider.declaringClass.findSuperTypeOriginatingFrom(hidden.declaringClass);
+ }
+ // TODO: should we implement hides() for method parameters?
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return new String(((VariableBinding) _binding).name);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final VariableElementImpl other = (VariableElementImpl) obj;
+ return Objects.equals(this._binding, other._binding);
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java
new file mode 100644
index 0000000..9c97895
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2011 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.type.WildcardType;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
+
+/**
+ * Implementation of the WildcardType
+ */
+public class WildcardTypeImpl extends TypeMirrorImpl implements WildcardType {
+
+ WildcardTypeImpl(BaseProcessingEnvImpl env, WildcardBinding binding) {
+ super(env, binding);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.WildcardType#getExtendsBound()
+ */
+ @Override
+ public TypeMirror getExtendsBound() {
+ WildcardBinding wildcardBinding = (WildcardBinding) this._binding;
+ if (wildcardBinding.boundKind != Wildcard.EXTENDS) return null;
+ TypeBinding bound = wildcardBinding.bound;
+ if (bound == null) return null;
+ return _env.getFactory().newTypeMirror(bound);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.TypeMirror#getKind()
+ */
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.WILDCARD;
+ }
+ /* (non-Javadoc)
+ * @see javax.lang.model.type.WildcardType#getSuperBound()
+ */
+ @Override
+ public TypeMirror getSuperBound() {
+ WildcardBinding wildcardBinding = (WildcardBinding) this._binding;
+ if (wildcardBinding.boundKind != Wildcard.SUPER) return null;
+ TypeBinding bound = wildcardBinding.bound;
+ if (bound == null) return null;
+ return _env.getFactory().newTypeMirror(bound);
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return v.visitWildcard(this, p);
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java
new file mode 100644
index 0000000..049964c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2017 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+import org.eclipse.jdt.internal.compiler.util.JRTUtil;
+
+/**
+ * Used as a zip file cache.
+ */
+public class Archive implements Closeable {
+
+ public static final Archive UNKNOWN_ARCHIVE = new Archive();
+
+ ZipFile zipFile;
+ File file;
+
+ protected Hashtable<String, ArrayList<String[]>> packagesCache;
+
+ protected Archive() {
+ // used to construct UNKNOWN_ARCHIVE
+ }
+
+ public Archive(File file) throws ZipException, IOException {
+ this.file = file;
+ this.zipFile = new ZipFile(file);
+ initialize();
+ }
+
+ private void initialize() {
+ // initialize packages
+ this.packagesCache = new Hashtable<>();
+ nextEntry : for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) {
+ String fileName = ((ZipEntry) e.nextElement()).getName();
+
+ // add the package name & all of its parent packages
+ int last = fileName.lastIndexOf('/');
+ // extract the package name
+ String packageName = fileName.substring(0, last + 1);
+ String typeName = fileName.substring(last + 1);
+ ArrayList<String[]> types = this.packagesCache.get(packageName);
+ if (types == null) {
+ // might be empty if this is a directory entry
+ if (typeName.length() == 0) {
+ continue nextEntry;
+ }
+ types = new ArrayList<>();
+ types.add(new String[]{typeName, null});
+ this.packagesCache.put(packageName, types);
+ } else {
+ types.add(new String[]{typeName, null});
+ }
+ }
+ }
+
+ public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) {
+ return new ArchiveFileObject(this.file, fileName, charset);
+ }
+
+ public boolean contains(String entryName) {
+ return this.zipFile.getEntry(entryName) != null;
+ }
+
+ public Set<String> allPackages() {
+ if (this.packagesCache == null) {
+ this.initialize();
+ }
+ return this.packagesCache.keySet();
+ }
+
+ /**
+ * Returns an array of String - the array contains exactly two elements. The first element
+ * is the name of the type and the second being the module that contains the type. For a regular
+ * Jar archive, the module element will be null. This is applicable only to Jimage files
+ * where types are contained by multiple modules.
+ */
+ public List<String[]> getTypes(String packageName) {
+ // package name is expected to ends with '/'
+ if (this.packagesCache == null) {
+ try {
+ this.zipFile = new ZipFile(this.file);
+ } catch(IOException e) {
+ String error = "Failed to read types from archive " + this.file; //$NON-NLS-1$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ return Collections.<String[]>emptyList();
+ }
+ this.initialize();
+ }
+ return this.packagesCache.get(packageName);
+ }
+
+ public void flush() {
+ this.packagesCache = null;
+ }
+
+ @Override
+ public void close() {
+ this.packagesCache = null;
+ try {
+ if (this.zipFile != null) {
+ this.zipFile.close();
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Archive: " + (this.file == null ? "UNKNOWN_ARCHIVE" : this.file.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java
new file mode 100644
index 0000000..c301c9d
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java
@@ -0,0 +1,262 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2021 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.util.JRTUtil;
+
+/**
+ * Implementation of a Java file object that corresponds to an entry in a zip/jar file
+ */
+public class ArchiveFileObject implements JavaFileObject {
+ protected String entryName;
+ protected File file;
+ protected Charset charset;
+
+ public ArchiveFileObject(File file, String entryName, Charset charset) {
+ this.entryName = entryName;
+ this.file = file;
+ this.charset = charset;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getAccessLevel()
+ */
+ @Override
+ public Modifier getAccessLevel() {
+ // cannot express multiple modifier
+ if (getKind() != Kind.CLASS) {
+ return null;
+ }
+ ClassFileReader reader = getClassReader();
+
+ if (reader == null) {
+ return null;
+ }
+ final int accessFlags = reader.accessFlags();
+ if ((accessFlags & ClassFileConstants.AccPublic) != 0) {
+ return Modifier.PUBLIC;
+ }
+ if ((accessFlags & ClassFileConstants.AccAbstract) != 0) {
+ return Modifier.ABSTRACT;
+ }
+ if ((accessFlags & ClassFileConstants.AccFinal) != 0) {
+ return Modifier.FINAL;
+ }
+ return null;
+ }
+
+ protected ClassFileReader getClassReader() {
+ ClassFileReader reader = null;
+ try {
+ try (ZipFile zip = new ZipFile(this.file)) {
+ reader = ClassFileReader.read(zip, this.entryName);
+ }
+ } catch (ClassFormatException e) {
+ // ignore
+ } catch (IOException e) {
+ String error = "Failed to read entry " + this.entryName + " from archive " + this.file; //$NON-NLS-1$ //$NON-NLS-2$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ }
+ return reader;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getKind()
+ */
+ @Override
+ public Kind getKind() {
+ String name = this.entryName.toLowerCase();
+ if (name.endsWith(Kind.CLASS.extension)) {
+ return Kind.CLASS;
+ } else if (name.endsWith(Kind.SOURCE.extension)) {
+ return Kind.SOURCE;
+ } else if (name.endsWith(Kind.HTML.extension)) {
+ return Kind.HTML;
+ }
+ return Kind.OTHER;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getNestingKind()
+ */
+ @Override
+ public NestingKind getNestingKind() {
+ switch(getKind()) {
+ case SOURCE :
+ return NestingKind.TOP_LEVEL;
+ case CLASS :
+ ClassFileReader reader = getClassReader();
+ if (reader == null) {
+ return null;
+ }
+ if (reader.isAnonymous()) {
+ return NestingKind.ANONYMOUS;
+ }
+ if (reader.isLocal()) {
+ return NestingKind.LOCAL;
+ }
+ if (reader.isMember()) {
+ return NestingKind.MEMBER;
+ }
+ return NestingKind.TOP_LEVEL;
+ default:
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#isNameCompatible(java.lang.String, javax.tools.JavaFileObject.Kind)
+ */
+ @Override
+ public boolean isNameCompatible(String simpleName, Kind kind) {
+ return this.entryName.endsWith(simpleName + kind.extension);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#delete()
+ */
+ @Override
+ public boolean delete() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ArchiveFileObject)) {
+ return false;
+ }
+ ArchiveFileObject archiveFileObject = (ArchiveFileObject) o;
+ return archiveFileObject.toUri().equals(this.toUri());
+ }
+
+ @Override
+ public int hashCode() {
+ return this.toUri().hashCode();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getCharContent(boolean)
+ */
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ if (getKind() == Kind.SOURCE) {
+ try (ZipFile zipFile2 = new ZipFile(this.file)) {
+ ZipEntry zipEntry = zipFile2.getEntry(this.entryName);
+ return Util.getCharContents(this, ignoreEncodingErrors, org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(zipEntry, zipFile2), this.charset.name());
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getLastModified()
+ */
+ @Override
+ public long getLastModified() {
+ try (ZipFile zip = new ZipFile(this.file)) {
+ ZipEntry zipEntry = zip.getEntry(this.entryName);
+ return zipEntry.getTime(); // looks the closest from the last modification
+ } catch(IOException e) {
+ // ignore
+ }
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getName()
+ */
+ @Override
+ public String getName() {
+ return this.entryName;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openInputStream()
+ */
+ @Override
+ public InputStream openInputStream() throws IOException {
+ try (ZipFile zipFile = new ZipFile(this.file);
+ InputStream inputStream = zipFile.getInputStream(zipFile.getEntry(this.entryName));) {
+ ByteArrayInputStream buffer = new ByteArrayInputStream(inputStream.readAllBytes());
+ return buffer;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openOutputStream()
+ */
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openReader(boolean)
+ */
+ @Override
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openWriter()
+ */
+ @Override
+ public Writer openWriter() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#toUri()
+ */
+ @Override
+ public URI toUri() {
+ try {
+ return new URI("jar:" + this.file.toURI().getPath() + "!" + this.entryName); //$NON-NLS-1$//$NON-NLS-2$
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ return this.file.getAbsolutePath() + "[" + this.entryName + "]";//$NON-NLS-1$//$NON-NLS-2$
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
new file mode 100644
index 0000000..b63a09f
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
@@ -0,0 +1,1615 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2022 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.lang.model.SourceVersion;
+import javax.tools.FileObject;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.apt.util.JrtFileSystem.JrtFileObject;
+import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.LocationContainer;
+import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.LocationWrapper;
+import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.ModuleLocationWrapper;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem;
+import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
+import org.eclipse.jdt.internal.compiler.batch.Main;
+import org.eclipse.jdt.internal.compiler.batch.Main.ResourceBundleFactory;
+import org.eclipse.jdt.internal.compiler.batch.ModuleFinder;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
+import org.eclipse.jdt.internal.compiler.env.AccessRule;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+import org.eclipse.jdt.internal.compiler.util.JRTUtil;
+import org.eclipse.jdt.internal.compiler.util.Util;
+
+/**
+ * Implementation of the Standard Java File Manager
+ */
+public class EclipseFileManager implements StandardJavaFileManager {
+ private static final String NO_EXTENSION = "";//$NON-NLS-1$
+ static final int HAS_EXT_DIRS = 1;
+ static final int HAS_BOOTCLASSPATH = 2;
+ static final int HAS_ENDORSED_DIRS = 4;
+ static final int HAS_PROCESSORPATH = 8;
+ static final int HAS_PROC_MODULEPATH = 16;
+
+ Map<File, Archive> archivesCache;
+ Charset charset;
+ Locale locale;
+ ModuleLocationHandler locationHandler;
+ final Map<Location, URLClassLoader> classloaders;
+ int flags;
+ boolean isOnJvm9;
+ File jrtHome;
+ JrtFileSystem jrtSystem;
+ public ResourceBundle bundle;
+ String releaseVersion;
+
+ public EclipseFileManager(Locale locale, Charset charset) {
+ this.locale = locale == null ? Locale.getDefault() : locale;
+ this.charset = charset == null ? Charset.defaultCharset() : charset;
+ this.locationHandler = new ModuleLocationHandler();
+ this.classloaders = new HashMap<>();
+ this.archivesCache = new HashMap<>();
+ this.isOnJvm9 = isRunningJvm9();
+ try {
+ initialize(Util.getJavaHome());
+ } catch (IOException e) {
+ String error = "Failed to init EclipseFileManager from " + Util.getJavaHome(); //$NON-NLS-1$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ }
+ try {
+ this.bundle = ResourceBundleFactory.getBundle(this.locale);
+ } catch(MissingResourceException e) {
+ System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
+ protected void initialize(File javahome) throws IOException {
+ if (this.isOnJvm9) {
+ this.jrtSystem = new JrtFileSystem(javahome);
+ try (Archive previous = this.archivesCache.put(javahome, this.jrtSystem)) {
+ // nothing. Only theoretically autoclose the previous instance - which does not exist at this time
+ }
+ this.jrtHome = javahome;
+ this.locationHandler.newSystemLocation(StandardLocation.SYSTEM_MODULES, this.jrtSystem);
+ } else {
+ this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath());
+ }
+ Iterable<? extends File> defaultClasspath = getDefaultClasspath();
+ this.setLocation(StandardLocation.CLASS_PATH, defaultClasspath);
+ // No annotation module path by default
+ this.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, defaultClasspath);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#close()
+ */
+ @Override
+ public void close() throws IOException {
+ this.locationHandler.close();
+ for (Archive archive : this.archivesCache.values()) {
+ if (archive != null) {
+ archive.close();
+ }
+ }
+ this.archivesCache.clear();
+ for (URLClassLoader cl : this.classloaders.values()) {
+ cl.close();
+ }
+ this.classloaders.clear();
+ }
+
+ private void collectAllMatchingFiles(Location location, File file, String normalizedPackageName, Set<Kind> kinds, boolean recurse, ArrayList<JavaFileObject> collector) {
+ if (file.equals(this.jrtHome)) {
+ if (location instanceof ModuleLocationWrapper) {
+ List<JrtFileObject> list = this.jrtSystem.list((ModuleLocationWrapper) location, normalizedPackageName, kinds, recurse, this.charset);
+ for (JrtFileObject fo : list) {
+ Kind kind = getKind(getExtension(fo.entryName));
+ if (kinds.contains(kind)) {
+ collector.add(fo);
+ }
+ }
+ }
+ } else if (isArchive(file)) {
+ @SuppressWarnings("resource") // cached archive is closed in EclipseFileManager.close()
+ Archive archive = this.getArchive(file);
+ if (archive != Archive.UNKNOWN_ARCHIVE) {
+ String key = normalizedPackageName;
+ if (!normalizedPackageName.endsWith("/")) {//$NON-NLS-1$
+ key += '/';
+ }
+ // we have an archive file
+ if (recurse) {
+ for (String packageName : archive.allPackages()) {
+ if (packageName.startsWith(key)) {
+ List<String[]> types = archive.getTypes(packageName);
+ if (types != null) {
+ for (String[] entry : types) {
+ final Kind kind = getKind(getExtension(entry[0]));
+ if (kinds.contains(kind)) {
+ collector.add(archive.getArchiveFileObject(packageName + entry[0], entry[1],
+ this.charset));
+ }
+ }
+ }
+ }
+ }
+ } else {
+ List<String[]> types = archive.getTypes(key);
+ if (types != null) {
+ for (String[] entry : types) {
+ final Kind kind = getKind(getExtension(entry[0]));
+ if (kinds.contains(kind)) {
+ collector.add(archive.getArchiveFileObject(key + entry[0], entry[1], this.charset));
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // we must have a directory
+ File currentFile = new File(file, normalizedPackageName);
+ if (!currentFile.exists()) return;
+ String path;
+ try {
+ path = currentFile.getCanonicalPath();
+ } catch (IOException e) {
+ return;
+ }
+ if (File.separatorChar == '/') {
+ if (!path.endsWith(normalizedPackageName)) return;
+ } else if (!path.endsWith(normalizedPackageName.replace('/', File.separatorChar))) return;
+ File[] files = currentFile.listFiles();
+ if (files != null) {
+ // this was a directory
+ for (File f : files) {
+ if (f.isDirectory() && recurse) {
+ collectAllMatchingFiles(location, file, normalizedPackageName + '/' + f.getName(), kinds, recurse, collector);
+ } else {
+ final Kind kind = getKind(f);
+ if (kinds.contains(kind)) {
+ collector.add(new EclipseFileObject(normalizedPackageName + f.getName(), f.toURI(), kind, this.charset));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private Iterable<? extends File> concatFiles(Iterable<? extends File> iterable, Iterable<? extends File> iterable2) {
+ ArrayList<File> list = new ArrayList<>();
+ if (iterable2 == null) return iterable;
+ for (Iterator<? extends File> iterator = iterable.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ for (Iterator<? extends File> iterator = iterable2.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ return list;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#flush()
+ */
+ @Override
+ public void flush() throws IOException {
+ for (Archive archive : this.archivesCache.values()) {
+ if (archive != null) {
+ archive.flush();
+ }
+ }
+ }
+
+ JrtFileSystem getJrtFileSystem(File f){
+ return (JrtFileSystem) getArchive(f);
+ }
+
+ private Archive getArchive(File f) {
+ // check the archive (jar/zip) cache
+ Archive existing = this.archivesCache.get(f);
+ if (existing != null) {
+ return existing;
+ }
+ Archive archive = Archive.UNKNOWN_ARCHIVE;
+ // create a new archive
+ if (f.exists()) {
+ try {
+ if (isJrt(f)) {
+ archive = new JrtFileSystem(f);
+ } else {
+ archive = new Archive(f);
+ }
+ } catch (IOException e) {
+ String error = "Failed to create archive from " + f; //$NON-NLS-1$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ }
+ }
+ try (Archive previous = this.archivesCache.put(f, archive)) {
+ // Nothing but closing previous instance - which should not exist at this time
+ }
+ return archive;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getClassLoader(javax.tools.JavaFileManager.Location)
+ */
+ @Override
+ public ClassLoader getClassLoader(Location location) {
+ validateNonModuleLocation(location);
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ // location is unknown
+ return null;
+ }
+ URLClassLoader cl = this.classloaders.get(location);
+ if (cl == null) {
+ ArrayList<URL> allURLs = new ArrayList<>();
+ for (File f : files) {
+ try {
+ allURLs.add(f.toURI().toURL());
+ } catch (MalformedURLException e) {
+ // the url is malformed - this should not happen
+ throw new RuntimeException(e);
+ }
+ }
+ URL[] result = new URL[allURLs.size()];
+ cl = new URLClassLoader(allURLs.toArray(result), getClass().getClassLoader());
+ try (URLClassLoader previous = this.classloaders.put(location, cl)) {
+ // Nothing but closing previous instance - which should not exist at this time
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ return cl;
+ }
+
+ private Iterable<? extends File> getPathsFrom(String path) {
+ ArrayList<FileSystem.Classpath> paths = new ArrayList<>();
+ ArrayList<File> files = new ArrayList<>();
+ try {
+ this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ for (FileSystem.Classpath classpath : paths) {
+ files.add(new File(classpath.getPath()));
+ }
+ return files;
+ }
+
+ Iterable<? extends File> getDefaultBootclasspath() {
+ List<File> files = new ArrayList<>();
+ String javaversion = System.getProperty("java.version");//$NON-NLS-1$
+ if(javaversion.length() > 3)
+ javaversion = javaversion.substring(0, 3);
+ long jdkLevel = CompilerOptions.versionToJdkLevel(javaversion);
+ if (jdkLevel < ClassFileConstants.JDK1_6) {
+ // wrong jdk - 1.6 or above is required
+ return null;
+ }
+
+ for (FileSystem.Classpath classpath : org.eclipse.jdt.internal.compiler.util.Util.collectFilesNames()) {
+ files.add(new File(classpath.getPath()));
+ }
+ return files;
+ }
+
+ Iterable<? extends File> getDefaultClasspath() {
+ // default classpath
+ ArrayList<File> files = new ArrayList<>();
+ String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$
+ if ((classProp == null) || (classProp.length() == 0)) {
+ return null;
+ } else {
+ StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
+ String token;
+ while (tokenizer.hasMoreTokens()) {
+ token = tokenizer.nextToken();
+ File file = new File(token);
+ if (file.exists()) {
+ files.add(file);
+ }
+ }
+ }
+ return files;
+ }
+
+ private Iterable<? extends File> getEndorsedDirsFrom(String path) {
+ ArrayList<FileSystem.Classpath> paths = new ArrayList<>();
+ ArrayList<File> files = new ArrayList<>();
+ try {
+ this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ for (FileSystem.Classpath classpath : paths) {
+ files.add(new File(classpath.getPath()));
+ }
+ return files;
+ }
+
+ private Iterable<? extends File> getExtdirsFrom(String path) {
+ ArrayList<FileSystem.Classpath> paths = new ArrayList<>();
+ ArrayList<File> files = new ArrayList<>();
+ try {
+ this.processPathEntries(Main.DEFAULT_SIZE_CLASSPATH, paths, path, this.charset.name(), false, false);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ for (FileSystem.Classpath classpath : paths) {
+ files.add(new File(classpath.getPath()));
+ }
+ return files;
+ }
+
+ private String getExtension(File file) {
+ String name = file.getName();
+ return getExtension(name);
+ }
+ private String getExtension(String name) {
+ int index = name.lastIndexOf('.');
+ if (index == -1) {
+ return EclipseFileManager.NO_EXTENSION;
+ }
+ return name.substring(index);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String)
+ */
+ @Override
+ public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
+ validateNonModuleLocation(location);
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+ String normalizedFileName = normalizedFileName(packageName, relativeName);
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // handle directory
+ File f = new File(file, normalizedFileName);
+ if (f.exists()) {
+ return new EclipseFileObject(packageName + File.separator + relativeName, f.toURI(), getKind(f), this.charset);
+ } else {
+ continue; // go to next entry in the location
+ }
+ } else if (isArchive(file)) {
+ // handle archive file
+ ArchiveFileObject fileObject = getFileObject(file, normalizedFileName);
+ if (fileObject!=null) {
+ return fileObject;
+ }
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("resource") // cached archive is closed in EclipseFileManager.close()
+ private ArchiveFileObject getFileObject(File archiveFile, String normalizedFileName) {
+ Archive archive = getArchive(archiveFile);
+ if (archive == Archive.UNKNOWN_ARCHIVE) {
+ return null;
+ }
+ if (archive.contains(normalizedFileName)) {
+ return archive.getArchiveFileObject(normalizedFileName, null, this.charset);
+ }
+ return null;
+ }
+
+ @SuppressWarnings("resource") // cached archive is closed in EclipseFileManager.close()
+ private Boolean containsFileObject(File archiveFile, String normalizedFileName) {
+ Archive archive = getArchive(archiveFile);
+ if (archive == Archive.UNKNOWN_ARCHIVE) {
+ return null;
+ }
+ return archive.contains(normalizedFileName);
+ }
+
+
+ private String normalizedFileName(String packageName, String relativeName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(normalized(packageName));
+ if (sb.length() > 0) {
+ sb.append('/');
+ }
+ sb.append(relativeName.replace('\\', '/'));
+ return sb.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String, javax.tools.FileObject)
+ */
+ @Override
+ public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling)
+ throws IOException {
+ validateOutputLocation(location);
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+ final Iterator<? extends File> iterator = files.iterator();
+ if (iterator.hasNext()) {
+ File file = iterator.next();
+ String normalizedFileName = normalized(packageName) + '/' + relativeName.replace('\\', '/');
+ File f = new File(file, normalizedFileName);
+ return new EclipseFileObject(packageName + File.separator + relativeName, f.toURI(), getKind(f), this.charset);
+ } else {
+ throw new IllegalArgumentException("location is empty : " + location);//$NON-NLS-1$
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getJavaFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind)
+ */
+ @Override
+ public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException {
+ validateNonModuleLocation(location);
+ if (kind != Kind.CLASS && kind != Kind.SOURCE) {
+ throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$
+ }
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+ String normalizedFileName = normalized(className);
+ normalizedFileName += kind.extension;
+ for (File file : files) {
+ if (file.equals(this.jrtHome)) {
+ String modName;
+ if (location instanceof ModuleLocationWrapper) {
+ modName = ((ModuleLocationWrapper) location).modName;
+ } else {
+ modName = ""; //$NON-NLS-1$
+ }
+ return this.jrtSystem.getArchiveFileObject(normalizedFileName, modName, this.charset);
+ } else if (file.isDirectory()) {
+ // handle directory
+ File f = new File(file, normalizedFileName);
+ if (f.exists()) {
+ return new EclipseFileObject(className, f.toURI(), kind, this.charset);
+ } else {
+ continue; // go to next entry in the location
+ }
+ } else if (isArchive(file)) {
+ // handle archive file
+ ArchiveFileObject fileObject = getFileObject(file, normalizedFileName);
+ if (fileObject!=null) {
+ return fileObject;
+ }
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject)
+ */
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling)
+ throws IOException {
+ validateOutputLocation(location);
+ if (kind != Kind.CLASS && kind != Kind.SOURCE) {
+ throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$
+ }
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ if (!location.equals(StandardLocation.CLASS_OUTPUT)
+ && !location.equals(StandardLocation.SOURCE_OUTPUT))
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ // we will use either the sibling or user.dir
+ if (sibling != null) {
+ String normalizedFileName = normalized(className);
+ int index = normalizedFileName.lastIndexOf('/');
+ if (index != -1) {
+ normalizedFileName = normalizedFileName.substring(index + 1);
+ }
+ normalizedFileName += kind.extension;
+ URI uri = sibling.toUri();
+ URI uri2 = null;
+ try {
+ String path = uri.getPath();
+ index = path.lastIndexOf('/');
+ if (index != -1) {
+ path = path.substring(0, index + 1);
+ path += normalizedFileName;
+ }
+ uri2 = new URI(uri.getScheme(), uri.getHost(), path, uri.getFragment());
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException("invalid sibling", e);//$NON-NLS-1$
+ }
+ return new EclipseFileObject(className, uri2, kind, this.charset);
+ } else {
+ String normalizedFileName = normalized(className);
+ normalizedFileName += kind.extension;
+ File f = new File(System.getProperty("user.dir"), normalizedFileName);//$NON-NLS-1$
+ return new EclipseFileObject(className, f.toURI(), kind, this.charset);
+ }
+ }
+ final Iterator<? extends File> iterator = files.iterator();
+ if (iterator.hasNext()) {
+ File file = iterator.next();
+ String normalizedFileName = normalized(className);
+ normalizedFileName += kind.extension;
+ File f = new File(file, normalizedFileName);
+ return new EclipseFileObject(className, f.toURI(), kind, this.charset);
+ } else {
+ throw new IllegalArgumentException("location is empty : " + location);//$NON-NLS-1$
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjects(java.io.File[])
+ */
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
+ return getJavaFileObjectsFromFiles(Arrays.asList(files));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjects(java.lang.String[])
+ */
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
+ return getJavaFileObjectsFromStrings(Arrays.asList(names));
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjectsFromFiles(java.lang.Iterable)
+ */
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
+ ArrayList<JavaFileObject> javaFileArrayList = new ArrayList<>();
+ for (File f : files) {
+ if (f.isDirectory()) {
+ throw new IllegalArgumentException("file : " + f.getAbsolutePath() + " is a directory"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ javaFileArrayList.add(new EclipseFileObject(f.getAbsolutePath(), f.toURI(), getKind(f), this.charset));
+ }
+ return javaFileArrayList;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getJavaFileObjectsFromStrings(java.lang.Iterable)
+ */
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
+ ArrayList<File> files = new ArrayList<>();
+ for (String name : names) {
+ files.add(new File(name));
+ }
+ return getJavaFileObjectsFromFiles(files);
+ }
+
+ public Kind getKind(File f) {
+ return getKind(getExtension(f));
+ }
+
+ private Kind getKind(String extension) {
+ if (Kind.CLASS.extension.equals(extension)) {
+ return Kind.CLASS;
+ } else if (Kind.SOURCE.extension.equals(extension)) {
+ return Kind.SOURCE;
+ } else if (Kind.HTML.extension.equals(extension)) {
+ return Kind.HTML;
+ }
+ return Kind.OTHER;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#getLocation(javax.tools.JavaFileManager.Location)
+ */
+ @Override
+ public Iterable<? extends File> getLocation(Location location) {
+ if (location instanceof LocationWrapper) {
+ return getFiles(((LocationWrapper) location).paths);
+ }
+ LocationWrapper loc = this.locationHandler.getLocation(location, ""); //$NON-NLS-1$
+ if (loc == null) {
+ return null;
+ }
+ return getFiles(loc.getPaths());
+ }
+
+ private Iterable<? extends File> getOutputDir(String string) {
+ if ("none".equals(string)) {//$NON-NLS-1$
+ return null;
+ }
+ File file = new File(string);
+ if (file.exists() && !file.isDirectory()) {
+ throw new IllegalArgumentException("file : " + file.getAbsolutePath() + " is not a directory");//$NON-NLS-1$//$NON-NLS-2$
+ }
+ ArrayList<File> list = new ArrayList<>(1);
+ list.add(file);
+ return list;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#handleOption(java.lang.String, java.util.Iterator)
+ */
+ @Override
+ public boolean handleOption(String current, Iterator<String> remaining) {
+ try {
+ switch(current) {
+ case "-bootclasspath": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> bootclasspaths = getPathsFrom(remaining.next());
+ if (bootclasspaths != null) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH);
+ if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) == 0
+ && (this.flags & EclipseFileManager.HAS_EXT_DIRS) == 0) {
+ // override default bootclasspath
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootclasspaths);
+ } else if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) != 0) {
+ // endorseddirs have been processed first
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ concatFiles(iterable, bootclasspaths));
+ } else {
+ // extdirs have been processed first
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ prependFiles(iterable, bootclasspaths));
+ }
+ }
+ this.flags |= EclipseFileManager.HAS_BOOTCLASSPATH;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "--system": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> classpaths = getPathsFrom(remaining.next());
+ if (classpaths != null) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.SYSTEM_MODULES);
+ if (iterable != null) {
+ setLocation(StandardLocation.SYSTEM_MODULES, concatFiles(iterable, classpaths));
+ } else {
+ setLocation(StandardLocation.SYSTEM_MODULES, classpaths);
+ }
+ }
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "--upgrade-module-path": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> classpaths = getPathsFrom(remaining.next());
+ if (classpaths != null) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.UPGRADE_MODULE_PATH);
+ if (iterable != null) {
+ setLocation(StandardLocation.UPGRADE_MODULE_PATH,
+ concatFiles(iterable, classpaths));
+ } else {
+ setLocation(StandardLocation.UPGRADE_MODULE_PATH, classpaths);
+ }
+ }
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "-classpath": //$NON-NLS-1$
+ case "-cp": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> classpaths = getPathsFrom(remaining.next());
+ if (classpaths != null) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.CLASS_PATH);
+ if (iterable != null) {
+ setLocation(StandardLocation.CLASS_PATH,
+ concatFiles(iterable, classpaths));
+ } else {
+ setLocation(StandardLocation.CLASS_PATH, classpaths);
+ }
+ if ((this.flags & EclipseFileManager.HAS_PROCESSORPATH) == 0) {
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths);
+ } else if ((this.flags & EclipseFileManager.HAS_PROC_MODULEPATH) == 0) {
+ if (this.isOnJvm9)
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, classpaths);
+ }
+ }
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "--module-path": //$NON-NLS-1$
+ case "-p": //$NON-NLS-1$
+ final Iterable<? extends File> classpaths = getPathsFrom(remaining.next());
+ if (classpaths != null) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.MODULE_PATH);
+ if (iterable != null) {
+ setLocation(StandardLocation.MODULE_PATH, concatFiles(iterable, classpaths));
+ } else {
+ setLocation(StandardLocation.MODULE_PATH, classpaths);
+ }
+ if ((this.flags & EclipseFileManager.HAS_PROCESSORPATH) == 0) {
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths);
+ } else if ((this.flags & EclipseFileManager.HAS_PROC_MODULEPATH) == 0) {
+ if (this.isOnJvm9)
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, classpaths);
+ }
+ }
+ return true;
+ case "-encoding": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ this.charset = Charset.forName(remaining.next());
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "-sourcepath": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> sourcepaths = getPathsFrom(remaining.next());
+ if (sourcepaths != null) setLocation(StandardLocation.SOURCE_PATH, sourcepaths);
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "--module-source-path": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> sourcepaths = getPathsFrom(remaining.next());
+ if (sourcepaths != null && this.isOnJvm9)
+ setLocation(StandardLocation.MODULE_SOURCE_PATH, sourcepaths);
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "-extdirs": //$NON-NLS-1$
+ if (this.isOnJvm9) {
+ throw new IllegalArgumentException();
+ }
+ if (remaining.hasNext()) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH);
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ concatFiles(iterable, getExtdirsFrom(remaining.next())));
+ this.flags |= EclipseFileManager.HAS_EXT_DIRS;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "-endorseddirs": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ Iterable<? extends File> iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH);
+ setLocation(StandardLocation.PLATFORM_CLASS_PATH,
+ prependFiles(iterable, getEndorsedDirsFrom(remaining.next())));
+ this.flags |= EclipseFileManager.HAS_ENDORSED_DIRS;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "-d": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> outputDir = getOutputDir(remaining.next());
+ if (outputDir != null) {
+ setLocation(StandardLocation.CLASS_OUTPUT, outputDir);
+ }
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "-s": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> outputDir = getOutputDir(remaining.next());
+ if (outputDir != null) {
+ setLocation(StandardLocation.SOURCE_OUTPUT, outputDir);
+ }
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "-processorpath": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> processorpaths = getPathsFrom(remaining.next());
+ if (processorpaths != null) {
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpaths);
+ }
+ this.flags |= EclipseFileManager.HAS_PROCESSORPATH;
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "--processor-module-path": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ final Iterable<? extends File> processorpaths = getPathsFrom(remaining.next());
+ if (processorpaths != null && this.isOnJvm9) {
+ setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, processorpaths);
+ this.flags |= EclipseFileManager.HAS_PROC_MODULEPATH;
+ }
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ case "--release": //$NON-NLS-1$
+ if (remaining.hasNext()) {
+ this.releaseVersion = remaining.next();
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+ } catch (IOException e) {
+ String error = "Failed to handle option " + current; //$NON-NLS-1$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#hasLocation(javax.tools.JavaFileManager.Location)
+ */
+ @Override
+ public boolean hasLocation(Location location) {
+ try {
+ return getLocationForModule(location, "") != null; //$NON-NLS-1$
+ } catch (IOException e) {
+ // nothing to do
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#inferBinaryName(javax.tools.JavaFileManager.Location, javax.tools.JavaFileObject)
+ */
+ @Override
+ public String inferBinaryName(Location location, JavaFileObject file) {
+ validateNonModuleLocation(location);
+ Iterable<? extends Path> paths = getLocationAsPaths(location);
+ if (paths == null) {
+ return null;
+ }
+ if (file instanceof JrtFileObject) {
+ Path filePath = ((JrtFileObject) file).path;
+ filePath = filePath.subpath(2, filePath.getNameCount());
+ String name = filePath.toString();
+ int index = name.lastIndexOf('.');
+ if (index != -1) {
+ name = name.substring(0, index);
+ }
+ return name.replace('/', '.');
+ }
+ String name = file.getName();
+ JavaFileObject javaFileObject = null;
+ int index = name.lastIndexOf('.');
+ if (index != -1) {
+ name = name.substring(0, index);
+ }
+ try {
+ javaFileObject = getJavaFileForInput(location, name, file.getKind());
+ } catch (IOException e) {
+ // ignore
+ } catch (IllegalArgumentException iae) {
+ return null; // Either unknown kind or location not present
+ }
+ if (javaFileObject == null) {
+ return null;
+ }
+ return name.replace('/', '.');
+ }
+
+ private boolean isArchive(File f) {
+ if (isJrt(f))
+ return false;
+ String extension = getExtension(f);
+ return extension.equalsIgnoreCase(".jar") || extension.equalsIgnoreCase(".zip"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private boolean isJrt(File f) {
+ return f.getName().toLowerCase().equals(JrtFileSystem.BOOT_MODULE);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#isSameFile(javax.tools.FileObject, javax.tools.FileObject)
+ */
+ @Override
+ public boolean isSameFile(FileObject fileObject1, FileObject fileObject2) {
+ // EclipseFileManager creates only EcliseFileObject
+ if (!(fileObject1 instanceof EclipseFileObject)) throw new IllegalArgumentException("Unsupported file object class : " + fileObject1.getClass());//$NON-NLS-1$
+ if (!(fileObject2 instanceof EclipseFileObject)) throw new IllegalArgumentException("Unsupported file object class : " + fileObject2.getClass());//$NON-NLS-1$
+ return fileObject1.equals(fileObject2);
+ }
+ /* (non-Javadoc)
+ * @see javax.tools.OptionChecker#isSupportedOption(java.lang.String)
+ */
+ @Override
+ public int isSupportedOption(String option) {
+ return Options.processOptionsFileManager(option);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileManager#list(javax.tools.JavaFileManager.Location, java.lang.String, java.util.Set, boolean)
+ */
+ @Override
+ public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse)
+ throws IOException {
+ validateNonModuleLocation(location);
+ Iterable<? extends File> allFilesInLocations = getLocation(location);
+ if (allFilesInLocations == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+
+ ArrayList<JavaFileObject> collector = new ArrayList<>();
+ String normalizedPackageName = normalized(packageName);
+ for (File file : allFilesInLocations) {
+ collectAllMatchingFiles(location, file, normalizedPackageName, kinds, recurse, collector);
+ }
+ return collector;
+ }
+
+ private String normalized(String className) {
+ char[] classNameChars = className.toCharArray();
+ for (int i = 0, max = classNameChars.length; i < max; i++) {
+ switch(classNameChars[i]) {
+ case '\\' :
+ classNameChars[i] = '/';
+ break;
+ case '.' :
+ classNameChars[i] = '/';
+ }
+ }
+ return new String(classNameChars);
+ }
+
+ private Iterable<? extends File> prependFiles(Iterable<? extends File> iterable,
+ Iterable<? extends File> iterable2) {
+ if (iterable2 == null) return iterable;
+ ArrayList<File> list = new ArrayList<>();
+ for (Iterator<? extends File> iterator = iterable2.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ if (iterable != null) {
+ for (Iterator<? extends File> iterator = iterable.iterator(); iterator.hasNext(); ) {
+ list.add(iterator.next());
+ }
+ }
+ return list;
+ }
+ private boolean isRunningJvm9() {
+ return (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0);
+ }
+ /* (non-Javadoc)
+ * @see javax.tools.StandardJavaFileManager#setLocation(javax.tools.JavaFileManager.Location, java.lang.Iterable)
+ */
+ @Override
+ public void setLocation(Location location, Iterable<? extends File> files) throws IOException {
+ if (location.isOutputLocation() && files != null) {
+ // output location
+ int count = 0;
+ for (Iterator<? extends File> iterator = files.iterator(); iterator.hasNext(); ) {
+ iterator.next();
+ count++;
+ }
+ if (count != 1) {
+ throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$
+ }
+ }
+ this.locationHandler.setLocation(location, "", getPaths(files)); //$NON-NLS-1$
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale == null ? Locale.getDefault() : locale;
+ try {
+ this.bundle = ResourceBundleFactory.getBundle(this.locale);
+ } catch(MissingResourceException e) {
+ System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$
+ throw e;
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public void processPathEntries(final int defaultSize, final ArrayList paths,
+ final String currentPath, String customEncoding, boolean isSourceOnly,
+ boolean rejectDestinationPathOnJars) {
+
+ String currentClasspathName = null;
+ String currentDestinationPath = null;
+ ArrayList currentRuleSpecs = new ArrayList(defaultSize);
+ StringTokenizer tokenizer = new StringTokenizer(currentPath,
+ File.pathSeparator + "[]", true); //$NON-NLS-1$
+ ArrayList tokens = new ArrayList();
+ while (tokenizer.hasMoreTokens()) {
+ tokens.add(tokenizer.nextToken());
+ }
+ // state machine
+ final int start = 0;
+ final int readyToClose = 1;
+ // 'path' 'path1[rule];path2'
+ final int readyToCloseEndingWithRules = 2;
+ // 'path[rule]' 'path1;path2[rule]'
+ final int readyToCloseOrOtherEntry = 3;
+ // 'path[rule];' 'path;' 'path1;path2;'
+ final int rulesNeedAnotherRule = 4;
+ // 'path[rule1;'
+ final int rulesStart = 5;
+ // 'path[' 'path1;path2['
+ final int rulesReadyToClose = 6;
+ // 'path[rule' 'path[rule1;rule2'
+ final int destinationPathReadyToClose = 7;
+ // 'path[-d bin'
+ final int readyToCloseEndingWithDestinationPath = 8;
+ // 'path[-d bin]' 'path[rule][-d bin]'
+ final int destinationPathStart = 9;
+ // 'path[rule]['
+ final int bracketOpened = 10;
+ // '.*[.*'
+ final int bracketClosed = 11;
+ // '.*([.*])+'
+
+ final int error = 99;
+ int state = start;
+ String token = null;
+ int cursor = 0, tokensNb = tokens.size(), bracket = -1;
+ while (cursor < tokensNb && state != error) {
+ token = (String) tokens.get(cursor++);
+ if (token.equals(File.pathSeparator)) {
+ switch (state) {
+ case start:
+ case readyToCloseOrOtherEntry:
+ case bracketOpened:
+ break;
+ case readyToClose:
+ case readyToCloseEndingWithRules:
+ case readyToCloseEndingWithDestinationPath:
+ state = readyToCloseOrOtherEntry;
+ addNewEntry(paths, currentClasspathName, currentRuleSpecs,
+ customEncoding, currentDestinationPath, isSourceOnly,
+ rejectDestinationPathOnJars);
+ currentRuleSpecs.clear();
+ break;
+ case rulesReadyToClose:
+ state = rulesNeedAnotherRule;
+ break;
+ case destinationPathReadyToClose:
+ throw new IllegalArgumentException(
+ this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$
+ currentPath));
+ case bracketClosed:
+ cursor = bracket + 1;
+ state = rulesStart;
+ break;
+ default:
+ state = error;
+ }
+ } else if (token.equals("[")) { //$NON-NLS-1$
+ switch (state) {
+ case start:
+ currentClasspathName = ""; //$NON-NLS-1$
+ //$FALL-THROUGH$
+ case readyToClose:
+ bracket = cursor - 1;
+ //$FALL-THROUGH$
+ case bracketClosed:
+ state = bracketOpened;
+ break;
+ case readyToCloseEndingWithRules:
+ state = destinationPathStart;
+ break;
+ case readyToCloseEndingWithDestinationPath:
+ state = rulesStart;
+ break;
+ case bracketOpened:
+ default:
+ state = error;
+ }
+ } else if (token.equals("]")) { //$NON-NLS-1$
+ switch (state) {
+ case rulesReadyToClose:
+ state = readyToCloseEndingWithRules;
+ break;
+ case destinationPathReadyToClose:
+ state = readyToCloseEndingWithDestinationPath;
+ break;
+ case bracketOpened:
+ state = bracketClosed;
+ break;
+ case bracketClosed:
+ default:
+ state = error;
+ }
+ } else {
+ // regular word
+ switch (state) {
+ case start:
+ case readyToCloseOrOtherEntry:
+ state = readyToClose;
+ currentClasspathName = token;
+ break;
+ case rulesStart:
+ if (token.startsWith("-d ")) { //$NON-NLS-1$
+ if (currentDestinationPath != null) {
+ throw new IllegalArgumentException(
+ this.bind("configure.duplicateDestinationPathEntry", //$NON-NLS-1$
+ currentPath));
+ }
+ currentDestinationPath = token.substring(3).trim();
+ state = destinationPathReadyToClose;
+ break;
+ } // else we proceed with a rule
+ //$FALL-THROUGH$
+ case rulesNeedAnotherRule:
+ if (currentDestinationPath != null) {
+ throw new IllegalArgumentException(
+ this.bind("configure.accessRuleAfterDestinationPath", //$NON-NLS-1$
+ currentPath));
+ }
+ state = rulesReadyToClose;
+ currentRuleSpecs.add(token);
+ break;
+ case destinationPathStart:
+ if (!token.startsWith("-d ")) { //$NON-NLS-1$
+ state = error;
+ } else {
+ currentDestinationPath = token.substring(3).trim();
+ state = destinationPathReadyToClose;
+ }
+ break;
+ case bracketClosed:
+ for (int i = bracket; i < cursor ; i++) {
+ currentClasspathName += (String) tokens.get(i);
+ }
+ state = readyToClose;
+ break;
+ case bracketOpened:
+ break;
+ default:
+ state = error;
+ }
+ }
+ if (state == bracketClosed && cursor == tokensNb) {
+ cursor = bracket + 1;
+ state = rulesStart;
+ }
+ }
+ switch(state) {
+ case readyToCloseOrOtherEntry:
+ break;
+ case readyToClose:
+ case readyToCloseEndingWithRules:
+ case readyToCloseEndingWithDestinationPath:
+ addNewEntry(paths, currentClasspathName, currentRuleSpecs,
+ customEncoding, currentDestinationPath, isSourceOnly,
+ rejectDestinationPathOnJars);
+ break;
+ case bracketOpened:
+ case bracketClosed:
+ default :
+ // we go on anyway
+ }
+ }
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ protected void addNewEntry(ArrayList paths, String currentClasspathName,
+ ArrayList currentRuleSpecs, String customEncoding,
+ String destPath, boolean isSourceOnly,
+ boolean rejectDestinationPathOnJars) {
+
+ int rulesSpecsSize = currentRuleSpecs.size();
+ AccessRuleSet accessRuleSet = null;
+ if (rulesSpecsSize != 0) {
+ AccessRule[] accessRules = new AccessRule[currentRuleSpecs.size()];
+ boolean rulesOK = true;
+ Iterator i = currentRuleSpecs.iterator();
+ int j = 0;
+ while (i.hasNext()) {
+ String ruleSpec = (String) i.next();
+ char key = ruleSpec.charAt(0);
+ String pattern = ruleSpec.substring(1);
+ if (pattern.length() > 0) {
+ switch (key) {
+ case '+':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(), 0);
+ break;
+ case '~':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(),
+ IProblem.DiscouragedReference);
+ break;
+ case '-':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(),
+ IProblem.ForbiddenReference);
+ break;
+ case '?':
+ accessRules[j++] = new AccessRule(pattern
+ .toCharArray(),
+ IProblem.ForbiddenReference, true/*keep looking for accessible type*/);
+ break;
+ default:
+ rulesOK = false;
+ }
+ } else {
+ rulesOK = false;
+ }
+ }
+ if (rulesOK) {
+ accessRuleSet = new AccessRuleSet(accessRules, AccessRestriction.COMMAND_LINE, currentClasspathName);
+ } else {
+ return;
+ }
+ }
+ if (Main.NONE.equals(destPath)) {
+ destPath = Main.NONE; // keep == comparison valid
+ }
+ if (rejectDestinationPathOnJars && destPath != null &&
+ (currentClasspathName.endsWith(".jar") || //$NON-NLS-1$
+ currentClasspathName.endsWith(".zip"))) { //$NON-NLS-1$
+ throw new IllegalArgumentException(
+ this.bind("configure.unexpectedDestinationPathEntryFile", //$NON-NLS-1$
+ currentClasspathName));
+ }
+ FileSystem.Classpath currentClasspath = FileSystem.getClasspath(
+ currentClasspathName,
+ customEncoding,
+ isSourceOnly,
+ accessRuleSet,
+ destPath,
+ null,
+ this.releaseVersion);
+ if (currentClasspath != null) {
+ paths.add(currentClasspath);
+ }
+ }
+ /*
+ * Lookup the message with the given ID in this catalog and bind its
+ * substitution locations with the given string.
+ */
+ private String bind(String id, String binding) {
+ return bind(id, new String[] { binding });
+ }
+
+ /*
+ * Lookup the message with the given ID in this catalog and bind its
+ * substitution locations with the given string values.
+ */
+ private String bind(String id, String[] arguments) {
+ if (id == null)
+ return "No message available"; //$NON-NLS-1$
+ String message = null;
+ try {
+ message = this.bundle.getString(id);
+ } catch (MissingResourceException e) {
+ // If we got an exception looking for the message, fail gracefully by just returning
+ // the id we were looking for. In most cases this is semi-informative so is not too bad.
+ return "Missing message: " + id + " in: " + Main.bundleName; //$NON-NLS-2$ //$NON-NLS-1$
+ }
+ return MessageFormat.format(message, (Object[]) arguments);
+ }
+
+ private Iterable<? extends File> getFiles(final Iterable<? extends Path> paths) {
+ if (paths == null)
+ return null;
+ return () -> new Iterator<>() {
+ Iterator<? extends Path> original = paths.iterator();
+ @Override
+ public boolean hasNext() {
+ return this.original.hasNext();
+ }
+ @Override
+ public File next() {
+ return this.original.next().toFile();
+ }
+ };
+ }
+ private Iterable<? extends Path> getPaths(final Iterable<? extends File> files) {
+ if (files == null)
+ return null;
+ return () -> new Iterator<>() {
+ Iterator<? extends File> original = files.iterator();
+ @Override
+ public boolean hasNext() {
+ return this.original.hasNext();
+ }
+ @Override
+ public Path next() {
+ return this.original.next().toPath();
+ }
+ };
+ }
+
+ private void validateFileObject(FileObject file) {
+ // FIXME: fill-up
+ }
+ private void validateModuleLocation(Location location, String modName) {
+ Objects.requireNonNull(location);
+ if (modName == null) {
+ throw new IllegalArgumentException("module must not be null"); //$NON-NLS-1$
+ }
+ if (this.isOnJvm9) {
+ if (!location.isModuleOrientedLocation() && !location.isOutputLocation()) {
+ throw new IllegalArgumentException("location is module related :" + location.getName()); //$NON-NLS-1$
+ }
+ }
+ }
+ private void validateNonModuleLocation(Location location) {
+ Objects.requireNonNull(location);
+ if (this.isOnJvm9) {
+ if (location.isModuleOrientedLocation() && location.isOutputLocation()) {
+ throw new IllegalArgumentException("location is module related :" + location.getName()); //$NON-NLS-1$
+ }
+ }
+ }
+ private void validateOutputLocation(Location location) {
+ Objects.requireNonNull(location);
+ if (!location.isOutputLocation()) {
+ throw new IllegalArgumentException("location is not output location :" + location.getName()); //$NON-NLS-1$
+ }
+ }
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjects(Path... paths) {
+ return getJavaFileObjectsFromPaths(Arrays.asList(paths));
+ }
+
+ @Override
+ public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(Iterable<? extends Path> paths) {
+ return getJavaFileObjectsFromFiles(getFiles(paths));
+ }
+
+ @Override
+ public Iterable<? extends Path> getLocationAsPaths(Location location) {
+ if (location instanceof LocationWrapper) {
+ return ((LocationWrapper) location).paths;
+ }
+ LocationWrapper loc = this.locationHandler.getLocation(location);
+ if (loc == null) {
+ return null;
+ }
+ return loc.getPaths();
+ }
+
+ @Override
+ public void setLocationFromPaths(Location location, Collection<? extends Path> paths) throws IOException {
+ setLocation(location, getFiles(paths));
+ if (location == StandardLocation.MODULE_PATH || location == StandardLocation.MODULE_SOURCE_PATH) {
+ // FIXME: same for module source path?
+ Map<String, String> options = new HashMap<>();
+ // FIXME: Find a way to get the options from the EclipseCompiler and pass it to the parser.
+ String latest = CompilerOptions.getLatestVersion();
+ options.put(CompilerOptions.OPTION_Compliance, latest);
+ options.put(CompilerOptions.OPTION_Source, latest);
+ options.put(CompilerOptions.OPTION_TargetPlatform, latest);
+ CompilerOptions compilerOptions = new CompilerOptions(options);
+ ProblemReporter problemReporter =
+ new ProblemReporter(
+ DefaultErrorHandlingPolicies.proceedWithAllProblems(),
+ compilerOptions,
+ new DefaultProblemFactory());
+ for (Path path : paths) {
+ List<Classpath> mp = ModuleFinder.findModules(path.toFile(), null,
+ new Parser(problemReporter, true), null, true, this.releaseVersion);
+ for (Classpath cp : mp) {
+ Collection<String> moduleNames = cp.getModuleNames(null);
+ for (String string : moduleNames) {
+ Path p = Paths.get(cp.getPath());
+ setLocationForModule(location, string, Collections.singletonList(p));
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean contains(Location location, FileObject fo) throws IOException {
+ validateFileObject(fo);
+ Iterable<? extends File> files = getLocation(location);
+ if (files == null) {
+ throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$
+ }
+ for (File file : files) {
+ if (file.isDirectory()) {
+ if (fo instanceof EclipseFileObject) {
+ Path filepath = ((EclipseFileObject) fo).f.toPath();
+ if (filepath.startsWith(Paths.get(file.toURI()).toAbsolutePath())) {
+ return true;
+ }
+ }
+ } else if (isArchive(file)) {
+ if (fo instanceof ArchiveFileObject) {
+ Boolean contains = containsFileObject(file, ((ArchiveFileObject) fo).entryName);
+ if (contains != null) {
+ return contains;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Location getLocationForModule(Location location, String moduleName) throws IOException {
+ validateModuleLocation(location, moduleName);
+ Location result = this.locationHandler.getLocation(location, moduleName);
+ if (result == null && location == StandardLocation.CLASS_OUTPUT) {
+ LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.MODULE_SOURCE_PATH, moduleName);
+ // There are cases where we don't have module source path in that case we need to create
+ // classes in default location
+ if (wrapper == null) {
+ result = location;
+ } else {
+ deriveOutputLocationForModules(moduleName, wrapper.paths);
+ result = getLocationForModule(location, moduleName);
+ }
+ } else if (result == null && location == StandardLocation.SOURCE_OUTPUT) {
+ LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.MODULE_SOURCE_PATH, moduleName);
+ deriveSourceOutputLocationForModules(moduleName, wrapper.paths);
+ result = getLocationForModule(location, moduleName);
+ }
+ return result;
+ }
+
+ @Override
+ public Location getLocationForModule(Location location, JavaFileObject fo) {
+ validateModuleLocation(location, ""); //$NON-NLS-1$
+ Path path = null;
+ if (fo instanceof ArchiveFileObject) {
+ path = ((ArchiveFileObject) fo).file.toPath();
+ return this.locationHandler.getLocation(location, path);
+ } else if (fo instanceof EclipseFileObject) {
+ path = ((EclipseFileObject) fo).f.toPath();
+ try {
+ path = path.toRealPath();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ LocationContainer container = this.locationHandler.getLocation(location);
+ while (path != null) {
+ Location loc = container.get(path);
+ if (loc != null)
+ return loc;
+ path = path.getParent();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public <S> ServiceLoader<S> getServiceLoader(Location location, Class<S> service) throws IOException {
+ // FIXME: Need special handling in case of module class loaders.
+ return ServiceLoader.load(service, getClassLoader(location));
+ }
+
+ @Override
+ public String inferModuleName(Location location) throws IOException {
+ if (location instanceof ModuleLocationWrapper) {
+ ModuleLocationWrapper wrapper = (ModuleLocationWrapper) location;
+ return wrapper.modName;
+ }
+ return null;
+ }
+
+ @Override
+ public Iterable<Set<Location>> listLocationsForModules(Location location) {
+ validateModuleLocation(location, ""); //$NON-NLS-1$
+ return this.locationHandler.listLocationsForModules(location);
+ }
+
+ @Override
+ public Path asPath(FileObject file) {
+ validateFileObject(file);
+ EclipseFileObject eclFile = (EclipseFileObject) file;
+ if (eclFile.f != null) {
+ return eclFile.f.toPath();
+ }
+ return null;
+ }
+ private void deriveOutputLocationForModules(String moduleName, Collection<? extends Path> paths) {
+ LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, moduleName);
+ if (wrapper == null) {
+ // First get from our internally known location for legacy/unnamed location
+ wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, ""); //$NON-NLS-1$
+ if (wrapper == null) {
+ wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT);
+ }
+ if (wrapper != null) {
+ Iterator<? extends Path> iterator = wrapper.paths.iterator();
+ if (iterator.hasNext()) {
+ try {
+ // Per module output location is always a singleton list
+ Path path = iterator.next().resolve(moduleName);
+ this.locationHandler.setLocation(StandardLocation.CLASS_OUTPUT, moduleName, Collections.singletonList(path));
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ private void deriveSourceOutputLocationForModules(String moduleName, Collection<? extends Path> paths) {
+ LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.SOURCE_OUTPUT, moduleName);
+ if (wrapper == null) {
+ // First get from our internally known location for legacy/unnamed location
+ wrapper = this.locationHandler.getLocation(StandardLocation.SOURCE_OUTPUT, ""); //$NON-NLS-1$
+ if (wrapper == null) {
+ wrapper = this.locationHandler.getLocation(StandardLocation.SOURCE_OUTPUT);
+ }
+ if (wrapper != null) {
+ Iterator<? extends Path> iterator = wrapper.paths.iterator();
+ if (iterator.hasNext()) {
+ try {
+ // Per module output location is always a singleton list
+ Path path = iterator.next().resolve(moduleName);
+ this.locationHandler.setLocation(StandardLocation.SOURCE_OUTPUT, moduleName, Collections.singletonList(path));
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ @Override
+ public void setLocationForModule(Location location, String moduleName, Collection<? extends Path> paths) throws IOException {
+ validateModuleLocation(location, moduleName);
+ this.locationHandler.setLocation(location, moduleName, paths);
+ if (location == StandardLocation.MODULE_SOURCE_PATH) {
+ LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, moduleName);
+ if (wrapper == null) {
+ wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, ""); //$NON-NLS-1$
+ if (wrapper != null) {
+ Iterator<? extends Path> iterator = wrapper.paths.iterator();
+ if (iterator.hasNext()) {
+ // Per module output location is always a singleton list
+ Path path = iterator.next().resolve(moduleName);
+ this.locationHandler.setLocation(StandardLocation.CLASS_OUTPUT, moduleName, Collections.singletonList(path));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java
new file mode 100644
index 0000000..b45307c
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2017 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Walter Harley - Patch for ensuring the parent folders are created
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.charset.Charset;
+
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.SimpleJavaFileObject;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.util.JRTUtil;
+
+/**
+ * Implementation of a Java file object that corresponds to a file on the file system
+ */
+public class EclipseFileObject extends SimpleJavaFileObject {
+ File f;
+ private Charset charset;
+ private boolean parentsExist; // parent directories exist
+
+ public EclipseFileObject(String className, URI uri, Kind kind, Charset charset) {
+ super(uri, kind);
+ this.f = new File(this.uri);
+ this.charset = charset;
+ this.parentsExist = false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getAccessLevel()
+ */
+ @Override
+ public Modifier getAccessLevel() {
+ // cannot express multiple modifier
+ if (getKind() != Kind.CLASS) {
+ return null;
+ }
+ ClassFileReader reader = null;
+ try {
+ reader = ClassFileReader.read(this.f);
+ } catch (ClassFormatException e) {
+ // ignore
+ } catch (IOException e) {
+ String error = "Failed to read access level from " + this.f; //$NON-NLS-1$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ }
+ if (reader == null) {
+ return null;
+ }
+ final int accessFlags = reader.accessFlags();
+ if ((accessFlags & ClassFileConstants.AccPublic) != 0) {
+ return Modifier.PUBLIC;
+ }
+ if ((accessFlags & ClassFileConstants.AccAbstract) != 0) {
+ return Modifier.ABSTRACT;
+ }
+ if ((accessFlags & ClassFileConstants.AccFinal) != 0) {
+ return Modifier.FINAL;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.JavaFileObject#getNestingKind()
+ */
+ @Override
+ public NestingKind getNestingKind() {
+ switch(this.kind) {
+ case SOURCE :
+ return NestingKind.TOP_LEVEL;
+ case CLASS :
+ ClassFileReader reader = null;
+ try {
+ reader = ClassFileReader.read(this.f);
+ } catch (ClassFormatException e) {
+ // ignore
+ } catch (IOException e) {
+ String error = "Failed to read access nesting kind from " + this.f; //$NON-NLS-1$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ }
+ if (reader == null) {
+ return null;
+ }
+ if (reader.isAnonymous()) {
+ return NestingKind.ANONYMOUS;
+ }
+ if (reader.isLocal()) {
+ return NestingKind.LOCAL;
+ }
+ if (reader.isMember()) {
+ return NestingKind.MEMBER;
+ }
+ return NestingKind.TOP_LEVEL;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * @see javax.tools.FileObject#delete()
+ */
+ @Override
+ public boolean delete() {
+ return this.f.delete();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof EclipseFileObject)) {
+ return false;
+ }
+ EclipseFileObject eclipseFileObject = (EclipseFileObject) o;
+ return eclipseFileObject.toUri().equals(this.uri);
+ }
+
+ /**
+ * @see javax.tools.FileObject#getCharContent(boolean)
+ */
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return Util.getCharContents(this, ignoreEncodingErrors, org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(this.f), this.charset.name());
+ }
+
+ /**
+ * @see javax.tools.FileObject#getLastModified()
+ */
+ @Override
+ public long getLastModified() {
+ return this.f.lastModified();
+ }
+
+ @Override
+ public String getName() {
+ return this.f.getPath();
+ }
+
+ @Override
+ public int hashCode() {
+ return this.f.hashCode();
+ }
+
+ /**
+ * @see javax.tools.FileObject#openInputStream()
+ */
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return new BufferedInputStream(new FileInputStream(this.f));
+ }
+
+ /**
+ * @see javax.tools.FileObject#openOutputStream()
+ */
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ ensureParentDirectoriesExist();
+ return new BufferedOutputStream(new FileOutputStream(this.f));
+ }
+
+ /**
+ * @see javax.tools.FileObject#openReader(boolean)
+ */
+ @Override
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ return new BufferedReader(new FileReader(this.f));
+ }
+
+ /**
+ * @see javax.tools.FileObject#openWriter()
+ */
+ @Override
+ public Writer openWriter() throws IOException {
+ ensureParentDirectoriesExist();
+ return new BufferedWriter(new FileWriter(this.f));
+ }
+
+ @Override
+ public String toString() {
+ return this.f.getAbsolutePath();
+ }
+
+ private void ensureParentDirectoriesExist() throws IOException {
+ if (!this.parentsExist) {
+ File parent = this.f.getParentFile();
+ if (parent != null && !parent.exists()) {
+ if (!parent.mkdirs()) {
+ // could have been concurrently created
+ if (!parent.exists() || !parent.isDirectory())
+ throw new IOException("Unable to create parent directories for " + this.f); //$NON-NLS-1$
+ }
+ }
+ this.parentsExist = true;
+ }
+ }
+
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/JrtFileSystem.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/JrtFileSystem.java
new file mode 100644
index 0000000..04c1976
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/JrtFileSystem.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2017 IBM Corporation.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.charset.Charset;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipException;
+
+import javax.tools.JavaFileObject;
+
+import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.ModuleLocationWrapper;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.util.JRTUtil;
+
+public class JrtFileSystem extends Archive {
+
+ private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$
+
+ static final String BOOT_MODULE = "jrt-fs.jar"; //$NON-NLS-1$
+
+ public HashMap<String, Path> modulePathMap;
+ Path modules;
+ private java.nio.file.FileSystem jrtfs;
+
+ public JrtFileSystem(File file) throws ZipException, IOException {
+ this.file = file;
+ initialize();
+ }
+
+ public void initialize() throws IOException {
+ // initialize packages
+ this.modulePathMap = new HashMap<>();
+ URL jrtPath = null;
+
+ if (this.file.exists()) {
+ jrtPath = Paths.get(this.file.toPath().toString(), "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$
+ try (URLClassLoader loader = new URLClassLoader(new URL[] { jrtPath })) {
+ HashMap<String, ?> env = new HashMap<>();
+ this.jrtfs = FileSystems.newFileSystem(JRT_URI, env, loader);
+ this.modules = this.jrtfs.getPath("/modules"); //$NON-NLS-1$
+ }
+ } else {
+ return;
+ }
+
+ org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(this.file,
+ new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitModule(Path path, String name) throws IOException {
+ JrtFileSystem.this.modulePathMap.put(name, path);
+ return FileVisitResult.CONTINUE;
+ }
+ }, JRTUtil.NOTIFY_MODULES);
+ }
+
+ public List<JrtFileObject> list(ModuleLocationWrapper location, String packageName,
+ Set<JavaFileObject.Kind> kinds, boolean recurse, Charset charset) {
+ String module = location.modName;
+ Path mPath = this.modules.resolve(module);
+ Path resolve = mPath.resolve(packageName);
+ java.util.List<Path> files = null;
+ try (Stream<Path> p = Files.list(resolve)) {
+ files = p.filter((path) -> {
+ if (Files.isDirectory(path))
+ return false;
+ else
+ return true;
+ }).collect(Collectors.toList());
+ } catch (IOException e) {
+ String error = "Failed to read files from " + resolve; //$NON-NLS-1$
+ if (JRTUtil.PROPAGATE_IO_ERRORS) {
+ throw new IllegalStateException(error, e);
+ } else {
+ System.err.println(error);
+ e.printStackTrace();
+ }
+ }
+ List<JrtFileObject> result = new ArrayList<>();
+ for (Path p: files) {
+ result.add(new JrtFileObject(this.file, p, module, charset));
+ }
+ return result;
+ }
+ @Override
+ public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) {
+ return new JrtFileObject(this.file, this.modules.resolve(module).resolve(fileName), module, charset);
+ }
+
+ @Override
+ public boolean contains(String entryName) {
+ // FIXME
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "JRT: " + (this.file == null ? "UNKNOWN_ARCHIVE" : this.file.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ class JrtFileObject extends ArchiveFileObject {
+ String module;
+ Path path;
+ private JrtFileObject(File file, Path path, String module, Charset charset) {
+ super(file, path.toString(), charset);
+ this.path = path;
+ this.module = module;
+ }
+
+ @Override
+ protected ClassFileReader getClassReader() {
+ ClassFileReader reader = null;
+ try {
+ byte[] content = JRTUtil.getClassfileContent(this.file, this.entryName, this.module);
+ if (content == null) return null;
+ return new ClassFileReader(content, this.entryName.toCharArray());
+ } catch (ClassFormatException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return reader;
+ }
+
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getCharContent(boolean)
+ */
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return Util.getCharContents(this, ignoreEncodingErrors,
+ org.eclipse.jdt.internal.compiler.util.JRTUtil.getClassfileContent(this.file, this.entryName, this.module),
+ this.charset.name());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getLastModified()
+ */
+ @Override
+ public long getLastModified() {
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#getName()
+ */
+ @Override
+ public String getName() {
+ return this.path.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openInputStream()
+ */
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return Files.newInputStream(this.path);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openOutputStream()
+ */
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openReader(boolean)
+ */
+ @Override
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#openWriter()
+ */
+ @Override
+ public Writer openWriter() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.tools.FileObject#toUri()
+ */
+ @Override
+ public URI toUri() {
+ try {
+ return new URI("JRT:" + this.file.toURI().getPath() + "!" + this.entryName); //$NON-NLS-1$//$NON-NLS-2$
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ return this.file.getAbsolutePath() + "[" + this.entryName + "]";//$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java
new file mode 100644
index 0000000..d1f0c57
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java
@@ -0,0 +1,368 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2017 BEA Systems, Inc.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * wharley@bea.com - initial API and implementation
+ * (originally in org.eclipse.jdt.apt.core)
+ * IBM Corporation - Bug 513790
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manage a Map<T1, Set<T2>>, with reverse links so that it is possible to
+ * efficiently find all T1s that have a particular T2 associated with them.
+ * Access to the map is synchronized, so that it is possible to read and
+ * write simultaneously from multiple threads.
+ * <p>
+ * The map permits the null value for keys nor for value elements.
+ * <p>
+ * Design invariants preserved by all operations on this map are as follows:
+ * <ul>
+ * <li> If a key exists, it has at least one value associated with it; that is,
+ * for all k such that null != containsKey(k), getValues(k) returns a non-empty
+ * set.</li>
+ * <li> If a value exists, it has at least one key associated with it; that is,
+ * for all v such that null != containsValue(v), getKeys(v) returns a non-empty
+ * set.</li>
+ */
+public class ManyToMany<T1, T2> {
+
+ private final Map<T1, Set<T2>> _forward = new HashMap<>();
+ private final Map<T2, Set<T1>> _reverse = new HashMap<>();
+ private boolean _dirty = false;
+
+ /**
+ * Empty all maps. If the maps previously contained entries,
+ * this will set the dirty bit.
+ * @return true if the maps contained any entries prior to being cleared
+ */
+ public synchronized boolean clear() {
+ boolean hadContent = !_forward.isEmpty() || !_reverse.isEmpty();
+ _reverse.clear();
+ _forward.clear();
+ _dirty |= hadContent;
+ return hadContent;
+ }
+
+ /**
+ * Sets the dirty bit to false. Internal operations do not use the dirty
+ * bit; clearing it will not affect behavior of the map. It's just there
+ * for the convenience of callers who don't want to keep track of every
+ * put() and remove().
+ */
+ public synchronized void clearDirtyBit() {
+ _dirty = false;
+ }
+
+ /**
+ * Equivalent to keySet().contains(key).
+ * @return true if the map contains the specified key.
+ */
+ public synchronized boolean containsKey(T1 key) {
+ return _forward.containsKey(key);
+ }
+
+ /**
+ * Is there a key that is mapped to the specified value?
+ * Search within the forward map.
+ * @return true if such a key exists
+ */
+ public synchronized boolean containsKeyValuePair(T1 key, T2 value) {
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ return false;
+ }
+ return values.contains(value);
+ }
+
+ /**
+ * Equivalent to values().contains(value).
+ * @return true if the map contains the specified value (regardless
+ * of what key it might be associated with).
+ */
+ public synchronized boolean containsValue(T2 value) {
+ return _reverse.containsKey(value);
+ }
+
+ /**
+ * Search the reverse map for all keys that have been associated with
+ * a particular value.
+ * @return the set of keys that are associated with the specified value,
+ * or an empty set if the value does not exist in the map.
+ */
+ public synchronized Set<T1> getKeys(T2 value) {
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys) {
+ return Collections.emptySet();
+ }
+ return new HashSet<>(keys);
+ }
+
+ /**
+ * Search the forward map for all values associated with a particular key.
+ * Returns a copy of the set of values.
+ * @return a copy of the set of values that are associated with the
+ * specified key, or an empty set if the key does not exist in the map.
+ */
+ public synchronized Set<T2> getValues(T1 key) {
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ return Collections.emptySet();
+ }
+ return new HashSet<>(values);
+ }
+
+ /**
+ * @return a copy of the set of all keys (that is, all items of type T1).
+ * If the maps are empty, the returned set will be empty, not null. The
+ * returned set can be modified by the caller without affecting the map.
+ * @see #getValueSet()
+ */
+ public synchronized Set<T1> getKeySet() {
+ Set<T1> keys = new HashSet<>(_forward.keySet());
+ return keys;
+ }
+
+ /**
+ * @return a copy of the set of all values (that is, all items of type T2).
+ * If the maps are empty, the returned set will be empty, not null. The
+ * returned set can be modified by the caller without affecting the map.
+ * @see #getKeySet()
+ */
+ public synchronized Set<T2> getValueSet() {
+ Set<T2> values = new HashSet<>(_reverse.keySet());
+ return values;
+ }
+
+ /**
+ * Return the state of the dirty bit. All operations that change the state
+ * of the maps, including @see #clear(), set the dirty bit if any content actually
+ * changed. The only way to clear the dirty bit is to call @see #clearDirtyBit().
+ * @return true if the map content has changed since it was created or since
+ * the last call to clearDirtyBit().
+ * @see #clearDirtyBit()
+ */
+ public synchronized boolean isDirty() {
+ return _dirty;
+ }
+
+ /**
+ * Check whether <code>key</code> has an association to any values other
+ * than <code>value</code> - that is, whether the same key has been added
+ * with multiple values. Equivalent to asking whether the intersection of
+ * <code>getValues(key)</code> and the set containing <code>value</code> is
+ * non-empty.
+ * @return true iff <code>key</code> is in the map and is associated
+ * with values other than <code>value</code>.
+ * @see #valueHasOtherKeys(Object, Object)
+ */
+ public synchronized boolean keyHasOtherValues(T1 key, T2 value) {
+ Set<T2> values = _forward.get(key);
+ if (values == null)
+ return false;
+ int size = values.size();
+ if (size == 0)
+ return false;
+ else if (size > 1)
+ return true;
+ else // size == 1
+ return !values.contains(value);
+ }
+
+ /**
+ * Associate the specified value with the key. Adds the entry
+ * to both the forward and reverse maps. Adding the same value
+ * twice to a particular key has no effect. Because this is a
+ * many-to-many map, adding a new value for an existing key does
+ * not change the existing association, it adds a new one.
+ * @param key can be null
+ * @param value can be null
+ * @return true if the key/value pair did not exist prior to being added
+ */
+ public synchronized boolean put(T1 key, T2 value) {
+ // Add to forward map
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ values = new HashSet<>();
+ _forward.put(key, values);
+ }
+ boolean added = values.add(value);
+ _dirty |= added;
+
+ // Add to reverse map
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys) {
+ keys = new HashSet<>();
+ _reverse.put(value, keys);
+ }
+ keys.add(key);
+
+ assert checkIntegrity();
+ return added;
+ }
+
+ /**
+ * Remove a particular key-value association. This is the inverse
+ * of put(key, value). If the key does not exist, or the value
+ * does not exist, or the association does not exist, this call
+ * has no effect.
+ * @return true if the key/value pair existed in the map prior to removal
+ */
+ public synchronized boolean remove(T1 key, T2 value) {
+ Set<T2> values = _forward.get(key);
+ if (values == null) {
+ assert checkIntegrity();
+ return false;
+ }
+ boolean removed = values.remove(value);
+ if (values.isEmpty()) {
+ _forward.remove(key);
+ }
+ if (removed) {
+ _dirty = true;
+ // it existed, so we need to remove from reverse map as well
+ Set<T1> keys = _reverse.get(value);
+ keys.remove(key);
+ if (keys.isEmpty()) {
+ _reverse.remove(value);
+ }
+ }
+ assert checkIntegrity();
+ return removed;
+ }
+
+ /**
+ * Remove the key and its associated key/value entries.
+ * Calling removeKey(k) is equivalent to calling remove(k,v)
+ * for every v in getValues(k).
+ * @return true if the key existed in the map prior to removal
+ */
+ public synchronized boolean removeKey(T1 key) {
+ // Remove all back-references to key.
+ Set<T2> values = _forward.get(key);
+ if (null == values) {
+ // key does not exist in map.
+ assert checkIntegrity();
+ return false;
+ }
+ for (T2 value : values) {
+ Set<T1> keys = _reverse.get(value);
+ if (null != keys) {
+ keys.remove(key);
+ if (keys.isEmpty()) {
+ _reverse.remove(value);
+ }
+ }
+ }
+ // Now remove the forward references from key.
+ _forward.remove(key);
+ _dirty = true;
+ assert checkIntegrity();
+ return true;
+ }
+
+ /**
+ * Remove the value and its associated key/value entries.
+ * Calling removeValue(v) is equivalent to calling remove(k,v)
+ * for every k in getKeys(v).
+ * @return true if the value existed in the map prior to removal.
+ */
+ public synchronized boolean removeValue(T2 value) {
+ // Remove any forward references to value
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys) {
+ // value does not exist in map.
+ assert checkIntegrity();
+ return false;
+ }
+ for (T1 key : keys) {
+ Set<T2> values = _forward.get(key);
+ if (null != values) {
+ values.remove(value);
+ if (values.isEmpty()) {
+ _forward.remove(key);
+ }
+ }
+ }
+ // Now remove the reverse references from value.
+ _reverse.remove(value);
+ _dirty = true;
+ assert checkIntegrity();
+ return true;
+ }
+
+ /**
+ * Check whether <code>value</code> has an association from any keys other
+ * than <code>key</code> - that is, whether the same value has been added
+ * with multiple keys. Equivalent to asking whether the intersection of
+ * <code>getKeys(value)</code> and the set containing <code>key</code> is
+ * non-empty.
+ * @return true iff <code>value</code> is in the map and is associated
+ * with keys other than <code>key</code>.
+ * @see #keyHasOtherValues(Object, Object)
+ */
+ public synchronized boolean valueHasOtherKeys(T2 value, T1 key) {
+ Set<T1> keys = _reverse.get(value);
+ if (keys == null)
+ return false;
+ int size = keys.size();
+ if (size == 0)
+ return false;
+ else if (size > 1)
+ return true;
+ else // size == 1
+ return !keys.contains(key);
+ }
+
+ /**
+ * Check the integrity of the internal data structures. This is intended to
+ * be called within an assert, so that if asserts are disabled the integrity
+ * checks will not cause a performance impact.
+ * @return true if everything is okay.
+ * @throws IllegalStateException if there is a problem.
+ */
+ private boolean checkIntegrity() {
+ // For every T1->T2 mapping in the forward map, there should be a corresponding
+ // T2->T1 mapping in the reverse map.
+ for (Map.Entry<T1, Set<T2>> entry : _forward.entrySet()) {
+ Set<T2> values = entry.getValue();
+ if (values.isEmpty()) {
+ throw new IllegalStateException("Integrity compromised: forward map contains an empty set"); //$NON-NLS-1$
+ }
+ for (T2 value : values) {
+ Set<T1> keys = _reverse.get(value);
+ if (null == keys || !keys.contains(entry.getKey())) {
+ throw new IllegalStateException("Integrity compromised: forward map contains an entry missing from reverse map: " + value); //$NON-NLS-1$
+ }
+ }
+ }
+ // And likewise in the other direction.
+ for (Map.Entry<T2, Set<T1>> entry : _reverse.entrySet()) {
+ Set<T1> keys = entry.getValue();
+ if (keys.isEmpty()) {
+ throw new IllegalStateException("Integrity compromised: reverse map contains an empty set"); //$NON-NLS-1$
+ }
+ for (T1 key : keys) {
+ Set<T2> values = _forward.get(key);
+ if (null == values || !values.contains(entry.getKey())) {
+ throw new IllegalStateException("Integrity compromised: reverse map contains an entry missing from forward map: " + key); //$NON-NLS-1$
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ModuleLocationHandler.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ModuleLocationHandler.java
new file mode 100644
index 0000000..533ccbb
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/ModuleLocationHandler.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2017 IBM Corporation.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.tools.JavaFileManager.Location;
+import javax.tools.StandardLocation;
+
+public class ModuleLocationHandler {
+
+ Map<Location, LocationContainer> containers;
+
+ ModuleLocationHandler() {
+ this.containers = new HashMap<>();
+ }
+
+ public void newSystemLocation(Location loc, JrtFileSystem jrt) throws IOException {
+ SystemLocationContainer systemLocationWrapper = new SystemLocationContainer(StandardLocation.SYSTEM_MODULES, jrt);
+ this.containers.put(loc, systemLocationWrapper);
+ }
+
+ public LocationWrapper getLocation(Location loc, String moduleName) {
+ if (loc instanceof LocationWrapper) {
+ loc = ((LocationWrapper) loc).loc;
+ }
+ LocationContainer forwarder = this.containers.get(loc);
+ if (forwarder != null) {
+ return forwarder.get(moduleName);
+ }
+ return null;
+ }
+
+ public Location getLocation(Location loc, Path path) {
+ LocationContainer forwarder = this.containers.get(loc);
+ if (forwarder != null) {
+ return forwarder.get(path);
+ }
+ return null;
+ }
+ public LocationContainer getLocation(Location location) {
+ return this.containers.get(location);
+ }
+ public void setLocation(Location location, Iterable<? extends Path> paths) {
+ LocationContainer container = this.containers.get(location);
+ if (container == null) {
+ container = new LocationContainer(location);
+ this.containers.put(location, container);
+ }
+ container.setPaths(paths);
+ }
+ public void setLocation(Location location, String moduleName, Iterable<? extends Path> paths) {
+ LocationWrapper wrapper = null;
+ LocationContainer container = this.containers.get(location);
+ if (container != null) {
+ wrapper = container.get(moduleName);
+ } else {
+ container = new LocationContainer(location);
+ this.containers.put(location, container);
+ }
+ if (wrapper == null) {
+ // module name can't be null
+ // TODO: Check unnamed modules can have their own module specific path - probably not
+ if (moduleName.equals("")) { //$NON-NLS-1$
+ wrapper = new LocationWrapper(location, location.isOutputLocation(), paths);
+ } else {
+ wrapper = new ModuleLocationWrapper(location, moduleName, location.isOutputLocation(), paths);
+ for (Path path : paths) {
+ container.put(path, wrapper);
+ }
+ }
+ } else {
+ wrapper.setPaths(paths);
+ }
+ container.put(moduleName, wrapper);
+ }
+ public Iterable<Set<Location>> listLocationsForModules(Location location) {
+ LocationContainer locationContainer = this.containers.get(location);
+ if (locationContainer == null) {
+ return Collections.emptyList();
+ }
+ Set<Location> set = new HashSet<>(locationContainer.locationNames.values());
+ List<Set<Location>> singletonList = Collections.singletonList(set);
+ return singletonList;
+ }
+
+ class LocationContainer extends LocationWrapper {
+
+ Map<String, LocationWrapper> locationNames;
+ Map<Path, LocationWrapper> locationPaths;
+ LocationContainer(Location loc) {
+ super();
+ this.loc = loc;
+ this.locationNames = new HashMap<>();
+ this.locationPaths = new HashMap<>();
+ }
+
+ LocationWrapper get(String moduleName) {
+ return this.locationNames.get(moduleName);
+ }
+
+ void put(String moduleName, LocationWrapper impl) {
+ this.locationNames.put(moduleName, impl);
+ this.paths = null;
+ }
+
+ void put(Path path, LocationWrapper impl) {
+ this.locationPaths.put(path, impl);
+ this.paths = null;
+ }
+
+ Location get(Path path) {
+ return this.locationPaths.get(path);
+ }
+
+ @Override
+ void setPaths(Iterable<? extends Path> paths) {
+ super.setPaths(paths);
+ this.clear();
+ }
+ @Override
+ Iterable<? extends Path> getPaths() {
+ if (this.paths != null)
+ return this.paths;
+ return this.locationPaths.keySet();
+ }
+
+ public void clear() {
+ this.locationNames.clear();
+ this.locationPaths.clear();
+ }
+ }
+
+ class SystemLocationContainer extends LocationContainer {
+
+ public SystemLocationContainer(Location loc, JrtFileSystem jrt) throws IOException {
+ super(loc);
+ jrt.initialize();
+ HashMap<String, Path> modulePathMap = jrt.modulePathMap;
+ Set<String> keySet = modulePathMap.keySet();
+ for (String mod : keySet) {
+ Path path = jrt.file.toPath();
+ ModuleLocationWrapper wrapper = new ModuleLocationWrapper(loc, mod, false,
+ Collections.singletonList(path));
+ this.locationNames.put(mod, wrapper);
+ this.locationPaths.put(path, wrapper);
+ }
+ }
+ }
+
+ class LocationWrapper implements Location {
+
+ Location loc;
+ boolean output;
+ List<? extends Path> paths;
+ LocationWrapper() {
+ }
+ public LocationWrapper(Location loc, boolean output, Iterable<? extends Path> paths) {
+ this.loc = loc;
+ this.output = output;
+ setPaths(paths);
+ }
+
+ @Override
+ public String getName() {
+ return this.loc.getName();
+ }
+
+ @Override
+ public boolean isOutputLocation() {
+ return this.output;
+ }
+
+ Iterable<? extends Path> getPaths() {
+ return this.paths;
+ }
+
+ void setPaths(Iterable<? extends Path> paths) {
+ if (paths == null) {
+ this.paths = null;
+ } else {
+ List<Path> newPaths = new ArrayList<>();
+ for (Path file : paths) {
+ newPaths.add(file);
+ }
+ this.paths = Collections.unmodifiableList(newPaths);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return this.loc.toString() + "[]"; //$NON-NLS-1$
+ }
+ }
+
+ class ModuleLocationWrapper extends LocationWrapper {
+ String modName;
+
+ public ModuleLocationWrapper(Location loc, String mod, boolean output, Iterable<? extends Path> paths) {
+ super(loc, output, paths);
+ this.modName = mod;
+ }
+
+ @Override
+ public String getName() {
+ return this.loc.getName() + "[" + this.modName + "]"; //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ @Override
+ public boolean isOutputLocation() {
+ return this.output;
+ }
+
+ @Override
+ Iterable<? extends Path> getPaths() {
+ return this.paths;
+ }
+
+ @Override
+ public String toString() {
+ return this.loc.toString() + "[" + this.modName + "]"; //$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
+ public void close() {
+ Collection<LocationContainer> values = this.containers.values();
+ for (LocationContainer locationContainer : values) {
+ locationContainer.clear();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/Options.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/Options.java
new file mode 100644
index 0000000..09d84cf
--- /dev/null
+++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/util/Options.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 IBM Corporation 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
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Class used to handle options in the EclipseFileManager and the EclipseCompiler
+ */
+public final class Options {
+ private static final Set<String> ZERO_ARGUMENT_OPTIONS;
+ private static final Set<String> ONE_ARGUMENT_OPTIONS;
+ private static final Set<String> FILE_MANAGER_OPTIONS;
+ static {
+ ZERO_ARGUMENT_OPTIONS = new HashSet<>();
+ Options.ZERO_ARGUMENT_OPTIONS.add("-progress");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-proceedOnError");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-proceedOnError:Fatal");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-time");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-v");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-version");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-showversion");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-deprecation");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-help");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-?");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-help:warn");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-?:warn");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-noExit");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-verbose");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-referenceInfo");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-inlineJSR");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-g");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-g:none");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-warn:none");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-preserveAllLocals");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-enableJavadoc");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-Xemacs");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-X");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-O");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-1.3");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-1.4");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-1.5");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-5");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-5.0");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-1.6");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-6");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-6.0");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-1.7");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-7");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-7.0");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-1.8");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-8");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-8.0");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-proc:only");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-proc:none");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-XprintProcessorInfo");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-XprintRounds");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-parameters");//$NON-NLS-1$
+ Options.ZERO_ARGUMENT_OPTIONS.add("-genericsignature");//$NON-NLS-1$
+
+ FILE_MANAGER_OPTIONS = new HashSet<>();
+ Options.FILE_MANAGER_OPTIONS.add("-bootclasspath");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-encoding");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-d");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-classpath");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-cp");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-sourcepath");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-extdirs");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-endorseddirs");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-s");//$NON-NLS-1$
+ Options.FILE_MANAGER_OPTIONS.add("-processorpath");//$NON-NLS-1$
+
+ ONE_ARGUMENT_OPTIONS = new HashSet<>();
+ Options.ONE_ARGUMENT_OPTIONS.addAll(Options.FILE_MANAGER_OPTIONS);
+ Options.ONE_ARGUMENT_OPTIONS.add("-log");//$NON-NLS-1$
+ Options.ONE_ARGUMENT_OPTIONS.add("-repeat");//$NON-NLS-1$
+ Options.ONE_ARGUMENT_OPTIONS.add("-maxProblems");//$NON-NLS-1$
+ Options.ONE_ARGUMENT_OPTIONS.add("-source");//$NON-NLS-1$
+ Options.ONE_ARGUMENT_OPTIONS.add("-target");//$NON-NLS-1$
+ Options.ONE_ARGUMENT_OPTIONS.add("-processor");//$NON-NLS-1$
+ Options.ONE_ARGUMENT_OPTIONS.add("-classNames");//$NON-NLS-1$
+ Options.ONE_ARGUMENT_OPTIONS.add("-properties");//$NON-NLS-1$
+
+ }
+ public static int processOptionsFileManager(String option) {
+ if (option == null) return -1;
+ if (Options.FILE_MANAGER_OPTIONS.contains(option)) {
+ return 1;
+ }
+ return -1;
+ }
+
+ public static int processOptions(String option) {
+ if (option == null) return -1;
+ if (Options.ZERO_ARGUMENT_OPTIONS.contains(option)) {
+ return 0;
+ }
+ if (Options.ONE_ARGUMENT_OPTIONS.contains(option)) {
+ return 1;
+ }
+ if (option.startsWith("-g")) { //$NON-NLS-1$
+ int length = option.length();
+ if (length > 3) {
+ StringTokenizer tokenizer =
+ new StringTokenizer(option.substring(3, option.length()), ",");//$NON-NLS-1$
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if ("vars".equals(token) || "lines".equals(token) || "source".equals(token)) {//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ continue;
+ }
+ return -1;
+ }
+ return 0;
+ }
+ return -1;
+ }
+ if (option.startsWith("-warn")) {//$NON-NLS-1$
+ int length = option.length();
+ if (length <= 6) {
+ return -1;
+ }
+ int warnTokenStart;
+ switch (option.charAt(6)) {
+ case '+' :
+ warnTokenStart = 7;
+ break;
+ case '-' :
+ warnTokenStart = 7;
+ break;
+ default:
+ warnTokenStart = 6;
+ }
+
+ StringTokenizer tokenizer =
+ new StringTokenizer(option.substring(warnTokenStart, option.length()), ","); //$NON-NLS-1$
+ int tokenCounter = 0;
+
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ tokenCounter++;
+ if (token.equals("allDeadCode")//$NON-NLS-1$
+ || token.equals("allDeprecation")//$NON-NLS-1$
+ || token.equals("allJav