Skylark parser: make the end position of location ranges inclusive.

Previously, the end line and column of a location were the position past the actual end of a location. This makes sense for the end offset, because one can use `input.substring(startOffset, endOffset)` to get the string belonging to an ASTNode.

However the line and column (as opposed to the offset) aren't used for that. Therefore I made the change that the end line and column now point to the last character in the location. This is also they way every compiler I know does it.

RELNOTES: none
PiperOrigin-RevId: 170723732
diff --git a/src/main/java/com/google/devtools/build/lib/events/Location.java b/src/main/java/com/google/devtools/build/lib/events/Location.java
index 8420254..24d2c2d 100644
--- a/src/main/java/com/google/devtools/build/lib/events/Location.java
+++ b/src/main/java/com/google/devtools/build/lib/events/Location.java
@@ -17,7 +17,6 @@
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
-
 import java.io.Serializable;
 import java.util.Objects;
 
@@ -117,11 +116,11 @@
   }
 
   /**
-   * Returns the end offset relative to the beginning of the file the object
-   * resides in.
+   * Returns the end offset relative to the beginning of the file the object resides in.
    *
-   * <p>The end offset is one position past the actual end position, making this method
-   * behave in a compatible fashion with {@link String#substring(int, int)}.
+   * <p>The end offset is one position past the last character in range, making this method behave
+   * in a compatible fashion with {@link String#substring(int, int)}. (By contrast, {@link
+   * #getEndLineAndColumn} returns the actual end position.)
    *
    * <p>To compute the length of this location, use {@code getEndOffset() - getStartOffset()}.
    */
@@ -161,8 +160,14 @@
   }
 
   /**
-   * Returns a (line, column) pair corresponding to the position denoted by
-   * getEndOffset.  Returns null if this information is not available.
+   * Returns a (line, column) pair corresponding to the end position or null if this information is
+   * unavailable.
+   *
+   * <p>The returned line and column are the position of the last character in the location range.
+   * (By contrast, {@link #getEndOffset} returns the position <strong>past</strong> the actual end
+   * position.) In particular, this means that the location spans {@code
+   * getEndLineAndColumn().getColumn() - getStartLineAndColumn().getColumn() + 1} columns but
+   * contains {@code getEndOffset() - getStartOffset()} characters.
    */
   public LineAndColumn getEndLineAndColumn() {
     return null;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java
index b1b63c8..10ff03e 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java
@@ -184,7 +184,12 @@
 
     @Override
     public LineAndColumn getEndLineAndColumn() {
-      return lineNumberTable.getLineAndColumn(getEndOffset());
+      // The end offset is the location *past* the actual end position --> subtract 1:
+      int endOffset = getEndOffset() - 1;
+      if (endOffset < 0) {
+        endOffset = 0;
+      }
+      return lineNumberTable.getLineAndColumn(endOffset);
     }
 
 
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
index 20923da..20ea5c0 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
@@ -20,6 +20,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.events.Location.LineAndColumn;
 import com.google.devtools.build.lib.syntax.DictionaryLiteral.DictionaryEntryLiteral;
 import com.google.devtools.build.lib.syntax.Parser.ParsingLevel;
 import com.google.devtools.build.lib.syntax.SkylarkImports.SkylarkImportSyntaxException;
@@ -356,7 +357,7 @@
 
     assertLocation(5, 29, arg1val.getLocation());
     assertThat(expr.substring(5, 28)).isEqualTo("[x for foo foo foo foo]");
-    assertThat(arg1val.getLocation().getEndLineAndColumn().getColumn()).isEqualTo(30);
+    assertThat(arg1val.getLocation().getEndLineAndColumn().getColumn()).isEqualTo(29);
 
     IntegerLiteral arg2 = (IntegerLiteral) e.getArguments().get(2).getValue();
     assertThat((int) arg2.getValue()).isEqualTo(3);
@@ -480,6 +481,14 @@
   }
 
   @Test
+  public void testEndLineAndColumnIsInclusive() {
+    AssignmentStatement stmt =
+        (AssignmentStatement) parseStatement(ParsingLevel.LOCAL_LEVEL, "a = b");
+    assertThat(stmt.getLValue().getLocation().getEndLineAndColumn())
+        .isEqualTo(new LineAndColumn(1, 1));
+  }
+
+  @Test
   public void testFuncallLocation() {
     List<Statement> statements = parseFile("a(b);c = d\n");
     Statement statement = statements.get(0);