Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 439   Methods: 35
NCLOC: 219   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ReducedModelControl.java 23.8% 34.5% 60% 36.4%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.model.definitions.reducedmodel;
 38   
 39    import java.util.ArrayList;
 40   
 41    import edu.rice.cs.util.UnexpectedException;
 42   
 43    /** This class provides an implementation of the BraceReduction interface for brace matching. In order to correctly
 44    * match, this class keeps track of what is commented (line and block) and what is inside double quotes (strings).
 45    * To avoid unnecessary complication, this class maintains a few invariants for its consistent states, i.e., between
 46    * top-level function calls.
 47    * <ol>
 48    * <li> The cursor offset is never at the end of a brace. If movement or insertion puts it there, the cursor is
 49    * updated to point to the 0 offset of the next brace. (token?)
 50    * <li> Quoting information is invalid inside valid comments. When part of the document becomes uncommented, the
 51    * reduced model must update the quoting information linearly in the newly revealed code.
 52    * <li> Quote shadowing and comment shadowing are mutually exclusive.
 53    * <li> There is no nesting of comment open characters. If // is encountered in the middle of a comment, it is
 54    * treated as two separate slashes. Similarly for /*.
 55    * </ol>
 56    * All of the code in the class assumes that the document read lock and the lock on this are held.
 57    * @author JavaPLT
 58    * @version $Id: ReducedModelControl.java 5175 2010-01-20 08:46:32Z mgricken $
 59    */
 60    public class ReducedModelControl implements BraceReduction {
 61    /* private fields; default visibility for testing purposes only. */
 62    final ReducedModelBrace _rmb; // the reduced brace model
 63    final ReducedModelComment _rmc; // the reduced comment model
 64    volatile int _offset;
 65   
 66    /** Standard constructor. */
 67  1582 public ReducedModelControl() {
 68  1582 _rmb = new ReducedModelBrace(this);
 69  1582 _rmc = new ReducedModelComment();
 70    }
 71   
 72    /** @return the absolute offset of the cursor in the brace model, which is expensive. Used for testing purposes only.
 73    * This value should agree with commentCursorOffset().
 74    */
 75  0 public int braceCursorOffset() { return _rmb.absOffset(); }
 76    /** @return the absolute offset of the cursor in the comment model, which is expensive. Used for testing purposes
 77    * only. This value should agree with braceCursorOffset().
 78    */
 79  0 public int commentCursorOffset() { return _rmc.absOffset(); }
 80   
 81    /** @return the absolute offset of the walker in the comment model, which is expensive. Used for testing purposes only. */
 82  0 public int walkerOffset() { return _rmc.walkerOffset(); }
 83   
 84    // private ReducedModelBrace _getRMB() { return _rmb; }
 85   
 86    // private ReducedModelComment _getRMC() { return _rmc; }
 87   
 88  62498 public void insertChar(char ch) {
 89  62498 _rmb.insertChar(ch);
 90  62498 _rmc.insertChar(ch);
 91    }
 92   
 93    /** Updates the BraceReduction to reflect cursor movement. Negative values move left; positive values move right.
 94    * ASSUMES that count is within range, i.e. that 0 <= absOffset() + count <= getLength
 95    * NOTE: this method does NOT move the _walker in ReduceModelComment.
 96    * @param count indicates the direction and magnitude of cursor movement
 97    */
 98  474470 public void move(int count) {
 99  474470 try {
 100  474470 _rmb.move(count);
 101  474468 _rmc.move(count);
 102    }
 103    catch(IllegalArgumentException e) {
 104  2 resetLocation(); // Why reset the _walker here?
 105  2 throw new UnexpectedException(e);
 106    }
 107    }
 108   
 109    /** Updates the BraceReduction to reflect text deletion. Assumes that count is within range!
 110    * @param count A number indicating the size and direction of text deletion. Negative values delete text to the left
 111    * of the cursor, positive values delete text to the right.
 112    */
 113  337 public void delete(int count) {
 114  337 _rmb.delete(count);
 115  337 _rmc.delete(count);
 116    }
 117   
 118    /** Determines if cursor position is shadowed by comment or string (does not include opening comment or quotation "brace"). */
 119  185777 public boolean isShadowed() { return _rmc.isShadowed(); }
 120   
 121    /** Determines if current token is either shadowed or an opening comment brace ("//" or "/*"). */
 122  0 public boolean isWeaklyShadowed() { return _rmc.isWeaklyShadowed(); }
 123   
 124    /** Finds the closing brace that matches the next significant brace iff that brace is an open brace. Fails when
 125    * brace is shadowed. </P>
 126    * @return the distance until the matching closing brace. On failure, returns -1.
 127    * @see #balanceBackward()
 128    */
 129  3982 public int balanceForward() { return _rmb.balanceForward(); }
 130   
 131    /** Finds the open brace that matches the previous significant brace iff that brace is an closing brace. Fails when
 132    * brace is shadowed. </P>
 133    * @return the distance until the matching open brace. On failure, returns -1.
 134    * @see #balanceForward()
 135    */
 136  94 public int balanceBackward() { return _rmb.balanceBackward(); }
 137   
 138    /** Returns the state at the relDistance, where relDistance is relative to the last time it was called. You can reset
 139    * the last call to the current offset using resetLocation.
 140    */
 141  8011 public ReducedModelState moveWalkerGetState(int relDistance) { return _rmc.moveWalkerGetState(relDistance); }
 142   
 143    /** This function resets the location of the walker in the comment list to where the current cursor is. This allows
 144    * the walker to keep walking and using relative distance instead of having to rewalk the same distance every call
 145    * to stateAtRelLocation. It is an optimization.
 146    */
 147  5526 public void resetLocation() { _rmc.resetWalkerLocationToCursor(); }
 148   
 149    /** Gets the token currently pointed at by the cursor. Because the reduced model is split into two reduced sub-models,
 150    * we have to check each sub-model first as each one has unique information. If we find a non-gap token in either
 151    * sub-model we want to return that. Otherwise, we want to return a sort of hybrid Gap of the two, i.e., a Gap where
 152    * there are neither special comment/quote tokens nor parens/squigglies/brackets.
 153    * @return a ReducedToken representative of the unified reduced model
 154    */
 155  454 public ReducedToken currentToken() {
 156    // check the reduced comment model for specials
 157  454 ReducedToken rmcToken = _rmc.current();
 158  361 if (! rmcToken.isGap()) return rmcToken;
 159    // check the reduced brace model for braces
 160  93 ReducedToken rmbToken = _rmb.current();
 161  93 if (! rmbToken.isGap()) {
 162  30 rmbToken.setState(_rmc.getStateAtCurrent());
 163  30 return rmbToken;
 164    }
 165    // otherwise, we have a gap.
 166  63 int size = getSize(rmbToken,rmcToken);
 167  63 return new Gap(size, _rmc.getStateAtCurrent());
 168    }
 169   
 170    /** Gets the shadowing state at the current caret position.
 171    * @return FREE|INSIDE_LINE_COMMENT|INSIDE_BLOCK_COMMENT|
 172    * INSIDE_SINGLE_QUOTE|INSIDE_DOUBLE_QUOTE
 173    */
 174  87556 public ReducedModelState getStateAtCurrent() { return _rmc.getStateAtCurrent(); }
 175   
 176    /** Get a string representation of the current token's type.
 177    * @return "" if current is a Gap, otherwise, use ReducedToken.getType()
 178    */
 179  0 String getType() {
 180  0 ReducedToken rmcToken = _rmc.current();
 181  0 if (! rmcToken.isGap())
 182  0 return rmcToken.getType();
 183   
 184  0 ReducedToken rmbToken = _rmb.current();
 185  0 if (! rmbToken.isGap()) {
 186  0 return rmbToken.getType();
 187    }
 188  0 return ""; //a gap
 189    }
 190   
 191    /** Gets the size of the current token. It checks both the brace and comment sub-models to find the size of the
 192    * current token. If the current token is a Gap, we have to reconcile the information of both sub-models in order
 193    * to get the correct size of the current token as seen by the outside world.
 194    * @return the number of characters represented by the current token
 195    */
 196  0 int getSize() {
 197  0 return getSize(_rmb.current(),_rmc.current());
 198    }
 199   
 200  63 int getSize(ReducedToken rmbToken, ReducedToken rmcToken) {
 201  63 int rmb_offset = _rmb.getBlockOffset();
 202  63 int rmc_offset = _rmc.getBlockOffset();
 203  63 int rmb_size = rmbToken.getSize();
 204  63 int rmc_size = rmcToken.getSize();
 205  63 int size;
 206  63 if (rmb_offset < rmc_offset) {
 207  2 size = rmb_offset;
 208  2 _offset = size;
 209    }
 210    else {
 211  61 size = rmc_offset;
 212  61 _offset = size;
 213    }
 214   
 215  63 if (rmb_size - rmb_offset < rmc_size - rmc_offset) {
 216  2 size += (rmb_size - rmb_offset);
 217    }
 218    else {
 219  61 size += (rmc_size - rmc_offset);
 220    }
 221  63 return size;
 222    }
 223   
 224    /** Move the reduced model to the next token (with 0 offset) and update the cursor information. */
 225  0 void next() {
 226  0 if (_rmc._cursor.atStart()) {
 227  0 _rmc.next();
 228  0 _rmb.next();
 229  0 return;
 230    }
 231  0 int size = getSize(_rmb.current(), _rmc.current());
 232  0 _rmc.move(size - _offset);
 233  0 _rmb.move(size - _offset);
 234    }
 235   
 236    /** Move the reduced model to the previous token and update the cursor information. */
 237  0 void prev() {
 238  0 int size;
 239  0 if (_rmc._cursor.atEnd()) {
 240  0 _rmc.prev();
 241  0 _rmb.prev();
 242  0 if (_rmc._cursor.atStart()) {
 243  0 return; // because in place now.
 244    }
 245   
 246  0 if (_rmc.current().getSize() < _rmb.current().getSize()) {
 247  0 size = -_rmc.current().getSize();
 248    }
 249    else {
 250  0 size = -_rmb.current().getSize();
 251    }
 252  0 _rmc.next();
 253  0 _rmb.next();
 254  0 move(size);
 255    }
 256  0 else if (_rmb.getBlockOffset() < _rmc.getBlockOffset()) {
 257  0 _rmb.prev();
 258  0 size = _rmb.current().getSize() + _rmb.getBlockOffset();
 259  0 _rmb.next();
 260  0 if (size < _rmc.getBlockOffset()) {
 261  0 move(-size);
 262    }
 263    else {
 264  0 move(-_rmc.getBlockOffset());
 265    }
 266    }
 267  0 else if (_rmb.getBlockOffset() == _rmc.getBlockOffset()) {
 268  0 _rmb.prev();
 269  0 _rmc.prev();
 270  0 _rmb.setBlockOffset(0);
 271  0 _rmc.setBlockOffset(0);
 272    }
 273    else {
 274  0 _rmc.prev();
 275  0 size = _rmc.current().getSize() + _rmc.getBlockOffset();
 276  0 _rmc.next();
 277  0 if (size < _rmb.getBlockOffset()) {
 278  0 move(-size);
 279    }
 280    else {
 281  0 move(-_rmb.getBlockOffset());
 282    }
 283    }
 284    }
 285   
 286    /** Get the previous token. */
 287  0 public ReducedToken prevItem() {
 288  0 int rmbOffset = _rmb.getBlockOffset();
 289  0 int rmcOffset = _rmc.getBlockOffset();
 290   
 291  0 prev();
 292  0 ReducedToken temp = currentToken();
 293  0 next();
 294   
 295  0 _rmb.setBlockOffset(rmbOffset);
 296  0 _rmc.setBlockOffset(rmcOffset);
 297  0 return temp;
 298    }
 299   
 300    /** Get the next token. */
 301  0 public ReducedToken nextItem() {
 302  0 int rmbOffset = _rmb.getBlockOffset();
 303  0 int rmcOffset = _rmc.getBlockOffset();
 304  0 next();
 305  0 ReducedToken temp = currentToken();
 306  0 prev();
 307  0 _rmb.setBlockOffset(rmbOffset);
 308  0 _rmc.setBlockOffset(rmcOffset);
 309  0 return temp;
 310    }
 311   
 312    /** Determines if the cursor is at the end of the reduced model. */
 313  9 boolean atEnd() { return (_rmb._cursor.atEnd() || _rmc._cursor.atEnd()); }
 314   
 315    /** Determines if the cursor is at the start of the reduced model. */
 316  1 boolean atStart() { return (_rmb._cursor.atStart() || _rmc._cursor.atStart()); }
 317   
 318    /** Gets the offset within the current token. */
 319  4 int getBlockOffset() {
 320  0 if (_rmb.getBlockOffset() < _rmc.getBlockOffset()) return _rmb.getBlockOffset();
 321  4 return _rmc.getBlockOffset();
 322    }
 323   
 324    /** Gets the absolute character offset into the document represented by the reduced model. */
 325  130 public int absOffset() {
 326  130 int offset = _rmc.absOffset();
 327  130 assert offset == _rmb.absOffset();
 328  130 return offset;
 329    }
 330   
 331   
 332    /** A toString() substitute. */
 333  0 public String simpleString() {
 334  0 return "\n********\n" + _rmb.simpleString() + "\n________\n" + _rmc.simpleString();
 335    }
 336   
 337    // /** Returns an IndentInfo containing the following information:
 338    // * - distance to the previous newline (start of this line)
 339    // * - distance to the brace enclosing the beginning of the current line
 340    // * - distance to the beginning of the line containing that brace
 341    // */
 342    // public IndentInfo getIndentInformation() {
 343    // IndentInfo info = new IndentInfo();
 344    // //get distance to the previous newline (in info.distToStart)
 345    //// System.err.println("Before calls, info = " + info);
 346    // _rmc.getDistToStart(info);
 347    //// System.err.println("After getDistToStart, info = " + info);
 348    // //get distance to the closing brace before that new line.
 349    // _rmb.getDistToLineEnclosingBrace(info);
 350    //// System.err.println("After getDistToLineEnclosingBrace, info = " + info);
 351    // //get distance to newline before the previous, just mentioned, brace.
 352    // _rmc.getDistToLineEnclosingBraceStart(info);
 353    //// System.err.println("After getDistToLineEnclosingBraceStart info = " + info);
 354    // // get distance to the brace enclosing the current location
 355    // _rmb.getDistToEnclosingBrace(info);
 356    //// System.err.println("After getDistToEnclosingBrace, info = " + info);
 357    // // get distance to the beginning of that brace's line
 358    // _rmc.getDistToEnclosingBraceStart(info);
 359    //// System.err.println("After getDistToEnclosingBraceStart, info = " + info);
 360    // return info;
 361    // }
 362   
 363  0 public int getDistToIdentNewline() { return -1; }
 364  0 public int getDistToEnclosingBraceStart() { return -1; }
 365   
 366    /** Gets info about the brace enclosing the beginning of this line. */
 367  821 public BraceInfo _getLineEnclosingBrace() { return _rmb._getLineEnclosingBrace(); }
 368   
 369    /** Gets info about the brace enclosing this location. */
 370  354 public BraceInfo _getEnclosingBrace() { return _rmb._getEnclosingBrace(); }
 371    /** Gets distance to the new newline character (not including the newline). */
 372  821 public int getDistToStart() { return _rmc.getDistToStart(); }
 373    /** Gets distance to previous newline character (not including the newline). */
 374  15137 public int getDistToStart(int relLoc) { return _rmc.getDistToStart(relLoc); }
 375   
 376  24740 public int getDistToNextNewline() { return _rmc.getDistToNextNewline(); }
 377   
 378    /** Return all highlight status info for text between the current location and current location + length. This should
 379    * collapse adjoining blocks with the same status into one. Assumes read and reduced locks are already held.
 380    * @param start The start location of the area being inspected. The reduced model cursor is already set at this
 381    * position, but this value is needed to compute the absolute positions of HighlightStatus objects.
 382    * @param length The length of the text segment for which status information must be generated.
 383    */
 384  0 public ArrayList<HighlightStatus> getHighlightStatus(final int start, final int length) {
 385  0 ArrayList<HighlightStatus> vec = new ArrayList<HighlightStatus>();
 386   
 387  0 int curState;
 388  0 int curLocation;
 389  0 int curLength;
 390   
 391  0 TokenList.Iterator cursor = _rmc._cursor.copy();
 392    // int ct = rmc._tokens.listenerCount();
 393  0 curLocation = start;
 394    // NOTE: old code threw an exception if cursor.atStart(); it used wrong value for curLength atEnd too
 395    // curLength = ! cursor.atEnd() ? cursor.current().getSize() - rmc.getBlockOffset() : start + length;
 396    // curState = ! cursor.atEnd() ? cursor.current().getHighlightState() : 0;
 397  0 if (cursor.atEnd() || cursor.atStart()) { // cursor is not inside a reduced model token
 398  0 curLength = length;
 399  0 curState = 0;
 400    }
 401    else {
 402  0 curLength = cursor.current().getSize() - _rmc.getBlockOffset();
 403  0 curState = cursor.current().getHighlightState();
 404    }
 405   
 406  0 while (curLocation + curLength < start + length) {
 407  0 cursor.next();
 408    //TODO: figure out why this function is iterating past the end of the collection
 409    //when it gets called from the ColoringGlyphPainter after deleting the last character
 410  0 if (cursor.atEnd()) break;
 411  0 int nextState = cursor.current().getHighlightState();
 412   
 413  0 if (nextState == curState) {
 414    // add on and keep building
 415  0 curLength += cursor.current().getSize();
 416    }
 417    else {
 418    // add old one to the vector and start new one
 419  0 vec.add(new HighlightStatus(curLocation, curLength, curState));
 420  0 curLocation += curLength; // new block starts after previous one
 421  0 curLength = cursor.current().getSize();
 422  0 curState = nextState;
 423    }
 424    }
 425   
 426    // Make sure this token length doesn't extend past start+length.
 427    // This is because we guarantee that the returned vector only refers
 428    // to chars on [start, start+length).
 429  0 int requestEnd = start + length;
 430  0 if (curLocation + curLength > requestEnd) curLength = requestEnd - curLocation;
 431   
 432    // Add the last one, which has not been added yet
 433  0 vec.add(new HighlightStatus(curLocation, curLength, curState));
 434   
 435  0 cursor.dispose();
 436   
 437  0 return vec;
 438    }
 439    }