From 197c5b885e03a54860e521c654e044e6d8f4d9b3 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Tue, 26 Oct 2021 08:51:21 +0200 Subject: [PATCH] [fixes #1309] Extract interface + pull up --- .../lombok/eclipse/agent/EclipsePatcher.java | 76 ++++++++++++++++++- .../lombok/launch/PatchFixesHider.java | 37 ++++++++- 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index 33dad64e8a..06e109607b 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -90,10 +90,11 @@ public String mapResourceName(int classFileFormatVersion, String resourceName) { patchListRewriteHandleGeneratedMethods(sm); patchSyntaxAndOccurrencesHighlighting(sm); patchSortMembersOperation(sm); - patchExtractInterface(sm); + patchExtractInterfaceAndPullUp(sm); patchAboutDialog(sm); patchEclipseDebugPatches(sm); patchJavadoc(sm); + patchASTConverterLiterals(sm); patchPostCompileHookEcj(sm); @@ -133,7 +134,7 @@ private static void patchRenameField(ScriptManager sm) { .transplant().build()); } - private static void patchExtractInterface(ScriptManager sm) { + private static void patchExtractInterfaceAndPullUp(ScriptManager sm) { /* Fix sourceEnding for generated nodes to avoid null pointer */ sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.compiler.SourceElementNotifier", "notifySourceElementRequestor", "void", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "org.eclipse.jdt.internal.compiler.ast.ImportReference")) @@ -155,10 +156,31 @@ private static void patchExtractInterface(ScriptManager sm) { .requestExtra(StackRequest.THIS, StackRequest.PARAM4) .transplant().build()); - /* get real generated node in stead of a random one generated by the annotation */ + /* Get real node source instead of the annotation */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor", "createPlaceholderForSingleVariableDeclaration", "org.eclipse.jdt.core.dom.SingleVariableDeclaration", + "org.eclipse.jdt.core.dom.SingleVariableDeclaration", + "org.eclipse.jdt.core.ICompilationUnit", + "org.eclipse.jdt.core.dom.rewrite.ASTRewrite" + )) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor", "createPlaceholderForType", "org.eclipse.jdt.core.dom.Type", + "org.eclipse.jdt.core.dom.Type", + "org.eclipse.jdt.core.ICompilationUnit", + "org.eclipse.jdt.core.dom.rewrite.ASTRewrite" + )) + .methodToWrap(new Hook("org.eclipse.jdt.core.IBuffer", "getText", "java.lang.String", "int", "int")) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealNodeSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.dom.ASTNode")) + .requestExtra(StackRequest.PARAM1) + .transplant() + .build()); + + /* Get real generated node instead of a random one generated by the annotation */ sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.replaceMethodCall() .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMemberDeclarations")) .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMethodComments")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "createAbstractMethod")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "addMethodStubForAbstractMethod")) + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor", "createChangeManager")) .methodToReplace(new Hook("org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil", "getMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) .replacementMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit")) .transplant().build()); @@ -176,6 +198,29 @@ private static void patchExtractInterface(ScriptManager sm) { .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) .request(StackRequest.PARAM2) .transplant().build()); + + /* Do not add a modifier to the generating annotation during pull up + * + * Example: Pull up a protected method (canEqual()/@EqualsAndHashCode) + */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor$IncomingMemberVisibilityAdjustment", "rewriteVisibility")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "skipRewriteVisibility", "boolean", "org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor$IncomingMemberVisibilityAdjustment")) + .request(StackRequest.THIS) + .transplant() + .build()); + + /* + * ImportRemover sometimes removes lombok imports if a generated method/type gets changed. Skipping all generated nodes fixes this behavior. + * + * Example: Create a class (Use.java) that uses a generated method (Test t; t.toString();) and pull up this generated method. + */ + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.exitEarly() + .target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover", "registerRemovedNode", "void", "org.eclipse.jdt.core.dom.ASTNode")) + .decisionMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode")) + .request(StackRequest.PARAM1) + .transplant() + .build()); } private static void patchAboutDialog(ScriptManager sm) { @@ -526,6 +571,13 @@ private static void patchSetGeneratedFlag(ScriptManager sm) { "org.eclipse.jdt.core.dom.Name", "java.lang.Object")) .transplant().build()); + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration")) + .methodToWrap(new Hook("org.eclipse.jdt.core.dom.Block", "", "void", "org.eclipse.jdt.core.dom.AST")) + .requestExtra(StackRequest.PARAM2) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void", + "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .transplant().build()); sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertType", "org.eclipse.jdt.core.dom.Type", "org.eclipse.jdt.internal.compiler.ast.TypeReference")) @@ -926,4 +978,22 @@ private static void patchJavadoc(ScriptManager sm) { .build()); } + private static void patchASTConverterLiterals(ScriptManager sm) { + sm.addScriptIfWitness(OSGI_TYPES, ScriptBuilder.wrapMethodCall() + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.Expression", "org.eclipse.jdt.internal.compiler.ast.StringLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.Expression", "org.eclipse.jdt.internal.compiler.ast.TextBlock")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.CharacterLiteral", "org.eclipse.jdt.internal.compiler.ast.CharLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.DoubleLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.FloatLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.LongLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.LongLiteralMinValue")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.IntLiteral")) + .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.NumberLiteral", "org.eclipse.jdt.internal.compiler.ast.IntLiteralMinValue")) + .methodToWrap(new Hook("java.lang.String", "", "void", "char[]", "int", "int")) + .requestExtra(StackRequest.PARAM1) + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "getRealNodeSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.internal.compiler.ast.ASTNode")) + .transplant() + .build()); + } + } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index 061f3584ba..63bb3747e8 100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; +import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment; import static lombok.eclipse.EcjAugments.ASTNode_generatedBy; @@ -413,6 +414,16 @@ public static boolean isGenerated(org.eclipse.jdt.internal.compiler.ast.ASTNode } return result; } + + public static boolean isGenerated(org.eclipse.jdt.core.IMember member) { + boolean result = false; + try { + result = member.getNameRange().getLength() <= 0 || member.getNameRange().equals(member.getSourceRange()); + } catch (JavaModelException e) { + // better to assume it isn't generated + } + return result; + } public static boolean isBlockedVisitorAndGenerated(org.eclipse.jdt.core.dom.ASTNode node, org.eclipse.jdt.core.dom.ASTVisitor visitor) { if (visitor == null) return false; @@ -465,8 +476,10 @@ public static java.lang.String getRealMethodDeclarationSource(java.lang.String o StringBuilder signature = new StringBuilder(); addAnnotations(annotations, signature); - if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); - if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); + try { + if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public "); + if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract "); + } catch (Throwable t) { } signature .append(declaration.getReturnType2().toString()) @@ -512,7 +525,7 @@ public static void addAnnotations(List anno for (Object value : normalAnn.values()) values.add(value.toString()); } - signature.append("@").append(annotation.resolveTypeBinding().getQualifiedName()); + signature.append("@").append(annotation.getTypeName().getFullyQualifiedName()); if (!values.isEmpty()) { signature.append("("); boolean first = true; @@ -688,7 +701,7 @@ public static int getTokenEndOffsetFixed(TokenScanner scanner, int token, int st public static IMethod[] removeGeneratedMethods(IMethod[] methods) throws Exception { List result = new ArrayList(); for (IMethod m : methods) { - if (m.getNameRange().getLength() > 0 && !m.getNameRange().equals(m.getSourceRange())) result.add(m); + if (!isGenerated(m)) result.add(m); } return result.size() == methods.length ? methods : result.toArray(new IMethod[0]); } @@ -791,5 +804,21 @@ public static Annotation[] convertAnnotations(Annotation[] out, IAnnotatable ann return replace; } + + public static String getRealNodeSource(String original, org.eclipse.jdt.internal.compiler.ast.ASTNode node) { + if (!isGenerated(node)) return original; + + return node.toString(); + } + + public static java.lang.String getRealNodeSource(java.lang.String original, org.eclipse.jdt.core.dom.ASTNode node) throws Exception { + if (!isGenerated(node)) return original; + + return node.toString(); + } + + public static boolean skipRewriteVisibility(IncomingMemberVisibilityAdjustment adjustment) { + return isGenerated(adjustment.getMember()); + } } }