aboutsummaryrefslogtreecommitdiff
path: root/src/eclipseAgent
diff options
context:
space:
mode:
Diffstat (limited to 'src/eclipseAgent')
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java90
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/ExtensionMethodCompletionProposal.java76
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java106
-rwxr-xr-xsrc/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java39
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java138
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchVal.java25
-rwxr-xr-xsrc/eclipseAgent/lombok/launch/PatchFixesHider.java34
7 files changed, 458 insertions, 50 deletions
diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
index 2a7a6d51..1c7de88b 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
@@ -104,6 +104,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
patchRetrieveEllipsisStartPosition(sm);
patchRetrieveRightBraceOrSemiColonPosition(sm);
patchRetrieveProperRightBracketPosition(sm);
+ patchRetrieveStartBlockPosition(sm);
patchSetGeneratedFlag(sm);
patchDomAstReparseIssues(sm);
patchHideGeneratedNodes(sm);
@@ -126,6 +127,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
patchExtensionMethod(sm, ecjOnly);
patchRenameField(sm);
patchNullCheck(sm);
+ patchJavadoc(sm);
if (reloadExistingClasses) sm.reloadClasses(instrumentation);
}
@@ -414,6 +416,13 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
.transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build());
}
+ private static void patchRetrieveStartBlockPosition(ScriptManager sm) {
+ sm.addScript(ScriptBuilder.wrapReturnValue()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveStartBlockPosition"))
+ .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveStartBlockPosition", "int", "int", "int"))
+ .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build());
+ }
+
private static void patchRetrieveRightBraceOrSemiColonPosition(ScriptManager sm) {
sm.addScript(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"))
@@ -450,7 +459,15 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
sm.addScript(ScriptBuilder.wrapMethodCall()
.target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "extractSubArrayType", "org.eclipse.jdt.core.dom.ArrayType", "org.eclipse.jdt.core.dom.ArrayType", "int", "int"))
.methodToWrap(new Hook("org.eclipse.jdt.core.dom.ASTConverter", "retrieveProperRightBracketPosition", "int", "int", "int"))
- .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveProperRightBracketPosition", "int", "int", "org.eclipse.jdt.core.dom.ArrayType"))
+ .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveProperRightBracketPosition", "int", "int", "org.eclipse.jdt.core.dom.Type"))
+ .requestExtra(StackRequest.PARAM1)
+ .transplant()
+ .build());
+
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToArray", "org.eclipse.jdt.core.dom.ArrayType", "org.eclipse.jdt.core.dom.Type", "int", "int", "int", "org.eclipse.jdt.internal.compiler.ast.Annotation[][]"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.ASTConverter", "retrieveProperRightBracketPosition", "int", "int", "int"))
+ .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveProperRightBracketPosition", "int", "int", "org.eclipse.jdt.core.dom.Type"))
.requestExtra(StackRequest.PARAM1)
.transplant()
.build());
@@ -507,6 +524,8 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
.target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVariableDeclarationFragment", "org.eclipse.jdt.core.dom.VariableDeclarationFragment", "org.eclipse.jdt.internal.compiler.ast.FieldDeclaration"))
.target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVariableDeclarationFragment", "org.eclipse.jdt.core.dom.VariableDeclarationFragment", "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration"))
.target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVariableDeclarationStatement", "org.eclipse.jdt.core.dom.VariableDeclarationStatement", "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "createBaseType", "org.eclipse.jdt.core.dom.Type", "org.eclipse.jdt.internal.compiler.ast.TypeReference", "long[]", "org.eclipse.jdt.internal.compiler.ast.Annotation[][]", "char[][]", "int", "int", "boolean"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "createQualifiedType", "org.eclipse.jdt.core.dom.QualifiedType", "org.eclipse.jdt.internal.compiler.ast.TypeReference", "long[]", "org.eclipse.jdt.internal.compiler.ast.Annotation[][]", "char[][]", "int", "org.eclipse.jdt.core.dom.Type"))
/* Targets above are only patched because the resulting dom nodes should be marked if generated. */
.request(StackRequest.PARAM1, StackRequest.RETURN_VALUE)
.wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void",
@@ -542,6 +561,43 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
.wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlagForName", "void",
"org.eclipse.jdt.core.dom.Name", "java.lang.Object"))
.transplant().build());
+
+
+ sm.addScript(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"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.PrimitiveType", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM1)
+ .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.addScript(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"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleType", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM1)
+ .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.addScript(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"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.ParameterizedType", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM1)
+ .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.addScript(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"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.QualifiedType", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM1)
+ .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "setIsGeneratedFlag", "void",
+ "org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode"))
+ .transplant()
+ .build());
/* Set generated flag for QualifiedNames */
sm.addScript(ScriptBuilder.wrapMethodCall()
@@ -850,5 +906,37 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
.request(StackRequest.PARAM1)
.transplant().build());
}
+
+ private static void patchJavadoc(ScriptManager sm) {
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2", "getHTMLContent", "java.lang.String", "org.eclipse.jdt.core.IJavaElement", "boolean"))
+ .methodToWrap(new Hook("org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2", "getHTMLContentFromSource", "java.lang.String", "org.eclipse.jdt.core.IJavaElement"))
+ .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Javadoc", "getHTMLContentFromSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.IJavaElement"))
+ .requestExtra(StackRequest.PARAM1)
+ .build());
+
+ /* This is an older version that uses IMember instead of IJavaElement */
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2", "getHTMLContent", "java.lang.String", "org.eclipse.jdt.core.IMember", "boolean"))
+ .methodToWrap(new Hook("org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2", "getHTMLContentFromSource", "java.lang.String", "org.eclipse.jdt.core.IMember"))
+ .wrapMethod(new Hook("lombok.launch.PatchFixesHider$Javadoc", "getHTMLContentFromSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.IJavaElement"))
+ .requestExtra(StackRequest.PARAM1)
+ .build());
+
+ sm.addScript(ScriptBuilder.replaceMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.internal.compiler.ast.TypeDeclaration", "printBody", "java.lang.StringBuffer", "int", "java.lang.StringBuffer"))
+ .methodToReplace(new Hook("org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "print", "java.lang.StringBuffer", "int", "java.lang.StringBuffer"))
+ .replacementMethod(new Hook("lombok.launch.PatchFixesHider$Javadoc", "printMethod", "java.lang.StringBuffer", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration", "int", "java.lang.StringBuffer", "org.eclipse.jdt.internal.compiler.ast.TypeDeclaration"))
+ .requestExtra(StackRequest.THIS)
+ .build());
+
+ sm.addScript(ScriptBuilder.addField()
+ .fieldName("$javadoc")
+ .fieldType("Ljava/util/Map;")
+ .setPublic()
+ .setTransient()
+ .targetClass("org.eclipse.jdt.internal.core.CompilationUnit")
+ .build());
+ }
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/ExtensionMethodCompletionProposal.java b/src/eclipseAgent/lombok/eclipse/agent/ExtensionMethodCompletionProposal.java
index 46ce63f9..833a8226 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/ExtensionMethodCompletionProposal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/ExtensionMethodCompletionProposal.java
@@ -22,10 +22,15 @@
package lombok.eclipse.agent;
import static org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.AccStatic;
+import static org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.AccVarargs;
import java.util.Arrays;
+import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.CompletionProposal;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.codeassist.CompletionEngine;
import org.eclipse.jdt.internal.codeassist.InternalCompletionProposal;
@@ -35,16 +40,29 @@ import org.eclipse.jdt.internal.codeassist.complete.CompletionOnSingleNameRefere
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.core.NameLookup;
public class ExtensionMethodCompletionProposal extends InternalCompletionProposal {
+ private char[] fullSignature;
+ private char[][] parameterNames;
+
public ExtensionMethodCompletionProposal(final int replacementOffset) {
super(CompletionProposal.METHOD_REF, replacementOffset - 1);
}
public void setMethodBinding(final MethodBinding method, final ASTNode node) {
+ // Add proposal parameter names, sometimes its empty...
+ if (method.parameterNames != null && method.parameterNames.length > 0) {
+ setParameterNames(Arrays.copyOfRange(method.parameterNames, 1, method.parameterNames.length));
+ } else {
+ // Copy signature for parameter name resolution, this is more reliable but slower
+ fullSignature = CompletionEngine.getSignature(method);
+ }
+
MethodBinding original = method.original();
TypeBinding[] parameters = Arrays.copyOf(method.parameters, method.parameters.length);
method.parameters = Arrays.copyOfRange(method.parameters, 1, method.parameters.length);
+
TypeBinding[] originalParameters = null;
if (original != method) {
originalParameters = Arrays.copyOf(method.original().parameters, method.original().parameters.length);
@@ -76,6 +94,10 @@ public class ExtensionMethodCompletionProposal extends InternalCompletionProposa
setName(method.selector);
setCompletion(completion);
setFlags(method.modifiers & (~AccStatic));
+ // Remove varargs flag if it is the only parameter
+ if (method.isVarargs() && length == 0) {
+ setFlags(getFlags() & (~AccVarargs));
+ }
int index = node.sourceEnd + 1;
if (node instanceof CompletionOnQualifiedNameReference) {
index -= ((CompletionOnQualifiedNameReference) node).completionIdentifier.length;
@@ -96,4 +118,58 @@ public class ExtensionMethodCompletionProposal extends InternalCompletionProposa
method.original().parameters = originalParameters;
}
}
+
+ @Override
+ public char[][] findParameterNames(IProgressMonitor monitor) {
+ if (parameterNames != null) {
+ return parameterNames;
+ }
+
+ NameLookup.Answer answer = this.nameLookup.findType(
+ new String(this.declarationTypeName),
+ new String(this.declarationPackageName),
+ false,
+ NameLookup.ACCEPT_CLASSES & NameLookup.ACCEPT_INTERFACES,
+ true/* consider secondary types */,
+ false/* do NOT wait for indexes */,
+ false/*don't check restrictions*/,
+ null);
+
+ if (answer != null && answer.type != null) {
+ char[][] parameterTypes = Signature.getParameterTypes(fullSignature);
+
+ String[] args = new String[parameterTypes.length];
+ for (int i = 0; i < parameterTypes.length; i++) {
+ args[i] = new String(parameterTypes[i]);
+ }
+ IMethod method = answer.type.getMethod(new String(this.getName()), args);
+ IMethod[] methods = answer.type.findMethods(method);
+ if (methods != null && methods.length > 0) {
+ method = methods[0];
+ }
+ if (method != null) {
+ try {
+ String[] parameterNames = method.getParameterNames();
+ char[][] parameterNamesAsChar = new char[parameterNames.length - 1][];
+ for (int i = 0; i < parameterNamesAsChar.length; i++) {
+ parameterNamesAsChar[i] = parameterNames[i + 1].toCharArray();
+ }
+ setParameterNames(parameterNamesAsChar);
+ } catch (JavaModelException e) {
+ // Nope
+ }
+ }
+ }
+ // Seems like we failed, fallback
+ if (parameterNames == null) {
+ parameterNames = super.findParameterNames(monitor);
+ }
+ return parameterNames;
+ }
+
+ @Override
+ public void setParameterNames(char[][] parameterNames) {
+ this.parameterNames = parameterNames;
+ super.setParameterNames(parameterNames);
+ }
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java
index fcc76059..0b33ff0a 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java
@@ -24,6 +24,7 @@ package lombok.eclipse.agent;
import static lombok.eclipse.handlers.EclipseHandlerUtil.createAnnotation;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -58,6 +59,7 @@ import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
@@ -250,6 +252,14 @@ public class PatchExtensionMethod {
Binding binding = ((NameReference)methodCall.receiver).binding;
if (binding instanceof TypeBinding) skip = true;
}
+ // It's impossible to resolve the right method without types
+ if (Reflection.argumentsHaveErrors != null) {
+ try {
+ if ((Boolean) Reflection.argumentsHaveErrors.get(methodCall)) skip = true;
+ } catch (IllegalAccessException ignore) {
+ // ignore
+ }
+ }
if (!skip) for (Extension extension : extensions) {
if (!extension.suppressBaseMethods && !(methodCall.binding instanceof ProblemMethodBinding)) continue;
@@ -262,13 +272,30 @@ public class PatchExtensionMethod {
List<Expression> arguments = new ArrayList<Expression>();
arguments.add(methodCall.receiver);
if (methodCall.arguments != null) arguments.addAll(Arrays.asList(methodCall.arguments));
+ Expression[] originalArgs = methodCall.arguments;
+ methodCall.arguments = arguments.toArray(new Expression[0]);
+
List<TypeBinding> argumentTypes = new ArrayList<TypeBinding>();
for (Expression argument : arguments) {
- if (argument.resolvedType != null) argumentTypes.add(argument.resolvedType);
- // TODO: Instead of just skipping nulls entirely, there is probably a 'unresolved type' placeholder. THAT is what we ought to be adding here!
+ TypeBinding argumentType = argument.resolvedType;
+ if (argumentType == null && Reflection.isFunctionalExpression(argument)) {
+ argumentType = Reflection.getPolyTypeBinding(argument);
+ }
+ if (argumentType == null) {
+ argumentType = TypeBinding.NULL;
+ }
+ argumentTypes.add(argumentType);
}
- Expression[] originalArgs = methodCall.arguments;
- methodCall.arguments = arguments.toArray(new Expression[0]);
+
+ // Copy generic information. This one covers a few simple cases, more complex cases are still broken
+ int typeVariables = extensionMethod.typeVariables.length;
+ if (typeVariables > 0 && methodCall.receiver.resolvedType instanceof ParameterizedTypeBinding) {
+ ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) methodCall.receiver.resolvedType;
+ if (parameterizedTypeBinding.arguments != null && parameterizedTypeBinding.arguments.length == typeVariables) {
+ methodCall.genericTypeArguments = parameterizedTypeBinding.arguments;
+ }
+ }
+
MethodBinding fixedBinding = scope.getMethod(extensionMethod.declaringClass, methodCall.selector, argumentTypes.toArray(new TypeBinding[0]), methodCall);
if (fixedBinding instanceof ProblemMethodBinding) {
methodCall.arguments = originalArgs;
@@ -276,18 +303,33 @@ public class PatchExtensionMethod {
PostponedInvalidMethodError.invoke(scope.problemReporter(), methodCall, fixedBinding, scope);
}
} else {
+ // If the extension method uses varargs, the last fixed binding parameter is an array but
+ // the method arguments are not. Even thought we already know that the method is fine we still
+ // have to compare each parameter with the type of the array to support autoboxing/unboxing.
+ boolean isVarargs = fixedBinding.isVarargs();
for (int i = 0, iend = arguments.size(); i < iend; i++) {
Expression arg = arguments.get(i);
- if (fixedBinding.parameters[i].isArrayType() != arg.resolvedType.isArrayType()) break;
- if (arg instanceof MessageSend) {
- ((MessageSend) arg).valueCast = arg.resolvedType;
+ TypeBinding[] parameters = fixedBinding.parameters;
+ TypeBinding param;
+ if (isVarargs && i >= parameters.length - 1) {
+ // Extract the array element type for all vararg arguments
+ param = parameters[parameters.length - 1].leafComponentType();
+ } else {
+ param = parameters[i];
+ }
+ // Resolve types for lambdas
+ if (Reflection.isFunctionalExpression(arg)) {
+ arg.setExpectedType(param);
+ arg.resolveType(scope);
}
- if (!fixedBinding.parameters[i].isBaseType() && arg.resolvedType.isBaseType()) {
- int id = arg.resolvedType.id;
- arg.implicitConversion = TypeIds.BOXING | (id + (id << 4)); // magic see TypeIds
- } else if (fixedBinding.parameters[i].isBaseType() && !arg.resolvedType.isBaseType()) {
- int id = fixedBinding.parameters[i].id;
- arg.implicitConversion = TypeIds.UNBOXING | (id + (id << 4)); // magic see TypeIds
+ if (arg.resolvedType != null) {
+ if (!param.isBaseType() && arg.resolvedType.isBaseType()) {
+ int id = arg.resolvedType.id;
+ arg.implicitConversion = TypeIds.BOXING | (id + (id << 4)); // magic see TypeIds
+ } else if (param.isBaseType() && !arg.resolvedType.isBaseType()) {
+ int id = parameters[i].id;
+ arg.implicitConversion = TypeIds.UNBOXING | (id + (id << 4)); // magic see TypeIds
+ }
}
}
@@ -295,6 +337,7 @@ public class PatchExtensionMethod {
methodCall.actualReceiverType = extensionMethod.declaringClass;
methodCall.binding = fixedBinding;
methodCall.resolvedType = methodCall.binding.returnType;
+ methodCall.statementEnd = methodCall.sourceEnd;
if (Reflection.argumentTypes != null) {
try {
Reflection.argumentTypes.set(methodCall, argumentTypes.toArray(new TypeBinding[0]));
@@ -340,16 +383,41 @@ public class PatchExtensionMethod {
}
private static final class Reflection {
- public static final Field argumentTypes;
+ public static final Field argumentTypes = Permit.permissiveGetField(MessageSend.class, "argumentTypes");
+ public static final Field argumentsHaveErrors = Permit.permissiveGetField(MessageSend.class, "argumentsHaveErrors");
+ private static final Class<?> functionalExpression;
+ private static final Constructor<?> polyTypeBindingConstructor;
static {
- Field a = null;
+ Class<?> a = null;
+ Constructor<?> b = null;
try {
- a = Permit.getField(MessageSend.class, "argumentTypes");
- } catch (Throwable t) {
- //ignore - old eclipse versions don't know this one
+ a = Class.forName("org.eclipse.jdt.internal.compiler.ast.FunctionalExpression");
+ } catch (Exception e) {
+ // Ignore
+ }
+ try {
+ b = Permit.getConstructor(Class.forName("org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding"), Expression.class);
+ } catch (Exception e) {
+ // Ignore
+ }
+ functionalExpression = a;
+ polyTypeBindingConstructor = b;
+ }
+
+ public static boolean isFunctionalExpression(Expression expression) {
+ if (functionalExpression == null) return false;
+ return functionalExpression.isInstance(expression);
+ }
+
+ public static TypeBinding getPolyTypeBinding(Expression expression) {
+ if (polyTypeBindingConstructor == null) return null;
+ try {
+ return (TypeBinding) polyTypeBindingConstructor.newInstance(expression);
+ } catch (Exception e) {
+ // Ignore
}
- argumentTypes = a;
+ return null;
}
}
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java
index 085c903f..08a42d1c 100755
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java
@@ -65,13 +65,14 @@ public class PatchExtensionMethodCompletionProposal {
CompletionProposalCollector completionProposalCollector) {
List<IJavaCompletionProposal> proposals = new ArrayList<IJavaCompletionProposal>(Arrays.asList(javaCompletionProposals));
- if (canExtendCodeAssist(proposals)) {
- IJavaCompletionProposal firstProposal = proposals.get(0);
- int replacementOffset = getReplacementOffset(firstProposal);
+ if (canExtendCodeAssist()) {
for (Extension extension : getExtensionMethods(completionProposalCollector)) {
for (MethodBinding method : extension.extensionMethods) {
- ExtensionMethodCompletionProposal newProposal = new ExtensionMethodCompletionProposal(replacementOffset);
- copyNameLookupAndCompletionEngine(completionProposalCollector, firstProposal, newProposal);
+ if (!isMatchingProposal(method, completionProposalCollector)) {
+ continue;
+ }
+ ExtensionMethodCompletionProposal newProposal = new ExtensionMethodCompletionProposal(0);
+ copyNameLookupAndCompletionEngine(completionProposalCollector, newProposal);
ASTNode node = getAssistNode(completionProposalCollector);
newProposal.setMethodBinding(method, node);
createAndAddJavaCompletionProposal(completionProposalCollector, newProposal, proposals);
@@ -81,7 +82,6 @@ public class PatchExtensionMethodCompletionProposal {
return proposals.toArray(new IJavaCompletionProposal[0]);
}
-
private static List<Extension> getExtensionMethods(CompletionProposalCollector completionProposalCollector) {
List<Extension> extensions = new ArrayList<Extension>();
ClassScope classScope = getClassScope(completionProposalCollector);
@@ -96,6 +96,17 @@ public class PatchExtensionMethodCompletionProposal {
return extensions;
}
+ private static boolean isMatchingProposal(MethodBinding method, CompletionProposalCollector completionProposalCollector) {
+ try {
+ InternalCompletionContext context = (InternalCompletionContext) Reflection.contextField.get(completionProposalCollector);
+ String searchToken = new String(context.getToken());
+ String extensionMethodName = new String(method.selector);
+ return extensionMethodName.contains(searchToken);
+ } catch (IllegalAccessException e) {
+ return true;
+ }
+ }
+
static TypeBinding getFirstParameterType(TypeDeclaration decl, CompletionProposalCollector completionProposalCollector) {
TypeBinding firstParameterType = null;
ASTNode node = getAssistNode(completionProposalCollector);
@@ -149,8 +160,7 @@ public class PatchExtensionMethodCompletionProposal {
return scope;
}
- private static void copyNameLookupAndCompletionEngine(CompletionProposalCollector completionProposalCollector, IJavaCompletionProposal proposal,
- InternalCompletionProposal newProposal) {
+ private static void copyNameLookupAndCompletionEngine(CompletionProposalCollector completionProposalCollector, InternalCompletionProposal newProposal) {
try {
InternalCompletionContext context = (InternalCompletionContext) Reflection.contextField.get(completionProposalCollector);
@@ -173,17 +183,10 @@ public class PatchExtensionMethodCompletionProposal {
}
}
- private static boolean canExtendCodeAssist(List<IJavaCompletionProposal> proposals) {
- return !proposals.isEmpty() && Reflection.isComplete();
- }
-
- private static int getReplacementOffset(Object proposal) {
- try {
- return Reflection.replacementOffsetField.getInt(proposal);
- } catch (Exception ignore) {
- return 0;
- }
+ private static boolean canExtendCodeAssist() {
+ return Reflection.isComplete();
}
+
static class Reflection {
public static final Field replacementOffsetField;
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java
new file mode 100644
index 00000000..a91e4d8b
--- /dev/null
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchJavadoc.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Project Lombok Authors.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package lombok.eclipse.agent;
+
+import static lombok.eclipse.EclipseAugments.CompilationUnit_javadoc;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IMember;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.core.CompilationUnit;
+import org.eclipse.jdt.internal.core.SourceMethod;
+import org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2;
+
+import lombok.eclipse.EclipseAugments;
+import lombok.eclipse.handlers.EclipseHandlerUtil;
+import lombok.permit.Permit;
+
+public class PatchJavadoc {
+
+ public static String getHTMLContentFromSource(String original, IJavaElement member) {
+ if (original != null) {
+ return original;
+ }
+
+ if (member instanceof SourceMethod) {
+ SourceMethod sourceMethod = (SourceMethod) member;
+ ICompilationUnit iCompilationUnit = sourceMethod.getCompilationUnit();
+ if (iCompilationUnit instanceof CompilationUnit) {
+ CompilationUnit compilationUnit = (CompilationUnit) iCompilationUnit;
+ Map<String, String> docs = EclipseAugments.CompilationUnit_javadoc.get(compilationUnit);
+
+ String signature = getSignature(sourceMethod);
+ String rawJavadoc = docs.get(signature);
+ if (rawJavadoc == null) return null;
+
+ return Reflection.javadoc2HTML((IMember) member, member, rawJavadoc);
+ }
+ }
+
+ return null;
+ }
+
+ public static StringBuffer printMethod(AbstractMethodDeclaration methodDeclaration, Integer tab, StringBuffer output, TypeDeclaration type) {
+ if (methodDeclaration.compilationResult.compilationUnit instanceof CompilationUnit) {
+ Map<String, String> docs = CompilationUnit_javadoc.get((CompilationUnit) methodDeclaration.compilationResult.compilationUnit);
+ if (docs != null) {
+ String signature = EclipseHandlerUtil.getSignature(type, methodDeclaration);
+ String rawJavadoc = docs.get(signature);
+ if (rawJavadoc != null) {
+ for (String line : rawJavadoc.split("\r?\n")) {
+ ASTNode.printIndent(tab, output).append(line).append("\n");
+ }
+ }
+ }
+ }
+ return methodDeclaration.print(tab, output);
+ }
+
+ private static String getSignature(SourceMethod sourceMethod) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(sourceMethod.getParent().getElementName());
+ sb.append(".");
+ sb.append(sourceMethod.getElementName());
+ sb.append("(");
+ for (String type : sourceMethod.getParameterTypes()) {
+ sb.append(type);
+ }
+ sb.append(")");
+
+ return sb.toString();
+ }
+
+ /**
+ * The method <code>javadoc2HTML</code> changed 2014-12 to accept an
+ * additional IJavaElement parameter. To support older versions, try to
+ * find that one too.
+ */
+ private static class Reflection {
+ private static final Method javadoc2HTML;
+ private static final Method oldJavadoc2HTML;
+ static {
+ Method a = null, b = null;
+
+ try {
+ a = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, IJavaElement.class, String.class);
+ } catch (Throwable t) {}
+ try {
+ b = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, String.class);
+ } catch (Throwable t) {}
+
+ javadoc2HTML = a;
+ oldJavadoc2HTML = b;
+ }
+
+ private static String javadoc2HTML(IMember member, IJavaElement element, String rawJavadoc) {
+ if (javadoc2HTML != null) {
+ try {
+ return (String) javadoc2HTML.invoke(null, member, element, rawJavadoc);
+ } catch (Throwable t) {
+ return null;
+ }
+ }
+ if (oldJavadoc2HTML != null) {
+ try {
+ return (String) oldJavadoc2HTML.invoke(null, member, rawJavadoc);
+ } catch (Throwable t) {
+ return null;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
index 056852c8..f22e78a8 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
@@ -35,11 +35,13 @@ import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
@@ -227,14 +229,16 @@ public class PatchVal {
boolean var = isVar(local, scope);
if (!(val || var)) return false;
- StackTraceElement[] st = new Throwable().getStackTrace();
- for (int i = 0; i < st.length - 2 && i < 10; i++) {
- if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) {
- boolean valInForStatement = val &&
- st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") &&
- st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement");
- if (valInForStatement) return false;
- break;
+ if (val) {
+ StackTraceElement[] st = new Throwable().getStackTrace();
+ for (int i = 0; i < st.length - 2 && i < 10; i++) {
+ if (st[i].getClassName().equals("lombok.launch.PatchFixesHider$Val")) {
+ boolean valInForStatement =
+ st[i + 1].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.LocalDeclaration") &&
+ st[i + 2].getClassName().equals("org.eclipse.jdt.internal.compiler.ast.ForStatement");
+ if (valInForStatement) return false;
+ break;
+ }
}
}
@@ -264,6 +268,7 @@ public class PatchVal {
}
TypeBinding resolved = null;
+ Constant oldConstant = init.constant;
try {
resolved = decomponent ? getForEachComponentType(init, scope) : resolveForExpression(init, scope);
} catch (NullPointerException e) {
@@ -280,6 +285,10 @@ public class PatchVal {
} catch (Exception e) {
// Some type thing failed.
}
+ } else {
+ if (init instanceof MessageSend && ((MessageSend) init).actualReceiverType == null) {
+ init.constant = oldConstant;
+ }
}
}
diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
index 708824dd..76f30527 100755
--- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java
+++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
@@ -35,12 +35,13 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IAnnotatable;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IField;
+import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -50,6 +51,7 @@ import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
@@ -303,6 +305,26 @@ final class PatchFixesHider {
}
}
+ /** Contains patch code to support Javadoc for generated methods */
+ public static final class Javadoc {
+ private static final Method GET_HTML;
+ private static final Method PRINT_METHOD;
+
+ static {
+ Class<?> shadowed = Util.shadowLoadClass("lombok.eclipse.agent.PatchJavadoc");
+ GET_HTML = Util.findMethod(shadowed, "getHTMLContentFromSource", String.class, IJavaElement.class);
+ PRINT_METHOD = Util.findMethod(shadowed, "printMethod", AbstractMethodDeclaration.class, Integer.class, StringBuffer.class, TypeDeclaration.class);
+ }
+
+ public static String getHTMLContentFromSource(String original, IJavaElement member) {
+ return (String) Util.invokeMethod(GET_HTML, original, member);
+ }
+
+ public static StringBuffer printMethod(AbstractMethodDeclaration methodDeclaration, int tab, StringBuffer output, TypeDeclaration type) {
+ return (StringBuffer) Util.invokeMethod(PRINT_METHOD, methodDeclaration, tab, output, type);
+ }
+ }
+
/**
* Contains a mix of methods: ecj only, ecj+eclipse, and eclipse only. As a consequence, _EVERY_ method from here used for ecj MUST be
* transplanted, as ecj itself cannot load this class (signatures refer to things that don't exist in ecj-only mode).
@@ -503,6 +525,10 @@ final class PatchFixesHider {
return original == -1 ? end : original;
}
+ public static int fixRetrieveStartBlockPosition(int original, int start) {
+ return original == -1 ? start : original;
+ }
+
public static int fixRetrieveRightBraceOrSemiColonPosition(int original, int end) {
// if (original == -1) {
// Thread.dumpStack();
@@ -524,9 +550,9 @@ final class PatchFixesHider {
return -1;
}
- public static int fixRetrieveProperRightBracketPosition(int retVal, ArrayType arrayType) {
- if (retVal != -1 || arrayType == null) return retVal;
- if (isGenerated(arrayType)) return arrayType.getStartPosition() + arrayType.getLength() - 1;
+ public static int fixRetrieveProperRightBracketPosition(int retVal, Type type) {
+ if (retVal != -1 || type == null) return retVal;
+ if (isGenerated(type)) return type.getStartPosition() + type.getLength() - 1;
return -1;
}