All Downloads are FREE. Search and download functionalities are using the official Maven repository.

android.databinding.tool.expr.MethodBaseExpr Maven / Gradle / Ivy

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.databinding.tool.expr;

import android.databinding.tool.processing.Scope;
import android.databinding.tool.reflection.ModelAnalyzer;
import android.databinding.tool.reflection.ModelClass;
import android.databinding.tool.reflection.ModelMethod;
import android.databinding.tool.solver.ExecutionPath;

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

public abstract class MethodBaseExpr extends Expr {
    String mName;

    MethodBaseExpr(Expr parent, String name) {
        super(parent);
        mName = name;
    }

    public Expr getTarget() {
        return getChildren().get(0);
    }

    @Override
    public List toExecutionPath(List paths) {
        final List targetPaths = getTarget().toExecutionPath(paths);
        // after this, we need a null check.
        List result = new ArrayList();
        if (getTarget() instanceof StaticIdentifierExpr) {
            result.addAll(toExecutionPathInOrder(paths, getTarget()));
        } else {
            for (ExecutionPath path : targetPaths) {
                final ComparisonExpr cmp = getModel()
                        .comparison("!=", getTarget(), getModel().symbol("null", Object.class));
                path.addPath(cmp);
                final ExecutionPath subPath = path.addBranch(cmp, true);
                if (subPath != null) {
                    subPath.addPath(this);
                    result.add(subPath);
                }
            }
        }
        return result;
    }

    protected Expr resolveListenersAsMethodReference(ModelClass listener, Expr parent) {
        final Expr target = getTarget();
        final ModelClass childType = target.getResolvedType();
        if (listener == null) {
            throw new IllegalStateException(
                    String.format("Could not resolve %s as a listener.", this));
        }

        List abstractMethods = listener.getAbstractMethods();
        int numberOfAbstractMethods = abstractMethods == null ? 0 : abstractMethods.size();
        if (numberOfAbstractMethods != 1) {
            throw new IllegalStateException(String.format(
                    "Could not find accessor %s.%s and %s has %d abstract methods, so is" +
                            " not resolved as a listener",
                    childType.getCanonicalName(), mName,
                    listener.getCanonicalName(), numberOfAbstractMethods));
        }

        // Look for a signature matching the abstract method
        final ModelMethod listenerMethod = abstractMethods.get(0);
        final ModelClass[] listenerParameters = listenerMethod.getParameterTypes();
        boolean isStatic = getTarget() instanceof StaticIdentifierExpr;
        List methods = childType.findMethods(mName, isStatic);
        for (ModelMethod method : methods) {
            if (acceptsParameters(method, listenerParameters) &&
                    method.getReturnType(null).equals(listenerMethod.getReturnType(null))) {
                target.getParents().remove(this);
                resetResolvedType();
                // replace this with ListenerExpr in parent
                Expr listenerExpr = getModel().listenerExpr(getTarget(), mName, listener,
                        listenerMethod);
                if (parent != null) {
                    int index;
                    while ((index = parent.getChildren().indexOf(this)) != -1) {
                        parent.getChildren().set(index, listenerExpr);
                    }
                }
                if (getModel().mBindingExpressions.contains(this)) {
                    getModel().bindingExpr(listenerExpr);
                }
                getParents().remove(parent);
                if (getParents().isEmpty()) {
                    getModel().removeExpr(this);
                }
                return listenerExpr;
            }
        }

        throw new IllegalStateException(String.format(
                "Listener class %s with method %s did not match signature of any method %s",
                listener.getCanonicalName(), listenerMethod.getName(), this));
    }

    private boolean acceptsParameters(ModelMethod method, ModelClass[] listenerParameters) {
        ModelClass[] parameters = method.getParameterTypes();
        if (parameters.length != listenerParameters.length) {
            return false;
        }
        for (int i = 0; i < parameters.length; i++) {
            if (!parameters[i].isAssignableFrom(listenerParameters[i])) {
                return false;
            }
        }
        return true;
    }

    @Override
    protected List constructDependencies() {
        final List dependencies = constructDynamicChildrenDependencies();
        for (Dependency dependency : dependencies) {
            if (dependency.getOther() == getTarget()) {
                dependency.setMandatory(true);
            }
        }
        return dependencies;
    }

    public String getName() {
        return mName;
    }

    @Override
    public void updateExpr(ModelAnalyzer modelAnalyzer) {
        try {
            Scope.enter(this);
            resolveType(modelAnalyzer);
            super.updateExpr(modelAnalyzer);
        } finally {
            Scope.exit();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy