Package com.strobel.decompiler.ast

Source Code of com.strobel.decompiler.ast.Expression

/*
* Expression.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.decompiler.ast;

import com.strobel.annotations.NotNull;
import com.strobel.annotations.Nullable;
import com.strobel.assembler.Collection;
import com.strobel.assembler.metadata.FieldReference;
import com.strobel.assembler.metadata.MemberReference;
import com.strobel.assembler.metadata.MethodReference;
import com.strobel.assembler.metadata.TypeReference;
import com.strobel.componentmodel.Key;
import com.strobel.componentmodel.UserDataStore;
import com.strobel.componentmodel.UserDataStoreBase;
import com.strobel.core.ArrayUtilities;
import com.strobel.core.Comparer;
import com.strobel.core.VerifyArgument;
import com.strobel.decompiler.DecompilerHelpers;
import com.strobel.decompiler.ITextOutput;
import com.strobel.decompiler.NameSyntax;

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

import static com.strobel.decompiler.DecompilerHelpers.writeType;

public final class Expression extends Node implements Cloneable, UserDataStore {
    public static final Object ANY_OPERAND = new Object();

    private final Collection<Expression> _arguments = new Collection<>();

    private final Collection<Range> _ranges = new Collection<Range>() {
        @Override
        public void add(final int index, final Range element) {
            if (contains(element)) {
                return;
            }
            super.add(index, element);
        }
    };

    private AstCode _code;
    private Object _operand;
    private TypeReference _expectedType;
    private TypeReference _inferredType;
    private UserDataStoreBase _userData;

    public Expression(final AstCode code, final Object operand, final List<Expression> arguments) {
        _code = VerifyArgument.notNull(code, "code");
        _operand = VerifyArgument.verifyNotInstanceOf(Expression.class, operand, "operand");

        if (arguments != null) {
            _arguments.addAll(arguments);
        }
    }

    public Expression(final AstCode code, final Object operand, final Expression... arguments) {
        _code = VerifyArgument.notNull(code, "code");
        _operand = VerifyArgument.verifyNotInstanceOf(Expression.class, operand, "operand");

        if (arguments != null) {
            Collections.addAll(_arguments, arguments);
        }
    }

    public final List<Expression> getArguments() {
        return _arguments;
    }

    public final AstCode getCode() {
        return _code;
    }

    public final void setCode(final AstCode code) {
        _code = code;
    }

    public final Object getOperand() {
        return _operand;
    }

    public final void setOperand(final Object operand) {
        _operand = operand;
    }

    public final TypeReference getExpectedType() {
        return _expectedType;
    }

    public final void setExpectedType(final TypeReference expectedType) {
        _expectedType = expectedType;
    }

    public final TypeReference getInferredType() {
        return _inferredType;
    }

    public final void setInferredType(final TypeReference inferredType) {
        _inferredType = inferredType;
    }

    public final boolean isBranch() {
        return _operand instanceof Label ||
               _operand instanceof Label[];
    }

    public final List<Label> getBranchTargets() {
        if (_operand instanceof Label) {
            return Collections.singletonList((Label) _operand);
        }

        if (_operand instanceof Label[]) {
            return ArrayUtilities.asUnmodifiableList((Label[]) _operand);
        }

        return Collections.emptyList();
    }

    public final Collection<Range> getRanges() {
        return _ranges;
    }

    @Override
    public final List<Node> getChildren() {
        final ArrayList<Node> childrenCopy = new ArrayList<>();
        childrenCopy.addAll(_arguments);
        return childrenCopy;
    }

    public final boolean containsReferenceTo(final Variable variable) {
        if (_operand == variable) {
            return true;
        }

        for (int i = 0; i < _arguments.size(); i++) {
            if (_arguments.get(i).containsReferenceTo(variable)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public final void writeTo(final ITextOutput output) {
        final AstCode code = _code;
        final Object operand = _operand;
        final TypeReference inferredType = _inferredType;
        final TypeReference expectedType = _expectedType;

        if (operand instanceof Variable &&
            ((Variable) operand).isGenerated()) {

            if (AstCodeHelpers.isLocalStore(code)) {
                output.write(((Variable) operand).getName());
                output.write(" = ");
                getArguments().get(0).writeTo(output);
                return;
            }

            if (AstCodeHelpers.isLocalLoad(code)) {
                output.write(((Variable) operand).getName());

                if (inferredType != null) {
                    output.write(':');
                    writeType(output, inferredType, NameSyntax.SHORT_TYPE_NAME);

                    if (expectedType != null &&
                        !Comparer.equals(expectedType.getInternalName(), inferredType.getInternalName())) {

                        output.write("[expected:");
                        writeType(output, expectedType, NameSyntax.SHORT_TYPE_NAME);
                        output.write(']');
                    }
                }

                return;
            }
        }

        output.writeReference(code.name().toLowerCase(), code);

        if (inferredType != null) {
            output.write(':');
            writeType(output, inferredType, NameSyntax.SHORT_TYPE_NAME);

            if (expectedType != null &&
                !Comparer.equals(expectedType.getInternalName(), inferredType.getInternalName())) {

                output.write("[expected:");
                writeType(output, expectedType, NameSyntax.SHORT_TYPE_NAME);
                output.write(']');
            }
        }
        else if (expectedType != null) {
            output.write("[expected:");
            writeType(output, expectedType, NameSyntax.SHORT_TYPE_NAME);
            output.write(']');
        }

        output.write('(');

        boolean first = true;

        if (operand != null) {
            if (operand instanceof Label) {
                output.writeReference(((Label) operand).getName(), operand);
            }
            else if (operand instanceof Label[]) {
                final Label[] labels = (Label[]) operand;

                for (int i = 0; i < (labels).length; i++) {
                    if (i != 0) {
                        output.write(", ");
                    }

                    output.writeReference(labels[i].getName(), labels[i]);
                }
            }
            else if (operand instanceof MethodReference ||
                     operand instanceof FieldReference) {

                final MemberReference member = (MemberReference) operand;
                final TypeReference declaringType = member.getDeclaringType();

                if (declaringType != null) {
                    writeType(output, declaringType, NameSyntax.SHORT_TYPE_NAME);
                    output.write("::");
                }

                output.writeReference(member.getName(), member);
            }
            else {
                DecompilerHelpers.writeOperand(output, operand);
            }

            first = false;
        }

        for (final Expression argument : getArguments()) {
            if (!first) {
                output.write(", ");
            }

            argument.writeTo(output);
            first = false;
        }

        output.write(')');
    }

    @SuppressWarnings("CloneDoesntCallSuperClone")
    public final Expression clone() {
        final Expression clone = new Expression(_code, _operand);

        clone._code = _code;
        clone._expectedType = _expectedType;
        clone._inferredType = _inferredType;
        clone._operand = _operand;
        clone._userData = _userData != null ? _userData.clone() : null;

        for (final Expression argument : _arguments) {
            clone._arguments.add(argument.clone());
        }

        return clone;
    }

    @Override
    public <T> T getUserData(@NotNull final Key<T> key) {
        if (_userData == null) {
            return null;
        }
        return _userData.getUserData(key);
    }

    @Override
    public <T> void putUserData(@NotNull final Key<T> key, @Nullable final T value) {
        if (_userData == null) {
            _userData = new UserDataStoreBase();
        }
        _userData.putUserData(key, value);
    }

    @Override
    public <T> T putUserDataIfAbsent(@NotNull final Key<T> key, @Nullable final T value) {
        if (_userData == null) {
            _userData = new UserDataStoreBase();
        }
        return _userData.putUserDataIfAbsent(key, value);
    }

    @Override
    public <T> boolean replace(@NotNull final Key<T> key, @Nullable final T oldValue, @Nullable final T newValue) {
        if (_userData == null) {
            _userData = new UserDataStoreBase();
        }
        return _userData.replace(key, oldValue, newValue);
    }
}
TOP

Related Classes of com.strobel.decompiler.ast.Expression

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.