aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobbert Jan Grootjans <grootjans@gmail.com>2012-06-18 23:58:51 +0200
committerRobbert Jan Grootjans <grootjans@gmail.com>2012-06-18 23:59:05 +0200
commit3ed67fc8aecf50757d85bdfb55075015c6627740 (patch)
tree28618c792f6578de68e74eb8da7a497149fd053a
parent2af094030f2025f0853955585c150b5451b108d2 (diff)
downloadlombok-3ed67fc8aecf50757d85bdfb55075015c6627740.tar.gz
lombok-3ed67fc8aecf50757d85bdfb55075015c6627740.tar.bz2
lombok-3ed67fc8aecf50757d85bdfb55075015c6627740.zip
Fixed Help Content in Eclipse / ecj support.
- Moved Completion proposal code to the PatchExtensionMethodCompletionProposal class - Moved out error reporting from EclipseAST. - Fixed error reporting of the portals.
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java82
-rw-r--r--src/core/lombok/eclipse/EclipseAstProblemView.java56
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchDelegatePortal.java11
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java134
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java141
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java15
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodPortal.java103
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchValEclipsePortal.java48
8 files changed, 391 insertions, 199 deletions
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java
index 4b009469..8ab42140 100644
--- a/src/core/lombok/eclipse/EclipseAST.java
+++ b/src/core/lombok/eclipse/EclipseAST.java
@@ -21,15 +21,16 @@
*/
package lombok.eclipse;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import lombok.Lombok;
import lombok.core.AST;
-import org.eclipse.jdt.core.compiler.CategorizedProblem;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -42,9 +43,6 @@ import org.eclipse.jdt.internal.compiler.ast.Initializer;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
-import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
-import org.eclipse.jdt.internal.compiler.util.Util;
/**
* Wraps around Eclipse's internal AST view to add useful features as well as the ability to visit parents from children,
@@ -147,44 +145,25 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
public static void addProblemToCompilationResult(CompilationUnitDeclaration ast,
boolean isWarning, String message, int sourceStart, int sourceEnd) {
if (ast.compilationResult == null) return;
- char[] fileNameArray = ast.getFileName();
- if (fileNameArray == null) fileNameArray = "(unknown).java".toCharArray();
- int lineNumber = 0;
- int columnNumber = 1;
- CompilationResult result = ast.compilationResult;
- int[] lineEnds = null;
- lineNumber = sourceStart >= 0
- ? Util.getLineNumber(sourceStart, lineEnds = result.getLineSeparatorPositions(), 0, lineEnds.length-1)
- : 0;
- columnNumber = sourceStart >= 0
- ? Util.searchColumnNumber(result.getLineSeparatorPositions(), lineNumber,sourceStart)
- : 0;
-
- CategorizedProblem ecProblem = new LombokProblem(
- fileNameArray, message, 0, new String[0],
- isWarning ? ProblemSeverities.Warning : ProblemSeverities.Error,
- sourceStart, sourceEnd, lineNumber, columnNumber);
- ast.compilationResult.record(ecProblem, null);
- }
-
- private static class LombokProblem extends DefaultProblem {
- private static final String MARKER_ID = "org.eclipse.jdt.apt.pluggable.core.compileProblem"; //$NON-NLS-1$
-
- public LombokProblem(char[] originatingFileName, String message, int id,
- String[] stringArguments, int severity,
- int startPosition, int endPosition, int line, int column) {
- super(originatingFileName, message, id, stringArguments, severity, startPosition, endPosition, line, column);
- }
-
- @Override public int getCategoryID() {
- return CAT_UNSPECIFIED;
- }
-
- @Override public String getMarkerType() {
- return MARKER_ID;
+ try {
+ EcjReflectionCheck.addProblemToCompilationResult.invoke(null, ast, isWarning, message, sourceStart, sourceEnd);
+ } catch (NoClassDefFoundError e) {
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ } catch (IllegalAccessException e) {
+ throw Lombok.sneakyThrow(e);
+ } catch (InvocationTargetException e) {
+ throw Lombok.sneakyThrow(e);
+ } catch (NullPointerException e) {
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(EcjReflectionCheck.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
}
}
-
+
private final CompilationUnitDeclaration compilationUnitDeclaration;
private boolean completeParse;
@@ -372,4 +351,25 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
@Override protected Collection<Class<? extends ASTNode>> getStatementTypes() {
return Collections.<Class<? extends ASTNode>>singleton(Statement.class);
}
+
+ private static class EcjReflectionCheck {
+ private static final String CUD_TYPE = "org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration";
+
+ public static Method addProblemToCompilationResult;
+ public static final Throwable problem;
+
+ static {
+ Throwable problem_ = null;
+ Method m = null;
+ try {
+ m = EclipseAstProblemView.class.getMethod("addProblemToCompilationResult", Class.forName(CUD_TYPE), boolean.class, String.class, int.class, int.class);
+ } catch (Throwable t) {
+ // That's problematic, but as long as no local classes are used we don't actually need it.
+ // Better fail on local classes than crash altogether.
+ problem_ = t;
+ }
+ addProblemToCompilationResult = m;
+ problem = problem_;
+ }
+ }
}
diff --git a/src/core/lombok/eclipse/EclipseAstProblemView.java b/src/core/lombok/eclipse/EclipseAstProblemView.java
new file mode 100644
index 00000000..a2d5b833
--- /dev/null
+++ b/src/core/lombok/eclipse/EclipseAstProblemView.java
@@ -0,0 +1,56 @@
+package lombok.eclipse;
+
+
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+import org.eclipse.jdt.internal.compiler.util.Util;
+
+public class EclipseAstProblemView {
+ /**
+ * Adds a problem to the provided CompilationResult object so that it will show up
+ * in the Problems/Warnings view.
+ */
+ public static void addProblemToCompilationResult(CompilationUnitDeclaration ast,
+ boolean isWarning, String message, int sourceStart, int sourceEnd) {
+ if (ast.compilationResult == null) return;
+ char[] fileNameArray = ast.getFileName();
+ if (fileNameArray == null) fileNameArray = "(unknown).java".toCharArray();
+ int lineNumber = 0;
+ int columnNumber = 1;
+ CompilationResult result = ast.compilationResult;
+ int[] lineEnds = null;
+ lineNumber = sourceStart >= 0
+ ? Util.getLineNumber(sourceStart, lineEnds = result.getLineSeparatorPositions(), 0, lineEnds.length-1)
+ : 0;
+ columnNumber = sourceStart >= 0
+ ? Util.searchColumnNumber(result.getLineSeparatorPositions(), lineNumber,sourceStart)
+ : 0;
+
+ CategorizedProblem ecProblem = new LombokProblem(
+ fileNameArray, message, 0, new String[0],
+ isWarning ? ProblemSeverities.Warning : ProblemSeverities.Error,
+ sourceStart, sourceEnd, lineNumber, columnNumber);
+ ast.compilationResult.record(ecProblem, null);
+ }
+
+ private static class LombokProblem extends DefaultProblem {
+ private static final String MARKER_ID = "org.eclipse.jdt.apt.pluggable.core.compileProblem"; //$NON-NLS-1$
+
+ public LombokProblem(char[] originatingFileName, String message, int id,
+ String[] stringArguments, int severity,
+ int startPosition, int endPosition, int line, int column) {
+ super(originatingFileName, message, id, stringArguments, severity, startPosition, endPosition, line, column);
+ }
+
+ @Override public int getCategoryID() {
+ return CAT_UNSPECIFIED;
+ }
+
+ @Override public String getMarkerType() {
+ return MARKER_ID;
+ }
+ }
+}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegatePortal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegatePortal.java
index 1620014c..49083df0 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegatePortal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegatePortal.java
@@ -39,10 +39,15 @@ public class PatchDelegatePortal {
} catch (IllegalAccessException e) {
throw Lombok.sneakyThrow(e);
} catch (InvocationTargetException e) {
- throw Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e.getCause());
} catch (NullPointerException e) {
- e.initCause(Reflection.problem);
- throw e;
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return false;
}
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java
index 1b244234..36d884b9 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethod.java
@@ -23,9 +23,6 @@ package lombok.eclipse.agent;
import static lombok.eclipse.handlers.EclipseHandlerUtil.createAnnotation;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -41,39 +38,25 @@ import lombok.eclipse.TransformEclipseAST;
import lombok.eclipse.handlers.EclipseHandlerUtil;
import lombok.experimental.ExtensionMethod;
-import org.eclipse.jdt.core.CompletionProposal;
-import org.eclipse.jdt.internal.codeassist.InternalCompletionContext;
-import org.eclipse.jdt.internal.codeassist.InternalCompletionProposal;
-import org.eclipse.jdt.internal.codeassist.InternalExtendedCompletionContext;
-import org.eclipse.jdt.internal.codeassist.complete.CompletionOnMemberAccess;
-import org.eclipse.jdt.internal.codeassist.complete.CompletionOnQualifiedNameReference;
-import org.eclipse.jdt.internal.codeassist.complete.CompletionOnSingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Expression;
-import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
-import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
-import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
-import org.eclipse.jdt.internal.ui.text.java.AbstractJavaCompletionProposal;
-import org.eclipse.jdt.ui.text.java.CompletionProposalCollector;
public class PatchExtensionMethod {
static class Extension {
@@ -138,7 +121,7 @@ public class PatchExtensionMethod {
return null;
}
- private static EclipseNode upToType(EclipseNode typeNode) {
+ static EclipseNode upToType(EclipseNode typeNode) {
EclipseNode node = typeNode;
do {
node = node.up();
@@ -146,7 +129,7 @@ public class PatchExtensionMethod {
return node;
}
- private static List<Extension> getApplicableExtensionMethods(EclipseNode typeNode, Annotation ann, TypeBinding receiverType) {
+ static List<Extension> getApplicableExtensionMethods(EclipseNode typeNode, Annotation ann, TypeBinding receiverType) {
List<Extension> extensions = new ArrayList<Extension>();
if ((typeNode != null) && (ann != null) && (receiverType != null)) {
BlockScope blockScope = ((TypeDeclaration) typeNode.get()).initializerScope;
@@ -295,118 +278,7 @@ public class PatchExtensionMethod {
return new QualifiedNameReference(sources, poss, source.sourceStart, source.sourceEnd);
}
}
-
- static List<Extension> getExtensionMethods(CompletionProposalCollector completionProposalCollector) {
- List<Extension> extensions = new ArrayList<Extension>();
- ClassScope classScope = getClassScope(completionProposalCollector);
- if (classScope != null) {
- TypeDeclaration decl = classScope.referenceContext;
- TypeBinding firstParameterType = getFirstParameterType(decl, completionProposalCollector);
- for (EclipseNode typeNode = getTypeNode(decl); typeNode != null; typeNode = upToType(typeNode)) {
- Annotation ann = getAnnotation(ExtensionMethod.class, typeNode);
- extensions.addAll(0, getApplicableExtensionMethods(typeNode, ann, firstParameterType));
- }
- }
- return extensions;
- }
-
- private static ClassScope getClassScope(CompletionProposalCollector completionProposalCollector) {
- ClassScope scope = null;
- try {
- InternalCompletionContext context = (InternalCompletionContext) Reflection.contextField.get(completionProposalCollector);
- InternalExtendedCompletionContext extendedContext = (InternalExtendedCompletionContext) Reflection.extendedContextField.get(context);
- if (extendedContext != null) {
- Scope assistScope = ((Scope) Reflection.assistScopeField.get(extendedContext));
- if (assistScope != null) {
- scope = assistScope.classScope();
- }
- }
- } catch (IllegalAccessException ignore) {
- // ignore
- }
- return scope;
- }
-
- private static TypeBinding getFirstParameterType(TypeDeclaration decl, CompletionProposalCollector completionProposalCollector) {
- TypeBinding firstParameterType = null;
- ASTNode node = getAssistNode(completionProposalCollector);
- if (node == null) return null;
- if (!(node instanceof CompletionOnQualifiedNameReference) && !(node instanceof CompletionOnSingleNameReference) && !(node instanceof CompletionOnMemberAccess)) return null;
-
- if (node instanceof NameReference) {
- Binding binding = ((NameReference) node).binding;
- if ((node instanceof SingleNameReference) && (((SingleNameReference) node).token.length == 0)) {
- firstParameterType = decl.binding;
- } else if (binding instanceof VariableBinding) {
- firstParameterType = ((VariableBinding) binding).type;
- } else if (binding instanceof TypeBinding) {
- firstParameterType = (TypeBinding) binding;
- }
- } else if (node instanceof FieldReference) {
- firstParameterType = ((FieldReference) node).actualReceiverType;
- }
- return firstParameterType;
- }
-
- static ASTNode getAssistNode(CompletionProposalCollector completionProposalCollector) {
- try {
- InternalCompletionContext context = (InternalCompletionContext) Reflection.contextField.get(completionProposalCollector);
- InternalExtendedCompletionContext extendedContext = (InternalExtendedCompletionContext) Reflection.extendedContextField.get(context);
- if (extendedContext == null) return null;
- return (ASTNode) Reflection.assistNodeField.get(extendedContext);
- } catch (Exception ignore) {
- return null;
- }
- }
-
- static class Reflection {
- public static final Field replacementOffsetField;
- public static final Field contextField;
- public static final Field extendedContextField;
- public static final Field assistNodeField;
- public static final Field assistScopeField;
- public static final Field lookupEnvironmentField;
- public static final Field completionEngineField;
- public static final Field nameLookupField;
- public static final Method createJavaCompletionProposalMethod;
- static {
- replacementOffsetField = accessField(AbstractJavaCompletionProposal.class, "fReplacementOffset");
- contextField = accessField(CompletionProposalCollector.class, "fContext");
- extendedContextField = accessField(InternalCompletionContext.class, "extendedContext");
- assistNodeField = accessField(InternalExtendedCompletionContext.class, "assistNode");
- assistScopeField = accessField(InternalExtendedCompletionContext.class, "assistScope");
- lookupEnvironmentField = accessField(InternalExtendedCompletionContext.class, "lookupEnvironment");
- completionEngineField = accessField(InternalCompletionProposal.class, "completionEngine");
- nameLookupField = accessField(InternalCompletionProposal.class, "nameLookup");
- createJavaCompletionProposalMethod = accessMethod(CompletionProposalCollector.class, "createJavaCompletionProposal", CompletionProposal.class);
- }
-
- static boolean isComplete() {
- Object[] requiredFieldsAndMethods = { replacementOffsetField, contextField, extendedContextField, assistNodeField, assistScopeField, lookupEnvironmentField, completionEngineField, nameLookupField, createJavaCompletionProposalMethod };
- for (Object o : requiredFieldsAndMethods) if (o == null) return false;
- return true;
- }
-
- private static Field accessField(Class<?> clazz, String fieldName) {
- try {
- return makeAccessible(clazz.getDeclaredField(fieldName));
- } catch (Exception e) {
- return null;
- }
- }
-
- private static Method accessMethod(Class<?> clazz, String methodName, Class<?> parameter) {
- try {
- return makeAccessible(clazz.getDeclaredMethod(methodName, parameter));
- } catch (Exception e) {
- return null;
- }
- }
+
- private static <T extends AccessibleObject> T makeAccessible(T object) {
- object.setAccessible(true);
- return object;
- }
- }
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java
index bd6e328c..701a2029 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java
@@ -21,21 +21,41 @@
*/
package lombok.eclipse.agent;
+import static lombok.eclipse.agent.PatchExtensionMethod.*;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import lombok.eclipse.EclipseNode;
import lombok.eclipse.agent.PatchExtensionMethod.Extension;
-import lombok.eclipse.agent.PatchExtensionMethod.Reflection;
+import lombok.experimental.ExtensionMethod;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.internal.codeassist.InternalCompletionContext;
import org.eclipse.jdt.internal.codeassist.InternalCompletionProposal;
import org.eclipse.jdt.internal.codeassist.InternalExtendedCompletionContext;
+import org.eclipse.jdt.internal.codeassist.complete.CompletionOnMemberAccess;
+import org.eclipse.jdt.internal.codeassist.complete.CompletionOnQualifiedNameReference;
+import org.eclipse.jdt.internal.codeassist.complete.CompletionOnSingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.FieldReference;
+import org.eclipse.jdt.internal.compiler.ast.NameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
+import org.eclipse.jdt.internal.ui.text.java.AbstractJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.CompletionProposalCollector;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
@@ -49,11 +69,11 @@ public class PatchExtensionMethodCompletionProposal {
if (canExtendCodeAssist(proposals)) {
IJavaCompletionProposal firstProposal = proposals.get(0);
int replacementOffset = getReplacementOffset(firstProposal);
- for (Extension extension : PatchExtensionMethod.getExtensionMethods(completionProposalCollector)) {
+ for (Extension extension : getExtensionMethods(completionProposalCollector)) {
for (MethodBinding method : extension.extensionMethods) {
ExtensionMethodCompletionProposal newProposal = new ExtensionMethodCompletionProposal(replacementOffset);
copyNameLookupAndCompletionEngine(completionProposalCollector, firstProposal, newProposal);
- ASTNode node = PatchExtensionMethod.getAssistNode(completionProposalCollector);
+ ASTNode node = getAssistNode(completionProposalCollector);
newProposal.setMethodBinding(method, node);
createAndAddJavaCompletionProposal(completionProposalCollector, newProposal, proposals);
}
@@ -62,6 +82,70 @@ public class PatchExtensionMethodCompletionProposal {
return proposals.toArray(new IJavaCompletionProposal[proposals.size()]);
}
+
+ private static List<Extension> getExtensionMethods(CompletionProposalCollector completionProposalCollector) {
+ List<Extension> extensions = new ArrayList<Extension>();
+ ClassScope classScope = getClassScope(completionProposalCollector);
+ if (classScope != null) {
+ TypeDeclaration decl = classScope.referenceContext;
+ TypeBinding firstParameterType = getFirstParameterType(decl, completionProposalCollector);
+ for (EclipseNode typeNode = getTypeNode(decl); typeNode != null; typeNode = upToType(typeNode)) {
+ Annotation ann = getAnnotation(ExtensionMethod.class, typeNode);
+ extensions.addAll(0, getApplicableExtensionMethods(typeNode, ann, firstParameterType));
+ }
+ }
+ return extensions;
+ }
+
+ static TypeBinding getFirstParameterType(TypeDeclaration decl, CompletionProposalCollector completionProposalCollector) {
+ TypeBinding firstParameterType = null;
+ ASTNode node = getAssistNode(completionProposalCollector);
+ if (node == null) return null;
+ if (!(node instanceof CompletionOnQualifiedNameReference) && !(node instanceof CompletionOnSingleNameReference) && !(node instanceof CompletionOnMemberAccess)) return null;
+
+ if (node instanceof NameReference) {
+ Binding binding = ((NameReference) node).binding;
+ if ((node instanceof SingleNameReference) && (((SingleNameReference) node).token.length == 0)) {
+ firstParameterType = decl.binding;
+ } else if (binding instanceof VariableBinding) {
+ firstParameterType = ((VariableBinding) binding).type;
+ } else if (binding instanceof TypeBinding) {
+ firstParameterType = (TypeBinding) binding;
+ }
+ } else if (node instanceof FieldReference) {
+ firstParameterType = ((FieldReference) node).actualReceiverType;
+ }
+ return firstParameterType;
+ }
+
+ private static ASTNode getAssistNode(CompletionProposalCollector completionProposalCollector) {
+ try {
+ InternalCompletionContext context = (InternalCompletionContext) Reflection.contextField.get(completionProposalCollector);
+ InternalExtendedCompletionContext extendedContext = (InternalExtendedCompletionContext) Reflection.extendedContextField.get(context);
+ if (extendedContext == null) return null;
+ return (ASTNode) Reflection.assistNodeField.get(extendedContext);
+ } catch (Exception ignore) {
+ return null;
+ }
+ }
+
+ private static ClassScope getClassScope(CompletionProposalCollector completionProposalCollector) {
+ ClassScope scope = null;
+ try {
+ InternalCompletionContext context = (InternalCompletionContext) Reflection.contextField.get(completionProposalCollector);
+ InternalExtendedCompletionContext extendedContext = (InternalExtendedCompletionContext) Reflection.extendedContextField.get(context);
+ if (extendedContext != null) {
+ Scope assistScope = ((Scope) Reflection.assistScopeField.get(extendedContext));
+ if (assistScope != null) {
+ scope = assistScope.classScope();
+ }
+ }
+ } catch (IllegalAccessException ignore) {
+ // ignore
+ }
+ return scope;
+ }
+
private static void copyNameLookupAndCompletionEngine(CompletionProposalCollector completionProposalCollector, IJavaCompletionProposal proposal,
InternalCompletionProposal newProposal) {
@@ -97,4 +181,55 @@ public class PatchExtensionMethodCompletionProposal {
return 0;
}
}
+
+ static class Reflection {
+ public static final Field replacementOffsetField;
+ public static final Field contextField;
+ public static final Field extendedContextField;
+ public static final Field assistNodeField;
+ public static final Field assistScopeField;
+ public static final Field lookupEnvironmentField;
+ public static final Field completionEngineField;
+ public static final Field nameLookupField;
+ public static final Method createJavaCompletionProposalMethod;
+
+ static {
+ replacementOffsetField = accessField(AbstractJavaCompletionProposal.class, "fReplacementOffset");
+ contextField = accessField(CompletionProposalCollector.class, "fContext");
+ extendedContextField = accessField(InternalCompletionContext.class, "extendedContext");
+ assistNodeField = accessField(InternalExtendedCompletionContext.class, "assistNode");
+ assistScopeField = accessField(InternalExtendedCompletionContext.class, "assistScope");
+ lookupEnvironmentField = accessField(InternalExtendedCompletionContext.class, "lookupEnvironment");
+ completionEngineField = accessField(InternalCompletionProposal.class, "completionEngine");
+ nameLookupField = accessField(InternalCompletionProposal.class, "nameLookup");
+ createJavaCompletionProposalMethod = accessMethod(CompletionProposalCollector.class, "createJavaCompletionProposal", CompletionProposal.class);
+ }
+
+ static boolean isComplete() {
+ Object[] requiredFieldsAndMethods = { replacementOffsetField, contextField, extendedContextField, assistNodeField, assistScopeField, lookupEnvironmentField, completionEngineField, nameLookupField, createJavaCompletionProposalMethod };
+ for (Object o : requiredFieldsAndMethods) if (o == null) return false;
+ return true;
+ }
+
+ private static Field accessField(Class<?> clazz, String fieldName) {
+ try {
+ return makeAccessible(clazz.getDeclaredField(fieldName));
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static Method accessMethod(Class<?> clazz, String methodName, Class<?> parameter) {
+ try {
+ return makeAccessible(clazz.getDeclaredMethod(methodName, parameter));
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static <T extends AccessibleObject> T makeAccessible(T object) {
+ object.setAccessible(true);
+ return object;
+ }
+ }
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java
index 29aedc81..6dca1901 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposalPortal.java
@@ -24,10 +24,10 @@ package lombok.eclipse.agent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
-
import lombok.Lombok;
+import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
+
public class PatchExtensionMethodCompletionProposalPortal {
private static final String COMPLETION_PROPOSAL_COLLECTOR = "org.eclipse.jdt.ui.text.java.CompletionProposalCollector";
@@ -44,10 +44,15 @@ public class PatchExtensionMethodCompletionProposalPortal {
} catch (IllegalAccessException e) {
throw Lombok.sneakyThrow(e);
} catch (InvocationTargetException e) {
- throw Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e.getCause());
} catch (NullPointerException e) {
- e.initCause(ReflectionForUi.problem);
- throw e;
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(ReflectionForUi.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return (IJavaCompletionProposal[])javaCompletionProposals;
}
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodPortal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodPortal.java
new file mode 100644
index 00000000..02e4e123
--- /dev/null
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodPortal.java
@@ -0,0 +1,103 @@
+package lombok.eclipse.agent;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import lombok.Lombok;
+
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+
+public class PatchExtensionMethodPortal {
+ private static final String TYPE_BINDING = "org.eclipse.jdt.internal.compiler.lookup.TypeBinding";
+ private static final String TYPE_BINDING_ARRAY = "[Lorg.eclipse.jdt.internal.compiler.lookup.TypeBinding;";
+ private static final String MESSAGE_SEND = "org.eclipse.jdt.internal.compiler.ast.MessageSend";
+ private static final String BLOCK_SCOPE = "org.eclipse.jdt.internal.compiler.lookup.BlockScope";
+ private static final String METHOD_BINDING = "org.eclipse.jdt.internal.compiler.lookup.MethodBinding";
+ private static final String PROBLEM_REPORTER = "org.eclipse.jdt.internal.compiler.problem.ProblemReporter";
+
+ public static TypeBinding resolveType(Object resolvedType, Object methodCall, Object scope) {
+ try {
+ return (TypeBinding) Reflection.resolveType.invoke(null, resolvedType, methodCall, scope);
+ } catch (NoClassDefFoundError e) {
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return (TypeBinding) resolvedType;
+ } catch (IllegalAccessException e) {
+ throw Lombok.sneakyThrow(e);
+ } catch (InvocationTargetException e) {
+ throw Lombok.sneakyThrow(e);
+ } catch (NullPointerException e) {
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ return (TypeBinding)resolvedType;
+ }
+ }
+
+ public static void errorNoMethodFor(Object problemReporter, Object messageSend, Object recType, Object params) {
+ try {
+ Reflection.errorNoMethodFor.invoke(null, problemReporter, messageSend, recType, params);
+ } catch (NoClassDefFoundError e) {
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ } catch (IllegalAccessException e) {
+ throw Lombok.sneakyThrow(e);
+ } catch (InvocationTargetException e) {
+ throw Lombok.sneakyThrow(e.getCause());
+ } catch (NullPointerException e) {
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ }
+ }
+
+ public static void invalidMethod(Object problemReporter, Object messageSend, Object method) {
+ try {
+ Reflection.invalidMethod.invoke(null, problemReporter, messageSend, method);
+ } catch (NoClassDefFoundError e) {
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ } catch (IllegalAccessException e) {
+ Lombok.sneakyThrow(e);
+ } catch (InvocationTargetException e) {
+ throw Lombok.sneakyThrow(e.getCause());
+ } catch (NullPointerException e) {
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
+ }
+ }
+
+ private static final class Reflection {
+ public static final Method resolveType, errorNoMethodFor, invalidMethod;
+ public static final Throwable problem;
+
+ static {
+ Method m = null, n = null, o = null;
+ Throwable problem_ = null;
+ try {
+ m = PatchExtensionMethod.class.getMethod("resolveType", Class.forName(TYPE_BINDING), Class.forName(MESSAGE_SEND), Class.forName(BLOCK_SCOPE));
+ n = PatchExtensionMethod.class.getMethod("errorNoMethodFor", Class.forName(PROBLEM_REPORTER),
+ Class.forName(MESSAGE_SEND), Class.forName(TYPE_BINDING), Class.forName(TYPE_BINDING_ARRAY));
+ o = PatchExtensionMethod.class.getMethod("invalidMethod", Class.forName(PROBLEM_REPORTER), Class.forName(MESSAGE_SEND), Class.forName(METHOD_BINDING));
+ } catch (Throwable t) {
+ // That's problematic, but as long as no local classes are used we don't actually need it.
+ // Better fail on local classes than crash altogether.
+ problem_ = t;
+ }
+ resolveType = m;
+ errorNoMethodFor = n;
+ invalidMethod = o;
+ problem = problem_;
+ }
+ }
+}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipsePortal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipsePortal.java
index dacd81b4..5342ecab 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipsePortal.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipsePortal.java
@@ -40,12 +40,16 @@ public class PatchValEclipsePortal {
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
//do anything useful here.
} catch (IllegalAccessException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e);
} catch (InvocationTargetException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e.getCause());
} catch (NullPointerException e) {
- e.initCause(Reflection.problem);
- throw e;
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
}
}
@@ -56,12 +60,16 @@ public class PatchValEclipsePortal {
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
//do anything useful here.
} catch (IllegalAccessException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e);
} catch (InvocationTargetException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e.getCause());
} catch (NullPointerException e) {
- e.initCause(Reflection.problem);
- throw e;
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
}
}
@@ -72,12 +80,16 @@ public class PatchValEclipsePortal {
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
//do anything useful here.
} catch (IllegalAccessException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e);
} catch (InvocationTargetException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e.getCause());
} catch (NullPointerException e) {
- e.initCause(Reflection.problem);
- throw e;
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
}
}
@@ -88,12 +100,16 @@ public class PatchValEclipsePortal {
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
//do anything useful here.
} catch (IllegalAccessException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e);
} catch (InvocationTargetException e) {
- Lombok.sneakyThrow(e);
+ throw Lombok.sneakyThrow(e.getCause());
} catch (NullPointerException e) {
- e.initCause(Reflection.problem);
- throw e;
+ if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) {
+ e.initCause(Reflection.problem);
+ throw e;
+ }
+ //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
+ //do anything useful here.
}
}