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

org.walkmod.javalang.compiler.actions.LoadFieldDeclarationsAction Maven / Gradle / Ivy

There is a newer version: 2.3.10
Show newest version
/*
 * Copyright (C) 2015 Raquel Pau and Albert Coroleu.
 * 
 * Walkmod is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * 
 * Walkmod is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with Walkmod. If
 * not, see .
 */
package org.walkmod.javalang.compiler.actions;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.walkmod.javalang.ast.Node;
import org.walkmod.javalang.ast.body.AnnotationDeclaration;
import org.walkmod.javalang.ast.body.BodyDeclaration;
import org.walkmod.javalang.ast.body.ClassOrInterfaceDeclaration;
import org.walkmod.javalang.ast.body.EnumConstantDeclaration;
import org.walkmod.javalang.ast.body.EnumDeclaration;
import org.walkmod.javalang.ast.body.FieldDeclaration;
import org.walkmod.javalang.ast.body.TypeDeclaration;
import org.walkmod.javalang.ast.body.VariableDeclarator;
import org.walkmod.javalang.ast.expr.ObjectCreationExpr;
import org.walkmod.javalang.ast.type.ClassOrInterfaceType;
import org.walkmod.javalang.ast.type.Type;
import org.walkmod.javalang.compiler.providers.SymbolActionProvider;
import org.walkmod.javalang.compiler.reflection.ClassInspector;
import org.walkmod.javalang.compiler.reflection.FieldInspector;
import org.walkmod.javalang.compiler.reflection.GenericBuilderFromGenericClasses;
import org.walkmod.javalang.compiler.symbols.ASTSymbolTypeResolver;
import org.walkmod.javalang.compiler.symbols.ReferenceType;
import org.walkmod.javalang.compiler.symbols.Scope;
import org.walkmod.javalang.compiler.symbols.Symbol;
import org.walkmod.javalang.compiler.symbols.SymbolAction;
import org.walkmod.javalang.compiler.symbols.SymbolTable;
import org.walkmod.javalang.compiler.symbols.SymbolType;
import org.walkmod.javalang.exceptions.InvalidTypeException;
import org.walkmod.javalang.visitors.VoidVisitorAdapter;

public class LoadFieldDeclarationsAction extends SymbolAction {

    private SymbolActionProvider actionProvider;

    public LoadFieldDeclarationsAction(SymbolActionProvider actionProvider) {

        this.actionProvider = actionProvider;
    }

    @Override
    public void doPush(Symbol symbol, SymbolTable table) throws Exception {

        if (symbol.getName().equals("this")) {
            Node node = symbol.getLocation();
            if (node instanceof TypeDeclaration || node instanceof ObjectCreationExpr
                    || node instanceof EnumConstantDeclaration) {
                node.accept(new FieldsPopulator(table), table.getScopes().peek());
            }

        }
    }

    private class FieldsPopulator extends VoidVisitorAdapter {

        private SymbolTable table;

        public FieldsPopulator(SymbolTable table) {
            this.table = table;
        }

        @Override
        public void visit(ObjectCreationExpr o, Scope scope) {
            if (!scope.hasFieldsLoaded()) {
                table.pushScope(scope);
                List types = new LinkedList();
                types.add(o.getType());
                loadExtendsOrImplements(types);
                loadFields(o.getAnonymousClassBody(), scope);
                table.popScope(true);
            }
        }

        @Override
        public void visit(EnumConstantDeclaration o, Scope scope) {
            if (!scope.hasFieldsLoaded()) {
                table.pushScope(scope);
                loadFields(o.getClassBody(), scope);
                table.popScope(true);
            }
        }

        @Override
        public void visit(ClassOrInterfaceDeclaration n, Scope scope) {
            if (!scope.hasFieldsLoaded()) {
                table.pushScope(scope);

                loadExtendsOrImplements(n.getExtends());
                loadExtendsOrImplements(n.getImplements());
                loadFields(n.getMembers(), scope);
                table.popScope(true);
            }

        }

        @Override
        public void visit(EnumDeclaration n, Scope scope) {
            if (!scope.hasFieldsLoaded()) {
                table.pushScope(scope);
                loadExtendsOrImplements(n.getImplements());
                loadFields(n.getMembers(), scope);
                table.popScope(true);
            }
        }

        @Override
        public void visit(AnnotationDeclaration n, Scope scope) {
            if (!scope.hasFieldsLoaded()) {
                table.pushScope(scope);
                loadFields(n.getMembers(), scope);
                table.popScope(true);
            }
        }

