diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/CodeTemplateContextType.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/CodeTemplateContextType.java index d2f1198367d..eaefd786341 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/CodeTemplateContextType.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/CodeTemplateContextType.java @@ -66,6 +66,7 @@ public class CodeTemplateContextType extends TemplateContextType { public static final String MARKDOWNGETTERCOMMENT_CONTEXTTYPE= "markdowngettercomment_context"; //$NON-NLS-1$ public static final String MARKDOWNSETTERCOMMENT_CONTEXTTYPE= "markdownsettercomment_context"; //$NON-NLS-1$ public static final String MARKDOWNMODULECOMMENT_CONTEXTTYPE= "markdownmodulecomment_context"; //$NON-NLS-1$ + public static final String MARKDOWNOVERRIDECOMMENT_CONTEXTTYPE= "markdownoverridecomment_context"; //$NON-NLS-1$ /* templates */ @@ -104,6 +105,7 @@ public class CodeTemplateContextType extends TemplateContextType { public static final String MARKDOWNGETTERCOMMENT_ID= CODETEMPLATES_PREFIX + "markdowngetter" + COMMENT_SUFFIX; //$NON-NLS-1$ public static final String MARKDOWNSETTERCOMMENT_ID= CODETEMPLATES_PREFIX + "markdownsetter" + COMMENT_SUFFIX; //$NON-NLS-1$ public static final String MARKDOWNMODULECOMMENT_ID= CODETEMPLATES_PREFIX + "markdownmodule" + COMMENT_SUFFIX; //$NON-NLS-1$ + public static final String MARKDOWNOVERRIDECOMMENT_ID= CODETEMPLATES_PREFIX + "markdownoverride" + COMMENT_SUFFIX; //$NON-NLS-1$ /* resolver types */ public static final String EXCEPTION_TYPE= "exception_type"; //$NON-NLS-1$ @@ -285,6 +287,7 @@ public CodeTemplateContextType(String contextName) { addCompilationUnitVariables(); fIsComment= true; break; + case MARKDOWNOVERRIDECOMMENT_CONTEXTTYPE: case OVERRIDECOMMENT_CONTEXTTYPE: addResolver(new CodeTemplateVariableResolver(ENCLOSING_TYPE, JavaManipulationMessages.CodeTemplateContextType_variable_description_enclosingtype)); addResolver(new CodeTemplateVariableResolver(ENCLOSING_METHOD, JavaManipulationMessages.CodeTemplateContextType_variable_description_enclosingmethod)); @@ -403,6 +406,7 @@ public static void registerContextTypes(ContextTypeRegistry registry) { registry.addContextType(new CodeTemplateContextType(CodeTemplateContextType.MARKDOWNDELEGATECOMMENT_CONTEXTTYPE)); registry.addContextType(new CodeTemplateContextType(CodeTemplateContextType.MARKDOWNGETTERCOMMENT_CONTEXTTYPE)); registry.addContextType(new CodeTemplateContextType(CodeTemplateContextType.MARKDOWNSETTERCOMMENT_CONTEXTTYPE)); + registry.addContextType(new CodeTemplateContextType(CodeTemplateContextType.MARKDOWNOVERRIDECOMMENT_CONTEXTTYPE)); } /* diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/StubUtility.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/StubUtility.java index 2c261493ee4..19bb56dd895 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/StubUtility.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/core/manipulation/StubUtility.java @@ -326,6 +326,11 @@ public static String getTypeComment(ICompilationUnit cu, String typeQualifiedNam throw new CoreException(new Status(IStatus.ERROR, JavaManipulation.ID_PLUGIN, IStatus.ERROR, e.getMessage(), e)); } } + if (useMarkdown && typeParameterNames.length == 0 && params.length == 0 ) { + str = document.get(); + str = str.replace("\n/// ", ""); //$NON-NLS-1$ //$NON-NLS-2$ + return str; + } return document.get(); } @@ -444,7 +449,7 @@ public static String getMethodComment(ICompilationUnit cu, String typeName, Stri if (delegate) templateName= useMarkdown ? CodeTemplateContextType.MARKDOWNDELEGATECOMMENT_ID : CodeTemplateContextType.DELEGATECOMMENT_ID; else - templateName= CodeTemplateContextType.OVERRIDECOMMENT_ID; + templateName= useMarkdown ? CodeTemplateContextType.MARKDOWNOVERRIDECOMMENT_ID : CodeTemplateContextType.OVERRIDECOMMENT_ID; } Template template= getCodeTemplate(templateName, cu.getJavaProject()); if (template == null) { @@ -720,7 +725,7 @@ public static String getMethodComment(ICompilationUnit cu, String typeName, Meth if (delegate) templateName= useMarkdown ? CodeTemplateContextType.MARKDOWNDELEGATECOMMENT_ID : CodeTemplateContextType.DELEGATECOMMENT_ID; else - templateName= CodeTemplateContextType.OVERRIDECOMMENT_ID; + templateName= useMarkdown ? CodeTemplateContextType.MARKDOWNOVERRIDECOMMENT_ID : CodeTemplateContextType.OVERRIDECOMMENT_ID; } Template template= getCodeTemplate(templateName, cu.getJavaProject()); if (template == null) { diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddMissingMethodDeclarationFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddMissingMethodDeclarationFixCore.java index e825dbd24fb..c700383c82e 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddMissingMethodDeclarationFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddMissingMethodDeclarationFixCore.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 IBM Corporation and others. + * Copyright (c) 2024, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -16,9 +16,14 @@ import java.util.List; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTMatcher; import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.CompilationUnit; @@ -33,7 +38,6 @@ import org.eclipse.jdt.core.dom.ParameterizedType; import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.ReturnStatement; -import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; @@ -42,9 +46,12 @@ import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.core.dom.rewrite.ListRewrite; +import org.eclipse.jdt.core.refactoring.CompilationUnitChange; import org.eclipse.jdt.internal.corext.dom.ASTNodes; +import org.eclipse.jdt.internal.corext.dom.AbortSearchException; import org.eclipse.jdt.internal.corext.dom.Bindings; +import org.eclipse.jdt.internal.corext.refactoring.Checks; import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages; @@ -52,8 +59,32 @@ public class AddMissingMethodDeclarationFixCore extends CompilationUnitRewriteOperationsFixCore { + private final CompilationUnit fCompilationUnit; + public AddMissingMethodDeclarationFixCore(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation operation) { super(name, compilationUnit, operation); + fCompilationUnit= compilationUnit; + } + + /** + * Returns the compilation unit being modified by this fix. + * This may be different from the compilation unit containing the quick assist invocation. + * + * @return the target compilation unit + */ + public ICompilationUnit getCompilationUnit() { + return (ICompilationUnit) fCompilationUnit.getJavaElement(); + } + + @Override + public CompilationUnitChange createChange(IProgressMonitor progressMonitor) throws CoreException { + CompilationUnitChange change= super.createChange(progressMonitor); + if (change != null) { + // When modifying a file that may not be open in an editor, we need to ensure + // the change is saved. The default LEAVE_DIRTY mode doesn't work for unopened files. + change.setSaveMode(org.eclipse.ltk.core.refactoring.TextFileChange.FORCE_SAVE); + } + return change; } public static AddMissingMethodDeclarationFixCore createAddMissingMethodDeclaration(CompilationUnit compilationUnit, ASTNode node) { @@ -64,7 +95,37 @@ public static AddMissingMethodDeclarationFixCore createAddMissingMethodDeclarati return null; } - TypeDeclaration typeDeclaration= ASTNodes.getParent(methodReferenceNode, TypeDeclaration.class); + IMethodBinding refBinding= methodReferenceNode.resolveMethodBinding(); + if (refBinding != null) { + return null; + } + + Expression exp= methodReferenceNode.getExpression(); + ITypeBinding expBinding= exp.resolveTypeBinding(); + if (expBinding == null) { + return null; + } + + IJavaElement element= expBinding.getJavaElement(); + CompilationUnit cu= null; + if (element == null) { + return null; + } + element= element.getAncestor(IJavaElement.COMPILATION_UNIT); + if (element instanceof ICompilationUnit icu) { + cu= Checks.convertICUtoCU(icu); + } + if (cu == null) { + return null; + } + + TypeDeclaration typeDeclaration= null; + TypeDeclarationFinder finder= new TypeDeclarationFinder(expBinding); + try { + cu.accept(finder); + } catch (AbortSearchException e) { + typeDeclaration= finder.getTypeDeclaration(); + } if (typeDeclaration == null) { return null; } @@ -85,7 +146,7 @@ public static AddMissingMethodDeclarationFixCore createAddMissingMethodDeclarati Assignment variableAssignment= ASTNodes.getParent(methodReferenceNode, Assignment.class); String label= Messages.format(CorrectionMessages.AddUnimplementedMethodReferenceOperation_AddMissingMethod_group, - new String[] { methodReferenceNode.getName().getIdentifier(), typeDeclaration.getName().getIdentifier() }); + new String[] { methodReferenceNode.getName().getIdentifier(), expBinding.getName() }); if ((variableAssignment != null || variableDeclarationStatement != null) && methodInvocationNode == null) { /* @@ -109,7 +170,9 @@ public static AddMissingMethodDeclarationFixCore createAddMissingMethodDeclarati if (returnType.binding == null) { return null; } - return new AddMissingMethodDeclarationFixCore(label, compilationUnit, new AddMissingMethodDeclarationProposalOperation(methodReferenceNode, returnType, null)); + // Note: passing cu (the target compilation unit) instead of compilationUnit (the current one) + // This fix modifies the target type's compilation unit, which may be different from the current file + return new AddMissingMethodDeclarationFixCore(label, cu, new AddMissingMethodDeclarationProposalOperation(methodReferenceNode, typeDeclaration, returnType, null)); } else { if (methodInvocationNode == null) { return null; @@ -132,7 +195,9 @@ public static AddMissingMethodDeclarationFixCore createAddMissingMethodDeclarati // node not found return null; } - return new AddMissingMethodDeclarationFixCore(label, compilationUnit, new AddMissingMethodDeclarationProposalOperation(methodReferenceNode, null, methodBinding)); + // Note: passing cu (the target compilation unit) instead of compilationUnit (the current one) + // This fix modifies the target type's compilation unit, which may be different from the current file + return new AddMissingMethodDeclarationFixCore(label, cu, new AddMissingMethodDeclarationProposalOperation(methodReferenceNode, typeDeclaration, null, methodBinding)); } } @@ -160,6 +225,28 @@ private static class ReturnType { public ITypeBinding binding; } + private static class TypeDeclarationFinder extends ASTVisitor { + private TypeDeclaration foundDeclaration; + private final ITypeBinding fTypeBinding; + + public TypeDeclarationFinder(ITypeBinding typeBinding) { + this.fTypeBinding= typeBinding; + } + + public TypeDeclaration getTypeDeclaration() { + return foundDeclaration; + } + + @Override + public boolean visit(TypeDeclaration node) { + if (this.fTypeBinding.isEqualTo(node.resolveBinding())) { + foundDeclaration= node; + throw new AbortSearchException(); + } + return true; + } + } + private static class AddMissingMethodDeclarationProposalOperation extends CompilationUnitRewriteOperation { @@ -167,9 +254,12 @@ private static class AddMissingMethodDeclarationProposalOperation extends Compil private ReturnType returnType; + private TypeDeclaration typeDeclaration; + private IMethodBinding methodBinding; - public AddMissingMethodDeclarationProposalOperation(ExpressionMethodReference methodReferenceNode, ReturnType returnType, IMethodBinding methodBinding) { + + public AddMissingMethodDeclarationProposalOperation(ExpressionMethodReference methodReferenceNode, TypeDeclaration typeDeclaration, ReturnType returnType, IMethodBinding methodBinding) { if (returnType == null && methodBinding == null) { throw new IllegalArgumentException("both returnType and methodBinding cannot be null."); //$NON-NLS-1$ } @@ -177,12 +267,13 @@ public AddMissingMethodDeclarationProposalOperation(ExpressionMethodReference me this.methodReferenceNode= methodReferenceNode; this.returnType= returnType; this.methodBinding= methodBinding; + this.typeDeclaration= typeDeclaration; } + @Override public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore linkedModel) throws CoreException { boolean addStaticModifier= false; - TypeDeclaration typeDeclaration= ASTNodes.getParent(this.methodReferenceNode, TypeDeclaration.class); if (QuickAssistProcessorUtil.isTypeReferenceToInstanceMethod(methodReferenceNode)) { addStaticModifier= true; @@ -201,7 +292,7 @@ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore returnType.type= importRewrite.addImport(returnType.binding, ast); MethodDeclaration newMethodDeclaration= ast.newMethodDeclaration(); - newMethodDeclaration.setName((SimpleName) rewrite.createCopyTarget(methodReferenceNode.getName())); + newMethodDeclaration.setName(ast.newSimpleName(methodReferenceNode.getName().getFullyQualifiedName())); newMethodDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD)); if (addStaticModifier) { newMethodDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD)); @@ -241,7 +332,12 @@ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore ITypeBinding[] parameterTypesFunctionalInterface= parameterTypes[index].getFunctionalInterfaceMethod().getParameterTypes(); ITypeBinding returnTypeBindingFunctionalInterface= parameterTypes[index].getFunctionalInterfaceMethod().getReturnType(); MethodDeclaration newMethodDeclaration= ast.newMethodDeclaration(); - newMethodDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD)); + CompilationUnit root= (CompilationUnit) methodReferenceNode.getRoot(); + if (root.subtreeMatch(new ASTMatcher(), cuRewrite.getRoot())) { + newMethodDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD)); + } else { + newMethodDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD)); + } if (addStaticModifier) { newMethodDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD)); } @@ -263,7 +359,7 @@ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore addIfMissing(newMethodDeclaration, newTypeParameter); } } - newMethodDeclaration.setName((SimpleName) rewrite.createCopyTarget(methodReferenceNode.getName())); + newMethodDeclaration.setName(ast.newSimpleName(methodReferenceNode.getName().getFullyQualifiedName())); newMethodDeclaration.setReturnType2(newReturnType); pLoop: for (int i= 0; i < parameterTypesFunctionalInterface.length; i++) { ITypeBinding parameterType2= parameterTypesFunctionalInterface[i]; diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ReplaceQualifiedTypeFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ReplaceQualifiedTypeFixCore.java index e7de0233c32..9f61ad97fe3 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ReplaceQualifiedTypeFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/ReplaceQualifiedTypeFixCore.java @@ -40,6 +40,7 @@ import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.AbortSearchException; import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; +import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover; import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages; @@ -126,7 +127,8 @@ private void checkTypeBinding(ITypeBinding typeBinding) { @Override public boolean visit(QualifiedName qname) { - if (qname.getFullyQualifiedName().equals(fullQualifiedName)) { + if (qname.getFullyQualifiedName().equals(fullQualifiedName) && !(qname.getParent() instanceof ImportDeclaration)) { + // I will add the qname if and only if is not an instance of an ImportDeclaration searchResults.add(qname); } return false; @@ -211,15 +213,26 @@ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore TextEditGroup group= createTextEditGroup(CorrectionMessages.QuickAssistProcessor_replaceQualifiedName_description, cuRewrite); ASTRewrite rewrite= cuRewrite.getASTRewrite(); AST ast= cuRewrite.getRoot().getAST(); + ImportRemover iRemover= cuRewrite.getImportRemover(); for (QualifiedName itemToModify : itemsToModify) { SimpleName newItem= ast.newSimpleName(className.getFullyQualifiedName()); + iRemover.registerRemovedNode(itemToModify); ASTNodes.replaceButKeepComment(rewrite, itemToModify, newItem, group); } if (needImport) { ImportRewrite iRewrite= cuRewrite.getImportRewrite(); - if (isImportStatic) { - iRewrite.addStaticImport(itemsToModify.get(0).resolveBinding()); + QualifiedName itemToModify = itemsToModify.get(0); + if (itemToModify.resolveBinding() instanceof ITypeBinding) { + // When an static class is used within another, we don't need to use import static + // but we still need to import it. + String itemToImport = itemToModify.resolveTypeBinding().getQualifiedName(); + if(itemToImport != null) { + iRewrite.addImport(itemToImport); + } + } else { + iRewrite.addStaticImport(itemsToModify.get(0).resolveBinding()); + } } else { iRewrite.addImport(itemsToModify.get(0).getFullyQualifiedName()); } diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/RefactoringCoreMessages.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/RefactoringCoreMessages.java index 6edf3626b6a..18745ee67f6 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/RefactoringCoreMessages.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/RefactoringCoreMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2025 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -1405,6 +1405,8 @@ public final class RefactoringCoreMessages extends NLS { public static String MoveInstanceMethodProcessor_target_name_already_used; + public static String MoveInstanceMethodProcessor_target_null_comparison; + public static String MoveInstanceMethodProcessor_this_reference; public static String MoveInstanceMethodProcessor_uses_super; @@ -2550,6 +2552,7 @@ public final class RefactoringCoreMessages extends NLS { public static String ConvertToRecordRefactoring_member_types_not_supported; + static { NLS.initializeMessages(BUNDLE_NAME, RefactoringCoreMessages.class); } diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java index 9bb9352645d..4dc2d51e0d2 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -61,6 +61,7 @@ import org.eclipse.jdt.core.dom.SuperMethodInvocation; import org.eclipse.jdt.core.dom.ThisExpression; import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.manipulation.ImportReferencesCollector; @@ -175,6 +176,7 @@ private IMethodBinding getBinding() { private class UpdateCollector extends ASTVisitor { private int fTypeCounter; + private int fLocalTypeCounter; @Override public boolean visit(TypeDeclaration node) { return visitType(node); @@ -192,6 +194,15 @@ public void endVisit(EnumDeclaration node) { fTypeCounter--; } @Override + public boolean visit(TypeDeclarationStatement node) { + fLocalTypeCounter++; + return true; + } + @Override + public void endVisit(TypeDeclarationStatement node) { + fLocalTypeCounter--; + } + @Override public boolean visit(AnnotationTypeDeclaration node) { return visitType(node); } @@ -234,10 +245,21 @@ public boolean visit(MethodDeclaration node) { } @Override public boolean visit(MethodInvocation node) { - if (fTypeCounter == 0) { - Expression receiver= node.getExpression(); - if (receiver == null && !isStaticallyImported(node.getName())) { + Expression receiver= node.getExpression(); + if (receiver == null && !isStaticallyImported(node.getName())) { + if (fTypeCounter == 0) { fImplicitReceivers.add(node); + } else if (fLocalTypeCounter > 0) { + IMethodBinding methodBinding= node.resolveMethodBinding(); + if (methodBinding != null) { + ITypeBinding typeBinding= methodBinding.getDeclaringClass(); + while (typeBinding != null && typeBinding.isMember()) { + typeBinding= typeBinding.getDeclaringClass(); + } + if (typeBinding != null && !typeBinding.isLocal()) { + fImplicitReceivers.add(node); + } + } } } return true; @@ -265,12 +287,10 @@ public boolean visit(SuperConstructorInvocation node) { } @Override public boolean visit(ClassInstanceCreation node) { - if (fTypeCounter == 0) { - Expression receiver= node.getExpression(); - if (receiver == null) { - if (node.resolveTypeBinding().isLocal() && !node.resolveTypeBinding().isAnonymous()) - fImplicitReceivers.add(node); - } + Expression receiver= node.getExpression(); + if (receiver == null) { + if (node.resolveTypeBinding().isMember()) + fImplicitReceivers.add(node); } return true; } @@ -303,7 +323,17 @@ public boolean visit(SimpleName node) { StructuralPropertyDescriptor location= node.getLocationInParent(); if (location != SingleVariableDeclaration.NAME_PROPERTY && location != VariableDeclarationFragment.NAME_PROPERTY) { - fImplicitReceivers.add(node); + if (fTypeCounter == 0) { + fImplicitReceivers.add(node); + } else if (fLocalTypeCounter > 0) { + ITypeBinding typeBinding= vb.getDeclaringClass(); + while (typeBinding != null && typeBinding.isMember()) { + typeBinding= typeBinding.getDeclaringClass(); + } + if (typeBinding != null && !typeBinding.isLocal()) { + fImplicitReceivers.add(node); + } + } } } } else if (!vb.isField()) { diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties index 899ee0f3006..9b143b3c671 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties @@ -934,6 +934,7 @@ MoveInstanceMethodProcessor_this_reference=A reference to 'this' has been found MoveInstanceMethodProcessor_no_resolved_target=The target of the method could not be resolved. MoveInstanceMethodProcessor_no_null_argument=The method invocation ''{0}'' cannot be updated, since it uses null as argument. MoveInstanceMethodProcessor_target_name_already_used=The name of the target conflicts with the method parameter ''{0}''. +MoveInstanceMethodProcessor_target_null_comparison=The move will cause ''{0}'' being replaced by ''this'' and compared to null which is invalid logic and may imply an NPE can occur. MoveInstanceMethodProcessor_target_element_pattern=Target element: ''{0}'' MoveInstanceMethodProcessor_present_type_parameter_warning=The type parameter ''{0}'' is already present in the target type ''{1}'' and will be removed from the method. MoveInstanceMethodProcessor_remove_original_method=Remove method declaration diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java index 7a0c602fcad..2d064115457 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2025 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -97,6 +97,8 @@ import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.InfixExpression.Operator; import org.eclipse.jdt.core.dom.Javadoc; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; @@ -1713,7 +1715,7 @@ public RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, fi final RefactoringStatus status= new RefactoringStatus(); fChangeManager= new TextChangeManager(); try { - monitor.beginTask("", 6); //$NON-NLS-1$ + monitor.beginTask("", 7); //$NON-NLS-1$ monitor.setTaskName(RefactoringCoreMessages.MoveInstanceMethodProcessor_checking); status.merge(Checks.checkIfCuBroken(fMethod)); if (!status.hasError()) { @@ -1732,6 +1734,7 @@ public RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, fi checkConflictingTarget(Progress.subMonitor(monitor, 1), status); checkConflictingMethod(Progress.subMonitor(monitor, 1), status); checkOverrideOuterMethod(Progress.subMonitor(monitor, 1), status); + checkTargetNullCheck(Progress.subMonitor(monitor, 1), status); checkFinalMethod(status); Checks.addModifiedFilesToChecker(computeModifiedFiles(fMethod.getCompilationUnit(), type.getCompilationUnit()), context); @@ -1751,6 +1754,44 @@ public RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, fi return status; } + private void checkTargetNullCheck(IProgressMonitor monitor, RefactoringStatus status) throws JavaModelException { + Assert.isNotNull(monitor); + Assert.isNotNull(status); + try { + monitor.beginTask("", 1); //$NON-NLS-1$ + monitor.setTaskName(RefactoringCoreMessages.MoveInstanceMethodProcessor_checking); + ASTVisitor visitor= new ASTVisitor() { + @Override + public boolean visit(InfixExpression node) { + if (node.getOperator() == Operator.EQUALS || node.getOperator() == Operator.NOT_EQUALS) { + Expression rightOperand= node.getRightOperand(); + if (rightOperand instanceof NullLiteral) { + Expression leftOperand= node.getLeftOperand(); + if (leftOperand instanceof Name name) { + IBinding nameBinding= name.resolveBinding(); + if (nameBinding.isEqualTo(fTarget)) { + throw new AbortSearchException(); + } + } + } + } + return true; + } + }; + try { + final MethodDeclaration declaration= ASTNodeSearchUtil.getMethodDeclarationNode(fMethod, fSourceRewrite.getRoot()); + if (declaration != null) { + declaration.accept(visitor); + } + } catch (AbortSearchException e) { + status.merge(RefactoringStatus.createErrorStatus( + Messages.format(RefactoringCoreMessages.MoveInstanceMethodProcessor_target_null_comparison, new String[] {fTarget.getName()}), JavaStatusContext.create(fMethod))); + } + } finally { + monitor.done(); + } + } + /** * Checks whether the target is a type variable or a generic type. * diff --git a/org.eclipse.jdt.core.manipulation/forceQualifierUpdate.txt b/org.eclipse.jdt.core.manipulation/forceQualifierUpdate.txt index 26b4cd9fe7d..8f589835e6e 100644 --- a/org.eclipse.jdt.core.manipulation/forceQualifierUpdate.txt +++ b/org.eclipse.jdt.core.manipulation/forceQualifierUpdate.txt @@ -1,4 +1,5 @@ https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1979 https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/2044 https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/2595 -https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/2995 \ No newline at end of file +https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/2995 +https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/3927 diff --git a/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF index 4ed4206e43e..57b2707c0fc 100644 --- a/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.jdt.junit.core Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.junit.core;singleton:=true -Bundle-Version: 3.14.300.qualifier +Bundle-Version: 3.15.0.qualifier Bundle-Activator: org.eclipse.jdt.internal.junit.JUnitCorePlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName 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 db6b67141e5..30ae5538b9c 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 @@ -124,7 +124,20 @@ public String showCommandLine(ILaunchConfiguration configuration, String mode, I } } - private VMRunnerConfiguration getVMRunnerConfiguration(ILaunchConfiguration configuration, ILaunch launch, String mode, IProgressMonitor monitor) throws CoreException { + /** + * Creates the VM runner configuration for the given JUnit launch configuration. + * Subclasses can use this method to obtain the fully resolved launch configuration + * while customizing the existing protected launch hooks. + * + * @param configuration the launch configuration + * @param launch the launch + * @param mode the launch mode + * @param monitor the progress monitor + * @return the VM runner configuration, or {@code null} if the operation was canceled + * @throws CoreException if the launch configuration cannot be resolved + * @since 3.15 + */ + protected final VMRunnerConfiguration getVMRunnerConfiguration(ILaunchConfiguration configuration, ILaunch launch, String mode, IProgressMonitor monitor) throws CoreException { SubMonitor subMon= SubMonitor.convert(monitor, JUnitMessages.JUnitLaunchConfigurationDelegate_verifying_attriburtes_description, 4); // check for cancellation if (subMon.isCanceled()) { diff --git a/org.eclipse.jdt.junit/META-INF/MANIFEST.MF b/org.eclipse.jdt.junit/META-INF/MANIFEST.MF index db838e50d29..79c2fe29870 100644 --- a/org.eclipse.jdt.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.junit/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.jdt.junit Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.junit;singleton:=true -Bundle-Version: 3.17.500.qualifier +Bundle-Version: 3.17.600.qualifier Bundle-Activator: org.eclipse.jdt.internal.junit.ui.JUnitPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName diff --git a/org.eclipse.jdt.junit/forceQualifierUpdate.txt b/org.eclipse.jdt.junit/forceQualifierUpdate.txt index 543e637bd78..4bd1a00751d 100644 --- a/org.eclipse.jdt.junit/forceQualifierUpdate.txt +++ b/org.eclipse.jdt.junit/forceQualifierUpdate.txt @@ -16,4 +16,5 @@ https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/16 https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1781 https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1923 https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/2044 -https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/2595 \ No newline at end of file +https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/2595 +https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/3927 diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/CustomFoldingRegionTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/CustomFoldingRegionTest.java index 5ca5fdaff2e..4c14eec931f 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/CustomFoldingRegionTest.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/CustomFoldingRegionTest.java @@ -37,7 +37,6 @@ import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.projection.ProjectionAnnotation; @@ -101,7 +100,7 @@ public void testNoCustomFoldingRegions() throws Exception { package org.example.test; public class Test { } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); assertEquals(0, projectionRanges.size()); } @@ -118,7 +117,7 @@ class Test { // endregion } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 1, 3); // region 1 FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 5, 7); // region 2 } @@ -136,7 +135,7 @@ class Test { // endregion inner } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); assertEquals(3, projectionRanges.size()); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 2, 8);//class Test FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 7);//outer @@ -157,7 +156,7 @@ class Test { // endregion inner } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 3);//outer } @@ -173,7 +172,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 5); // region 1 } @@ -184,7 +183,7 @@ public void testNoCustomFoldingRegionsSingleImport() throws Exception { import java.util.List; """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); assertEquals(0, projectionRanges.size()); } @@ -197,7 +196,7 @@ public void testCustomFoldingRegionAroundSingleImport() throws Exception { import java.util.List; // endregion """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 2, 4); // imports } @@ -225,7 +224,7 @@ class D { } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 6, 15); // region 1 } @@ -247,7 +246,7 @@ void a(){ } // endregion outside class """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); assertEquals(5, projectionRanges.size()); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 2, 12);//class Test FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 1, 13);//outside class @@ -269,7 +268,7 @@ void a(){ } // endregion outside class """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 4);//region inside method } @@ -289,7 +288,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); if (extendedFoldingActive) { assertEquals(5, projectionRanges.size()); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 2, 11);//class SpecialCommentTypes @@ -323,7 +322,7 @@ class Inner{ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 4, 7);//region 1 } @@ -348,7 +347,7 @@ class B { } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 3);// region outside } @@ -367,7 +366,7 @@ void b(){ // endregion } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 9);//region 1 } @@ -387,7 +386,7 @@ class Test { // endregion should be ignored } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 4); // this is the region } @@ -403,7 +402,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 5);//region 1 } @@ -419,7 +418,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 3); } @@ -435,7 +434,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 3); } @@ -451,7 +450,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 5);//region 1 } @@ -468,7 +467,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 4, 6);//region 1 } @@ -485,7 +484,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 4, 6);//region 1 } @@ -501,7 +500,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 4);//region 1 } @@ -515,7 +514,7 @@ void a(){/* region 1*/} /* endregion */ } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 2); } @@ -529,7 +528,7 @@ class Test { void a(){/* endregion*/} } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 2); } @@ -549,7 +548,7 @@ void a(){ } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 4);//region 1 FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 5, 6);//region 1 } @@ -574,7 +573,7 @@ void a() { } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 3);// region 1 FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 6);// region 2 FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(projectionRanges, str, 9);// region 3 @@ -591,7 +590,7 @@ class Test { /* endregion */ void test(){} } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 4); // region 1 } @@ -611,7 +610,7 @@ class Test { } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 4);//first start FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 5, 6);//second start } @@ -641,7 +640,7 @@ void test() { // ---- } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 7);//variables FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 8, 13);//methods } @@ -675,7 +674,7 @@ void otherMethod() { } } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 6, 9);//inner FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 10, 12);//inner 2 FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 15, 19);//outer 2 @@ -699,7 +698,7 @@ class Test { } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 3, 8);//no end marker FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 5, 6);//first FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 7, 8);//second @@ -721,7 +720,7 @@ public void testStartMarkerStartsWithEndMarkerWithoutTopLevelType() throws Excep // regend second """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionWithOffsetAndLength(projectionRanges, 2, 7, //no end marker FoldingTestUtils.findLineStartIndex(str, 2), str.length() - 1); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 4, 5);//first @@ -751,7 +750,7 @@ class Test { // reg end } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 6, 7);//first FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 10, 11);//second FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 12, 13);//third @@ -767,7 +766,7 @@ public void testSameStartAndEndMarkerTerminatesAtEOF() throws Exception { // reg my region // some comment without line break"""; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 0, 2); } @@ -782,7 +781,7 @@ public void testSameStartAndEndMarkerTerminatesAtEOFEmptyLine() throws Exception """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 0, 3); } @@ -809,7 +808,7 @@ public String test(boolean b) { } """; - List projectionRanges= getProjectionRangesOfFile(str); + List projectionRanges= getProjectionRangesOfFile(str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(projectionRanges, str, 4, 12);//custom region } @@ -838,7 +837,7 @@ void someMethod() { try { ProjectionAnnotationModel model= editor.getAdapter(ProjectionAnnotationModel.class); - List initialRegions= FoldingTestUtils.extractRegions(model); + List initialRegions= FoldingTestUtils.extractRegions(model); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(initialRegions, code, 2, 15);//outer FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(initialRegions, code, 5, 12);//middle @@ -856,8 +855,8 @@ void someMethod() { // check that regions are in the same order as before and not modified in another way for(int i= 0; i < positions.size(); i++) { - assertEquals(initialRegions.get(i).getOffset(), positions.get(i).getOffset()); - assertEquals(initialRegions.get(i).getLength() + additionalText.length(), positions.get(i).getLength()); + assertEquals(initialRegions.get(i).offset(), positions.get(i).getOffset()); + assertEquals(initialRegions.get(i).length() + additionalText.length(), positions.get(i).getLength()); } } finally { editor.close(false); @@ -946,8 +945,9 @@ private List getFoldingPositionsFromModel(ProjectionAnnotationModel mo return positions; } - private List getProjectionRangesOfFile(String str) throws Exception { + private List getProjectionRangesOfFile(String str) throws Exception { return FoldingTestUtils.getProjectionRangesOfPackage(fPackageFragment, str); } } + diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingIncludeClosingBracketTests.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingIncludeClosingBracketTests.java index 8f136e622b2..f496455e816 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingIncludeClosingBracketTests.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingIncludeClosingBracketTests.java @@ -27,7 +27,6 @@ import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.text.IRegion; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; @@ -95,7 +94,7 @@ void x() { }; } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // if FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 6, 8); // for FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 9, 11); // while @@ -119,7 +118,7 @@ void x() { } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 11); // x() FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 6); // s FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 8, 9); // s2 @@ -148,10 +147,11 @@ void someMethod() { @interface SomeAnnotation {} @interface OtherAnnotation {} """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 3); // A FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 6); // B FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 8, 9); // C FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 11, 14); // someMethod } } + diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTest.java index 243533cda9c..f045e0fe186 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTest.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTest.java @@ -31,7 +31,6 @@ import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.text.IRegion; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; @@ -88,7 +87,7 @@ public void testCompilationUnitFolding() throws Exception { class A { //here should be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 1, 2); // class } @@ -118,7 +117,7 @@ public void testFoldOneLinersEmptyClass() throws Exception { class A { //here should be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 1, 2); // class } @@ -133,7 +132,7 @@ class HeaderCommentTest { } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 1, 3); // Javadoc } @@ -149,7 +148,7 @@ class ImportsTest { } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 3); // Imports } @@ -167,7 +166,7 @@ public void foo() { //here should be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); // Javadoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 5, 7); // foo Methode } @@ -184,7 +183,7 @@ public void foo() { //here should not be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 5); // method FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(regions, str, 3); } @@ -203,7 +202,7 @@ public void bar() { //here should be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); // foo Methode FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 5, 7); // bar Methode } @@ -221,7 +220,7 @@ void bar() { //here should be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // InnerClass FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // bar Methode } @@ -245,7 +244,7 @@ void bar() { //here should be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); // OuterWithDocs Javadoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 5, 12); // InnerWithDocs Klasse FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 6, 8); // InnerWithDocs Javadoc @@ -268,7 +267,7 @@ public void testJavadocs() throws Exception { class Example {} """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 1, 3); // 1. Javadoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 6); // 2. Javadoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 7, 9); // 3. Javadoc @@ -301,7 +300,7 @@ void b() { //here should be an annotation } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 1, 3); // 1. Javadoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 6); // 2. Javadoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 7, 9); // 3. Javadoc @@ -322,7 +321,7 @@ public void testCopyrightHeader() throws Exception { class SomeClass {} """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 0, 2); } @@ -341,7 +340,7 @@ void a() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); // JavaDoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 5, 6); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 7, 9); // 2. Method @@ -360,7 +359,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // if } @@ -380,7 +379,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 8); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 4); // try FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 5, 7); // catch @@ -399,7 +398,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // while } @@ -417,7 +416,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // for } @@ -435,7 +434,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // for } @@ -453,7 +452,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 4); // do } @@ -471,7 +470,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // synchronized } @@ -490,7 +489,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 7); // 1. Method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 6); // Supplier } @@ -507,7 +506,7 @@ void y() { //here should be an annotation }; } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // Object FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // Method } @@ -530,7 +529,7 @@ public void run() { } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 8); // method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 7); // Runnable (anonymous class) FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 6); // run @@ -548,7 +547,7 @@ enum N { //here should be an annotation B } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 1, 4); // enum } @@ -562,7 +561,7 @@ class O { } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); // static } @@ -585,7 +584,7 @@ void x() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 12); // method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 11); // if FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 10); // for @@ -605,7 +604,7 @@ class Inner2{ //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // method FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 3, 5); // inner class } @@ -641,7 +640,7 @@ public void bar() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 21); // x() FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 22, 23); // bar() FoldingTestUtils.assertDoesNotContainRegionUsingStartLine(regions, str, 3); // do-while @@ -688,7 +687,7 @@ void a() { } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 24); // switch expression } @@ -715,7 +714,7 @@ void a() { } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 4, 15); // switch } @@ -732,7 +731,7 @@ class Inner {} } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 5); // @Deprecated } @@ -752,7 +751,7 @@ class RecordTest { } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // array } @@ -778,10 +777,54 @@ public static void main(String[] args) { } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); // predicate FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 5, 7); // ArrayList FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 9, 10); // if FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 11, 13); // else } + + /** + * See GitHub Issue #3031 + */ + @Test + public void testFoldInnerTypesByDefault() throws Exception { + IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); + store.setValue(PreferenceConstants.EDITOR_FOLDING_INNERTYPES, true); + + String str= """ + class B { // Should not be folded + static class B1 { // Should be folded + + } + } + + public class A { // Should not be folded + static class A1 { // Should be folded + } + + static class A2 { // Should be folded + public static void main(String[] args) { + Runnable r = new Runnable() { // Should be folded + @Override + public void run() { + + } + }; + } + + } + } + """; + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + FoldingTestUtils.assertContainsExpandedRegionUsingStartAndEndLine(regions, str, 0, 4); // class B + FoldingTestUtils.assertContainsCollapsedRegionUsingStartAndEndLine(regions, str, 1, 3); // class B1 + FoldingTestUtils.assertContainsExpandedRegionUsingStartAndEndLine(regions, str, 6, 21); // class A + FoldingTestUtils.assertContainsCollapsedRegionUsingStartAndEndLine(regions, str, 7, 8); // class A1 + FoldingTestUtils.assertContainsCollapsedRegionUsingStartAndEndLine(regions, str, 10, 20); // class A2 + FoldingTestUtils.assertContainsCollapsedRegionUsingStartAndEndLine(regions, str, 12, 17); // Runnable + JavaPlugin.getDefault().getPreferenceStore().setToDefault(PreferenceConstants.EDITOR_FOLDING_INNERTYPES); + + } } + diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTestUtils.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTestUtils.java index ebcb68b75f5..d998ba5df46 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTestUtils.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingTestUtils.java @@ -25,9 +25,7 @@ import java.util.List; import java.util.Map; -import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; -import org.eclipse.jface.text.Region; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.projection.ProjectionAnnotation; import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; @@ -39,29 +37,35 @@ import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; public final class FoldingTestUtils { - private record StartEnd(int start, int end) {} + private record StartEnd(int start, int end) { + } + + public record ProjectionRegion(int offset, int length, boolean collapsed) { + } private FoldingTestUtils() { } - public static List getProjectionRangesOfPackage(IPackageFragment packageFragment, String code) throws Exception { + public static List getProjectionRangesOfPackage(IPackageFragment packageFragment, String code) throws Exception { ICompilationUnit cu= packageFragment.createCompilationUnit("A.java", code, true, null); JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(cu); - ProjectionAnnotationModel model= editor.getAdapter(ProjectionAnnotationModel.class); + try { + ProjectionAnnotationModel model= editor.getAdapter(ProjectionAnnotationModel.class); - List regions= extractRegions(model); - editor.close(false); - return regions; + return extractRegions(model); + } finally { + editor.close(false); + } } - public static List extractRegions(ProjectionAnnotationModel model) { - List regions= new ArrayList<>(); + public static List extractRegions(ProjectionAnnotationModel model) { + List regions= new ArrayList<>(); Iterator it= model.getAnnotationIterator(); while (it.hasNext()) { Annotation a= it.next(); - if (a instanceof ProjectionAnnotation) { + if (a instanceof ProjectionAnnotation projectionAnnotation) { Position p= model.getPosition(a); - regions.add(new Region(p.getOffset(), p.getLength())); + regions.add(new ProjectionRegion(p.getOffset(), p.getLength(), projectionAnnotation.isCollapsed())); } } assertNoDuplicatedRegions(regions); @@ -69,18 +73,18 @@ public static List extractRegions(ProjectionAnnotationModel model) { return regions; } - private static void assertNoDuplicatedRegions(List regions) { + private static void assertNoDuplicatedRegions(List regions) { long distinctRegions= regions.stream() - .map(r -> Map.entry(r.getOffset(), r.getLength())) // map to offset-length pairs + .map(r -> Map.entry(r.offset(), r.length())) // map to offset-length pairs .distinct() .count(); assertEquals(regions.size(), distinctRegions, "Some regions are duplicated: " + sorted(regions)); } - private static void assertNoRegionsStartInTheSameOffset(Collection regions) { + private static void assertNoRegionsStartInTheSameOffset(Collection regions) { long distinctOffsets= regions.stream() - .map(IRegion::getOffset) + .map(ProjectionRegion::offset) .distinct() .count(); @@ -89,30 +93,58 @@ private static void assertNoRegionsStartInTheSameOffset(Collection regi } public static void assertCodeHasRegions(IPackageFragment packageFragment, String code, int regionsCount) throws Exception { - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, code); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, code); assertEquals(regionsCount, regions.size(), String.format("Expected %d regions but saw %d.", regionsCount, regions.size())); } - public static void assertDoesNotContainRegionUsingStartLine(List projectionRanges, String input, int startLine) { + public static void assertDoesNotContainRegionUsingStartLine(List projectionRanges, String input, int startLine) { int startLineBegin= findLineStartIndex(input, startLine); - for (IRegion region : projectionRanges) { - if (region.getOffset() == startLineBegin) { - fail("found unexpected region at offset=" + region.getOffset() + ", length=" + region.getLength() + + for (ProjectionRegion region : projectionRanges) { + if (region.offset() == startLineBegin) { + fail("found unexpected region at offset=" + region.offset() + ", length=" + region.length() + " starting at line " + startLine + " (line offset: " + startLineBegin + ")"); } } } - public static void assertDoesNotContainRegionUsingStartAndEndLine(List projectionRanges, String input, int startLine, int endLine) { - StartEnd startEnd = getStartEnd(input, startLine, endLine); + public static void assertDoesNotContainRegionUsingStartAndEndLine(List projectionRanges, String input, int startLine, int endLine) { + StartEnd startEnd= getStartEnd(input, startLine, endLine); assertDoesNotContainRegionWithOffsetAndLength(projectionRanges, startLine, endLine, startEnd.start(), startEnd.end()); } - public static void assertContainsRegionUsingStartAndEndLine(List projectionRanges, String input, int startLine, int endLine) { - StartEnd startEnd = getStartEnd(input, startLine, endLine); + public static void assertContainsRegionUsingStartAndEndLine(List projectionRanges, String input, int startLine, int endLine) { + StartEnd startEnd= getStartEnd(input, startLine, endLine); assertContainsRegionWithOffsetAndLength(projectionRanges, startLine, endLine, startEnd.start(), startEnd.end()); } + public static void assertContainsCollapsedRegionUsingStartAndEndLine(List projectionRanges, String input, int startLine, int endLine) { + assertContainsRegionWithCollapsedState(projectionRanges, input, startLine, endLine, true); + } + + public static void assertContainsExpandedRegionUsingStartAndEndLine(List projectionRanges, String input, int startLine, int endLine) { + assertContainsRegionWithCollapsedState(projectionRanges, input, startLine, endLine, false); + } + + private static void assertContainsRegionWithCollapsedState(List projectionRanges, String input, int startLine, int endLine, boolean collapsed) { + StartEnd startEnd= getStartEnd(input, startLine, endLine); + int expectedRegionBegin= startEnd.start(); + int expectedRegionLength= startEnd.end() - startEnd.start() + 1; + + for (ProjectionRegion projectionRegion : projectionRanges) { + if (projectionRegion.offset() == expectedRegionBegin && projectionRegion.length() == expectedRegionLength) { + assertEquals(collapsed, projectionRegion.collapsed(), + "incorrect collapsed state for region from line " + startLine + " to line " + endLine + " (offset: " + expectedRegionBegin + + ", length: " + expectedRegionLength + ")"); + return; + } + } + + fail( + "missing region from line " + startLine + " to line " + endLine + " (offset: " + expectedRegionBegin + + ", length: " + expectedRegionLength + ")" + + ", actual regions: " + sorted(projectionRanges)); + } + private static StartEnd getStartEnd(String input, int startLine, int endLine) { assertTrue(startLine <= endLine, "start line must be smaller or equal to end line"); int startLineBegin= findLineStartIndex(input, startLine); @@ -124,11 +156,11 @@ private static StartEnd getStartEnd(String input, int startLine, int endLine) { return new StartEnd(expectedRegionBegin, expectedRegionEnd); } - static void assertDoesNotContainRegionWithOffsetAndLength(List projectionRanges, int startLine, int endLine, int expectedRegionBegin, int expectedRegionEnd) { + static void assertDoesNotContainRegionWithOffsetAndLength(List projectionRanges, int startLine, int endLine, int expectedRegionBegin, int expectedRegionEnd) { int expectedRegionLength= expectedRegionEnd - expectedRegionBegin + 1; - for (IRegion region : projectionRanges) { - if (region.getOffset() == expectedRegionBegin && region.getLength() == expectedRegionLength) { + for (ProjectionRegion region : projectionRanges) { + if (region.offset() == expectedRegionBegin && region.length() == expectedRegionLength) { fail( "The region from line " + startLine + " to line " + endLine + " (offset: " + expectedRegionBegin + ", length: " + expectedRegionLength + ")" + @@ -137,11 +169,11 @@ static void assertDoesNotContainRegionWithOffsetAndLength(List projecti } } - static void assertContainsRegionWithOffsetAndLength(List projectionRanges, int startLine, int endLine, int expectedRegionBegin, int expectedRegionEnd) { + static void assertContainsRegionWithOffsetAndLength(List projectionRanges, int startLine, int endLine, int expectedRegionBegin, int expectedRegionEnd) { int expectedRegionLength= expectedRegionEnd - expectedRegionBegin + 1; - for (IRegion region : projectionRanges) { - if (region.getOffset() == expectedRegionBegin && region.getLength() == expectedRegionLength) { + for (ProjectionRegion region : projectionRanges) { + if (region.offset() == expectedRegionBegin && region.length() == expectedRegionLength) { return; } } @@ -159,9 +191,9 @@ static void assertContainsRegionWithOffsetAndLength(List projectionRang *
  • Then by length (descending i.e. longer regions first)
  • * */ - private static Collection sorted(Collection regions) { - List sortedRegions= new ArrayList<>(regions); - sortedRegions.sort(Comparator.comparingInt(IRegion::getOffset).thenComparing(Comparator.comparingInt(IRegion::getLength).reversed())); + private static Collection sorted(Collection regions) { + List sortedRegions= new ArrayList<>(regions); + sortedRegions.sort(Comparator.comparingInt(ProjectionRegion::offset).thenComparing(Comparator.comparingInt(ProjectionRegion::length).reversed())); return sortedRegions; } diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingWithShowSelectedElementTests.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingWithShowSelectedElementTests.java index 04be2c43c7f..3c33b329f91 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingWithShowSelectedElementTests.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/FoldingWithShowSelectedElementTests.java @@ -29,7 +29,6 @@ import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; import org.eclipse.jdt.core.ICompilationUnit; @@ -82,7 +81,7 @@ void someMethod() { } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(packageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); } @@ -115,7 +114,7 @@ void someMethod() { } """, editor.getViewer().getTextWidget().getText()); - List regions= FoldingTestUtils.extractRegions(model); + List regions= FoldingTestUtils.extractRegions(model); IDocument document= editor.getViewer().getDocument(); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 6); // region (custom) @@ -162,3 +161,4 @@ void someMethod() { } } } + diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/MarkdownJavadocFoldingTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/MarkdownJavadocFoldingTest.java index f05de075d34..b85c0327221 100644 --- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/MarkdownJavadocFoldingTest.java +++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/folding/MarkdownJavadocFoldingTest.java @@ -29,7 +29,6 @@ import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.text.IRegion; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; @@ -88,7 +87,7 @@ public void testClassWithMarkdownJavadocAsHeaderComment() throws Exception { class HeaderCommentTest { } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(fPackageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(fPackageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 1, 3); // Javadoc } @@ -105,8 +104,9 @@ public void foo() { //here should be an annotation } } """; - List regions= FoldingTestUtils.getProjectionRangesOfPackage(fPackageFragment, str); + List regions= FoldingTestUtils.getProjectionRangesOfPackage(fPackageFragment, str); FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 2, 4); // Javadoc FoldingTestUtils.assertContainsRegionUsingStartAndEndLine(regions, str, 5, 7); // foo method } } + diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3069.java b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3069.java new file mode 100644 index 00000000000..fad30a6461b --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3069.java @@ -0,0 +1,34 @@ +package bugs_in; + +public class Test_issue_3069 { + + int x; + + public static void main(String[] args) { + Test_issue_3069 obj= new Test_issue_3069(); + int result= obj.f(); + } + + int helper() { + return 7; + } + + int /*]*/ f()/*[*/ { + class H { + int y; + int j() { + return helper(); + } + class K { + int g() { + return helper(); + } + int h() { + return g() + x + y; + } + } + } + return H.class.getSimpleName().length() + helper(); + } + +} \ No newline at end of file diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3070_1.java b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3070_1.java new file mode 100644 index 00000000000..c3d691260eb --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3070_1.java @@ -0,0 +1,19 @@ +package bugs_in; + +public class Test_issue_3070_1 { + public static void main(String[] args) { + Test_issue_3070_1 obj = new Test_issue_3070_1(); + int result = obj.f(); + System.out.println(result); + } + + class H { + int g() { + return 7; + } + } + + int /*]*/f()/*[*/ { + return new H().g(); + } +} diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3070_2.java b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3070_2.java new file mode 100644 index 00000000000..bde01ab80c9 --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_in/Test_issue_3070_2.java @@ -0,0 +1,18 @@ +package bugs_in; + +public class Test_issue_3070_2 { + public static void main(String[] args) { + Test_issue_3070_2 obj = new Test_issue_3070_2(); + int result = obj.f(); + System.out.println(result); + } + + int /*]*/f()/*[*/ { + class H { + int g() { + return 7; + } + } + return new H().g(); + } +} diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3069.java b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3069.java new file mode 100644 index 00000000000..100d9f2e3ff --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3069.java @@ -0,0 +1,30 @@ +package bugs_in; + +public class Test_issue_3069 { + + int x; + + public static void main(String[] args) { + Test_issue_3069 obj= new Test_issue_3069(); + class H { + int y; + int j() { + return obj.helper(); + } + class K { + int g() { + return obj.helper(); + } + int h() { + return g() + obj.x + y; + } + } + } + int result= H.class.getSimpleName().length() + obj.helper(); + } + + int helper() { + return 7; + } + +} \ No newline at end of file diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3070_1.java b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3070_1.java new file mode 100644 index 00000000000..6c4f2655852 --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3070_1.java @@ -0,0 +1,15 @@ +package bugs_in; + +public class Test_issue_3070_1 { + public static void main(String[] args) { + Test_issue_3070_1 obj = new Test_issue_3070_1(); + int result = obj.new H().g(); + System.out.println(result); + } + + class H { + int g() { + return 7; + } + } +} diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3070_2.java b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3070_2.java new file mode 100644 index 00000000000..87d4972d3e1 --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/InlineMethodWorkspace/TestCases/bugs_out/Test_issue_3070_2.java @@ -0,0 +1,14 @@ +package bugs_in; + +public class Test_issue_3070_2 { + public static void main(String[] args) { + Test_issue_3070_2 obj = new Test_issue_3070_2(); + class H { + int g() { + return 7; + } + } + int result = new H().g(); + System.out.println(result); + } +} diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInstanceMethod/cannotMove/testFail21/in/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInstanceMethod/cannotMove/testFail21/in/A.java new file mode 100644 index 00000000000..f185d91c015 --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInstanceMethod/cannotMove/testFail21/in/A.java @@ -0,0 +1,10 @@ +package p1; + +class A { + B b; + + int m() { + if (b != null) return 2; + return 0; + } +} diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInstanceMethod/cannotMove/testFail21/in/B.java b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInstanceMethod/cannotMove/testFail21/in/B.java new file mode 100644 index 00000000000..df33307636d --- /dev/null +++ b/org.eclipse.jdt.ui.tests.refactoring/resources/MoveInstanceMethod/cannotMove/testFail21/in/B.java @@ -0,0 +1,5 @@ +package p1; + +public class B { + +} \ No newline at end of file diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/InlineMethodTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/InlineMethodTests.java index 29f0674218c..c73d5a763f7 100644 --- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/InlineMethodTests.java +++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/InlineMethodTests.java @@ -572,6 +572,21 @@ public void test_issue_2376() throws Exception { performBugTest(); } + @Test + public void test_issue_3069() throws Exception { + performBugTest(); + } + + @Test + public void test_issue_3070_1() throws Exception { + performBugTest(); + } + + @Test + public void test_issue_3070_2() throws Exception { + performBugTest(); + } + /* *********************** Argument Tests ******************************* */ private void performArgumentTest() throws Exception { diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInstanceMethodTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInstanceMethodTests.java index 62b577c4068..063f3ab0f34 100644 --- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInstanceMethodTests.java +++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/MoveInstanceMethodTests.java @@ -789,6 +789,48 @@ public void testFail1() throws Exception { failHelper1("p1.A", 5, 26, 5, 29, PARAMETER, "b", true, true); } + // Cannot move static method + @Test + public void testFail2() throws Exception { + failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 23, 6, 24, PARAMETER, "b", true, true); + } + + // Cannot move native method + @Test + public void testFail3() throws Exception { + failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 23, 6, 24, PARAMETER, "b", true, true); + } + + // Cannot move method that references "super" + @Test + public void testFail4() throws Exception { + failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 11, 20, 11, 21, PARAMETER, "b", true, true); + } + + // Cannot move method that references an enclosing instance + @Test + public void testFail5() throws Exception { + failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 8, 21, 8, 21, PARAMETER, "b", true, true); + } + + // Cannot move potentially directly recursive method + @Test + public void testFail6() throws Exception { + failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 16, 6, 17, PARAMETER, "b", true, true); + } + + // Cannot move synchronized method + @Test + public void testFail8() throws Exception { + failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 29, 6, 29, PARAMETER, "b", true, true); + } + + // Cannot move method if there's no new potential receiver + @Test + public void testFail9() throws Exception { + failHelper1(new String[] { "p1.A", "p2.B", "p3.C"}, "p1.A", 7, 17, 7, 20, PARAMETER, "b", true, true); + } + // Cannot move method if there's no new potential receiver @Test public void testFail10() throws Exception { @@ -857,45 +899,9 @@ public void testFail20() throws Exception { failHelper1(new String[] { "p1.A" }, "p1.A", 6, 17, 6, 23, FIELD, "b", true, true); } - // Cannot move static method - @Test - public void testFail2() throws Exception { - failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 23, 6, 24, PARAMETER, "b", true, true); - } - - // Cannot move native method - @Test - public void testFail3() throws Exception { - failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 23, 6, 24, PARAMETER, "b", true, true); - } - - // Cannot move method that references "super" - @Test - public void testFail4() throws Exception { - failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 11, 20, 11, 21, PARAMETER, "b", true, true); - } - - // Cannot move method that references an enclosing instance - @Test - public void testFail5() throws Exception { - failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 8, 21, 8, 21, PARAMETER, "b", true, true); - } - - // Cannot move potentially directly recursive method - @Test - public void testFail6() throws Exception { - failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 16, 6, 17, PARAMETER, "b", true, true); - } - - // Cannot move synchronized method - @Test - public void testFail8() throws Exception { - failHelper1(new String[] { "p1.A", "p2.B"}, "p1.A", 6, 29, 6, 29, PARAMETER, "b", true, true); - } - - // Cannot move method if there's no new potential receiver + // Issue 3035 @Test - public void testFail9() throws Exception { - failHelper1(new String[] { "p1.A", "p2.B", "p3.C"}, "p1.A", 7, 17, 7, 20, PARAMETER, "b", true, true); + public void testFail21() throws Exception { + failHelper1(new String[] { "p1.A", "p1.B" }, "p1.A", 6, 9, 6, 10, FIELD, "b", true, true); } } diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TemplateStoreTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TemplateStoreTest.java index 3a1531371c3..938e4cd908d 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TemplateStoreTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TemplateStoreTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2026 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 @@ public class TemplateStoreTest extends CoreTests { CodeTemplateContextType.MARKDOWNGETTERCOMMENT_ID, CodeTemplateContextType.MARKDOWNSETTERCOMMENT_ID, CodeTemplateContextType.MARKDOWNMODULECOMMENT_ID, + CodeTemplateContextType.MARKDOWNOVERRIDECOMMENT_ID, }; private TemplatePersistenceData find(String id, TemplatePersistenceData[] templateData) { diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GetTypeCommentMarkdownTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GetTypeCommentMarkdownTest.java new file mode 100644 index 00000000000..ade3fb184e7 --- /dev/null +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/GetTypeCommentMarkdownTest.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2026 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ui.tests.core.source; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +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.jface.preference.IPreferenceStore; + +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.internal.core.manipulation.CodeTemplateContextType; +import org.eclipse.jdt.internal.core.manipulation.StubUtility; + +import org.eclipse.jdt.ui.PreferenceConstants; +import org.eclipse.jdt.ui.tests.core.rules.Java23ProjectTestSetup; +import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup; + +import org.eclipse.jdt.internal.ui.JavaPlugin; + +public class GetTypeCommentMarkdownTest { + + private static final String MARKDOWN_TYPECOMMENT_TEMPLATE= "/// ${type_name}" + "\n/// ${tags}"; + @Rule + public ProjectTestSetup pts= new Java23ProjectTestSetup(false); + + private IJavaProject fJavaProject; + private IPackageFragmentRoot fSourceFolder; + private IPackageFragment fPackageP; + + @Before + public void setUp() throws CoreException { + fJavaProject= pts.getProject(); + fSourceFolder= JavaProjectHelper.addSourceContainer(fJavaProject, "src"); + fPackageP= fSourceFolder.createPackageFragment("p", true, null); + + IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); + store.setValue(PreferenceConstants.CODEGEN_USE_MARKDOWN, true); + store.setValue(PreferenceConstants.CODEGEN_ADD_COMMENTS, true); + + StubUtility.setCodeTemplate(CodeTemplateContextType.MARKDOWNTYPECOMMENT_ID, MARKDOWN_TYPECOMMENT_TEMPLATE, null); + } + + @After + public void tearDown() { + IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); + store.setValue(PreferenceConstants.CODEGEN_USE_MARKDOWN, false); + store.setValue(PreferenceConstants.CODEGEN_ADD_COMMENTS, false); + fJavaProject= null; + fPackageP= null; + } + + @Test + public void testNoTagsStripsTrailingMarkdownLine() throws Exception { + ICompilationUnit cu= fPackageP.createCompilationUnit("A.java", + "package p;\n\npublic class A {\n}\n", true, null); + + String comment= StubUtility.getTypeComment(cu, "p.A", new String[0], new String[0], "\n"); + + assertEquals("/// A", comment); + } + + @Test + public void testTypeParameterTagsNotStripped() throws Exception { + ICompilationUnit cu= fPackageP.createCompilationUnit("B.java", + "package p;\n\npublic class B {\n}\n", true, null); + + String comment= StubUtility.getTypeComment(cu, "p.B", new String[] { "T" }, new String[0], "\n"); + + assertTrue("expected type-name line", comment.startsWith("/// B\n")); + assertTrue("expected @param tag to be preserved", comment.contains("@param ")); + } + + @Test + public void testRecordComponentParamsNotStripped() throws Exception { + ICompilationUnit cu= fPackageP.createCompilationUnit("R.java", + "package p;\n\npublic record R(String x, int y) {\n}\n", true, null); + + String comment= StubUtility.getTypeComment(cu, "p.R", new String[0], new String[] { "x", "y" }, "\n"); + + assertTrue("expected type-name line", comment.startsWith("/// R\n")); + assertTrue("missing @param tag for record component x", comment.contains("@param x")); + assertTrue("missing @param tag for record component y", comment.contains("@param y")); + } +} \ No newline at end of file diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceActionTests.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceActionTests.java index 164e7fa1e1e..14339167d28 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceActionTests.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceActionTests.java @@ -33,7 +33,8 @@ GenerateHashCodeEqualsTest.class, GenerateToStringTest.class, GenerateRecordConstructorTest.class, -AddJavaDocStubOperationTest.class +AddJavaDocStubOperationTest.class, +GetTypeCommentMarkdownTest.class }) public class SourceActionTests { } diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/JavadocHoverTests.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/JavadocHoverTests.java index e2a39b414bd..75116ee61bf 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/JavadocHoverTests.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/hover/JavadocHoverTests.java @@ -44,6 +44,7 @@ import org.eclipse.jdt.core.IField; 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; @@ -370,6 +371,99 @@ record FooBar(String foo, String bar) {} } } + @Test + public void testRecordConstructor1() throws Exception { + // https://github.com/eclipse-jdt/eclipse.jdt.ui/issues/931 + String source= + """ + package p; + public class X {} + /** + * A foo bar. + * @param foo The foo. + * @param bar The bar. + */ + record FooBar(String foo, String bar) { + public FooBar { + if (foo == null) { + foo = "abc"; + } + } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/X.java", source, null); + assertNotNull("TestClass.java", cu); + + IType recordType= cu.getType("FooBar"); + boolean found= false; + for (IJavaElement member : recordType.getChildren()) { + if (member.getElementName().equals("FooBar")) { + assertTrue("not a constructor", member instanceof IMethod method && method.isConstructor()); + found= true; + IJavaElement[] elements= { member }; + ISourceRange range= ((ISourceReference) member).getNameRange(); + // copy logic from JavadocHover + if (elements.length == 1 && elements[0] instanceof IMethod method && method.isConstructor() + && method.getJavadocRange() == null && method.getParent() instanceof IType type && type.isRecord()) { + elements[0]= method.getParent(); + } + JavadocBrowserInformationControlInput hoverInfo= JavadocHover.getHoverInfo(elements, cu, new Region(range.getOffset(), range.getLength()), null); + String actualHtmlContent= hoverInfo.getHtml(); + int index= actualHtmlContent.indexOf("A foo bar."); + assertNotEquals("Expected HTML not found, instead found : " + actualHtmlContent, -1, index); + } + } + assertTrue("constructor not found", found); + } + + @Test + public void testRecordConstructor2() throws Exception { + // https://github.com/eclipse-jdt/eclipse.jdt.ui/issues/931 + String source= + """ + package p; + public class X {} + /** + * A foo bar. + * @param foo The foo. + * @param bar The bar. + */ + record FooBar(String foo, String bar) { + /** + * Foobar constructor + */ + public FooBar { + if (foo == null) { + foo = "abc"; + } + } + } + """; + ICompilationUnit cu= getWorkingCopy("/TestSetupProject/src/p/X.java", source, null); + assertNotNull("TestClass.java", cu); + + IType recordType= cu.getType("FooBar"); + boolean found= false; + for (IJavaElement member : recordType.getChildren()) { + if (member.getElementName().equals("FooBar")) { + assertTrue("not a constructor", member instanceof IMethod method && method.isConstructor()); + found= true; + IJavaElement[] elements= { member }; + ISourceRange range= ((ISourceReference) member).getNameRange(); + // copy logic from JavadocHover + if (elements.length == 1 && elements[0] instanceof IMethod method && method.isConstructor() + && method.getJavadocRange() == null && method.getParent() instanceof IType type && type.isRecord()) { + elements[0]= method.getParent(); + } + JavadocBrowserInformationControlInput hoverInfo= JavadocHover.getHoverInfo(elements, cu, new Region(range.getOffset(), range.getLength()), null); + String actualHtmlContent= hoverInfo.getHtml(); + int index= actualHtmlContent.indexOf("Foobar constructor"); + assertNotEquals("Expected HTML not found, instead found : " + actualHtmlContent, -1, index); + } + } + assertTrue("constructor not found", found); + } + @Test public void testLinkTagWithHttp_01() throws Exception { String source= 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 f9da4508bca..6690c231406 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2025 IBM Corporation and others. + * Copyright (c) 2013, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -3945,7 +3945,7 @@ static String method4() { AssistContext context= getCorrectionContext(cu, offset, 0); assertNoErrors(context); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 4); + assertNumberOfProposals(proposals, 3); assertCorrectLabels(proposals); String expected= """ @@ -3998,7 +3998,7 @@ static String method4() { context= getCorrectionContext(cu, offset, 0); assertNoErrors(context); proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 4); + assertNumberOfProposals(proposals, 3); assertCorrectLabels(proposals); expected= """ @@ -4051,7 +4051,7 @@ static String method4() { context= getCorrectionContext(cu, offset, 0); assertNoErrors(context); proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 5); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); expected= """ @@ -4104,7 +4104,7 @@ static String method4() { context= getCorrectionContext(cu, offset, 0); assertNoErrors(context); proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 5); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); expected= """ @@ -4157,7 +4157,7 @@ static String method4() { context= getCorrectionContext(cu, offset, 0); assertNoErrors(context); proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 5); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); expected= """ @@ -4210,7 +4210,7 @@ static String method4() { context= getCorrectionContext(cu, offset, 0); assertNoErrors(context); proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 5); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); expected= """ @@ -7884,5 +7884,157 @@ public testExample() { assertNumberOfProposals(proposals, 0); } + @Test + public void testIssue3061() throws Exception { + // We have a superclass that contains another TestClass as package private. No proposal expected. + IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); + String src1= """ + package test.test1; + public class Second { + + public void consume1(String s) { + } + } + """; + pack1.createCompilationUnit("Second.java", src1, false, null); + + String src= """ + package test.test1; + import java.util.function.Consumer; + + public class First { + void f(Consumer s) { + } + + void g() { + Second second = new Second(); + f(second::consume1); + f(second::consume2); + } + } + """; + ICompilationUnit cu1= pack1.createCompilationUnit("First.java", src, false, null); + int offset= src.indexOf("second::consume2"); + AssistContext context= getCorrectionContext(cu1, offset, 0); + List proposals= collectAssists(context, false); + String expected= """ + package test.test1; + public class Second { + + public void consume1(String s) { + } + + public void consume2(String string1) { + } + } + """; + assertExpectedExistInProposals(proposals, new String[] { expected }); + } + + @Test + public void test_refactorQualifiedName_bug_3060() throws Exception { + // If the classes share the same package the import will not be added + IPackageFragment pack1= fSourceFolder.createPackageFragment("test3", false, null); + String classToImport= """ + package test3; + + public class Test { + + public static class Test2 { + public static int x; + public static int getX() { + return x; + } + } + } + """; + pack1.createCompilationUnit("Test.java", classToImport, false, null); + IPackageFragment pack2= fSourceFolder.createPackageFragment("test2", false, null); + String importingClass= """ + package test2; + + import test3.Test; + + public class TestStaticImport { + + public int foo3() { + return Test.Test2.getX(); + } + + } + """; + + String expected= """ + package test2; + + import test3.Test.Test2; + + public class TestStaticImport { + + public int foo3() { + return Test2.getX(); + } + + } + """; + ICompilationUnit cu1= pack2.createCompilationUnit("TestStaticImport.java", importingClass, false, null); + int offset= importingClass.indexOf("Test.Test2"); + AssistContext context= getCorrectionContext(cu1, offset+2, 0); + List proposals= collectAssists(context, false); + assertNumberOfProposals(proposals, 1); + assertExpectedExistInProposals(proposals, new String[] { expected }); + } + + @Test + public void test_refactorQualifiedName_bug_3060_2() throws Exception { + // If the classes share the same package the import will not be added + IPackageFragment pack1= fSourceFolder.createPackageFragment("test3", false, null); + String classToImport= """ + package test3; + + public class Test { + + public static class Test2 { + public static int x; + public static int getX() { + return x; + } + } + } + """; + pack1.createCompilationUnit("Test.java", classToImport, false, null); + IPackageFragment pack2= fSourceFolder.createPackageFragment("test2", false, null); + String importingClass= """ + package test2; + + public class TestStaticImport { + + public int foo4() { + return test3.Test.Test2.getX(); + } + + } + """; + + String expected= """ + package test2; + + import test3.Test.Test2; + + public class TestStaticImport { + + public int foo4() { + return Test2.getX(); + } + + } + """; + ICompilationUnit cu1= pack2.createCompilationUnit("TestStaticImport.java", importingClass, false, null); + int offset= importingClass.indexOf("Test.Test2"); + AssistContext context= getCorrectionContext(cu1, offset, 0); + List proposals= collectAssists(context, false); + assertNumberOfProposals(proposals, 1); + assertExpectedExistInProposals(proposals, new String[] { expected }); + } } diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/SaveParticipantTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/SaveParticipantTest.java index 6f4f6579642..89a26b811da 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/SaveParticipantTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/SaveParticipantTest.java @@ -35,6 +35,8 @@ import org.eclipse.jface.text.CopyOnWriteTextStore; +import org.eclipse.ui.internal.texteditor.quickdiff.DocumentLineDiffer; + import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; @@ -105,6 +107,7 @@ public void tearDown() throws Exception { private static void editCUInEditor(ICompilationUnit cu, String newContent) throws Exception { JavaEditor editor= (JavaEditor) EditorUtility.openInEditor(cu); Job.getJobManager().join(ReconcilerJobFamilies.FAMILY_RECONCILER, null); + Job.getJobManager().join(DocumentLineDiffer.QUICKDIFF_INITIALIZE_FAMILY, null); TestUtils.cancelDecorationJob(); cu.getBuffer().setContents(newContent); diff --git a/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml b/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml index 5802fe03bf8..23af0625e5f 100644 --- a/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml +++ b/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF b/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF index 6d109083bae..0be42ed242f 100644 --- a/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.jdt.ui.unittest.junit Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.ui.unittest.junit;singleton:=true -Bundle-Version: 1.3.100.qualifier +Bundle-Version: 1.4.0.qualifier Bundle-Activator: org.eclipse.jdt.ui.unittest.junit.JUnitTestPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName diff --git a/org.eclipse.jdt.ui.unittest.junit/pom.xml b/org.eclipse.jdt.ui.unittest.junit/pom.xml index abe760784eb..c113e8c5ebf 100644 --- a/org.eclipse.jdt.ui.unittest.junit/pom.xml +++ b/org.eclipse.jdt.ui.unittest.junit/pom.xml @@ -18,6 +18,6 @@ org.eclipse.jdt org.eclipse.jdt.ui.unittest.junit - 1.3.100-SNAPSHOT + 1.4.0-SNAPSHOT eclipse-plugin diff --git a/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.java b/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.java index 31d88ef019c..3a4769d82a8 100644 --- a/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.java +++ b/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.java @@ -134,7 +134,20 @@ public String showCommandLine(ILaunchConfiguration configuration, String mode, I } } - private VMRunnerConfiguration getVMRunnerConfiguration(ILaunchConfiguration configuration, ILaunch launch, + /** + * Creates the VM runner configuration for the given JUnit launch configuration. + * Subclasses can use this method to obtain the fully resolved launch configuration + * while customizing the existing protected launch hooks. + * + * @param configuration the launch configuration + * @param launch the launch + * @param mode the launch mode + * @param monitor the progress monitor + * @return the VM runner configuration, or {@code null} if the operation was canceled + * @throws CoreException if the launch configuration cannot be resolved + * @since 1.4 + */ + protected final VMRunnerConfiguration getVMRunnerConfiguration(ILaunchConfiguration configuration, ILaunch launch, String mode, IProgressMonitor monitor) throws CoreException { VMRunnerConfiguration runConfig = null; monitor.beginTask(MessageFormat.format("{0}...", configuration.getName()), 5); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.ui/templates/default-codetemplates.xml b/org.eclipse.jdt.ui/templates/default-codetemplates.xml index 770bfe00344..7b067b0753d 100644 --- a/org.eclipse.jdt.ui/templates/default-codetemplates.xml +++ b/org.eclipse.jdt.ui/templates/default-codetemplates.xml @@ -76,6 +76,8 @@ + +