From e82cd2c49f33dc2da558eca41ef3a807b667b4f4 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Wed, 11 Sep 2024 14:45:28 -0400 Subject: [PATCH 01/15] Fix generate hashcode to add this expression when needed (#1636) - fix GenerateHashCodeEqualsOperation.createHashCodeMethod() to add this specifier for fields that match local variables generated - add new test to GenerateHashCodeEqualsTest - fixes #1560 --- .../GenerateHashCodeEqualsOperation.java | 4 +- .../source/GenerateHashCodeEqualsTest.java | 116 +++++++++++++++++- 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/GenerateHashCodeEqualsOperation.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/GenerateHashCodeEqualsOperation.java index a2521a0fd5f..f0b08ac4f25 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/GenerateHashCodeEqualsOperation.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/GenerateHashCodeEqualsOperation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -471,7 +471,7 @@ private MethodDeclaration createHashCodeMethod() throws CoreException { if (field.getType().isArray()) { body.statements().add(createAddArrayHashCode(field)); } else if (fUseJ7HashEquals) { - j7Invoc.arguments().add(fAst.newSimpleName(field.getName())); + j7Invoc.arguments().add(getThisAccessForHashCode(field.getName())); } else if (field.getType().isPrimitive()) { Statement[] sts= createAddSimpleHashCode(field.getType(), this::getThisAccessForHashCode, field.getName(), false); body.statements().addAll(Arrays.asList(sts)); diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GenerateHashCodeEqualsTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GenerateHashCodeEqualsTest.java index e41feb744b8..6ceee8b7fa4 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GenerateHashCodeEqualsTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GenerateHashCodeEqualsTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -2238,4 +2238,118 @@ public void arraysDeepEqualsIn15() throws Exception { ""; compareSource(expected, a.getSource()); } + + @Test + public void testIssue1560() throws Exception { + ICompilationUnit a= fPackageP.createCompilationUnit("A.java", + """ + package p; + + import java.util.Objects; + + public class A { + static class Parent { + + private int fieldA; + private String fieldB; + + @Override + public int hashCode() { + return Objects.hash(fieldA, fieldB); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Parent)) { + return false; + } + Parent other = (Parent) obj; + return fieldA == other.fieldA && Objects.equals(fieldB, other.fieldB); + } + } + + static class Child extends Parent { + + private String result; + + } + + } + """, true, null); + + IType[] allTypes= a.getAllTypes(); + IType childType= null; + for (IType type : allTypes) { + if (type.getElementName().equals("Child")) { + childType= type; + break; + } + } + IField[] fields= getFields(childType, new String[] { "result"} ); + runJ7Operation(childType, fields, false); + + String expected= """ + package p; + + import java.util.Objects; + + public class A { + static class Parent { + + private int fieldA; + private String fieldB; + + @Override + public int hashCode() { + return Objects.hash(fieldA, fieldB); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Parent)) { + return false; + } + Parent other = (Parent) obj; + return fieldA == other.fieldA && Objects.equals(fieldB, other.fieldB); + } + } + + static class Child extends Parent { + + private String result; + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Objects.hash(this.result); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + Child other = (Child) obj; + return Objects.equals(result, other.result); + } + + } + + } + """; + + compareSource(expected, a.getSource()); + + } } \ No newline at end of file From 65be1d3f04da8f3ff22701b3bf6a3bcaba7a52c8 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Wed, 11 Sep 2024 21:45:29 -0400 Subject: [PATCH 02/15] Add logic to useless return/continue cleanups to prevent logic change (#1640) - add logic to UselessContinueCleanUp and UselessReturnCleanUp so they do not remove a return or continue statement if it is in an if then and there is an else with a single statement and the user has also specified to reduce indentation - add new test to CleanUpTest - fixes #1638 --- .../jdt/ui/tests/quickfix/CleanUpTest.java | 66 +++++++++++++++++++ .../ui/fix/UselessContinueCleanUp.java | 12 +++- .../internal/ui/fix/UselessReturnCleanUp.java | 12 +++- 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java index 31334d36252..15138fb71bc 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java @@ -17109,6 +17109,72 @@ public void doNotRemoveContinueWithFollowingCode(List texts, boolean isV assertRefactoringHasNoChange(new ICompilationUnit[] { cu }); } + @Test + public void testIssue1638() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String input= """ + package test1; + + public class E1 { + public void doNotRemoveUselessReturn(boolean arg) { + if (arg) { + return; + } else { + System.out.println("here"); + } + } + + public void doNotRemoveUselessContinue(boolean arg) { + while (arg) { + arg = bar(); + if (arg) { + continue; + } else { + System.out.println("Hello World"); + } + } + } + + public boolean bar() { + return true; + } + } + """; + ICompilationUnit cu= pack1.createCompilationUnit("E1.java", input, false, null); + + enable(CleanUpConstants.REMOVE_USELESS_CONTINUE); + enable(CleanUpConstants.REMOVE_USELESS_RETURN); + enable(CleanUpConstants.REDUCE_INDENTATION); + + String output= """ + package test1; + + public class E1 { + public void doNotRemoveUselessReturn(boolean arg) { + if (arg) { + return; + } + System.out.println("here"); + } + + public void doNotRemoveUselessContinue(boolean arg) { + while (arg) { + arg = bar(); + if (arg) { + continue; + } + System.out.println("Hello World"); + } + } + + public boolean bar() { + return true; + } + } + """; + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { output }); + } + @Test public void testUnloopedWhile() throws Exception { // Given diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java index a11e66f25f9..43ec72c47df 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020 Fabrice TIERCELIN and others. + * Copyright (c) 2020, 2024 Fabrice TIERCELIN and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -150,6 +150,16 @@ private boolean isLastStatementInLoop(final Statement node) { return true; } + if (parent instanceof IfStatement ifStatement && ifStatement.getElseStatement() != null + && node.getLocationInParent() != IfStatement.ELSE_STATEMENT_PROPERTY) { + if (isEnabled(CleanUpConstants.REDUCE_INDENTATION)) { + Statement elseStatement= ifStatement.getElseStatement(); + if (!(elseStatement instanceof Block elseBlock) || elseBlock.statements().size() == 1) { + return false; + } + } + } + if (parent instanceof MethodDeclaration) { return false; } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java index e12306238c6..4f2ba0b1f8b 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020 Fabrice TIERCELIN and others. + * Copyright (c) 2020, 2024 Fabrice TIERCELIN and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -149,6 +149,16 @@ private boolean isLastStatement(final Statement node) { return false; } + if (parent instanceof IfStatement ifStatement && ifStatement.getElseStatement() != null + && node.getLocationInParent() != IfStatement.ELSE_STATEMENT_PROPERTY) { + if (isEnabled(CleanUpConstants.REDUCE_INDENTATION)) { + Statement elseStatement= ifStatement.getElseStatement(); + if (!(elseStatement instanceof Block elseBlock) || elseBlock.statements().size() == 1) { + return false; + } + } + } + if (parent instanceof Statement) { return isLastStatement((Statement) parent); } From 88b6f63d91c546293e04e4b3a505f5a97d6c0e6f Mon Sep 17 00:00:00 2001 From: Mickael Istria Date: Fri, 13 Sep 2024 21:40:44 +0200 Subject: [PATCH 03/15] Finer check to trigger cast when converting to methodRef (#1637) * Finer check to trigger cast when converting to methodRef In some cases (eg JDT-LS AnonymousClassCreationToLambdaTest.testConvertToLambda12 with Javac backend), a cast is needlessly added just because a method with same name exists. Also check the number of arguments to decide whether to add a cast or not. Co-authored-by: Jeff Johnston --- ...ConvertLambdaToMethodReferenceFixCore.java | 4 +- .../LambdaExpressionAndMethodRefFixCore.java | 4 +- .../corext/fix/LambdaExpressionsFixCore.java | 4 +- .../tests/quickfix/AssistQuickFixTest1d8.java | 53 ++++++++ .../jdt/ui/tests/quickfix/CleanUpTest1d8.java | 127 ++++++++++++++++++ 5 files changed, 189 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ConvertLambdaToMethodReferenceFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ConvertLambdaToMethodReferenceFixCore.java index 9a847531afb..63195b7986f 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ConvertLambdaToMethodReferenceFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ConvertLambdaToMethodReferenceFixCore.java @@ -372,7 +372,9 @@ private ASTNode castMethodRefIfNeeded(final CompilationUnitRewrite cuRewrite, AS while (parentTypeBinding != null) { IMethodBinding[] parentTypeMethods= parentTypeBinding.getDeclaredMethods(); for (IMethodBinding parentTypeMethod : parentTypeMethods) { - if (parentTypeMethod.getName().equals(parentBinding.getName()) && !parentTypeMethod.isEqualTo(parentBinding)) { + if (parentTypeMethod.getName().equals(parentBinding.getName()) + && parentTypeMethod.getParameterTypes().length == args.size() + && !parentTypeMethod.isEqualTo(parentBinding)) { needCast= true; break; } diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionAndMethodRefFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionAndMethodRefFixCore.java index 15bdc0ea007..7e57142be1f 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionAndMethodRefFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionAndMethodRefFixCore.java @@ -479,7 +479,9 @@ private ASTNode castMethodRefIfNeeded(final CompilationUnitRewrite cuRewrite, AS while (parentTypeBinding != null) { IMethodBinding[] parentTypeMethods= parentTypeBinding.getDeclaredMethods(); for (IMethodBinding parentTypeMethod : parentTypeMethods) { - if (parentTypeMethod.getName().equals(parentBinding.getName()) && !parentTypeMethod.isEqualTo(parentBinding)) { + if (parentTypeMethod.getName().equals(parentBinding.getName()) + && parentTypeMethod.getParameterTypes().length == args.size() + && !parentTypeMethod.isEqualTo(parentBinding)) { needCast= true; break; } diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java index bca7b84ef48..844c6ce9b1d 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java @@ -974,7 +974,9 @@ private Expression castMethodRefIfNeeded(final CompilationUnitRewrite cuRewrite, while (parentTypeBinding != null) { IMethodBinding[] parentTypeMethods= parentTypeBinding.getDeclaredMethods(); for (IMethodBinding parentTypeMethod : parentTypeMethods) { - if (parentTypeMethod.getName().equals(parentBinding.getName()) && !parentTypeMethod.isEqualTo(parentBinding)) { + if (parentTypeMethod.getName().equals(parentBinding.getName()) + && parentTypeMethod.getParameterTypes().length == args.size() + && !parentTypeMethod.isEqualTo(parentBinding)) { needCast= true; break; } diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java index bb50449a157..8a2cf14b372 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java @@ -5349,6 +5349,59 @@ void test() { assertExpectedExistInProposals(proposals, new String[] { expected1 }); } + @Test + public void testIssue1047_5() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String str= """ + package test1; + import java.util.function.Supplier; + + public class E1 { + public static void func( String ... args) { + } + private void called( Supplier r ) { + } + + } + """; + pack1.createCompilationUnit("E1.java", str, false, null); + + String str1= """ + package test1; + + public class E extends E1 { + + void called( Runnable r, int i ) { + } + + void test() { + called(() -> E1.func(), 3); + } + } + """; + ICompilationUnit cu= pack1.createCompilationUnit("E.java", str1, false, null); + + int offset= str1.indexOf("func()"); + AssistContext context= getCorrectionContext(cu, offset, 0); + assertNoErrors(context); + List proposals= collectAssists(context, false); + assertCorrectLabels(proposals); + String expected1= """ + package test1; + + public class E extends E1 { + + void called( Runnable r, int i ) { + } + + void test() { + called(E1::func, 3); + } + } + """; + assertExpectedExistInProposals(proposals, new String[] { expected1 }); + } + @Test public void testFixParenthesesInLambdaExpressionAdd() throws Exception { IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java index 6d3073e17ff..62f2a0eaf1e 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java @@ -959,6 +959,77 @@ default void m() { assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { original }, null); } + @Test + public void testConvertToLambdaAmbiguous04() throws Exception { + IPackageFragment pack1= fSourceFolder.createPackageFragment("test", false, null); + String sample= """ + package test; + public interface E { + default void m() { + bar(0, new FI() { + @Override + public int foo(int x) { + return x++; + } + }, 3); + baz(0, new ZI() { + @Override + public int zoo() { + return 1; + } + }); + } + + void bar(int i, FI fi, int j); + void bar(int i, FV fv); + + void baz(int i, ZI zi); + void baz(int i, ZV zv); + } + + @FunctionalInterface interface FI { int foo(int a); } + @FunctionalInterface interface FV { void foo(int a); } + + @FunctionalInterface interface ZI { int zoo(); } + @FunctionalInterface interface ZV { void zoo(); } + """; + String original= sample; + ICompilationUnit cu1= pack1.createCompilationUnit("E.java", original, false, null); + + enable(CleanUpConstants.CONVERT_FUNCTIONAL_INTERFACES); + enable(CleanUpConstants.USE_LAMBDA); + + sample= """ + package test; + public interface E { + default void m() { + bar(0, x -> x++, 3); + baz(0, () -> 1); + } + + void bar(int i, FI fi, int j); + void bar(int i, FV fv); + + void baz(int i, ZI zi); + void baz(int i, ZV zv); + } + + @FunctionalInterface interface FI { int foo(int a); } + @FunctionalInterface interface FV { void foo(int a); } + + @FunctionalInterface interface ZI { int zoo(); } + @FunctionalInterface interface ZV { void zoo(); } + """; + String expected1= sample; + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }, null); + + disable(CleanUpConstants.USE_LAMBDA); + enable(CleanUpConstants.USE_ANONYMOUS_CLASS_CREATION); + + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { original }, null); + } + @Test public void testConvertToLambdaConflictingNames() throws Exception { IPackageFragment pack1= fSourceFolder.createPackageFragment("test", false, null); @@ -2201,6 +2272,62 @@ void test() { new HashSet<>(Arrays.asList(MultiFixMessages.LambdaExpressionAndMethodRefCleanUp_description))); } + @Test + public void testIssue1047_5() throws Exception { + // Given + IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null); + String given1= """ + import java.util.function.Supplier; + + public class E1 { + + static void func( String ... args) { + + } + void called( Supplier r ) { + + } + } + """; // + ICompilationUnit cu1= pack.createCompilationUnit("E1.java", given1, false, null); + + String given= """ + import java.util.function.Supplier; + + public class E extends E1 { + + void called( Runnable r, int i ) { + + } + void test() { + called(() -> E1.func(), 3); + } + } + """; // + + String expected= """ + import java.util.function.Supplier; + + public class E extends E1 { + + void called( Runnable r, int i ) { + + } + void test() { + called(E1::func, 3); + } + } + """; // + // When + ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null); + enable(CleanUpConstants.SIMPLIFY_LAMBDA_EXPRESSION_AND_METHOD_REF); + + // Then + assertNotEquals("The class must be changed", given, expected); + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu, cu1 }, new String[] { expected, given1 }, + new HashSet<>(Arrays.asList(MultiFixMessages.LambdaExpressionAndMethodRefCleanUp_description))); + } + @Test public void testBug579393() throws Exception { // Given From 7881cea0bab4363feca6dea51cec018f55240540 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Fri, 13 Sep 2024 16:16:23 -0400 Subject: [PATCH 04/15] Tweak new logic for useless return or useless continue clean-up (#1645) - do not check how many statements are in the else clause, just that there is an else clause --- .../org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java | 2 +- .../org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java index 43ec72c47df..083887c81c6 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessContinueCleanUp.java @@ -154,7 +154,7 @@ private boolean isLastStatementInLoop(final Statement node) { && node.getLocationInParent() != IfStatement.ELSE_STATEMENT_PROPERTY) { if (isEnabled(CleanUpConstants.REDUCE_INDENTATION)) { Statement elseStatement= ifStatement.getElseStatement(); - if (!(elseStatement instanceof Block elseBlock) || elseBlock.statements().size() == 1) { + if (elseStatement != null) { return false; } } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java index 4f2ba0b1f8b..7352ead23bf 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UselessReturnCleanUp.java @@ -153,7 +153,7 @@ private boolean isLastStatement(final Statement node) { && node.getLocationInParent() != IfStatement.ELSE_STATEMENT_PROPERTY) { if (isEnabled(CleanUpConstants.REDUCE_INDENTATION)) { Statement elseStatement= ifStatement.getElseStatement(); - if (!(elseStatement instanceof Block elseBlock) || elseBlock.statements().size() == 1) { + if (elseStatement != null) { return false; } } From dd3a576db0017fde4087352938eb4e5cc2e13156 Mon Sep 17 00:00:00 2001 From: mvm-sap <56332955+mvm-sap@users.noreply.github.com> Date: Tue, 17 Sep 2024 22:09:03 +0530 Subject: [PATCH 05/15] Removing unnecessary themeing extension for breadcrumb (light theme) (#1577) --- .../css/e4-light_jdt_syntaxhighlighting.css | 22 ------------------- org.eclipse.jdt.ui/plugin.xml | 6 ----- 2 files changed, 28 deletions(-) delete mode 100644 org.eclipse.jdt.ui/css/e4-light_jdt_syntaxhighlighting.css diff --git a/org.eclipse.jdt.ui/css/e4-light_jdt_syntaxhighlighting.css b/org.eclipse.jdt.ui/css/e4-light_jdt_syntaxhighlighting.css deleted file mode 100644 index f73017e32c0..00000000000 --- a/org.eclipse.jdt.ui/css/e4-light_jdt_syntaxhighlighting.css +++ /dev/null @@ -1,22 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 SAP SE 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 - *******************************************************************************/ - -#BreadcrumbComposite > Composite, -#BreadcrumbItemComposite, -#BreadcrumbItemDetailComposite, -#BreadcrumbItemDetailTextComposite, -#BreadcrumbItemDetailImageComposite, -#BreadcrumbItemDetailTextLabel, -#BreadcrumbItemDetailImageLabel, -#BreadcrumbItemDropDownToolBar -{ - background-color:COLOR-WIDGET-LIGHT-SHADOW;; -} \ No newline at end of file diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml index 2a975350cd8..450a620e65c 100644 --- a/org.eclipse.jdt.ui/plugin.xml +++ b/org.eclipse.jdt.ui/plugin.xml @@ -6986,12 +6986,6 @@ refid="org.eclipse.e4.ui.css.theme.e4_dark"> - - - - Date: Tue, 17 Sep 2024 07:21:30 +0200 Subject: [PATCH 06/15] JUnitLaunch: fix ArrayIndexOutOfBoundsException #1651 no types below package-info.java https://github.com/eclipse-jdt/eclipse.jdt.ui/issues/1651 --- .../junit/launcher/JUnitLaunchConfigurationDelegate.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java index 0d136823008..e97ac908a33 100644 --- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java +++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java @@ -540,8 +540,10 @@ private List enumerateTypesInPackage(IPackageFragmentRoot packageFragment for (IJavaElement ije : children) { if (ije instanceof ICompilationUnit icu) { IType[] allTypes= icu.getAllTypes(); - IType topLevelType = allTypes[0]; - typesToExecute.add(topLevelType); + for (IType topLevelType: allTypes) { + typesToExecute.add(topLevelType); + break; // just one + } } } } From 754e3fb1b596e6690545c806cb075b328d7fd77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=8A?= =?UTF-8?q?=D1=80=20=D0=9A=D1=83=D1=80=D1=82=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 17 Sep 2024 18:26:43 +0300 Subject: [PATCH 07/15] Move away of deprecated org.eclipse.jface.internal.text.html.SubstitutionTextReader --- .../internal/ui/text/javadoc/JavaDoc2HTMLTextReader.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDoc2HTMLTextReader.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDoc2HTMLTextReader.java index 34fd3dbf19d..bf3965aa659 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDoc2HTMLTextReader.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDoc2HTMLTextReader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -22,8 +22,9 @@ import java.util.Iterator; import java.util.List; +import org.eclipse.text.readers.SubstitutionReader; + import org.eclipse.jface.internal.text.html.HTMLPrinter; -import org.eclipse.jface.internal.text.html.SubstitutionTextReader; import org.eclipse.jdt.core.dom.TagElement; @@ -31,7 +32,7 @@ /** * Processes JavaDoc tags. */ -public class JavaDoc2HTMLTextReader extends SubstitutionTextReader { +public class JavaDoc2HTMLTextReader extends SubstitutionReader { static private class Pair { From 64ae4a641278cc444769d1fe0b04b89d9ba8c297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=8A?= =?UTF-8?q?=D1=80=20=D0=9A=D1=83=D1=80=D1=82=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 17 Sep 2024 21:59:23 +0300 Subject: [PATCH 08/15] Move away of deprecated CopyProjectAction(Shell) Use CopyProjectAction(IShellProvider) instead. --- .../jdt/internal/ui/refactoring/reorg/ReorgCopyAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/ReorgCopyAction.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/ReorgCopyAction.java index 2142ff83be8..ab1c359fe1c 100644 --- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/ReorgCopyAction.java +++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/ReorgCopyAction.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -76,7 +76,7 @@ public void selectionChanged(IStructuredSelection selection) { } private CopyProjectAction createWorkbenchAction(IStructuredSelection selection) { - CopyProjectAction action= new CopyProjectAction(getShell()); + CopyProjectAction action= new CopyProjectAction(getSite()); action.selectionChanged(selection); return action; } From ffa74dbde6ce4fdc66bceda23cf847ebd1729b89 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Tue, 17 Sep 2024 22:52:58 -0400 Subject: [PATCH 09/15] Bug 310510 - fix move to new type so extraneous import not added (#1659) * Bug 310510 - fix move to new type so extraneous import not added - fix MoveInnerToTopRefactoring.TypeReferenceQualifier visitor to not add qualifier to fields of member types that will end up being moved so to prevent call to addImport() to acquire Type - add new test to MoveInnerToTopLevelTests - fixes #1658 --- .../structure/MoveInnerToTopRefactoring.java | 13 ++++++- .../testBug310510/in/A.java | 10 +++++ .../testBug310510/out/A.java | 4 ++ .../testBug310510/out/Inner.java | 7 ++++ .../test_Bug572639_2/out/Layout.java | 38 +++++++++---------- .../refactoring/MoveInnerToTopLevelTests.java | 7 +++- 6 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/in/A.java create mode 100644 org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/A.java create mode 100644 org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/Inner.java diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.java index 7e402d853de..7b5498d8958 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -303,8 +303,17 @@ public boolean visit(final SimpleType node) { final ITypeBinding binding= node.resolveBinding(); if (binding != null) { final ITypeBinding declaring= binding.getDeclaringClass(); - if (declaring != null && !Bindings.equals(declaring, fTypeBinding.getDeclaringClass()) && !Bindings.equals(binding, fTypeBinding) && fSourceRewrite.getRoot().findDeclaringNode(binding) != null && Modifier.isStatic(binding.getModifiers())) + if (declaring != null && !Bindings.equals(declaring, fTypeBinding.getDeclaringClass()) && !Bindings.equals(binding, fTypeBinding) && fSourceRewrite.getRoot().findDeclaringNode(binding) != null && Modifier.isStatic(binding.getModifiers())) { + ITypeBinding temp= binding; + while (temp != null && temp.isMember()) { + ITypeBinding declaringType= temp.getDeclaringClass(); + if (Bindings.equals(declaringType, fTypeBinding)) { + return super.visit(node); + } + temp= declaringType; + } addTypeQualification(node, fSourceRewrite, fGroup); + } } } return super.visit(node); diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/in/A.java new file mode 100644 index 00000000000..cb0b284bf1d --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/in/A.java @@ -0,0 +1,10 @@ +package p; + +class A { + static class Inner { + Q q; + + static class Q { + } + } +} diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/A.java new file mode 100644 index 00000000000..8b7d8d5d86f --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/A.java @@ -0,0 +1,4 @@ +package p; + +class A { +} diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/Inner.java b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/Inner.java new file mode 100644 index 00000000000..76b3f63c902 --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel/testBug310510/out/Inner.java @@ -0,0 +1,7 @@ +package p; +class Inner { + Q q; + + static class Q { + } +} \ No newline at end of file diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel16/test_Bug572639_2/out/Layout.java b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel16/test_Bug572639_2/out/Layout.java index d20c06f5076..5259170af44 100644 --- a/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel16/test_Bug572639_2/out/Layout.java +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInnerToTopLevel16/test_Bug572639_2/out/Layout.java @@ -11,13 +11,13 @@ public interface Layout /*permits Layout.PrimitiveLayout, Layout.ListLayout, Layout.StructLayout*/ { default boolean isPrimitive() { - return this instanceof Layout.PrimitiveLayout; + return this instanceof PrimitiveLayout; } default boolean isList() { - return this instanceof Layout.ListLayout; + return this instanceof ListLayout; } default boolean isStruct() { - return this instanceof Layout.StructLayout; + return this instanceof StructLayout; } boolean nullable(); default Map fields() { @@ -30,56 +30,56 @@ default Layout element() { throw new IllegalArgumentException("no element"); } - static Layout.PrimitiveLayout u1(boolean nullable) { + static PrimitiveLayout u1(boolean nullable) { return new PrimitiveLayout(nullable, boolean.class); } - static Layout.PrimitiveLayout byte8(boolean nullable) { + static PrimitiveLayout byte8(boolean nullable) { return new PrimitiveLayout(nullable, byte.class); } - static Layout.PrimitiveLayout short16(boolean nullable) { + static PrimitiveLayout short16(boolean nullable) { return new PrimitiveLayout(nullable, short.class); } - static Layout.PrimitiveLayout char16(boolean nullable) { + static PrimitiveLayout char16(boolean nullable) { return new PrimitiveLayout(nullable, char.class); } - static Layout.PrimitiveLayout int32(boolean nullable) { + static PrimitiveLayout int32(boolean nullable) { return new PrimitiveLayout(nullable, int.class); } - static Layout.PrimitiveLayout float32(boolean nullable) { + static PrimitiveLayout float32(boolean nullable) { return new PrimitiveLayout(nullable, float.class); } - static Layout.PrimitiveLayout double64(boolean nullable) { + static PrimitiveLayout double64(boolean nullable) { return new PrimitiveLayout(nullable, double.class); } - static Layout.PrimitiveLayout long64(boolean nullable) { + static PrimitiveLayout long64(boolean nullable) { return new PrimitiveLayout(nullable, long.class); } - static Layout.ListLayout list(boolean nullable, Layout layout) { + static ListLayout list(boolean nullable, Layout layout) { return new ListLayout(nullable, layout); } - static Layout.ListLayout string(boolean nullable) { + static ListLayout string(boolean nullable) { return list(true, char16(nullable)); } - static Layout.Field field(String name, Layout layout) { + static Field field(String name, Layout layout) { return new Field(name, layout); } - static Layout.StructLayout struct(boolean nullable, Layout.Field... fields) { + static StructLayout struct(boolean nullable, Field... fields) { return new StructLayout(nullable, Arrays.stream(fields).collect(toMap(Field::name, Field::layout, (_1, _2) -> null, LinkedHashMap::new))); } private static String toString(String space, Layout layout) { - if (layout instanceof Layout.PrimitiveLayout primitiveLayout) { + if (layout instanceof PrimitiveLayout primitiveLayout) { return primitiveLayout.toString(); } - if (layout instanceof Layout.ListLayout listLayout) { - if (listLayout.element instanceof Layout.PrimitiveLayout elementLayout && elementLayout.type == char.class) { + if (layout instanceof ListLayout listLayout) { + if (listLayout.element instanceof PrimitiveLayout elementLayout && elementLayout.type == char.class) { return "string(" + elementLayout.nullable + ")"; } return "list(" + listLayout.nullable + ", " + toString(space, listLayout.element); } - if (layout instanceof Layout.StructLayout structLayout) { + if (layout instanceof StructLayout structLayout) { if (structLayout.fields.isEmpty()) { return "struct(" + structLayout.nullable + ")"; } diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInnerToTopLevelTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInnerToTopLevelTests.java index 8373c765def..cf33f0908ed 100644 --- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInnerToTopLevelTests.java +++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInnerToTopLevelTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -432,6 +432,11 @@ public void test44() throws Exception { validatePassingTest("A", "B", "p", new String[] { "A"}, new String[] { "p"}, "a", true, true, true, true); } + @Test + public void testBug310510() throws Exception { + validatePassingTest("A", "Inner", new String[]{"A"}, new String[]{"p"}, null, false, false); + } + // static context: https://bugs.eclipse.org/bugs/show_bug.cgi?id=385237 @Test public void test_static_context_0() throws Exception{ From a531b3780dd45b818452730414b96df252a5b43c Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Tue, 17 Sep 2024 22:53:23 -0400 Subject: [PATCH 10/15] Fix reading html content of a package fragment to not return null (#1657) - in the case of a package fragement, when we search for Javadoc content and do not find any package info, just return the empty string so Javadoc hover will at least show the package name --- .../core/manipulation/internal/javadoc/CoreJavadocAccess.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreJavadocAccess.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreJavadocAccess.java index 66257073914..24f5e7c9ae7 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreJavadocAccess.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreJavadocAccess.java @@ -184,8 +184,7 @@ protected String readHTMLContent(IPackageFragment packageFragment) throws CoreEx return packageFragment.getAttachedJavadoc(null); } - - return null; + return ""; //$NON-NLS-1$ } From d034430c32a7358212d855b411706265368d4e9f Mon Sep 17 00:00:00 2001 From: Noopur Gupta Date: Wed, 18 Sep 2024 12:40:35 +0530 Subject: [PATCH 11/15] Merge remote-tracking branch 'upstream/BETA_JAVA23' Fixes https://github.com/eclipse-jdt/eclipse.jdt.ui/issues/1660 --- Jenkinsfile | 2 +- org.eclipse.jdt.astview.feature/feature.xml | 2 +- org.eclipse.jdt.astview/META-INF/MANIFEST.MF | 2 +- .../eclipse/jdt/astview/views/ASTView.java | 3 + .../.settings/.api_filters | 8 + .../META-INF/MANIFEST.MF | 4 +- .../javadoc/CoreMarkdownAccessImpl.java | 121 +++ .../internal/javadoc/JavadocLookup.java | 8 +- .../AbstractFastJavaPartitionScanner.java | 59 +- .../jdt/internal/ui/util/ASTHelper.java | 1 + .../corext/dom/HierarchicalASTVisitor.java | 30 - .../internal/corext/util/JavaModelUtil.java | 23 +- .../eclipse/jdt/ui/text/IJavaPartitions.java | 6 +- .../META-INF/MANIFEST.MF | 2 +- org.eclipse.jdt.text.tests/pom.xml | 2 +- .../AbstractSemanticHighlightingTest.java | 9 + .../tests/Java23SemanticHighlightingTest.java | 47 + .../jdt/text/tests/JdtTextTestSuite.java | 1 + .../contentassist/CodeCompletionTest23.java | 222 +++++ .../contentassist/ContentAssistTestSuite.java | 2 + .../semanticHighlightingTest1/Java23.java | 11 + org.eclipse.jdt.ui.tests/pom.xml | 3 +- .../jdt/testplugin/JavaProjectHelper.java | 26 + org.eclipse.jdt.ui.tests/test.xml | 1 + .../eclipse/jdt/ui/tests/AutomatedSuite.java | 2 + .../core/rules/Java23ProjectTestSetup.java | 76 ++ .../ui/tests/hover/MarkdownCommentTests.java | 811 ++++++++++++++++++ .../corext/template/java/JavaFormatter.java | 3 +- .../ui/javaeditor/CompilationUnitEditor.java | 4 +- .../internal/ui/javaeditor/IndentUtil.java | 10 +- .../internal/ui/javaeditor/JavaEditor.java | 7 +- .../SemanticHighlightingReconciler.java | 27 +- ...CodeTemplateSourceViewerConfiguration.java | 3 +- .../ComplianceConfigurationBlock.java | 27 +- .../internal/ui/search/JavaMatchFilter.java | 1 + .../ui/text/JavaPartitionerManager.java | 5 +- .../ui/text/java/JavaAutoIndentStrategy.java | 9 +- .../java/SmartSemicolonAutoEditStrategy.java | 4 +- .../ui/text/java/hover/JavaSourceHover.java | 3 +- .../javadoc/JavaDocAutoIndentStrategy.java | 14 +- .../text/JavaSourceViewerConfiguration.java | 14 +- .../DefaultJavaFoldingStructureProvider.java | 41 +- pom.xml | 6 +- 43 files changed, 1559 insertions(+), 103 deletions(-) create mode 100644 org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreMarkdownAccessImpl.java create mode 100644 org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/Java23SemanticHighlightingTest.java create mode 100644 org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest23.java create mode 100644 org.eclipse.jdt.text.tests/testResources/semanticHighlightingTest1/Java23.java create mode 100644 org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java create mode 100644 org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java diff --git a/Jenkinsfile b/Jenkinsfile index 1ded9318239..6b0ad979049 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -19,7 +19,7 @@ pipeline { sh """ mvn -U -e -DskipTests=false -Dmaven.repo.local=$WORKSPACE/.m2/repository \ clean verify --batch-mode --fail-at-end \ - -Pbree-libs -Papi-check -Pjavadoc \ + -Pbree-libs -Papi-check -Pjavadoc -Pbuild-individual-bundles \ -Dmaven.test.failure.ignore=true \ -Dcompare-version-with-baselines.skip=false """ diff --git a/org.eclipse.jdt.astview.feature/feature.xml b/org.eclipse.jdt.astview.feature/feature.xml index babe7e1f648..4d4e1166d07 100644 --- a/org.eclipse.jdt.astview.feature/feature.xml +++ b/org.eclipse.jdt.astview.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jdt.astview/META-INF/MANIFEST.MF b/org.eclipse.jdt.astview/META-INF/MANIFEST.MF index 19509cff114..968cb6b5779 100644 --- a/org.eclipse.jdt.astview/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.astview/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.jdt.astview Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.astview; singleton:=true -Bundle-Version: 1.6.200.qualifier +Bundle-Version: 1.6.250.qualifier Bundle-Activator: org.eclipse.jdt.astview.ASTViewPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/org.eclipse.jdt.astview/src/org/eclipse/jdt/astview/views/ASTView.java b/org.eclipse.jdt.astview/src/org/eclipse/jdt/astview/views/ASTView.java index 1f4c89c6c64..f690b2da1dd 100644 --- a/org.eclipse.jdt.astview/src/org/eclipse/jdt/astview/views/ASTView.java +++ b/org.eclipse.jdt.astview/src/org/eclipse/jdt/astview/views/ASTView.java @@ -138,6 +138,7 @@ public class ASTView extends ViewPart implements IShowInSource, IShowInTargetList { static final int JLS_LATEST= AST.getJLSLatest(); + private static final int JLS23= ASTHelper.JLS23; private static final int JLS22= ASTHelper.JLS22; private static final int JLS21= ASTHelper.JLS21; private static final int JLS20= ASTHelper.JLS20; @@ -522,6 +523,7 @@ public ASTView() { case JLS20: case JLS21: case JLS22: + case JLS23: fCurrentASTLevel= level; } } catch (NumberFormatException e) { @@ -1150,6 +1152,7 @@ public void run() { new ASTLevelToggle("AST Level 2&0 (20)", JLS20), //$NON-NLS-1$ new ASTLevelToggle("AST Level 2&1 (21)", JLS21), //$NON-NLS-1$ new ASTLevelToggle("AST Level 2&2 (22)", JLS22), //$NON-NLS-1$ + new ASTLevelToggle("AST Level 2&3 (23)", JLS23), //$NON-NLS-1$ }; fAddToTrayAction= new Action() { diff --git a/org.eclipse.jdt.core.manipulation/.settings/.api_filters b/org.eclipse.jdt.core.manipulation/.settings/.api_filters index ece44acdf99..aa01ed20907 100644 --- a/org.eclipse.jdt.core.manipulation/.settings/.api_filters +++ b/org.eclipse.jdt.core.manipulation/.settings/.api_filters @@ -31,4 +31,12 @@ + + + + + + + + diff --git a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF index f06df4743ac..fe3bd6dd9c2 100644 --- a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF @@ -16,7 +16,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.31.0,4.0.0)", org.eclipse.jdt.launching;bundle-version="3.23.0", org.eclipse.core.filesystem;bundle-version="1.10.0", org.eclipse.core.filebuffers;bundle-version="3.8.0", - org.eclipse.search.core;bundle-version="3.16.0" + org.eclipse.search.core;bundle-version="3.16.0", + org.commonmark;bundle-version="0.22.0", + org.commonmark-gfm-tables;bundle-version="0.22.0" Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.jdt.core.manipulation, org.eclipse.jdt.core.refactoring, diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreMarkdownAccessImpl.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreMarkdownAccessImpl.java new file mode 100644 index 00000000000..fe2111a4508 --- /dev/null +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/CoreMarkdownAccessImpl.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2024 GK Software SE 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: + * Stephan Herrmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.manipulation.internal.javadoc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.commonmark.Extension; +import org.commonmark.ext.gfm.tables.TablesExtension; +import org.commonmark.node.Document; +import org.commonmark.node.Node; +import org.commonmark.node.Paragraph; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.TagElement; +import org.eclipse.jdt.core.dom.TextElement; + +public class CoreMarkdownAccessImpl extends CoreJavadocAccessImpl { + + private Parser fParser; + private HtmlRenderer fRenderer; + private int fBlockDepth= 0; + + public CoreMarkdownAccessImpl(IJavaElement element, Javadoc javadoc, String source) { + super(element, javadoc, source); + init(); + } + public CoreMarkdownAccessImpl(IJavaElement element, Javadoc javadoc, String source, JavadocLookup lookup) { + super(element, javadoc, source, lookup); + init(); + } + + private void init() { + List extensions= List.of(TablesExtension.create()); + fParser= Parser.builder().extensions(extensions).build(); + fRenderer= HtmlRenderer.builder().extensions(extensions).build(); + } + + @Override + protected String removeDocLineIntros(String textWithSlashes) { + String lineBreakGroup= "(\\r\\n?|\\n)"; //$NON-NLS-1$ + String noBreakSpace= "[^\r\n&&\\s]"; //$NON-NLS-1$ + // in the markdown case relevant leading whitespace is contained in TextElements, no need to preserve blanks *between* elements + return textWithSlashes.replaceAll(lineBreakGroup + noBreakSpace + "*///" + noBreakSpace + '*', "$1"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + protected void handleLink(List fragments) { + if (fragments.size() == 2 && fragments.get(0) instanceof TextElement) { + // super method expects the reference as first fragment, optional label as second fragment + fragments= Arrays.asList(fragments.get(1), fragments.get(0)); + } + super.handleLink(fragments); + } + + @Override + protected String getBlockTagStart() { + this.fBlockDepth++; + return "\n"+super.getBlockTagStart(); //$NON-NLS-1$ + } + + @Override + protected String getBlockTagEnd() { + if (this.fBlockDepth > 0) + this.fBlockDepth--; + return super.getBlockTagEnd(); + } + + @Override + protected void handleContentElements(List nodes, boolean skipLeadingWhitespace, TagElement tagElement) { + int start= fBuf.length(); + super.handleContentElements(nodes, skipLeadingWhitespace, tagElement); + if (this.fBlockDepth > 0) { + // inside an HTML block the markdown content must be rendered now + String generated= fBuf.substring(start); // extract new part of fBuf + Node node= fParser.parse(generated); + if (node.getFirstChild() instanceof Paragraph para && para.getNext() == null) { + // inside block replace single paragraph with its children + node= eliminateContainerNode(para); + } + String rendered= fRenderer.render(node); + fBuf.replace(start, fBuf.length(), rendered); // replace new part with its rendered version + } + } + + /** Return a new Document containing all children of the given container node. */ + protected Node eliminateContainerNode(Node container) { + List children= new ArrayList<>(); + for (Node child= container.getFirstChild(); child != null; child= child.getNext()) { + children.add(child); + } + Document doc= new Document(); + for (Node child2 : children) { + doc.appendChild(child2); + } + return doc; + } + + @Override + public String toHTML() { + String content= super.toHTML(); + Node document= fParser.parse(content); + return fRenderer.render(document); + } +} diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/JavadocLookup.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/JavadocLookup.java index 94fda594b24..1d69c207cc9 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/JavadocLookup.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/internal/javadoc/JavadocLookup.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 IBM Corporation and others. + * Copyright (c) 2023, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -33,6 +33,12 @@ public class JavadocLookup { public static final IJavadocContentFactory DEFAULT_FACTORY= new IJavadocContentFactory() { @Override public IJavadocAccess createJavadocAccess(IJavaElement element, Javadoc javadoc, String source, JavadocLookup lookup) { + if (source.startsWith("///")) { //$NON-NLS-1$ + if (lookup == null) + return new CoreMarkdownAccessImpl(element, javadoc, source); + else + return new CoreMarkdownAccessImpl(element, javadoc, source, lookup); + } if (lookup == null) return new CoreJavadocAccessImpl(element, javadoc, source); else diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/AbstractFastJavaPartitionScanner.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/AbstractFastJavaPartitionScanner.java index f19dfa669f1..407b604af0d 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/AbstractFastJavaPartitionScanner.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/AbstractFastJavaPartitionScanner.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 IBM Corporation and others. + * Copyright (c) 2023, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -45,15 +45,18 @@ public abstract class AbstractFastJavaPartitionScanner implements IPartitionToke private static final int CHARACTER= 4; private static final int STRING= 5; private static final int MULTI_LINE_STRING= 6; + private static final int MARKDOWN_COMMENT = 7; // beginning of prefixes and postfixes private static final int NONE= 0; private static final int BACKSLASH= 1; // postfix for STRING and CHARACTER private static final int SLASH= 2; // prefix for SINGLE_LINE or MULTI_LINE or JAVADOC - private static final int SLASH_STAR= 3; // prefix for MULTI_LINE_COMMENT or JAVADOC - private static final int SLASH_STAR_STAR= 4; // prefix for MULTI_LINE_COMMENT or JAVADOC - private static final int STAR= 5; // postfix for MULTI_LINE_COMMENT or JAVADOC - private static final int CARRIAGE_RETURN=6; // postfix for STRING, CHARACTER and SINGLE_LINE_COMMENT + private static final int SLASH_SLASH = 3; // prefix for MARKDOWN + private static final int SLASH_STAR= 4; // prefix for MULTI_LINE_COMMENT or JAVADOC + private static final int SLASH_STAR_STAR= 5; // prefix for MULTI_LINE_COMMENT or JAVADOC + private static final int SLASH_SLASH_SLASH= 6; // prefix for MULTI_LINE_COMMENT or JAVADOC + private static final int STAR= 7; // postfix for MULTI_LINE_COMMENT or JAVADOC + private static final int CARRIAGE_RETURN=8; // postfix for STRING, CHARACTER and SINGLE_LINE_COMMENT private static final int TRIPLE_QUOTE= 9; // prefix for TextBlock. /** The scanner. */ @@ -87,7 +90,8 @@ public abstract class AbstractFastJavaPartitionScanner implements IPartitionToke new Token(JAVA_DOC), new Token(JAVA_CHARACTER), new Token(JAVA_STRING), - new Token(JAVA_MULTI_LINE_STRING) + new Token(JAVA_MULTI_LINE_STRING), + new Token(JAVA_MARKDOWN_COMMENT) }; public AbstractFastJavaPartitionScanner(boolean emulate) { @@ -149,6 +153,7 @@ public IToken nextToken() { } else { switch (fState) { + case MARKDOWN_COMMENT: case SINGLE_LINE_COMMENT: case CHARACTER: case STRING: @@ -181,6 +186,7 @@ public IToken nextToken() { case '\n': switch (fState) { + case MARKDOWN_COMMENT: case SINGLE_LINE_COMMENT: case CHARACTER: case STRING: @@ -254,9 +260,9 @@ public IToken nextToken() { case '/': if (fLast == SLASH) { if (fTokenLength - getLastLength(fLast) > 0) { - return preFix(JAVA, SINGLE_LINE_COMMENT, NONE, 2); + return preFix(JAVA, SINGLE_LINE_COMMENT, SLASH_SLASH, 2); } else { - preFix(JAVA, SINGLE_LINE_COMMENT, NONE, 2); + preFix(JAVA, SINGLE_LINE_COMMENT, SLASH_SLASH, 2); fTokenOffset += fTokenLength; fTokenLength= fPrefixLength; break; @@ -326,9 +332,36 @@ public IToken nextToken() { break; case SINGLE_LINE_COMMENT: - consume(); + switch (ch) { + case '/': + if (fLast == SLASH_SLASH) { + fLast= SLASH_SLASH_SLASH; + fTokenLength++; + fState= MARKDOWN_COMMENT; + } else { + fTokenLength++; + fLast= SLASH; + } + break; + default: + consume(); + break; + } + break; + case MARKDOWN_COMMENT: + switch (ch) { + case '\r': + case '\n': + return postFix(MARKDOWN_COMMENT); + case '/': + fTokenLength++; + fLast= SLASH_SLASH_SLASH; + break; + default: + consume(); + break; + } break; - case JAVADOC: switch (ch) { case '/': @@ -632,10 +665,10 @@ private static final int getLastLength(int last) { case SLASH: case STAR: return 1; - + case SLASH_SLASH: case SLASH_STAR: return 2; - + case SLASH_SLASH_SLASH: case SLASH_STAR_STAR: case TRIPLE_QUOTE: return 3; @@ -695,6 +728,8 @@ private static int getState(String contentType) { return CHARACTER; case JAVA_MULTI_LINE_STRING: return MULTI_LINE_STRING; + case JAVA_MARKDOWN_COMMENT: + return MARKDOWN_COMMENT; default: return JAVA; } diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/util/ASTHelper.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/util/ASTHelper.java index 1cba2f4f94e..f174befb3f0 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/util/ASTHelper.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/util/ASTHelper.java @@ -38,6 +38,7 @@ public class ASTHelper { public static final int JLS20 = AST.JLS20; public static final int JLS21 = AST.JLS21; public static final int JLS22 = AST.JLS22; + public static final int JLS23 = AST.JLS23; private static boolean isNodeTypeSupportedInAST(AST ast, int nodeType) { switch (nodeType) { diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/HierarchicalASTVisitor.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/HierarchicalASTVisitor.java index 2243e1c93b9..99de20ddf60 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/HierarchicalASTVisitor.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/HierarchicalASTVisitor.java @@ -727,36 +727,6 @@ public void endVisit(StringLiteral node) { endVisit((Expression)node); } - @Override - public boolean visit(StringTemplateExpression node) { - return visit((Expression) node); - } - - @Override - public boolean visit(StringTemplateComponent node) { - return visit((Expression) node); - } - - @Override - public boolean visit(StringFragment node) { - return visit((Expression) node); - } - - @Override - public void endVisit(StringTemplateExpression node) { - endVisit((Expression) node); - } - - @Override - public void endVisit(StringTemplateComponent node) { - endVisit((Expression) node); - } - - @Override - public void endVisit(StringFragment node) { - endVisit((Expression) node); - } - @Override public boolean visit(SuperFieldAccess node) { return visit((Expression)node); diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.java index f8e394aa59e..fcd591f6f0e 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.java @@ -78,7 +78,7 @@ public final class JavaModelUtil { */ public static final String VERSION_LATEST; static { - VERSION_LATEST= JavaCore.VERSION_22; // make sure it is not inlined + VERSION_LATEST= JavaCore.VERSION_23; // make sure it is not inlined } public static final int VALIDATE_EDIT_CHANGED_CONTENT= 10003; @@ -870,6 +870,10 @@ public static boolean is22OrHigher(String compliance) { return !isVersionLessThan(compliance, JavaCore.VERSION_22); } + public static boolean is23OrHigher(String compliance) { + return !isVersionLessThan(compliance, JavaCore.VERSION_23); + } + /** * Checks if the given project or workspace has source compliance 1.2 or greater. * @@ -1065,6 +1069,17 @@ public static boolean is22OrHigher(IJavaProject project) { return is22OrHigher(getSourceCompliance(project)); } + /** + * Checks if the given project or workspace has source compliance 23 or greater. + * + * @param project the project to test or null to test the workspace settings + * @return true if the given project or workspace has source compliance 23 or + * greater. + */ + public static boolean is23OrHigher(IJavaProject project) { + return is23OrHigher(getSourceCompliance(project)); + } + public static String getSourceCompliance(IJavaProject project) { return project != null ? project.getOption(JavaCore.COMPILER_SOURCE, true) : JavaCore.getOption(JavaCore.COMPILER_SOURCE); } @@ -1115,6 +1130,8 @@ public static String getCompilerCompliance(IVMInstall2 vMInstall, String default String version= vMInstall.getJavaVersion(); if (version == null) { return defaultCompliance; + } else if (version.startsWith(JavaCore.VERSION_23)) { + return JavaCore.VERSION_23; } else if (version.startsWith(JavaCore.VERSION_22)) { return JavaCore.VERSION_22; } else if (version.startsWith(JavaCore.VERSION_21)) { @@ -1163,7 +1180,9 @@ public static String getExecutionEnvironmentCompliance(IExecutionEnvironment exe // fallback: String desc= executionEnvironment.getId(); - if (desc.indexOf(JavaCore.VERSION_22) != -1) { + if (desc.indexOf(JavaCore.VERSION_23) != -1) { + return JavaCore.VERSION_23; + } else if (desc.indexOf(JavaCore.VERSION_22) != -1) { return JavaCore.VERSION_22; } else if (desc.indexOf(JavaCore.VERSION_21) != -1) { return JavaCore.VERSION_21; diff --git a/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/ui/text/IJavaPartitions.java b/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/ui/text/IJavaPartitions.java index 5b76ab5cea8..61ad4c19ef6 100644 --- a/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/ui/text/IJavaPartitions.java +++ b/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/ui/text/IJavaPartitions.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -57,4 +57,8 @@ public interface IJavaPartitions { * @since 3.20 */ String JAVA_MULTI_LINE_STRING= "__java_multiline_string"; //$NON-NLS-1$ + /** + * @since 1.21 + */ + String JAVA_MARKDOWN_COMMENT = "__java_markdown_comment"; //$NON-NLS-1$ } diff --git a/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF index f94140e8a1e..e0eb890ce7c 100644 --- a/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.jdt.text.tests Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.jdt.text.tests;singleton:=true -Bundle-Version: 3.14.500.qualifier +Bundle-Version: 3.14.550.qualifier Bundle-Activator: org.eclipse.jdt.text.tests.JdtTextTestPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %Plugin.providerName diff --git a/org.eclipse.jdt.text.tests/pom.xml b/org.eclipse.jdt.text.tests/pom.xml index 9986c27ab8d..d67ef8a73e7 100644 --- a/org.eclipse.jdt.text.tests/pom.xml +++ b/org.eclipse.jdt.text.tests/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jdt org.eclipse.jdt.text.tests - 3.14.500-SNAPSHOT + 3.14.550-SNAPSHOT eclipse-test-plugin diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/AbstractSemanticHighlightingTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/AbstractSemanticHighlightingTest.java index 1a54a70be2a..58670025031 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/AbstractSemanticHighlightingTest.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/AbstractSemanticHighlightingTest.java @@ -36,6 +36,7 @@ import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.ui.PreferenceConstants; @@ -68,6 +69,14 @@ public void before() throws Exception { assertTrue(EditorTestHelper.joinReconciler(fSourceViewer, 0, 10000, 100)); } + public void updateCompliance(String compliance, boolean enablePreview) { + fJavaProject.setOption(JavaCore.COMPILER_SOURCE, compliance); + fJavaProject.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, compliance); + fJavaProject.setOption(JavaCore.COMPILER_COMPLIANCE, compliance); + fJavaProject.setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED); + fJavaProject.setOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, enablePreview ? JavaCore.ENABLED: JavaCore.DISABLED); + } + protected String getTestFilename() { return "/SHTest/src/SHTest.java"; } diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/Java23SemanticHighlightingTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/Java23SemanticHighlightingTest.java new file mode 100644 index 00000000000..404825dd127 --- /dev/null +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/Java23SemanticHighlightingTest.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2024 GK Software SE 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: + * Stephan Herrmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.text.tests; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import org.eclipse.jface.text.Position; + +import org.eclipse.jdt.internal.ui.javaeditor.SemanticHighlightingsCore; + +public class Java23SemanticHighlightingTest extends AbstractSemanticHighlightingTest { + + @Rule + public SemanticHighlightingTestSetup shts= new SemanticHighlightingTestSetup( "/SHTest/src/Java23.java"); + + @Before + public void updateCompliance() { + shts.updateCompliance("23", true); + } + + @Test + public void restrictedKeywordHighlighting() throws Exception { + setUpSemanticHighlighting(SemanticHighlightingsCore.RESTRICTED_KEYWORDS); + Position[] expected= new Position[] { + createPosition(0, 7, 6), // module (import modifier) + createPosition(3, 1, 6), // sealed + createPosition(3, 8, 6), // record + createPosition(6, 1, 10),// non-sealed + createPosition(8, 2, 3), // var + }; + Position[] actual= getSemanticHighlightingPositions(); + assertEqualPositions(expected, actual); + } +} diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/JdtTextTestSuite.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/JdtTextTestSuite.java index ff0615684f2..78ae735ecc5 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/JdtTextTestSuite.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/JdtTextTestSuite.java @@ -53,6 +53,7 @@ SpellCheckEngineTestCase.class, SemanticHighlightingTest.class, AutoboxingSemanticHighlightingTest.class, + Java23SemanticHighlightingTest.class, NewForLoopJavaContextTest.class, IteratorForLoopJavaContextTest.class, ArrayWithTempVarForLoopJavaContextTest.class, diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest23.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest23.java new file mode 100644 index 00000000000..e36c845f357 --- /dev/null +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest23.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2024 GK Software SE 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: + * Stephan Herrmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.text.tests.contentassist; + +import static org.junit.Assert.assertEquals; + +import java.util.Hashtable; +import java.util.List; + +import org.junit.Rule; +import org.junit.Test; + +import org.eclipse.jdt.testplugin.JavaProjectHelper; +import org.eclipse.jdt.testplugin.TestOptions; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.jface.preference.IPreferenceStore; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.source.ISourceViewer; + +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; + +import org.eclipse.jdt.internal.core.manipulation.CodeTemplateContextType; +import org.eclipse.jdt.internal.core.manipulation.StubUtility; + +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jdt.ui.PreferenceConstants; +import org.eclipse.jdt.ui.tests.core.rules.Java23ProjectTestSetup; +import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext; + +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; +import org.eclipse.jdt.internal.ui.text.java.JavaAllCompletionProposalComputer; +import org.eclipse.jdt.internal.ui.text.java.JavaTypeCompletionProposalComputer; + +/** + * Those tests are made to run on Java 23 + */ +public class CodeCompletionTest23 extends AbstractCompletionTest { + @Rule + public Java23ProjectTestSetup j23s= new Java23ProjectTestSetup(true); + + private IJavaProject fJProject1; + + @Override + public void setUp() throws Exception { + fJProject1= j23s.getProject(); + + Hashtable options= TestOptions.getDefaultOptions(); + options.put(DefaultCodeFormatterConstants.FORMATTER_NUMBER_OF_EMPTY_LINES_TO_PRESERVE, "1"); + options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.SPACE); + options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "4"); + options.put(JavaCore.CODEASSIST_FIELD_PREFIXES, "f"); + JavaCore.setOptions(options); + + IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); + store.setValue(PreferenceConstants.CODEGEN_ADD_COMMENTS, true); + store.setValue(PreferenceConstants.CODEASSIST_GUESS_METHOD_ARGUMENTS, true); + store.setValue(PreferenceConstants.CODEASSIST_SHOW_VISIBLE_PROPOSALS, true); + + StubUtility.setCodeTemplate(CodeTemplateContextType.OVERRIDECOMMENT_ID, "/* (non-Javadoc)\n * ${see_to_overridden}\n */", null); + StubUtility.setCodeTemplate(CodeTemplateContextType.DELEGATECOMMENT_ID, "/* (non-Javadoc)\n * ${see_to_target}\n */", null); + StubUtility.setCodeTemplate(CodeTemplateContextType.METHODSTUB_ID, "//TODO\n${body_statement}", null); + StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORCOMMENT_ID, "/**\n * Constructor.\n */", null); + StubUtility.setCodeTemplate(CodeTemplateContextType.METHODCOMMENT_ID, "/**\n * Method.\n */", null); + StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORSTUB_ID, "//TODO\n${body_statement}", null); + StubUtility.setCodeTemplate(CodeTemplateContextType.GETTERCOMMENT_ID, "/**\n * @return the ${bare_field_name}\n */", fJProject1); + StubUtility.setCodeTemplate(CodeTemplateContextType.SETTERCOMMENT_ID, "/**\n * @param ${param} the ${bare_field_name} to set\n */", fJProject1); + } + + @Override + public void tearDown() throws Exception { + IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); + store.setToDefault(PreferenceConstants.CODEGEN_ADD_COMMENTS); + store.setToDefault(PreferenceConstants.CODEASSIST_GUESS_METHOD_ARGUMENTS); + store.setToDefault(PreferenceConstants.CODEASSIST_SHOW_VISIBLE_PROPOSALS); + closeAllEditors(); + JavaProjectHelper.clear(fJProject1, j23s.getDefaultClasspath()); + } + + public static void closeEditor(IEditorPart editor) { + IWorkbenchPartSite site; + IWorkbenchPage page; + if (editor != null && (site= editor.getSite()) != null && (page= site.getPage()) != null) + page.closeEditor(editor, false); + } + + public static void closeAllEditors() { + for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) { + for (IWorkbenchPage page : window.getPages()) { + for (IEditorReference editorReference : page.getEditorReferences()) { + closeEditor(editorReference.getEditor(false)); + } + } + } + } + + private JavaContentAssistInvocationContext createContext(int offset, ICompilationUnit cu) throws PartInitException, JavaModelException { + JavaEditor editor= (JavaEditor) JavaUI.openInEditor(cu); + ISourceViewer viewer= editor.getViewer(); + return new JavaContentAssistInvocationContext(viewer, offset, editor); + } + + @Test + public void testMarkdownLink_method() throws CoreException { + IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + IPackageFragment pack1= sourceFolder.createPackageFragment("javadoc", false, null); + String contents= + """ + package javadoc; + /// + /// see [#me] for details + public class Test { + void method() {} + } + """; + ICompilationUnit cu= pack1.createCompilationUnit("Test.java", contents, false, null); + + + String str= "#me"; + + int offset= contents.indexOf(str) + str.length() - 1; + + JavaTypeCompletionProposalComputer comp= new JavaAllCompletionProposalComputer(); + + List proposals= comp.computeCompletionProposals(createContext(offset, cu), null); + ICompletionProposal proposal = proposals.get(0); + + IEditorPart part= JavaUI.openInEditor(cu); + IDocument doc= JavaUI.getDocumentProvider().getDocument(part.getEditorInput()); + if (proposal != null) { + proposal.apply(doc); + } + + String expectedContents= + """ + package javadoc; + /// + /// see [#method()] for details + public class Test { + void method() {} + } + """; + assertEquals(expectedContents, doc.get()); + } + + @Test + public void testMarkdownLink_type() throws CoreException { + IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src"); + + IPackageFragment pack1= sourceFolder.createPackageFragment("javadoc", false, null); + String contents= + """ + package javadoc; + public class Test { + /// + /// see [Tes + /// + void method() {} + } + """; + ICompilationUnit cu= pack1.createCompilationUnit("Test.java", contents, false, null); + + + String str= "[Tes"; + + int offset= contents.indexOf(str) + str.length() - 1; + + JavaTypeCompletionProposalComputer comp= new JavaAllCompletionProposalComputer(); + + List proposals= comp.computeCompletionProposals(createContext(offset, cu), null); + ICompletionProposal proposal = proposals.get(0); + + IEditorPart part= JavaUI.openInEditor(cu); + IDocument doc= JavaUI.getDocumentProvider().getDocument(part.getEditorInput()); + if (proposal != null) { + proposal.apply(doc); + } + + String expectedContents= + """ + package javadoc; + public class Test { + /// + /// see [Test + /// + void method() {} + } + """; + assertEquals(expectedContents, doc.get()); + } + +} diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/ContentAssistTestSuite.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/ContentAssistTestSuite.java index 569e85c4466..bb539ae074d 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/ContentAssistTestSuite.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/ContentAssistTestSuite.java @@ -39,6 +39,8 @@ SpecialMethodsCompletionTest.class, CodeCompletionTest.class, CodeCompletionTest1d8.class, + CodeCompletionTest16.class, + CodeCompletionTest23.class, ContinuousTypingCompletionTest.class, ChainCompletionTest.class, PostFixCompletionTest.class diff --git a/org.eclipse.jdt.text.tests/testResources/semanticHighlightingTest1/Java23.java b/org.eclipse.jdt.text.tests/testResources/semanticHighlightingTest1/Java23.java new file mode 100644 index 00000000000..5565412e590 --- /dev/null +++ b/org.eclipse.jdt.text.tests/testResources/semanticHighlightingTest1/Java23.java @@ -0,0 +1,11 @@ +import module java.base; + +public class Java23 { + sealed record SampleRecord(String left, String right) { + + } + non-sealed interface NSI {} + void m() { + var var = "Hello"; + } +} \ No newline at end of file diff --git a/org.eclipse.jdt.ui.tests/pom.xml b/org.eclipse.jdt.ui.tests/pom.xml index defff69d934..4d09430d667 100644 --- a/org.eclipse.jdt.ui.tests/pom.xml +++ b/org.eclipse.jdt.ui.tests/pom.xml @@ -26,6 +26,7 @@ true --add-modules ALL-SYSTEM --add-opens jdk.localedata/sun.util.resources.cldr.provider=ALL-UNNAMED --add-opens jdk.localedata/sun.util.resources.provider=ALL-UNNAMED --add-opens java.base/com.sun.crypto.provider=ALL-UNNAMED --add-opens java.base/com.sun.security.ntlm=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.annotation=ALL-UNNAMED --add-opens java.base/java.lang.constant=ALL-UNNAMED --add-opens java.base/java.lang.invoke=ALL-UNNAMED --add-opens java.base/java.lang.module=ALL-UNNAMED --add-opens java.base/java.lang.ref=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.lang.runtime=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.net.spi=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.nio.channels=ALL-UNNAMED --add-opens java.base/java.nio.channels.spi=ALL-UNNAMED --add-opens java.base/java.nio.charset=ALL-UNNAMED --add-opens java.base/java.nio.charset.spi=ALL-UNNAMED --add-opens java.base/java.nio.file=ALL-UNNAMED --add-opens java.base/java.nio.file.attribute=ALL-UNNAMED --add-opens java.base/java.nio.file.spi=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.security.cert=ALL-UNNAMED --add-opens java.base/java.security.interfaces=ALL-UNNAMED --add-opens java.base/java.security.spec=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.text.spi=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.time.chrono=ALL-UNNAMED --add-opens java.base/java.time.format=ALL-UNNAMED --add-opens java.base/java.time.temporal=ALL-UNNAMED --add-opens java.base/java.time.zone=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED --add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED --add-opens java.base/java.util.function=ALL-UNNAMED --add-opens java.base/java.util.jar=ALL-UNNAMED --add-opens java.base/java.util.random=ALL-UNNAMED --add-opens java.base/java.util.regex=ALL-UNNAMED --add-opens java.base/java.util.spi=ALL-UNNAMED --add-opens java.base/java.util.stream=ALL-UNNAMED --add-opens java.base/java.util.zip=ALL-UNNAMED --add-opens java.base/javax.crypto=ALL-UNNAMED --add-opens java.base/javax.crypto.interfaces=ALL-UNNAMED --add-opens java.base/javax.crypto.spec=ALL-UNNAMED --add-opens java.base/javax.net=ALL-UNNAMED --add-opens java.base/javax.net.ssl=ALL-UNNAMED --add-opens java.base/javax.security.auth=ALL-UNNAMED --add-opens java.base/javax.security.auth.callback=ALL-UNNAMED --add-opens java.base/javax.security.auth.login=ALL-UNNAMED --add-opens java.base/javax.security.auth.spi=ALL-UNNAMED --add-opens java.base/javax.security.auth.x500=ALL-UNNAMED --add-opens java.base/javax.security.cert=ALL-UNNAMED --add-opens java.base/jdk.internal=ALL-UNNAMED --add-opens java.base/jdk.internal.access=ALL-UNNAMED --add-opens java.base/jdk.internal.access.foreign=ALL-UNNAMED --add-opens java.base/jdk.internal.event=ALL-UNNAMED --add-opens java.base/jdk.internal.icu.impl=ALL-UNNAMED --add-opens java.base/jdk.internal.icu.impl.data.icudt67b=ALL-UNNAMED --add-opens java.base/jdk.internal.icu.lang=ALL-UNNAMED --add-opens java.base/jdk.internal.icu.text=ALL-UNNAMED --add-opens java.base/jdk.internal.icu.util=ALL-UNNAMED --add-opens java.base/jdk.internal.invoke=ALL-UNNAMED --add-opens java.base/jdk.internal.javac=ALL-UNNAMED --add-opens java.base/jdk.internal.jimage=ALL-UNNAMED --add-opens java.base/jdk.internal.jimage.decompressor=ALL-UNNAMED --add-opens java.base/jdk.internal.jmod=ALL-UNNAMED --add-opens java.base/jdk.internal.jrtfs=ALL-UNNAMED --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens java.base/jdk.internal.logger=ALL-UNNAMED --add-opens java.base/jdk.internal.math=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED --add-opens java.base/jdk.internal.module=ALL-UNNAMED --add-opens java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED --add-opens java.base/jdk.internal.org.objectweb.asm.commons=ALL-UNNAMED --add-opens java.base/jdk.internal.org.objectweb.asm.signature=ALL-UNNAMED --add-opens java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED --add-opens java.base/jdk.internal.org.objectweb.asm.tree.analysis=ALL-UNNAMED --add-opens java.base/jdk.internal.org.objectweb.asm.util=ALL-UNNAMED --add-opens java.base/jdk.internal.org.xml.sax=ALL-UNNAMED --add-opens java.base/jdk.internal.org.xml.sax.helpers=ALL-UNNAMED --add-opens java.base/jdk.internal.perf=ALL-UNNAMED --add-opens java.base/jdk.internal.platform=ALL-UNNAMED --add-opens java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.util=ALL-UNNAMED --add-opens java.base/jdk.internal.util.jar=ALL-UNNAMED --add-opens java.base/jdk.internal.util.random=ALL-UNNAMED --add-opens java.base/jdk.internal.util.xml=ALL-UNNAMED --add-opens java.base/jdk.internal.util.xml.impl=ALL-UNNAMED --add-opens java.base/jdk.internal.vm=ALL-UNNAMED --add-opens java.base/jdk.internal.vm.annotation=ALL-UNNAMED --add-opens java.base/jdk.internal.vm.vector=ALL-UNNAMED --add-opens java.base/sun.invoke=ALL-UNNAMED --add-opens java.base/sun.invoke.empty=ALL-UNNAMED --add-opens java.base/sun.invoke.util=ALL-UNNAMED --add-opens java.base/sun.io=ALL-UNNAMED --add-opens java.base/sun.launcher=ALL-UNNAMED --add-opens java.base/sun.launcher.resources=ALL-UNNAMED --add-opens java.base/sun.net=ALL-UNNAMED --add-opens java.base/sun.net.dns=ALL-UNNAMED --add-opens java.base/sun.net.ext=ALL-UNNAMED --add-opens java.base/sun.net.ftp=ALL-UNNAMED --add-opens java.base/sun.net.ftp.impl=ALL-UNNAMED --add-opens java.base/sun.net.idn=ALL-UNNAMED --add-opens java.base/sun.net.sdp=ALL-UNNAMED --add-opens java.base/sun.net.smtp=ALL-UNNAMED --add-opens java.base/sun.net.spi=ALL-UNNAMED --add-opens java.base/sun.net.util=ALL-UNNAMED --add-opens java.base/sun.net.www=ALL-UNNAMED --add-opens java.base/sun.net.www.content.text=ALL-UNNAMED --add-opens java.base/sun.net.www.http=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.file=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.ftp=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.http=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.http.ntlm=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.jar=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.jmod=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.jrt=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.mailto=ALL-UNNAMED --add-opens java.base/sun.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/sun.nio.cs=ALL-UNNAMED --add-opens java.base/sun.nio.fs=ALL-UNNAMED --add-opens java.base/sun.reflect.annotation=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.factory=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.parser=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.repository=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.scope=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.tree=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.visitor=ALL-UNNAMED --add-opens java.base/sun.reflect.misc=ALL-UNNAMED --add-opens java.base/sun.security.action=ALL-UNNAMED --add-opens java.base/sun.security.internal.interfaces=ALL-UNNAMED --add-opens java.base/sun.security.internal.spec=ALL-UNNAMED --add-opens java.base/sun.security.jca=ALL-UNNAMED --add-opens java.base/sun.security.pkcs=ALL-UNNAMED --add-opens java.base/sun.security.pkcs10=ALL-UNNAMED --add-opens java.base/sun.security.pkcs12=ALL-UNNAMED --add-opens java.base/sun.security.provider=ALL-UNNAMED --add-opens java.base/sun.security.provider.certpath=ALL-UNNAMED --add-opens java.base/sun.security.provider.certpath.ssl=ALL-UNNAMED --add-opens java.base/sun.security.rsa=ALL-UNNAMED --add-opens java.base/sun.security.ssl=ALL-UNNAMED --add-opens java.base/sun.security.timestamp=ALL-UNNAMED --add-opens java.base/sun.security.tools=ALL-UNNAMED --add-opens java.base/sun.security.tools.keytool=ALL-UNNAMED --add-opens java.base/sun.security.util=ALL-UNNAMED --add-opens java.base/sun.security.util.math=ALL-UNNAMED --add-opens java.base/sun.security.util.math.intpoly=ALL-UNNAMED --add-opens java.base/sun.security.validator=ALL-UNNAMED --add-opens java.base/sun.security.x509=ALL-UNNAMED --add-opens java.base/sun.text=ALL-UNNAMED --add-opens java.base/sun.text.resources=ALL-UNNAMED --add-opens java.base/sun.text.resources.cldr=ALL-UNNAMED --add-opens java.base/sun.text.spi=ALL-UNNAMED --add-opens java.base/sun.util=ALL-UNNAMED --add-opens java.base/sun.util.calendar=ALL-UNNAMED --add-opens java.base/sun.util.cldr=ALL-UNNAMED --add-opens java.base/sun.util.locale=ALL-UNNAMED --add-opens java.base/sun.util.locale.provider=ALL-UNNAMED --add-opens java.base/sun.util.logging=ALL-UNNAMED --add-opens java.base/sun.util.resources=ALL-UNNAMED --add-opens java.base/sun.util.resources.cldr=ALL-UNNAMED --add-opens java.base/sun.util.spi=ALL-UNNAMED --add-opens java.xml/com.sun.java_cup.internal.runtime=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.bcel.internal=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.bcel.internal.classfile=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.bcel.internal.generic=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.bcel.internal.util=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.extensions=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.lib=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.res=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.templates=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.utils=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.compiler=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.compiler.util=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.dom=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime.output=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.util=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.dom=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.dom.events=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.dtd=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.dtd.models=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.dv=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.dv.dtd=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.dv.util=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.io=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.msg=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.validation=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xpath=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xpath.regex=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xs=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xs.identity=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xs.models=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xs.opti=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.impl.xs.util=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.jaxp=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.jaxp.datatype=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.jaxp.validation=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.parsers=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.util=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.utils=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.xinclude=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.xni=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.xni.grammars=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.xni.parser=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.xpointer=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.xs=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xerces.internal.xs.datatypes=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.dtm=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.dtm.ref=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.dtm.ref.dom2dtm=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.dtm.ref.sax2dtm=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.res=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.serialize=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.serializer=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.serializer.dom3=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.serializer.utils=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.utils=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xml.internal.utils.res=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.axes=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.compiler=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.functions=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.jaxp=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.objects=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.operations=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.patterns=ALL-UNNAMED --add-opens java.xml/com.sun.org.apache.xpath.internal.res=ALL-UNNAMED --add-opens java.xml/com.sun.xml.internal.stream=ALL-UNNAMED --add-opens java.xml/com.sun.xml.internal.stream.dtd=ALL-UNNAMED --add-opens java.xml/com.sun.xml.internal.stream.dtd.nonvalidating=ALL-UNNAMED --add-opens java.xml/com.sun.xml.internal.stream.events=ALL-UNNAMED --add-opens java.xml/com.sun.xml.internal.stream.util=ALL-UNNAMED --add-opens java.xml/com.sun.xml.internal.stream.writers=ALL-UNNAMED --add-opens java.xml/javax.xml=ALL-UNNAMED --add-opens java.xml/javax.xml.catalog=ALL-UNNAMED --add-opens java.xml/javax.xml.datatype=ALL-UNNAMED --add-opens java.xml/javax.xml.namespace=ALL-UNNAMED --add-opens java.xml/javax.xml.parsers=ALL-UNNAMED --add-opens java.xml/javax.xml.stream=ALL-UNNAMED --add-opens java.xml/javax.xml.stream.events=ALL-UNNAMED --add-opens java.xml/javax.xml.stream.util=ALL-UNNAMED --add-opens java.xml/javax.xml.transform=ALL-UNNAMED --add-opens java.xml/javax.xml.transform.dom=ALL-UNNAMED --add-opens java.xml/javax.xml.transform.sax=ALL-UNNAMED --add-opens java.xml/javax.xml.transform.stax=ALL-UNNAMED --add-opens java.xml/javax.xml.transform.stream=ALL-UNNAMED --add-opens java.xml/javax.xml.validation=ALL-UNNAMED --add-opens java.xml/javax.xml.xpath=ALL-UNNAMED --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED --add-opens java.xml/org.w3c.dom=ALL-UNNAMED --add-opens java.xml/org.w3c.dom.bootstrap=ALL-UNNAMED --add-opens java.xml/org.w3c.dom.events=ALL-UNNAMED --add-opens java.xml/org.w3c.dom.ls=ALL-UNNAMED --add-opens java.xml/org.w3c.dom.ranges=ALL-UNNAMED --add-opens java.xml/org.w3c.dom.traversal=ALL-UNNAMED --add-opens java.xml/org.w3c.dom.views=ALL-UNNAMED --add-opens java.xml/org.xml.sax=ALL-UNNAMED --add-opens java.xml/org.xml.sax.ext=ALL-UNNAMED --add-opens java.xml/org.xml.sax.helpers=ALL-UNNAMED --add-opens java.desktop/com.sun.beans=ALL-UNNAMED --add-opens java.desktop/java.beans=ALL-UNNAMED --add-opens java.logging/java.util.logging=ALL-UNNAMED --add-opens java.management/com.sun.jmx.defaults=ALL-UNNAMED --add-opens java.management/com.sun.jmx.interceptor=ALL-UNNAMED --add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED --add-opens java.management/com.sun.jmx.remote.internal=ALL-UNNAMED --add-opens java.management/com.sun.jmx.remote.security=ALL-UNNAMED --add-opens java.management/com.sun.jmx.remote.util=ALL-UNNAMED --add-opens java.management/java.lang.management=ALL-UNNAMED --add-opens java.management/javax.management=ALL-UNNAMED --add-opens java.management/javax.management.loading=ALL-UNNAMED --add-opens java.management/javax.management.modelmbean=ALL-UNNAMED --add-opens java.management/javax.management.monitor=ALL-UNNAMED --add-opens java.management/javax.management.openmbean=ALL-UNNAMED --add-opens java.management/javax.management.relation=ALL-UNNAMED --add-opens java.management/javax.management.remote=ALL-UNNAMED --add-opens java.management/javax.management.timer=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens java.management/sun.management.counter=ALL-UNNAMED --add-opens java.management/sun.management.counter.perf=ALL-UNNAMED --add-opens java.management/sun.management.spi=ALL-UNNAMED --add-opens jdk.management/com.sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED --illegal-access=permit + -XX:CompileCommand=exclude,org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer::getExtendedRange @@ -49,7 +50,7 @@ 0.0.0 - ${leakTestsArgLine} + ${leakTestsArgLine} ${jitExclusions} diff --git a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java index a64e147ff54..27eeb35322c 100644 --- a/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java +++ b/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java @@ -356,6 +356,23 @@ public static void set18CompilerOptions(IJavaProject project) { project.setOptions(options); } + /** + * Sets the compiler options to 23 for the given project. + * + * @param project the java project + * @param enable_preview_feature sets enable-preview compliance project option based on the + * value specified. + */ + public static void set23CompilerOptions(IJavaProject project, boolean enable_preview_feature) { + Map options= project.getOptions(false); + set23_CompilerOptions(options); + if (enable_preview_feature) { + options.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); + options.put(JavaCore.COMPILER_PB_REPORT_PREVIEW_FEATURES, JavaCore.IGNORE); + } + project.setOptions(options); + } + /** * Sets the compiler options to 9. * @@ -437,6 +454,15 @@ public static void set17_CompilerOptions(Map options) { JavaCore.setComplianceOptions(JavaCore.VERSION_17, options); } + /** + * Sets the compiler options to 23. + * + * @param options the compiler options to configure + */ + public static void set23_CompilerOptions(Map options) { + JavaCore.setComplianceOptions(JavaCore.VERSION_23, options); + } + /** * Sets the compiler options to 1.8 * diff --git a/org.eclipse.jdt.ui.tests/test.xml b/org.eclipse.jdt.ui.tests/test.xml index 9206c307b0d..b6121fa3f6b 100644 --- a/org.eclipse.jdt.ui.tests/test.xml +++ b/org.eclipse.jdt.ui.tests/test.xml @@ -35,6 +35,7 @@ + diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java index 506f7f20c8f..740d3e6a6a8 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java @@ -32,6 +32,7 @@ import org.eclipse.jdt.ui.tests.core.CoreTestSuite; import org.eclipse.jdt.ui.tests.core.CoreTests; import org.eclipse.jdt.ui.tests.hover.JavadocHoverTests; +import org.eclipse.jdt.ui.tests.hover.MarkdownCommentTests; import org.eclipse.jdt.ui.tests.hover.PackageJavadocTests; import org.eclipse.jdt.ui.tests.jarexport.JarExportTests; import org.eclipse.jdt.ui.tests.model.ContentProviderTests; @@ -82,6 +83,7 @@ JarExportTests.class, PackageJavadocTests.class, JavadocHoverTests.class, + MarkdownCommentTests.class, SmokeViewsTest.class }) public class AutomatedSuite { diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java new file mode 100644 index 00000000000..19ac112be75 --- /dev/null +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/rules/Java23ProjectTestSetup.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2024 GK Software SE 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: + * Stephan Herrmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ui.tests.core.rules; + +import org.eclipse.jdt.testplugin.JavaProjectHelper; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.jdt.core.IClasspathAttribute; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; + +import org.eclipse.jdt.internal.core.ClasspathEntry; + +/** Variant derived from Java17ProjectTestSetup */ +public class Java23ProjectTestSetup extends ProjectTestSetup { + + public static final String PROJECT_NAME23= "TestSetupProject23"; + + private final String projectName; + + private final boolean enable_preview_feature; + + @Override + public IJavaProject getProject() { + IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + return JavaCore.create(project); + } + + @Override + public IClasspathEntry[] getDefaultClasspath() throws CoreException { + IPath[] rtJarPath= JavaProjectHelper.findRtJar(JavaProjectHelper.RT_STUBS17); + IClasspathAttribute[] extraAttributes= { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, Boolean.TRUE.toString()) }; + return new IClasspathEntry[] { JavaCore.newLibraryEntry(rtJarPath[0], rtJarPath[1], rtJarPath[2], ClasspathEntry.NO_ACCESS_RULES, extraAttributes, true) }; + } + + public Java23ProjectTestSetup( boolean enable_preview_feature) { + this.enable_preview_feature= enable_preview_feature; + projectName= PROJECT_NAME23; + } + + public Java23ProjectTestSetup( String projectName, boolean enable_preview_feature) { + this.enable_preview_feature= enable_preview_feature; + this.projectName= projectName; + } + + @Override + protected boolean projectExists() { + return getProject().exists(); + } + + @Override + protected IJavaProject createAndInitializeProject() throws CoreException { + IJavaProject javaProject= JavaProjectHelper.createJavaProject(projectName, "bin"); + javaProject.setRawClasspath(getDefaultClasspath(), null); + JavaProjectHelper.set23CompilerOptions(javaProject, enable_preview_feature); + return javaProject; + } + +} diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java new file mode 100644 index 00000000000..f7c03e78fa3 --- /dev/null +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java @@ -0,0 +1,811 @@ +/******************************************************************************* + * Copyright (c) 2024 GK Software SE 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: + * Stephan Herrmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ui.tests.hover; + +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import org.eclipse.jdt.testplugin.JavaProjectHelper; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.jface.text.Region; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.ISourceReference; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.WorkingCopyOwner; + +import org.eclipse.jdt.ui.tests.core.CoreTests; +import org.eclipse.jdt.ui.tests.core.rules.Java23ProjectTestSetup; +import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup; + +import org.eclipse.jdt.internal.ui.text.java.hover.JavadocBrowserInformationControlInput; +import org.eclipse.jdt.internal.ui.text.java.hover.JavadocHover; + +public class MarkdownCommentTests extends CoreTests { + + @Rule + public ProjectTestSetup pts= new Java23ProjectTestSetup("TestSetupProject", false); + + private IJavaProject fJProject1; + + // copies from CoreJavaElementLinks + private static final char LINK_SEPARATOR= '\u2602'; + private static final char LINK_BRACKET_REPLACEMENT= '\u2603'; + + // copies from JavaElement: + static final char JEM_JAVAPROJECT= '='; + static final char JEM_PACKAGEFRAGMENTROOT= '/'; + static final char JEM_PACKAGEFRAGMENT= '<'; + static final char JEM_FIELD= '^'; + static final char JEM_METHOD= '~'; + static final char JEM_COMPILATIONUNIT= '{'; + static final char JEM_TYPE= LINK_BRACKET_REPLACEMENT; // replacement for '[' + + @Before + public void setUp() throws Exception { + fJProject1= pts.getProject(); + JavaProjectHelper.addSourceContainer(fJProject1, "src"); + } + + @After + public void tearDown() throws Exception { + JavaProjectHelper.clear(fJProject1, pts.getDefaultClasspath()); + } + + protected ICompilationUnit getWorkingCopy(String path, String source, WorkingCopyOwner owner) throws JavaModelException { + ICompilationUnit workingCopy= (ICompilationUnit) JavaCore.create(getFile(path)); + if (owner != null) + workingCopy= workingCopy.getWorkingCopy(owner, null/*no progress monitor*/); + else + workingCopy.becomeWorkingCopy(null/*no progress monitor*/); + workingCopy.getBuffer().setContents(source); + workingCopy.makeConsistent(null/*no progress monitor*/); + return workingCopy; + } + + protected IFile getFile(String path) { + IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot(); + return root.getFile(new Path(path)); + } + + private String makeEncodedClassUri(String pack, String cuName, String clazz) { + try { + StringBuilder buf= new StringBuilder(); + buf.append(LINK_SEPARATOR); + buf.append(JEM_JAVAPROJECT).append("TestSetupProject"); + buf.append(JEM_PACKAGEFRAGMENTROOT).append("src"); + buf.append(JEM_PACKAGEFRAGMENT).append(pack); + buf.append(JEM_COMPILATIONUNIT).append(cuName).append(".java"); + buf.append(JEM_TYPE).append(clazz); + URI uri= new URI("eclipse-javadoc", buf.toString(), null); + return uri.toASCIIString(); + } catch (URISyntaxException e) { + fail(e); + return null; + } + } + + /** Create a javadoc link to the specified method. */ + private String makeEncodedMethodUri(String pack, String cuName, String clazz, String selector, String... parameters) { + return makeEncodedMethodUri(false, pack, cuName, clazz, selector, parameters); + } + /** Create a javadoc link for the specified method. + * @param asScopeURI when {@code true} the link is intended as a scope prefix for {@link #makeEncodedRelativeUri(String, String...)}. + */ + private String makeEncodedMethodUri(boolean asScopeURI, String pack, String cuName, String clazz, String selector, String... parameters) { + try { + StringBuilder buf= new StringBuilder(); + buf.append(LINK_SEPARATOR); + buf.append(JEM_JAVAPROJECT).append("TestSetupProject"); + buf.append(JEM_PACKAGEFRAGMENTROOT).append("src"); + buf.append(JEM_PACKAGEFRAGMENT).append(pack); + buf.append(JEM_COMPILATIONUNIT).append(cuName).append(".java"); + buf.append(JEM_TYPE).append(clazz); + + if (asScopeURI) { + buf.append(JEM_METHOD); + } else { + buf.append(LINK_SEPARATOR); + buf.append(LINK_SEPARATOR); + } + buf.append(selector); + for (String parameter : parameters) { + if (asScopeURI) { + buf.append(JEM_METHOD); + } else { + buf.append(LINK_SEPARATOR); + } + buf.append(parameter); + } + URI uri= new URI("eclipse-javadoc", buf.toString(), null); + return uri.toASCIIString(); + } catch (URISyntaxException e) { + fail(e); + return null; + } + } + + /** Create a javadoc link to the element specified by moreWords as seen from the scope specified by scopeURI. */ + private String makeEncodedRelativeUri(String scopeURI, String... moreWords) { + try { + StringBuilder buf= new StringBuilder(scopeURI); + for (String parameter : moreWords) { + buf.append(LINK_SEPARATOR).append(parameter); + } + URI uri= new URI(buf.toString()); + return uri.toASCIIString(); + } catch (URISyntaxException e) { + fail(e); + return null; + } + } + + private String getHoverHtmlContent(ICompilationUnit cu, T element) throws JavaModelException { + ISourceRange range= element.getNameRange(); + JavadocBrowserInformationControlInput hoverInfo= JavadocHover.getHoverInfo( + new IJavaElement[] { element }, + cu, + new Region(range.getOffset(), range.getLength()), + null); + return hoverInfo.getHtml(); + } + + /** Strips standard head and tail of actualContent for convenient assertEquals() comparison. */ + private void assertHtmlContent(String expectedContent, String actualContent) { + int start= actualContent.indexOf(""); + assertEquals(expectedContent, actualContent.substring(start+headerTail.length(), end)); + } + + @Test + public void testBasicFormatting() throws Exception { + String source= """ + package p; + /// ## TestClass + /// + /// Paragraph + /// + /// - item 1 + /// - _item 2_ + public class TestClass { + /// ### m() + /// + /// Paragraph with _emphasis_ + /// - item 1 + /// - item 2 + /// @param i an _integer_ ! + void m(int i) { + } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/TestClass.java", source, null); + assertNotNull("TestClass.java", cu); + + IType type= cu.getType("TestClass"); + String actualHtmlContent= getHoverHtmlContent(cu, type); + + assertHtmlContent(""" +

TestClass

+

Paragraph

+
    +
  • item 1
  • +
  • item 2
  • +
+ """, + actualHtmlContent); + + IMethod elem= type.getMethods()[0]; + actualHtmlContent= getHoverHtmlContent(cu, elem); + + assertHtmlContent(""" +

m()

+

Paragraph with emphasis

+
    +
  • item 1
  • +
  • item 2
  • +
+
Parameters:
i an integer !
+ """, + actualHtmlContent); + } + + @Test + public void testItemAtEnd() throws Exception { + String source= """ + package p; + /// - item 1 + /// - item 2 + public class TestClass { + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/TestClass.java", source, null); + assertNotNull("TestClass.java", cu); + + IType type= cu.getType("TestClass"); + String actualHtmlContent= getHoverHtmlContent(cu, type); + assertHtmlContent(""" +
    +
  • item 1
  • +
  • item 2
  • +
+ """, + actualHtmlContent); + } + + @Test + public void testMarkdownLink1() throws Exception { + String source= """ + package p; + /// ## TestClass + /// + /// Please have a _look at [#m1(int)]_ if you like. + public class TestClass { + public void m1(int i) {} + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/TestClass.java", source, null); + assertNotNull("TestClass.java", cu); + + String expectedURI= makeEncodedMethodUri("p", "TestClass", "TestClass", "m1", "int"); + String expectedHtmlContent= """ +

TestClass

+

Please have a look at m1(int) if you like.

+ """ + .replace("URI", expectedURI); + + IType type= cu.getType("TestClass"); + String actualHtmlContent= getHoverHtmlContent(cu, type); + assertHtmlContent(expectedHtmlContent, actualHtmlContent); + } + + @Test + public void testMarkdownLink2() throws Exception { + String source= """ + package p; + /// ## TestClass + /// + /// Please have a _look at [method 1][#m1(int)]_ if you like. + public class TestClass { + public void m1(int i) {} + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/TestClass.java", source, null); + assertNotNull("TestClass.java", cu); + + String expectedURI= makeEncodedMethodUri("p", "TestClass", "TestClass", "m1", "int"); + String expectedHtmlContent= """ +

TestClass

+

Please have a look at method 1 if you like.

+ """ + .replace("URI", expectedURI); + + IType type= cu.getType("TestClass"); + String actualHtmlContent= getHoverHtmlContent(cu, type); + assertHtmlContent(expectedHtmlContent, actualHtmlContent); + } + + @Test + public void testMarkdownLink3() throws Exception { + // reference mentions an array type: array-[] must be escaped + String source= """ + package p; + /// ## TestClass + /// + /// Simple link [#m1(int\\[\\])]. + /// Link with custom text [method 1][#m1(int\\[\\])]. + public class TestClass { + public void m1(int[] i) {} + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/TestClass.java", source, null); + assertNotNull("TestClass.java", cu); + + String expectedURI= makeEncodedMethodUri("p", "TestClass", "TestClass", "m1", "int []"); + String expectedHtmlContent= """ +

TestClass

+

Simple link m1(int []). + Link with custom text method 1.

+ """ + .replaceAll("URI", expectedURI); + + IType type= cu.getType("TestClass"); + String actualHtmlContent= getHoverHtmlContent(cu, type); + assertHtmlContent(expectedHtmlContent, actualHtmlContent); + } + + @Test + public void testSpec01Links() throws CoreException { + String source= """ + package p; + public class Spec01Links { + + /// - a module [java.base/] + /// - a package [java.util] + /// - a class [String] + /// - a field [String#CASE_INSENSITIVE_ORDER] + /// - a method [String#chars()] + public void plainLinks() { + + } + + /// - [the `java.base` module][java.base/] + /// - [the `java.util` package][java.util] + /// - [a class][String] + /// - [a field][String#CASE_INSENSITIVE_ORDER] + /// - [a method][String#chars()] + public void linksDisplayString() { + + } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/Spec01Links.java", source, null); + assertNotNull("Spec01Links.java", cu); + IType type= cu.getType("Spec01Links"); + + String plainLinksURI= makeEncodedMethodUri(true, "p", "Spec01Links", "Spec01Links", "plainLinks"); + String moduleURI= makeEncodedRelativeUri(plainLinksURI, "java.base/"); + String packageURI= makeEncodedRelativeUri(plainLinksURI, "java.util"); + String classURI= makeEncodedRelativeUri(plainLinksURI, "String"); + String fieldURI= makeEncodedRelativeUri(plainLinksURI, "String", "CASE_INSENSITIVE_ORDER"); + String methodURI= makeEncodedRelativeUri(plainLinksURI, "String", "chars", ""); + String expectedHtmlContent= """ + + """ + .replace("MODULE_URI", moduleURI) + .replace("PACKAGE_URI", packageURI) + .replace("CLASS_URI", classURI) + .replace("FIELD_URI", fieldURI) + .replace("METHOD_URI", methodURI); + + IMethod method= type.getMethod("plainLinks", new String[0]); + String actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(expectedHtmlContent, actualHtmlContent); + + expectedHtmlContent= """ + + """ + .replace("MODULE_URI", moduleURI) + .replace("PACKAGE_URI", packageURI) + .replace("CLASS_URI", classURI) + .replace("FIELD_URI", fieldURI) + .replace("METHOD_URI", methodURI) + .replaceAll("plainLinks", "linksDisplayString"); // rebase all links to be relative to linksDisplayString + method= type.getMethod("linksDisplayString", new String[0]); + actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(expectedHtmlContent, actualHtmlContent); + } + + @Test + public void testSpec02Table() throws CoreException { + String source= """ + package p; + + /// | Latin | Greek | + /// |-------|-------| + /// | a | alpha | + /// | b | beta | + /// | c | gamma | + public class Spec02Table { + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/Spec02Table.java", source, null); + assertNotNull("Spec02Table.java", cu); + + IType type= cu.getType("Spec02Table"); + String actualHtmlContent= getHoverHtmlContent(cu, type); + assertHtmlContent(""" + + + + + + + + + + + + + + + + + + + + + +
LatinGreek
aalpha
bbeta
cgamma
+ """, + actualHtmlContent); + } + + @Test + public void testSpec03Tags() throws CoreException { + String source= """ + package p; + class Super { + /// super doc + public void m(int i) {} + } + public class Spec03Tags extends Super { + + /// {@inheritDoc} + /// In addition, this methods calls [#wait()]. + /// + /// @param i the index + public void m(int i) {} + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/Spec03Tags.java", source, null); + assertNotNull("Spec03Tags.java", cu); + + String mURI= makeEncodedMethodUri(true, "p", "Spec03Tags", "Spec03Tags","m", "I"); + String waitURI= makeEncodedRelativeUri(mURI, "", "wait", ""); + String superURI= makeEncodedClassUri("p", "Spec03Tags", "Super"); + String superMURI= makeEncodedMethodUri(true, "p", "Spec03Tags", "Super","m", "I"); + String expectedContent= """ +

super doc + In addition, this methods calls wait().

Overrides: m(...) in Super

+
Parameters:
i the index
+ """ + .replace("METHOD_URI", waitURI) + .replace("SUPER_M_URI", superMURI) + .replace("SUPER_URI", superURI); + + IType type= cu.getType("Spec03Tags"); + IMethod method= type.getMethod("m", new String[] { "I" }); + String actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(expectedContent, actualHtmlContent); + } + + @Test + public void testSpec04Code() throws CoreException { + String source= """ + /// The following code span contains literal text, and not a JavaDoc tag: + /// `{@inheritDoc}` + /// + /// In the following indented code block, `@Override` is an annotation, + /// and not a JavaDoc tag: + /// + /// @Override + /// public void m() ... + /// + /// Likewise, in the following fenced code block, `@Override` is an annotation, + /// and not a JavaDoc tag: + /// + /// ``` + /// @Override + /// public void m() ... + /// ``` + public class Spec04Code { + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/Spec04Code.java", source, null); + assertNotNull("Spec04Code.java", cu); + + String expectedContent= """ +

The following code span contains literal text, and not a JavaDoc tag: + {@inheritDoc}

+

In the following indented code block, @Override is an annotation, + and not a JavaDoc tag:

+
@Override
+				public void m() ...
+				
+

Likewise, in the following fenced code block, @Override is an annotation, + and not a JavaDoc tag:

+
@Override
+				public void m() ...
+				
+ """; + IType type= cu.getType("Spec04Code"); + String actualHtmlContent= getHoverHtmlContent(cu, type); + assertHtmlContent(expectedContent, actualHtmlContent); + } + + @Test + public void testSpec05TextInTag() throws CoreException { + String source= """ + import java.util.List; + + public class Spec05TextInTag { + /// @param l the list, or `null` if no list is available + public void m(List l) {} + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/Spec05TextInTag.java", source, null); + assertNotNull("Spec05TextInTag.java", cu); + + IType type= cu.getType("Spec05TextInTag"); + IMethod method= type.getMethods()[0]; + String actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(""" +
Parameters:
l the list, or null if no list is available
+ """, + actualHtmlContent); + } + + @Test + public void testCodeAtEdge() throws CoreException { + String source= """ + package p; + + public class CodeAtEdge { + /// @Override + /// void m() {} + /// + /// Plain text + /// + /// @Override + /// void m() {} + public void m() {} + } + + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/CodeAtEdge.java", source, null); + assertNotNull("CodeAtEdge.java", cu); + + IType type= cu.getType("CodeAtEdge"); + + IMethod method= type.getMethods()[0]; + String actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(""" +
@Override
+				void m() {}
+				
+

Plain text

+
@Override
+				void m() {}
+				
+ """, + actualHtmlContent); + } + @Test + public void testLineStarts() throws CoreException { + String source= """ + package p; + + public class LineStarts { + /// Three + //// Four - show one slash + ///// Five - show two slashes + /// Drei + void numberOfSlashes() { } + + /// two + /// + ///none - all leadings spaces will be significant + /// + /// public void one() + /// + /// public void four() // four spaces suffice for code + /// + void numberOfSpaces1() { } + + /// two + /// + /// public void one() + /// + /// public void two() + /// + /// public void four() + /// + /// public void five() // shown correctly by both + /// + /// public void one() + /// + /// public void four() + /// + /// public void five() // dropped by javadoc + void numberOfSpaces2() { } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/LineStarts.java", source, null); + assertNotNull("LineStarts.java", cu); + + IType type= cu.getType("LineStarts"); + + IMethod method= type.getMethods()[0]; + String actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(""" +

Three + / Four - show one slash + // Five - show two slashes + Drei

+ """, + actualHtmlContent); + + method= type.getMethods()[1]; + actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(""" +

two

+

none - all leadings spaces will be significant

+

public void one()

+
public void four() // four spaces suffice for code
+				
+ """, + actualHtmlContent); + + method= type.getMethods()[2]; + actualHtmlContent= getHoverHtmlContent(cu, method); + assertHtmlContent(""" +

two

+

public void one()

+

public void two()

+

public void four()

+
public void five() // shown correctly by both
+				
+

public void one()

+

public void four()

+
public void five() // dropped by javadoc
+				
+ """, + actualHtmlContent); + } + + + @Test + public void testSeeTag() throws CoreException { + String source= """ + package p; + + /// @see #m() + /// @see Eclipse.org + public class SeeTag { + public void m() {} + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/SeeTag.java", source, null); + assertNotNull("SeeTag.java", cu); + + IType type= cu.getType("SeeTag"); + + String actualHtmlContent= getHoverHtmlContent(cu, type); + String expectedContent= """ +
See Also:
m()
Eclipse.org
+ """ + .replace("METHOD_URI", makeEncodedMethodUri("p", "SeeTag", "SeeTag","m", "")); + assertHtmlContent(expectedContent, actualHtmlContent); + } + + @Test + public void testGH2808_codeAfterPara() throws CoreException { + String source= """ + package p; + + public class CodeAfterPara { + /// Plain Text + /// @Override public void four() // four significant spaces but no blank line + void noBlankLine() { } + + /// Plain Text + /// \s + /// @Override public void four() // four significant spaces after blank line + void withBlankLine() { } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/CodeAfterPara.java", source, null); + assertNotNull("CodeAfterPara.java", cu); + + IType type= cu.getType("CodeAfterPara"); + + IMethod method= type.getMethods()[0]; + String actualHtmlContent= getHoverHtmlContent(cu, method); + String expectedContent= """ +

Plain Text

+
@Override
public void four() // four significant spaces but no blank line
+ """; + assertHtmlContent(expectedContent, actualHtmlContent); + + method= type.getMethods()[1]; + actualHtmlContent= getHoverHtmlContent(cu, method); + expectedContent= """ +

Plain Text

+
@Override public void four() // four significant spaces after blank line
+				
+ """; + assertHtmlContent(expectedContent, actualHtmlContent); + } + + @Test + public void testGH2808_terminatingAnIndentedCodeBlock() throws CoreException { + String source= """ + package p; + + public class BlockEnding { + /// Plain Text + /// + /// @Override public void four() + /// ``` + /// /// doc + /// /// ``` + /// /// @Override Nested Code + /// /// ``` + /// ``` + void indentedWithFence() { } + + /// Plain Text + /// + /// @Override public void four() + /// Plain again + void paraAfterCode() { } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/BlockEnding.java", source, null); + assertNotNull("BlockEnding.java", cu); + + IType type= cu.getType("BlockEnding"); + + IMethod method= type.getMethods()[0]; + String actualHtmlContent= getHoverHtmlContent(cu, method); + String expectedContent= """ +

Plain Text

+
@Override public void four()
+				```
+				/// doc
+				/// ```
+				/// @Override Nested Code
+				/// ```
+				```
+				
+ """; + assertHtmlContent(expectedContent, actualHtmlContent); + + method= type.getMethods()[1]; + actualHtmlContent= getHoverHtmlContent(cu, method); + expectedContent= """ +

Plain Text

+
@Override public void four()
+				
+

Plain again

+ """; + assertHtmlContent(expectedContent, actualHtmlContent); + } +} diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaFormatter.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaFormatter.java index d805fa4fbc3..4cc93104ca9 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaFormatter.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaFormatter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -104,6 +104,7 @@ public VariableTracker(TemplateBuffer buffer, IJavaProject project) throws Malfo private static void installJavaStuff(Document document, IJavaProject project) { String[] types= new String[] { IJavaPartitions.JAVA_DOC, + IJavaPartitions.JAVA_MARKDOWN_COMMENT, IJavaPartitions.JAVA_MULTI_LINE_COMMENT, IJavaPartitions.JAVA_SINGLE_LINE_COMMENT, IJavaPartitions.JAVA_STRING, diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java index bf6465babef..80c2a10ce5f 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -532,7 +532,7 @@ public void verifyKey(VerifyEvent event) { } ITypedRegion partition= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset, true); - if (!IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())) + if (!IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType()) && !IJavaPartitions.JAVA_MARKDOWN_COMMENT.equals(partition.getType())) return; if (!validateEditorInputState()) return; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/IndentUtil.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/IndentUtil.java index d10af28b6fd..1ef0b143ab7 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/IndentUtil.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/IndentUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2022 IBM Corporation and others. + * Copyright (c) 2005, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -320,7 +320,9 @@ private static String getCurrentIndent(IDocument document, int line) throws BadL // don't count the space before javadoc like, asterix-style comment lines if (to > from && to < endOffset - 1 && " *".equals(document.get(to - 1, 2))) { //$NON-NLS-1$ String type= TextUtilities.getContentType(document, IJavaPartitions.JAVA_PARTITIONING, to, true); - if (IJavaPartitions.JAVA_DOC.equals(type) || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type)) + if (IJavaPartitions.JAVA_DOC.equals(type) + || IJavaPartitions.JAVA_MARKDOWN_COMMENT.equals(type) + || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type)) to--; } @@ -380,7 +382,9 @@ private static boolean indentLine(IDocument document, int line, JavaIndenter ind ITypedRegion partition= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset, true); ITypedRegion startingPartition= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset, false); String type= partition.getType(); - if (IJavaPartitions.JAVA_DOC.equals(type) || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type)) { + if (IJavaPartitions.JAVA_DOC.equals(type) + || IJavaPartitions.JAVA_MARKDOWN_COMMENT.equals(type) + || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type)) { indent= computeJavadocIndent(document, line, scanner, startingPartition); } else if (!commentLines[lineIndex] && startingPartition.getOffset() == offset && IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(startingPartition.getType())) { return false; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java index 1372bf69f47..a35ed9947ec 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2022 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -1151,7 +1151,10 @@ public void run() { if (emptySelection) { final ITypedRegion partition= TextUtilities.getPartition(viewer.getDocument(), IJavaPartitions.JAVA_PARTITIONING, selection.x, true); String type= partition.getType(); - if (IJavaPartitions.JAVA_DOC.equals(type) || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type) || IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(type)) { + if (IJavaPartitions.JAVA_DOC.equals(type) + || IJavaPartitions.JAVA_MARKDOWN_COMMENT.equals(type) + || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type) + || IJavaPartitions.JAVA_SINGLE_LINE_COMMENT.equals(type)) { viewer.setSelectedRange(partition.getOffset(), partition.getLength()); viewer.doOperation(ISourceViewer.FORMAT); return; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.java index 72880716f8b..9453d16ab8a 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.java @@ -212,24 +212,27 @@ public boolean visit(TypeDeclaration node) { @Override public boolean visit(Modifier node) { AST ast= node.getAST(); + int offset= node.getStartPosition(); + int length = 0; + ModifierKeyword keyword= node.getKeyword(); if (ASTHelper.isSealedTypeSupportedInAST(ast)) { - ModifierKeyword keyword= node.getKeyword(); - int offset= node.getStartPosition(); - int length; if (keyword == ModifierKeyword.SEALED_KEYWORD) { length= 6; } else if (keyword == ModifierKeyword.NON_SEALED_KEYWORD) { length= 10; - } else { - return true; } - if (offset > -1 && length > 0) { - for (int i= 0; i < fJobSemanticHighlightings.length; i++) { - SemanticHighlighting semanticHighlighting= fJobSemanticHighlightings[i]; - if (semanticHighlighting instanceof RestrictedIdentifiersHighlighting) { - addPosition(offset, length, fJobHighlightings[i]); - return false; - } + } + if (length == 0 && ast.apiLevel() >= AST.JLS23) { + if (keyword == ModifierKeyword.MODULE_KEYWORD) { + length= 6; + } + } + if (offset > -1 && length > 0) { + for (int i= 0; i < fJobSemanticHighlightings.length; i++) { + SemanticHighlighting semanticHighlighting= fJobSemanticHighlightings[i]; + if (semanticHighlighting instanceof RestrictedIdentifiersHighlighting) { + addPosition(offset, length, fJobHighlightings[i]); + return false; } } } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeTemplateSourceViewerConfiguration.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeTemplateSourceViewerConfiguration.java index 568f38a9e50..7caaf3d458b 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeTemplateSourceViewerConfiguration.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeTemplateSourceViewerConfiguration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -118,6 +118,7 @@ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { assistant.setContentAssistProcessor(fProcessor, IJavaPartitions.JAVA_SINGLE_LINE_COMMENT); assistant.setContentAssistProcessor(fProcessor, IJavaPartitions.JAVA_MULTI_LINE_COMMENT); assistant.setContentAssistProcessor(fProcessor, IJavaPartitions.JAVA_DOC); + assistant.setContentAssistProcessor(fProcessor, IJavaPartitions.JAVA_MARKDOWN_COMMENT); assistant.enableAutoInsert(store.getBoolean(PreferenceConstants.CODEASSIST_AUTOINSERT)); assistant.enableAutoActivation(store.getBoolean(PreferenceConstants.CODEASSIST_AUTOACTIVATION)); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ComplianceConfigurationBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ComplianceConfigurationBlock.java index a5b613018b2..a34d6b97d0f 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ComplianceConfigurationBlock.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ComplianceConfigurationBlock.java @@ -268,14 +268,23 @@ private Composite createComplianceTabContent(Composite folder) { ArrayList allJavaProjectVersions = new ArrayList<>(JavaCore.getAllJavaSourceVersionsSupportedByCompiler()); Collections.reverse(allJavaProjectVersions); + final String[] complianceVersions= allJavaProjectVersions.toArray(String[]::new); - final String[] complianceLabels= complianceVersions; + + for (int i= 0; i < allJavaProjectVersions.size(); i++) { + String version= allJavaProjectVersions.get(i); + if (isBetaVersion(version)) { + allJavaProjectVersions.set(i, version + " (BETA)"); //$NON-NLS-1$ + break; + } + } + final String[] complianceLabels= allJavaProjectVersions.toArray(String[]::new); // 2nd copy in case (BETA) was added final String[] targetVersions= complianceVersions; - final String[] targetLabels= targetVersions; + final String[] targetLabels= complianceLabels; final String[] sourceVersions= complianceVersions; - final String[] sourceLabels= sourceVersions; + final String[] sourceLabels= complianceLabels; final ScrolledPageContent sc1 = new ScrolledPageContent(folder); Composite composite= sc1.getBody(); @@ -680,12 +689,24 @@ private void validateComplianceStatus() { } } + if (isBetaVersion(getValue(PREF_COMPLIANCE))) { + fJRE50InfoText.setText( + "This is an implementation of an early-draft specification developed under the Java Community Process (JCP) and is made available for testing and evaluation purposes only. The code is not compatible with any specification of the JCP."); //$NON-NLS-1$ + isVisible= true; + } + fJRE50InfoText.setVisible(isVisible); fJRE50InfoImage.setImage(isVisible ? image : null); fJRE50InfoImage.getParent().layout(); } } + @SuppressWarnings("unused") + protected boolean isBetaVersion(String compliance) { + return false; +// return JavaCore.VERSION_23.equals(compliance); + } + private String addsExportToSystemModule() { if (fProject == null) { return null; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/JavaMatchFilter.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/JavaMatchFilter.java index c6f281e57ff..74bd0caf256 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/JavaMatchFilter.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/JavaMatchFilter.java @@ -330,6 +330,7 @@ public boolean isApplicable(JavaSearchQuery query) { case IJavaElement.METHOD: case IJavaElement.FIELD: case IJavaElement.PACKAGE_FRAGMENT: + case IJavaElement.JAVA_MODULE: isApplicable= true; break; default: diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaPartitionerManager.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaPartitionerManager.java index 33d3cce587b..9b1ecb834c9 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaPartitionerManager.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaPartitionerManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 IBM Corporation and others. + * Copyright (c) 2019, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -31,7 +31,8 @@ public class JavaPartitionerManager implements IJavaPartitionerManager { IJavaPartitions.JAVA_SINGLE_LINE_COMMENT, IJavaPartitions.JAVA_STRING, IJavaPartitions.JAVA_CHARACTER, - IJavaPartitions.JAVA_MULTI_LINE_STRING + IJavaPartitions.JAVA_MULTI_LINE_STRING, + IJavaPartitions.JAVA_MARKDOWN_COMMENT }; private static ITextEditor fEditor; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaAutoIndentStrategy.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaAutoIndentStrategy.java index cc51be3077f..fb7b50b39c0 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaAutoIndentStrategy.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaAutoIndentStrategy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -57,13 +57,13 @@ import org.eclipse.jdt.core.dom.WhileStatement; import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jdt.ui.text.IJavaPartitions; import org.eclipse.jdt.internal.ui.JavaPlugin; -import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; import org.eclipse.jdt.internal.ui.text.FastJavaPartitionScanner; import org.eclipse.jdt.internal.ui.text.FastJavaPartitioner; @@ -632,6 +632,7 @@ private boolean isClosed(IDocument document, int offset, int length) { private void installJavaStuff(Document document) { String[] types= new String[] { IJavaPartitions.JAVA_DOC, + IJavaPartitions.JAVA_MARKDOWN_COMMENT, IJavaPartitions.JAVA_MULTI_LINE_COMMENT, IJavaPartitions.JAVA_SINGLE_LINE_COMMENT, IJavaPartitions.JAVA_STRING, @@ -801,7 +802,9 @@ private static String getCurrentIndent(Document document, int line) throws BadLo // don't count the space before javadoc like, asterisk-style comment lines if (to > from && to < endOffset - 1 && " *".equals(document.get(to - 1, 2))) { //$NON-NLS-1$ String type= TextUtilities.getContentType(document, IJavaPartitions.JAVA_PARTITIONING, to, true); - if (IJavaPartitions.JAVA_DOC.equals(type) || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type)) + if (IJavaPartitions.JAVA_DOC.equals(type) + || IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(type) + || IJavaPartitions.JAVA_MARKDOWN_COMMENT.equals(type)) to--; } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/SmartSemicolonAutoEditStrategy.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/SmartSemicolonAutoEditStrategy.java index 95cef7623be..96d898379a7 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/SmartSemicolonAutoEditStrategy.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/SmartSemicolonAutoEditStrategy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -985,6 +985,8 @@ private static int nextPartitionOrLineEnd(IDocument document, ITextSelection lin private static int getValidPositionForPartition(IDocument doc, ITypedRegion partition, int maxOffset) { final int INVALID= -1; + if (IJavaPartitions.JAVA_MARKDOWN_COMMENT.equals(partition.getType())) + return INVALID; if (IJavaPartitions.JAVA_DOC.equals(partition.getType())) return INVALID; if (IJavaPartitions.JAVA_MULTI_LINE_COMMENT.equals(partition.getType())) diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavaSourceHover.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavaSourceHover.java index ae660c206dc..d31910161b4 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavaSourceHover.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/hover/JavaSourceHover.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2022 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -272,6 +272,7 @@ void setVisibleRegion(SourceViewer sourceViewer) { partition= doc.getPartition(IJavaPartitions.JAVA_PARTITIONING, offset, false); switch (partition.getType()) { case IJavaPartitions.JAVA_DOC: + case IJavaPartitions.JAVA_MARKDOWN_COMMENT: case IJavaPartitions.JAVA_SINGLE_LINE_COMMENT: case IJavaPartitions.JAVA_MULTI_LINE_COMMENT: offset+= partition.getLength(); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDocAutoIndentStrategy.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDocAutoIndentStrategy.java index aa9392b5e91..12690865297 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDocAutoIndentStrategy.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/javadoc/JavaDocAutoIndentStrategy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -43,10 +43,10 @@ import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.manipulation.CodeGeneration; -import org.eclipse.jdt.internal.corext.util.JavaModelUtil; -import org.eclipse.jdt.internal.corext.util.MethodOverrideTester; import org.eclipse.jdt.internal.core.manipulation.StubUtility; import org.eclipse.jdt.internal.core.manipulation.util.Strings; +import org.eclipse.jdt.internal.corext.util.JavaModelUtil; +import org.eclipse.jdt.internal.corext.util.MethodOverrideTester; import org.eclipse.jdt.internal.corext.util.SuperTypeHierarchyCache; import org.eclipse.jdt.ui.IWorkingCopyManager; @@ -104,8 +104,12 @@ private void indentAfterNewLine(IDocument d, DocumentCommand c) { if (firstNonWS < offset) { if (d.getChar(firstNonWS) == '/') { - // Javadoc started on this line - buf.append(" * "); //$NON-NLS-1$ + // Javadoc/markdown started on this line + if (d.getChar(firstNonWS+1) == '/') { + buf.append("///"); //$NON-NLS-1$ + } else { + buf.append(" * "); //$NON-NLS-1$ + } if (isPreferenceTrue(PreferenceConstants.EDITOR_CLOSE_JAVADOCS) && isNewComment(d, offset)) { c.shiftsCaret= false; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/JavaSourceViewerConfiguration.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/JavaSourceViewerConfiguration.java index a3d022a3eec..afa83d91b3e 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/JavaSourceViewerConfiguration.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/JavaSourceViewerConfiguration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -407,6 +407,10 @@ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceVie reconciler.setDamager(dr, IJavaPartitions.JAVA_DOC); reconciler.setRepairer(dr, IJavaPartitions.JAVA_DOC); + dr= new DefaultDamagerRepairer(getJavaDocScanner()); + reconciler.setDamager(dr, IJavaPartitions.JAVA_MARKDOWN_COMMENT); + reconciler.setRepairer(dr, IJavaPartitions.JAVA_MARKDOWN_COMMENT); + dr= new DefaultDamagerRepairer(getMultilineCommentScanner()); reconciler.setDamager(dr, IJavaPartitions.JAVA_MULTI_LINE_COMMENT); reconciler.setRepairer(dr, IJavaPartitions.JAVA_MULTI_LINE_COMMENT); @@ -457,6 +461,9 @@ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { ContentAssistProcessor javadocProcessor= new JavadocCompletionProcessor(getEditor(), assistant); assistant.setContentAssistProcessor(javadocProcessor, IJavaPartitions.JAVA_DOC); + ContentAssistProcessor markdownProcessor= new JavadocCompletionProcessor(getEditor(), assistant); + assistant.setContentAssistProcessor(markdownProcessor, IJavaPartitions.JAVA_MARKDOWN_COMMENT); + ContentAssistProcessor multiLineStringProcessor= new JavaCompletionProcessor(getEditor(), assistant, IJavaPartitions.JAVA_MULTI_LINE_STRING); assistant.setContentAssistProcessor(multiLineStringProcessor, IJavaPartitions.JAVA_MULTI_LINE_STRING); @@ -514,6 +521,7 @@ public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, Str if (contentType != null) { switch (contentType) { case IJavaPartitions.JAVA_DOC: + case IJavaPartitions.JAVA_MARKDOWN_COMMENT: case IJavaPartitions.JAVA_MULTI_LINE_COMMENT: return new IAutoEditStrategy[] { new JavaDocAutoIndentStrategy(partitioning) }; case IJavaPartitions.JAVA_STRING: @@ -539,6 +547,7 @@ public ITextDoubleClickStrategy getDoubleClickStrategy(ISourceViewer sourceViewe if (contentType != null) { switch (contentType) { case IJavaPartitions.JAVA_DOC: + case IJavaPartitions.JAVA_MARKDOWN_COMMENT: return new JavadocDoubleClickStrategy(getConfiguredDocumentPartitioning(sourceViewer)); case IJavaPartitions.JAVA_SINGLE_LINE_COMMENT: case IJavaPartitions.JAVA_MULTI_LINE_COMMENT: @@ -743,6 +752,7 @@ public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { return new String[] { IDocument.DEFAULT_CONTENT_TYPE, IJavaPartitions.JAVA_DOC, + IJavaPartitions.JAVA_MARKDOWN_COMMENT, IJavaPartitions.JAVA_MULTI_LINE_COMMENT, IJavaPartitions.JAVA_SINGLE_LINE_COMMENT, IJavaPartitions.JAVA_STRING, @@ -860,6 +870,7 @@ public IInformationPresenter getOutlinePresenter(ISourceViewer sourceViewer, boo IInformationProvider provider= new JavaElementProvider(getEditor(), doCodeResolve); presenter.setInformationProvider(provider, IDocument.DEFAULT_CONTENT_TYPE); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_DOC); + presenter.setInformationProvider(provider, IJavaPartitions.JAVA_MARKDOWN_COMMENT); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_MULTI_LINE_COMMENT); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_SINGLE_LINE_COMMENT); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_STRING); @@ -905,6 +916,7 @@ public IInformationPresenter getHierarchyPresenter(ISourceViewer sourceViewer, b IInformationProvider provider= new JavaElementProvider(getEditor(), doCodeResolve); presenter.setInformationProvider(provider, IDocument.DEFAULT_CONTENT_TYPE); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_DOC); + presenter.setInformationProvider(provider, IJavaPartitions.JAVA_MARKDOWN_COMMENT); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_MULTI_LINE_COMMENT); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_SINGLE_LINE_COMMENT); presenter.setInformationProvider(provider, IJavaPartitions.JAVA_STRING); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java index f9b2da2f9e7..e212f37c39a 100755 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2011 IBM Corporation and others. + * Copyright (c) 2006, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -54,6 +54,7 @@ import org.eclipse.jdt.core.IImportDeclaration; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaElementDelta; +import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.ISourceRange; @@ -103,7 +104,8 @@ protected final class FoldingStructureComputationContext { private IType fFirstType; private boolean fHasHeaderComment; private LinkedHashMap fMap= new LinkedHashMap<>(); - private IScanner fScanner; + private IScanner fDefaultScanner; // this one may or not be the shared DefaultJavaFoldingStructureProvider.fSharedScanner + private IScanner fScannerForProject; private FoldingStructureComputationContext(IDocument document, ProjectionAnnotationModel model, boolean allowCollapsing, IScanner scanner) { Assert.isNotNull(document); @@ -111,7 +113,7 @@ private FoldingStructureComputationContext(IDocument document, ProjectionAnnotat fDocument= document; fModel= model; fAllowCollapsing= allowCollapsing; - fScanner= scanner; + fDefaultScanner= scanner; } private void setFirstType(IType type) { @@ -163,9 +165,28 @@ private ProjectionAnnotationModel getModel() { } private IScanner getScanner() { - if (fScanner == null) - fScanner= ToolFactory.createScanner(true, false, false, false); - return fScanner; + if (fScannerForProject != null) { + return fScannerForProject; + } + IJavaProject javaProject= fInput != null ? fInput.getJavaProject(): null; + if (javaProject != null) { + String projectSource= javaProject.getOption(JavaCore.COMPILER_SOURCE, true); + String projectCompliance= javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true); + if (!JavaCore.getOption(JavaCore.COMPILER_COMPLIANCE).equals(projectCompliance) + || !JavaCore.getOption(JavaCore.COMPILER_SOURCE).equals(projectSource)) { + return fScannerForProject= ToolFactory.createScanner(true, false, false, projectSource, projectCompliance); + } + } + if (fDefaultScanner == null) + fDefaultScanner= ToolFactory.createScanner(true, false, false, false); + return fDefaultScanner; + } + + private void setSource(char[] source) { + if (fDefaultScanner != null) + fDefaultScanner.setSource(source); + if (fScannerForProject != null) + fScannerForProject.setSource(source); } /** @@ -965,7 +986,7 @@ private void update(FoldingStructureComputationContext ctx) { Annotation[] changedArray= updates.toArray(new Annotation[updates.size()]); ctx.getModel().modifyAnnotations(deletedArray, additions, changedArray); - ctx.fScanner.setSource(null); + ctx.setSource(null); } private void computeFoldingStructure(FoldingStructureComputationContext ctx) { @@ -1137,6 +1158,7 @@ protected final IRegion[] computeProjectionRanges(ISourceReference reference, Fo switch (token) { case ITerminalSymbols.TokenNameCOMMENT_JAVADOC: + case ITerminalSymbols.TokenNameCOMMENT_MARKDOWN: case ITerminalSymbols.TokenNameCOMMENT_BLOCK: { int end= scanner.getCurrentTokenEndPosition() + 1; regions.add(new Region(start, end - start)); @@ -1189,7 +1211,10 @@ private IRegion computeHeaderComment(FoldingStructureComputationContext ctx) thr && (terminal != ITerminalSymbols.TokenNameenum) && (!foundComment || ((terminal != ITerminalSymbols.TokenNameimport) && (terminal != ITerminalSymbols.TokenNamepackage)))) { - if (terminal == ITerminalSymbols.TokenNameCOMMENT_JAVADOC || terminal == ITerminalSymbols.TokenNameCOMMENT_BLOCK || terminal == ITerminalSymbols.TokenNameCOMMENT_LINE) { + if (terminal == ITerminalSymbols.TokenNameCOMMENT_JAVADOC + || terminal == ITerminalSymbols.TokenNameCOMMENT_BLOCK + || terminal == ITerminalSymbols.TokenNameCOMMENT_LINE + || terminal == ITerminalSymbols.TokenNameCOMMENT_MARKDOWN) { if (!foundComment) headerStart= scanner.getCurrentTokenStartPosition(); headerEnd= scanner.getCurrentTokenEndPosition(); diff --git a/pom.xml b/pom.xml index 8813f73dabe..9a274ae941e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,15 +1,11 @@ From 30472e013dc745303074e4666a5c57e5bae61cc2 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Mon, 23 Sep 2024 10:56:35 -0400 Subject: [PATCH 12/15] Add new simplify boolean if/else cleanup (#1667) - add new SimplifyBooleanIfElseCleanUpCore which reduces an if/else statement where the then statement is a boolean return statement and the else statement is an opposite boolean return statement - add new tests to CleanUpTest - add code to ReduceIndentationCleanUp to avoid collision with new clean up - add new CleanUpNLSUtils class - fixes #1632 --- .../jdt/internal/ui/fix/CleanUpNLSUtils.java | 47 +++ .../jdt/internal/ui/fix/MultiFixMessages.java | 3 +- .../ui/fix/MultiFixMessages.properties | 3 +- .../fix/SimplifyBooleanIfElseCleanUpCore.java | 218 ++++++++++++++ .../internal/corext/fix/CleanUpConstants.java | 11 + .../internal/corext/fix/SwitchFixCore.java | 24 +- .../jdt/ui/tests/quickfix/CleanUpTest.java | 282 +++++++++++++++--- .../corext/fix/CleanUpConstantsOptions.java | 4 +- org.eclipse.jdt.ui/plugin.xml | 7 +- .../ui/fix/ReduceIndentationCleanUp.java | 10 +- .../preferences/cleanup/CleanUpMessages.java | 3 +- .../cleanup/CleanUpMessages.properties | 3 +- .../preferences/cleanup/CodeStyleTabPage.java | 5 + 13 files changed, 554 insertions(+), 66 deletions(-) create mode 100644 org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/CleanUpNLSUtils.java create mode 100644 org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SimplifyBooleanIfElseCleanUpCore.java diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/CleanUpNLSUtils.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/CleanUpNLSUtils.java new file mode 100644 index 00000000000..3f60dacd1a7 --- /dev/null +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/CleanUpNLSUtils.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.fix; + +import org.eclipse.jface.text.BadLocationException; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; + +import org.eclipse.jdt.internal.corext.refactoring.nls.NLSLine; +import org.eclipse.jdt.internal.corext.refactoring.nls.NLSScanner; + +public class CleanUpNLSUtils { + + public static NLSLine scanCurrentLine(ICompilationUnit cu, ASTNode exp) { + CompilationUnit cUnit= (CompilationUnit)exp.getRoot(); + int startLine= cUnit.getLineNumber(exp.getStartPosition()); + int lineStart= cUnit.getPosition(startLine, 0); + int endOfLine= cUnit.getPosition(startLine + 1, 0); + NLSLine[] lines; + try { + lines= NLSScanner.scan(cu.getBuffer().getText(lineStart, endOfLine - lineStart)); + if (lines.length > 0) { + return lines[0]; + } + } catch (IndexOutOfBoundsException | JavaModelException | InvalidInputException | BadLocationException e) { + e.printStackTrace(); + // fall-through + } + return null; + } + +} diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java index db45164fc8c..b105bded44a 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -73,6 +73,7 @@ private MultiFixMessages() { public static String CodeStyleCleanUp_PullUpAssignment_description; public static String CodeStyleCleanUp_ElseIf_description; public static String CodeStyleCleanUp_ReduceIndentation_description; + public static String CodeStyleCleanUp_SimplifyBooleanIfElse_description; public static String CodeStyleCleanUp_Instanceof_description; public static String CodeStyleCleanUp_numberSuffix_description; public static String CodeStyleCleanUp_QualifyNonStaticMethod_description; diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties index 286cd85bc6b..0342b02609d 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2005, 2023 IBM Corporation and others. +# Copyright (c) 2005, 2024 IBM Corporation and others. # # This program and the accompanying materials # are made available under the terms of the Eclipse Public License 2.0 @@ -37,6 +37,7 @@ CodeStyleCleanUp_ExtractIncrement_description=Extract increment/decrement from s CodeStyleCleanUp_PullUpAssignment_description=Pull up assignment CodeStyleCleanUp_ElseIf_description=Combine nested 'if' statement in 'else' block to 'else if' CodeStyleCleanUp_ReduceIndentation_description=Reduce indentation +CodeStyleCleanUp_SimplifyBooleanIfElse_description=Simplify boolean if/else to a single return if possible CodeStyleCleanUp_Instanceof_description=Use instanceof keyword instead of Class.isInstance() CodeStyleCleanUp_numberSuffix_description=Use uppercase for long literal suffix CodeFormatFix_RemoveTrailingWhitespace_changeDescription=Remove trailing whitespace diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SimplifyBooleanIfElseCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SimplifyBooleanIfElseCleanUpCore.java new file mode 100644 index 00000000000..98967da17bf --- /dev/null +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SimplifyBooleanIfElseCleanUpCore.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.fix; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.text.edits.TextEditGroup; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BooleanLiteral; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.PatternInstanceofExpression; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; + +import org.eclipse.jdt.internal.corext.fix.CleanUpConstants; +import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFixCore; +import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperationWithSourceRange; +import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore; +import org.eclipse.jdt.internal.corext.refactoring.nls.NLSElement; +import org.eclipse.jdt.internal.corext.refactoring.nls.NLSLine; +import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; + +import org.eclipse.jdt.ui.cleanup.CleanUpRequirements; +import org.eclipse.jdt.ui.cleanup.ICleanUpFix; +import org.eclipse.jdt.ui.text.java.IProblemLocation; + +public class SimplifyBooleanIfElseCleanUpCore extends AbstractMultiFix { + + public SimplifyBooleanIfElseCleanUpCore() { + this(Collections.emptyMap()); + } + + public SimplifyBooleanIfElseCleanUpCore(final Map options) { + super(options); + } + + @Override + public CleanUpRequirements getRequirements() { + boolean requireAST= isEnabled(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE); + return new CleanUpRequirements(requireAST, false, false, null); + } + + @Override + public String[] getStepDescriptions() { + if (isEnabled(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE)) { + return new String[] { MultiFixMessages.CodeStyleCleanUp_SimplifyBooleanIfElse_description }; + } + + return new String[0]; + } + + @Override + public String getPreview() { + StringBuilder bld= new StringBuilder(); + if (isEnabled(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE)) { + bld.append("return i > 0;\n"); //$NON-NLS-1$ + } else { + bld.append("if (i > 0) {\n"); //$NON-NLS-1$ + bld.append(" return true;\n"); //$NON-NLS-1$ + bld.append("} else {\n"); //$NON-NLS-1$ + bld.append(" return false;\n"); //$NON-NLS-1$ + bld.append("}\n"); //$NON-NLS-1$ + } + + return bld.toString(); + } + + @Override + public boolean canFix(ICompilationUnit compilationUnit, IProblemLocation problem) { + // TODO Auto-generated method stub + return false; + } + + public static enum SimplifyStatus { + INVALID, VALID_THEN_TRUE, VALID_ELSE_TRUE + } + + public static SimplifyStatus verifyBooleanIfElse(final IfStatement ifStatement) { + if (ifStatement.getElseStatement() == null || ifStatement.getExpression() instanceof PatternInstanceofExpression) { + return SimplifyStatus.INVALID; + } + + boolean thenValue= true; + + Statement thenStatement= ifStatement.getThenStatement(); + if (thenStatement instanceof ReturnStatement returnStatement) { + if (returnStatement.getExpression() instanceof BooleanLiteral literal) { + thenValue= literal.booleanValue(); + } + } else if (thenStatement instanceof Block block && block.statements().size() == 1 + && block.statements().get(0) instanceof ReturnStatement returnStatement) { + if (returnStatement.getExpression() instanceof BooleanLiteral literal) { + thenValue= literal.booleanValue(); + } else { + return SimplifyStatus.INVALID; + } + } else { + return SimplifyStatus.INVALID; + } + + Statement elseStatement= ifStatement.getElseStatement(); + if (elseStatement instanceof ReturnStatement returnStatement) { + if (returnStatement.getExpression() instanceof BooleanLiteral literal) { + if (literal.booleanValue() == thenValue) { + return SimplifyStatus.INVALID; + } + } + } else if (elseStatement instanceof Block block && block.statements().size() == 1 + && block.statements().get(0) instanceof ReturnStatement returnStatement) { + if (returnStatement.getExpression() instanceof BooleanLiteral literal) { + if (literal.booleanValue() == thenValue) { + return SimplifyStatus.INVALID; + } + } else { + return SimplifyStatus.INVALID; + } + } else { + return SimplifyStatus.INVALID; + } + return thenValue == true ? SimplifyStatus.VALID_THEN_TRUE : SimplifyStatus.VALID_ELSE_TRUE; + } + + @Override + protected ICleanUpFix createFix(CompilationUnit unit) throws CoreException { + if (!isEnabled(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE)) { + return null; + } + + final List rewriteOperations= new ArrayList<>(); + + unit.accept(new ASTVisitor() { + @Override + public boolean visit(final IfStatement visited) { + SimplifyStatus status= verifyBooleanIfElse(visited); + if (status != SimplifyStatus.INVALID) { + rewriteOperations.add(new SimplifyBooleanIfElseOperation(visited, status)); + } + return true; + } + }); + + if (rewriteOperations.isEmpty()) { + return null; + } + + return new CompilationUnitRewriteOperationsFixCore(MultiFixMessages.CodeStyleCleanUp_SimplifyBooleanIfElse_description, unit, + rewriteOperations.toArray(new CompilationUnitRewriteOperationWithSourceRange[0])); + } + + @Override + protected ICleanUpFix createFix(CompilationUnit unit, IProblemLocation[] problems) throws CoreException { + // TODO Auto-generated method stub + return null; + } + + private static class SimplifyBooleanIfElseOperation extends CompilationUnitRewriteOperationWithSourceRange { + private final IfStatement visited; + private final SimplifyStatus status; + + public SimplifyBooleanIfElseOperation(final IfStatement visited, final SimplifyStatus status) { + this.visited= visited; + this.status= status; + } + + @Override + public void rewriteASTInternal(final CompilationUnitRewrite cuRewrite, final LinkedProposalModelCore linkedModel) throws CoreException { + ASTRewrite rewrite= cuRewrite.getASTRewrite(); + TextEditGroup group= createTextEditGroup(MultiFixMessages.CodeStyleCleanUp_SimplifyBooleanIfElse_description, cuRewrite); + + CompilationUnit cu= (CompilationUnit) visited.getRoot(); + ICompilationUnit icu= (ICompilationUnit) cu.getJavaElement(); + NLSLine nlsLine= CleanUpNLSUtils.scanCurrentLine(icu, visited.getExpression()); + StringBuilder nlsBuffer= new StringBuilder(); + if (nlsLine != null) { + NLSElement[] nlsElements= nlsLine.getElements(); + for (int i= 0; i < nlsElements.length; ++i) { + NLSElement element= nlsElements[i]; + if (element.hasTag()) { + nlsBuffer.append(" //$NON-NLS-" + (i + 1) + "$"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + ReturnStatement newReturn= null; + String ifExpression= icu.getBuffer().getText(visited.getExpression().getStartPosition(), visited.getExpression().getLength()); + if (status == SimplifyStatus.VALID_THEN_TRUE) { + newReturn= (ReturnStatement) rewrite.createStringPlaceholder("return " + ifExpression + ";" + nlsBuffer.toString(), ASTNode.RETURN_STATEMENT); //$NON-NLS-1$ //$NON-NLS-2$ + } else { // otherwise we need to reverse the if expression so it returns the right value + newReturn= (ReturnStatement) rewrite.createStringPlaceholder("return !(" + ifExpression + ");" + //$NON-NLS-1$ //$NON-NLS-2$ + nlsBuffer.toString(), ASTNode.RETURN_STATEMENT); + } + rewrite.replace(visited, newReturn, group); + } + + } + +} diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java index e6f1d8e491b..5967c1892f7 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java @@ -2112,6 +2112,17 @@ public class CleanUpConstants { */ public static final String REDUCE_INDENTATION= "cleanup.reduce_indentation"; //$NON-NLS-1$ + /** + * Convert if/else that returns true or false based on condition to a single return statement if possible. + *

+ * Possible values: {TRUE, FALSE} + * + * @see CleanUpOptions#TRUE + * @see CleanUpOptions#FALSE + * @since 4.35 + */ + public static final String SIMPLIFY_BOOLEAN_IF_ELSE= "cleanup.simplify_boolean_if_else"; //$NON-NLS-1$ + /** * Uses an {@code instanceof} expression to check an object against a hardcoded class. *

diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java index 8d169e49fbb..9893a8b5270 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java @@ -24,14 +24,11 @@ import org.eclipse.text.edits.TextEditGroup; -import org.eclipse.jface.text.BadLocationException; - import org.eclipse.jdt.core.IBuffer; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.compiler.InvalidInputException; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; @@ -64,11 +61,11 @@ import org.eclipse.jdt.internal.corext.dom.InterruptibleVisitor; import org.eclipse.jdt.internal.corext.refactoring.nls.NLSElement; import org.eclipse.jdt.internal.corext.refactoring.nls.NLSLine; -import org.eclipse.jdt.internal.corext.refactoring.nls.NLSScanner; import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; import org.eclipse.jdt.ui.cleanup.ICleanUpFix; +import org.eclipse.jdt.internal.ui.fix.CleanUpNLSUtils; import org.eclipse.jdt.internal.ui.fix.MultiFixMessages; public class SwitchFixCore extends CompilationUnitRewriteOperationsFixCore { @@ -383,7 +380,7 @@ private Variable extractVariableWithConstantStringValue(final Expression variabl && constant.resolveConstantExpressionValue() != null) { CompilationUnit cu= (CompilationUnit) variable.getRoot(); ICompilationUnit icu= (ICompilationUnit) cu.getJavaElement(); - NLSLine nlsLine= scanCurrentLine(icu, variable); + NLSLine nlsLine= CleanUpNLSUtils.scanCurrentLine(icu, variable); boolean hasTag= false; if (nlsLine != null) { for (NLSElement element : nlsLine.getElements()) { @@ -402,23 +399,6 @@ private Variable extractVariableWithConstantStringValue(final Expression variabl return null; } - private NLSLine scanCurrentLine(ICompilationUnit cu, Expression exp) { - CompilationUnit cUnit= (CompilationUnit)exp.getRoot(); - int startLine= cUnit.getLineNumber(exp.getStartPosition()); - int lineStart= cUnit.getPosition(startLine, 0); - int endOfLine= cUnit.getPosition(startLine + 1, 0); - NLSLine[] lines; - try { - lines= NLSScanner.scan(cu.getBuffer().getText(lineStart, endOfLine - lineStart)); - if (lines.length > 0) { - return lines[0]; - } - } catch (IndexOutOfBoundsException | JavaModelException | InvalidInputException | BadLocationException e) { - // fall-through - } - return null; - } - } } diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java index 15138fb71bc..f406680d4a1 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java @@ -16622,58 +16622,266 @@ public void testDoNotReturnExpression() throws Exception { package test1; public class E { - private int i; + private int i; + public int doNotInlineFieldAssignment1() { + i = 0; + return i; + } - public int doNotInlineFieldAssignment1() { - i = 0; - return i; + public int doNotInlineFieldAssignment2() { + this.i = 0; + return i; + } + + public int doNotInlineVariableInFinally() { + int i = 0; + try { + i = 1; + return i; + } finally { + System.out.println(i); + } + } + public int doNotInlineCatchVariableInFinally() { + int i = 0; + try { + return 1; + } catch (Exception e) { + i = 1; + return 2; + } finally { + System.out.println(i); + } + } + + public int doNotInlineVariableInFarAwayFinally() { + int i = 0; + try { + try { + i = 1; + return i; + } finally { + System.out.println("Finished"); + } + } finally { + System.out.println(i); + } + } + } + """; + ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null); + + enable(CleanUpConstants.RETURN_EXPRESSION); + + assertRefactoringHasNoChange(new ICompilationUnit[] { cu }); + } + + @Test + public void testSimplifyBooleanIfElseExpression01() throws Exception { + // Given + IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null); + String given= """ + package test1; + + public class E { + public boolean simplifyNormal(int x) { + if (x > 0 && x < 7) { + return true; + } else { + return false; + } } - public int doNotInlineFieldAssignment2() { - this.i = 0; - return i; + public boolean simplifyReverse(int x) { + if (x > 0 && x < 7) { + return false; + } else { + return true; + } } - public int doNotInlineVariableInFinally() { - int i = 0; - try { - i = 1; - return i; - } finally { - System.out.println(i); + public boolean simplifyCompoundIf(int x) { + if (x < 0) { + return false; + } else if (x < 7) { + return true; + } else { + return false; + } + } + + public boolean simplifyNLS(String x) { + if (x.equals("abc")) { //$NON-NLS-1$ + return true; + } else { + return false; + } + } + } + """; + + String expected= """ + package test1; + + public class E { + public boolean simplifyNormal(int x) { + return x > 0 && x < 7; + } + + public boolean simplifyReverse(int x) { + return !(x > 0 && x < 7); + } + + public boolean simplifyCompoundIf(int x) { + if (x < 0) { + return false; + } else + return x < 7; + } + + public boolean simplifyNLS(String x) { + return x.equals("abc"); //$NON-NLS-1$ + } + } + """; + + // When + ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null); + enable(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE); + + // Then + assertNotEquals("The class must be changed", given, expected); + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected }, + new HashSet<>(Arrays.asList(MultiFixMessages.CodeStyleCleanUp_SimplifyBooleanIfElse_description))); + } + + @Test + public void testSimplifyBooleanIfElseExpression02() throws Exception { + // Given + IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null); + String given= """ + package test1; + + public class E { + public boolean simplifyNormal(int x) { + if (x > 0 && x < 7) { + return true; + } else { + return false; } } - public int doNotInlineCatchVariableInFinally() { - int i = 0; - try { - return 1; - } catch (Exception e) { - i = 1; - return 2; - } finally { - System.out.println(i); + public boolean simplifyReverse(int x) { + if (x > 0 && x < 7) { + return false; + } else { + return true; } } - public int doNotInlineVariableInFarAwayFinally() { - int i = 0; - try { - try { - i = 1; - return i; - } finally { - System.out.println("Finished"); - } - } finally { - System.out.println(i); + public boolean simplifyCompoundIf(int x) { + if (x < 0) { + return false; + } else if (x < 7) { + return true; + } else { + return false; + } + } + + public boolean simplifyNLS(String x) { + if (x.equals("abc")) { //$NON-NLS-1$ + return true; + } else { + return false; + } + } + } + """; + + String expected= """ + package test1; + + public class E { + public boolean simplifyNormal(int x) { + return x > 0 && x < 7; + } + + public boolean simplifyReverse(int x) { + return !(x > 0 && x < 7); + } + + public boolean simplifyCompoundIf(int x) { + if (x < 0) { + return false; + } else + return x < 7; + } + + public boolean simplifyNLS(String x) { + return x.equals("abc"); //$NON-NLS-1$ + } + } + """; + + // When + ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null); + enable(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE); + enable(CleanUpConstants.REDUCE_INDENTATION); + + // Then + assertNotEquals("The class must be changed", given, expected); + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected }, + new HashSet<>(Arrays.asList(MultiFixMessages.CodeStyleCleanUp_SimplifyBooleanIfElse_description))); + } + + @Test + public void testDoNotSimplifyBooleanIfElseExpression01() throws Exception { + // Given + IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null); + String given= """ + package test1; + + public class E { + public boolean doNotSimplifyIfBooleanSame(int x) { + if (x > 0 && x < 7) { + return true; + } else { + return true; + } + } + + public boolean doNotSimplifyIfBooleanTheSame2(int x) { + if (x > 0 && x < 7) { + return false; + } else { + return false; } } + + public boolean doNotSimplifyIfNoElse(int x) { + if (x < 0) { + return false; + } else if (x < 7) { + return true; + } + return false; + } + + public int doNotSimplifyNoneBoolean(String x) { + if (x.equals("abc")) { //$NON-NLS-1$ + return 1; + } else { + return 2; + } + } } - """; - ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null); + """; - enable(CleanUpConstants.RETURN_EXPRESSION); + + ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null); + + enable(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE); assertRefactoringHasNoChange(new ICompilationUnit[] { cu }); } diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java index 7b5ac1e4689..fff49f16e4d 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2023 IBM Corporation and others. + * Copyright (c) 2018, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -57,6 +57,7 @@ private static void setEclipseDefaultSettings(CleanUpOptions options) { options.setOption(PULL_UP_ASSIGNMENT, CleanUpOptions.FALSE); options.setOption(ELSE_IF, CleanUpOptions.FALSE); + options.setOption(SIMPLIFY_BOOLEAN_IF_ELSE, CleanUpOptions.FALSE); options.setOption(REDUCE_INDENTATION, CleanUpOptions.FALSE); options.setOption(INSTANCEOF, CleanUpOptions.FALSE); options.setOption(NUMBER_SUFFIX, CleanUpOptions.FALSE); @@ -242,6 +243,7 @@ private static void setSaveParticipantSettings(CleanUpOptions options) { options.setOption(PULL_UP_ASSIGNMENT, CleanUpOptions.FALSE); options.setOption(ELSE_IF, CleanUpOptions.FALSE); + options.setOption(SIMPLIFY_BOOLEAN_IF_ELSE, CleanUpOptions.FALSE); options.setOption(REDUCE_INDENTATION, CleanUpOptions.FALSE); options.setOption(INSTANCEOF, CleanUpOptions.FALSE); options.setOption(NUMBER_SUFFIX, CleanUpOptions.FALSE); diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml index 450a620e65c..afcf2703239 100644 --- a/org.eclipse.jdt.ui/plugin.xml +++ b/org.eclipse.jdt.ui/plugin.xml @@ -7134,11 +7134,16 @@ class="org.eclipse.jdt.internal.ui.fix.ElseIfCleanUpCore" id="org.eclipse.jdt.ui.cleanup.else_if" runAfter="org.eclipse.jdt.ui.cleanup.variables"> + + + runAfter="org.eclipse.jdt.ui.cleanup.simplify_boolean_if_else"> @@ -197,6 +199,12 @@ public boolean visit(final IfStatement visited) { return true; } + if (isEnabled(CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE)) { + if (SimplifyBooleanIfElseCleanUpCore.verifyBooleanIfElse(visited) != SimplifyStatus.INVALID) { + return true; + } + } + if (visited.getElseStatement() != null && !ASTNodes.isInElse(visited)) { if (ASTNodes.fallsThrough(visited.getThenStatement())) { if (ASTNodes.fallsThrough(visited.getElseStatement())) { diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java index e451b64638e..e42841f5dbe 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -64,6 +64,7 @@ public class CleanUpMessages extends NLS { public static String CodeStyleTabPage_CheckboxName_ExtractIncrement; public static String CodeStyleTabPage_CheckboxName_PullUpAssignment; public static String CodeStyleTabPage_CheckboxName_ElseIf; + public static String CodeStyleTabPage_CheckboxName_SimplifyBooleanIfElse; public static String CodeStyleTabPage_CheckboxName_ReduceIndentation; public static String CodeStyleTabPage_CheckboxName_Instanceof; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties index 4e3e29fe466..0fc33bf6230 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2005, 2023 IBM Corporation and others. +# Copyright (c) 2005, 2024 IBM Corporation and others. # # This program and the accompanying materials # are made available under the terms of the Eclipse Public License 2.0 @@ -40,6 +40,7 @@ CodeStyleTabPage_RadioName_AlwaysUseBlocks=Al&ways CodeStyleTabPage_RadioName_NeverUseBlocks=Only if &necessary CodeStyleTabPage_CheckboxName_ElseIf=C&ombine nested 'if' statement in 'else' block to 'else if' CodeStyleTabPage_CheckboxName_ReduceIndentation=Reduce indentation when possible +CodeStyleTabPage_CheckboxName_SimplifyBooleanIfElse=Simplify boolean if/else to single return if possible CodeStyleTabPage_GroupName_Expressions=Expressions CodeStyleTabPage_CheckboxName_ExtractIncrement=Extract increment/decrement from statement CodeStyleTabPage_CheckboxName_PullUpAssignment=Pull up assignment diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java index ac384669e8c..d19506b5fdc 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CodeStyleTabPage.java @@ -31,6 +31,7 @@ import org.eclipse.jdt.internal.ui.fix.NumberSuffixCleanUp; import org.eclipse.jdt.internal.ui.fix.PullUpAssignmentCleanUp; import org.eclipse.jdt.internal.ui.fix.ReduceIndentationCleanUp; +import org.eclipse.jdt.internal.ui.fix.SimplifyBooleanIfElseCleanUpCore; import org.eclipse.jdt.internal.ui.fix.SwitchCleanUpCore; import org.eclipse.jdt.internal.ui.fix.VariableDeclarationCleanUpCore; @@ -51,6 +52,7 @@ protected AbstractCleanUp[] createPreviewCleanUps(Map values) { new NumberSuffixCleanUp(values), new InstanceofCleanUp(values), new VariableDeclarationCleanUpCore(values), + new SimplifyBooleanIfElseCleanUpCore(values), new LambdaExpressionAndMethodRefCleanUp(values) }; } @@ -71,6 +73,9 @@ protected void doCreatePreferences(Composite composite, int numColumns) { CheckboxPreference elseIf= createCheckboxPref(controlGroup, numColumns, CleanUpMessages.CodeStyleTabPage_CheckboxName_ElseIf, CleanUpConstants.ELSE_IF, CleanUpModifyDialog.FALSE_TRUE); registerPreference(elseIf); + final CheckboxPreference simplifyIfElse= createCheckboxPref(controlGroup, numColumns, CleanUpMessages.CodeStyleTabPage_CheckboxName_SimplifyBooleanIfElse, CleanUpConstants.SIMPLIFY_BOOLEAN_IF_ELSE, CleanUpModifyDialog.FALSE_TRUE); + registerPreference(simplifyIfElse); + final CheckboxPreference reduceIndentationPref= createCheckboxPref(controlGroup, numColumns, CleanUpMessages.CodeStyleTabPage_CheckboxName_ReduceIndentation, CleanUpConstants.REDUCE_INDENTATION, CleanUpModifyDialog.FALSE_TRUE); registerPreference(reduceIndentationPref); From dedfb121e02299ffd691ef13c1145f1f7e72b8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=8A?= =?UTF-8?q?=D1=80=20=D0=9A=D1=83=D1=80=D1=82=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Tue, 10 Sep 2024 10:03:56 +0300 Subject: [PATCH 13/15] Build on ubuntu-latest centos-latest is deprecated as per: https://github.com/eclipse-cbi/jiro-agents/blob/master/README.md --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6b0ad979049..968b85b28dc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,7 +6,7 @@ pipeline { timestamps() } agent { - label "centos-latest" + label "ubuntu-latest" } tools { maven 'apache-maven-latest' From e669610ab4ddb4362d205c6850b5d3304f503f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=8A?= =?UTF-8?q?=D1=80=20=D0=9A=D1=83=D1=80=D1=82=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Wed, 18 Sep 2024 08:32:10 +0300 Subject: [PATCH 14/15] Show error on SmokeViewsTest failure --- .../ui/org/eclipse/jdt/ui/tests/views/SmokeViewsTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/views/SmokeViewsTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/views/SmokeViewsTest.java index 102b42169da..686e72bc5c3 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/views/SmokeViewsTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/views/SmokeViewsTest.java @@ -138,7 +138,8 @@ private void smokeTest(String viewId) throws PartInitException { view = window.getActivePage().showView(viewId); assertNotNull("View " + viewId + " should be created", view); DisplayHelper.driveEventQueue(Display.getDefault()); - if(view instanceof org.eclipse.ui.internal.ErrorViewPart) { + if(view instanceof org.eclipse.ui.internal.ErrorViewPart errorView) { + System.out.println(errorView.getContentDescription()); fail("Error happened on opening view " + viewId); } } From 66053c1a731d0bf48f023e226f708ff056bf8dd8 Mon Sep 17 00:00:00 2001 From: Jay Arthanareeswaran Date: Wed, 25 Sep 2024 09:14:03 +0530 Subject: [PATCH 15/15] [23] Markdown doc comments with codeblock don't parse Javadoc tags afterwards (#1665) Test case for https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2980 --- .../ui/tests/hover/MarkdownCommentTests.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java index f7c03e78fa3..e44c2b1fc6a 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/MarkdownCommentTests.java @@ -808,4 +808,95 @@ void paraAfterCode() { } """; assertHtmlContent(expectedContent, actualHtmlContent); } + @Test + public void testGH2980() throws CoreException { + String source= """ + package p; + + public class X { + /// This is a test Javadoc for method test1() + /// ```java + /// test1(42); + /// ``` + /// @param a some parameter for test1 + public void test1(int a) {} + /// + /// This is a test Javadoc for method test2() + /// 'test2(0)' + /// @param b some parameter for test1 + public void test2(int b) {} + /// This is a test Javadoc for method test3() + /// ```java + /// int r = test3(); + /// System.out.println(r); + /// ``` + /// @return an int value + public int test3() { + return 0; + } + /// This is a test Javadoc for method test4() + /// Invocation method 1: + /// ```java + /// int r = test4(); + /// System.out.println(r); + /// ``` + /// Invocation method 2: + /// ```java + /// System.out.println(test4()); + /// ``` + /// @return an int value + /// @param i an int param + public int test4(int i) { + return 0; + } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/X.java", source, null); + assertNotNull("X.java", cu); + + IType type= cu.getType("X"); + + IMethod method= type.getMethods()[0]; + String actualHtmlContent= getHoverHtmlContent(cu, method); + String expectedContent= """ +

This is a test Javadoc for method test1()

+
test1(42);
+					
+
Parameters:
a some parameter for test1
+ """; + assertHtmlContent(expectedContent, actualHtmlContent); + + method= type.getMethods()[1]; + actualHtmlContent= getHoverHtmlContent(cu, method); + expectedContent= """ +

This is a test Javadoc for method test2() + 'test2(0)'

+
Parameters:
b some parameter for test1
+ """; + assertHtmlContent(expectedContent, actualHtmlContent); + + method= type.getMethods()[2]; + actualHtmlContent= getHoverHtmlContent(cu, method); + expectedContent= """ +

This is a test Javadoc for method test3()

+
int r = test3();
+					System.out.println(r);
+					
+
Returns:
an int value
+ """; + method= type.getMethods()[3]; + actualHtmlContent= getHoverHtmlContent(cu, method); + expectedContent= """ +

This is a test Javadoc for method test4() + Invocation method 1:

+
int r = test4();
+					System.out.println(r);
+					
+

Invocation method 2:

+
System.out.println(test4());
+					
+
Parameters:
i an int param
Returns:
an int value
+ """; + assertHtmlContent(expectedContent, actualHtmlContent); + } }