From abc1cb144a905450ed9e4dd6e9e036c285735753 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 15 Sep 2021 14:08:49 +0200 Subject: [PATCH] Refactored sequence diagram visitor --- src/uml/sequence_diagram_model.cc | 23 +++++ src/uml/sequence_diagram_model.h | 2 - src/uml/sequence_diagram_visitor.cc | 150 ++++++++++++++++++++++++++++ src/uml/sequence_diagram_visitor.h | 124 +---------------------- 4 files changed, 178 insertions(+), 121 deletions(-) create mode 100644 src/uml/sequence_diagram_model.cc create mode 100644 src/uml/sequence_diagram_visitor.cc diff --git a/src/uml/sequence_diagram_model.cc b/src/uml/sequence_diagram_model.cc new file mode 100644 index 00000000..64c760c7 --- /dev/null +++ b/src/uml/sequence_diagram_model.cc @@ -0,0 +1,23 @@ +/** + * src/uml/sequence_diagram_model.cc + * + * Copyright (c) 2021 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sequence_diagram_visitor.h" + +namespace clanguml::model::sequence_diagram { + +} diff --git a/src/uml/sequence_diagram_model.h b/src/uml/sequence_diagram_model.h index 395a3714..f100a170 100644 --- a/src/uml/sequence_diagram_model.h +++ b/src/uml/sequence_diagram_model.h @@ -54,8 +54,6 @@ struct diagram { std::string name; std::map sequences; - - void sort() { } }; } } diff --git a/src/uml/sequence_diagram_visitor.cc b/src/uml/sequence_diagram_visitor.cc new file mode 100644 index 00000000..0f438a96 --- /dev/null +++ b/src/uml/sequence_diagram_visitor.cc @@ -0,0 +1,150 @@ +/** + * src/uml/sequence_diagram_visitor.cc + * + * Copyright (c) 2021 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sequence_diagram_visitor.h" + +namespace clanguml::visitor::sequence_diagram { + +// +// tu_context +// + +tu_context::tu_context(clanguml::model::sequence_diagram::diagram &d_, + const clanguml::config::sequence_diagram &config_) + : d{d_} + , config{config_} +{ +} + +enum CXChildVisitResult translation_unit_visitor( + CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data) +{ + using clanguml::model::sequence_diagram::activity; + using clanguml::model::sequence_diagram::diagram; + using clanguml::model::sequence_diagram::message; + using clanguml::model::sequence_diagram::message_t; + + struct tu_context *ctx = (struct tu_context *)client_data; + + enum CXChildVisitResult ret = CXChildVisit_Break; + + cx::cursor cursor{std::move(cx_cursor)}; + cx::cursor parent{std::move(cx_parent)}; + + if (cursor.spelling().empty()) { + return CXChildVisit_Recurse; + } + + switch (cursor.kind()) { + case CXCursor_FunctionTemplate: + case CXCursor_CXXMethod: + case CXCursor_FunctionDecl: + ctx->current_method = cursor; + ret = CXChildVisit_Recurse; + break; + case CXCursor_CallExpr: { + auto referenced = cursor.referenced(); + auto referenced_type = referenced.type(); + auto referenced_cursor_name = referenced.display_name(); + + auto semantic_parent = referenced.semantic_parent(); + auto sp_name = semantic_parent.fully_qualified(); + auto lexical_parent = cursor.lexical_parent(); + auto lp_name = lexical_parent.spelling(); + + CXFile f; + unsigned int line{}; + unsigned int column{}; + unsigned int offset{}; + clang_getFileLocation(cursor.location(), &f, &line, &column, &offset); + std::string file{clang_getCString(clang_getFileName(f))}; + + auto &d = ctx->d; + auto &config = ctx->config; + if (referenced.kind() == CXCursor_CXXMethod) { + if (config.should_include(sp_name)) { + // Get calling object + std::string caller{}; + if (ctx->current_method.semantic_parent() + .is_translation_unit() || + ctx->current_method.semantic_parent().is_namespace()) { + caller = ctx->current_method.semantic_parent() + .fully_qualified() + + "::" + ctx->current_method.spelling() + "()"; + } + else { + caller = + ctx->current_method.semantic_parent().fully_qualified(); + } + + auto caller_usr = ctx->current_method.usr(); + // Get called object + auto callee = referenced.semantic_parent().fully_qualified(); + auto callee_usr = referenced.semantic_parent().usr(); + + // Get called method + auto called_message = cursor.spelling(); + + // Found method call: CXCursorKind () const + spdlog::debug("Adding method call at line {}:{} to diagram {}" + "\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: " + "{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: " + "{}\n\tRETURN_TYPE: {}", + file, line, d.name, ctx->current_method.spelling(), caller, + callee, called_message, caller_usr, callee_usr, + referenced.type().result_type().spelling()); + + message m; + m.type = message_t::kCall; + m.from = caller; + m.from_usr = caller_usr; + m.line = line; + m.to = callee; + m.to_usr = referenced.usr(); + m.message = called_message; + m.return_type = referenced.type().result_type().spelling(); + + if (d.sequences.find(caller_usr) == d.sequences.end()) { + activity a; + a.usr = caller_usr; + a.from = caller; + d.sequences.insert({caller_usr, std::move(a)}); + } + + d.sequences[caller_usr].messages.emplace_back(std::move(m)); + } + } + else if (referenced.kind() == CXCursor_FunctionDecl) { + // TODO + } + + ret = CXChildVisit_Recurse; + break; + } + case CXCursor_Namespace: { + ret = CXChildVisit_Recurse; + break; + } + default: + ret = CXChildVisit_Recurse; + } + + return ret; +} + +} diff --git a/src/uml/sequence_diagram_visitor.h b/src/uml/sequence_diagram_visitor.h index 7ee9bd0f..cfdfbdfa 100644 --- a/src/uml/sequence_diagram_visitor.h +++ b/src/uml/sequence_diagram_visitor.h @@ -19,6 +19,7 @@ #include "cx/cursor.h" #include "sequence_diagram_model.h" +#include "config/config.h" #include #include @@ -32,17 +33,9 @@ namespace clanguml { namespace visitor { namespace sequence_diagram { -using clanguml::model::sequence_diagram::activity; -using clanguml::model::sequence_diagram::diagram; -using clanguml::model::sequence_diagram::message; -using clanguml::model::sequence_diagram::message_t; - struct tu_context { - tu_context(diagram &d_, const clanguml::config::sequence_diagram &config_) - : d{d_} - , config{config_} - { - } + tu_context(clanguml::model::sequence_diagram::diagram &d_, + const clanguml::config::sequence_diagram &config_); std::vector namespace_; cx::cursor current_method; @@ -50,116 +43,9 @@ struct tu_context { const clanguml::config::sequence_diagram &config; }; -static enum CXChildVisitResult translation_unit_visitor( - CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data) -{ - struct tu_context *ctx = (struct tu_context *)client_data; +enum CXChildVisitResult translation_unit_visitor( + CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data); - enum CXChildVisitResult ret = CXChildVisit_Break; - - cx::cursor cursor{std::move(cx_cursor)}; - cx::cursor parent{std::move(cx_parent)}; - - if (cursor.spelling().empty()) { - return CXChildVisit_Recurse; - } - - switch (cursor.kind()) { - case CXCursor_FunctionTemplate: - case CXCursor_CXXMethod: - case CXCursor_FunctionDecl: - ctx->current_method = cursor; - ret = CXChildVisit_Recurse; - break; - case CXCursor_CallExpr: { - auto referenced = cursor.referenced(); - auto referenced_type = referenced.type(); - auto referenced_cursor_name = referenced.display_name(); - - auto semantic_parent = referenced.semantic_parent(); - auto sp_name = semantic_parent.fully_qualified(); - auto lexical_parent = cursor.lexical_parent(); - auto lp_name = lexical_parent.spelling(); - - CXFile f; - unsigned int line{}; - unsigned int column{}; - unsigned int offset{}; - clang_getFileLocation(cursor.location(), &f, &line, &column, &offset); - std::string file{clang_getCString(clang_getFileName(f))}; - - auto &d = ctx->d; - auto &config = ctx->config; - if (referenced.kind() == CXCursor_CXXMethod) { - if (config.should_include(sp_name)) { - // Get calling object - std::string caller{}; - if (ctx->current_method.semantic_parent() - .is_translation_unit() || - ctx->current_method.semantic_parent().is_namespace()) { - caller = ctx->current_method.semantic_parent() - .fully_qualified() + - "::" + ctx->current_method.spelling() + "()"; - } - else { - caller = - ctx->current_method.semantic_parent().fully_qualified(); - } - - auto caller_usr = ctx->current_method.usr(); - // Get called object - auto callee = referenced.semantic_parent().fully_qualified(); - auto callee_usr = referenced.semantic_parent().usr(); - - // Get called method - auto called_message = cursor.spelling(); - - // Found method call: CXCursorKind () const - spdlog::debug("Adding method call at line {}:{} to diagram {}" - "\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: " - "{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: " - "{}\n\tRETURN_TYPE: {}", - file, line, d.name, ctx->current_method.spelling(), caller, - callee, called_message, caller_usr, callee_usr, - referenced.type().result_type().spelling()); - - message m; - m.type = message_t::kCall; - m.from = caller; - m.from_usr = caller_usr; - m.line = line; - m.to = callee; - m.to_usr = referenced.usr(); - m.message = called_message; - m.return_type = referenced.type().result_type().spelling(); - - if (d.sequences.find(caller_usr) == d.sequences.end()) { - activity a; - a.usr = caller_usr; - a.from = caller; - d.sequences.insert({caller_usr, std::move(a)}); - } - - d.sequences[caller_usr].messages.emplace_back(std::move(m)); - } - } - else if (referenced.kind() == CXCursor_FunctionDecl) { - // TODO - } - - ret = CXChildVisit_Recurse; - break; - } - case CXCursor_Namespace: { - ret = CXChildVisit_Recurse; - break; - } - default: - ret = CXChildVisit_Recurse; - } - - return ret; -} } } }