0.5.4
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
config.cc
Go to the documentation of this file.
1/**
2 * @file src/config/config.cc
3 *
4 * Copyright (c) 2021-2024 Bartek Kryza <bkryza@gmail.com>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include "config.h"
20#include "diagram_templates.h"
21#include "glob/glob.hpp"
22
23#include <filesystem>
24
26
27std::string to_string(const hint_t t)
28{
29 switch (t) {
30 case hint_t::up:
31 return "up";
32 case hint_t::down:
33 return "down";
34 case hint_t::left:
35 return "left";
36 case hint_t::right:
37 return "right";
39 return "together";
40 case hint_t::row:
41 return "row";
42 case hint_t::column:
43 return "column";
44 default:
45 assert(false);
46 return "";
47 }
48}
49
50std::string to_string(const method_arguments ma)
51{
52 switch (ma) {
54 return "full";
56 return "abbreviated";
58 return "none";
59 default:
60 assert(false);
61 return "";
62 }
63}
64
65std::string to_string(method_type mt)
66{
67 switch (mt) {
69 return "constructor";
71 return "destructor";
73 return "assignment";
75 return "operator";
77 return "defaulted";
79 return "deleted";
81 return "static";
82 }
83
84 assert(false);
85 return "";
86}
87
88std::string to_string(callee_type mt)
89{
90 switch (mt) {
92 return "constructor";
94 return "assignment";
96 return "operator";
98 return "defaulted";
100 return "static";
102 return "method";
104 return "function";
106 return "function_template";
108 return "lambda";
110 return "cuda_kernel";
112 return "cuda_device";
113 }
114
115 assert(false);
116 return "";
117}
118
119std::string to_string(const comment_parser_t cp)
120{
121 switch (cp) {
123 return "clang";
125 return "plain";
126 default:
127 assert(false);
128 return "";
129 }
130}
131
132std::string to_string(location_t cp)
133{
134 switch (cp) {
136 return "fileline";
138 return "function";
140 return "marker";
141 default:
142 assert(false);
143 return "";
144 }
145}
146
148{
149 switch (pt) {
151 return "namespace";
153 return "directory";
155 return "module";
156 default:
157 assert(false);
158 return "";
159 }
160}
161
163{
164 switch (mo) {
166 return "lexical";
168 return "as_is";
169 default:
170 assert(false);
171 return "";
172 }
173}
175{
176 switch (cd) {
178 return "inward";
180 return "outward";
182 return "any";
183 default:
184 assert(false);
185 return "";
186 }
187}
188
190{
191 switch (fm) {
193 return "basic";
195 return "advanced";
196 default:
197 assert(false);
198 return "";
199 }
200}
201
202std::optional<std::string> plantuml::get_style(
203 const common::model::relationship_t relationship_type) const
204{
205 if (style.count(to_string(relationship_type)) == 0)
206 return {};
207
208 return style.at(to_string(relationship_type));
209}
210
211std::optional<std::string> plantuml::get_style(
212 const std::string &element_type) const
213{
214 if (style.count(element_type) == 0)
215 return {};
216
217 return style.at(element_type);
218}
219
221{
222 before.insert(before.end(), r.before.begin(), r.before.end());
223 after.insert(after.end(), r.after.begin(), r.after.end());
224 if (cmd.empty())
225 cmd = r.cmd;
226}
227
229{
230 before.insert(before.end(), r.before.begin(), r.before.end());
231 after.insert(after.end(), r.after.begin(), r.after.end());
232 if (cmd.empty())
233 cmd = r.cmd;
234}
235
237 const inheritable_diagram_options &parent)
238{
239 glob.override(parent.glob);
240 using_namespace.override(parent.using_namespace);
246 include.override(parent.include);
247 exclude.override(parent.exclude);
248 puml.override(parent.puml);
249 mermaid.override(parent.mermaid);
260 generate_links.override(parent.generate_links);
262 git.override(parent.git);
276}
277
279 std::string full_name) const
280{
282 aliases.insert(type_aliases().begin(), type_aliases().end());
283
284 bool matched{true};
285 while (matched) {
286 auto matched_in_iteration{false};
287 for (const auto &[pattern, replacement] : aliases) {
288 matched_in_iteration =
289 util::replace_all(full_name, pattern, replacement) ||
290 matched_in_iteration;
291 }
292 matched = matched_in_iteration;
293 }
294
295 return full_name;
296}
297
299{
302}
303
304std::vector<std::string> diagram::glob_translation_units(
305 const std::vector<std::string> &compilation_database_files) const
306{
307 // If glob is not defined use all translation units from the
308 // compilation database
309 if (!glob.has_value) {
310 return compilation_database_files;
311 }
312
313 // Otherwise, get all translation units matching the glob from diagram
314 // configuration
315 std::vector<std::string> result{};
316
317 LOG_DBG("Looking for translation units in {}", root_directory().string());
318
319 for (const auto &g : glob()) {
320 if (g.is_regex()) {
321 LOG_DBG("Searching glob regex {}", g.to_string());
322
323 std::regex regex_pattern(
324 g.to_string(), std::regex_constants::optimize);
325
326 std::copy_if(compilation_database_files.begin(),
327 compilation_database_files.end(), std::back_inserter(result),
328 [&regex_pattern](const auto &tu) {
329 std::smatch m;
330 return std::regex_search(tu, m, regex_pattern);
331 });
332 }
333 else {
334 std::filesystem::path absolute_glob_path{g.to_string()};
335
336#ifdef _MSC_VER
337 if (!absolute_glob_path.has_root_name())
338#else
339 if (!absolute_glob_path.is_absolute())
340#endif
341 absolute_glob_path = root_directory() / absolute_glob_path;
342
343 LOG_DBG("Searching glob path {}", absolute_glob_path.string());
344
345 auto matches = glob::glob(absolute_glob_path.string(), true, false);
346
347 for (const auto &match : matches) {
348 const auto path =
349 std::filesystem::canonical(root_directory() / match);
350
351 result.emplace_back(path.string());
352 }
353 }
354 }
355
356 return result;
357}
358
359std::filesystem::path diagram::root_directory() const
360{
361 return weakly_canonical(absolute(base_directory() / relative_to()));
362}
363
364std::filesystem::path diagram::make_path_relative(
365 const std::filesystem::path &p) const
366{
367 return relative(p, root_directory()).lexically_normal().string();
368}
369
370std::vector<std::string> diagram::make_module_relative(
371 const std::optional<std::string> &maybe_module) const
372{
373 if (!maybe_module)
374 return {};
375
376 auto module_path = common::model::path(
377 maybe_module.value(), common::model::path_type::kModule)
378 .tokens();
379
381 auto using_module_path = common::model::path(
383 .tokens();
384
385 if (util::starts_with(module_path, using_module_path)) {
386 util::remove_prefix(module_path, using_module_path);
387 }
388 }
389
390 return module_path;
391}
392
393std::optional<std::string> diagram::get_together_group(
394 const std::string &full_name) const
395{
396 const auto relative_name = using_namespace().relative(full_name);
397
398 for (const auto &[hint_target, hints] : layout()) {
399 for (const auto &hint : hints) {
400 if (hint.hint == hint_t::together) {
401 const auto &together_others =
402 std::get<std::vector<std::string>>(hint.entity);
403
404 if ((full_name == hint_target) ||
405 util::contains(together_others, full_name))
406 return hint_target;
407
408 if ((relative_name == hint_target) ||
409 util::contains(together_others, relative_name))
410 return hint_target;
411 }
412 }
413 }
414
415 return std::nullopt;
416}
417
419{
420 if (type_aliases().count("std::basic_string<char>") == 0U) {
421 type_aliases().insert({"std::basic_string<char>", "std::string"});
422 }
423 if (type_aliases().count("std::basic_string<char,std::char_traits<"
424 "char>,std::allocator<char>>") == 0U) {
425 type_aliases().insert({"std::basic_string<char,std::char_traits<"
426 "char>,std::allocator<char>>",
427 "std::string"});
428 }
429 if (type_aliases().count("std::basic_string<wchar_t>") == 0U) {
430 type_aliases().insert({"std::basic_string<wchar_t>", "std::wstring"});
431 }
432 if (type_aliases().count("std::basic_string<char16_t>") == 0U) {
433 type_aliases().insert(
434 {"std::basic_string<char16_t>", "std::u16string"});
435 }
436 if (type_aliases().count("std::basic_string<char32_t>") == 0U) {
437 type_aliases().insert(
438 {"std::basic_string<char32_t>", "std::u32string"});
439 }
440 if (type_aliases().count("std::integral_constant<bool,true>") == 0U) {
441 type_aliases().insert(
442 {"std::integral_constant<bool,true>", "std::true_type"});
443 }
444 if (type_aliases().count("std::integral_constant<bool,false>") == 0U) {
445 type_aliases().insert(
446 {"std::integral_constant<bool,false>", "std::false_type"});
447 }
448#if LLVM_VERSION_MAJOR >= 16
449 if (type_aliases().count("std::basic_string") == 0U) {
450 type_aliases().insert({"std::basic_string", "std::string"});
451 }
452#endif
453}
454
456{
458}
459
461{
463}
464
466{
468}
469
471{
473}
474
476{
478
479 if (relationship_hints().count("std::vector") == 0U) {
480 relationship_hints().insert({"std::vector", {}});
481 }
482 if (relationship_hints().count("std::unique_ptr") == 0U) {
483 relationship_hints().insert({"std::unique_ptr", {}});
484 }
485 if (relationship_hints().count("std::shared_ptr") == 0U) {
486 relationship_hints().insert(
487 {"std::shared_ptr", {relationship_t::kAssociation}});
488 }
489 if (relationship_hints().count("std::weak_ptr") == 0U) {
490 relationship_hints().insert(
491 {"std::weak_ptr", {relationship_t::kAssociation}});
492 }
493 if (relationship_hints().count("std::tuple") == 0U) {
494 relationship_hints().insert({"std::tuple", {}});
495 }
496 if (relationship_hints().count("std::map") == 0U) {
497 relationship_hint_t hint{relationship_t::kNone};
498 hint.argument_hints.insert({1, relationship_t::kAggregation});
499 relationship_hints().insert({"std::tuple", std::move(hint)});
500 }
501}
502
503template <> void append_value<plantuml>(plantuml &l, const plantuml &r)
504{
505 l.append(r);
506}
507} // namespace clanguml::config