0.6.0
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
compilation_database.cc
Go to the documentation of this file.
1/**
2 * @file src/common/compilation_database.cc
3 *
4 * Copyright (c) 2021-2025 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
20#include "util/error.h"
22
23namespace clanguml::common {
24
25std::unique_ptr<compilation_database>
27 const clanguml::config::config &cfg)
28{
29 std::string error_message;
30 auto res = clang::tooling::CompilationDatabase::autoDetectFromDirectory(
31 cfg.compilation_database_dir(), error_message);
32
33 if (!error_message.empty())
34 throw error::compilation_database_error(error_message);
35
36 if (res.get() == nullptr)
37 throw error::compilation_database_error(fmt::format(
38 "Autodetection of compilation database from directory '{}' failed",
40
41 // This is a workaround to determine whether Clang loaded a fixed
42 // compilation database or a proper one. This cannot be done with
43 // dynamic_cast if RTTI was not enabled in the LLVM build
44 bool is_fixed{res->getAllFiles().empty()};
45
46 return std::make_unique<compilation_database>(
47 std::move(res), cfg, is_fixed);
48}
49
51 std::unique_ptr<clang::tooling::CompilationDatabase> base,
52 const clanguml::config::config &cfg, bool is_fixed)
53 : base_{std::move(base)}
54 , config_{cfg}
55 , is_fixed_{is_fixed}
56{
57}
58
60
62{
63 return config_;
64}
65
66const clang::tooling::CompilationDatabase &compilation_database::base() const
67{
68 return *base_;
69}
70
71std::vector<std::string> compilation_database::getAllFiles() const
72{
73 return base().getAllFiles();
74}
75
76std::vector<clang::tooling::CompileCommand>
77compilation_database::getCompileCommands(clang::StringRef FilePath) const
78{
79 auto commands = base().getCompileCommands(FilePath);
80
82
83 return commands;
84}
85
86std::vector<clang::tooling::CompileCommand>
88{
89 auto commands = base().getAllCompileCommands();
90
92
93 return commands;
94}
95
97 const std::string &filename) const
98{
99 if (util::ends_with(filename, std::string{".c"}))
100 return "c";
101
102 return "c++";
103}
104
106 const std::vector<std::string> &files) const
107{
108 if (is_fixed())
109 return files.size();
110
111 auto result{0UL};
112
113 for (const auto &f : files) {
114 result += getCompileCommands(f).size();
115 }
116
117 return result;
118}
119
121 std::vector<clang::tooling::CompileCommand> &commands) const
122{
123#if !defined(_WIN32)
124 if (config().query_driver && !config().query_driver().empty()) {
125 for (auto &compile_command : commands) {
126 auto argv0 = config().query_driver() == "."
127 ? compile_command.CommandLine.at(0)
128 : config().query_driver();
129
131 argv0, guess_language_from_filename(compile_command.Filename)};
132
133 extractor.execute();
134
135 std::vector<std::string> system_header_args;
136 for (const auto &path : extractor.system_include_paths()) {
137 system_header_args.emplace_back("-isystem");
138 system_header_args.emplace_back(path);
139 }
140
141 compile_command.CommandLine.insert(
142 compile_command.CommandLine.begin() + 1,
143 system_header_args.begin(), system_header_args.end());
144
145 if (!extractor.target().empty()) {
146 compile_command.CommandLine.insert(
147 compile_command.CommandLine.begin() + 1,
148 fmt::format("--target={}", extractor.target()));
149 }
150 }
151 }
152#endif
153
154 if (config().add_compile_flags && !config().add_compile_flags().empty()) {
155 for (auto &compile_command : commands) {
156 compile_command.CommandLine.insert(
157 // Add flags after argv[0]
158 compile_command.CommandLine.begin() + 1,
159 config().add_compile_flags().begin(),
160 config().add_compile_flags().end());
161 }
162 }
163
165 !config().remove_compile_flags().empty()) {
166 for (auto &compile_command : commands) {
167 for (const auto &flag : config().remove_compile_flags()) {
168 util::erase_if(compile_command.CommandLine,
169 [&flag](const auto &arg) { return flag == arg; });
170 }
171 }
172 }
173}
174
176 const clang::tooling::CompileCommand &command,
177 const std::string &file) const
178{
179 auto command_filename = std::filesystem::path{command.Filename};
180
181 if (!command_filename.is_absolute()) {
182 command_filename = config().root_directory() / command_filename;
183 }
184
185 return (command_filename == file) ||
186 (command_filename.lexically_normal().string() == file);
187}
188} // namespace clanguml::common