clang-tools 24.0.0git
BuildConfusableTable.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 "llvm/ADT/STLExtras.h"
10#include "llvm/ADT/StringExtras.h"
11#include "llvm/ADT/StringMap.h"
12#include "llvm/Support/ConvertUTF.h"
13#include "llvm/Support/MemoryBuffer.h"
14#include "llvm/Support/raw_ostream.h"
15
16using namespace llvm;
17
18namespace {
19struct ConfusableEntry {
20 UTF32 CodePoint;
21 std::string Replacement;
22};
23} // namespace
24
25int main(int argc, char *argv[]) {
26 auto ErrorOrBuffer = MemoryBuffer::getFile(argv[1], true);
27 if (!ErrorOrBuffer)
28 return 1;
29 std::unique_ptr<MemoryBuffer> Buffer = std::move(ErrorOrBuffer.get());
30 StringRef Content = Buffer->getBuffer();
31 Content = Content.drop_until([](char C) { return C == '#'; });
33 SplitString(Content, Lines, "\r\n");
34
35 std::vector<ConfusableEntry> Entries;
37 for (const StringRef Line : Lines) {
38 if (Line.starts_with('#'))
39 continue;
40
41 Values.clear();
42 Line.split(Values, ';');
43 if (Values.size() < 2) {
44 errs() << "Failed to parse: " << Line << "\n";
45 return 2;
46 }
47
48 const StringRef From = Values[0].trim();
49 llvm::UTF32 CodePoint = 0;
50 From.getAsInteger(16, CodePoint);
51
52 std::string Replacement;
54 Values[1].split(ToN, ' ', -1, false);
55 for (const StringRef ToI : ToN) {
56 llvm::UTF32 ToCodePoint = 0;
57 ToI.trim().getAsInteger(16, ToCodePoint);
58 char Encoded[UNI_MAX_UTF8_BYTES_PER_CODE_POINT];
59 char *EncodedEnd = Encoded;
60 if (!ConvertCodePointToUTF8(ToCodePoint, EncodedEnd)) {
61 errs() << "Failed to encode code point: " << ToI << "\n";
62 return 3;
63 }
64 Replacement.append(Encoded, EncodedEnd);
65 }
66
67 Entries.push_back({CodePoint, std::move(Replacement)});
68 }
69 llvm::sort(Entries,
70 [](const ConfusableEntry &LHS, const ConfusableEntry &RHS) {
71 return LHS.CodePoint < RHS.CodePoint;
72 });
73
74 StringMap<uint16_t> ReplacementOffsets;
75 std::string ReplacementData;
76 for (const ConfusableEntry &Entry : Entries) {
77 if (ReplacementOffsets.contains(Entry.Replacement))
78 continue;
79 if (ReplacementData.size() + Entry.Replacement.size() >
80 std::numeric_limits<uint16_t>::max()) {
81 errs() << "Confusable replacement data exceeds 16-bit offsets\n";
82 return 4;
83 }
84 ReplacementOffsets.try_emplace(
85 Entry.Replacement, static_cast<uint16_t>(ReplacementData.size()));
86 ReplacementData.append(Entry.Replacement);
87 }
88
89 std::error_code Ec;
90 llvm::raw_fd_ostream Os(argv[2], Ec);
91
92 static constexpr char HexDigits[] = "0123456789ABCDEF";
93 Os << "constexpr char ConfusableReplacementData[] =\n";
94 for (size_t I = 0; I < ReplacementData.size(); I += 32) {
95 Os << " \"";
96 for (const unsigned char C : StringRef(ReplacementData).substr(I, 32))
97 Os << "\\x" << HexDigits[C >> 4] << HexDigits[C & 0x0F];
98 Os << "\"\n";
99 }
100 Os << " ;\n\n";
101
102 Os << "constexpr ConfusableEntry ConfusableEntries[] = {\n";
103 for (const ConfusableEntry &Entry : Entries) {
104 const auto It = ReplacementOffsets.find(Entry.Replacement);
105 Os << " {" << Entry.CodePoint << ", " << It->second << ", "
106 << Entry.Replacement.size() << "},\n";
107 }
108 Os << "};\n";
109 return 0;
110}
int main(int argc, char *argv[])
Some operations such as code completion produce a set of candidates.
Definition Generators.h:150