• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
3  * Copyright (C) 2011, 2013-2016 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 
22 package com.github.javaparser.printer.lexicalpreservation;
23 
24 import com.github.javaparser.ast.Node;
25 import com.github.javaparser.ast.observer.AstObserver;
26 import com.github.javaparser.ast.observer.AstObserverAdapter;
27 import com.github.javaparser.ast.type.UnknownType;
28 
29 import java.util.IdentityHashMap;
30 import java.util.Map;
31 
32 import static java.util.Collections.synchronizedMap;
33 
34 /**
35  * We want to recognize and ignore "phantom" nodes, like the fake type of variable in FieldDeclaration
36  */
37 class PhantomNodeLogic {
38 
39     private static final int LEVELS_TO_EXPLORE = 3;
40 
41     private static final Map<Node, Boolean> isPhantomNodeCache = synchronizedMap(new IdentityHashMap<>());
42 
43     private static final AstObserver cacheCleaner = new AstObserverAdapter() {
44         @Override
45         public void parentChange(Node observedNode, Node previousParent, Node newParent) {
46             isPhantomNodeCache.remove(observedNode);
47         }
48     };
49 
isPhantomNode(Node node)50     static boolean isPhantomNode(Node node) {
51         if (isPhantomNodeCache.containsKey(node)) {
52             return isPhantomNodeCache.get(node);
53         } else {
54             if (node instanceof UnknownType) {
55                 return true;
56             }
57             boolean res = (node.getParentNode().isPresent() &&
58                     !node.getParentNode().get().getRange().get().contains(node.getRange().get())
59                     || inPhantomNode(node, LEVELS_TO_EXPLORE));
60             isPhantomNodeCache.put(node, res);
61             node.register(cacheCleaner);
62             return res;
63         }
64     }
65 
66     /**
67      * A node contained in a phantom node is also a phantom node. We limit how many levels up we check just for performance reasons.
68      */
inPhantomNode(Node node, int levels)69     private static boolean inPhantomNode(Node node, int levels) {
70         return node.getParentNode().isPresent() &&
71                 (isPhantomNode(node.getParentNode().get())
72                         || inPhantomNode(node.getParentNode().get(), levels - 1));
73     }
74 }
75