1 | //===- unittests/Serialization/SourceLocationEncodingTests.cpp ------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/Serialization/SourceLocationEncoding.h" |
10 | |
11 | #include "gtest/gtest.h" |
12 | #include <climits> |
13 | #include <optional> |
14 | |
15 | using namespace llvm; |
16 | using namespace clang; |
17 | |
18 | namespace { |
19 | using LocSeq = SourceLocationSequence; |
20 | |
21 | // Convert a single source location into encoded form and back. |
22 | // If ExpectedEncoded is provided, verify the encoded value too. |
23 | // Loc is the raw (in-memory) form of SourceLocation. |
24 | void roundTrip(SourceLocation::UIntTy Loc, |
25 | std::optional<uint64_t> ExpectedEncoded = std::nullopt) { |
26 | uint64_t ActualEncoded = SourceLocationEncoding::encode( |
27 | Loc: SourceLocation::getFromRawEncoding(Encoding: Loc), /*BaseOffset=*/0, |
28 | /*BaseModuleFileIndex=*/0); |
29 | if (ExpectedEncoded) { |
30 | ASSERT_EQ(ActualEncoded, *ExpectedEncoded) << "Encoding " << Loc; |
31 | } |
32 | SourceLocation::UIntTy DecodedEncoded = |
33 | SourceLocationEncoding::decode(Encoded: ActualEncoded).first.getRawEncoding(); |
34 | ASSERT_EQ(DecodedEncoded, Loc) << "Decoding " << ActualEncoded; |
35 | } |
36 | |
37 | // As above, but use sequence encoding for a series of locations. |
38 | void roundTrip(std::vector<SourceLocation::UIntTy> Locs, |
39 | std::vector<uint64_t> ExpectedEncoded = {}) { |
40 | std::vector<uint64_t> ActualEncoded; |
41 | { |
42 | LocSeq::State Seq; |
43 | for (auto L : Locs) |
44 | ActualEncoded.push_back(x: SourceLocationEncoding::encode( |
45 | Loc: SourceLocation::getFromRawEncoding(Encoding: L), /*BaseOffset=*/0, |
46 | /*BaseModuleFileIndex=*/0, Seq)); |
47 | if (!ExpectedEncoded.empty()) { |
48 | ASSERT_EQ(ActualEncoded, ExpectedEncoded) |
49 | << "Encoding " << testing::PrintToString(value: Locs); |
50 | } |
51 | } |
52 | std::vector<SourceLocation::UIntTy> DecodedEncoded; |
53 | { |
54 | LocSeq::State Seq; |
55 | for (auto L : ActualEncoded) { |
56 | SourceLocation Loc = SourceLocationEncoding::decode(Encoded: L, Seq).first; |
57 | DecodedEncoded.push_back(x: Loc.getRawEncoding()); |
58 | } |
59 | ASSERT_EQ(DecodedEncoded, Locs) |
60 | << "Decoding " << testing::PrintToString(value: ActualEncoded); |
61 | } |
62 | } |
63 | |
64 | constexpr SourceLocation::UIntTy MacroBit = |
65 | 1 << (sizeof(SourceLocation::UIntTy) * CHAR_BIT - 1); |
66 | constexpr SourceLocation::UIntTy Big = MacroBit >> 1; |
67 | constexpr SourceLocation::UIntTy Biggest = -1; |
68 | |
69 | TEST(SourceLocationEncoding, Individual) { |
70 | roundTrip(Loc: 1, ExpectedEncoded: 2); |
71 | roundTrip(Loc: 100, ExpectedEncoded: 200); |
72 | roundTrip(Loc: MacroBit, ExpectedEncoded: 1); |
73 | roundTrip(Loc: MacroBit | 5, ExpectedEncoded: 11); |
74 | roundTrip(Loc: Big); |
75 | roundTrip(Loc: Big + 1); |
76 | roundTrip(Loc: MacroBit | Big); |
77 | roundTrip(Loc: MacroBit | (Big + 1)); |
78 | } |
79 | |
80 | TEST(SourceLocationEncoding, Sequence) { |
81 | roundTrip(Locs: {1, 2, 3, 3, 2, 1}, |
82 | ExpectedEncoded: {2, // 1 |
83 | 5, // +2 (+1 of non-raw) |
84 | 5, // +2 |
85 | 1, // +0 |
86 | 4, // -2 |
87 | 4} // -2 |
88 | ); |
89 | roundTrip(Locs: {100, 0, 100}, |
90 | ExpectedEncoded: {200, // 100 |
91 | 0, // 0 |
92 | 1} // +0 |
93 | ); |
94 | |
95 | roundTrip(Locs: {1, Big}, ExpectedEncoded: {2, ((Big - 1) << 2) + 1}); |
96 | roundTrip(Locs: {2, MacroBit | Big}, ExpectedEncoded: {4, ((Big - 1) << 2) - 1}); |
97 | |
98 | roundTrip(Locs: {3, MacroBit | 5, MacroBit | 4, 3}, |
99 | ExpectedEncoded: {6, // 3 |
100 | 11, // +5 (+2 of non-raw + set macro bit) |
101 | 4, // -2 |
102 | 6} // -3 (-2 of non-raw, clear macro bit) |
103 | ); |
104 | |
105 | roundTrip( |
106 | Locs: {123 | MacroBit, 1, 9, Biggest, Big, Big + 1, 0, MacroBit | Big, 0}); |
107 | } |
108 | |
109 | } // namespace |
110 | |