Standard Libraries

/** --- Location ---

   Locations represent parts of files and are used to map elements to their source 
   location.
*/

import FileSystem

/** does X have location L? */
predicate hasLocation(@locatable X, @location L) {
  locations(L,X,_,_,_,_,_,_,_)
}

/** A locatable has an associated Location to represent its source location. */
class Locatable extends @locatable {
  /** source location for this element */
  Location getLocation() { hasLocation(this,result) }

  /** URL for this element */
  string getURL() { result = this.getLocation().getURL() or
                    (not exists(this.getLocation().getURL()) and
                         result="") }
  string toString() { result = this.getLocation().toString() }
}

/** A location maps language elements to positions in source files. */
class Location extends @location {
  /** offset that this location starts at */
  int getStart() { locations(this,_,_,result,_,_,_,_,_) }

 /** number of characters that this location ranges over */
  int getLength() { locations(this,_,_,_,result,_,_,_,_) }

  /** line number that this location starts at */
  int getStartLine() { locations(this,_,_,_,_,result,_,_,_) }

  /** number of lines that this location ranges over */
  int getNumberOfLines() { locations(this,_,_,_,_,_,result,_,_) }

  /** number of lines of code that this location ranges over */
  int getNumberOfLinesOfCode() { locations(this,_,_,_,_,_,_,result,_) }

  /** number of comment lines that this location ranges over */
  int getNumberOfCommentLines() { locations(this,_,_,_,_,_,_,_,result) }

  /** return a string representation containing the file and range for this location */
  string toString() {
    exists(File f, int startline, int totallines |
      locations(this,_,f,_,_,startline,totallines,_,_) and
      if totallines = 0 then
        result = f.toString() + ":" + startline.toString()
      else 
        result = f.toString() + ":" + 
           startline.toString() + "-" + (startline + totallines - 1).toString())
  }

  /** URL of this location */
  string getURL() { 
    exists(File f, int start, int length, int startline |
             locations(this,_,f,start,length,startline,_,_,_) and
             result = "file://" + f.getPath() + ":" + startline.toString()
                                + ":" + start.toString() + ":" + length.toString())
  }
}