org.eclipse.recommenders.utils.rcp.CompilerBindings.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.recommenders.utils.rcp.CompilerBindings.java

Source

/**
 * Copyright (c) 2010 Darmstadt University of Technology.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Marcel Bruch - initial API and implementation.
 */
package org.eclipse.recommenders.utils.rcp;

import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.fromNullable;
import static com.google.common.base.Optional.of;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.corext.template.java.SignatureUtil;
import org.eclipse.recommenders.utils.annotations.Nullable;
import org.eclipse.recommenders.utils.names.IMethodName;
import org.eclipse.recommenders.utils.names.ITypeName;
import org.eclipse.recommenders.utils.names.VmMethodName;
import org.eclipse.recommenders.utils.names.VmTypeName;

import com.google.common.base.Optional;

@SuppressWarnings("restriction")
public class CompilerBindings {

    public static Optional<ITypeName> toTypeName(@Nullable Binding b) {
        if (b instanceof TypeBinding) {
            return toTypeName((TypeBinding) b);
        } else if (b instanceof VariableBinding) {
            TypeBinding type = ((VariableBinding) b).type;
            return toTypeName(type);
        } else
            return absent();
    }

    /**
     * TODO nested anonymous types are not resolved correctly. JDT uses line numbers for inner types instead of $1,..,$n
     */
    public static Optional<ITypeName> toTypeName(@Nullable TypeBinding binding) {
        // XXX generics fail
        if (binding == null) {
            return absent();
        }
        //
        final boolean boundParameterizedType = binding.isBoundParameterizedType();
        final boolean parameterizedType = binding.isParameterizedType();

        // if (binding.isBoundParameterizedType()) {
        // return null;
        // }

        if (binding.isArrayType()) {
            final int dimensions = binding.dimensions();
            final TypeBinding leafComponentType = binding.leafComponentType();
            final String arrayDimensions = StringUtils.repeat("[", dimensions);
            final Optional<ITypeName> typeName = toTypeName(leafComponentType);
            if (!typeName.isPresent()) {
                return absent();
            }
            final ITypeName res = VmTypeName.get(arrayDimensions + typeName.get().getIdentifier());
            return fromNullable(res);
        }
        // TODO: handling of generics is bogus!
        if (binding instanceof TypeVariableBinding) {
            final TypeVariableBinding generic = (TypeVariableBinding) binding;
            if (generic.declaringElement instanceof TypeBinding) {
                // XXX: for this?
                binding = (TypeBinding) generic.declaringElement;
            } else if (generic.superclass != null) {
                // example Tuple<T1 extends List, T2 extends Number) --> for
                // generic.superclass (T2)=Number
                // we replace the generic by its superclass
                binding = generic.superclass;
            }
        }

        String signature = String.valueOf(binding.genericTypeSignature());
        // if (binding instanceof BinaryTypeBinding) {
        // signature = StringUtils.substringBeforeLast(signature, ";");
        // }

        if (signature.length() == 1) {
            // no handling needed. primitives always look the same.
        } else if (signature.endsWith(";")) {
            signature = StringUtils.substringBeforeLast(signature, ";");
        } else {
            signature = "L" + SignatureUtil.stripSignatureToFQN(signature);
        }
        final ITypeName res = VmTypeName.get(signature);
        return fromNullable(res);
    }

    public static Optional<IMethodName> toMethodName(@Nullable final MethodBinding binding) {
        if (binding == null) {
            return absent();
        }
        try {
            final String uniqueKey = String.valueOf(binding.computeUniqueKey());
            String qualifiedMethodName = StringUtils.substringBefore(uniqueKey, "(").replace(";.", ".");
            if (qualifiedMethodName.endsWith("."))
                qualifiedMethodName += new String(TypeConstants.INIT);
            final String[] parameterTypes = Signature.getParameterTypes(uniqueKey);
            final String returnType = Signature.getReturnType(uniqueKey);
            final StringBuilder sb = new StringBuilder();
            sb.append(qualifiedMethodName).append("(");
            for (final String parameter : parameterTypes) {
                sb.append(parameter);
            }
            sb.append(")").append(returnType);
            final IMethodName res = VmMethodName.get(sb.toString());
            return of(res);
        } catch (final RuntimeException e) {
            // if the signature could not be parsed by JDT (because it is incomplete!):
            return absent();
        }
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }

    public static Optional<ITypeName> toTypeName(final TypeReference type) {
        return (Optional<ITypeName>) (type == null ? Optional.absent() : toTypeName(type.resolvedType));
    }

    public static Optional<Binding> getBinding(final ASTNode node) {
        Binding b = null;
        if (node instanceof FieldDeclaration) {
            final FieldDeclaration f = (FieldDeclaration) node;
            b = f.binding;
        } else if (node instanceof MethodDeclaration) {
            final MethodDeclaration d = (MethodDeclaration) node;
            b = d.binding;
        } else if (node instanceof LocalDeclaration) {
            final LocalDeclaration l = (LocalDeclaration) node;
            b = l.binding;
        } else if (node instanceof TypeParameter) {
            final TypeParameter t = (TypeParameter) node;
            b = t.binding;
        }
        return fromNullable(b);
    }

    public static Optional<String> getVariableName(final Binding node) {
        if (node == null) {
            return absent();
        }
        switch (node.kind()) {
        case Binding.FIELD:
        case Binding.LOCAL:
            return of(String.valueOf(node.shortReadableName()));
        }
        return absent();
    }
}