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.
This commit is contained in:
Robbert Jan Grootjans committed 2012-06-18 23:59:05 +02:00
1 parent 2af094030f
commit 3ed67fc8ae
8 files changed
+391 -199

No files matched your search

+41 -41
View File
@@ -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_;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
@@ -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_;
}
}
}
@@ -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.
}
}