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 = |
27 | SourceLocationEncoding::encode(Loc: SourceLocation::getFromRawEncoding(Encoding: Loc)); |
28 | if (ExpectedEncoded) { |
29 | ASSERT_EQ(ActualEncoded, *ExpectedEncoded) << "Encoding " << Loc; |
30 | } |
31 | SourceLocation::UIntTy DecodedEncoded = |
32 | SourceLocationEncoding::decode(Encoded: ActualEncoded).getRawEncoding(); |
33 | ASSERT_EQ(DecodedEncoded, Loc) << "Decoding " << ActualEncoded; |
34 | } |
35 | |
36 | // As above, but use sequence encoding for a series of locations. |
37 | void roundTrip(std::vector<SourceLocation::UIntTy> Locs, |
38 | std::vector<uint64_t> ExpectedEncoded = {}) { |
39 | std::vector<uint64_t> ActualEncoded; |
40 | { |
41 | LocSeq::State Seq; |
42 | for (auto L : Locs) |
43 | ActualEncoded.push_back(x: SourceLocationEncoding::encode( |
44 | Loc: SourceLocation::getFromRawEncoding(Encoding: L), Seq)); |
45 | if (!ExpectedEncoded.empty()) { |
46 | ASSERT_EQ(ActualEncoded, ExpectedEncoded) |
47 | << "Encoding " << testing::PrintToString(value: Locs); |
48 | } |
49 | } |
50 | std::vector<SourceLocation::UIntTy> DecodedEncoded; |
51 | { |
52 | LocSeq::State Seq; |
53 | for (auto L : ActualEncoded) { |
54 | SourceLocation Loc = SourceLocationEncoding::decode(Encoded: L, Seq); |
55 | DecodedEncoded.push_back(x: Loc.getRawEncoding()); |
56 | } |
57 | ASSERT_EQ(DecodedEncoded, Locs) |
58 | << "Decoding " << testing::PrintToString(value: ActualEncoded); |
59 | } |
60 | } |
61 | |
62 | constexpr SourceLocation::UIntTy MacroBit = |
63 | 1 << (sizeof(SourceLocation::UIntTy) * CHAR_BIT - 1); |
64 | constexpr SourceLocation::UIntTy Big = MacroBit >> 1; |
65 | constexpr SourceLocation::UIntTy Biggest = -1; |
66 | |
67 | TEST(SourceLocationEncoding, Individual) { |
68 | roundTrip(Loc: 1, ExpectedEncoded: 2); |
69 | roundTrip(Loc: 100, ExpectedEncoded: 200); |
70 | roundTrip(Loc: MacroBit, ExpectedEncoded: 1); |
71 | roundTrip(Loc: MacroBit | 5, ExpectedEncoded: 11); |
72 | roundTrip(Loc: Big); |
73 | roundTrip(Loc: Big + 1); |
74 | roundTrip(Loc: MacroBit | Big); |
75 | roundTrip(Loc: MacroBit | (Big + 1)); |
76 | } |
77 | |
78 | TEST(SourceLocationEncoding, Sequence) { |
79 | roundTrip(Locs: {1, 2, 3, 3, 2, 1}, |
80 | ExpectedEncoded: {2, // 1 |
81 | 5, // +2 (+1 of non-raw) |
82 | 5, // +2 |
83 | 1, // +0 |
84 | 4, // -2 |
85 | 4} // -2 |
86 | ); |
87 | roundTrip(Locs: {100, 0, 100}, |
88 | ExpectedEncoded: {200, // 100 |
89 | 0, // 0 |
90 | 1} // +0 |
91 | ); |
92 | |
93 | roundTrip(Locs: {1, Big}, ExpectedEncoded: {2, ((Big - 1) << 2) + 1}); |
94 | roundTrip(Locs: {2, MacroBit | Big}, ExpectedEncoded: {4, ((Big - 1) << 2) - 1}); |
95 | |
96 | roundTrip(Locs: {3, MacroBit | 5, MacroBit | 4, 3}, |
97 | ExpectedEncoded: {6, // 3 |
98 | 11, // +5 (+2 of non-raw + set macro bit) |
99 | 4, // -2 |
100 | 6} // -3 (-2 of non-raw, clear macro bit) |
101 | ); |
102 | |
103 | roundTrip( |
104 | Locs: {123 | MacroBit, 1, 9, Biggest, Big, Big + 1, 0, MacroBit | Big, 0}); |
105 | } |
106 | |
107 | } // namespace |
108 | |