use of org.eclipse.jdt.internal.compiler.ast.MethodDeclaration in project lombok by rzwitserloot.
the class EclipseHandlerUtil method findGetter.
private static GetterMethod findGetter(EclipseNode field) {
FieldDeclaration fieldDeclaration = (FieldDeclaration) field.get();
boolean forceBool = FieldDeclaration_booleanLazyGetter.get(fieldDeclaration);
TypeReference fieldType = fieldDeclaration.type;
boolean isBoolean = forceBool || isBoolean(fieldType);
EclipseNode typeNode = field.up();
for (String potentialGetterName : toAllGetterNames(field, isBoolean)) {
for (EclipseNode potentialGetter : typeNode.down()) {
if (potentialGetter.getKind() != Kind.METHOD)
continue;
if (!(potentialGetter.get() instanceof MethodDeclaration))
continue;
MethodDeclaration method = (MethodDeclaration) potentialGetter.get();
if (!potentialGetterName.equalsIgnoreCase(new String(method.selector)))
continue;
/** static getX() methods don't count. */
if ((method.modifiers & ClassFileConstants.AccStatic) != 0)
continue;
/** Nor do getters with a non-empty parameter list. */
if (method.arguments != null && method.arguments.length > 0)
continue;
return new GetterMethod(method.selector, method.returnType);
}
}
// Check if the field has a @Getter annotation.
boolean hasGetterAnnotation = false;
for (EclipseNode child : field.down()) {
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
AnnotationValues<Getter> ann = createAnnotation(Getter.class, child);
//Definitely WONT have a getter.
if (ann.getInstance().value() == AccessLevel.NONE)
return null;
hasGetterAnnotation = true;
}
}
if (!hasGetterAnnotation && new HandleGetter().fieldQualifiesForGetterGeneration(field)) {
//Check if the class has @Getter or @Data annotation.
EclipseNode containingType = field.up();
if (containingType != null)
for (EclipseNode child : containingType.down()) {
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Data.class, child))
hasGetterAnnotation = true;
if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
AnnotationValues<Getter> ann = createAnnotation(Getter.class, child);
//Definitely WONT have a getter.
if (ann.getInstance().value() == AccessLevel.NONE)
return null;
hasGetterAnnotation = true;
}
}
}
if (hasGetterAnnotation) {
String getterName = toGetterName(field, isBoolean);
if (getterName == null)
return null;
return new GetterMethod(getterName.toCharArray(), fieldType);
}
return null;
}
use of org.eclipse.jdt.internal.compiler.ast.MethodDeclaration in project lombok by rzwitserloot.
the class PatchDelegate method createDelegateMethod.
private static MethodDeclaration createDelegateMethod(char[] name, EclipseNode typeNode, BindingTuple pair, CompilationResult compilationResult, EclipseNode annNode, DelegateReceiver delegateReceiver) {
/* public <T, U, ...> ReturnType methodName(ParamType1 name1, ParamType2 name2, ...) throws T1, T2, ... {
* (return) delegate.<T, U>methodName(name1, name2);
* }
*/
boolean isVarargs = (pair.base.modifiers & ClassFileConstants.AccVarargs) != 0;
try {
checkConflictOfTypeVarNames(pair, typeNode);
} catch (CantMakeDelegates e) {
annNode.addError("There's a conflict in the names of type parameters. Fix it by renaming the following type parameters of your class: " + e.conflicted);
return null;
}
ASTNode source = annNode.get();
int pS = source.sourceStart, pE = source.sourceEnd;
MethodBinding binding = pair.parameterized;
MethodDeclaration method = new MethodDeclaration(compilationResult);
setGeneratedBy(method, source);
method.sourceStart = pS;
method.sourceEnd = pE;
method.modifiers = ClassFileConstants.AccPublic;
method.returnType = makeType(binding.returnType, source, false);
boolean isDeprecated = binding.isDeprecated();
method.selector = binding.selector;
if (binding.thrownExceptions != null && binding.thrownExceptions.length > 0) {
method.thrownExceptions = new TypeReference[binding.thrownExceptions.length];
for (int i = 0; i < method.thrownExceptions.length; i++) {
method.thrownExceptions[i] = makeType(binding.thrownExceptions[i], source, false);
}
}
MessageSend call = new MessageSend();
call.sourceStart = pS;
call.sourceEnd = pE;
call.nameSourcePosition = pos(source);
setGeneratedBy(call, source);
call.receiver = delegateReceiver.get(source, name);
call.selector = binding.selector;
if (binding.typeVariables != null && binding.typeVariables.length > 0) {
method.typeParameters = new TypeParameter[binding.typeVariables.length];
call.typeArguments = new TypeReference[binding.typeVariables.length];
for (int i = 0; i < method.typeParameters.length; i++) {
method.typeParameters[i] = new TypeParameter();
method.typeParameters[i].sourceStart = pS;
method.typeParameters[i].sourceEnd = pE;
setGeneratedBy(method.typeParameters[i], source);
method.typeParameters[i].name = binding.typeVariables[i].sourceName;
call.typeArguments[i] = new SingleTypeReference(binding.typeVariables[i].sourceName, pos(source));
setGeneratedBy(call.typeArguments[i], source);
ReferenceBinding super1 = binding.typeVariables[i].superclass;
ReferenceBinding[] super2 = binding.typeVariables[i].superInterfaces;
if (super2 == null)
super2 = new ReferenceBinding[0];
if (super1 != null || super2.length > 0) {
int offset = super1 == null ? 0 : 1;
method.typeParameters[i].bounds = new TypeReference[super2.length + offset - 1];
if (super1 != null)
method.typeParameters[i].type = makeType(super1, source, false);
else
method.typeParameters[i].type = makeType(super2[0], source, false);
int ctr = 0;
for (int j = (super1 == null) ? 1 : 0; j < super2.length; j++) {
method.typeParameters[i].bounds[ctr] = makeType(super2[j], source, false);
method.typeParameters[i].bounds[ctr++].bits |= ASTNode.IsSuperType;
}
}
}
}
if (isDeprecated) {
method.annotations = new Annotation[] { generateDeprecatedAnnotation(source) };
}
method.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
if (binding.parameters != null && binding.parameters.length > 0) {
method.arguments = new Argument[binding.parameters.length];
call.arguments = new Expression[method.arguments.length];
for (int i = 0; i < method.arguments.length; i++) {
AbstractMethodDeclaration sourceElem;
try {
sourceElem = pair.base.sourceMethod();
} catch (Exception e) {
sourceElem = null;
}
char[] argName;
if (sourceElem == null)
argName = ("arg" + i).toCharArray();
else {
argName = sourceElem.arguments[i].name;
}
method.arguments[i] = new Argument(argName, pos(source), makeType(binding.parameters[i], source, false), ClassFileConstants.AccFinal);
setGeneratedBy(method.arguments[i], source);
call.arguments[i] = new SingleNameReference(argName, pos(source));
setGeneratedBy(call.arguments[i], source);
}
if (isVarargs) {
method.arguments[method.arguments.length - 1].type.bits |= ASTNode.IsVarArgs;
}
}
Statement body;
if (method.returnType instanceof SingleTypeReference && ((SingleTypeReference) method.returnType).token == TypeConstants.VOID) {
body = call;
} else {
body = new ReturnStatement(call, source.sourceStart, source.sourceEnd);
setGeneratedBy(body, source);
}
method.statements = new Statement[] { body };
return method;
}
use of org.eclipse.jdt.internal.compiler.ast.MethodDeclaration in project lombok by rzwitserloot.
the class PatchDelegate method generateDelegateMethods.
/*
* We may someday finish this method. Steps to be completed:
*
* (A) Turn any Parameterized anythings into non-parameterized versions. Resolving parameterized stuff will definitely not work safely.
* (B) scope.problemReporter() will need to return a noop reporter as various errors are marked off.
* (C) Find a way to do _something_ for references to typevars (i.e. 'T') which are declared on the method itself.
* (D) getTypeBinding isn't public, so call it via reflection.
*/
// private static TypeBinding safeResolveAndErase(TypeReference ref, Scope scope) {
// if (ref.resolvedType != null) {
// return ref.resolvedType.isValidBinding() ? ref.resolvedType : null;
// }
//
// try {
// TypeBinding bind = ref.getTypeBinding(scope);
// if (!bind.isValidBinding()) return null;
// } catch (AbortCompilation e) {
// return null;
// }
// return bind.erasure();
// }
/*
* Not using this because calling clone.resolveType() taints a bunch of caches and reports erroneous errors.
*/
// private static void removeExistingMethods(List<BindingTuple> list, TypeDeclaration decl, ClassScope scope) {
// for (AbstractMethodDeclaration methodDecl : decl.methods) {
// if (!(methodDecl instanceof MethodDeclaration)) continue;
// MethodDeclaration md = (MethodDeclaration) methodDecl;
// char[] name = md.selector;
// TypeBinding[] args = md.arguments == null ? new TypeBinding[0] : new TypeBinding[md.arguments.length];
// for (int i = 0; i < args.length; i++) {
// TypeReference clone = Eclipse.copyType(md.arguments[i].type, md.arguments[i]);
// args[i] = clone.resolveType(scope).erasure(); // This is the problematic line
// }
// Iterator<BindingTuple> it = list.iterator();
// methods:
// while (it.hasNext()) {
// MethodBinding mb = it.next().parameterized;
// if (!Arrays.equals(mb.selector, name)) continue;
// int paramLen = mb.parameters == null ? 0 : mb.parameters.length;
// if (paramLen != args.length) continue;
// if (md.typeParameters == null || md.typeParameters.length == 0) {
// for (int i = 0; i < paramLen; i++) {
// if (!mb.parameters[i].erasure().isEquivalentTo(args[i])) continue methods;
// }
// } else {
// for (int i = 0; i < paramLen; i++) {
// if (!mb.parameters[i].erasure().isEquivalentTo(args[i])) ;
// }
// //BUG #???: We erase the method's parameter types using the class scope, but we should be using the method scope.
// // In practice this is no problem UNLESS the method has type parameters, such as <T> T[] toArray(T[] in).
// // In this case the class scope cannot resolve the T[] parameter and erase it to Object[], which is a big problem because
// // it would mean manually writing <X> X[] toArray(X[] in) does NOT stop lombok from ALSO trying to make the delegated toArray method,
// // thus causing an error (2 methods with post-erasure duplicate signatures). Our 'fix' for this is to treat any method with type parameters
// // as if each parameter's type matches anything else; so, if the name matches and the parameter count, we DONT generate it, even if its just
// // an overloaded method.
// //
// // The reason we do this now is because making that MethodScope properly is effectively impossible at this step, so we need to do the resolving
// // ourselves, which involves chasing down array bindings (T[]), following the path down type variables, i.e. <X extends Y, Y extends T>, and then
// // resolving the final result of this exercise against the class scope.
//
// // When this crappy incomplete workaround of ours occurs, we end up in this else block, which does nothing and thus we fall through and remove
// // the method.
// }
// it.remove(); // Method already exists in this class - don't create a delegating implementation.
// }
// }
// }
private static void generateDelegateMethods(EclipseNode typeNode, List<BindingTuple> methods, DelegateReceiver delegateReceiver) {
CompilationUnitDeclaration top = (CompilationUnitDeclaration) typeNode.top().get();
for (BindingTuple pair : methods) {
EclipseNode annNode = typeNode.getAst().get(pair.responsible);
MethodDeclaration method = createDelegateMethod(pair.fieldName, typeNode, pair, top.compilationResult, annNode, delegateReceiver);
if (method != null) {
SetGeneratedByVisitor visitor = new SetGeneratedByVisitor(annNode.get());
method.traverse(visitor, ((TypeDeclaration) typeNode.get()).scope);
injectMethod(typeNode, method);
}
}
}
use of org.eclipse.jdt.internal.compiler.ast.MethodDeclaration in project lombok by rzwitserloot.
the class PatchDelegate method fillMethodBindingsForMethods.
private static void fillMethodBindingsForMethods(CompilationUnitDeclaration cud, ClassScope scope, List<BindingTuple> methodsToDelegate) {
TypeDeclaration decl = scope.referenceContext;
if (decl == null)
return;
if (decl.methods != null)
for (AbstractMethodDeclaration methodDecl : decl.methods) {
if (methodDecl.annotations == null)
continue;
for (Annotation ann : methodDecl.annotations) {
if (!isDelegate(ann, decl))
continue;
if (Annotation_applied.getAndSet(ann, true))
continue;
if (!(methodDecl instanceof MethodDeclaration)) {
EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
break;
}
if (methodDecl.arguments != null) {
EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
break;
}
if ((methodDecl.modifiers & ClassFileConstants.AccStatic) != 0) {
EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
break;
}
MethodDeclaration method = (MethodDeclaration) methodDecl;
List<ClassLiteralAccess> rawTypes = rawTypes(ann, "types");
List<ClassLiteralAccess> excludedRawTypes = rawTypes(ann, "excludes");
List<BindingTuple> methodsToExclude = new ArrayList<BindingTuple>();
List<BindingTuple> methodsToDelegateForThisAnn = new ArrayList<BindingTuple>();
try {
for (ClassLiteralAccess cla : excludedRawTypes) {
addAllMethodBindings(methodsToExclude, cla.type.resolveType(decl.initializerScope), new HashSet<String>(), method.selector, ann);
}
Set<String> banList = new HashSet<String>();
for (BindingTuple excluded : methodsToExclude) banList.add(printSig(excluded.parameterized));
if (rawTypes.isEmpty()) {
if (method.returnType == null)
continue;
addAllMethodBindings(methodsToDelegateForThisAnn, method.returnType.resolveType(decl.initializerScope), banList, method.selector, ann);
} else {
for (ClassLiteralAccess cla : rawTypes) {
addAllMethodBindings(methodsToDelegateForThisAnn, cla.type.resolveType(decl.initializerScope), banList, method.selector, ann);
}
}
} catch (DelegateRecursion e) {
EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
eclipseAst.get(ann).addError(String.format(RECURSION_NOT_ALLOWED, new String(e.member), new String(e.type)));
break;
}
// Not doing this right now because of problems - see commented-out-method for info.
// removeExistingMethods(methodsToDelegate, decl, scope);
String dupe = containsDuplicates(methodsToDelegateForThisAnn);
if (dupe != null) {
EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
eclipseAst.get(ann).addError("The method '" + dupe + "' is being delegated by more than one specified type.");
} else {
methodsToDelegate.addAll(methodsToDelegateForThisAnn);
}
}
}
}
use of org.eclipse.jdt.internal.compiler.ast.MethodDeclaration in project lombok by rzwitserloot.
the class HandleSynchronized method preHandle.
@Override
public void preHandle(AnnotationValues<Synchronized> annotation, Annotation source, EclipseNode annotationNode) {
EclipseNode methodNode = annotationNode.up();
if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof MethodDeclaration))
return;
MethodDeclaration method = (MethodDeclaration) methodNode.get();
if (method.isAbstract())
return;
createLockField(annotation, annotationNode, method.isStatic(), false);
}
Aggregations