1 19 20 package org.netbeans.modules.javacore.parser; 21 22 import java.io.*; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.List ; 26 import java.util.regex.Pattern ; 27 import javax.swing.text.BadLocationException ; 28 import javax.swing.text.Document ; 29 import javax.swing.text.Position.Bias; 30 import org.netbeans.api.java.queries.SourceLevelQuery; 31 import org.netbeans.jmi.javamodel.Resource; 32 import org.netbeans.lib.java.parser.*; 33 import org.netbeans.modules.javacore.JMManager; 34 import org.openide.ErrorManager; 35 import org.openide.cookies.EditorCookie; 36 import org.openide.filesystems.FileObject; 37 import org.openide.loaders.DataObject; 38 import org.openide.loaders.DataObjectNotFoundException; 39 import org.openide.text.CloneableEditorSupport; 40 import org.openide.text.PositionBounds; 41 import org.openide.text.PositionRef; 42 43 44 48 public class ASTProvider implements ParserTokens, ASTreeTypes, ASTContext { 49 FileObject fobj; 50 private CloneableEditorSupport editor; 51 private ASTree topNode; 52 private Token[] tokens; 53 private String sourceText; 54 private Resource rsc; 55 static ASTree[] NULL_TREE=new ASTree[0]; 56 boolean documentPositions; 57 boolean hasSyntaxErrors; 58 59 60 public ASTProvider(Resource r,FileObject obj) { 61 rsc=r; 62 fobj = obj; 63 if (obj == null) throw new javax.jmi.reflect.InvalidObjectException(r); 64 } 65 66 protected ASTProvider(Resource r, FileObject obj, String sourceText, boolean isFromDoc) { 67 this(r, obj); 68 this.sourceText = sourceText; 69 this.documentPositions = isFromDoc; 70 } 71 72 private void createASTree() { 73 Reader r; 74 int status=-1; 75 hasSyntaxErrors = false; 76 77 try { 78 r=getReader(); 79 } catch (Exception ex) { 80 JMManager.getLog().log(ErrorManager.WARNING, "Error opening stream for: " + getResource().getName() + "; " + ex.toString()); 81 ErrorManager.getDefault().notify(ex); 82 return; 83 } 84 JParser parser=Factory.getDefault().getParser(this, r, fobj.getName()); 85 try { 86 if (JMManager.PERF_DEBUG) { 87 System.err.println("Parsing file: " + fobj.getName()); 88 Thread.dumpStack(); 89 } 90 status=parser.parse(false); } catch (Exception ex) { 92 JMManager.getLog().notify(ErrorManager.INFORMATIONAL, ex); 93 dumpSource(ex); 94 } 95 96 tokens=parser.getTokens(); 97 if (tokens == null) 98 tokens = new Token[0]; 99 100 if (status!=0) { 101 hasSyntaxErrors = true; 102 topNode = new ASTRepairer(this, parser).fixTree(); 103 } else { 104 topNode = parser.getASTree(); 105 } 106 } 107 108 Token[] getTokens() { 109 return tokens; 110 } 111 112 public Token getTokenByOffset(int offset) { 113 if (offset >= sourceText.length()) return null; 114 int lo = 0; 115 int hi = tokens.length; 116 int check; 117 int index; 118 while (true) { 119 if (lo >= hi) return null; 120 index = (hi - lo) / 2 + lo; 121 check = checkToken(tokens[index], offset); 122 if (check < 0) { 123 hi = index; 124 } else if (check > 0) { 125 lo = index + 1; 126 } else { 127 break; 128 } 129 } 130 Token result = tokens[index]; 131 Token[] paddings = result.getPadding(); 132 if (paddings != null) { 133 for (int i = paddings.length - 1; i >= 0; i--) { 134 if (paddings[i].getEndOffset() > offset) { 135 result = paddings[i]; 136 } 137 } 138 } 139 return result; 140 } 141 142 private int checkToken(Token token, int offset) { 143 Token[] padding = token.getPadding(); 144 int startOffset = padding != null && padding.length > 0 ? padding[0].getStartOffset() : token.getStartOffset(); 145 int endOffset = token.getEndOffset(); 146 if (offset < startOffset) return -1; 147 else if (offset >= endOffset) return 1; 148 else return 0; 149 } 150 151 public ASTree getASTree() { 152 if (!fobj.isValid()) 155 return null; 156 if (topNode==null) 157 createASTree(); 158 return topNode; 159 } 160 161 public boolean hasSyntaxError() { 162 return hasSyntaxErrors; 163 } 164 165 FileObject getFileObject() { 166 return fobj; 167 } 168 169 String getRealSource(boolean overridePositions) throws FileNotFoundException, UnsupportedEncodingException, IOException { 170 EditorCookie editor; 171 Document doc=null; 172 DataObject dobj=Util.getModifiedDataObject(fobj); 173 174 if (dobj!=null) { 175 editor = (EditorCookie) dobj.getCookie(EditorCookie.class); 176 if (editor!=null) { 177 doc = editor.getDocument(); 178 } 179 assert doc!=null:"Modified DO "+fobj.getPath()+" without document"; 180 if (overridePositions) 181 documentPositions = true; 182 final String [] str = new String [1]; 184 final Document doc2 = doc; 186 Runnable run = new Runnable () { 187 public void run() { 188 try { 189 str[0] = doc2.getText(0, doc2.getLength()); 190 } 191 catch (BadLocationException e) { 192 } 194 } 195 }; 196 doc.render(run); 197 return str[0]; 198 } else { 199 InputStream is = fobj.getInputStream(); 201 Reader fileReader; 202 String encoding=Util.getFileEncoding(fobj); 203 204 if (encoding == null) { 205 fileReader = new InputStreamReader(is); 206 } else { 207 fileReader = new InputStreamReader(is, encoding); 208 } 209 try { 210 return Util.readContents(fileReader,fobj.getSize()); 211 } finally { 212 fileReader.close(); 213 } 214 } 215 } 216 217 Reader getFileReader(boolean overridePositions) throws FileNotFoundException, UnsupportedEncodingException, IOException { 218 return new StringReader(getRealSource(overridePositions)); 219 } 220 221 228 public Reader getReader() throws FileNotFoundException, UnsupportedEncodingException, IOException { 229 if (sourceText==null) { 230 sourceText = getRealSource(true); 231 } 232 return new StringReader(sourceText); 233 } 234 235 public Resource getResource() { 236 return rsc; 237 } 238 239 public String getJavaDoc(ASTree tree) { 240 String javadoText=null; 241 Token javaDocToken=getComment(tree); 242 243 if (javaDocToken.getType()==DOC_COMMENT) { 244 javadoText=getText(javaDocToken); 245 } 246 return removeJavadocStars(javadoText); 247 } 248 249 public ASTree findTree(ASTree parentTree, int firstToken, int lastToken, int type) { 250 ASTree[] children = parentTree.getSubTrees(); 251 252 for (int i = 0; i < children.length; i++) { 253 ASTree ch = children[i]; 254 if (ch != null) { 255 int first = ch.getFirstToken(); 256 int last = ch.getLastToken(); 257 if (first == firstToken && last == lastToken && type == ch.getType()) { 258 return ch; 259 } 260 if (first <= firstToken && last >= lastToken) { 261 return findTree(ch, firstToken, lastToken, type); 262 } 263 } 264 } 265 throw new IllegalArgumentException ("Child tree not found (type: " + type + " firstToken: " + firstToken + " lastToken: " + lastToken + " resource: " + getResource().getName() + ")"); } 267 268 public Token getComment(ASTree t) { 269 Token first=getToken(t.getFirstToken()); 270 Token pad[]=first.getPadding(); 271 int i; 272 273 for(i=pad.length-1;i>=0;i--) { 274 Token c=pad[i]; 275 276 if (c.getType()==DOC_COMMENT) 277 return c; 278 } 279 return first; 280 } 281 282 ASTree[] check(ASTree tree) { 283 if (tree==null || tree.getType()==SEMICOLON) 284 return null; 285 return NULL_TREE; 286 } 287 288 public ASTree[] filterParts(ASTree parts[]) { 289 if (parts!=null) { 290 List typeDecl=null; 291 int i; 292 293 for (i=parts.length-1;i>=0;i--) { 294 ASTree tree=parts[i]; 295 ASTree checked[]=check(tree); 296 297 if (checked!=NULL_TREE) { 298 if (typeDecl==null) { 299 typeDecl=new ArrayList (Arrays.asList((Object []) parts)); 300 } 301 if (checked==null) 302 typeDecl.remove(i); 303 else 304 typeDecl.addAll(i, Arrays.asList((Object []) checked)); 305 } 306 } 307 if (typeDecl!=null) { 308 return (ASTree[])typeDecl.toArray(new ASTree[typeDecl.size()]); 309 } 310 } 311 return parts; 312 } 313 314 public String getText(ASTree tree) { 315 if (tree == null) { 316 return null; 317 } else { 318 return getText(tree,tree); 319 } 320 } 321 322 public String getText(ASTree first,ASTree last) { 323 int start=getToken(first.getFirstToken()).getStartOffset(); 324 int end=getToken(last.getLastToken()).getEndOffset(); 325 326 return sourceText.substring(start,end); 327 } 328 329 public String getText(Token token) { 330 int start=token.getStartOffset(); 331 int end=token.getEndOffset(); 332 333 return sourceText.substring(start,end); 334 } 335 336 public Token getToken(int index) { 337 return (index >= 0 && index < tokens.length) ? tokens[index] : null; 338 } 339 340 public ASTree getParent(ASTree tree) { 341 ASTree parent=getASTree(); 342 int index=tree.getFirstToken(); 343 344 while(true) { 345 ASTree parts[]=parent.getSubTrees(); 346 ASTree element=null; 347 int i; 348 349 for (i=0;i<parts.length;i++) { 350 element=parts[i]; 351 if (element!=null && element.getFirstToken()<=index && element.getLastToken()>=index) 352 break; 353 } 354 if (i==parts.length) 355 return parent; 356 if (element==tree) 357 return parent; 358 parent=element; 359 } 360 } 361 362 public boolean isFromDocument() { 363 return documentPositions; 364 } 365 366 383 public PositionBounds createBounds(ASTree startTree, ASTree endTree, boolean inclDoc) { 384 Token startToken; 385 if (inclDoc) { 386 startToken = getComment(startTree); 387 } else { 388 startToken = getToken(startTree.getFirstToken()); 389 } 390 Token endToken=getToken(endTree.getLastToken()); 391 392 if (startToken == null || endToken == null) { 393 RuntimeException ex; 394 String startTreeText = null; 395 String endTreeText = null; 396 try { 397 startTreeText = startTree.toString(); 398 endTreeText = endTree.toString(); 399 } catch (RuntimeException e) { 400 } 402 if (startToken == null) { 403 ex = new RuntimeException ("First token is null for ASTree: " + startTreeText + " of type: " + startTree.getType() + ";\ncalling startTree.getFirstToken() returns " + startTree.getFirstToken()); } else { 406 ex = new RuntimeException ("Last token is null for ASTree: " + endTreeText + " of type: " + endTree.getType() + ";\ncalling endTree.getLastToken() returns " + endTree.getLastToken()); } 409 ex.printStackTrace(); 410 dumpSource(ex); 411 } 412 413 return createBounds(new int[] {startToken.getStartOffset(), endToken.getEndOffset()}); 414 } 415 416 public PositionBounds createBounds(int startOffset,int endOffset) { 417 return createBounds(new int[] {startOffset, endOffset}); 418 } 419 420 public PositionBounds createBounds(int[] oldOffsets) { 421 if (editor == null) { 422 DataObject dobj; 423 try { 424 dobj=DataObject.find(fobj); 425 } catch (DataObjectNotFoundException ex) { 426 ErrorManager.getDefault().notify(ex); 427 return null; 428 } 429 editor = Util.findCloneableEditorSupport(dobj); 430 } 431 int[] offsets = getDocumentOffsets(oldOffsets); 432 433 PositionRef start=editor.createPositionRef(offsets[0], Bias.Forward); 434 PositionRef end=editor.createPositionRef(offsets[1], Bias.Backward); 435 436 return new PositionBounds(start,end); 437 } 438 439 public int[] getDocumentOffsets(int[] offsets) { 442 if (!isFromDocument()) { 443 return convertToDocumentOffsets(offsets); 444 } else { 445 return offsets; 446 } 447 } 448 449 public int[] convertToDocumentOffsets(final int[] offsets) { 450 int pos = -1; 451 int firstOffset = 0; 452 453 int[] newOffsets = (int[]) offsets.clone(); 454 int srcLastIdx = sourceText.length()-1; 455 while (pos < offsets[offsets.length - 1]) { 456 pos = sourceText.indexOf('\r',pos+1); 457 if (pos == -1) break; 458 if (pos < srcLastIdx && sourceText.charAt(pos+1) != '\n') 459 continue; 460 while ((firstOffset < offsets.length) && (offsets[firstOffset] <= pos)) { 461 firstOffset++; 462 } 463 for (int i = firstOffset; i < offsets.length; i++) { 464 newOffsets[i]--; 465 } 466 } 467 return newOffsets; 468 } 469 470 public String getSourceText() { 471 if (sourceText == null) { 472 try { 473 getReader(); 474 } catch (Exception ex) { 475 JMManager.getLog().log(ErrorManager.WARNING, "Error opening stream for: " + getResource().getName() + "; " + ex.toString()); 476 ErrorManager.getDefault().notify(ex); 477 } 478 } 479 return sourceText; 480 } 481 482 483 private static final Pattern docRegExp = Pattern.compile("\\r?\\n(\\s*\\*+)?"); 485 private static String removeJavadocStars(String rawText) { 486 if (rawText==null) 487 return null; 488 rawText="\n".concat(rawText.substring(1,rawText.length()-2)); String [] lines=docRegExp.split(rawText,Integer.MAX_VALUE); 490 StringBuffer purgedComment = new StringBuffer (rawText.length()); 491 for (int i=1; i<lines.length; i++) { 492 if ((i+1)==lines.length) { 493 if (lines[i].trim().length() != 0) { 494 purgedComment.append(lines[i]); 495 } 496 } 497 else { 498 purgedComment.append(lines[i]).append('\n'); } 500 } 501 return purgedComment.toString(); 502 } 503 504 public ASTree getRootTree() { 506 return getASTree(); 507 } 508 509 public String getSourceLevel() { 510 return SourceLevelQuery.getSourceLevel(fobj); 511 } 512 513 public String getClassPath() { 514 return null; 515 } 516 517 public ErrConsumer getErrorConsumer() { 518 return null; 519 } 520 521 531 private void dumpSource(Exception exc) { 532 String dumpDir = System.getProperty("netbeans.user") + "/var/log/"; String src = getSourceText(); 534 String rscName = getResource() == null ? "null" : getResource().getName(); 535 int pos = rscName.lastIndexOf('/'); 536 String origName; 537 if (pos >= 0) { 538 origName = rscName.substring(pos + 1); 539 } else { 540 origName = rscName; 541 } 542 String name = null; 543 File f = new File(dumpDir + origName + ".dump"); int i = 1; 545 while (i < 255) { 546 if (!f.exists()) 547 break; 548 f = new File(dumpDir + origName + '_' + i + ".dump"); i++; 550 } 551 if (!f.exists()) { 552 try { 553 OutputStream os = new FileOutputStream(f); 554 PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, "UTF-8")); try { 556 writer.println(src); 557 writer.println("----- Original exception ---------------------------------------------"); exc.printStackTrace(writer); 559 name = f.getName(); 560 } finally { 561 writer.close(); 562 } 563 } catch (IOException ioe) { 564 ErrorManager.getDefault().annotate(ioe, ErrorManager.UNKNOWN, "Error when writing parser dump file!", null, null, null); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe); 566 name = null; 567 } 568 } 569 if (name != null) { 570 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, new RuntimeException ("Invalid AST returned from parser or error parsing \'" + rscName + "\'. Please report a bug against java module and attach dump file '" + dumpDir + name + "'.")); } else { 573 ErrorManager.getDefault().log(ErrorManager.WARNING, 574 "Dump could not be written. Either dump file could not " + "be created or all dump files were already used. Please " + "check that you have write permission to '" + dumpDir + "' and " + "clean all *.dump files in that directory."); } 579 } 580 581 public String toString() { 582 return "ASTProvider@" + System.identityHashCode(this) + " for \"" + getResource().getName() + "\""; 583 } 584 } 585 | Popular Tags |