JavaParser Source Viewer

Home|JavaParser/com/github/javaparser/utils/PositionUtils.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.utils;
23
24import com.github.javaparser.Position;
25import com.github.javaparser.Range;
26import com.github.javaparser.ast.Modifier;
27import com.github.javaparser.ast.Node;
28import com.github.javaparser.ast.NodeList;
29import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
30import com.github.javaparser.ast.body.FieldDeclaration;
31import com.github.javaparser.ast.body.MethodDeclaration;
32import com.github.javaparser.ast.expr.AnnotationExpr;
33import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
34
35import java.util.Comparator;
36import java.util.List;
37
38import static java.lang.Integer.signum;
39
40public final class PositionUtils {
41
42    private PositionUtils() {
43        // prevent instantiation
44    }
45
46    public static <T extends Nodevoid sortByBeginPosition(List<Tnodes) {
47        sortByBeginPosition(nodesfalse);
48    }
49
50    public static <T extends Nodevoid sortByBeginPosition(NodeList<Tnodes) {
51        sortByBeginPosition(nodesfalse);
52    }
53
54    public static <T extends Nodevoid sortByBeginPosition(List<Tnodesfinal boolean ignoringAnnotations) {
55        nodes.sort((o1o2) -> PositionUtils.compare(o1o2ignoringAnnotations));
56    }
57
58    public static boolean areInOrder(Node aNode b) {
59        return areInOrder(abfalse);
60    }
61
62    public static boolean areInOrder(Node aNode bboolean ignoringAnnotations) {
63        return compare(abignoringAnnotations) <= 0;
64    }
65
66    private static int compare(Node aNode bboolean ignoringAnnotations) {
67        if (a.getRange().isPresent() && !b.getRange().isPresent()) {
68            return -1;
69        }
70        if (!a.getRange().isPresent() && b.getRange().isPresent()) {
71            return 1;
72        }
73        if (!a.getRange().isPresent() && !b.getRange().isPresent()) {
74            return 0;
75        }
76        if (ignoringAnnotations) {
77            int signLine = signum(beginLineWithoutConsideringAnnotation(a) - beginLineWithoutConsideringAnnotation(b));
78            if (signLine == 0) {
79                return signum(beginColumnWithoutConsideringAnnotation(a) - beginColumnWithoutConsideringAnnotation(b));
80            } else {
81                return signLine;
82            }
83        }
84
85        Position aBegin = a.getBegin().get();
86        Position bBegin = b.getBegin().get();
87
88        int signLine = signum(aBegin.line - bBegin.line);
89        if (signLine == 0) {
90            return signum(aBegin.column - bBegin.column);
91        } else {
92            return signLine;
93        }
94    }
95
96    public static AnnotationExpr getLastAnnotation(Node node) {
97        if (node instanceof NodeWithAnnotations) {
98            NodeList<AnnotationExprannotations = NodeList.nodeList(((NodeWithAnnotations<?>) node).getAnnotations());
99            if (annotations.isEmpty()) {
100                return null;
101            }
102            sortByBeginPosition(annotations);
103            return annotations.get(annotations.size() - 1);
104        } else {
105            return null;
106        }
107    }
108
109    private static int beginLineWithoutConsideringAnnotation(Node node) {
110        return firstNonAnnotationNode(node).getRange().get().begin.line;
111    }
112
113
114    private static int beginColumnWithoutConsideringAnnotation(Node node) {
115        return firstNonAnnotationNode(node).getRange().get().begin.column;
116    }
117
118    private static Node firstNonAnnotationNode(Node node) {
119        // TODO: Consider the remaining "types" of thing that annotations can target ( https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/ElementType.html )
120        if (node instanceof ClassOrInterfaceDeclaration) {
121            // Modifiers appear before the class name --
122            ClassOrInterfaceDeclaration casted = (ClassOrInterfaceDeclarationnode;
123            Modifier earliestModifier = casted.getModifiers()
124                    .stream()
125                    .filter(modifier -> modifier.getRange().isPresent())
126                    .min(Comparator.comparing(o -> o.getRange().get().begin))
127                    .orElse(null);
128            if (earliestModifier == null) {
129                return casted.getName();
130            } else {
131                return earliestModifier;
132            }
133        } else if (node instanceof MethodDeclaration) {
134            // Modifiers appear before the class name --
135            MethodDeclaration casted = (MethodDeclarationnode;
136            Modifier earliestModifier = casted.getModifiers()
137                    .stream()
138                    .filter(modifier -> modifier.getRange().isPresent())
139                    .min(Comparator.comparing(o -> o.getRange().get().begin))
140                    .orElse(null);
141            if (earliestModifier == null) {
142                return casted.getType();
143            } else {
144                return earliestModifier;
145            }
146        } else if (node instanceof FieldDeclaration) {
147            // Modifiers appear before the class name --
148            FieldDeclaration casted = (FieldDeclarationnode;
149            Modifier earliestModifier = casted.getModifiers()
150                    .stream()
151                    .filter(modifier -> modifier.getRange().isPresent())
152                    .min(Comparator.comparing(o -> o.getRange().get().begin))
153                    .orElse(null);
154            if (earliestModifier == null) {
155                return casted.getVariable(0).getType();
156            } else {
157                return earliestModifier;
158            }
159        } else {
160            return node;
161        }
162    }
163
164
165    /**
166     * Compare the position of two nodes. Optionally include annotations within the range checks.
167     * This method takes into account whether the nodes are within the same compilation unit.
168     * <p>
169     * Note that this performs a "strict contains", where the container must extend beyond the other node in both
170     * directions (otherwise it would count as an overlap, rather than "contain").
171     * <p>
172     * If `ignoringAnnotations` is false, annotations on the container are ignored. For this reason, where
173     * `container == other`, the raw `other` may extend beyond the sans-annotations `container` thus return false.
174     */
175    public static boolean nodeContains(Node containerNode otherboolean ignoringAnnotations) {
176        if (!container.getRange().isPresent()) {
177            throw new IllegalArgumentException("Cannot compare the positions of nodes if container node does not have a range.");
178        }
179        if (!other.getRange().isPresent()) {
180            throw new IllegalArgumentException("Cannot compare the positions of nodes if contained node does not have a range.");
181        }
182
183//        // FIXME: Not all nodes seem to have the compilation unit available?
184//        if (!Objects.equals(container.findCompilationUnit(), other.findCompilationUnit())) {
185//            // Allow the check to complete if they are both within a known CU (i.e. the CUs are the same),
186//            // ... or both not within a CU (i.e. both are Optional.empty())
187//            return false;
188//        }
189
190        final boolean nodeCanHaveAnnotations = container instanceof NodeWithAnnotations;
191//        final boolean hasAnnotations = PositionUtils.getLastAnnotation(container) != null;
192        if (!ignoringAnnotations || PositionUtils.getLastAnnotation(container) == null) {
193            // No special consideration required - perform simple range check.
194            return container.containsWithinRange(other);
195        }
196
197        if (!container.containsWithinRange(other)) {
198            return false;
199        }
200
201        if (!nodeCanHaveAnnotations) {
202            return true;
203        }
204
205        // If the node is contained, but it comes immediately after the annotations,
206        // let's not consider it contained (i.e. it must be "strictly contained").
207        Node nodeWithoutAnnotations = firstNonAnnotationNode(container);
208        Range rangeWithoutAnnotations = container.getRange().get()
209                .withBegin(nodeWithoutAnnotations.getBegin().get());
210        return rangeWithoutAnnotations
211//                .contains(other.getRange().get());
212                .strictlyContains(other.getRange().get());
213
214    }
215
216}
217
MembersX
PositionUtils:firstNonAnnotationNode:Block:Block:casted
PositionUtils:firstNonAnnotationNode:Block:Block:earliestModifier
PositionUtils:compare
PositionUtils:getLastAnnotation
PositionUtils:beginLineWithoutConsideringAnnotation
PositionUtils:PositionUtils
PositionUtils:areInOrder
PositionUtils:getLastAnnotation:Block:Block:annotations
PositionUtils:compare:Block:Block:signLine
PositionUtils:compare:Block:aBegin
PositionUtils:sortByBeginPosition
PositionUtils:compare:Block:signLine
PositionUtils:beginColumnWithoutConsideringAnnotation
PositionUtils:nodeContains:Block:nodeWithoutAnnotations
PositionUtils:nodeContains:Block:rangeWithoutAnnotations
PositionUtils:firstNonAnnotationNode
PositionUtils:nodeContains:Block:nodeCanHaveAnnotations
PositionUtils:nodeContains
PositionUtils:compare:Block:bBegin
Members
X