Skip to content

Commit

Permalink
Adding Objective C sequence diagram support, continued... (#296)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkryza committed Sep 19, 2024
1 parent 2bf079f commit 900a127
Show file tree
Hide file tree
Showing 12 changed files with 617 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,11 @@ void generator::generate(const objc_interface &c, std::ostream &ostr) const
ostr << " {" << '\n';

if (c.is_protocol())
ostr << indent(2) << "<<ObjC Protocol>>\n";
ostr << indent(2) << "<< ObjC Protocol >>\n";
else if (c.is_protocol())
ostr << indent(2) << "<<ObjC Category>>\n";
ostr << indent(2) << "<< ObjC Category >>\n";
else
ostr << indent(2) << "<<ObjC Interface>>\n";
ostr << indent(2) << "<< ObjC Interface >>\n";

//
// Process methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
const auto &f = dynamic_cast<const model::method &>(to.value());
message = f.message_name(render_mode);
}
else if (to.value().type_name() == "objc_method") {
const auto &f = dynamic_cast<const model::objc_method &>(to.value());
message = f.message_name(render_mode);
}
else if (config().combine_free_functions_into_file_participants()) {
if (to.value().type_name() == "function") {
const auto &f = dynamic_cast<const model::function &>(to.value());
Expand Down Expand Up @@ -420,6 +424,34 @@ void generator::generate_participant(

generated_participants_.emplace(class_id);
}
else if (participant.type_name() == "objc_method") {
const auto class_id =
model()
.get_participant<model::objc_method>(participant_id)
.value()
.class_id();

if (is_participant_generated(class_id))
return;

const auto &class_participant =
model().get_participant<model::participant>(class_id).value();

print_debug(class_participant, ostr);

auto participant_name =
config().using_namespace().relative(config().simplify_template_type(
class_participant.full_name(false)));
common::ensure_lambda_type_is_relative(config(), participant_name);

ostr << indent(1) << "participant " << class_participant.alias()
<< " as " << render_participant_name(participant_name)
<< " << ObjC Interface >>";

ostr << '\n';

generated_participants_.emplace(class_id);
}
else if ((participant.type_name() == "function" ||
participant.type_name() == "function_template") &&
config().combine_free_functions_into_file_participants()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
message =
fmt::format("{}{}{}", style, f.message_name(render_mode), style);
}
if (to.value().type_name() == "objc_method") {
const auto &f = dynamic_cast<const model::objc_method &>(to.value());
const std::string_view style = f.is_static() ? "__" : "";
message =
fmt::format("{}{}{}", style, f.message_name(render_mode), style);
}
else if (config().combine_free_functions_into_file_participants()) {
if (to.value().type_name() == "function") {
const auto &f = dynamic_cast<const model::function &>(to.value());
Expand Down Expand Up @@ -429,6 +435,40 @@ void generator::generate_participant(

generated_participants_.emplace(class_id);
}
else if (participant.type_name() == "objc_method") {
const auto class_id =
model()
.get_participant<model::objc_method>(participant_id)
.value()
.class_id();

if (is_participant_generated(class_id))
return;

const auto &class_participant =
model().get_participant<model::participant>(class_id).value();

print_debug(class_participant, ostr);

auto participant_name =
config().simplify_template_type(class_participant.full_name(false));
participant_name =
config().using_namespace().relative(participant_name);

common::ensure_lambda_type_is_relative(config(), participant_name);

ostr << "participant \"" << render_name(participant_name) << "\" as "
<< class_participant.alias() << " <<ObjC Interface>>";

if (config().generate_links) {
common_generator<diagram_config, diagram_model>::generate_link(
ostr, class_participant);
}

ostr << '\n';

generated_participants_.emplace(class_id);
}
else if ((participant.type_name() == "function" ||
participant.type_name() == "function_template") &&
config().combine_free_functions_into_file_participants()) {
Expand Down Expand Up @@ -554,6 +594,7 @@ void generator::generate_diagram(std::ostream &ostr) const
model().get_participant<model::function>(*from_activity_id);

if (from.value().type_name() == "method" ||
from.value().type_name() == "objc_method" ||
config().combine_free_functions_into_file_participants()) {
generate_participant(ostr, *from_activity_id);
ostr << "[->"
Expand Down Expand Up @@ -594,6 +635,7 @@ void generator::generate_diagram(std::ostream &ostr) const
model().get_participant<model::function>(from_activity_id);

if (from.value().type_name() == "method" ||
from.value().type_name() == "objc_method" ||
config().combine_free_functions_into_file_participants()) {
generate_participant(ostr, from_activity_id);
ostr << "[->"
Expand Down Expand Up @@ -660,6 +702,7 @@ void generator::generate_diagram(std::ostream &ostr) const
// 'entry' point call to know which method relates to the
// first activity for this 'start_from' condition
if (from.value().type_name() == "method" ||
from.value().type_name() == "objc_method" ||
config().combine_free_functions_into_file_participants()) {
ostr << "[->"
<< " " << from_alias << " : "
Expand All @@ -671,6 +714,7 @@ void generator::generate_diagram(std::ostream &ostr) const
generate_activity(start_from, ostr, visited_participants);

if (from.value().type_name() == "method" ||
from.value().type_name() == "objc_method" ||
config().combine_free_functions_into_file_participants()) {

if (!from.value().is_void()) {
Expand Down
82 changes: 82 additions & 0 deletions src/sequence_diagram/model/participant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ bool class_::is_lambda() const { return is_lambda_; }

void class_::is_lambda(bool is_lambda) { is_lambda_ = is_lambda; }

bool class_::is_objc_interface() const { return is_objc_interface_; }

void class_::is_objc_interface(bool is_objc_interface)
{
is_objc_interface_ = is_objc_interface;
}

bool class_::is_objc_protocol() const { return is_objc_protocol_; }

void class_::is_objc_protocol(bool is_objc_protocol)
{
is_objc_protocol_ = is_objc_protocol;
}

bool operator==(const class_ &l, const class_ &r) { return l.id() == r.id(); }

function::function(const common::model::namespace_ &using_namespace)
Expand Down Expand Up @@ -169,6 +183,74 @@ const std::vector<std::string> &function::parameters() const
return parameters_;
}

objc_method::objc_method(const common::model::namespace_ &using_namespace)
: function{using_namespace}
{
}

std::string objc_method::method_name() const { return method_name_; }

std::string objc_method::alias() const
{
assert(class_id_.is_global());

return fmt::format("C_{:022}", class_id_.value());
}

void objc_method::set_method_name(const std::string &name)
{
method_name_ = name;
}

void objc_method::set_class_id(eid_t id) { class_id_ = id; }

void objc_method::set_class_full_name(const std::string &name)
{
class_full_name_ = name;
}

const auto &objc_method::class_full_name() const { return class_full_name_; }

std::string objc_method::full_name(bool relative) const
{
if (relative)
return fmt::format("{}({}){}", method_name(),
fmt::join(parameters(), ","), is_const() ? " const" : "");

return fmt::format("{}::{}({}){}", class_full_name(), method_name(),
fmt::join(parameters(), ","), is_const() ? " const" : "");
}

std::string objc_method::message_name(message_render_mode mode) const
{
constexpr auto kAbbreviatedMethodArgumentsLength{15};

const std::string style{};

if (mode == message_render_mode::no_arguments) {
return fmt::format("{}{}(){}{}", style, method_name(),
is_const() ? " const" : "", style);
}
if (mode == message_render_mode::abbreviated) {
return fmt::format("{}({}){}", name(),
clanguml::util::abbreviate(
fmt::format("{}", fmt::join(parameters(), ",")),
kAbbreviatedMethodArgumentsLength),
is_const() ? " const" : "");
}

return fmt::format("{}{}({}){}{}", style, method_name(),
fmt::join(parameters(), ","), is_const() ? " const" : "", style);
}

eid_t objc_method::class_id() const { return class_id_; }

std::string objc_method::to_string() const
{
return fmt::format("Participant '{}': id={}, name={}, class_id={}",
type_name(), id(), full_name(false), class_id());
}

method::method(const common::model::namespace_ &using_namespace)
: function{using_namespace}
{
Expand Down
102 changes: 102 additions & 0 deletions src/sequence_diagram/model/participant.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ struct class_ : public participant {
if (is_lambda())
return "lambda";

if (is_objc_interface())
return "objc_interface";

return "class";
}

Expand Down Expand Up @@ -191,6 +194,14 @@ struct class_ : public participant {
*/
void is_lambda(bool is_lambda);

bool is_objc_interface() const;

void is_objc_interface(bool is_objc_interface);

bool is_objc_protocol() const;

void is_objc_protocol(bool is_objc_protocol);

void set_lambda_operator_id(eid_t id) { lambda_operator_id_ = id; }

eid_t lambda_operator_id() const { return lambda_operator_id_; }
Expand All @@ -201,6 +212,8 @@ struct class_ : public participant {
bool is_template_instantiation_{false};
bool is_alias_{false};
bool is_lambda_{false};
bool is_objc_interface_{false};
bool is_objc_protocol_{false};
eid_t lambda_operator_id_{};

std::string full_name_;
Expand Down Expand Up @@ -511,6 +524,95 @@ struct method : public function {
bool is_assignment_{false};
};

struct objc_method : public function {
objc_method(const common::model::namespace_ &using_namespace);

objc_method(const objc_method &) = delete;
objc_method(objc_method &&) noexcept = delete;
objc_method &operator=(const objc_method &) = delete;
objc_method &operator=(objc_method &&) = delete;

/**
* Get the type name of the diagram element.
*
* @return Type name of the diagram element.
*/
std::string type_name() const override { return "objc_method"; }

/**
* @brief Get method name
* @return Method name
*/
std::string method_name() const;

/**
* @brief Set method name
*
* @param name Method name
*/
void set_method_name(const std::string &name);

/**
* @brief Get the participant PlantUML alias
*
* @todo This method does not belong here - refactor to PlantUML specific
* code.
*
* @return PlantUML alias for the participant to which this method belongs
* to.
*/
std::string alias() const override;

/**
* @brief Set the id of the participant to which this method belongs to.
*
* @param id Id of the class to which this method belongs to
*/
void set_class_id(eid_t id);

/**
* @brief Set full qualified name of the class
*
* @param name Name of the class including namespace
*/
void set_class_full_name(const std::string &name);

/**
* @brief Get the class full name.
*
* @return Class full name
*/
const auto &class_full_name() const;

/**
* Return elements full name.
*
* @return Fully qualified elements name.
*/
std::string full_name(bool relative) const override;

std::string message_name(message_render_mode mode) const override;

/**
* @brief Get the class id
*
* @return Class id
*/
eid_t class_id() const;

/**
* @brief Create a string representation of the participant
*
* @return Participant representation as string
*/
std::string to_string() const override;

private:
eid_t class_id_{};
std::string method_name_;
std::string class_full_name_;
};

/**
* @brief Participant model representing a function template.
*/
Expand Down
Loading

0 comments on commit 900a127

Please sign in to comment.