1 12 package org.eclipse.jdt.internal.core; 13 14 import java.util.ArrayList ; 15 import java.util.Collections ; 16 import java.util.Comparator ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 20 import org.eclipse.jdt.core.IBuffer; 21 import org.eclipse.jdt.core.ICompilationUnit; 22 import org.eclipse.jdt.core.IJavaElement; 23 import org.eclipse.jdt.core.IJavaModelStatus; 24 import org.eclipse.jdt.core.IJavaModelStatusConstants; 25 import org.eclipse.jdt.core.JavaModelException; 26 import org.eclipse.jdt.core.compiler.CharOperation; 27 import org.eclipse.jdt.core.dom.ASTNode; 28 import org.eclipse.jdt.core.dom.ASTParser; 29 import org.eclipse.jdt.core.dom.ASTVisitor; 30 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 31 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; 32 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 33 import org.eclipse.jdt.core.dom.BodyDeclaration; 34 import org.eclipse.jdt.core.dom.EnumConstantDeclaration; 35 import org.eclipse.jdt.core.dom.EnumDeclaration; 36 import org.eclipse.jdt.core.dom.TypeDeclaration; 37 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 38 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 39 import org.eclipse.jdt.core.util.CompilationUnitSorter; 40 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; 41 import org.eclipse.jdt.internal.core.util.Messages; 42 import org.eclipse.jface.text.BadLocationException; 43 import org.eclipse.jface.text.Document; 44 import org.eclipse.text.edits.RangeMarker; 45 import org.eclipse.text.edits.TextEdit; 46 import org.eclipse.text.edits.TextEditGroup; 47 48 54 public class SortElementsOperation extends JavaModelOperation { 55 public static final String CONTAINS_MALFORMED_NODES = "malformed"; 57 Comparator comparator; 58 int[] positions; 59 int apiLevel; 60 61 69 public SortElementsOperation(int level, IJavaElement[] elements, int[] positions, Comparator comparator) { 70 super(elements); 71 this.comparator = comparator; 72 this.positions = positions; 73 this.apiLevel = level; 74 } 75 76 80 protected int getMainAmountOfWork(){ 81 return this.elementsToProcess.length; 82 } 83 84 boolean checkMalformedNodes(ASTNode node) { 85 Object property = node.getProperty(CONTAINS_MALFORMED_NODES); 86 if (property == null) return false; 87 return ((Boolean ) property).booleanValue(); 88 } 89 90 protected boolean isMalformed(ASTNode node) { 91 return (node.getFlags() & ASTNode.MALFORMED) != 0; 92 } 93 94 97 protected void executeOperation() throws JavaModelException { 98 try { 99 beginTask(Messages.operation_sortelements, getMainAmountOfWork()); 100 CompilationUnit copy = (CompilationUnit) this.elementsToProcess[0]; 101 ICompilationUnit unit = copy.getPrimary(); 102 IBuffer buffer = copy.getBuffer(); 103 if (buffer == null) { 104 return; 105 } 106 char[] bufferContents = buffer.getCharacters(); 107 String result = processElement(unit, bufferContents); 108 if (!CharOperation.equals(result.toCharArray(), bufferContents)) { 109 copy.getBuffer().setContents(result); 110 } 111 worked(1); 112 } finally { 113 done(); 114 } 115 } 116 117 122 public TextEdit calculateEdit(org.eclipse.jdt.core.dom.CompilationUnit unit, TextEditGroup group) throws JavaModelException { 123 if (this.elementsToProcess.length != 1) 124 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS)); 125 126 if (!(this.elementsToProcess[0] instanceof ICompilationUnit)) 127 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this.elementsToProcess[0])); 128 129 try { 130 beginTask(Messages.operation_sortelements, getMainAmountOfWork()); 131 132 ICompilationUnit cu= (ICompilationUnit)this.elementsToProcess[0]; 133 String content= cu.getBuffer().getContents(); 134 ASTRewrite rewrite= sortCompilationUnit(unit, group); 135 if (rewrite == null) { 136 return null; 137 } 138 139 Document document= new Document(content); 140 return rewrite.rewriteAST(document, null); 141 } finally { 142 done(); 143 } 144 } 145 146 151 private String processElement(ICompilationUnit unit, char[] source) { 152 Document document = new Document(new String (source)); 153 CompilerOptions options = new CompilerOptions(unit.getJavaProject().getOptions(true)); 154 ASTParser parser = ASTParser.newParser(this.apiLevel); 155 parser.setCompilerOptions(options.getMap()); 156 parser.setSource(source); 157 parser.setKind(ASTParser.K_COMPILATION_UNIT); 158 parser.setResolveBindings(false); 159 org.eclipse.jdt.core.dom.CompilationUnit ast = (org.eclipse.jdt.core.dom.CompilationUnit) parser.createAST(null); 160 161 ASTRewrite rewriter= sortCompilationUnit(ast, null); 162 if (rewriter == null) 163 return document.get(); 164 165 TextEdit edits = rewriter.rewriteAST(document, null); 166 167 RangeMarker[] markers = null; 168 if (this.positions != null) { 169 markers = new RangeMarker[this.positions.length]; 170 for (int i = 0, max = this.positions.length; i < max; i++) { 171 markers[i]= new RangeMarker(this.positions[i], 0); 172 insert(edits, markers[i]); 173 } 174 } 175 try { 176 edits.apply(document, TextEdit.UPDATE_REGIONS); 177 if (this.positions != null) { 178 for (int i= 0, max = markers.length; i < max; i++) { 179 this.positions[i]= markers[i].getOffset(); 180 } 181 } 182 } catch (BadLocationException e) { 183 } 185 return document.get(); 186 } 187 188 189 private ASTRewrite sortCompilationUnit(org.eclipse.jdt.core.dom.CompilationUnit ast, final TextEditGroup group) { 190 ast.accept(new ASTVisitor() { 191 public boolean visit(org.eclipse.jdt.core.dom.CompilationUnit compilationUnit) { 192 List types = compilationUnit.types(); 193 for (Iterator iter = types.iterator(); iter.hasNext();) { 194 AbstractTypeDeclaration typeDeclaration = (AbstractTypeDeclaration) iter.next(); 195 typeDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer (typeDeclaration.getStartPosition())); 196 compilationUnit.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(typeDeclaration))); 197 } 198 return true; 199 } 200 public boolean visit(AnnotationTypeDeclaration annotationTypeDeclaration) { 201 List bodyDeclarations = annotationTypeDeclaration.bodyDeclarations(); 202 for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) { 203 BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next(); 204 bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer (bodyDeclaration.getStartPosition())); 205 annotationTypeDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration))); 206 } 207 return true; 208 } 209 210 public boolean visit(AnonymousClassDeclaration anonymousClassDeclaration) { 211 List bodyDeclarations = anonymousClassDeclaration.bodyDeclarations(); 212 for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) { 213 BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next(); 214 bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer (bodyDeclaration.getStartPosition())); 215 anonymousClassDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration))); 216 } 217 return true; 218 } 219 220 public boolean visit(TypeDeclaration typeDeclaration) { 221 List bodyDeclarations = typeDeclaration.bodyDeclarations(); 222 for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) { 223 BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next(); 224 bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer (bodyDeclaration.getStartPosition())); 225 typeDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration))); 226 } 227 return true; 228 } 229 230 public boolean visit(EnumDeclaration enumDeclaration) { 231 List bodyDeclarations = enumDeclaration.bodyDeclarations(); 232 for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) { 233 BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next(); 234 bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer (bodyDeclaration.getStartPosition())); 235 enumDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration))); 236 } 237 List enumConstants = enumDeclaration.enumConstants(); 238 for (Iterator iter = enumConstants.iterator(); iter.hasNext();) { 239 EnumConstantDeclaration enumConstantDeclaration = (EnumConstantDeclaration) iter.next(); 240 enumConstantDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer (enumConstantDeclaration.getStartPosition())); 241 enumDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(enumConstantDeclaration))); 242 } 243 return true; 244 } 245 }); 246 247 final ASTRewrite rewriter= ASTRewrite.create(ast.getAST()); 248 final boolean[] hasChanges= new boolean[] {false}; 249 250 ast.accept(new ASTVisitor() { 251 252 private void sortElements(List elements, ListRewrite listRewrite) { 253 if (elements.size() == 0) 254 return; 255 256 final List myCopy = new ArrayList (); 257 myCopy.addAll(elements); 258 Collections.sort(myCopy, SortElementsOperation.this.comparator); 259 260 for (int i = 0; i < elements.size(); i++) { 261 ASTNode oldNode= (ASTNode) elements.get(i); 262 ASTNode newNode= (ASTNode) myCopy.get(i); 263 if (oldNode != newNode) { 264 listRewrite.replace(oldNode, rewriter.createMoveTarget(newNode), group); 265 hasChanges[0]= true; 266 } 267 } 268 } 269 270 public boolean visit(org.eclipse.jdt.core.dom.CompilationUnit compilationUnit) { 271 if (checkMalformedNodes(compilationUnit)) { 272 return true; } 274 275 sortElements(compilationUnit.types(), rewriter.getListRewrite(compilationUnit, org.eclipse.jdt.core.dom.CompilationUnit.TYPES_PROPERTY)); 276 return true; 277 } 278 279 public boolean visit(AnnotationTypeDeclaration annotationTypeDeclaration) { 280 if (checkMalformedNodes(annotationTypeDeclaration)) { 281 return true; } 283 284 sortElements(annotationTypeDeclaration.bodyDeclarations(), rewriter.getListRewrite(annotationTypeDeclaration, AnnotationTypeDeclaration.BODY_DECLARATIONS_PROPERTY)); 285 return true; 286 } 287 288 public boolean visit(AnonymousClassDeclaration anonymousClassDeclaration) { 289 if (checkMalformedNodes(anonymousClassDeclaration)) { 290 return true; } 292 293 sortElements(anonymousClassDeclaration.bodyDeclarations(), rewriter.getListRewrite(anonymousClassDeclaration, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY)); 294 return true; 295 } 296 297 public boolean visit(TypeDeclaration typeDeclaration) { 298 if (checkMalformedNodes(typeDeclaration)) { 299 return true; } 301 302 sortElements(typeDeclaration.bodyDeclarations(), rewriter.getListRewrite(typeDeclaration, TypeDeclaration.BODY_DECLARATIONS_PROPERTY)); 303 return true; 304 } 305 306 public boolean visit(EnumDeclaration enumDeclaration) { 307 if (checkMalformedNodes(enumDeclaration)) { 308 return true; } 310 311 sortElements(enumDeclaration.bodyDeclarations(), rewriter.getListRewrite(enumDeclaration, EnumDeclaration.BODY_DECLARATIONS_PROPERTY)); 312 sortElements(enumDeclaration.enumConstants(), rewriter.getListRewrite(enumDeclaration, EnumDeclaration.ENUM_CONSTANTS_PROPERTY)); 313 return true; 314 } 315 }); 316 317 if (!hasChanges[0]) 318 return null; 319 320 return rewriter; 321 } 322 323 331 public IJavaModelStatus verify() { 332 if (this.elementsToProcess.length != 1) { 333 return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS); 334 } 335 if (this.elementsToProcess[0] == null) { 336 return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS); 337 } 338 if (!(this.elementsToProcess[0] instanceof ICompilationUnit) || !((ICompilationUnit) this.elementsToProcess[0]).isWorkingCopy()) { 339 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this.elementsToProcess[0]); 340 } 341 return JavaModelStatus.VERIFIED_OK; 342 } 343 344 public static void insert(TextEdit parent, TextEdit edit) { 345 if (!parent.hasChildren()) { 346 parent.addChild(edit); 347 return; 348 } 349 TextEdit[] children= parent.getChildren(); 350 for (int i= 0; i < children.length; i++) { 352 TextEdit child= children[i]; 353 if (covers(child, edit)) { 354 insert(child, edit); 355 return; 356 } 357 } 358 for (int i= children.length - 1; i >= 0; i--) { 361 TextEdit child= children[i]; 362 if (covers(edit, child)) { 363 parent.removeChild(i); 364 edit.addChild(child); 365 } 366 } 367 parent.addChild(edit); 368 } 369 370 private static boolean covers(TextEdit thisEdit, TextEdit otherEdit) { 371 if (thisEdit.getLength() == 0) { 372 return false; 373 } 374 375 int thisOffset= thisEdit.getOffset(); 376 int thisEnd= thisEdit.getExclusiveEnd(); 377 if (otherEdit.getLength() == 0) { 378 int otherOffset= otherEdit.getOffset(); 379 return thisOffset <= otherOffset && otherOffset < thisEnd; 380 } else { 381 int otherOffset= otherEdit.getOffset(); 382 int otherEnd= otherEdit.getExclusiveEnd(); 383 return thisOffset <= otherOffset && otherEnd <= thisEnd; 384 } 385 } 386 } 387 | Popular Tags |