1 /******************************************************************************* 2 * Copyright (c) 2000, 2010 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.ui.javaeditor; 15 16 import org.eclipse.jface.text.IDocument; 17 import org.eclipse.jface.text.TextSelection; 18 19 import org.eclipse.jdt.core.IJavaElement; 20 import org.eclipse.jdt.core.ITypeRoot; 21 import org.eclipse.jdt.core.JavaModelException; 22 import org.eclipse.jdt.core.dom.ASTNode; 23 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 24 import org.eclipse.jdt.core.dom.Annotation; 25 import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; 26 import org.eclipse.jdt.core.dom.BodyDeclaration; 27 import org.eclipse.jdt.core.dom.CompilationUnit; 28 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 29 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 30 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore; 31 32 import org.eclipse.jdt.internal.corext.dom.Selection; 33 import org.eclipse.jdt.internal.corext.dom.SelectionAnalyzer; 34 35 import org.eclipse.jdt.internal.ui.actions.SelectionConverter; 36 37 /** 38 * A special text selection that gives access to the resolved and 39 * enclosing element. 40 */ 41 public class JavaTextSelection extends TextSelection { 42 43 private ITypeRoot fElement; 44 private IJavaElement[] fResolvedElements; 45 46 private boolean fEnclosingElementRequested; 47 private IJavaElement fEnclosingElement; 48 49 private boolean fPartialASTRequested; 50 private CompilationUnit fPartialAST; 51 52 private boolean fNodesRequested; 53 private ASTNode[] fSelectedNodes; 54 private ASTNode fCoveringNode; 55 56 private boolean fInMethodBodyRequested; 57 private boolean fInMethodBody; 58 59 private boolean fInClassInitializerRequested; 60 private boolean fInClassInitializer; 61 62 private boolean fInVariableInitializerRequested; 63 private boolean fInVariableInitializer; 64 65 /** 66 * Indicates whether the selection node has been checked to be of type <code>Annotation</code>. 67 * 68 * @since 3.7 69 */ 70 private boolean fInAnnotationRequested; 71 72 /** 73 * Indicates whether selection node is of type <code>Annotation</code>. 74 * 75 * @since 3.7 76 */ 77 private boolean fInAnnotation; 78 79 /** 80 * Creates a new text selection at the given offset and length. 81 * @param element the root element 82 * @param document the document 83 * @param offset offset of the selection 84 * @param length length of the selection 85 */ JavaTextSelection(ITypeRoot element, IDocument document, int offset, int length)86 public JavaTextSelection(ITypeRoot element, IDocument document, int offset, int length) { 87 super(document, offset, length); 88 fElement= element; 89 } 90 91 /** 92 * Resolves the <code>IJavaElement</code>s at the current offset. Returns 93 * an empty array if the string under the offset doesn't resolve to a 94 * <code>IJavaElement</code>. 95 * 96 * @return the resolved java elements at the current offset 97 * @throws JavaModelException passed from the underlying code resolve API 98 */ resolveElementAtOffset()99 public IJavaElement[] resolveElementAtOffset() throws JavaModelException { 100 if (fResolvedElements != null) 101 return fResolvedElements; 102 // long start= System.currentTimeMillis(); 103 fResolvedElements= SelectionConverter.codeResolve(fElement, this); 104 // System.out.println("Time resolving element: " + (System.currentTimeMillis() - start)); 105 return fResolvedElements; 106 } 107 resolveEnclosingElement()108 public IJavaElement resolveEnclosingElement() throws JavaModelException { 109 if (fEnclosingElementRequested) 110 return fEnclosingElement; 111 fEnclosingElementRequested= true; 112 fEnclosingElement= SelectionConverter.resolveEnclosingElement(fElement, this); 113 return fEnclosingElement; 114 } 115 resolvePartialAstAtOffset()116 public CompilationUnit resolvePartialAstAtOffset() { 117 if (fPartialASTRequested) 118 return fPartialAST; 119 fPartialASTRequested= true; 120 // long start= System.currentTimeMillis(); 121 fPartialAST= SharedASTProviderCore.getAST(fElement, SharedASTProviderCore.WAIT_YES, null); 122 // System.out.println("Time requesting partial AST: " + (System.currentTimeMillis() - start)); 123 return fPartialAST; 124 } 125 resolveSelectedNodes()126 public ASTNode[] resolveSelectedNodes() { 127 if (fNodesRequested) 128 return fSelectedNodes; 129 fNodesRequested= true; 130 CompilationUnit root= resolvePartialAstAtOffset(); 131 if (root == null) 132 return null; 133 Selection ds= Selection.createFromStartLength(getOffset(), getLength()); 134 SelectionAnalyzer analyzer= new SelectionAnalyzer(ds, false); 135 root.accept(analyzer); 136 fSelectedNodes= analyzer.getSelectedNodes(); 137 fCoveringNode= analyzer.getLastCoveringNode(); 138 return fSelectedNodes; 139 } 140 resolveCoveringNode()141 public ASTNode resolveCoveringNode() { 142 if (fNodesRequested) 143 return fCoveringNode; 144 resolveSelectedNodes(); 145 return fCoveringNode; 146 } 147 resolveInMethodBody()148 public boolean resolveInMethodBody() { 149 if (fInMethodBodyRequested) 150 return fInMethodBody; 151 fInMethodBodyRequested= true; 152 resolveSelectedNodes(); 153 ASTNode node= getStartNode(); 154 if (node == null) { 155 fInMethodBody= true; 156 } else { 157 while (node != null) { 158 int nodeType= node.getNodeType(); 159 if (nodeType == ASTNode.BLOCK && node.getParent() instanceof BodyDeclaration) { 160 fInMethodBody= node.getParent().getNodeType() == ASTNode.METHOD_DECLARATION; 161 break; 162 } else if (nodeType == ASTNode.ANONYMOUS_CLASS_DECLARATION) { 163 fInMethodBody= false; 164 break; 165 } 166 node= node.getParent(); 167 } 168 } 169 return fInMethodBody; 170 } 171 resolveInClassInitializer()172 public boolean resolveInClassInitializer() { 173 if (fInClassInitializerRequested) 174 return fInClassInitializer; 175 fInClassInitializerRequested= true; 176 resolveSelectedNodes(); 177 ASTNode node= getStartNode(); 178 if (node == null) { 179 fInClassInitializer= true; 180 } else { 181 while (node != null) { 182 int nodeType= node.getNodeType(); 183 if (node instanceof AbstractTypeDeclaration) { 184 fInClassInitializer= false; 185 break; 186 } else if (nodeType == ASTNode.ANONYMOUS_CLASS_DECLARATION) { 187 fInClassInitializer= false; 188 break; 189 } else if (nodeType == ASTNode.INITIALIZER) { 190 fInClassInitializer= true; 191 break; 192 } 193 node= node.getParent(); 194 } 195 } 196 return fInClassInitializer; 197 } 198 resolveInVariableInitializer()199 public boolean resolveInVariableInitializer() { 200 if (fInVariableInitializerRequested) 201 return fInVariableInitializer; 202 fInVariableInitializerRequested= true; 203 resolveSelectedNodes(); 204 ASTNode node= getStartNode(); 205 ASTNode last= null; 206 while (node != null) { 207 int nodeType= node.getNodeType(); 208 if (node instanceof AbstractTypeDeclaration) { 209 fInVariableInitializer= false; 210 break; 211 } else if (nodeType == ASTNode.ANONYMOUS_CLASS_DECLARATION) { 212 fInVariableInitializer= false; 213 break; 214 } else if (nodeType == ASTNode.VARIABLE_DECLARATION_FRAGMENT && 215 ((VariableDeclarationFragment)node).getInitializer() == last) { 216 fInVariableInitializer= true; 217 break; 218 } else if (nodeType == ASTNode.SINGLE_VARIABLE_DECLARATION && 219 ((SingleVariableDeclaration)node).getInitializer() == last) { 220 fInVariableInitializer= true; 221 break; 222 } else if (nodeType == ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION && 223 ((AnnotationTypeMemberDeclaration)node).getDefault() == last) { 224 fInVariableInitializer= true; 225 break; 226 } 227 last= node; 228 node= node.getParent(); 229 } 230 return fInVariableInitializer; 231 } 232 233 /** 234 * Resolves the selected nodes and returns <code>true</code> if the node or any of its ancestors 235 * is of type <code>Annotation</code>, <code>false</code> otherwise. 236 * 237 * @return <code>true</code> if the node or any of its ancestors is of type 238 * <code>Annotation</code>, <code>false</code> otherwise 239 * @since 3.7 240 */ resolveInAnnotation()241 public boolean resolveInAnnotation() { 242 if (fInAnnotationRequested) 243 return fInAnnotation; 244 fInAnnotationRequested= true; 245 resolveSelectedNodes(); 246 ASTNode node= getStartNode(); 247 while (node != null) { 248 if (node instanceof Annotation) { 249 fInAnnotation= true; 250 break; 251 } 252 node= node.getParent(); 253 } 254 return fInAnnotation; 255 } 256 getStartNode()257 private ASTNode getStartNode() { 258 if (fSelectedNodes != null && fSelectedNodes.length > 0) 259 return fSelectedNodes[0]; 260 else 261 return fCoveringNode; 262 } 263 } 264