Fix DeclarationAssembler to correctly merge fragments with different offsets
PiperOrigin-RevId: 298723049
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/file/DeclarationAssembler.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/file/DeclarationAssembler.java
index 2a843ba..e5c4919 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/file/DeclarationAssembler.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/file/DeclarationAssembler.java
@@ -114,6 +114,20 @@
ByteBufferFragment merged = ByteBufferFragment.merge(fragments);
+ int newOffset;
+ if (Iterables.getLast(list).getBufferOffset() == firstOffset) {
+ // If all fragment offsets were the same (which is the case if all their originating buffers
+ // were the same), then the merged fragment has the start index of the first originating
+ // fragment, and the end index of the last originating fragment.
+ // The old offset can be used without issue.
+ newOffset = firstOffset;
+ } else {
+ // If fragment offsets differed, then the new merged fragment has a different offset.
+ // In this case, the merged fragment has relative indices [0, len), which means that its
+ // offset should reflect the absolute "real" start offset.
+ newOffset = first.getFragmentOffset();
+ }
+
int previousEnd = 0;
for (Range<Integer> range : interestingRanges) {
int idx =
@@ -123,11 +137,11 @@
// starting from the connection point between first and second fragments.
Preconditions.checkState(idx > previousEnd);
declarationConsumer.declaration(
- new ByteFragmentAtOffset(firstOffset, merged.subFragment(previousEnd, idx + 1)));
+ new ByteFragmentAtOffset(newOffset, merged.subFragment(previousEnd, idx + 1)));
previousEnd = idx + 1;
}
}
declarationConsumer.declaration(
- new ByteFragmentAtOffset(firstOffset, merged.subFragment(previousEnd, merged.length())));
+ new ByteFragmentAtOffset(newOffset, merged.subFragment(previousEnd, merged.length())));
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/DeclarationAssemblerTest.java b/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/DeclarationAssemblerTest.java
index 480d1ca..770ecaf 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/DeclarationAssemblerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/ninja/DeclarationAssemblerTest.java
@@ -16,13 +16,17 @@
package com.google.devtools.build.lib.bazel.rules.ninja;
import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
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.DeclarationAssembler;
import com.google.devtools.build.lib.bazel.rules.ninja.file.GenericParsingException;
import com.google.devtools.build.lib.bazel.rules.ninja.file.NinjaSeparatorFinder;
+import com.google.devtools.build.lib.util.Pair;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -54,6 +58,38 @@
doTwoBuffersTest("abc$", "\ndef", "abc$\ndef");
}
+ @Test
+ public void testMergeTwoDifferentBuffers() throws Exception {
+ List<Pair<Integer, String>> offsetStringPairList = Lists.newArrayList();
+ String unrelatedFirstBuffer = Strings.repeat(" ", 100);
+ String s1 = "hello";
+ String s2 = "goodbye";
+ byte[] chars1 = (unrelatedFirstBuffer + s1).getBytes(ISO_8859_1);
+ byte[] chars2 = s2.getBytes(ISO_8859_1);
+
+ DeclarationAssembler assembler =
+ new DeclarationAssembler(
+ (byteFragmentAtOffset) -> {
+ offsetStringPairList.add(
+ new Pair<>(
+ byteFragmentAtOffset.getFragmentOffset(),
+ byteFragmentAtOffset.getFragment().toString()));
+ },
+ NinjaSeparatorFinder.INSTANCE);
+
+ assembler.wrapUp(
+ Lists.newArrayList(
+ new ByteFragmentAtOffset(
+ 0,
+ new ByteBufferFragment(
+ ByteBuffer.wrap(chars1), unrelatedFirstBuffer.length(), chars1.length)),
+ new ByteFragmentAtOffset(
+ chars1.length, new ByteBufferFragment(ByteBuffer.wrap(chars2), 0, s2.length()))));
+
+ assertThat(Iterables.getOnlyElement(offsetStringPairList))
+ .isEqualTo(new Pair<>(unrelatedFirstBuffer.length(), "hellogoodbye"));
+ }
+
private static void doTwoBuffersTest(String s1, String s2, String... expected)
throws GenericParsingException, IOException {
List<String> list = Lists.newArrayList();