Skip to content

Commit 5912501

Browse files
committed
feat: collect embed/has_embed directive in PPCallbacks
1 parent 4d07bad commit 5912501

File tree

3 files changed

+147
-5
lines changed

3 files changed

+147
-5
lines changed

include/Compiler/Directive.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,46 @@ struct Import {
127127
std::vector<clang::SourceLocation> name_locations;
128128
};
129129

130+
struct Embed {
131+
/// The file name in the embed directive, not including quotes or angle brackets.
132+
llvm::StringRef file_name;
133+
134+
/// The actual file that may be embedded by this embed directive.
135+
clang::OptionalFileEntryRef file;
136+
137+
/// Whether the file name is angled.
138+
bool is_angled;
139+
140+
/// Location of the `#` token.
141+
clang::SourceLocation loc;
142+
143+
/// TODO: Currently we do not store parameters of the embed directive.
144+
/// See clang::LexEmbedParametersResult for details.
145+
};
146+
147+
struct HasEmbed {
148+
/// The file name in the embed directive, not including quotes or angle brackets.
149+
llvm::StringRef file_name;
150+
151+
/// The actual file that may be embedded by this embed directive.
152+
clang::OptionalFileEntryRef file;
153+
154+
/// Whether the file name is angled.
155+
bool is_angled;
156+
157+
/// Location of the `__has_embed` token.
158+
clang::SourceLocation loc;
159+
};
160+
130161
struct Directive {
131162
std::vector<Include> includes;
132163
std::vector<HasInclude> has_includes;
133164
std::vector<Condition> conditions;
134165
std::vector<MacroRef> macros;
135166
std::vector<Pragma> pragmas;
136167
std::vector<Import> imports;
168+
std::vector<Embed> embeds;
169+
std::vector<HasEmbed> has_embeds;
137170

138171
/// Tell preprocessor to collect directives information and store them in `directives`.
139172
static void attach(clang::Preprocessor& pp,

src/Compiler/Directive.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,39 @@ class DirectiveCollector : public clang::PPCallbacks {
5757
}
5858

5959
auto& directive = directives[sm.getFileID(loc)];
60-
directive.macros.emplace_back(MacroRef{def, kind, loc});
60+
directive.macros.push_back({def, kind, loc});
6161
}
6262

6363
public:
6464
/// ============================================================================
6565
/// Rewritten Preprocessor Callbacks
6666
/// ============================================================================
6767

68+
void HasEmbed(clang::SourceLocation location,
69+
llvm::StringRef filename,
70+
bool is_angled,
71+
clang::OptionalFileEntryRef file) override {
72+
directives[sm.getFileID(location)].has_embeds.push_back({
73+
filename,
74+
file,
75+
is_angled,
76+
location,
77+
});
78+
}
79+
80+
void EmbedDirective(clang::SourceLocation location,
81+
clang::StringRef filename,
82+
bool is_angled,
83+
clang::OptionalFileEntryRef file,
84+
const clang::LexEmbedParametersResult& Params) override {
85+
directives[sm.getFileID(location)].embeds.push_back({
86+
filename,
87+
file,
88+
is_angled,
89+
location,
90+
});
91+
}
92+
6893
void InclusionDirective(clang::SourceLocation hash_loc,
6994
const clang::Token& include_tok,
7095
llvm::StringRef,
@@ -80,7 +105,7 @@ class DirectiveCollector : public clang::PPCallbacks {
80105

81106
/// An `IncludeDirective` call is always followed by either a `LexedFileChanged`
82107
/// or a `FileSkipped`. so we cannot get the file id of included file here.
83-
directives[prev_fid].includes.emplace_back(Include{
108+
directives[prev_fid].includes.push_back({
84109
.fid = {},
85110
.location = include_tok.getLocation(),
86111
.filename_range = filename_range.getAsRange(),
@@ -139,7 +164,10 @@ class DirectiveCollector : public clang::PPCallbacks {
139164
fid = sm.translateFile(*file);
140165
}
141166

142-
directives[sm.getFileID(location)].has_includes.emplace_back(fid, location);
167+
directives[sm.getFileID(location)].has_includes.push_back({
168+
fid,
169+
location,
170+
});
143171
}
144172

145173
void PragmaDirective(clang::SourceLocation loc,
@@ -158,7 +186,7 @@ class DirectiveCollector : public clang::PPCallbacks {
158186
: Pragma::Other;
159187

160188
auto& directive = directives[fid];
161-
directive.pragmas.emplace_back(Pragma{
189+
directive.pragmas.push_back({
162190
that_line,
163191
kind,
164192
loc,

tests/unit/Compiler/Directive.cpp

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ suite<"Directive"> directive = [] {
1111
std::vector<Condition> conditions;
1212
std::vector<MacroRef> macros;
1313
std::vector<Pragma> pragmas;
14+
std::vector<Embed> embeds;
15+
std::vector<HasEmbed> has_embeds;
1416

1517
using u32 = std::uint32_t;
1618

@@ -24,6 +26,8 @@ suite<"Directive"> directive = [] {
2426
conditions = tester.unit->directives()[fid].conditions;
2527
macros = tester.unit->directives()[fid].macros;
2628
pragmas = tester.unit->directives()[fid].pragmas;
29+
embeds = tester.unit->directives()[fid].embeds;
30+
has_embeds = tester.unit->directives()[fid].has_embeds;
2731
};
2832

2933
auto expect_include = [&](u32 index, llvm::StringRef position, llvm::StringRef path) {
@@ -51,6 +55,25 @@ suite<"Directive"> directive = [] {
5155
expect(that % target == path);
5256
};
5357

58+
auto expect_embed = [&](u32 index, llvm::StringRef position, llvm::StringRef filename) {
59+
auto& embed = embeds[index];
60+
auto [_, offset] = tester.unit->decompose_location(embed.loc);
61+
expect(that % offset == tester.point(position));
62+
63+
expect(that % embed.file.has_value());
64+
expect(that % embed.file_name == filename);
65+
};
66+
67+
auto expect_has_embed =
68+
[&](u32 index, llvm::StringRef position, llvm::StringRef filename, bool exists = true) {
69+
auto& has_embed = has_embeds[index];
70+
auto [_, offset] = tester.unit->decompose_location(has_embed.loc);
71+
expect(that % offset == tester.point(position));
72+
73+
expect(that % has_embed.file.has_value() == exists);
74+
expect(that % has_embed.file_name == filename);
75+
};
76+
5477
auto expect_con = [&](u32 index, Condition::BranchKind kind, llvm::StringRef pos) {
5578
auto& condition = conditions[index];
5679
auto [_, offset] = tester.unit->decompose_location(condition.loc);
@@ -124,6 +147,65 @@ suite<"Directive"> directive = [] {
124147
expect_has_inl(1, "1", "");
125148
};
126149

150+
test("Embed") = [&] {
151+
run(R"cpp(
152+
#[bytes10.bin]
153+
0123456789
154+
155+
#[bytes5.bin]
156+
ABCDE
157+
158+
#[main.cpp]
159+
const char e0 = {
160+
$(0)#embed "bytes10.bin"
161+
};
162+
163+
const char e1 = {
164+
$(1)#embed "bytes10.bin"
165+
};
166+
167+
const char e2 = {
168+
$(2)#embed "bytes5.bin"
169+
};
170+
171+
const char e3 = {
172+
$(3)#embed "bytes5.bin"
173+
};
174+
175+
const char e4 = {
176+
$(4)#embed "non-existed.bin"
177+
};
178+
179+
)cpp");
180+
181+
// e4 will not be processed by clang::PPCallbacks::EmbedDirective(), so there is only 4
182+
// embeds.
183+
expect(that % embeds.size() == 4);
184+
expect_embed(0, "0", "bytes10.bin");
185+
expect_embed(1, "1", "bytes10.bin");
186+
expect_embed(2, "2", "bytes5.bin");
187+
expect_embed(3, "3", "bytes5.bin");
188+
};
189+
190+
test("HasEmbed") = [&] {
191+
run(R"cpp(
192+
#[test.bin]
193+
194+
#[main.cpp]
195+
#embed "test.bin"
196+
197+
#if __has_embed$(0)("test.bin")
198+
#endif
199+
200+
#if __has_embed$(1)("non-existed.bin")
201+
#endif
202+
)cpp");
203+
204+
expect(that % has_embeds.size() == 2);
205+
expect_has_embed(0, "0", "test.bin");
206+
expect_has_embed(1, "1", "non-existed.bin", /*exists=*/false);
207+
};
208+
127209
test("Condition") = [&] {
128210
run(R"cpp(
129211
#[main.cpp]
@@ -196,7 +278,6 @@ int y = $(6)expr($(7)expr(1));
196278
expect_pragma(2, Pragma::Kind::EndRegion, "2", "#pragma endregion");
197279
};
198280
};
199-
200281
} // namespace
201282

202283
} // namespace clice::testing

0 commit comments

Comments
 (0)