JavaParser Source Viewer

Home|JavaParser/com/github/javaparser/ast/nodeTypes/NodeWithVariables.java
1/*
2 * Copyright (C) 2007-2010 JĂșlio Vilmar Gesser.
3 * Copyright (C) 2011, 2013-2020 The JavaParser Team.
4 *
5 * This file is part of JavaParser.
6 *
7 * JavaParser can be used either under the terms of
8 * a) the GNU Lesser General Public License as published by
9 *     the Free Software Foundation, either version 3 of the License, or
10 *     (at your option) any later version.
11 * b) the terms of the Apache License
12 *
13 * You should have received a copy of both licenses in LICENCE.LGPL and
14 * LICENCE.APACHE. Please refer to those files for details.
15 *
16 * JavaParser is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 */
21
22package com.github.javaparser.ast.nodeTypes;
23
24import com.github.javaparser.ast.Node;
25import com.github.javaparser.ast.NodeList;
26import com.github.javaparser.ast.body.VariableDeclarator;
27import com.github.javaparser.ast.type.ArrayType;
28import com.github.javaparser.ast.type.Type;
29import com.github.javaparser.metamodel.DerivedProperty;
30
31import java.util.List;
32import java.util.Optional;
33import java.util.stream.Collectors;
34
35/**
36 * A node which has a list of variables.
37 */
38public interface NodeWithVariables<N extends Node> {
39    NodeList<VariableDeclaratorgetVariables();
40
41    N setVariables(NodeList<VariableDeclaratorvariables);
42
43    default VariableDeclarator getVariable(int i) {
44        return getVariables().get(i);
45    }
46
47    @SuppressWarnings("unchecked")
48    default N setVariable(int iVariableDeclarator variableDeclarator) {
49        getVariables().set(ivariableDeclarator);
50        return (N) this;
51    }
52
53    @SuppressWarnings("unchecked")
54    default N addVariable(VariableDeclarator variableDeclarator) {
55        getVariables().add(variableDeclarator);
56        return (N) this;
57    }
58
59    /**
60     * Returns the type that is shared between all variables.
61     * This is a shortcut for when you are certain that all variables share one type.
62     * What makes this difficult is arrays, and being able to set the type.
63     * <br>For {@code int a;} this is int.
64     * <br>For {@code int a,b,c,d;} this is also int.
65     * <br>For {@code int a,b[],c;} this is an assertion error since b is an int[], not an int.
66     * <br>For {@code int a,b;}, then doing setType(String) on b, this is an assertion error. It is also a situation that you don't really want.
67     */
68    default Type getCommonType() {
69        NodeList<VariableDeclaratorvariables = getVariables();
70        if (variables.isEmpty()) {
71            throw new AssertionError("There is no common type since there are no variables.");
72        }
73        Type type = variables.get(0).getType();
74        for (int i = 1i < variables.size(); i++) {
75            if (!variables.get(i).getType().equals(type)) {
76                throw new AssertionError("The variables do not have a common type.");
77            }
78        }
79        return type;
80    }
81
82    /**
83     * Returns the element type.
84     * <br>For {@code int a;} this is int.
85     * <br>For {@code int a,b,c,d;} this is also int.
86     * <br>For {@code int a,b[],c;} this is also int. Note: no mention of b being an array.
87     * <br>For {@code int a,b;}, then doing setType(String) on b, then calling getElementType(). This is an assertion error. It is also a situation that you don't really want.
88     */
89    default Type getElementType() {
90        NodeList<VariableDeclaratorvariables = getVariables();
91        if (variables.isEmpty()) {
92            throw new AssertionError("There is no element type since there are no variables.");
93        }
94        Type type = variables.get(0).getType().getElementType();
95        for (int i = 1i < variables.size(); i++) {
96            if (!variables.get(i).getType().getElementType().equals(type)) {
97                throw new AssertionError("The variables do not have a common type.");
98            }
99        }
100        return type;
101    }
102
103    /**
104     * Sets the type of all variables.
105     * Erases any existing type.
106     * This is a shortcut for setting a type on all variable declarators separately.
107     */
108    @SuppressWarnings("unchecked")
109    default N setAllTypes(Type newType) {
110        for (VariableDeclarator variable : getVariables()) {
111            variable.setType(newType);
112        }
113        return (N) this;
114    }
115
116    /**
117     * Returns the type that maximum shared type between all variables.
118     * The minimum common type does never include annotations on the array level.
119     * <p>
120     * <br>For {@code int a;} this is int.
121     * <br>For {@code int a,b,c,d;} this is also int.
122     * <br>For {@code int a,b[],c;} this is also int.
123     * <br>For {@code int[] a[][],b[],c[][];} this is int[][].
124     */
125    @DerivedProperty
126    default Optional<TypegetMaximumCommonType() {
127        return calculateMaximumCommonType(getVariables().stream().map(v -> v.getType()).collect(Collectors.toList()));
128    }
129
130    static Optional<TypecalculateMaximumCommonType(List<Typetypes) {
131        // we use a local class because we cannot use an helper static method in an interface
132        class Helper {
133            // Conceptually: given a type we start from the Element Type and get as many array levels as indicated
134            // From the implementation point of view we start from the actual type and we remove how many array
135            // levels as needed to get the target level of arrays
136            // It returns null if the type has less array levels then the desired target
137            private Optional<TypetoArrayLevel(Type typeint level) {
138                if (level > type.getArrayLevel()) {
139                    return Optional.empty();
140                }
141                for (int i = type.getArrayLevel(); i > leveli--) {
142                    if (!(type instanceof ArrayType)) {
143                        return Optional.empty();
144                    }
145                    type = ((ArrayTypetype).getComponentType();
146                }
147                return Optional.of(type);
148            }
149        }
150
151        Helper helper = new Helper();
152        int level = 0;
153        boolean keepGoing = true;
154        // In practice we want to check for how many levels of arrays all the variables have the same type,
155        // including also the annotations
156        while (keepGoing) {
157            final int currentLevel = level;
158            // Now, given that equality on nodes consider the position the simplest way is to compare
159            // the pretty-printed string got for a node. We just check all them are the same and if they
160            // are we just just is not null
161            Object[] values = types.stream().map(v -> {
162                Optional<Typet = helper.toArrayLevel(vcurrentLevel);
163                return t.map(Node::toString).orElse(null);
164            }).distinct().toArray();
165            if (values.length == 1 && values[0] != null) {
166                level++;
167            } else {
168                keepGoing = false;
169            }
170        }
171        return helper.toArrayLevel(types.get(0), --level);
172    }
173
174}
175
MembersX
NodeWithVariables:addVariable
NodeWithVariables:calculateMaximumCommonType:Block:helper
NodeWithVariables:getElementType:Block:variables
NodeWithVariables:setVariables
NodeWithVariables:calculateMaximumCommonType:Block:Block:values
NodeWithVariables:calculateMaximumCommonType:Block:Block:Block:t
NodeWithVariables:getCommonType:Block:type
NodeWithVariables:getElementType:Block:type
NodeWithVariables:setVariable
NodeWithVariables:calculateMaximumCommonType:Block:level
NodeWithVariables:getVariables
NodeWithVariables:getVariable
NodeWithVariables:getMaximumCommonType
NodeWithVariables:getCommonType:Block:variables
NodeWithVariables:calculateMaximumCommonType:Block:Block:currentLevel
NodeWithVariables:getElementType
NodeWithVariables:calculateMaximumCommonType:Block:Helper:toArrayLevel
NodeWithVariables:getCommonType
NodeWithVariables:calculateMaximumCommonType
NodeWithVariables:setAllTypes
NodeWithVariables:calculateMaximumCommonType:Block:keepGoing
Members
X