        public void loadExtendsOrImplements(List extendsList) {
            if (extendsList != null) {
                Symbol superSym = table.findSymbol("super");
                Map typeParams = null;
                Scope superScope = null;
                if (superSym != null) {
                    superScope = superSym.getInnerScope();

                    if (superScope != null) {
                        typeParams = superScope.getTypeParams();
                    }
                }

                for (ClassOrInterfaceType type : extendsList) {
                    String name = type.getName();
                    ClassOrInterfaceType scope = type.getScope();
                    if (scope != null) {
                        name = scope.toString() + "." + name;
                    }
                    Symbol s = table.findSymbol(name, ReferenceType.TYPE);

                    if (s != null) {
                        Scope inner = s.getInnerScope();
                        Object location = s.getLocation();
                        if (location != null && location instanceof TypeDeclaration) {
                            ((TypeDeclaration) location).accept(this, inner);
                            List parameters = s.getType().getParameterizedTypes();
                            if (parameters != null && typeParams != null) {
                                List> symbols = inner.getSymbolsByType(ReferenceType.VARIABLE);
                                table.pushScope(superScope);
                                for (Symbol sym : symbols) {
                                    String symName = sym.getName();
                                    if (!"this".equals(symName) && !"super".equals(symName)) {
                                        SymbolType refactorized = sym.getType().refactor(typeParams);

                                        table.pushSymbol(symName, ReferenceType.VARIABLE, refactorized,
                                                sym.getLocation());
                                    }
                                }
                                table.popScope(true);
                            }

                        } else {
                            Class clazz = s.getType().getClazz();
                            loadFieldsFromClass(clazz, typeParams);
                        }
                    } else {
                        Class clazz = null;

                        if (type.getParentNode() instanceof ObjectCreationExpr) {
                            ObjectCreationExpr parent = (ObjectCreationExpr) type.getParentNode();
                            clazz = parent.getSymbolData().getClazz().getSuperclass();
                        } else {
                            SymbolType stype = ASTSymbolTypeResolver.getInstance().valueOf(type);
                            clazz = stype.getClazz();

                        }
                        loadFieldsFromClass(clazz, typeParams);
                    }
                }
            }
        }

        private void loadFieldsFromClass(Class clazz, Map typeParams) {
            Set fields = FieldInspector.getNonPrivateFields(clazz);
            List params = table.getType("this").getParameterizedTypes();

            for (Field field : fields) {
                try {
                    Map typeMapping = null;
                    if (typeParams == null) {
                        if (!clazz.getName().equals(field.getDeclaringClass().getName())) {

                            List types = ClassInspector
                                    .getInterfaceOrSuperclassImplementations(clazz, field.getDeclaringClass());
                            if (!types.isEmpty()) {
                                java.lang.reflect.Type firstType = types.iterator().next();
                                if (firstType instanceof ParameterizedType) {
                                    typeMapping = new HashMap();
                                    ParameterizedType ptype = (ParameterizedType) firstType;
                                    java.lang.reflect.Type[] args = ptype.getActualTypeArguments();
                                    TypeVariable[] tv = field.getDeclaringClass().getTypeParameters();
                                    for (int i = 0; i < tv.length && i < args.length; i++) {
                                        typeMapping.put(tv[i].getName(), SymbolType.valueOf(args[i], null));
                                    }
                                }
                            }
                        }
                    } else {
                        typeMapping = new HashMap();

                        GenericBuilderFromGenericClasses builder =
                                new GenericBuilderFromGenericClasses(field.getDeclaringClass(), params);
                        builder.build(typeMapping);
                        typeMapping.putAll(typeParams);
                    }

                    table.pushSymbol(field.getName(), ReferenceType.VARIABLE,
                            SymbolType.valueOf(field.getGenericType(), typeMapping), null,

                            true);
                } catch (InvalidTypeException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        private void loadFields(List members, Scope scope) {
            if (!scope.hasFieldsLoaded()) {
                if (members != null) {

                    for (BodyDeclaration member : members) {
                        if (member instanceof FieldDeclaration) {

                            FieldDeclaration fd = (FieldDeclaration) member;
                            Type type = fd.getType();
                            List actions = null;

                            Symbol root = table.getScopes().peek().getRootSymbol();
                            if (root != null) {
                                Node location = root.getLocation();
                                if (location != null) {
                                    if (location == member.getParentNode()) {
                                        if (actionProvider != null) {
                                            actions = actionProvider.getActions(fd);
                                        }
                                    }
                                }
                            }

                            SymbolType resolvedType = ASTSymbolTypeResolver.getInstance().valueOf(type);

                            if (resolvedType == null) {
                                resolvedType = new SymbolType(Object.class);
                            }
                            type.setSymbolData(resolvedType);

                            for (VariableDeclarator var : fd.getVariables()) {
                                SymbolType symType = resolvedType.clone();
                                if (symType.getArrayCount() == 0) {
                                    symType.setArrayCount(var.getId().getArrayCount());
                                }

                                table.pushSymbol(var.getId().getName(), ReferenceType.VARIABLE, symType, var, actions,
                                        true);

                            }

                        }
                    }

                }
                scope.setHasFieldsLoaded(true);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy