* FORMATTER / Option to align type members of a type declaration on column
- * - option id: "org.eclipse.jdt.core.formatter.formatter.align_type_members_on_columns"
+ * - option id: "org.eclipse.jdt.core.formatter.align_type_members_on_columns"
* - possible values: { TRUE, FALSE }
* - default: FALSE
*
@@ -70,7 +70,49 @@ public class DefaultCodeFormatterConstants {
/**
*
- * FORMATTER / Option to align groups of members independently if they are separated by a certain number of blank lines
+ * FORMATTER / Option to align variable declarations on column
+ * - option id: "org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns"
+ * - possible values: { TRUE, FALSE }
+ * - default: FALSE
+ *
+ * @see #TRUE
+ * @see #FALSE
+ * @since 3.15
+ */
+ public static final String FORMATTER_ALIGN_VARIABLE_DECLARATIONS_ON_COLUMNS = JavaCore.PLUGIN_ID + ".formatter.align_variable_declarations_on_columns"; //$NON-NLS-1$
+
+ /**
+ *
+ * FORMATTER / Option to align assignment statements on column
+ * - option id: "org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns"
+ * - possible values: { TRUE, FALSE }
+ * - default: FALSE
+ *
+ * @see #TRUE
+ * @see #FALSE
+ * @since 3.15
+ */
+ public static final String FORMATTER_ALIGN_ASSIGNMENT_STATEMENTS_ON_COLUMNS = JavaCore.PLUGIN_ID + ".formatter.align_assignment_statements_on_columns"; //$NON-NLS-1$
+
+ /**
+ *
+ * FORMATTER / Option to use spaces when aligning members, independent of selected tabulation character
+ * - option id: "org.eclipse.jdt.core.formatter.align_with_spaces"
+ * - possible values: { TRUE, FALSE }
+ * - default: FALSE
+ *
+ * @see #TRUE
+ * @see #FALSE
+ * @since 3.15
+ */
+ public static final String FORMATTER_ALIGN_WITH_SPACES = JavaCore.PLUGIN_ID + ".formatter.align_with_spaces"; //$NON-NLS-1$
+
+ /**
+ *
+ * FORMATTER / Option to affect aligning on columns: groups of items are aligned independently
+ * if they are separated by at least the selected number of blank lines.
+ * Note: since 3.15 the 'fields' part is a (potentially misleading) residue as this option
+ * affects other types of aligning on columns as well.
* - option id: "org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines"
* - possible values: "<n>", where n is a positive integer
* - default: {@code Integer.MAX_VALUE}
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
index 2c8705a227..92f65e93c5 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
@@ -143,6 +143,9 @@ public static DefaultCodeFormatterOptions getJavaConventionsSettings() {
public int alignment_for_union_type_in_multicatch;
public boolean align_type_members_on_columns;
+ public boolean align_variable_declarations_on_columns;
+ public boolean align_assignment_statements_on_columns;
+ public boolean align_with_spaces;
public int align_fields_grouping_blank_lines;
public String brace_position_for_annotation_type_declaration;
@@ -484,7 +487,10 @@ public Map getMap() {
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_TYPE_PARAMETERS, getAlignment(this.alignment_for_type_parameters));
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_UNION_TYPE_IN_MULTICATCH, getAlignment(this.alignment_for_union_type_in_multicatch));
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_TYPE_MEMBERS_ON_COLUMNS, this.align_type_members_on_columns ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_VARIABLE_DECLARATIONS_ON_COLUMNS, this.align_variable_declarations_on_columns ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_ASSIGNMENT_STATEMENTS_ON_COLUMNS, this.align_assignment_statements_on_columns ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_FIELDS_GROUPING_BLANK_LINES, Integer.toString(this.align_fields_grouping_blank_lines));
+ options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_WITH_SPACES, this.align_with_spaces ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ANNOTATION_TYPE_DECLARATION, this.brace_position_for_annotation_type_declaration);
options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ANONYMOUS_TYPE_DECLARATION, this.brace_position_for_anonymous_type_declaration);
options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ARRAY_INITIALIZER, this.brace_position_for_array_initializer);
@@ -1045,6 +1051,14 @@ public void set(Map settings) {
if (alignTypeMembersOnColumnsOption != null) {
this.align_type_members_on_columns = DefaultCodeFormatterConstants.TRUE.equals(alignTypeMembersOnColumnsOption);
}
+ final Object alignVariableDeclarationsOnColumnsOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_VARIABLE_DECLARATIONS_ON_COLUMNS);
+ if (alignVariableDeclarationsOnColumnsOption != null) {
+ this.align_variable_declarations_on_columns = DefaultCodeFormatterConstants.TRUE.equals(alignVariableDeclarationsOnColumnsOption);
+ }
+ final Object alignAssignmentStatementsOnColumnsOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_ASSIGNMENT_STATEMENTS_ON_COLUMNS);
+ if (alignAssignmentStatementsOnColumnsOption != null) {
+ this.align_assignment_statements_on_columns = DefaultCodeFormatterConstants.TRUE.equals(alignAssignmentStatementsOnColumnsOption);
+ }
final Object alignGroupSepartionBlankLinesOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_FIELDS_GROUPING_BLANK_LINES);
if (alignTypeMembersOnColumnsOption != null) {
try {
@@ -1055,6 +1069,10 @@ public void set(Map settings) {
this.align_fields_grouping_blank_lines = Integer.MAX_VALUE;
}
}
+ final Object alignWithSpaces = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGN_WITH_SPACES);
+ if (alignWithSpaces != null) {
+ this.align_with_spaces = DefaultCodeFormatterConstants.TRUE.equals(alignWithSpaces);
+ }
final Object bracePositionForAnnotationTypeDeclarationOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ANNOTATION_TYPE_DECLARATION);
if (bracePositionForAnnotationTypeDeclarationOption != null) {
try {
@@ -2489,6 +2507,9 @@ public void setDefaultSettings() {
this.alignment_for_type_parameters = Alignment.M_NO_ALIGNMENT;
this.alignment_for_union_type_in_multicatch = Alignment.M_COMPACT_SPLIT;
this.align_type_members_on_columns = false;
+ this.align_variable_declarations_on_columns = false;
+ this.align_assignment_statements_on_columns = false;
+ this.align_with_spaces = false;
this.align_fields_grouping_blank_lines = Integer.MAX_VALUE;
this.brace_position_for_annotation_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
this.brace_position_for_anonymous_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
@@ -2806,6 +2827,9 @@ public void setJavaConventionsSettings() {
this.alignment_for_type_parameters = Alignment.M_NO_ALIGNMENT;
this.alignment_for_union_type_in_multicatch = Alignment.M_COMPACT_SPLIT;
this.align_type_members_on_columns = false;
+ this.align_variable_declarations_on_columns = false;
+ this.align_assignment_statements_on_columns = false;
+ this.align_with_spaces = false;
this.align_fields_grouping_blank_lines = Integer.MAX_VALUE;
this.brace_position_for_annotation_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
this.brace_position_for_anonymous_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
index 060df8dda3..28dfdc14c7 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
@@ -58,7 +58,7 @@ public TextEditsBuilder(String source, List regions, TokenManager token
this.options = options;
this.regions = adaptRegions(regions);
- this.alignChar = this.options.tab_char;
+ this.alignChar = this.options.align_with_spaces ? DefaultCodeFormatterOptions.SPACE : this.options.tab_char;
this.sourceLimit = source.length();
this.parent = null;
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/Aligner.java b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/Aligner.java
new file mode 100644
index 0000000000..47d33575ca
--- /dev/null
+++ b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/Aligner.java
@@ -0,0 +1,281 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2018 Mateusz Matela and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mateusz Matela - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
+ * Lars Vogel - Contributions for
+ * Bug 473178
+ *******************************************************************************/
+package org.eclipse.jdt.internal.formatter.linewrap;
+
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameEQUAL;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameIdentifier;
+import static java.util.stream.Collectors.toList;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.function.Function;
+import java.util.stream.IntStream;
+
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.Assignment;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.BodyDeclaration;
+import org.eclipse.jdt.core.dom.ExpressionStatement;
+import org.eclipse.jdt.core.dom.FieldDeclaration;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
+import org.eclipse.jdt.internal.formatter.Token;
+import org.eclipse.jdt.internal.formatter.TokenManager;
+import org.eclipse.jdt.internal.formatter.TokenTraverser;
+
+/** Implementation of the "Align items on columns" feature */
+public class Aligner {
+ private class PositionCounter extends TokenTraverser {
+ int stoppingIndex;
+ int maxPosition;
+
+ public PositionCounter() {
+ // nothing to do
+ }
+
+ @Override
+ protected boolean token(Token token, int index) {
+ if (index == this.stoppingIndex)
+ return false;
+ if (getLineBreaksBefore() > 0)
+ this.counter = Aligner.this.tm.getPositionInLine(index);
+ if (token.getAlign() > 0)
+ this.counter = token.getAlign();
+ this.counter += Aligner.this.tm.getLength(token, this.counter);
+ if (isSpaceAfter() && getLineBreaksAfter() == 0)
+ this.counter++;
+ this.maxPosition = Math.max(this.maxPosition, this.counter);
+ return true;
+ }
+
+ public int findMaxPosition(int fromIndex, int toIndex) {
+ this.counter = Aligner.this.tm.getPositionInLine(fromIndex);
+ this.stoppingIndex = toIndex;
+ this.maxPosition = 0;
+ Aligner.this.tm.traverse(fromIndex, this);
+ return this.maxPosition;
+ }
+ }
+
+ @FunctionalInterface
+ private interface AlignIndexFinder {
+ Optional findIndex(N node);
+ }
+
+ private final List> alignGroups = new ArrayList<>();
+
+ private final DefaultCodeFormatterOptions options;
+
+ final TokenManager tm;
+
+ public Aligner(TokenManager tokenManager, DefaultCodeFormatterOptions options) {
+ this.tm = tokenManager;
+ this.options = options;
+ }
+
+ public void handleAlign(List bodyDeclarations) {
+ if (!this.options.align_type_members_on_columns)
+ return;
+ List> fieldGroups = toAlignGroups(bodyDeclarations,
+ n -> optionalCast(n, FieldDeclaration.class));
+ this.alignGroups.addAll(fieldGroups);
+
+ AlignIndexFinder nameFinder = fd -> findName(
+ (VariableDeclarationFragment) fd.fragments().get(0));
+ fieldGroups.forEach(fg -> alignNodes(fg, nameFinder));
+
+ AlignIndexFinder assignFinder = fd -> findAssign(
+ (VariableDeclarationFragment) fd.fragments().get(0));
+ fieldGroups.forEach(fg -> alignNodes(fg, assignFinder));
+ }
+
+ public void handleAlign(Block block) {
+ List statements = block.statements();
+ if (this.options.align_variable_declarations_on_columns)
+ alignDeclarations(statements);
+ if (this.options.align_assignment_statements_on_columns)
+ alignAssignmentStatements(statements);
+ }
+
+ private void alignDeclarations(List statements) {
+ List> variableGroups = toAlignGroups(statements,
+ n -> optionalCast(n, VariableDeclarationStatement.class));
+ this.alignGroups.addAll(variableGroups);
+
+ AlignIndexFinder nameFinder = vd -> findName(
+ (VariableDeclarationFragment) vd.fragments().get(0));
+ variableGroups.forEach(vg -> alignNodes(vg, nameFinder));
+
+ AlignIndexFinder assignFinder = vd -> findAssign(
+ (VariableDeclarationFragment) vd.fragments().get(0));
+ variableGroups.forEach(vg -> alignNodes(vg, assignFinder));
+ }
+
+ private void alignAssignmentStatements(List statements) {
+ List> assignmentGroups = toAlignGroups(statements,
+ n -> optionalCast(n, ExpressionStatement.class)
+ .filter(es -> es.getExpression() instanceof Assignment));
+ this.alignGroups.addAll(assignmentGroups);
+
+ AlignIndexFinder assignFinder = es -> {
+ Assignment a = (Assignment) es.getExpression();
+ int operatorIndex = this.tm.firstIndexBefore(a.getRightHandSide(), -1);
+ while (this.tm.get(operatorIndex).isComment())
+ operatorIndex--;
+ return Optional.of(operatorIndex);
+ };
+ assignmentGroups.forEach(ag -> alignNodes(ag, assignFinder));
+
+ if (this.options.align_with_spaces || this.options.tab_char != DefaultCodeFormatterOptions.TAB) {
+ // align assign operators on their right side (e.g. +=, >>=)
+ for (List group : assignmentGroups) {
+ List assignTokens = group.stream()
+ .map(assignFinder::findIndex)
+ .filter(Optional::isPresent)
+ .map(o -> this.tm.get(o.get()))
+ .collect(toList());
+ int maxWidth = assignTokens.stream().mapToInt(Token::countChars).max().orElse(0);
+ for (Token token : assignTokens)
+ token.setAlign(token.getAlign() + maxWidth - token.countChars());
+ }
+ }
+ }
+
+ private Optional optionalCast(ASTNode node, Class c) {
+ return Optional.of(node).filter(c::isInstance).map(c::cast);
+ }
+
+ private Optional findName(VariableDeclarationFragment fragment) {
+ int nameIndex = this.tm.firstIndexIn(fragment.getName(), TokenNameIdentifier);
+ return Optional.of(nameIndex);
+ }
+
+ private Optional findAssign(VariableDeclarationFragment fragment) {
+ return Optional.ofNullable(fragment.getInitializer())
+ .map(i -> this.tm.firstIndexBefore(i, TokenNameEQUAL));
+ }
+
+ private List> toAlignGroups(List extends ASTNode> nodes,
+ Function> nodeConverter) {
+ List> result = new ArrayList<>();
+ List alignGroup = new ArrayList<>();
+ N previous = null;
+ for (ASTNode node : nodes) {
+ Optional converted = nodeConverter.apply(node);
+ if (converted.isPresent()) {
+ if (isNewGroup(node, previous)) {
+ result.add(alignGroup);
+ alignGroup = new ArrayList<>();
+ }
+ alignGroup.add(converted.get());
+ }
+ previous = converted.orElse(null);
+ }
+ result.add(alignGroup);
+ result.removeIf(l -> l.size() < 2);
+ return result;
+ }
+
+ private boolean isNewGroup(ASTNode node, ASTNode previousNode) {
+ if (previousNode == null)
+ return true;
+ int lineBreaks = 0;
+ int from = this.tm.lastIndexIn(previousNode, -1);
+ int to = this.tm.firstIndexIn(node, -1);
+ Token previousToken = this.tm.get(from);
+ for (int i = from + 1; i <= to; i++) {
+ Token token = this.tm.get(i);
+ lineBreaks += Math.min(this.tm.countLineBreaksBetween(previousToken, token),
+ this.options.number_of_empty_lines_to_preserve + 1);
+ previousToken = token;
+ }
+ return lineBreaks > this.options.align_fields_grouping_blank_lines;
+ }
+
+ private void alignNodes(List alignGroup, AlignIndexFinder tokenFinder) {
+ int[] tokenIndexes = alignGroup.stream()
+ .map(tokenFinder::findIndex)
+ .filter(Optional::isPresent)
+ .mapToInt(Optional::get).toArray();
+ OptionalInt maxPosition = IntStream.of(tokenIndexes).map(this.tm::getPositionInLine).max();
+ if (maxPosition.isPresent()) {
+ int align = normalizedAlign(maxPosition.getAsInt());
+ for (int tokenIndex : tokenIndexes)
+ this.tm.get(tokenIndex).setAlign(align);
+ }
+ }
+
+ public void alignComments() {
+ boolean alignLineComments = !this.options.comment_preserve_white_space_between_code_and_line_comments;
+ PositionCounter positionCounter = new PositionCounter();
+ // align comments after field declarations
+ for (List extends ASTNode> alignGroup : this.alignGroups) {
+ int maxCommentAlign = 0;
+ for (ASTNode node : alignGroup) {
+ int firstIndexInLine = findFirstTokenInLine(node);
+ int lastIndex = this.tm.lastIndexIn(node, -1) + 1;
+ maxCommentAlign = Math.max(maxCommentAlign,
+ positionCounter.findMaxPosition(firstIndexInLine, lastIndex));
+ }
+ maxCommentAlign = normalizedAlign(maxCommentAlign);
+
+ for (ASTNode node : alignGroup) {
+ int firstIndexInLine = findFirstTokenInLine(node);
+ int lastIndex = this.tm.lastIndexIn(node, -1);
+ lastIndex = Math.min(lastIndex, this.tm.size() - 2);
+ for (int i = firstIndexInLine; i <= lastIndex; i++) {
+ Token token = this.tm.get(i);
+ Token next = this.tm.get(i + 1);
+ boolean lineBreak = token.getLineBreaksAfter() > 0 || next.getLineBreaksBefore() > 0;
+ if (lineBreak) {
+ if (token.tokenType == TokenNameCOMMENT_BLOCK) {
+ token.setAlign(maxCommentAlign);
+ } else if (alignLineComments) {
+ this.tm.addNLSAlignIndex(i, maxCommentAlign);
+ }
+ } else if (next.tokenType == TokenNameCOMMENT_LINE && alignLineComments
+ || (next.tokenType == TokenNameCOMMENT_BLOCK && i == lastIndex)) {
+ next.setAlign(maxCommentAlign);
+ }
+ }
+ }
+ }
+ }
+
+ private int findFirstTokenInLine(ASTNode node) {
+ if (node instanceof FieldDeclaration) {
+ int typeIndex = this.tm.firstIndexIn(((FieldDeclaration) node).getType(), -1);
+ return this.tm.findFirstTokenInLine(typeIndex);
+ }
+ if (node instanceof VariableDeclarationStatement) {
+ int typeIndex = this.tm.firstIndexIn(((VariableDeclarationStatement) node).getType(), -1);
+ return this.tm.findFirstTokenInLine(typeIndex);
+ }
+ if (node instanceof ExpressionStatement) {
+ return this.tm.firstIndexIn(node, -1);
+ }
+ throw new IllegalArgumentException(node.getClass().getName());
+ }
+
+ private int normalizedAlign(int desiredAlign) {
+ if (this.options.align_with_spaces)
+ return desiredAlign;
+ return this.tm.toIndent(desiredAlign, false);
+ }
+}
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/FieldAligner.java b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/FieldAligner.java
deleted file mode 100644
index 9af0fab33c..0000000000
--- a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/FieldAligner.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014, 2016 Mateusz Matela and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Mateusz Matela - [formatter] Formatter does not format Java code correctly, especially when max line width is set - https://bugs.eclipse.org/303519
- * Lars Vogel - Contributions for
- * Bug 473178
- *******************************************************************************/
-package org.eclipse.jdt.internal.formatter.linewrap;
-
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameEQUAL;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameIdentifier;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jdt.core.dom.BodyDeclaration;
-import org.eclipse.jdt.core.dom.FieldDeclaration;
-import org.eclipse.jdt.core.dom.SimpleName;
-import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
-import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
-import org.eclipse.jdt.internal.formatter.Token;
-import org.eclipse.jdt.internal.formatter.TokenManager;
-import org.eclipse.jdt.internal.formatter.TokenTraverser;
-
-/** Implementation of the "Align fields on columns" feature */
-public class FieldAligner {
- private class PositionCounter extends TokenTraverser {
- int stoppingIndex;
- int maxPosition;
-
- public PositionCounter() {
- // nothing to do
- }
-
- @Override
- protected boolean token(Token token, int index) {
- if (index == this.stoppingIndex)
- return false;
- if (getLineBreaksBefore() > 0)
- this.counter = FieldAligner.this.tm.getPositionInLine(index);
- if (token.getAlign() > 0)
- this.counter = token.getAlign();
- this.counter += FieldAligner.this.tm.getLength(token, this.counter);
- if (isSpaceAfter() && getLineBreaksAfter() == 0)
- this.counter++;
- this.maxPosition = Math.max(this.maxPosition, this.counter);
- return true;
- }
-
- public int findMaxPosition(int fromIndex, int toIndex) {
- this.counter = FieldAligner.this.tm.getPositionInLine(fromIndex);
- this.stoppingIndex = toIndex;
- this.maxPosition = 0;
- FieldAligner.this.tm.traverse(fromIndex, this);
- return this.maxPosition;
- }
- }
-
- private final List> fieldAlignGroups = new ArrayList<>();
-
- private final DefaultCodeFormatterOptions options;
-
- final TokenManager tm;
-
- public FieldAligner(TokenManager tokenManager, DefaultCodeFormatterOptions options) {
- this.tm = tokenManager;
- this.options = options;
- }
-
- public void handleAlign(List bodyDeclarations) {
- if (!this.options.align_type_members_on_columns)
- return;
- ArrayList alignGroup = new ArrayList<>();
- BodyDeclaration previous = null;
- for (BodyDeclaration declaration : bodyDeclarations) {
- if (declaration instanceof FieldDeclaration) {
- if (isNewGroup(declaration, previous)) {
- alignFields(alignGroup);
- alignGroup = new ArrayList<>();
- }
- alignGroup.add((FieldDeclaration) declaration);
- }
- previous = declaration;
- }
- alignFields(alignGroup);
- }
-
- private boolean isNewGroup(BodyDeclaration declaration, BodyDeclaration previousDeclaration) {
- if (!(previousDeclaration instanceof FieldDeclaration))
- return true;
- int lineBreaks = 0;
- int from = this.tm.lastIndexIn(previousDeclaration, -1);
- int to = this.tm.firstIndexIn(declaration, -1);
- Token previous = this.tm.get(from);
- for (int i = from + 1; i <= to; i++) {
- Token token = this.tm.get(i);
- lineBreaks += Math.min(this.tm.countLineBreaksBetween(previous, token),
- this.options.number_of_empty_lines_to_preserve + 1);
- previous = token;
- }
- return lineBreaks > this.options.align_fields_grouping_blank_lines;
- }
-
- private void alignFields(ArrayList alignGroup) {
- if (alignGroup.size() < 2)
- return;
- this.fieldAlignGroups.add(alignGroup);
-
- int maxNameAlign = 0;
- for (FieldDeclaration declaration : alignGroup) {
- List fragments = declaration.fragments();
- SimpleName fieldName = fragments.get(0).getName();
- int nameIndex = this.tm.firstIndexIn(fieldName, TokenNameIdentifier);
- int positionInLine = this.tm.getPositionInLine(nameIndex);
- maxNameAlign = Math.max(maxNameAlign, positionInLine);
- }
- maxNameAlign = this.tm.toIndent(maxNameAlign, false);
-
- int maxAssignAlign = 0;
- for (FieldDeclaration declaration : alignGroup) {
- List fragments = declaration.fragments();
- VariableDeclarationFragment fragment = fragments.get(0);
- int nameIndex = this.tm.firstIndexIn(fragment.getName(), TokenNameIdentifier);
- Token nameToken = this.tm.get(nameIndex);
-
- nameToken.setAlign(maxNameAlign);
-
- if (fragment.getInitializer() != null) {
- int equalIndex = this.tm.firstIndexAfter(fragment.getName(), TokenNameEQUAL);
- int positionInLine = this.tm.getPositionInLine(equalIndex);
- maxAssignAlign = Math.max(maxAssignAlign, positionInLine);
- }
- }
- maxAssignAlign = this.tm.toIndent(maxAssignAlign, false);
-
- for (FieldDeclaration declaration : alignGroup) {
- List fragments = declaration.fragments();
- VariableDeclarationFragment fragment = fragments.get(0);
- if (fragment.getInitializer() != null) {
- int assingIndex = this.tm.firstIndexAfter(fragment.getName(), TokenNameEQUAL);
- Token assignToken = this.tm.get(assingIndex);
- assignToken.setAlign(maxAssignAlign);
- }
- }
- }
-
- public void alignComments() {
- if (this.fieldAlignGroups.isEmpty())
- return;
- boolean alignLineComments = !this.options.comment_preserve_white_space_between_code_and_line_comments;
- PositionCounter positionCounter = new PositionCounter();
- // align comments after field declarations
- for (List alignGroup : this.fieldAlignGroups) {
- int maxCommentAlign = 0;
- for (FieldDeclaration declaration : alignGroup) {
- int typeIndex = this.tm.firstIndexIn(declaration.getType(), -1);
- int firstIndexInLine = this.tm.findFirstTokenInLine(typeIndex);
- int lastIndex = this.tm.lastIndexIn(declaration, -1) + 1;
- maxCommentAlign = Math.max(maxCommentAlign,
- positionCounter.findMaxPosition(firstIndexInLine, lastIndex));
- }
- maxCommentAlign = this.tm.toIndent(maxCommentAlign, false);
-
- for (FieldDeclaration declaration : alignGroup) {
- int typeIndex = this.tm.firstIndexIn(declaration.getType(), -1);
- int firstIndexInLine = this.tm.findFirstTokenInLine(typeIndex);
- int lastIndex = this.tm.lastIndexIn(declaration, -1);
- lastIndex = Math.min(lastIndex, this.tm.size() - 2);
- for (int i = firstIndexInLine; i <= lastIndex; i++) {
- Token token = this.tm.get(i);
- Token next = this.tm.get(i + 1);
- boolean lineBreak = token.getLineBreaksAfter() > 0 || next.getLineBreaksBefore() > 0;
- if (lineBreak) {
- if (token.tokenType == TokenNameCOMMENT_BLOCK) {
- token.setAlign(maxCommentAlign);
- } else if (alignLineComments) {
- this.tm.addNLSAlignIndex(i, maxCommentAlign);
- }
- } else if (next.tokenType == TokenNameCOMMENT_LINE && alignLineComments
- || (next.tokenType == TokenNameCOMMENT_BLOCK && i == lastIndex)) {
- next.setAlign(maxCommentAlign);
- }
- }
- }
- }
- }
-}
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
index 9987d6a54b..1b684337fd 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
@@ -175,7 +175,7 @@ public int getIdentifierIndex(TokenManager tm) {
final DefaultCodeFormatterOptions options;
final int kind;
- final FieldAligner fieldAligner;
+ final Aligner aligner;
int importsStart = -1, importsEnd = -1;
@@ -197,7 +197,7 @@ public WrapPreparator(TokenManager tokenManager, DefaultCodeFormatterOptions opt
this.options = options;
this.kind = kind;
- this.fieldAligner = new FieldAligner(this.tm, this.options);
+ this.aligner = new Aligner(this.tm, this.options);
}
@Override
@@ -258,20 +258,20 @@ public boolean visit(TypeDeclaration node) {
prepareElementsList(node.typeParameters(), TokenNameCOMMA, TokenNameLESS);
handleWrap(this.options.alignment_for_type_parameters);
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@Override
public boolean visit(AnnotationTypeDeclaration node) {
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@Override
public boolean visit(AnonymousClassDeclaration node) {
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@@ -367,7 +367,7 @@ public boolean visit(EnumDeclaration node) {
handleWrap(this.options.alignment_for_superinterfaces_in_enum_declaration, PREFERRED);
}
- this.fieldAligner.handleAlign(node.bodyDeclarations());
+ this.aligner.handleAlign(node.bodyDeclarations());
return true;
}
@@ -382,6 +382,12 @@ public boolean visit(EnumConstantDeclaration node) {
return true;
}
+ @Override
+ public boolean visit(Block node) {
+ this.aligner.handleAlign(node);
+ return true;
+ }
+
@Override
public boolean visit(MethodInvocation node) {
handleArguments(node.arguments(), this.options.alignment_for_arguments_in_method_invocation);
@@ -1075,7 +1081,7 @@ public void finishUp(ASTNode astRoot, List regions) {
preserveExistingLineBreaks();
applyBreaksOutsideRegions(regions);
new WrapExecutor(this.tm, this.options).executeWraps();
- this.fieldAligner.alignComments();
+ this.aligner.alignComments();
wrapComments();
fixEnumConstantIndents(astRoot);
}
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
index 561c6084a6..a38d4a4e29 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
@@ -14,8 +14,9 @@
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
@@ -68,7 +69,6 @@ public class JarPackageFragmentRoot extends PackageFragmentRoot {
boolean knownToBeModuleLess;
private boolean multiVersion;
- public String versionPath;
/**
* Constructs a package fragment root which is the root of the Java package directory hierarchy
@@ -96,8 +96,8 @@ protected JarPackageFragmentRoot(IResource resource, JavaProject project) {
@Override
protected boolean computeChildren(OpenableElementInfo info, IResource underlyingResource) throws JavaModelException {
final HashtableOfArrayToObject rawPackageInfo = new HashtableOfArrayToObject();
- final Set overridden = new HashSet<>();
- IJavaElement[] children;
+ final Map overridden = new HashMap<>();
+ IJavaElement[] children = NO_ELEMENTS;
try {
// always create the default package
rawPackageInfo.put(CharOperation.NO_STRINGS, new ArrayList[] { EMPTY_LIST, EMPTY_LIST });
@@ -139,19 +139,38 @@ protected boolean computeChildren(OpenableElementInfo info, IResource underlying
ZipFile jar = null;
try {
jar = getJar();
- String version = "META-INF/versions/" + projectCompliance + "/"; //$NON-NLS-1$//$NON-NLS-2$
- int versionPathLength = version.length();
+ String version = "META-INF/versions/"; //$NON-NLS-1$
+ List versions = new ArrayList<>();
if (projectLevel >= ClassFileConstants.JDK9 && jar.getEntry(version) != null) {
+ int earliestJavaVersion = ClassFileConstants.MAJOR_VERSION_9;
+ long latestJDK = CompilerOptions.releaseToJDKLevel(projectCompliance);
+ int latestJavaVer = (int) (latestJDK >> 16);
+
+ for(int i = latestJavaVer; i >= earliestJavaVersion; i--) {
+ String s = "" + + (i - 44); //$NON-NLS-1$
+ String versionPath = version + s;
+ if (jar.getEntry(versionPath) != null) {
+ versions.add(s);
+ }
+ }
+ }
+
+ String[] supportedVersions = versions.toArray(new String[versions.size()]);
+ if (supportedVersions.length > 0) {
this.multiVersion = true;
- this.versionPath = version;
}
- for (Enumeration e= jar.entries(); e.hasMoreElements();) {
- ZipEntry member= (ZipEntry) e.nextElement();
+ int length = version.length();
+ for (Enumeration extends ZipEntry> e= jar.entries(); e.hasMoreElements();) {
+ ZipEntry member= e.nextElement();
String name = member.getName();
- if (this.multiVersion && name.length() > versionPathLength && name.startsWith(version)) {
- name = name.substring(version.length());
- if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) {
- overridden.add(name);
+ if (this.multiVersion && name.length() > (length + 2) && name.startsWith(version)) {
+ int end = name.indexOf('/', length);
+ if (end >= name.length()) continue;
+ String versionPath = name.substring(0, end);
+ String ver = name.substring(length, end);
+ if(versions.contains(ver) && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) {
+ name = name.substring(end + 1);
+ overridden.put(name, versionPath);
}
}
initRawPackageInfo(rawPackageInfo, name, member.isDirectory(), CompilerOptions.versionFromJdkLevel(classLevel));
@@ -180,7 +199,6 @@ protected boolean computeChildren(OpenableElementInfo info, IResource underlying
throw new JavaModelException(e);
}
}
-
info.setChildren(children);
((JarPackageFragmentRootInfo) info).rawPackageInfo = rawPackageInfo;
((JarPackageFragmentRootInfo) info).overriddenClasses = overridden;
@@ -285,9 +303,8 @@ public String getClassFilePath(String classname) {
JarPackageFragmentRootInfo elementInfo;
try {
elementInfo = (JarPackageFragmentRootInfo) getElementInfo();
- if (elementInfo.overriddenClasses.contains(classname)) {
- return this.versionPath == null ? classname : this.versionPath + classname;
- }
+ String versionPath = elementInfo.overriddenClasses.get(classname);
+ return versionPath == null ? classname : versionPath + '/' + classname;
} catch (JavaModelException e) {
// move on
}
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
index 113c5bfb37..1aa3bdcc1d 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core;
-import java.util.Set;
+import java.util.Map;
import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
@@ -20,6 +20,6 @@
class JarPackageFragmentRootInfo extends PackageFragmentRootInfo {
// a map from package name (String[]) to a size-2 array of Array, the first element being the .class file names, and the second element being the non-Java resource names
HashtableOfArrayToObject rawPackageInfo;
- Set overriddenClasses;
+ Map overriddenClasses;
}
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
index a0b66c437d..314926d152 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
@@ -93,6 +93,8 @@ protected String readJarContent(final SimpleSet packageSet) {
String modInfo = null;
for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) {
String fileName = ((ZipEntry) e.nextElement()).getName();
+ if (fileName.startsWith("META-INF/")) //$NON-NLS-1$
+ continue;
if (modInfo == null) {
int folderEnd = fileName.lastIndexOf('/');
folderEnd += 1;
@@ -111,11 +113,9 @@ IModule initializeModule() {
try {
file = new ZipFile(this.zipFilename);
String releasePath = "META-INF/versions/" + this.compliance + '/' + IModule.MODULE_INFO_CLASS; //$NON-NLS-1$
- System.out.println("Reading for module from: " + this.zipFilename); //$NON-NLS-1$
ClassFileReader classfile = null;
try {
classfile = ClassFileReader.read(file, releasePath);
- System.out.println("Read classfile : " + classfile); //$NON-NLS-1$
} catch (Exception e) {
e.printStackTrace();
// move on to the default
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java
index d5954151de..9b03ee6e02 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java
@@ -2,7 +2,6 @@
import java.io.IOException;
import java.net.URI;
-import java.nio.file.DirectoryStream;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
@@ -12,12 +11,15 @@
import java.nio.file.Paths;
import java.nio.file.ProviderNotFoundException;
import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.function.Predicate;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
+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.classfmt.ExternalAnnotationDecorator;
@@ -25,6 +27,7 @@
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.IModule;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
@@ -32,36 +35,84 @@
public class ClasspathMultiReleaseJar extends ClasspathJar {
private java.nio.file.FileSystem fs = null;
Path releasePath = null;
+ Path rootPath = null;
+ Path[] supportedVersions;
- ClasspathMultiReleaseJar(IFile resource, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
+ ClasspathMultiReleaseJar(IFile resource, AccessRuleSet accessRuleSet, IPath externalAnnotationPath,
+ boolean isOnModulePath, String compliance) {
super(resource, accessRuleSet, externalAnnotationPath, isOnModulePath);
this.compliance = compliance;
initializeVersions();
}
- ClasspathMultiReleaseJar(String zipFilename, long lastModified, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
+ ClasspathMultiReleaseJar(String zipFilename, long lastModified, AccessRuleSet accessRuleSet,
+ IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
super(zipFilename, lastModified, accessRuleSet, externalAnnotationPath, isOnModulePath);
this.compliance = compliance;
initializeVersions();
}
- public ClasspathMultiReleaseJar(ZipFile zipFile, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
+ public ClasspathMultiReleaseJar(ZipFile zipFile, AccessRuleSet accessRuleSet, IPath externalAnnotationPath,
+ boolean isOnModulePath, String compliance) {
this(zipFile.getName(), accessRuleSet, externalAnnotationPath, isOnModulePath, compliance);
this.zipFile = zipFile;
this.closeZipFileAtEnd = true;
}
- public ClasspathMultiReleaseJar(String fileName, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) {
+ public ClasspathMultiReleaseJar(String fileName, AccessRuleSet accessRuleSet, IPath externalAnnotationPath,
+ boolean isOnModulePath, String compliance) {
this(fileName, 0, accessRuleSet, externalAnnotationPath, isOnModulePath, compliance);
if (externalAnnotationPath != null)
this.externalAnnotationPath = externalAnnotationPath.toString();
}
+
+ @Override
+ IModule initializeModule() {
+ IModule mod = null;
+ ZipFile file = null;
+ try {
+ file = new ZipFile(this.zipFilename);
+ ClassFileReader classfile = null;
+ try {
+ for (Path path : this.supportedVersions) {
+ classfile = ClassFileReader.read(file, path.toString() + '/' + IModule.MODULE_INFO_CLASS);
+ if (classfile != null)
+ break;
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ // move on to the default
+ }
+ if (classfile == null) {
+ classfile = ClassFileReader.read(file, IModule.MODULE_INFO_CLASS); // FIXME: use jar cache
+ }
+ if (classfile != null) {
+ mod = classfile.getModuleDeclaration();
+ }
+ } catch (ClassFormatException | IOException e) {
+ // do nothing
+ } finally {
+ try {
+ if (file != null)
+ file.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+ return mod;
+ }
+
private void initializeVersions() {
Path filePath = Paths.get(this.zipFilename);
if (Files.exists(filePath)) {
- URI uri = URI.create("jar:" + filePath.toUri()); //$NON-NLS-1$
+ URI uri = URI.create("jar:" + filePath.toUri()); //$NON-NLS-1$
try {
- this.fs = FileSystems.getFileSystem(uri);
+ try {
+ this.fs = FileSystems.getFileSystem(uri);
+ } catch (FileSystemNotFoundException e) {
+ // move on
+ }
if (this.fs == null) {
HashMap env = new HashMap<>();
this.fs = FileSystems.newFileSystem(uri, env);
@@ -71,75 +122,88 @@ private void initializeVersions() {
} catch (IOException e) {
// move on
}
- if (this.fs == null) {
- this.releasePath = null;
- } else {
- this.releasePath = this.fs.getPath("/", "META-INF", "versions", this.compliance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- if (!Files.exists(this.releasePath)) {
- this.releasePath = null;
- try {
- this.fs.close();
- } catch (IOException e) {
- // ignore
- }
+ if (this.fs == null)
+ return;
+ this.rootPath = this.fs.getPath("/"); //$NON-NLS-1$
+ int earliestJavaVersion = ClassFileConstants.MAJOR_VERSION_9;
+ long latestJDK = CompilerOptions.releaseToJDKLevel(this.compliance);
+ int latestJavaVer = (int) (latestJDK >> 16);
+ List versions = new ArrayList<>();
+ for (int i = latestJavaVer; i >= earliestJavaVersion; i--) {
+ Path path = this.fs.getPath("/", "META-INF", "versions", "" + (i - 44)); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ if (Files.exists(path)) {
+ versions.add(this.rootPath.relativize(path));
+ }
+ }
+ this.supportedVersions = versions.toArray(new Path[versions.size()]);
+ if (this.supportedVersions.length <= 0) {
+ try {
+ this.fs.close();
+ } catch (IOException e) {
+ // ignore
}
}
}
}
+
@Override
protected String readJarContent(final SimpleSet packageSet) {
String[] modInfo = new String[1];
modInfo[0] = super.readJarContent(packageSet);
try {
- if (this.releasePath != null && Files.exists(this.releasePath)) {
- // go through the packages
- try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) {
- for (final java.nio.file.Path subdir: stream) {
- Files.walkFileTree(subdir, new FileVisitor() {
- @Override
- public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs)
- throws IOException {
- return FileVisitResult.CONTINUE;
- }
- @Override
- public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs)
- throws IOException {
- Path p = ClasspathMultiReleaseJar.this.releasePath.relativize(file);
- addToPackageSet(packageSet, p.toString(), false);
- if (modInfo[0] == null) {
- if (p.getFileName().toString().equalsIgnoreCase(IModule.MODULE_INFO_CLASS)) {
- modInfo[0] = ClasspathMultiReleaseJar.this.releasePath.relativize(file).toString();
- }
- }
- return FileVisitResult.CONTINUE;
- }
+ for (Path path : this.supportedVersions) {
+ Path relativePath = this.rootPath.resolve(path);
+ Files.walkFileTree(path, new FileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs)
+ throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
- @Override
- public FileVisitResult visitFileFailed(java.nio.file.Path file, IOException exc) throws IOException {
- return FileVisitResult.CONTINUE;
+ @Override
+ public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs)
+ throws IOException {
+ Path p = relativePath.relativize(file);
+ addToPackageSet(packageSet, p.toString(), false);
+ if (modInfo[0] == null) {
+ if (p.getFileName().toString().equalsIgnoreCase(IModule.MODULE_INFO_CLASS)) {
+ modInfo[0] = relativePath.relativize(file).toString();
}
+ }
+ return FileVisitResult.CONTINUE;
+ }
- @Override
- public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc)
- throws IOException {
- return FileVisitResult.CONTINUE;
- }
- });
+ @Override
+ public FileVisitResult visitFileFailed(java.nio.file.Path file, IOException exc)
+ throws IOException {
+ return FileVisitResult.CONTINUE;
}
- }
+
+ @Override
+ public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc)
+ throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+ });
}
} catch (Exception e) {
// move on;
}
return modInfo[0];
}
+
@Override
- public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly, Predicate moduleNameFilter) {
- if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case
- if (this.releasePath != null) {
+ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName,
+ String qualifiedBinaryFileName, boolean asBinaryOnly, Predicate moduleNameFilter) {
+ if (!isPackage(qualifiedPackageName, moduleName))
+ return null; // most common case
+ for (Path path : this.supportedVersions) {
+ Path relativePath = this.rootPath.resolve(path);
try {
- Path path = this.releasePath.resolve(qualifiedPackageName).resolve(binaryFileName);
- byte[] content = Files.readAllBytes(path);
+ Path p = relativePath.resolve(qualifiedPackageName).resolve(binaryFileName);
+ if (!Files.exists(p))
+ continue;
+ byte[] content = Files.readAllBytes(p);
IBinaryType reader = null;
if (content != null) {
reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray());
@@ -152,8 +216,9 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa
classReader.moduleName = modName;
else
modName = classReader.moduleName;
- }
- String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
+ }
+ String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0,
+ qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
if (this.externalAnnotationPath != null) {
try {
if (this.annotationZipFile == null) {
@@ -173,14 +238,15 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa
}
if (this.accessRuleSet == null)
return new NameEnvironmentAnswer(reader, null, modName);
- return new NameEnvironmentAnswer(reader,
- this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()),
- modName);
+ return new NameEnvironmentAnswer(reader,
+ this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), modName);
}
} catch (IOException | ClassFormatException e) {
+ e.printStackTrace();
// treat as if class file is missing
}
}
- return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, asBinaryOnly, moduleNameFilter);
+ return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, asBinaryOnly,
+ moduleNameFilter);
}
}
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/readme.txt b/jdt-patch/e49/org.eclipse.jdt.core/readme.txt
index b3136f76ce..6549eb434d 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/readme.txt
+++ b/jdt-patch/e49/org.eclipse.jdt.core/readme.txt
@@ -1,2 +1,3 @@
2018-08-03: 3b0b35b (2018-09 M2)
2018-08-24: 88a2114 (2018-09 M3)
+2018-09-02: 987e180 (2018-09 RC1)
diff --git a/jdt-patch/e49/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java b/jdt-patch/e49/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
index d5e26b9bda..c783aab41d 100644
--- a/jdt-patch/e49/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
+++ b/jdt-patch/e49/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
@@ -74,7 +74,8 @@ private static BinaryTypeDescriptor createDescriptor(PackageFragment pkg, ClassF
String overridePath = root.getClassFilePath(entryName);
if (overridePath != entryName) {
entryName = overridePath;
- name = ((JarPackageFragmentRoot) root).versionPath + name;
+ String versionPath = overridePath.substring(0, overridePath.indexOf(entryName));
+ name = versionPath + name;
}
char[] fieldDescriptor = CharArrayUtils.concat(new char[] { 'L' },
name.toCharArray(), new char[] { ';' });