docs: protected List<AbstractTraceRegion> toInvertedTraceRegions(List<Pair<ILocationData, AbstractTraceRegion>> locations,
  			SourceRelativeURI myPath) {
  		List<AbstractTraceRegion> result = Lists.newArrayListWithCapacity(2);
  		TraceRegion current = null;
  		int currentEndOffset = 0;
  		outer: for (int i = 0; i < locations.size(); i++) { // avoid concurrent modification exceptions
  			Pair<ILocationData, AbstractTraceRegion> nextPair = locations.get(i);
  			ILocationData nextLocation = nextPair.getFirst();
  			if (nextLocation.getOffset() == nextLocation.getLength() && nextLocation.getOffset() == 0) {
  				continue;
  			}
  			AbstractTraceRegion nextRegion = nextPair.getSecond();
  			if (current != null) {
  				// equal region - add mapped location
  				if (current.getMyOffset() == nextLocation.getOffset()
  						&& current.getMyLength() == nextLocation.getLength()) {
  					List<ILocationData> writableLocations = current.getWritableAssociatedLocations();
  					ILocationData newData = createLocationData(nextRegion, myPath);
  					if (!writableLocations.contains(newData))
  						writableLocations.add(newData);
  					continue outer;
  				} else {
  					// walk upwards if necessary
  					while (current != null && currentEndOffset <= nextLocation.getOffset()) {
  						current = (TraceRegion) current.getParent();
  						if (current != null)
  							currentEndOffset = current.getMyOffset() + current.getMyLength();
  						else
  							currentEndOffset = 0;
  					}
  				}
  			}
  			if (current != null) {
  				int nextOffset = nextLocation.getOffset();
  				if (nextOffset + nextLocation.getLength() <= currentEndOffset) {
  					current = new TraceRegion(nextOffset, nextLocation.getLength(), nextLocation.getLineNumber(),
  							nextLocation.getEndLineNumber(), true, createLocationData(nextRegion, myPath), current);
  					currentEndOffset = nextLocation.getOffset() + nextLocation.getLength();
  				} else {
  					int nextLength = currentEndOffset - nextOffset;
  					int nextEndLine = current.getMyEndLineNumber();
  					int splittedLength = nextLocation.getLength() - nextLength;
  					int splittedBeginLine = nextEndLine;
  					ILocationData splitted = new LocationData(currentEndOffset, splittedLength, splittedBeginLine,
  							nextLocation.getEndLineNumber(), nextLocation.getSrcRelativePath());
  					for (int j = i + 1; j < locations.size() && splitted != null; j++) {
  						ILocationData shiftMe = locations.get(j).getFirst();
  						if (splitted.getOffset() == shiftMe.getOffset()) {
  							if (splitted.getLength() > shiftMe.getLength()) {
  								locations.add(j, Tuples.create(splitted, nextRegion));
  								splitted = null;
  							}
  						} else if (splitted.getOffset() < shiftMe.getOffset()) {
  							locations.add(j, Tuples.create(splitted, nextRegion));
  							splitted = null;
  						}
  					}
  					if (splitted != null) {
  						locations.add(Tuples.create(splitted, nextRegion));
  					}
  					current = new TraceRegion(nextOffset, nextLength, nextLocation.getLineNumber(), splittedBeginLine,
  							true, createLocationData(nextRegion, myPath), current);
  					currentEndOffset = nextOffset + nextLength;
  				}
  			} else {
  				current = new TraceRegion(nextLocation.getOffset(), nextLocation.getLength(),
  						nextLocation.getLineNumber(), nextLocation.getEndLineNumber(),
  						true, createLocationData(nextRegion, myPath), null);
  				currentEndOffset = nextLocation.getOffset() + nextLocation.getLength();
  				result.add(current);
  			}
  		}
  		return result;
  	}