Package com.strobel.assembler.metadata

Source Code of com.strobel.assembler.metadata.MethodDefinition

/*
* MethodDefinition.java
*
* Copyright (c) 2013 Mike Strobel
*
* This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain;
* and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/

package com.strobel.assembler.metadata;

import com.strobel.assembler.Collection;
import com.strobel.assembler.ir.ConstantPool;
import com.strobel.assembler.ir.attributes.AttributeNames;
import com.strobel.assembler.ir.attributes.CodeAttribute;
import com.strobel.assembler.ir.attributes.ExceptionTableEntry;
import com.strobel.assembler.ir.attributes.SourceAttribute;
import com.strobel.assembler.metadata.annotations.CustomAnnotation;

import java.util.Collections;
import java.util.List;

public class MethodDefinition extends MethodReference implements IMemberDefinition {
    private final GenericParameterCollection _genericParameters;
    private final ParameterDefinitionCollection _parameters;
    private final AnonymousLocalTypeCollection _declaredTypes;
    private final Collection<TypeReference> _thrownTypes;
    private final Collection<CustomAnnotation> _customAnnotations;
    private final Collection<SourceAttribute> _sourceAttributes;
    private final List<GenericParameter> _genericParametersView;
    private final List<TypeDefinition> _declaredTypesView;
    private final List<ParameterDefinition> _parametersView;
    private final List<TypeReference> _thrownTypesView;
    private final List<CustomAnnotation> _customAnnotationsView;
    private final List<SourceAttribute> _sourceAttributesView;

    private MethodBody _body;
    private String _name;
    private String _fullName;
    private String _erasedSignature;
    private String _signature;
    private TypeReference _returnType;
    private TypeDefinition _declaringType;
    private long _flags;

    protected MethodDefinition() {
        _genericParameters = new GenericParameterCollection(this);
        _parameters = new ParameterDefinitionCollection(this);
        _declaredTypes = new AnonymousLocalTypeCollection(this);
        _thrownTypes = new Collection<>();
        _customAnnotations = new Collection<>();
        _sourceAttributes = new Collection<>();
        _genericParametersView = Collections.unmodifiableList(_genericParameters);
        _parametersView = Collections.unmodifiableList(_parameters);
        _declaredTypesView = Collections.unmodifiableList(_declaredTypes);
        _thrownTypesView = Collections.unmodifiableList(_thrownTypes);
        _customAnnotationsView = Collections.unmodifiableList(_customAnnotations);
        _sourceAttributesView = Collections.unmodifiableList(_sourceAttributes);
    }

    public final boolean hasBody() {
        return _body != null;
    }

    public final MethodBody getBody() {
        if (_body == null) {
            try {
                tryLoadBody();
            }
            catch (Throwable t) {
                setFlags(getFlags() | Flags.LOAD_BODY_FAILED);
            }
        }
        return _body;
    }

    public final boolean hasThis() {
        return !isStatic();
    }

    protected final void setBody(final MethodBody body) {
        _body = body;
    }

    @Override
    public final boolean isDefinition() {
        return true;
    }

    public final boolean isAnonymousClassConstructor() {
        return Flags.testAny(_flags, Flags.ANONCONSTR);
    }

    public final List<TypeDefinition> getDeclaredTypes() {
        return _declaredTypesView;
    }

    protected final AnonymousLocalTypeCollection getDeclaredTypesInternal() {
        return _declaredTypes;
    }

    @Override
    public final List<GenericParameter> getGenericParameters() {
        return _genericParametersView;
    }

    @Override
    public final List<TypeReference> getThrownTypes() {
        return _thrownTypesView;
    }

    @Override
    public final TypeDefinition getDeclaringType() {
        return _declaringType;
    }

    @Override
    public final List<CustomAnnotation> getAnnotations() {
        return _customAnnotationsView;
    }

    public final List<SourceAttribute> getSourceAttributes() {
        return _sourceAttributesView;
    }

    @Override
    public final String getName() {
        return _name;
    }

    @Override
    public String getFullName() {
        if (_fullName == null) {
            _fullName = super.getFullName();
        }
        return _fullName;
    }

    @Override
    public String getSignature() {
        if (_signature == null) {
            _signature = super.getSignature();
        }
        return _signature;
    }

    @Override
    public String getErasedSignature() {
        if (_erasedSignature == null) {
            _erasedSignature = super.getErasedSignature();
        }
        return _erasedSignature;
    }

    @Override
    public final TypeReference getReturnType() {
        return _returnType;
    }

    @Override
    public final List<ParameterDefinition> getParameters() {
        return _parametersView;
    }

    protected final void setName(final String name) {
        _name = name;
    }

    protected final void setReturnType(final TypeReference returnType) {
        _returnType = returnType;
    }

    protected final void setDeclaringType(final TypeDefinition declaringType) {
        _declaringType = declaringType;
        _parameters.setDeclaringType(declaringType);
    }

    protected final void setFlags(final long flags) {
        _flags = flags;
    }

    protected final GenericParameterCollection getGenericParametersInternal() {
        return _genericParameters;
    }

    protected final ParameterDefinitionCollection getParametersInternal() {
        return _parameters;
    }

    protected final Collection<TypeReference> getThrownTypesInternal() {
        return _thrownTypes;
    }

    protected final Collection<CustomAnnotation> getAnnotationsInternal() {
        return _customAnnotations;
    }

    protected final Collection<SourceAttribute> getSourceAttributesInternal() {
        return _sourceAttributes;
    }

    // <editor-fold defaultstate="collapsed" desc="Method Attributes">

    public final boolean isAbstract() {
        return Flags.testAny(getFlags(), Flags.ABSTRACT);
    }

    public final boolean isDefault() {
        return Flags.testAny(getFlags(), Flags.DEFAULT);
    }

    public final boolean isBridgeMethod() {
        return Flags.testAny(getFlags(), Flags.ACC_BRIDGE | Flags.BRIDGE);
    }

    public final boolean isVarArgs() {
        return Flags.testAny(getFlags(), Flags.ACC_VARARGS | Flags.VARARGS);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Member Attributes">_

    @Override
    public final long getFlags() {
        return _flags;
    }

    @Override
    public final int getModifiers() {
        return Flags.toModifiers(getFlags());
    }

    @Override
    public final boolean isFinal() {
        return Flags.testAny(getFlags(), Flags.FINAL);
    }

    @Override
    public final boolean isNonPublic() {
        return !Flags.testAny(getFlags(), Flags.PUBLIC);
    }

    @Override
    public final boolean isPrivate() {
        return Flags.testAny(getFlags(), Flags.PRIVATE);
    }

    @Override
    public final boolean isProtected() {
        return Flags.testAny(getFlags(), Flags.PROTECTED);
    }

    @Override
    public final boolean isPublic() {
        return Flags.testAny(getFlags(), Flags.PUBLIC);
    }

    @Override
    public final boolean isStatic() {
        return Flags.testAny(getFlags(), Flags.STATIC);
    }

    @Override
    public final boolean isSynthetic() {
        return Flags.testAny(getFlags(), Flags.SYNTHETIC);
    }

    @Override
    public final boolean isDeprecated() {
        return Flags.testAny(getFlags(), Flags.DEPRECATED);
    }

    @Override
    public final boolean isPackagePrivate() {
        return !Flags.testAny(getFlags(), Flags.PUBLIC | Flags.PROTECTED | Flags.PRIVATE);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Name and Signature Formatting">

    /**
     * Human-readable brief description of a type or member, which does not include information super types, thrown exceptions, or modifiers other than
     * 'static'.
     */
    @Override
    public String getBriefDescription() {
        return appendBriefDescription(new StringBuilder()).toString();
    }

    /**
     * Human-readable full description of a type or member, which includes specification of super types (in brief format), thrown exceptions, and modifiers.
     */
    @Override
    public String getDescription() {
        return appendDescription(new StringBuilder()).toString();
    }

    /**
     * Human-readable erased description of a type or member.
     */
    @Override
    public String getErasedDescription() {
        return appendErasedDescription(new StringBuilder()).toString();
    }

    /**
     * Human-readable simple description of a type or member, which does not include information super type or fully-qualified type names.
     */
    @Override
    public String getSimpleDescription() {
        return appendSimpleDescription(new StringBuilder()).toString();
    }

    @Override
    protected StringBuilder appendName(final StringBuilder sb, final boolean fullName, final boolean dottedName) {
        if (fullName) {
            final TypeDefinition declaringType = getDeclaringType();

            if (declaringType != null) {
                return declaringType.appendName(sb, true, false).append('.').append(getName());
            }
        }

        return sb.append(_name);
    }

    @SuppressWarnings("ConstantConditions")
    public StringBuilder appendDescription(final StringBuilder sb) {
        StringBuilder s = sb;

        for (final javax.lang.model.element.Modifier modifier : Flags.asModifierSet(getModifiers() & ~Flags.ACC_VARARGS)) {
            s.append(modifier.toString());
            s.append(' ');
        }

        final List<? extends TypeReference> typeArguments;

        if (this instanceof IGenericInstance) {
            typeArguments = ((IGenericInstance) this).getTypeArguments();
        }
        else if (hasGenericParameters()) {
            typeArguments = getGenericParameters();
        }
        else {
            typeArguments = Collections.emptyList();
        }

        if (!typeArguments.isEmpty()) {
            final int count = typeArguments.size();

            s.append('<');

            for (int i = 0; i < count; i++) {
                if (i != 0) {
                    s.append(", ");
                }
                s = typeArguments.get(i).appendSimpleDescription(s);
            }

            s.append('>');
            s.append(' ');
        }

        TypeReference returnType = getReturnType();

        while (returnType.isWildcardType()) {
            returnType = returnType.getExtendsBound();
        }

        if (returnType.isGenericParameter()) {
            s.append(returnType.getName());
        }
        else {
            s = returnType.appendSimpleDescription(s);
        }

        s.append(' ');
        s.append(getName());
        s.append('(');

        final List<ParameterDefinition> parameters = getParameters();

        for (int i = 0, n = parameters.size(); i < n; ++i) {
            final ParameterDefinition p = parameters.get(i);

            if (i != 0) {
                s.append(", ");
            }

            TypeReference parameterType = p.getParameterType();

            while (parameterType.isWildcardType()) {
                parameterType = parameterType.getExtendsBound();
            }

            if (parameterType.isGenericParameter()) {
                s.append(parameterType.getName());
            }
            else {
                s = parameterType.appendSimpleDescription(s);
            }

            s.append(" ").append(p.getName());
        }

        s.append(')');

        final List<TypeReference> thrownTypes = getThrownTypes();

        if (!thrownTypes.isEmpty()) {
            s.append(" throws ");

            for (int i = 0, n = thrownTypes.size(); i < n; ++i) {
                final TypeReference t = thrownTypes.get(i);
                if (i != 0) {
                    s.append(", ");
                }
                s = t.appendBriefDescription(s);
            }
        }

        return s;
    }

    public StringBuilder appendSimpleDescription(final StringBuilder sb) {
        StringBuilder s = sb;

        for (final javax.lang.model.element.Modifier modifier : Flags.asModifierSet(getModifiers() & ~Flags.ACC_VARARGS)) {
            s.append(modifier.toString());
            s.append(' ');
        }

        final List<? extends TypeReference> typeArguments;

        if (this instanceof IGenericInstance) {
            typeArguments = ((IGenericInstance) this).getTypeArguments();
        }
        else if (hasGenericParameters()) {
            typeArguments = getGenericParameters();
        }
        else {
            typeArguments = Collections.emptyList();
        }

        if (!typeArguments.isEmpty()) {
            s.append('<');
            for (int i = 0, n = typeArguments.size(); i < n; i++) {
                if (i != 0) {
                    s.append(", ");
                }

                final TypeReference typeArgument = typeArguments.get(i);

                if (typeArgument instanceof GenericParameter) {
                    s.append(typeArgument.getSimpleName());
                }
                else {
                    s = typeArgument.appendSimpleDescription(s);
                }
            }
            s.append('>');
            s.append(' ');
        }

        TypeReference returnType = getReturnType();

        while (returnType.isWildcardType()) {
            returnType = returnType.getExtendsBound();
        }

        if (returnType.isGenericParameter()) {
            s.append(returnType.getName());
        }
        else {
            s = returnType.appendSimpleDescription(s);
        }

        s.append(' ');
        s.append(getName());
        s.append('(');

        final List<ParameterDefinition> parameters = getParameters();

        for (int i = 0, n = parameters.size(); i < n; ++i) {
            final ParameterDefinition p = parameters.get(i);

            if (i != 0) {
                s.append(", ");
            }

            TypeReference parameterType = p.getParameterType();

            while (parameterType.isWildcardType()) {
                parameterType = parameterType.getExtendsBound();
            }

            if (parameterType.isGenericParameter()) {
                s.append(parameterType.getName());
            }
            else {
                s = parameterType.appendSimpleDescription(s);
            }
        }

        s.append(')');

        final List<TypeReference> thrownTypes = getThrownTypes();

        if (!thrownTypes.isEmpty()) {
            s.append(" throws ");

            for (int i = 0, n = thrownTypes.size(); i < n; ++i) {
                final TypeReference t = thrownTypes.get(i);
                if (i != 0) {
                    s.append(", ");
                }
                s = t.appendSimpleDescription(s);
            }
        }

        return s;
    }

    public StringBuilder appendBriefDescription(final StringBuilder sb) {
        StringBuilder s = sb;

        TypeReference returnType = getReturnType();

        while (returnType.isWildcardType()) {
            returnType = returnType.getExtendsBound();
        }

        if (returnType.isGenericParameter()) {
            s.append(returnType.getName());
        }
        else {
            s = returnType.appendBriefDescription(s);
        }

        s.append(' ');
        s.append(getName());
        s.append('(');

        final List<ParameterDefinition> parameters = getParameters();

        for (int i = 0, n = parameters.size(); i < n; ++i) {
            final ParameterDefinition p = parameters.get(i);

            if (i != 0) {
                s.append(", ");
            }

            TypeReference parameterType = p.getParameterType();

            while (parameterType.isWildcardType()) {
                parameterType = parameterType.getExtendsBound();
            }

            if (parameterType.isGenericParameter()) {
                s.append(parameterType.getName());
            }
            else {
                s = parameterType.appendBriefDescription(s);
            }
        }

        s.append(')');

        return s;
    }

    public StringBuilder appendErasedDescription(final StringBuilder sb) {
        if (hasGenericParameters() && !isGenericDefinition()) {
            final MethodDefinition definition = resolve();
            if (definition != null) {
                return definition.appendErasedDescription(sb);
            }
        }

        for (final javax.lang.model.element.Modifier modifier : Flags.asModifierSet(getModifiers() & ~Flags.ACC_VARARGS)) {
            sb.append(modifier.toString());
            sb.append(' ');
        }

        final List<ParameterDefinition> parameterTypes = getParameters();

        StringBuilder s = getReturnType().appendErasedDescription(sb);

        s.append(' ');
        s.append(getName());
        s.append('(');

        for (int i = 0, n = parameterTypes.size(); i < n; ++i) {
            if (i != 0) {
                s.append(", ");
            }
            s = parameterTypes.get(i).getParameterType().appendErasedDescription(s);
        }

        s.append(')');
        return s;
    }

    @Override
    public String toString() {
        return getSimpleDescription();
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Deferred Method Body Loading">

    private boolean tryLoadBody() {
        if (Flags.testAny(_flags, Flags.LOAD_BODY_FAILED)) {
            return false;
        }

        final CodeAttribute codeAttribute = SourceAttribute.find(AttributeNames.Code, _sourceAttributes);

        if (codeAttribute == null) {
            return false;
        }

        Buffer code = codeAttribute.getCode();
        ConstantPool constantPool = _declaringType.getConstantPool();

        if (code == null) {
            final ITypeLoader typeLoader = _declaringType.getTypeLoader();

            if (typeLoader == null) {
                _flags |= Flags.LOAD_BODY_FAILED;
                return true;
            }

            code = new Buffer();

            if (!typeLoader.tryLoadType(_declaringType.getInternalName(), code)) {
                _flags |= Flags.LOAD_BODY_FAILED;
                return true;
            }

            final List<ExceptionTableEntry> exceptionTableEntries = codeAttribute.getExceptionTableEntries();
            final List<SourceAttribute> codeAttributes = codeAttribute.getAttributes();

            final CodeAttribute newCode = new CodeAttribute(
                codeAttribute.getLength(),
                codeAttribute.getMaxStack(),
                codeAttribute.getMaxLocals(),
                codeAttribute.getCodeOffset(),
                codeAttribute.getCodeSize(),
                code,
                exceptionTableEntries.toArray(new ExceptionTableEntry[exceptionTableEntries.size()]),
                codeAttributes.toArray(new SourceAttribute[codeAttributes.size()])
            );

            _sourceAttributes.set(_sourceAttributes.indexOf(codeAttribute), newCode);

            if (constantPool == null) {
                final long magic = code.readInt() & 0xFFFFFFFFL;

                assert magic == ClassFileReader.MAGIC;

                //noinspection ConstantConditions
                if (magic != ClassFileReader.MAGIC) {
                    _flags |= Flags.LOAD_BODY_FAILED;
                    return true;
                }

                code.readUnsignedShort(); // minor version
                code.readUnsignedShort(); // major version

                constantPool = ConstantPool.read(code);
            }
        }

        final MetadataParser parser = new MetadataParser(_declaringType);
        final IMetadataScope scope = new ClassFileReader.Scope(parser, _declaringType, constantPool);

        _body = new MethodReader(this, scope).readBody();
        _body.freeze();

        return true;
    }

    // </editor-fold>
}
TOP

Related Classes of com.strobel.assembler.metadata.MethodDefinition

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.