0.5.4
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
diagram.h
Go to the documentation of this file.
1/**
2 * @file src/sequence_diagram/model/diagram.h
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#pragma once
19
20#include "activity.h"
22#include "common/types.h"
23#include "config/config.h"
24#include "participant.h"
25
26#include <map>
27#include <string>
28
30
31using message_chain_t = std::vector<sequence_diagram::model::message>;
32
33/**
34 * @brief Model of a sequence diagram
35 *
36 * @embed{sequence_model_class.svg}
37 */
39public:
40 diagram() = default;
41
42 diagram(const diagram &) = delete;
43 diagram(diagram &&) = default;
44 diagram &operator=(const diagram &) = delete;
45 diagram &operator=(diagram &&) = default;
46
47 /**
48 * @brief Get the diagram model type - in this case sequence.
49 *
50 * @return Type of sequence diagram.
51 */
52 common::model::diagram_t type() const override;
53
54 /**
55 * @brief Search for element in the diagram by fully qualified name.
56 *
57 * @param full_name Fully qualified element name.
58 * @return Optional reference to a diagram element.
59 */
61 const std::string &full_name) const override;
62
63 /**
64 * @brief Search for element in the diagram by id.
65 *
66 * @param id Element id.
67 * @return Optional reference to a diagram element.
68 */
70 eid_t id) const override;
71
72 /**
73 * @brief Get participant by id
74 *
75 * @param id Participant id.
76 * @return Optional reference to a diagram element.
77 */
78 template <typename T>
80 {
81 if (participants_.find(id) == participants_.end()) {
82 return {};
83 }
84
86 dynamic_cast<T *>(participants_.at(id).get()));
87 }
88
89 /**
90 * @brief Add sequence diagram participant
91 *
92 * @param p Sequence diagram participant model
93 */
94 void add_participant(std::unique_ptr<participant> p);
95
96 /**
97 * @brief Set participant with `id` as active
98 *
99 * @param id Id of participant to activate
100 */
102
103 /**
104 * @brief Check if diagram has activity identified by caller id
105 *
106 * @param id Caller id representing the activity
107 * @return True, if an activity already exists
108 */
109 bool has_activity(eid_t id) const;
110
111 /**
112 * @brief Get reference to current activity of a participant
113 *
114 * @param id Participant id
115 * @return
116 */
117 const activity &get_activity(eid_t id) const;
118
119 /**
120 * @brief Get reference to current activity of a participant
121 *
122 * @param id Participant id
123 * @return
124 */
126
127 /**
128 * @brief Add message to current activity
129 *
130 * @param message Message model
131 */
133
134 /**
135 * @brief Add block message to the current activity
136 *
137 * Block messages represent sequence diagram blocks such as `alt`
138 * or `loop`.
139 *
140 * The block messages can be stacked.
141 *
142 * @param message Message model
143 */
145
146 /**
147 * @brief End current block message
148 *
149 * @param message Message model
150 * @param start_type Type of block statement.
151 */
154
155 /**
156 * @brief Add `switch` block `case` statement
157 * @param m Message model
158 */
160
161 /**
162 * @brief Get all sequences in the diagram
163 *
164 * @return Map of sequences in the diagram
165 */
166 std::map<eid_t, activity> &sequences();
167
168 /**
169 * @brief Get all sequences in the diagram
170 *
171 * @return Map of sequences in the diagram
172 */
173 const std::map<eid_t, activity> &sequences() const;
174
175 /**
176 * @brief Get map of all participants in the diagram
177 *
178 * @return Map of participants in the diagram
179 */
180 std::map<eid_t, std::unique_ptr<participant>> &participants();
181
182 /**
183 * @brief Get map of all participants in the diagram
184 *
185 * @return Map of participants in the diagram
186 */
187 const std::map<eid_t, std::unique_ptr<participant>> &participants() const;
188
189 /**
190 * @brief Get all active participants in the diagram
191 *
192 * @return Set of all active participant ids
193 */
194 std::set<eid_t> &active_participants();
195
196 /**
197 * @brief Get all active participants in the diagram
198 *
199 * @return Set of all active participant ids
200 */
201 const std::set<eid_t> &active_participants() const;
202
203 /**
204 * @brief Convert element full name to PlantUML alias.
205 *
206 * @todo This method does not belong here - refactor to PlantUML specific
207 * code.
208 *
209 * @param full_name Full name of the diagram element.
210 * @return PlantUML alias.
211 */
212 std::string to_alias(const std::string &full_name) const;
213
214 /**
215 * @brief Return the elements JSON context for inja templates.
216 *
217 * @return JSON node with elements context.
218 */
219 inja::json context() const override;
220
221 /**
222 * @brief Debug method for printing entire diagram to console.
223 */
224 void print() const;
225
226 // Implicitly import should_include overloads from base class
228
229 /**
230 * @brief Convenience `should_include` overload for participant
231 * @param p Participant model
232 * @return True, if the participant should be included in the diagram
233 */
235
236 /**
237 * @brief Get list of all possible 'from' values in the model
238 *
239 * @return List of all possible 'from' values
240 */
241 std::vector<std::string> list_from_values() const;
242
243 /**
244 * @brief Get list of all possible 'to' values in the model
245 *
246 * @return List of all possible 'to' values
247 */
248 std::vector<std::string> list_to_values() const;
249
250 /**
251 * @brief Generate a list of message chains matching a from_to constraint
252 *
253 * If 'from_activity' is 0, this method will return all message chains
254 * ending in 'to_activity'.
255 *
256 * @param from_activity Source activity for from_to message chain
257 * @param to_activity Target activity for from_to message chain
258 * @return List of message chains
259 */
260 std::vector<message_chain_t> get_all_from_to_message_chains(
261 eid_t from_activity, eid_t to_activity) const;
262
263 /**
264 * @brief Get id of a 'to' activity
265 *
266 * @param to_location Target activity
267 * @return Activity id
268 */
269 std::optional<eid_t> get_to_activity_id(
270 const config::source_location &to_location) const;
271
272 /**
273 * @brief Get id of a 'from' activity
274 *
275 * @param from_location Source activity
276 * @return Activity id
277 */
278 std::optional<eid_t> get_from_activity_id(
279 const config::source_location &from_location) const;
280
281 /**
282 * @brief Once the diagram is complete, run any final processing.
283 *
284 * This method should be overriden by specific diagram models to do some
285 * final tasks like cleaning up the model (e.g. some filters only work
286 * on completed diagrams).
287 */
288 void finalize() override;
289
290 /**
291 * @brief Check whether the diagram is empty
292 *
293 * @return True, if diagram is empty
294 */
295 bool is_empty() const override;
296
297 /**
298 * If option to inline lambda calls is enabled, we need to modify the
299 * sequences to skip the lambda calls. In case lambda call does not lead
300 * to a non-lambda call, omit it entirely
301 */
303
304private:
305 /**
306 * This method checks the last messages in sequence (current_messages),
307 * if they represent a block sequence identified by statement_begin
308 * (e.g. if/else) and there are no actual call expressions within this block
309 * statement the entire block statement is removed from the end of the
310 * sequence.
311 *
312 * Otherwise the block statement is ended with a proper statement
313 * (e.g. endif)
314 *
315 * @param m Message to add to the sequence
316 * @param statement_begin Type of message which begins this type of block
317 * statement (e.g. message_t::kIf)
318 * @param current_messages Reference to the sequence messages which should
319 * be amended
320 */
322 common::model::message_t statement_begin,
323 std::vector<message> &current_messages) const;
324
326 {
328 static std::set<message_t> block_begin_types{message_t::kIf,
329 message_t::kWhile, message_t::kDo, message_t::kFor, message_t::kTry,
330 message_t::kSwitch, message_t::kConditional};
331
332 return block_begin_types.count(mt) > 0;
333 };
334
336 {
338 static std::set<message_t> block_end_types{message_t::kIfEnd,
339 message_t::kWhileEnd, message_t::kDoEnd, message_t::kForEnd,
340 message_t::kTryEnd, message_t::kSwitchEnd,
341 message_t::kConditionalEnd};
342
343 return block_end_types.count(mt) > 0;
344 };
345
347 eid_t id, model::activity &new_activity, const model::message &m);
348
349 std::map<eid_t, activity> activities_;
350
351 std::map<eid_t, std::unique_ptr<participant>> participants_;
352
353 std::set<eid_t> active_participants_;
354};
355
356} // namespace clanguml::sequence_diagram::model
357
358namespace clanguml::common::model {
359template <>
361 diagram_t t);
362}