]> git.uio.no Git - ifi-stolz-refaktor.git/blob - software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/utils/CompilationUnitTextSelection.java
67455bb433a5830a03a3ecba8e0f66068cfb1700
[ifi-stolz-refaktor.git] / software / no.uio.ifi.refaktor / src / no / uio / ifi / refaktor / utils / CompilationUnitTextSelection.java
1 package no.uio.ifi.refaktor.utils;
2
3 import java.lang.ref.SoftReference;
4
5 import no.uio.ifi.refaktor.analyze.collectors.LastStatementCollector;
6
7 import org.eclipse.core.resources.IProject;
8 import org.eclipse.jdt.core.ICompilationUnit;
9 import org.eclipse.jdt.core.IJavaElement;
10 import org.eclipse.jdt.core.IType;
11 import org.eclipse.jdt.core.dom.ASTNode;
12 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
13 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
14 import org.eclipse.jdt.core.dom.CompilationUnit;
15 import org.eclipse.jdt.core.dom.ITypeBinding;
16 import org.eclipse.jdt.core.dom.NodeFinder;
17 import org.eclipse.jdt.core.dom.Statement;
18 import org.eclipse.jface.text.IDocument;
19 import org.eclipse.jface.text.ITextSelection;
20 import org.eclipse.jface.text.TextSelection;
21
22 /**
23  * A custom TextSelection that enforces the presence of
24  * a compilation unit to back the selection.
25  */
26 public class CompilationUnitTextSelection extends TextSelection implements ITextSelection {
27
28         private class NodeFinderCache {
29                 private SoftReference<NodeFinder> nodeFinderRef = new NullSoftReference<NodeFinder>();
30                 private int selectionOffsetForNodeFinder;
31
32                 private NodeFinder getNodeFinder() {
33                         NodeFinder nodeFinder = nodeFinderRef.get();
34                         if (cacheIsDirty(nodeFinder)) {
35                                 nodeFinder = ParseUtils.createNodeFinder(ParseUtils.parse(compilationUnit), CompilationUnitTextSelection.this);
36                                 nodeFinderRef = new SoftReference<NodeFinder>(nodeFinder);
37                                 selectionOffsetForNodeFinder = getOffset();
38                         }
39                         return nodeFinder;
40                 }
41
42                 private boolean cacheIsDirty(NodeFinder nodeFinder) {
43                         return nodeFinder == null || selectionOffsetForNodeFinder != getOffset();
44                 }
45         }
46
47         private ICompilationUnit compilationUnit;
48         private final NodeFinderCache nodeFinderCache;
49
50         public CompilationUnitTextSelection(CompilationUnitTextSelection textSelection) {
51                 this(textSelection.getCompilationUnit(), textSelection);
52         }
53
54         public CompilationUnitTextSelection(ICompilationUnit compilationUnit, ITextSelection selection) {
55                 this(compilationUnit, selection.getOffset(), selection.getLength());
56         }
57
58         public CompilationUnitTextSelection(ICompilationUnit compilationUnit, int offset, int length) {
59                 super(offset, length); 
60                 if (compilationUnit == null)
61                         throw new NullPointerException(this.getClass().getCanonicalName() + ": given compilation unit cannot be null");
62                 this.compilationUnit = compilationUnit;
63                 nodeFinderCache = new NodeFinderCache();
64         }
65
66         @Override
67         public IDocument getDocument() {
68                 return DocumentUtils.getDocumentFromCompilationUnit(compilationUnit);
69         }
70
71         public int getEnd() {
72                 return getOffset() + getLength();
73         }
74
75         public IProject getProject() {
76                 return compilationUnit.getJavaProject().getProject();
77         }
78
79         public ICompilationUnit getCompilationUnit() {
80                 return compilationUnit;
81         }
82
83         public ASTNode getCoveringNode() {
84                 return getNodeFinder().getCoveringNode();
85         }
86
87         public ASTNode getCoveredNode() {
88                 return getNodeFinder().getCoveredNode();
89         }
90
91         private NodeFinder getNodeFinder() {
92                 return nodeFinderCache.getNodeFinder();
93         }
94
95         public boolean surroundsNode(ASTNode node) {
96                 return getOffset() <= node.getStartPosition() && endOfNode(node) <= getEnd();
97         }
98
99         private int endOfNode(ASTNode node) {
100                 return node.getStartPosition() + node.getLength();
101         }
102
103         public String getPackageName() {
104                 return getConcreteCompilationUnit().getPackage().getName().getFullyQualifiedName();
105         }
106
107         public String getFullyQualifiedNameOfSurroundingType() {
108                 ASTNode node = findClosestSurroundingClassDeclaration();
109
110                 if (!isRootNode(node)) {
111                         assert isClassDeclaration(node);
112
113                         ITypeBinding binding = null;
114
115                         if (node instanceof AbstractTypeDeclaration) {
116                                 binding = ((AbstractTypeDeclaration) node).resolveBinding();
117                         } else if (node instanceof AnonymousClassDeclaration) {
118                                 binding = ((AnonymousClassDeclaration) node).resolveBinding();
119                         }
120
121                         if (binding != null) {
122                                 IJavaElement javaElement = binding.getJavaElement();
123
124                                 if (javaElement instanceof IType)
125                                         return ((IType) javaElement).getFullyQualifiedName();
126                         }
127                 }
128
129                 return "";
130         }
131
132         private ASTNode findClosestSurroundingClassDeclaration() {
133                 ASTNode node = getCoveringNode();
134
135                 while (!(isClassDeclaration(node) || isRootNode(node)))
136                         node = node.getParent();
137                 return node;
138         }
139
140         private boolean isClassDeclaration(ASTNode node) {
141                 return node instanceof AbstractTypeDeclaration || node instanceof AnonymousClassDeclaration;
142         }
143
144         private boolean isRootNode(ASTNode node) {
145                 return node.getNodeType() == ASTNode.COMPILATION_UNIT;
146         }
147
148         private CompilationUnit getConcreteCompilationUnit() {
149                 ASTNode root = getCoveringNode().getRoot();
150                 assert root instanceof CompilationUnit;
151                 return (CompilationUnit) root;
152         }
153
154         @Override
155         public boolean equals(Object obj) {
156                 if (obj instanceof CompilationUnitTextSelection)
157                         return super.equals(obj) && compilationUnit.equals(((CompilationUnitTextSelection)obj).compilationUnit);
158                 return false;
159         }
160
161         @Override
162         public int hashCode() {
163                 return (getOffset() << 24) | (getLength() << 16) | compilationUnit.hashCode();
164         }
165
166         @Override
167         public String toString() {
168                 return getOffsetAndLengthString() + "; End: " + getEnd() + "; CU handle identifier: " + compilationUnit.getHandleIdentifier();
169         }
170
171         public String getOffsetAndLengthString() {
172                 return "Offset: " + getOffset() + "; Length: " + getLength();
173         }
174
175         @Override
176         public int getStartLine() {
177                 return createTextSelectionWithDocument().getStartLine();
178         }
179
180         @Override
181         public int getEndLine() {
182                 return createTextSelectionWithDocument().getEndLine();
183         }
184
185         @Override
186         public String getText() {
187                 return createTextSelectionWithDocument().getText();
188         }
189
190         private TextSelection createTextSelectionWithDocument() {
191                 return new TextSelection(getDocument(), getOffset(), getLength());
192         }
193
194         public boolean isEquivalentTo(CompilationUnitTextSelection textSelection) {
195                 return equals(textSelection) || servesTheSamePurposeAs(textSelection);
196
197         }
198
199         private boolean servesTheSamePurposeAs(CompilationUnitTextSelection textSelection) {
200                 return getOffset() == textSelection.getOffset() && 
201                                 getLength() == textSelection.getLength() && 
202                                 getCompilationUnit().equals(textSelection.getCompilationUnit());
203         }
204
205         public Statement getLastStatement() {
206                 ASTNode coveringNode = getCoveringNode();
207                 if (coveringNode == getCoveredNode()) {
208                         assert coveringNode instanceof Statement;
209                         return (Statement) coveringNode;
210                 }
211
212                 LastStatementCollector lastStatementCollector = new LastStatementCollector(this, coveringNode);
213                 coveringNode.accept(lastStatementCollector);
214                 return lastStatementCollector.getLastStatement();
215         }
216 }