/* * Copyright © 2011-2012 Philipp Eichhorn * * 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.handlers.ast; import static lombok.core.util.Arrays.*; import static org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.*; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import lombok.eclipse.EclipseNode; import lombok.eclipse.handlers.Eclipse; import lombok.eclipse.handlers.EclipseHandlerUtil; public final class EclipseTypeEditor implements lombok.ast.ITypeEditor<EclipseMethod, ASTNode, TypeDeclaration, AbstractMethodDeclaration> { private final EclipseType type; private final EclipseASTMaker builder; EclipseTypeEditor(final EclipseType type, final ASTNode source) { this.type = type; builder = new EclipseASTMaker(type.node(), source); } public TypeDeclaration get() { return type.get(); } public EclipseNode node() { return type.node(); } public <T extends ASTNode> T build(final lombok.ast.Node<?> node) { return builder.<T> build(node); } public <T extends ASTNode> T build(final lombok.ast.Node<?> node, final Class<T> extectedType) { return builder.build(node, extectedType); } public <T extends ASTNode> List<T> build(final List<? extends lombok.ast.Node<?>> nodes) { return builder.build(nodes); } public <T extends ASTNode> List<T> build(final List<? extends lombok.ast.Node<?>> nodes, final Class<T> extectedType) { return builder.build(nodes, extectedType); } public void injectInitializer(final lombok.ast.Initializer initializer) { final Initializer initializerBlock = builder.build(initializer); Eclipse.injectInitializer(node(), initializerBlock); } public void injectField(final lombok.ast.FieldDecl fieldDecl) { final FieldDeclaration field = builder.build(fieldDecl); EclipseHandlerUtil.injectField(node(), field); } public void injectField(final lombok.ast.EnumConstant enumConstant) { final FieldDeclaration field = builder.build(enumConstant); EclipseHandlerUtil.injectField(node(), field); } public AbstractMethodDeclaration injectMethod(final lombok.ast.MethodDecl methodDecl) { return (MethodDeclaration) injectMethodImpl(methodDecl); } public AbstractMethodDeclaration injectConstructor(final lombok.ast.ConstructorDecl constructorDecl) { return (ConstructorDeclaration) injectMethodImpl(constructorDecl); } private AbstractMethodDeclaration injectMethodImpl(final lombok.ast.AbstractMethodDecl<?> methodDecl) { final AbstractMethodDeclaration method = builder.build(methodDecl, MethodDeclaration.class); EclipseHandlerUtil.injectMethod(node(), method); TypeDeclaration type = get(); if (type.scope != null && method.scope == null) { boolean aboutToBeResolved = false; for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { if ("org.eclipse.jdt.internal.compiler.lookup.ClassScope".equals(elem.getClassName()) && "buildFieldsAndMethods".equals(elem.getMethodName())) { aboutToBeResolved = true; break; } } if (!aboutToBeResolved) { MethodScope scope = new MethodScope(type.scope, method, methodDecl.getModifiers().contains(lombok.ast.Modifier.STATIC)); MethodBinding methodBinding = null; try { methodBinding = (MethodBinding) Reflection.methodScopeCreateMethodMethod.invoke(scope, method); } catch (final Exception e) { // See 'Reflection' class for why we ignore this exception. } if (methodBinding != null) { SourceTypeBinding sourceType = type.scope.referenceContext.binding; MethodBinding[] methods = sourceType.methods(); methods = resize(methods, methods.length + 1); methods[methods.length - 1] = methodBinding; sourceType.setMethods(methods); sourceType.resolveTypesFor(methodBinding); } } } return method; } public void injectType(final lombok.ast.ClassDecl typeDecl) { final TypeDeclaration type = builder.build(typeDecl); Eclipse.injectType(node(), type); } public void removeMethod(final EclipseMethod method) { TypeDeclaration type = get(); List<AbstractMethodDeclaration> methods = new ArrayList<AbstractMethodDeclaration>(); for (AbstractMethodDeclaration decl : type.methods) { if (!decl.equals(method.get())) { methods.add(decl); } } type.methods = methods.toArray(new AbstractMethodDeclaration[0]); node().removeChild(method.node()); } public void makeEnum() { get().modifiers |= AccEnum; } public void makePrivate() { makePackagePrivate(); get().modifiers |= AccPrivate; } public void makePackagePrivate() { get().modifiers &= ~(AccPrivate | AccProtected | AccPublic); } public void makeProtected() { makePackagePrivate(); get().modifiers |= AccProtected; } public void makePublic() { makePackagePrivate(); get().modifiers |= AccPublic; } public void makeStatic() { get().modifiers |= AccStatic; } public void rebuild() { node().rebuild(); } @Override public String toString() { return get().toString(); } private static final class Reflection { public static final Method methodScopeCreateMethodMethod; static { Method m = null; try { m = MethodScope.class.getDeclaredMethod("createMethod", AbstractMethodDeclaration.class); m.setAccessible(true); } catch (final Exception e) { // well can't do anything about it then } methodScopeCreateMethodMethod = m; } } }