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

org.teavm.model.analysis.ClassMetadataRequirements Maven / Gradle / Ivy

There is a newer version: 0.2.8
Show newest version
/*
 *  Copyright 2019 Alexey Andreev.
 *
 *  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 org.teavm.model.analysis;

import java.util.HashMap;
import java.util.Map;
import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.MethodDependencyInfo;
import org.teavm.model.MethodReference;

public class ClassMetadataRequirements {
    private static final MethodReference GET_NAME_METHOD = new MethodReference(Class.class, "getName", String.class);
    private static final MethodReference GET_SIMPLE_NAME_METHOD = new MethodReference(Class.class,
            "getSimpleName", String.class);
    private static final MethodReference GET_DECLARING_CLASS_METHOD = new MethodReference(Class.class,
            "getDeclaringClass", Class.class);
    private static final MethodReference GET_ENCLOSING_CLASS_METHOD = new MethodReference(Class.class,
            "getEnclosingClass", Class.class);
    private static final ClassInfo EMPTY_INFO = new ClassInfo();
    private Map requirements = new HashMap<>();

    public ClassMetadataRequirements(DependencyInfo dependencyInfo) {
        MethodDependencyInfo getNameMethod = dependencyInfo.getMethod(GET_NAME_METHOD);
        if (getNameMethod != null) {
            addClassesRequiringName(requirements, getNameMethod.getVariable(0).getClassValueNode().getTypes());
        }

        MethodDependencyInfo getSimpleNameMethod = dependencyInfo.getMethod(GET_SIMPLE_NAME_METHOD);
        if (getSimpleNameMethod != null) {
            String[] classNames = getSimpleNameMethod.getVariable(0).getClassValueNode().getTypes();
            addClassesRequiringName(requirements, classNames);
            for (String className : classNames) {
                ClassInfo classInfo = requirements.computeIfAbsent(className, k -> new ClassInfo());
                classInfo.simpleName = true;
                classInfo.enclosingClass = true;
            }
        }

        MethodDependencyInfo getDeclaringClassMethod = dependencyInfo.getMethod(GET_DECLARING_CLASS_METHOD);
        if (getDeclaringClassMethod != null) {
            String[] classNames = getDeclaringClassMethod.getVariable(0).getClassValueNode().getTypes();
            for (String className : classNames) {
                requirements.computeIfAbsent(className, k -> new ClassInfo()).declaringClass = true;
            }
        }

        MethodDependencyInfo getEnclosingClassMethod = dependencyInfo.getMethod(GET_ENCLOSING_CLASS_METHOD);
        if (getEnclosingClassMethod != null) {
            String[] classNames = getEnclosingClassMethod.getVariable(0).getClassValueNode().getTypes();
            for (String className : classNames) {
                requirements.computeIfAbsent(className, k -> new ClassInfo()).enclosingClass = true;
            }
        }
    }

    public Info getInfo(String className) {
        ClassInfo result = requirements.get(className);
        if (result == null) {
            result = EMPTY_INFO;
        }
        return result;
    }

    private void addClassesRequiringName(Map target, String[] source) {
        for (String typeName : source) {
            if (typeName.startsWith("[")) {
                if (!typeName.endsWith(";")) {
                    continue;
                }
                int index = 0;
                while (typeName.charAt(index) == '[') {
                    ++index;
                }
                typeName = typeName.substring(index, typeName.length() - 1).replace('/', '.');
            }
            target.computeIfAbsent(typeName, k -> new ClassInfo()).name = true;
        }
    }

    static class ClassInfo implements Info {
        boolean name;
        boolean simpleName;
        boolean declaringClass;
        boolean enclosingClass;

        @Override
        public boolean name() {
            return name;
        }

        @Override
        public boolean simpleName() {
            return simpleName;
        }

        @Override
        public boolean declaringClass() {
            return declaringClass;
        }

        @Override
        public boolean enclosingClass() {
            return enclosingClass;
        }
    }

    public interface Info {
        boolean name();

        boolean simpleName();

        boolean declaringClass();

        boolean enclosingClass();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy