1 /* 2 * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.jvm; 27 28 import java.util.*; 29 30 import com.sun.tools.javac.resources.CompilerProperties.Warnings; 31 import com.sun.tools.javac.tree.*; 32 import com.sun.tools.javac.util.*; 33 import com.sun.tools.javac.util.List; 34 import com.sun.tools.javac.tree.JCTree.*; 35 import com.sun.tools.javac.tree.EndPosTable; 36 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression; 37 38 /** This class contains the CharacterRangeTable for some method 39 * and the hashtable for mapping trees or lists of trees to their 40 * ending positions. 41 * 42 * <p><b>This is NOT part of any supported API. 43 * If you write code that depends on this, you do so at your own risk. 44 * This code and its internal interfaces are subject to change or 45 * deletion without notice.</b> 46 */ 47 public class CRTable 48 implements CRTFlags { 49 50 private final boolean crtDebug = false; 51 52 /** The list of CRTable entries. 53 */ 54 private ListBuffer<CRTEntry> entries = new ListBuffer<>(); 55 56 /** The hashtable for source positions. 57 */ 58 private Map<Object,SourceRange> positions = new HashMap<>(); 59 60 /** The object for ending positions stored in the parser. 61 */ 62 private EndPosTable endPosTable; 63 64 /** The tree of the method this table is intended for. 65 * We should traverse this tree to get source ranges. 66 */ 67 JCTree.JCMethodDecl methodTree; 68 69 /** Constructor 70 */ CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable)71 public CRTable(JCTree.JCMethodDecl tree, EndPosTable endPosTable) { 72 this.methodTree = tree; 73 this.endPosTable = endPosTable; 74 } 75 76 /** Create a new CRTEntry and add it to the entries. 77 * @param tree The tree or the list of trees for which 78 * we are storing the code pointers. 79 * @param flags The set of flags designating type of the entry. 80 * @param startPc The starting code position. 81 * @param endPc The ending code position. 82 */ put(Object tree, int flags, int startPc, int endPc)83 public void put(Object tree, int flags, int startPc, int endPc) { 84 entries.append(new CRTEntry(tree, flags, startPc, endPc)); 85 } 86 87 /** Compute source positions and write CRT to the databuf. 88 * @param databuf The buffer to write bytecodes to. 89 */ writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log)90 public int writeCRT(ByteBuffer databuf, Position.LineMap lineMap, Log log) { 91 92 int crtEntries = 0; 93 94 // compute source positions for the method 95 new SourceComputer().csp(methodTree); 96 97 for (List<CRTEntry> l = entries.toList(); l.nonEmpty(); l = l.tail) { 98 99 CRTEntry entry = l.head; 100 101 // eliminate entries that do not produce bytecodes: 102 // for example, empty blocks and statements 103 if (entry.startPc == entry.endPc) 104 continue; 105 106 SourceRange pos = positions.get(entry.tree); 107 Assert.checkNonNull(pos, "CRT: tree source positions are undefined"); 108 if ((pos.startPos == Position.NOPOS) || (pos.endPos == Position.NOPOS)) 109 continue; 110 111 if (crtDebug) { 112 System.out.println("Tree: " + entry.tree + ", type:" + getTypes(entry.flags)); 113 System.out.print("Start: pos = " + pos.startPos + ", pc = " + entry.startPc); 114 } 115 116 // encode startPos into line/column representation 117 int startPos = encodePosition(pos.startPos, lineMap, log); 118 if (startPos == Position.NOPOS) 119 continue; 120 121 if (crtDebug) { 122 System.out.print("End: pos = " + pos.endPos + ", pc = " + (entry.endPc - 1)); 123 } 124 125 // encode endPos into line/column representation 126 int endPos = encodePosition(pos.endPos, lineMap, log); 127 if (endPos == Position.NOPOS) 128 continue; 129 130 // write attribute 131 databuf.appendChar(entry.startPc); 132 // 'endPc - 1' because endPc actually points to start of the next command 133 databuf.appendChar(entry.endPc - 1); 134 databuf.appendInt(startPos); 135 databuf.appendInt(endPos); 136 databuf.appendChar(entry.flags); 137 138 crtEntries++; 139 } 140 141 return crtEntries; 142 } 143 144 /** Return the number of the entries. 145 */ length()146 public int length() { 147 return entries.length(); 148 } 149 150 /** Return string describing flags enabled. 151 */ getTypes(int flags)152 private String getTypes(int flags) { 153 String types = ""; 154 if ((flags & CRT_STATEMENT) != 0) types += " CRT_STATEMENT"; 155 if ((flags & CRT_BLOCK) != 0) types += " CRT_BLOCK"; 156 if ((flags & CRT_ASSIGNMENT) != 0) types += " CRT_ASSIGNMENT"; 157 if ((flags & CRT_FLOW_CONTROLLER) != 0) types += " CRT_FLOW_CONTROLLER"; 158 if ((flags & CRT_FLOW_TARGET) != 0) types += " CRT_FLOW_TARGET"; 159 if ((flags & CRT_INVOKE) != 0) types += " CRT_INVOKE"; 160 if ((flags & CRT_CREATE) != 0) types += " CRT_CREATE"; 161 if ((flags & CRT_BRANCH_TRUE) != 0) types += " CRT_BRANCH_TRUE"; 162 if ((flags & CRT_BRANCH_FALSE) != 0) types += " CRT_BRANCH_FALSE"; 163 return types; 164 } 165 166 /** Source file positions in CRT are integers in the format: 167 * {@literal line-number << LINESHIFT + column-number } 168 */ encodePosition(int pos, Position.LineMap lineMap, Log log)169 private int encodePosition(int pos, Position.LineMap lineMap, Log log) { 170 int line = lineMap.getLineNumber(pos); 171 int col = lineMap.getColumnNumber(pos); 172 int new_pos = Position.encodePosition(line, col); 173 if (crtDebug) { 174 System.out.println(", line = " + line + ", column = " + col + 175 ", new_pos = " + new_pos); 176 } 177 if (new_pos == Position.NOPOS) 178 log.warning(pos, Warnings.PositionOverflow(line)); 179 180 return new_pos; 181 } 182 183 /* ************************************************************************ 184 * Traversal methods 185 *************************************************************************/ 186 187 /** 188 * This class contains methods to compute source positions for trees. 189 * Extends Tree.Visitor to traverse the abstract syntax tree. 190 */ 191 class SourceComputer extends JCTree.Visitor { 192 193 /** The result of the tree traversal methods. 194 */ 195 SourceRange result; 196 197 /** Visitor method: compute source positions for a single node. 198 */ csp(JCTree tree)199 public SourceRange csp(JCTree tree) { 200 if (tree == null) return null; 201 tree.accept(this); 202 if (result != null) { 203 positions.put(tree, result); 204 } 205 return result; 206 } 207 208 /** Visitor method: compute source positions for a list of nodes. 209 */ csp(List<? extends JCTree> trees)210 public SourceRange csp(List<? extends JCTree> trees) { 211 if ((trees == null) || !(trees.nonEmpty())) return null; 212 SourceRange list_sr = new SourceRange(); 213 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) { 214 list_sr.mergeWith(csp(l.head)); 215 } 216 positions.put(trees, list_sr); 217 return list_sr; 218 } 219 220 /** Visitor method: compute source positions for 221 * a list of case blocks of switch statements. 222 */ cspCases(List<JCCase> trees)223 public SourceRange cspCases(List<JCCase> trees) { 224 if ((trees == null) || !(trees.nonEmpty())) return null; 225 SourceRange list_sr = new SourceRange(); 226 for (List<JCCase> l = trees; l.nonEmpty(); l = l.tail) { 227 list_sr.mergeWith(csp(l.head)); 228 } 229 positions.put(trees, list_sr); 230 return list_sr; 231 } 232 233 /** Visitor method: compute source positions for 234 * a list of catch clauses in try statements. 235 */ cspCatchers(List<JCCatch> trees)236 public SourceRange cspCatchers(List<JCCatch> trees) { 237 if ((trees == null) || !(trees.nonEmpty())) return null; 238 SourceRange list_sr = new SourceRange(); 239 for (List<JCCatch> l = trees; l.nonEmpty(); l = l.tail) { 240 list_sr.mergeWith(csp(l.head)); 241 } 242 positions.put(trees, list_sr); 243 return list_sr; 244 } 245 visitMethodDef(JCMethodDecl tree)246 public void visitMethodDef(JCMethodDecl tree) { 247 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 248 sr.mergeWith(csp(tree.body)); 249 result = sr; 250 } 251 visitVarDef(JCVariableDecl tree)252 public void visitVarDef(JCVariableDecl tree) { 253 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 254 csp(tree.vartype); 255 sr.mergeWith(csp(tree.init)); 256 result = sr; 257 } 258 visitSkip(JCSkip tree)259 public void visitSkip(JCSkip tree) { 260 // endPos is the same as startPos for the empty statement 261 SourceRange sr = new SourceRange(startPos(tree), startPos(tree)); 262 result = sr; 263 } 264 visitBlock(JCBlock tree)265 public void visitBlock(JCBlock tree) { 266 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 267 csp(tree.stats); // doesn't compare because block's ending position is defined 268 result = sr; 269 } 270 visitDoLoop(JCDoWhileLoop tree)271 public void visitDoLoop(JCDoWhileLoop tree) { 272 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 273 sr.mergeWith(csp(tree.body)); 274 sr.mergeWith(csp(tree.cond)); 275 result = sr; 276 } 277 visitWhileLoop(JCWhileLoop tree)278 public void visitWhileLoop(JCWhileLoop tree) { 279 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 280 sr.mergeWith(csp(tree.cond)); 281 sr.mergeWith(csp(tree.body)); 282 result = sr; 283 } 284 visitForLoop(JCForLoop tree)285 public void visitForLoop(JCForLoop tree) { 286 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 287 sr.mergeWith(csp(tree.init)); 288 sr.mergeWith(csp(tree.cond)); 289 sr.mergeWith(csp(tree.step)); 290 sr.mergeWith(csp(tree.body)); 291 result = sr; 292 } 293 visitForeachLoop(JCEnhancedForLoop tree)294 public void visitForeachLoop(JCEnhancedForLoop tree) { 295 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 296 sr.mergeWith(csp(tree.var)); 297 sr.mergeWith(csp(tree.expr)); 298 sr.mergeWith(csp(tree.body)); 299 result = sr; 300 } 301 visitLabelled(JCLabeledStatement tree)302 public void visitLabelled(JCLabeledStatement tree) { 303 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 304 sr.mergeWith(csp(tree.body)); 305 result = sr; 306 } 307 visitSwitch(JCSwitch tree)308 public void visitSwitch(JCSwitch tree) { 309 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 310 sr.mergeWith(csp(tree.selector)); 311 sr.mergeWith(cspCases(tree.cases)); 312 result = sr; 313 } 314 315 @Override visitSwitchExpression(JCSwitchExpression tree)316 public void visitSwitchExpression(JCSwitchExpression tree) { 317 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 318 sr.mergeWith(csp(tree.selector)); 319 sr.mergeWith(cspCases(tree.cases)); 320 result = sr; 321 } 322 visitCase(JCCase tree)323 public void visitCase(JCCase tree) { 324 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 325 sr.mergeWith(csp(tree.pats)); 326 sr.mergeWith(csp(tree.stats)); 327 result = sr; 328 } 329 visitSynchronized(JCSynchronized tree)330 public void visitSynchronized(JCSynchronized tree) { 331 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 332 sr.mergeWith(csp(tree.lock)); 333 sr.mergeWith(csp(tree.body)); 334 result = sr; 335 } 336 visitTry(JCTry tree)337 public void visitTry(JCTry tree) { 338 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 339 sr.mergeWith(csp(tree.resources)); 340 sr.mergeWith(csp(tree.body)); 341 sr.mergeWith(cspCatchers(tree.catchers)); 342 sr.mergeWith(csp(tree.finalizer)); 343 result = sr; 344 } 345 visitCatch(JCCatch tree)346 public void visitCatch(JCCatch tree) { 347 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 348 sr.mergeWith(csp(tree.param)); 349 sr.mergeWith(csp(tree.body)); 350 result = sr; 351 } 352 visitConditional(JCConditional tree)353 public void visitConditional(JCConditional tree) { 354 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 355 sr.mergeWith(csp(tree.cond)); 356 sr.mergeWith(csp(tree.truepart)); 357 sr.mergeWith(csp(tree.falsepart)); 358 result = sr; 359 } 360 visitIf(JCIf tree)361 public void visitIf(JCIf tree) { 362 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 363 sr.mergeWith(csp(tree.cond)); 364 sr.mergeWith(csp(tree.thenpart)); 365 sr.mergeWith(csp(tree.elsepart)); 366 result = sr; 367 } 368 visitExec(JCExpressionStatement tree)369 public void visitExec(JCExpressionStatement tree) { 370 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 371 sr.mergeWith(csp(tree.expr)); 372 result = sr; 373 } 374 visitBreak(JCBreak tree)375 public void visitBreak(JCBreak tree) { 376 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 377 result = sr; 378 } 379 visitYield(JCYield tree)380 public void visitYield(JCYield tree) { 381 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 382 result = sr; 383 } 384 visitContinue(JCContinue tree)385 public void visitContinue(JCContinue tree) { 386 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 387 result = sr; 388 } 389 visitReturn(JCReturn tree)390 public void visitReturn(JCReturn tree) { 391 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 392 sr.mergeWith(csp(tree.expr)); 393 result = sr; 394 } 395 visitThrow(JCThrow tree)396 public void visitThrow(JCThrow tree) { 397 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 398 sr.mergeWith(csp(tree.expr)); 399 result = sr; 400 } 401 visitAssert(JCAssert tree)402 public void visitAssert(JCAssert tree) { 403 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 404 sr.mergeWith(csp(tree.cond)); 405 sr.mergeWith(csp(tree.detail)); 406 result = sr; 407 } 408 visitApply(JCMethodInvocation tree)409 public void visitApply(JCMethodInvocation tree) { 410 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 411 sr.mergeWith(csp(tree.meth)); 412 sr.mergeWith(csp(tree.args)); 413 result = sr; 414 } 415 visitNewClass(JCNewClass tree)416 public void visitNewClass(JCNewClass tree) { 417 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 418 sr.mergeWith(csp(tree.encl)); 419 sr.mergeWith(csp(tree.clazz)); 420 sr.mergeWith(csp(tree.args)); 421 sr.mergeWith(csp(tree.def)); 422 result = sr; 423 } 424 visitNewArray(JCNewArray tree)425 public void visitNewArray(JCNewArray tree) { 426 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 427 sr.mergeWith(csp(tree.elemtype)); 428 sr.mergeWith(csp(tree.dims)); 429 sr.mergeWith(csp(tree.elems)); 430 result = sr; 431 } 432 visitParens(JCParens tree)433 public void visitParens(JCParens tree) { 434 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 435 sr.mergeWith(csp(tree.expr)); 436 result = sr; 437 } 438 visitAssign(JCAssign tree)439 public void visitAssign(JCAssign tree) { 440 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 441 sr.mergeWith(csp(tree.lhs)); 442 sr.mergeWith(csp(tree.rhs)); 443 result = sr; 444 } 445 visitAssignop(JCAssignOp tree)446 public void visitAssignop(JCAssignOp tree) { 447 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 448 sr.mergeWith(csp(tree.lhs)); 449 sr.mergeWith(csp(tree.rhs)); 450 result = sr; 451 } 452 visitUnary(JCUnary tree)453 public void visitUnary(JCUnary tree) { 454 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 455 sr.mergeWith(csp(tree.arg)); 456 result = sr; 457 } 458 visitBinary(JCBinary tree)459 public void visitBinary(JCBinary tree) { 460 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 461 sr.mergeWith(csp(tree.lhs)); 462 sr.mergeWith(csp(tree.rhs)); 463 result = sr; 464 } 465 visitTypeCast(JCTypeCast tree)466 public void visitTypeCast(JCTypeCast tree) { 467 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 468 sr.mergeWith(csp(tree.clazz)); 469 sr.mergeWith(csp(tree.expr)); 470 result = sr; 471 } 472 visitTypeTest(JCInstanceOf tree)473 public void visitTypeTest(JCInstanceOf tree) { 474 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 475 sr.mergeWith(csp(tree.expr)); 476 sr.mergeWith(csp(tree.clazz)); 477 result = sr; 478 } 479 visitIndexed(JCArrayAccess tree)480 public void visitIndexed(JCArrayAccess tree) { 481 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 482 sr.mergeWith(csp(tree.indexed)); 483 sr.mergeWith(csp(tree.index)); 484 result = sr; 485 } 486 visitSelect(JCFieldAccess tree)487 public void visitSelect(JCFieldAccess tree) { 488 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 489 sr.mergeWith(csp(tree.selected)); 490 result = sr; 491 } 492 visitIdent(JCIdent tree)493 public void visitIdent(JCIdent tree) { 494 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 495 result = sr; 496 } 497 visitLiteral(JCLiteral tree)498 public void visitLiteral(JCLiteral tree) { 499 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 500 result = sr; 501 } 502 visitTypeIdent(JCPrimitiveTypeTree tree)503 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 504 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 505 result = sr; 506 } 507 visitTypeArray(JCArrayTypeTree tree)508 public void visitTypeArray(JCArrayTypeTree tree) { 509 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 510 sr.mergeWith(csp(tree.elemtype)); 511 result = sr; 512 } 513 visitTypeApply(JCTypeApply tree)514 public void visitTypeApply(JCTypeApply tree) { 515 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 516 sr.mergeWith(csp(tree.clazz)); 517 sr.mergeWith(csp(tree.arguments)); 518 result = sr; 519 } 520 521 @Override visitLetExpr(LetExpr tree)522 public void visitLetExpr(LetExpr tree) { 523 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 524 sr.mergeWith(csp(tree.defs)); 525 sr.mergeWith(csp(tree.expr)); 526 result = sr; 527 } 528 visitTypeParameter(JCTypeParameter tree)529 public void visitTypeParameter(JCTypeParameter tree) { 530 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 531 sr.mergeWith(csp(tree.bounds)); 532 result = sr; 533 } 534 535 @Override visitTypeUnion(JCTypeUnion tree)536 public void visitTypeUnion(JCTypeUnion tree) { 537 SourceRange sr = new SourceRange(startPos(tree), endPos(tree)); 538 sr.mergeWith(csp(tree.alternatives)); 539 result = sr; 540 } 541 visitWildcard(JCWildcard tree)542 public void visitWildcard(JCWildcard tree) { 543 result = null; 544 } 545 visitErroneous(JCErroneous tree)546 public void visitErroneous(JCErroneous tree) { 547 result = null; 548 } 549 visitTree(JCTree tree)550 public void visitTree(JCTree tree) { 551 Assert.error(); 552 } 553 554 /** The start position of given tree. 555 */ startPos(JCTree tree)556 public int startPos(JCTree tree) { 557 if (tree == null) return Position.NOPOS; 558 return TreeInfo.getStartPos(tree); 559 } 560 561 /** The end position of given tree, if it has 562 * defined endpos, NOPOS otherwise. 563 */ endPos(JCTree tree)564 public int endPos(JCTree tree) { 565 if (tree == null) return Position.NOPOS; 566 return TreeInfo.getEndPos(tree, endPosTable); 567 } 568 } 569 570 /** This class contains a CharacterRangeTableEntry. 571 */ 572 static class CRTEntry { 573 574 /** A tree or a list of trees to obtain source positions. 575 */ 576 Object tree; 577 578 /** The flags described in the CharacterRangeTable spec. 579 */ 580 int flags; 581 582 /** The starting code position of this entry. 583 */ 584 int startPc; 585 586 /** The ending code position of this entry. 587 */ 588 int endPc; 589 590 /** Constructor */ CRTEntry(Object tree, int flags, int startPc, int endPc)591 CRTEntry(Object tree, int flags, int startPc, int endPc) { 592 this.tree = tree; 593 this.flags = flags; 594 this.startPc = startPc; 595 this.endPc = endPc; 596 } 597 } 598 599 600 /** This class contains source positions 601 * for some tree or list of trees. 602 */ 603 static class SourceRange { 604 605 /** The starting source position. 606 */ 607 int startPos; 608 609 /** The ending source position. 610 */ 611 int endPos; 612 613 /** Constructor */ SourceRange()614 SourceRange() { 615 startPos = Position.NOPOS; 616 endPos = Position.NOPOS; 617 } 618 619 /** Constructor */ SourceRange(int startPos, int endPos)620 SourceRange(int startPos, int endPos) { 621 this.startPos = startPos; 622 this.endPos = endPos; 623 } 624 625 /** Compare the starting and the ending positions 626 * of the source range and combines them assigning 627 * the widest range to this. 628 */ mergeWith(SourceRange sr)629 SourceRange mergeWith(SourceRange sr) { 630 if (sr == null) return this; 631 if (startPos == Position.NOPOS) 632 startPos = sr.startPos; 633 else if (sr.startPos != Position.NOPOS) 634 startPos = (startPos < sr.startPos ? startPos : sr.startPos); 635 if (endPos == Position.NOPOS) 636 endPos = sr.endPos; 637 else if (sr.endPos != Position.NOPOS) 638 endPos = (endPos > sr.endPos ? endPos : sr.endPos); 639 return this; 640 } 641 } 642 643 } 644