Fix parsing the fragments with Ninja declarations to start from offset

The was a problem that we created NinjaLexer without paying attention to the inner offset in ByteFragmentAtOffset.
There was additionally a problem that we recorded build statement to start at the wrong offset.
Add test for the Ninja file with newlines.

Closes #10722.

PiperOrigin-RevId: 293781612
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/parser/NinjaParser.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/parser/NinjaParser.java
index 38894e7..6517bf4 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/parser/NinjaParser.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/parser/NinjaParser.java
@@ -49,7 +49,10 @@
     ByteBufferFragment fragment = byteFragmentAtOffset.getFragment();
     int offset = byteFragmentAtOffset.getRealStartOffset();
 
-    NinjaLexer lexer = new NinjaLexer(fragment);
+    // Lexer should start at the beginning of byteFragmentAtOffset -> apply offset.
+    ByteBufferFragment subFragment =
+        fragment.subFragment(byteFragmentAtOffset.getOffset(), fragment.length());
+    NinjaLexer lexer = new NinjaLexer(subFragment);
 
     if (!lexer.hasNextToken()) {
       throw new IllegalStateException("Empty fragment passed as declaration.");
@@ -99,7 +102,8 @@
         ByteFragmentAtOffset targetFragment =
             declarationStart == offset
                 ? byteFragmentAtOffset
-                : new ByteFragmentAtOffset(declarationStart, fragment);
+                // We pass an offset *inside the fragment* into ByteFragmentAtOffset constructor
+                : new ByteFragmentAtOffset(declarationStart - fragment.getStartIncl(), fragment);
         parseResult.addTarget(targetFragment);
         break;
       case DEFAULT:
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/pipeline/NinjaPipeline.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/pipeline/NinjaPipeline.java
index 48b84e5..98f8469 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/pipeline/NinjaPipeline.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/pipeline/NinjaPipeline.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.devtools.build.lib.bazel.rules.ninja.file.ByteBufferFragment;
 import com.google.devtools.build.lib.bazel.rules.ninja.file.ByteFragmentAtOffset;
 import com.google.devtools.build.lib.bazel.rules.ninja.file.CollectingListFuture;
 import com.google.devtools.build.lib.bazel.rules.ninja.file.GenericParsingException;
@@ -112,12 +113,18 @@
       NinjaScope currentScope = queue.removeFirst();
       List<ByteFragmentAtOffset> targetFragments = rawTargets.get(currentScope);
       Preconditions.checkNotNull(targetFragments);
-      for (ByteFragmentAtOffset fragment : targetFragments) {
+      for (ByteFragmentAtOffset byteFragmentAtOffset : targetFragments) {
         future.add(
             service.submit(
-                () ->
-                    new NinjaParserStep(new NinjaLexer(fragment.getFragment()))
-                        .parseNinjaTarget(currentScope, fragment.getRealStartOffset())));
+                () -> {
+                  // Lexer should start at the beginning of fragment -> apply offset.
+                  ByteBufferFragment bufferFragment = byteFragmentAtOffset.getFragment();
+                  ByteBufferFragment subFragment =
+                      bufferFragment.subFragment(
+                          byteFragmentAtOffset.getOffset(), bufferFragment.length());
+                  return new NinjaParserStep(new NinjaLexer(subFragment))
+                      .parseNinjaTarget(currentScope, byteFragmentAtOffset.getRealStartOffset());
+                }));
       }
       queue.addAll(currentScope.getIncludedScopes());
       queue.addAll(currentScope.getSubNinjaScopes());
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/NinjaPipelineTest.java b/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/NinjaPipelineTest.java
index d35b7b2..9198369 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/NinjaPipelineTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/NinjaPipelineTest.java
@@ -117,6 +117,33 @@
   }
 
   @Test
+  public void testOneFilePipelineWithNewlines() throws Exception {
+    Path vfsPath =
+        tester.writeTmpFile(
+            "test.ninja",
+            "",
+            "",
+            "",
+            "",
+            "rule r1",
+            "  command = c $in $out",
+            "",
+            "",
+            "",
+            "build t1: r1 in1 in2",
+            "",
+            "",
+            "",
+            "build t2: r1 in3",
+            "");
+    NinjaPipeline pipeline =
+        new NinjaPipeline(
+            vfsPath.getParentDirectory(), tester.getService(), ImmutableList.of(), "ninja_target");
+    List<NinjaTarget> targets = pipeline.pipeline(vfsPath);
+    checkTargets(targets);
+  }
+
+  @Test
   public void testWithIncluded() throws Exception {
     Path vfsPath =
         tester.writeTmpFile(