From 57456705bde897511f2a8430428708ffa45b581d Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 27 Feb 2022 11:42:20 +0100 Subject: [PATCH 01/14] Added svg formatter for diagrams stored in git to minimize diffs --- Makefile | 1 + docs/test_cases/t00002_class.svg | 152 ++++++----- docs/test_cases/t00003_class.svg | 116 +++++---- docs/test_cases/t00004_class.svg | 101 ++++---- docs/test_cases/t00005_class.svg | 259 ++++++++++--------- docs/test_cases/t00006_class.svg | 375 ++++++++++++++++------------ docs/test_cases/t00007_class.svg | 95 +++---- docs/test_cases/t00008_class.svg | 130 ++++++---- docs/test_cases/t00009_class.svg | 132 +++++----- docs/test_cases/t00010_class.svg | 122 +++++---- docs/test_cases/t00011_class.svg | 85 ++++--- docs/test_cases/t00012_class.svg | 223 ++++++++++------- docs/test_cases/t00013_class.svg | 258 +++++++++++-------- docs/test_cases/t00014_class.svg | 252 +++++++++++-------- docs/test_cases/t00015_class.svg | 91 +++---- docs/test_cases/t00016_class.svg | 121 +++++---- docs/test_cases/t00017_class.svg | 245 ++++++++++-------- docs/test_cases/t00018_class.svg | 101 ++++---- docs/test_cases/t00019_class.svg | 211 +++++++++------- docs/test_cases/t00020_class.svg | 208 ++++++++------- docs/test_cases/t00021_class.svg | 207 ++++++++------- docs/test_cases/t00022_class.svg | 89 ++++--- docs/test_cases/t00023_class.svg | 128 +++++----- docs/test_cases/t00024_class.svg | 126 +++++----- docs/test_cases/t00025_class.svg | 157 +++++++----- docs/test_cases/t00026_class.svg | 179 +++++++------ docs/test_cases/t00027_class.svg | 253 +++++++++++-------- docs/test_cases/t00028_class.svg | 296 ++++++++++++---------- docs/test_cases/t00029_class.svg | 151 +++++------ docs/test_cases/t00030_class.svg | 123 +++++---- docs/test_cases/t00031_class.svg | 156 +++++++----- docs/test_cases/t00032_class.svg | 180 +++++++------ docs/test_cases/t00033_class.svg | 172 +++++++------ docs/test_cases/t00034_class.svg | 138 +++++----- docs/test_cases/t00035_class.svg | 90 ++++--- docs/test_cases/t00036_class.svg | 138 +++++----- docs/test_cases/t20001_sequence.svg | 95 ++++--- docs/test_cases/t20002_sequence.svg | 70 ++++-- docs/test_cases/t30001_package.svg | 90 +++---- docs/test_cases/t30002_package.svg | 176 ++++++------- docs/test_cases/t30003_package.svg | 69 +++-- docs/test_cases/t30004_package.svg | 94 +++---- docs/test_cases/t30005_package.svg | 91 ++++--- docs/test_cases/t30006_package.svg | 71 +++--- docs/test_cases/t30007_package.svg | 81 +++--- docs/test_cases/t90000_class.svg | 80 +++--- util/format_svg.py | 51 ++++ 47 files changed, 3852 insertions(+), 2977 deletions(-) create mode 100755 util/format_svg.py diff --git a/Makefile b/Makefile index 3dc88576..fa43cc4f 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ test_plantuml: test document_test_cases: test_plantuml python3 util/generate_test_cases_docs.py + python3 util/format_svg.py docs/test_cases/*.svg clanguml_diagrams: debug mkdir -p docs/diagrams diff --git a/docs/test_cases/t00002_class.svg b/docs/test_cases/t00002_class.svg index 9af0b1d9..63e03bea 100644 --- a/docs/test_cases/t00002_class.svg +++ b/docs/test_cases/t00002_class.svg @@ -1,67 +1,85 @@ -Afoo_a() = 0 : voidfoo_c() = 0 : voidBfoo_a() : voidCfoo_c() : voidDas : std::vector<A*>foo_a() : voidfoo_c() : voidEas : std::vector<A*>foo_a() : voidfoo_c() : voidBase abstract interface.asas \ No newline at end of file + + + + + + + + + + + + + + A + + + + foo_a() = 0 : void + + foo_c() = 0 : void + + + + B + + + + foo_a() : void + + + + C + + + + foo_c() : void + + + + D + + + as : std::vector<A*> + + + foo_a() : void + + foo_c() : void + + + + E + + + as : std::vector<A*> + + + foo_a() : void + + foo_c() : void + + + Base abstract interface. + + + + + + + + as + + + + + + + + as + + + + + + diff --git a/docs/test_cases/t00003_class.svg b/docs/test_cases/t00003_class.svg index e5fc59cf..48241701 100644 --- a/docs/test_cases/t00003_class.svg +++ b/docs/test_cases/t00003_class.svg @@ -1,46 +1,70 @@ -Apublic_member : intstatic_int : intstatic_const_int : int constauto_member : unsigned long constprotected_member : intprivate_member : inta : intb : intc : intA() : voidA(int i) : voidA(A&& ) : voidA(A const& ) : void~A() : voidbasic_method() : voidstatic_method() : intconst_method() const : voidauto_method() : intdouble_int(int const i) : intsum(double const a, double const b) : doubledefault_int(int i = 12) : intdefault_string(int i, std::string s = "abc") : std::stringcreate_from_int(int i) : Aprotected_method() : voidprivate_method() : voidcompare : std::function<bool(int const)> \ No newline at end of file + + + + + + + + + + + + + + A + + + public_member : int + + static_int : int + + static_const_int : int const + + auto_member : unsigned long const + + protected_member : int + + private_member : int + + a : int + + b : int + + c : int + + + A() : void + + A(int i) : void + + A(A&& ) : void + + A(A const& ) : void + + ~A() : void + + basic_method() : void + + static_method() : int + + const_method() const : void + + auto_method() : int + + double_int(int const i) : int + + sum(double const a, double const b) : double + + default_int(int i = 12) : int + + default_string(int i, std::string s = "abc") : std::string + + create_from_int(int i) : A + + protected_method() : void + + private_method() : void + + compare : std::function<bool(int const)> + + diff --git a/docs/test_cases/t00004_class.svg b/docs/test_cases/t00004_class.svg index e673475c..baf5ccb3 100644 --- a/docs/test_cases/t00004_class.svg +++ b/docs/test_cases/t00004_class.svg @@ -1,46 +1,55 @@ -Afoo() const : voidfoo2() const : voidAALightsGreenYellowRedAAA \ No newline at end of file + + + + + + + + + + + + + + A + + + + foo() const : void + + foo2() const : void + + + + AA + + + + + + Lights + + Green + Yellow + Red + + + + + AAA + + + + + + + + + + + + + + + + diff --git a/docs/test_cases/t00005_class.svg b/docs/test_cases/t00005_class.svg index 6e548328..8adb2e51 100644 --- a/docs/test_cases/t00005_class.svg +++ b/docs/test_cases/t00005_class.svg @@ -1,112 +1,147 @@ -ABCDEFGHIJKRsome_int : intsome_int_pointer : int*some_int_pointer_pointer : int**some_int_reference : int&a : Ab : B*c : C&d : D const*e : E const&f : F&&g : G**h : H***i : I*&j : J volatile*k : K*+a+b+c+d+e+f+g+h+i+j+k \ No newline at end of file + + + + + + + + + + + + + + A + + + + + + B + + + + + + C + + + + + + D + + + + + + E + + + + + + F + + + + + + G + + + + + + H + + + + + + I + + + + + + J + + + + + + K + + + + + + R + + + some_int : int + + some_int_pointer : int* + + some_int_pointer_pointer : int** + + some_int_reference : int& + + a : A + + b : B* + + c : C& + + d : D const* + + e : E const& + + f : F&& + + g : G** + + h : H*** + + i : I*& + + j : J volatile* + + k : K* + + + + +a + + + +b + + + +c + + + +d + + + +e + + + +f + + + +g + + + +h + + + +i + + + +j + + + +k + + diff --git a/docs/test_cases/t00006_class.svg b/docs/test_cases/t00006_class.svg index cc402db1..08005a56 100644 --- a/docs/test_cases/t00006_class.svg +++ b/docs/test_cases/t00006_class.svg @@ -1,160 +1,215 @@ -ABCDEFGHIJKLMNNNNNNcustom_containerTdata : std::vector<T>custom_containerERa : std::vector<A>b : std::vector<B*>c : std::map<int,C>d : std::map<int,D*>e : custom_container<E>f : std::vector<std::vector<F>>g : std::map<int,std::vector<G*>>h : std::array<H,10>i : std::array<I*,5>j : J[10]k : K*[20]lm : std::vector<std::pair<L,M>>ns : std::tuple<N,NN,NNN>+a+b+c+d+e+f+g+h+i+j+klmlmnsnsns \ No newline at end of file + + + + + + + + + + + + + + A + + + + + + B + + + + + + C + + + + + + D + + + + + + E + + + + + + F + + + + + + G + + + + + + H + + + + + + I + + + + + + J + + + + + + K + + + + + + L + + + + + + M + + + + + + N + + + + + + NN + + + + + + NNN + + + + + + custom_container + + T + + + data : std::vector<T> + + + + + custom_container + + E + + + + + + R + + + a : std::vector<A> + + b : std::vector<B*> + + c : std::map<int,C> + + d : std::map<int,D*> + + e : custom_container<E> + + f : std::vector<std::vector<F>> + + g : std::map<int,std::vector<G*>> + + h : std::array<H,10> + + i : std::array<I*,5> + + j : J[10] + + k : K*[20] + + lm : std::vector<std::pair<L,M>> + + ns : std::tuple<N,NN,NNN> + + + + + + + + +a + + + +b + + + +c + + + +d + + + +e + + + +f + + + +g + + + +h + + + +i + + + +j + + + +k + + + + lm + + + + lm + + + + ns + + + + ns + + + + ns + + diff --git a/docs/test_cases/t00007_class.svg b/docs/test_cases/t00007_class.svg index 616fa5f8..4e78c6cc 100644 --- a/docs/test_cases/t00007_class.svg +++ b/docs/test_cases/t00007_class.svg @@ -1,44 +1,51 @@ -ABCRa : std::unique_ptr<A>b : std::shared_ptr<B>c : std::weak_ptr<C>+a+b+c \ No newline at end of file + + + + + + + + + + + + + + A + + + + + + B + + + + + + C + + + + + + R + + + a : std::unique_ptr<A> + + b : std::shared_ptr<B> + + c : std::weak_ptr<C> + + + + +a + + + +b + + + +c + + diff --git a/docs/test_cases/t00008_class.svg b/docs/test_cases/t00008_class.svg index ab9cfcdc..9ea74662 100644 --- a/docs/test_cases/t00008_class.svg +++ b/docs/test_cases/t00008_class.svg @@ -1,54 +1,76 @@ -AT,P,CMP,int Nvalue : Tpointer : T*reference : T&values : std::vector<P>ints : std::array<int,N>comparator : CMPVectorTvalues : std::vector<T>BT,C<>template_template : C<T>Bint,VectorDints : B<int,Vector>add(int i) : voidints \ No newline at end of file + + + + + + + + + + + + + + A + + T,P,CMP,int N + + + value : T + + pointer : T* + + reference : T& + + values : std::vector<P> + + ints : std::array<int,N> + + comparator : CMP + + + + + Vector + + T + + + values : std::vector<T> + + + + + B + + T,C<> + + + template_template : C<T> + + + + + B + + int,Vector + + + + + + D + + + ints : B<int,Vector> + + + add(int i) : void + + + + + + ints + + diff --git a/docs/test_cases/t00009_class.svg b/docs/test_cases/t00009_class.svg index ae6fd8b0..6c28d9fd 100644 --- a/docs/test_cases/t00009_class.svg +++ b/docs/test_cases/t00009_class.svg @@ -1,56 +1,76 @@ -ATvalue : TAintAstd::stringAstd::vector<std::string>Baint : A<int>astring : A<std::string>*avector : A<std::vector<std::string>>&aintastringavector \ No newline at end of file + + + + + + + + + + + + + + A + + T + + + value : T + + + + + A + + int + + + + + + A + + std::string + + + + + + A + + std::vector<std::string> + + + + + + B + + + aint : A<int> + + astring : A<std::string>* + + avector : A<std::vector<std::string>>& + + + + + + + + + + + aint + + + + astring + + + + avector + + diff --git a/docs/test_cases/t00010_class.svg b/docs/test_cases/t00010_class.svg index 03bd89fc..ca16e0e4 100644 --- a/docs/test_cases/t00010_class.svg +++ b/docs/test_cases/t00010_class.svg @@ -1,52 +1,70 @@ -AT,Pfirst : Tsecond : PAT,std::stringBTastring : A<T,std::string>BintCaintstring : B<int>astringaintstring \ No newline at end of file + + + + + + + + + + + + + + A + + T,P + + + first : T + + second : P + + + + + A + + T,std::string + + + + + + B + + T + + + astring : A<T,std::string> + + + + + B + + int + + + + + + C + + + aintstring : B<int> + + + + + + + astring + + + + + + aintstring + + diff --git a/docs/test_cases/t00011_class.svg b/docs/test_cases/t00011_class.svg index 67d574c1..c26f4fc1 100644 --- a/docs/test_cases/t00011_class.svg +++ b/docs/test_cases/t00011_class.svg @@ -1,38 +1,47 @@ -DTvalue : TAfoo() : voidBm_a : A*foo() : void«friend»m_a \ No newline at end of file + + + + + + + + + + + + + + D + + T + + + value : T + + + + + A + + + + foo() : void + + + + B + + + m_a : A* + + + foo() : void + + + «friend» + + + + m_a + + diff --git a/docs/test_cases/t00012_class.svg b/docs/test_cases/t00012_class.svg index 77b37438..b4f026b4 100644 --- a/docs/test_cases/t00012_class.svg +++ b/docs/test_cases/t00012_class.svg @@ -1,90 +1,133 @@ -AT,Ts...value : Tvalues : intBint Is...ints : std::array<int,sizeof...(Is)>CT,int Is...ints : std::array<T,sizeof...(Is)>Aint,std::string,floatAint,std::string,boolB3,2,1B1,1,1,1Cstd::map<int,std::vector<std::vector<std::vector<std::string>>>>,3,3,3Ra1 : A<int,std::string,float>a2 : A<int,std::string,bool>b1 : B<3,2,1>b2 : B<1,1,1,1>c1 : C<std::map<int,std::vector<std::vector<std::vector<std::string>>>>,3,3,3>Long template annotationa1a2b1b2c1 \ No newline at end of file + + + + + + + + + + + + + + A + + T,Ts... + + + value : T + + values : int + + + + + B + + int Is... + + + + ints : std::array<int,sizeof...(Is)> + + + + C + + T,int Is... + + + + ints : std::array<T,sizeof...(Is)> + + + + A + + int,std::string,float + + + + + + A + + int,std::string,bool + + + + + + B + + 3,2,1 + + + + + + B + + 1,1,1,1 + + + + + + C + + std::map<int,std::vector<std::vector<std::vector<std::string>>>>,3,3,3 + + + + + + R + + + a1 : A<int,std::string,float> + + a2 : A<int,std::string,bool> + + b1 : B<3,2,1> + + b2 : B<1,1,1,1> + + c1 : C<std::map<int,std::vector<std::vector<std::vector<std::string>>>>,3,3,3> + + + + Long template annotation + + + + + + + + + + + + + + a1 + + + + a2 + + + + b1 + + + + b2 + + + + c1 + + diff --git a/docs/test_cases/t00013_class.svg b/docs/test_cases/t00013_class.svg index c6c989a1..b68e16ff 100644 --- a/docs/test_cases/t00013_class.svg +++ b/docs/test_cases/t00013_class.svg @@ -1,110 +1,148 @@ -ABCD::FTf : TAa : intBb : intCc : intDd : intprint(R* r) : voidETe : TEintFintEstd::stringRestring : E<std::string>get_a(A* a) : intget_b(B& b) : intget_const_b(B const& b) : intget_c(C c) : intget_d(D&& d) : intget_d2(D&& d) : intget_e(E<T> e) : Tget_int_e(E<int> const& e) : intget_int_e2(E<int>& e) : intget_f(F<T> const& f) : Tget_int_f(F<int> const& f) : intestring \ No newline at end of file + + + + + + + + + + + + + + ABCD::F + + T + + + f : T + + + + + A + + + a : int + + + + + B + + + b : int + + + + + C + + + c : int + + + + + D + + + d : int + + + print(R* r) : void + + + + E + + T + + + e : T + + + + + E + + int + + + + + + F + + int + + + + + + E + + std::string + + + + + + R + + + estring : E<std::string> + + + get_a(A* a) : int + + get_b(B& b) : int + + get_const_b(B const& b) : int + + get_c(C c) : int + + get_d(D&& d) : int + + get_d2(D&& d) : int + + get_e(E<T> e) : T + + get_int_e(E<int> const& e) : int + + get_int_e2(E<int>& e) : int + + get_f(F<T> const& f) : T + + get_int_f(F<int> const& f) : int + + + + + + + + + + + + + + + + + + + + + + + + + + + + estring + + diff --git a/docs/test_cases/t00014_class.svg b/docs/test_cases/t00014_class.svg index 461ae116..8cfdf0b9 100644 --- a/docs/test_cases/t00014_class.svg +++ b/docs/test_cases/t00014_class.svg @@ -1,102 +1,150 @@ -AT,Pt : Tp : PAT,std::stringBvalue : std::stringAbool,std::stringAStringfloatAStringintAStringstd::stringGeneralCallbackAIntStringGeneralCallbackRboolstring : A<bool,std::string>floatstring : AString<float>intstring : AIntStringstringstring : AStringStringbs : BVectorbs2 : BVector2cb : GeneralCallback<AIntString>vcb : VoidCallbackboolstringfloatstringintstringstringstringbsbs2cbvcb \ No newline at end of file + + + + + + + + + + + + + + A + + T,P + + + t : T + + p : P + + + + + A + + T,std::string + + + + + + B + + + value : std::string + + + + + A + + bool,std::string + + + + + + AString + + float + + + + + + AString + + int + + + + + + AString + + std::string + + + + + + GeneralCallback + + AIntString + + + + + + GeneralCallback + + + + + + R + + + boolstring : A<bool,std::string> + + floatstring : AString<float> + + intstring : AIntString + + stringstring : AStringString + + bs : BVector + + bs2 : BVector2 + + cb : GeneralCallback<AIntString> + + vcb : VoidCallback + + + + + + + + + + + + + + + boolstring + + + + floatstring + + + + intstring + + + + stringstring + + + + bs + + + + bs2 + + + + cb + + + + vcb + + diff --git a/docs/test_cases/t00015_class.svg b/docs/test_cases/t00015_class.svg index 48ecd9ce..ed1cc348 100644 --- a/docs/test_cases/t00015_class.svg +++ b/docs/test_cases/t00015_class.svg @@ -1,43 +1,48 @@ -ns1::Ans1::ns2_v0_9_0::Ans1::Anonns3::ns1::ns2::Anonns3::B \ No newline at end of file + + + + + + + + + + + + + + ns1::A + + + + + + ns1::ns2_v0_9_0::A + + + + + + ns1::Anon + + + + + + ns3::ns1::ns2::Anon + + + + + + ns3::B + + + + + + + + + + diff --git a/docs/test_cases/t00016_class.svg b/docs/test_cases/t00016_class.svg index ed7797a1..5707acb9 100644 --- a/docs/test_cases/t00016_class.svg +++ b/docs/test_cases/t00016_class.svg @@ -1,53 +1,68 @@ -is_numeric<>value : enumis_numericcharvalue : enumis_numericunsigned charvalue : enumis_numericintvalue : enumis_numericboolvalue : enum \ No newline at end of file + + + + + + + + + + + + + + is_numeric<> + + + value : enum + + + + + is_numeric + + char + + + value : enum + + + + + is_numeric + + unsigned char + + + value : enum + + + + + is_numeric + + int + + + value : enum + + + + + is_numeric + + bool + + + value : enum + + + + + + + + + + + diff --git a/docs/test_cases/t00017_class.svg b/docs/test_cases/t00017_class.svg index 5be5275c..163ffe65 100644 --- a/docs/test_cases/t00017_class.svg +++ b/docs/test_cases/t00017_class.svg @@ -1,110 +1,135 @@ -ABCDEFGHIJKRsome_int : intsome_int_pointer : int*some_int_pointer_pointer : int**some_int_reference : int&R(int& some_int, C& cc, E const& ee, F&& ff, I*& ii) : void-c-e-f-i-a-b-d-g-h-j-k \ No newline at end of file + + + + + + + + + + + + + + A + + + + + + B + + + + + + C + + + + + + D + + + + + + E + + + + + + F + + + + + + G + + + + + + H + + + + + + I + + + + + + J + + + + + + K + + + + + + R + + + some_int : int + + some_int_pointer : int* + + some_int_pointer_pointer : int** + + some_int_reference : int& + + + R(int& some_int, C& cc, E const& ee, F&& ff, I*& ii) : void + + + + + -c + + + + + -e + + + + + -f + + + + + -i + + + -a + + + -b + + + -d + + + -g + + + -h + + + -j + + + -k + + diff --git a/docs/test_cases/t00018_class.svg b/docs/test_cases/t00018_class.svg index 76cdd262..6d09b37a 100644 --- a/docs/test_cases/t00018_class.svg +++ b/docs/test_cases/t00018_class.svg @@ -1,43 +1,58 @@ -impl::widgetn : intdraw(widget const& w) const : voiddraw(widget const& w) : voidwidget(int n) : voidwidgetpImpl : std::unique_ptr<impl::widget>draw() const : voiddraw() : voidshown() const : boolwidget(int ) : void~widget() : voidwidget(widget&& ) : voidwidget(widget const& ) : voidoperator=(widget&& ) : widget&operator=(widget const& ) : widget&pImpl \ No newline at end of file + + + + + + + + + + + + + + impl::widget + + + n : int + + + draw(widget const& w) const : void + + draw(widget const& w) : void + + widget(int n) : void + + + + widget + + + pImpl : std::unique_ptr<impl::widget> + + + draw() const : void + + draw() : void + + shown() const : bool + + widget(int ) : void + + ~widget() : void + + widget(widget&& ) : void + + widget(widget const& ) : void + + operator=(widget&& ) : widget& + + operator=(widget const& ) : widget& + + + + + + pImpl + + diff --git a/docs/test_cases/t00019_class.svg b/docs/test_cases/t00019_class.svg index 11452e5d..5ff485e8 100644 --- a/docs/test_cases/t00019_class.svg +++ b/docs/test_cases/t00019_class.svg @@ -1,89 +1,122 @@ -Layer2LowerLayerall_calls_count() const : intBaseBase() : void~Base() : voidm1() : intm2() : std::stringLayer1LowerLayerm1() : intm2() : std::stringLayer3LowerLayerm_m1_calls : intm_m2_calls : intm1() : intm2() : std::stringm1_calls() const : intm2_calls() const : intLayer3BaseLayer2Layer3<Base>Layer1Layer2<Layer3<Base>>Alayers : std::unique_ptr<Layer1<Layer2<Layer3<Base>>>>layers \ No newline at end of file + + + + + + + + + + + + + + Layer2 + + LowerLayer + + + + all_calls_count() const : int + + + + Base + + + + Base() : void + + ~Base() : void + + m1() : int + + m2() : std::string + + + + Layer1 + + LowerLayer + + + + m1() : int + + m2() : std::string + + + + Layer3 + + LowerLayer + + + m_m1_calls : int + + m_m2_calls : int + + + m1() : int + + m2() : std::string + + m1_calls() const : int + + m2_calls() const : int + + + + Layer3 + + Base + + + + + + Layer2 + + Layer3<Base> + + + + + + Layer1 + + Layer2<Layer3<Base>> + + + + + + A + + + layers : std::unique_ptr<Layer1<Layer2<Layer3<Base>>>> + + + + + + + + + + + + + + + + + + + + + + + layers + + diff --git a/docs/test_cases/t00020_class.svg b/docs/test_cases/t00020_class.svg index ec08620a..9024cd8d 100644 --- a/docs/test_cases/t00020_class.svg +++ b/docs/test_cases/t00020_class.svg @@ -1,94 +1,114 @@ -ProductA~ProductA() : voidsell(int price) const = 0 : boolProductA1sell(int price) const : boolProductA2sell(int price) const : boolProductB~ProductB() : voidbuy(int price) const = 0 : boolProductB1buy(int price) const : boolProductB2buy(int price) const : boolAbstractFactorymake_a() const = 0 : std::unique_ptr<ProductA>make_b() const = 0 : std::unique_ptr<ProductB>Factory1make_a() const : std::unique_ptr<ProductA>make_b() const : std::unique_ptr<ProductB>Factory2make_a() const : std::unique_ptr<ProductA>make_b() const : std::unique_ptr<ProductB> \ No newline at end of file + + + + + + + + + + + + + + ProductA + + + + ~ProductA() : void + + sell(int price) const = 0 : bool + + + + ProductA1 + + + + sell(int price) const : bool + + + + ProductA2 + + + + sell(int price) const : bool + + + + ProductB + + + + ~ProductB() : void + + buy(int price) const = 0 : bool + + + + ProductB1 + + + + buy(int price) const : bool + + + + ProductB2 + + + + buy(int price) const : bool + + + + AbstractFactory + + + + make_a() const = 0 : std::unique_ptr<ProductA> + + make_b() const = 0 : std::unique_ptr<ProductB> + + + + Factory1 + + + + make_a() const : std::unique_ptr<ProductA> + + make_b() const : std::unique_ptr<ProductB> + + + + Factory2 + + + + make_a() const : std::unique_ptr<ProductA> + + make_b() const : std::unique_ptr<ProductB> + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/test_cases/t00021_class.svg b/docs/test_cases/t00021_class.svg index 0400be70..dc51718b 100644 --- a/docs/test_cases/t00021_class.svg +++ b/docs/test_cases/t00021_class.svg @@ -1,95 +1,112 @@ -Visitor~Visitor() : voidvisit_A(A const& item) const = 0 : voidvisit_B(B const& item) const = 0 : voidVisitor1visit_A(A const& item) const : voidvisit_B(B const& item) const : voidVisitor2visit_A(A const& item) const : voidvisit_B(B const& item) const : voidVisitor3visit_A(A const& item) const : voidvisit_B(B const& item) const : voidItem~Item() : voidaccept(Visitor const& visitor) const = 0 : voidAaccept(Visitor const& visitor) const : voidBaccept(Visitor const& visitor) const : void \ No newline at end of file + + + + + + + + + + + + + + Visitor + + + + ~Visitor() : void + + visit_A(A const& item) const = 0 : void + + visit_B(B const& item) const = 0 : void + + + + Visitor1 + + + + visit_A(A const& item) const : void + + visit_B(B const& item) const : void + + + + Visitor2 + + + + visit_A(A const& item) const : void + + visit_B(B const& item) const : void + + + + Visitor3 + + + + visit_A(A const& item) const : void + + visit_B(B const& item) const : void + + + + Item + + + + ~Item() : void + + accept(Visitor const& visitor) const = 0 : void + + + + A + + + + accept(Visitor const& visitor) const : void + + + + B + + + + accept(Visitor const& visitor) const : void + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/test_cases/t00022_class.svg b/docs/test_cases/t00022_class.svg index e286fcf2..643e1fca 100644 --- a/docs/test_cases/t00022_class.svg +++ b/docs/test_cases/t00022_class.svg @@ -1,41 +1,48 @@ -Atemplate_method() : voidmethod1() = 0 : voidmethod2() = 0 : voidA1method1() : voidmethod2() : voidA2method1() : voidmethod2() : void \ No newline at end of file + + + + + + + + + + + + + + A + + + + template_method() : void + + method1() = 0 : void + + method2() = 0 : void + + + + A1 + + + + method1() : void + + method2() : void + + + + A2 + + + + method1() : void + + method2() : void + + + + + + diff --git a/docs/test_cases/t00023_class.svg b/docs/test_cases/t00023_class.svg index 4d394d1f..bf2a2775 100644 --- a/docs/test_cases/t00023_class.svg +++ b/docs/test_cases/t00023_class.svg @@ -1,58 +1,70 @@ -Strategy~Strategy() : voidalgorithm() = 0 : voidStrategyAalgorithm() : voidStrategyBalgorithm() : voidStrategyCalgorithm() : voidContextm_strategy : std::unique_ptr<Strategy>Context(std::unique_ptr<Strategy> strategy) : voidapply() : voidm_strategy \ No newline at end of file + + + + + + + + + + + + + + Strategy + + + + ~Strategy() : void + + algorithm() = 0 : void + + + + StrategyA + + + + algorithm() : void + + + + StrategyB + + + + algorithm() : void + + + + StrategyC + + + + algorithm() : void + + + + Context + + + m_strategy : std::unique_ptr<Strategy> + + + Context(std::unique_ptr<Strategy> strategy) : void + + apply() : void + + + + + + + + + + + + m_strategy + + diff --git a/docs/test_cases/t00024_class.svg b/docs/test_cases/t00024_class.svg index 4c02ceb0..7cd8c584 100644 --- a/docs/test_cases/t00024_class.svg +++ b/docs/test_cases/t00024_class.svg @@ -1,56 +1,70 @@ -Target~Target() : voidm1() = 0 : voidm2() = 0 : voidTarget1m1() : voidm2() : voidTarget2m1() : voidm2() : voidProxym_target : std::shared_ptr<Target>Proxy(std::shared_ptr<Target> target) : voidm1() : voidm2() : voidm_target \ No newline at end of file + + + + + + + + + + + + + + Target + + + + ~Target() : void + + m1() = 0 : void + + m2() = 0 : void + + + + Target1 + + + + m1() : void + + m2() : void + + + + Target2 + + + + m1() : void + + m2() : void + + + + Proxy + + + m_target : std::shared_ptr<Target> + + + Proxy(std::shared_ptr<Target> target) : void + + m1() : void + + m2() : void + + + + + + + + + + m_target + + + + diff --git a/docs/test_cases/t00025_class.svg b/docs/test_cases/t00025_class.svg index 8650a211..92f28c28 100644 --- a/docs/test_cases/t00025_class.svg +++ b/docs/test_cases/t00025_class.svg @@ -1,67 +1,90 @@ -Target1m1() : voidm2() : voidTarget2m1() : voidm2() : voidProxyTm_target : std::shared_ptr<T>Proxy(std::shared_ptr<T> target) : voidm1() : voidm2() : voidProxyTarget1ProxyTarget2ProxyHolderproxy1 : Proxy<Target1>proxy2 : Proxy<Target2>proxy1proxy2 \ No newline at end of file + + + + + + + + + + + + + + Target1 + + + + m1() : void + + m2() : void + + + + Target2 + + + + m1() : void + + m2() : void + + + + Proxy + + T + + + m_target : std::shared_ptr<T> + + + Proxy(std::shared_ptr<T> target) : void + + m1() : void + + m2() : void + + + + Proxy + + Target1 + + + + + + Proxy + + Target2 + + + + + + ProxyHolder + + + proxy1 : Proxy<Target1> + + proxy2 : Proxy<Target2> + + + + + + + + + + + + + proxy1 + + + + proxy2 + + diff --git a/docs/test_cases/t00026_class.svg b/docs/test_cases/t00026_class.svg index c5ad1cc0..5cf2fe41 100644 --- a/docs/test_cases/t00026_class.svg +++ b/docs/test_cases/t00026_class.svg @@ -1,73 +1,106 @@ -MementoTm_value : TMemento(T&& v) : voidvalue() const : TOriginatorTm_value : TOriginator(T&& v) : voidmemoize_value() const : Memento<T>load(Memento<T> const& m) : voidprint() const : voidset(T&& v) : voidCaretakerTm_mementos : std::unordered_map<std::string,Memento<T>>state(std::string const& n) : Memento<T>&set_state(std::string const& s, Memento<T>&& m) : voidCaretakerstd::stringOriginatorstd::stringStringMementocaretaker : Caretaker<std::string>originator : Originator<std::string>m_mementoscaretakeroriginator \ No newline at end of file + + + + + + + + + + + + + + Memento + + T + + + m_value : T + + + Memento(T&& v) : void + + value() const : T + + + + Originator + + T + + + m_value : T + + + Originator(T&& v) : void + + memoize_value() const : Memento<T> + + load(Memento<T> const& m) : void + + print() const : void + + set(T&& v) : void + + + + Caretaker + + T + + + m_mementos : std::unordered_map<std::string,Memento<T>> + + + state(std::string const& n) : Memento<T>& + + set_state(std::string const& s, Memento<T>&& m) : void + + + + Caretaker + + std::string + + + + + + Originator + + std::string + + + + + + StringMemento + + + caretaker : Caretaker<std::string> + + originator : Originator<std::string> + + + + + + + + + m_mementos + + + + + + + + caretaker + + + + originator + + diff --git a/docs/test_cases/t00027_class.svg b/docs/test_cases/t00027_class.svg index 222ab061..87cee6b1 100644 --- a/docs/test_cases/t00027_class.svg +++ b/docs/test_cases/t00027_class.svg @@ -1,105 +1,148 @@ -Shapedisplay() = 0 : void~Shape() : voidLineT<>display() : voidTextT<>display() : voidShapeDecoratordisplay() = 0 : voidColorTdisplay() : voidWeightTdisplay() : voidLineColor,WeightLineColorTextColor,WeightTextColorWindowborder : Line<Color,Weight>divider : Line<Color>title : Text<Color,Weight>description : Text<Color>borderdividertitledescription \ No newline at end of file + + + + + + + + + + + + + + Shape + + + + display() = 0 : void + + ~Shape() : void + + + + Line + + T<> + + + + display() : void + + + + Text + + T<> + + + + display() : void + + + + ShapeDecorator + + + + display() = 0 : void + + + + Color + + T + + + + display() : void + + + + Weight + + T + + + + display() : void + + + + Line + + Color,Weight + + + + + + Line + + Color + + + + + + Text + + Color,Weight + + + + + + Text + + Color + + + + + + Window + + + border : Line<Color,Weight> + + divider : Line<Color> + + title : Text<Color,Weight> + + description : Text<Color> + + + + + + + + + + + + + + + + + + + + + border + + + + divider + + + + title + + + + description + + diff --git a/docs/test_cases/t00028_class.svg b/docs/test_cases/t00028_class.svg index 87c260c5..eb76b63f 100644 --- a/docs/test_cases/t00028_class.svg +++ b/docs/test_cases/t00028_class.svg @@ -1,133 +1,163 @@ -AA class note.A class note.BB class note.B class note.CC class note.C class note.DDclassnote.Dclassnote.ETparam : TE template class note.GFonetwothreeF enum note.F enum note.EintRaaa : Abbb : B*ccc : C&ddd : std::vector<std::shared_ptr<D>>eee : E<int>ggg : G**R(C& c) : voidR class note.R class note.cccaaabbbdddeeeggg \ No newline at end of file + + + + + + + + + + + + + + A + + + + + A class note. + + + A class note. + + + + B + + + + + B class note. + + + B class note. + + + + C + + + + + C class note. + + + C class note. + + + + D + + + + + D + class + note. + + + D + class + note. + + + + E + + T + + + param : T + + + + E template class note. + + + + G + + + + + + F + + one + two + three + + + + F enum note. + + + F enum note. + + + + E + + int + + + + + + R + + + aaa : A + + bbb : B* + + ccc : C& + + ddd : std::vector<std::shared_ptr<D>> + + eee : E<int> + + ggg : G** + + + R(C& c) : void + + + R class note. + + + R class note. + + + + + + + + + + + ccc + + + + aaa + + + + bbb + + + + ddd + + + + eee + + + + ggg + + diff --git a/docs/test_cases/t00029_class.svg b/docs/test_cases/t00029_class.svg index f5a44483..5fb8b499 100644 --- a/docs/test_cases/t00029_class.svg +++ b/docs/test_cases/t00029_class.svg @@ -1,70 +1,81 @@ -ACTparam : TEonetwothreeG1G2G3G4Rg1 : G1g3 : G3&g4 : std::shared_ptr<G4>g1g4 \ No newline at end of file + + + + + + + + + + + + + + A + + + + + + C + + T + + + param : T + + + + + E + + one + two + three + + + + + G1 + + + + + + G2 + + + + + + G3 + + + + + + G4 + + + + + + R + + + g1 : G1 + + g3 : G3& + + g4 : std::shared_ptr<G4> + + + + + g1 + + + + g4 + + diff --git a/docs/test_cases/t00030_class.svg b/docs/test_cases/t00030_class.svg index 735fb9f2..ff438e89 100644 --- a/docs/test_cases/t00030_class.svg +++ b/docs/test_cases/t00030_class.svg @@ -1,52 +1,71 @@ -ABCDRaaa : Abbb : std::vector<B>ccc : std::vector<C>ddd : Daaabbb0..11..*ccc0..11..5ddd1 \ No newline at end of file + + + + + + + + + + + + + + A + + + + + + B + + + + + + C + + + + + + D + + + + + + R + + + aaa : A + + bbb : std::vector<B> + + ccc : std::vector<C> + + ddd : D + + + + + aaa + + + + bbb + 0..1 + 1..* + + + + ccc + 0..1 + 1..5 + + + + ddd + 1 + + diff --git a/docs/test_cases/t00031_class.svg b/docs/test_cases/t00031_class.svg index 175622b1..78b68bb8 100644 --- a/docs/test_cases/t00031_class.svg +++ b/docs/test_cases/t00031_class.svg @@ -1,63 +1,93 @@ -ABonetwothreeCTttt : TDCintRaaa : A*bbb : std::vector<B>ccc : C<int>ddd : D*aaabbbcccddd \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + A + + + + + + B + + one + two + three + + + + + + C + + T + + + ttt : T + + + + + D + + + + + + C + + int + + + + + + R + + + aaa : A* + + bbb : std::vector<B> + + ccc : C<int> + + ddd : D* + + + + + + + aaa + + + + bbb + + + + ccc + + + + ddd + + diff --git a/docs/test_cases/t00032_class.svg b/docs/test_cases/t00032_class.svg index ce226d29..d84a400f 100644 --- a/docs/test_cases/t00032_class.svg +++ b/docs/test_cases/t00032_class.svg @@ -1,82 +1,98 @@ -BaseTBaseAoperator()() : voidBoperator()() : voidCoperator()() : voidOverloadT,L,Ts...counter : LOverloadTBase,int,A,B,CRoverload : Overload<TBase,int,A,B,C>overload \ No newline at end of file + + + + + + + + + + + + + + Base + + + + + + TBase + + + + + + A + + + + operator()() : void + + + + B + + + + operator()() : void + + + + C + + + + operator()() : void + + + + Overload + + T,L,Ts... + + + counter : L + + + + + Overload + + TBase,int,A,B,C + + + + + + R + + + overload : Overload<TBase,int,A,B,C> + + + + + + + + + + + + + + + + + + + + + + + + + overload + + diff --git a/docs/test_cases/t00033_class.svg b/docs/test_cases/t00033_class.svg index 3f2ba4d5..368fba71 100644 --- a/docs/test_cases/t00033_class.svg +++ b/docs/test_cases/t00033_class.svg @@ -1,74 +1,98 @@ -ATaaa : TBTbbb : TCTccc : TDddd : intCDBstd::unique_ptr<C<D>>AB<std::unique_ptr<C<D>>>Rabc : A<B<std::unique_ptr<C<D>>>>abc \ No newline at end of file + + + + + + + + + + + + + + A + + T + + + aaa : T + + + + + B + + T + + + bbb : T + + + + + C + + T + + + ccc : T + + + + + D + + + ddd : int + + + + + C + + D + + + + + + B + + std::unique_ptr<C<D>> + + + + + + A + + B<std::unique_ptr<C<D>>> + + + + + + R + + + abc : A<B<std::unique_ptr<C<D>>>> + + + + + + + + + + + + + + + + + abc + + diff --git a/docs/test_cases/t00034_class.svg b/docs/test_cases/t00034_class.svg index a06629a6..886adb30 100644 --- a/docs/test_cases/t00034_class.svg +++ b/docs/test_cases/t00034_class.svg @@ -1,60 +1,78 @@ -Voidoperator==(Void const& ) const : booloperator!=(Void const& ) const : boollift_voidTlift_voidvoiddrop_voidTdrop_voidVoidARla : lift_void_t<A>*lv : lift_void_t<void>*la \ No newline at end of file + + + + + + + + + + + + + + Void + + + + operator==(Void const& ) const : bool + + operator!=(Void const& ) const : bool + + + + lift_void + + T + + + + + + lift_void + + void + + + + + + drop_void + + T + + + + + + drop_void + + Void + + + + + + A + + + + + + R + + + la : lift_void_t<A>* + + lv : lift_void_t<void>* + + + + + + + + + la + + diff --git a/docs/test_cases/t00035_class.svg b/docs/test_cases/t00035_class.svg index 46f289d8..38d5d469 100644 --- a/docs/test_cases/t00035_class.svg +++ b/docs/test_cases/t00035_class.svg @@ -1,48 +1,42 @@ -TopLeftCenterBottomRight \ No newline at end of file + + + + + + + + + + + + + + Top + + + + + + Left + + + + + + Center + + + + + + Bottom + + + + + + Right + + + + diff --git a/docs/test_cases/t00036_class.svg b/docs/test_cases/t00036_class.svg index e628e932..8c605353 100644 --- a/docs/test_cases/t00036_class.svg +++ b/docs/test_cases/t00036_class.svg @@ -1,62 +1,76 @@ -ns1ns11ns111ns2ns22clangumlEblueyellowATa : TAintBa_int : A<int>Ca_int \ No newline at end of file + + + + + + + + + + + + + ns1 + + + ns11 + + + ns111 + + + ns2 + + + ns22 + + + clanguml + + + + E + + blue + yellow + + + + + A + + T + + + a : T + + + + + A + + int + + + + + + B + + + a_int : A<int> + + + + + C + + + + + + + + a_int + + diff --git a/docs/test_cases/t20001_sequence.svg b/docs/test_cases/t20001_sequence.svg index 8253e215..bbbcbdff 100644 --- a/docs/test_cases/t20001_sequence.svg +++ b/docs/test_cases/t20001_sequence.svg @@ -1,32 +1,63 @@ -tmain()tmain()BBAAwrap_add3()add3()add()log_result()log_result()Main test function \ No newline at end of file + + + + + + + + + + + + + + + + + + + + tmain() + + tmain() + + B + + B + + A + + A + + + + + + + + wrap_add3() + + + add3() + + + + + add() + + + + + log_result() + + + + + log_result() + + + + + Main test function + + diff --git a/docs/test_cases/t20002_sequence.svg b/docs/test_cases/t20002_sequence.svg index e316b7f8..d8e94f30 100644 --- a/docs/test_cases/t20002_sequence.svg +++ b/docs/test_cases/t20002_sequence.svg @@ -1,23 +1,47 @@ -m1()m1()m2()m2()m3()m3()m4()m4()m2()m3()m4() \ No newline at end of file + + + + + + + + + + + + + + + + + + + m1() + + m1() + + m2() + + m2() + + m3() + + m3() + + m4() + + m4() + + + + + + m2() + + + m3() + + + m4() + + diff --git a/docs/test_cases/t30001_package.svg b/docs/test_cases/t30001_package.svg index 0b9ac111..5fe708ff 100644 --- a/docs/test_cases/t30001_package.svg +++ b/docs/test_cases/t30001_package.svg @@ -1,44 +1,46 @@ -AAABAAAAABBBBBAAABBBBBA AAA note... \ No newline at end of file + + + + + + + + + + + + + A + + + AA + + + B + + + AA + + + AAA + + + BBB + + + BB + + + AAA + + + BBB + + + BB + + + A AAA note... + + + diff --git a/docs/test_cases/t30002_package.svg b/docs/test_cases/t30002_package.svg index 5bacd6c5..1c52a720 100644 --- a/docs/test_cases/t30002_package.svg +++ b/docs/test_cases/t30002_package.svg @@ -1,84 +1,92 @@ -AAABBBA1A2A3A4A5A6A7A8A9A10A11A12A13BBB \ No newline at end of file + + + + + + + + + + + + + A + + + AA + + + B + + + BB + + + A1 + + + A2 + + + A3 + + + A4 + + + A5 + + + A6 + + + A7 + + + A8 + + + A9 + + + A10 + + + A11 + + + A12 + + + A13 + + + BBB + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/test_cases/t30003_package.svg b/docs/test_cases/t30003_package.svg index f1feab21..5c271413 100644 --- a/docs/test_cases/t30003_package.svg +++ b/docs/test_cases/t30003_package.svg @@ -1,35 +1,34 @@ -ns1ns3«deprecated»ns1ns2_v1_0_0ns2_v0_9_0«deprecated»ns2 \ No newline at end of file + + + + + + + + + + + + + ns1 + + + ns3 + «deprecated» + + + ns1 + + + ns2_v1_0_0 + + + ns2_v0_9_0 + «deprecated» + + + ns2 + + + + diff --git a/docs/test_cases/t30004_package.svg b/docs/test_cases/t30004_package.svg index 8591f854..c31fa15a 100644 --- a/docs/test_cases/t30004_package.svg +++ b/docs/test_cases/t30004_package.svg @@ -1,47 +1,47 @@ -APackage AAA.Package BBB.CCCC package note.Another CCC note.We skipped DDD.AAABBBCCCEEE \ No newline at end of file + + + + + + + + + + + + + A + + + Package AAA. + + + Package BBB. + + + CCCC package note. + + + Another CCC note. + + + We skipped DDD. + + + AAA + + + BBB + + + CCC + + + EEE + + + + + + + diff --git a/docs/test_cases/t30005_package.svg b/docs/test_cases/t30005_package.svg index f0ed020d..961fed2c 100644 --- a/docs/test_cases/t30005_package.svg +++ b/docs/test_cases/t30005_package.svg @@ -1,48 +1,43 @@ -AAABBBCCCAAABBBCCC \ No newline at end of file + + + + + + + + + + + + + A + + + AA + + + B + + + BB + + + C + + + CC + + + AAA + + + BBB + + + CCC + + + + + + diff --git a/docs/test_cases/t30006_package.svg b/docs/test_cases/t30006_package.svg index 92daf49f..bdb0cbb4 100644 --- a/docs/test_cases/t30006_package.svg +++ b/docs/test_cases/t30006_package.svg @@ -1,38 +1,33 @@ -BACTop A note.Bottom A note. \ No newline at end of file + + + + + + + + + + + + + B + + + A + + + C + + + Top A note. + + + Bottom A note. + + + + + + + + diff --git a/docs/test_cases/t30007_package.svg b/docs/test_cases/t30007_package.svg index b3794762..5ab9d3b9 100644 --- a/docs/test_cases/t30007_package.svg +++ b/docs/test_cases/t30007_package.svg @@ -1,45 +1,36 @@ -ABAACCompare layout with t30006.Bottom A note. \ No newline at end of file + + + + + + + + + + + + + A + + + B + + + AA + + + C + + + Compare layout with t30006. + + + Bottom A note. + + + + + + + + diff --git a/docs/test_cases/t90000_class.svg b/docs/test_cases/t90000_class.svg index a5beec6d..37c80296 100644 --- a/docs/test_cases/t90000_class.svg +++ b/docs/test_cases/t90000_class.svg @@ -1,33 +1,47 @@ -Fooint valueArrayListThis is a very important class.This is afloating noteThis note is connectedto several objects.Boo \ No newline at end of file + + + + + + + + + + + + + + Foo + + + int value + + + + + ArrayList + + + + + This is a very important class. + + + This is a + floating note + + + This note is connected + to several objects. + + + + Boo + + + + + + + + diff --git a/util/format_svg.py b/util/format_svg.py new file mode 100755 index 00000000..1539f88d --- /dev/null +++ b/util/format_svg.py @@ -0,0 +1,51 @@ +#!/usr/bin/python3 + +## +## util/format_svg.py +## +## Copyright (c) 2021-2022 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. +## + +import sys +from lxml import etree + +def main(argv): + if len(argv) < 1: + print('Usage: \n') + print('\t\t ./format_svg.py input_file1.svg input_file2.svg ...\n') + sys.exit(1) + + for inputfile in argv: + # Read svg file contents + with open(inputfile, 'r') as f: + xml = f.read() + + # Parse SVG XML + tree = etree.fromstring(bytes(xml, encoding='utf8')) + + # Remove comments from SVG, to minimize diff + # when updating diagrams in Git + comments = tree.xpath('//comment()') + + for c in comments: + p = c.getparent() + p.remove(c) + + # Overwrite the input svg properly formatted + etree.ElementTree(tree).write(inputfile, encoding='utf-8', pretty_print=True) + + +if __name__ == "__main__": + main(sys.argv[1:]) \ No newline at end of file From bee20e7f26f6590a4dc7e3b7b4b891e7d8e5be0d Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 27 Feb 2022 14:20:35 +0100 Subject: [PATCH 02/14] Added namespace to common model instead of vector --- src/class_diagram/model/class.cc | 8 ++++---- src/class_diagram/model/enum.cc | 2 +- src/common/model/element.cc | 10 +++++----- src/common/model/element.h | 6 +++--- src/common/model/package.cc | 2 +- tests/CMakeLists.txt | 18 ++++++++++++++++++ 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc index fdb459ed..ef034e2c 100644 --- a/src/class_diagram/model/class.cc +++ b/src/class_diagram/model/class.cc @@ -114,8 +114,8 @@ std::string class_::full_name(bool relative) const using namespace clanguml::util; std::ostringstream ostr; - if (relative && starts_with(get_namespace(), using_namespaces())) - ostr << ns_relative(using_namespaces(), name_and_ns()); + if (relative && starts_with(get_namespace(), using_namespace())) + ostr << ns_relative(using_namespace(), name_and_ns()); else ostr << name_and_ns(); @@ -134,11 +134,11 @@ std::ostringstream &class_::render_template_params( if (!tmplt.type().empty()) res.push_back( - util::ns_relative(using_namespaces(), tmplt.type())); + util::ns_relative(using_namespace(), tmplt.type())); if (!tmplt.name().empty()) res.push_back( - util::ns_relative(using_namespaces(), tmplt.name())); + util::ns_relative(using_namespace(), tmplt.name())); if (!tmplt.default_value().empty()) { res.push_back("="); diff --git a/src/class_diagram/model/enum.cc b/src/class_diagram/model/enum.cc index 49b75c77..a6318135 100644 --- a/src/class_diagram/model/enum.cc +++ b/src/class_diagram/model/enum.cc @@ -40,7 +40,7 @@ std::string enum_::full_name(bool relative) const std::ostringstream ostr; if (relative) - ostr << ns_relative(using_namespaces(), name()); + ostr << ns_relative(using_namespace(), name()); else ostr << name(); diff --git a/src/common/model/element.cc b/src/common/model/element.cc index b79645d3..e5044cf3 100644 --- a/src/common/model/element.cc +++ b/src/common/model/element.cc @@ -27,10 +27,10 @@ namespace clanguml::common::model { std::atomic_uint64_t element::m_nextId = 1; element::element(const std::vector &using_namespaces) - : using_namespaces_{using_namespaces} + : using_namespace_{using_namespaces} , m_id{m_nextId++} { - for (const auto &n : using_namespaces_) + for (const auto &n : using_namespace_) assert(!util::contains(n, "::")); } @@ -64,12 +64,12 @@ void element::set_using_namespaces(const std::vector &un) for (const auto &n : un) assert(!util::contains(n, "::")); - using_namespaces_ = un; + using_namespace_ = un; } -const std::vector &element::using_namespaces() const +const std::vector &element::using_namespace() const { - return using_namespaces_; + return using_namespace_; } std::vector &element::relationships() { return relationships_; } diff --git a/src/common/model/element.h b/src/common/model/element.h index 4c8ea662..40e26cbf 100644 --- a/src/common/model/element.h +++ b/src/common/model/element.h @@ -54,7 +54,7 @@ public: std::vector get_relative_namespace() const { auto relative_ns = namespace_; - util::remove_prefix(relative_ns, using_namespaces_); + util::remove_prefix(relative_ns, using_namespace_); return relative_ns; } @@ -62,7 +62,7 @@ public: void set_using_namespaces(const std::vector &un); - const std::vector &using_namespaces() const; + const std::vector &using_namespace() const; std::vector &relationships(); @@ -82,7 +82,7 @@ protected: private: std::string name_; std::vector namespace_; - std::vector using_namespaces_; + std::vector using_namespace_; std::vector relationships_; static std::atomic_uint64_t m_nextId; diff --git a/src/common/model/package.cc b/src/common/model/package.cc index 9d12601d..d628b09b 100644 --- a/src/common/model/package.cc +++ b/src/common/model/package.cc @@ -31,7 +31,7 @@ package::package(const std::vector &using_namespaces) std::string package::full_name(bool relative) const { auto fn = get_namespace(); - auto ns = using_namespaces(); + auto ns = using_namespace(); if (relative && (fn.size() >= ns.size())) { if (util::starts_with(fn, ns)) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8e25629b..b825fc09 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,14 @@ set(CLANG_UML_TEST_UTIL_HEADER catch.h ) +set(CLANG_UML_TEST_MODEL_SRC + test_model.cc + ${TEST_MODEL_SOURCES} + ) +set(CLANG_UML_TEST_MODEL_HEADER + catch.h + ) + set(CLANG_UML_TEST_CASES_SRC test_cases.cc ${TEST_CASE_SOURCES} @@ -50,6 +58,16 @@ target_link_libraries(test_util ${YAML_CPP_LIBRARIES} spdlog::spdlog clang-umllib cppast) +add_executable(test_model + ${CLANG_UML_TEST_MODEL_SRC} + ${CLANG_UML_TEST_MODEL_HEADER}) + +target_link_libraries(test_model + PRIVATE + ${LIBCLANG_LIBRARIES} + ${YAML_CPP_LIBRARIES} + spdlog::spdlog clang-umllib cppast) + add_executable(test_decorator_parser ${CLANG_UML_TEST_DECORATOR_PARSER_SRC} ${CLANG_UML_TEST_DECORATOR_PARSER_HEADER}) From a67b459437821d53faee7c8a78bcb0b7c2493603 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Fri, 4 Mar 2022 23:38:18 +0100 Subject: [PATCH 03/14] Initial refactor of namespace handling --- .../plantuml/class_diagram_generator.cc | 18 +- src/class_diagram/model/class.cc | 22 +- src/class_diagram/model/class.h | 2 +- src/class_diagram/model/diagram.cc | 2 +- src/class_diagram/model/enum.cc | 7 +- src/class_diagram/model/enum.h | 2 +- src/class_diagram/model/method_parameter.cc | 10 +- src/class_diagram/model/method_parameter.h | 3 +- .../visitor/translation_unit_context.cc | 8 +- .../visitor/translation_unit_context.h | 4 +- .../visitor/translation_unit_visitor.cc | 27 +-- src/common/generators/plantuml/generator.h | 11 +- src/common/model/element.cc | 21 +- src/common/model/element.h | 26 +-- src/common/model/namespace.cc | 213 ++++++++++++++++++ src/common/model/namespace.h | 87 +++++++ src/common/model/nested_trait.h | 35 +-- src/common/model/package.cc | 29 ++- src/common/model/package.h | 2 +- src/config/config.cc | 57 ++++- src/config/config.h | 19 +- src/config/option.h | 2 +- src/cx/util.cc | 11 +- src/cx/util.h | 8 +- .../plantuml/package_diagram_generator.cc | 4 +- src/package_diagram/model/diagram.cc | 10 +- .../visitor/translation_unit_context.cc | 4 +- .../visitor/translation_unit_context.h | 4 +- .../visitor/translation_unit_visitor.cc | 39 ++-- .../plantuml/sequence_diagram_generator.cc | 10 +- .../visitor/translation_unit_visitor.cc | 5 +- src/util/util.cc | 2 + src/util/util.h | 4 +- tests/t00002/test_case.h | 3 +- tests/t00003/test_case.h | 2 - tests/t00004/test_case.h | 3 - tests/test_config.cc | 4 +- tests/test_config_data/simple.yml | 3 +- tests/test_model.cc | 72 ++++++ tests/test_util.cc | 26 +-- 40 files changed, 620 insertions(+), 201 deletions(-) create mode 100644 src/common/model/namespace.cc create mode 100644 src/common/model/namespace.h create mode 100644 tests/test_model.cc diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index ace02486..3d2e7ce5 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -118,7 +118,7 @@ void generator::generate( if (m.is_defaulted()) ostr << " = default"; - ostr << " : " << ns_relative(uns, type); + ostr << " : " << uns.relative(type); ostr << '\n'; } @@ -154,9 +154,9 @@ void generator::generate( if (!r.multiplicity_destination().empty()) puml_relation += " \"" + r.multiplicity_destination() + "\""; - relstr << m_model.to_alias(ns_relative(uns, c.full_name())) << " " + relstr << m_model.to_alias(uns.relative(c.full_name())) << " " << puml_relation << " " - << m_model.to_alias(ns_relative(uns, destination)); + << m_model.to_alias(uns.relative(destination)); if (!r.label().empty()) { relstr << " : " << plantuml_common::to_plantuml(r.scope()) @@ -197,7 +197,7 @@ void generator::generate( ostr << "{static} "; ostr << plantuml_common::to_plantuml(m.scope()) << m.name() << " : " - << ns_relative(uns, m.type()) << '\n'; + << uns.relative(m.type()) << '\n'; } ostr << "}" << '\n'; @@ -206,10 +206,8 @@ void generator::generate( for (const auto &b : c.parents()) { std::stringstream relstr; try { - relstr << m_model.to_alias(ns_relative(uns, b.name())) - << " <|-- " - << m_model.to_alias(ns_relative(uns, c.full_name())) - << '\n'; + relstr << m_model.to_alias(uns.relative(b.name())) << " <|-- " + << m_model.to_alias(uns.relative(c.full_name())) << '\n'; all_relations_str << relstr.str(); } catch (error::uml_alias_missing &e) { @@ -253,13 +251,13 @@ void generator::generate( destination = r.destination(); relstr << m_model.to_alias( - ns_relative(m_config.using_namespace(), e.name())) + m_config.using_namespace().relative(e.name())) << " " << clanguml::common::generators::plantuml::to_plantuml( r.type(), r.style()) << " " << m_model.to_alias( - ns_relative(m_config.using_namespace(), destination)); + m_config.using_namespace().relative(destination)); if (!r.label().empty()) relstr << " : " << r.label(); diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc index ef034e2c..004797f1 100644 --- a/src/class_diagram/model/class.cc +++ b/src/class_diagram/model/class.cc @@ -24,8 +24,8 @@ namespace clanguml::class_diagram::model { -class_::class_(const std::vector &using_namespaces) - : element{using_namespaces} +class_::class_(const common::model::namespace_ &using_namespace) + : element{using_namespace} { } @@ -112,10 +112,12 @@ std::string class_::full_name_no_ns() const std::string class_::full_name(bool relative) const { using namespace clanguml::util; + using clanguml::common::model::namespace_; std::ostringstream ostr; - if (relative && starts_with(get_namespace(), using_namespace())) - ostr << ns_relative(using_namespace(), name_and_ns()); + // if (relative && starts_with(get_namespace(), using_namespace())) + if (relative) + ostr << namespace_{name()}.relative_to(using_namespace()).to_string(); else ostr << name_and_ns(); @@ -126,6 +128,8 @@ std::string class_::full_name(bool relative) const std::ostringstream &class_::render_template_params( std::ostringstream &ostr) const { + using clanguml::common::model::namespace_; + if (!templates_.empty()) { std::vector tnames; std::transform(templates_.cbegin(), templates_.cend(), @@ -133,12 +137,14 @@ std::ostringstream &class_::render_template_params( std::vector res; if (!tmplt.type().empty()) - res.push_back( - util::ns_relative(using_namespace(), tmplt.type())); + res.push_back(namespace_{tmplt.type()} + .relative_to(using_namespace()) + .to_string()); if (!tmplt.name().empty()) - res.push_back( - util::ns_relative(using_namespace(), tmplt.name())); + res.push_back(namespace_{tmplt.name()} + .relative_to(using_namespace()) + .to_string()); if (!tmplt.default_value().empty()) { res.push_back("="); diff --git a/src/class_diagram/model/class.h b/src/class_diagram/model/class.h index 62de2f15..5d17ad84 100644 --- a/src/class_diagram/model/class.h +++ b/src/class_diagram/model/class.h @@ -34,7 +34,7 @@ namespace clanguml::class_diagram::model { class class_ : public common::model::element, public common::model::stylable_element { public: - class_(const std::vector &using_namespaces); + class_(const common::model::namespace_ &using_namespace); class_(const class_ &) = delete; class_(class_ &&) noexcept = delete; diff --git a/src/class_diagram/model/diagram.cc b/src/class_diagram/model/diagram.cc index 80c9c810..00687c11 100644 --- a/src/class_diagram/model/diagram.cc +++ b/src/class_diagram/model/diagram.cc @@ -82,7 +82,7 @@ void diagram::add_class(std::unique_ptr &&c) auto ns = c->get_relative_namespace(); auto name = c->name(); add_element(ns, std::move(c)); - ns.push_back(name); + ns |= name; const auto ccc = get_element(ns); assert(ccc.value().name() == name); } diff --git a/src/class_diagram/model/enum.cc b/src/class_diagram/model/enum.cc index a6318135..2343559f 100644 --- a/src/class_diagram/model/enum.cc +++ b/src/class_diagram/model/enum.cc @@ -24,8 +24,8 @@ namespace clanguml::class_diagram::model { -enum_::enum_(const std::vector &using_namespaces) - : element{using_namespaces} +enum_::enum_(const common::model::namespace_ &using_namespace) + : element{using_namespace} { } @@ -37,10 +37,11 @@ bool operator==(const enum_ &l, const enum_ &r) std::string enum_::full_name(bool relative) const { using namespace clanguml::util; + using clanguml::common::model::namespace_; std::ostringstream ostr; if (relative) - ostr << ns_relative(using_namespace(), name()); + ostr << namespace_{name()}.relative_to(using_namespace()).to_string(); else ostr << name(); diff --git a/src/class_diagram/model/enum.h b/src/class_diagram/model/enum.h index f54da03e..ef6025ce 100644 --- a/src/class_diagram/model/enum.h +++ b/src/class_diagram/model/enum.h @@ -27,7 +27,7 @@ namespace clanguml::class_diagram::model { class enum_ : public common::model::element, public common::model::stylable_element { public: - enum_(const std::vector &using_namespaces); + enum_(const common::model::namespace_ &using_namespaces); enum_(const enum_ &) = delete; enum_(enum_ &&) = default; diff --git a/src/class_diagram/model/method_parameter.cc b/src/class_diagram/model/method_parameter.cc index f17b9094..2464e458 100644 --- a/src/class_diagram/model/method_parameter.cc +++ b/src/class_diagram/model/method_parameter.cc @@ -38,14 +38,16 @@ void method_parameter::set_default_value(const std::string &value) std::string method_parameter::default_value() const { return default_value_; } std::string method_parameter::to_string( - const std::vector &using_namespaces) const + const common::model::namespace_ &using_namespace) const { using namespace clanguml::util; - auto t = ns_relative(using_namespaces, type()); + auto type_ns = common::model::namespace_{type()} + .relative_to(using_namespace) + .to_string(); if (default_value().empty()) - return fmt::format("{} {}", t, name()); + return fmt::format("{} {}", type_ns, name()); - return fmt::format("{} {} = {}", t, name(), default_value()); + return fmt::format("{} {} = {}", type_ns, name(), default_value()); } } diff --git a/src/class_diagram/model/method_parameter.h b/src/class_diagram/model/method_parameter.h index 5eceadb6..04fdaea5 100644 --- a/src/class_diagram/model/method_parameter.h +++ b/src/class_diagram/model/method_parameter.h @@ -18,6 +18,7 @@ #pragma once #include "common/model/decorated_element.h" +#include "common/model/namespace.h" #include #include @@ -36,7 +37,7 @@ public: std::string default_value() const; std::string to_string( - const std::vector &using_namespaces) const; + const common::model::namespace_ &using_namespaces) const; private: std::string type_; diff --git a/src/class_diagram/visitor/translation_unit_context.cc b/src/class_diagram/visitor/translation_unit_context.cc index 7d9f612d..dd66ed05 100644 --- a/src/class_diagram/visitor/translation_unit_context.cc +++ b/src/class_diagram/visitor/translation_unit_context.cc @@ -154,14 +154,14 @@ translation_unit_context::get_type_alias_template( void translation_unit_context::push_namespace(const std::string &ns) { - namespace_.push_back(ns); + ns_ |= ns; } -void translation_unit_context::pop_namespace() { namespace_.pop_back(); } +void translation_unit_context::pop_namespace() { ns_.pop_back(); } -const std::vector &translation_unit_context::get_namespace() const +const common::model::namespace_ &translation_unit_context::get_namespace() const { - return namespace_; + return ns_; } const cppast::cpp_entity_index &translation_unit_context::entity_index() const diff --git a/src/class_diagram/visitor/translation_unit_context.h b/src/class_diagram/visitor/translation_unit_context.h index 453d2805..7775d89d 100644 --- a/src/class_diagram/visitor/translation_unit_context.h +++ b/src/class_diagram/visitor/translation_unit_context.h @@ -66,7 +66,7 @@ public: void pop_namespace(); - const std::vector &get_namespace() const; + const common::model::namespace_ &get_namespace() const; const cppast::cpp_entity_index &entity_index() const; @@ -80,7 +80,7 @@ public: private: // Current visitor namespace - std::vector namespace_; + common::model::namespace_ ns_; // Reference to the cppast entity index cppast::cpp_entity_index &entity_index_; diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index ebbfda63..0f98de94 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -200,7 +200,7 @@ void translation_unit_visitor::process_type_alias_template( cx::util::full_name(ctx.get_namespace(), at), type_safe::ref(at.type_alias().underlying_type())); - if (ctx.config().should_include(tinst->get_namespace(), tinst->name())) + if (ctx.config().should_include(tinst->get_namespace() | tinst->name())) ctx.diagram().add_class(std::move(tinst)); } } @@ -222,15 +222,14 @@ void translation_unit_visitor::process_type_alias( void translation_unit_visitor::process_namespace( const cppast::cpp_entity &e, const cppast::cpp_namespace &ns_declaration) { - std::vector package_parent = ctx.get_namespace(); - auto package_path = package_parent; - package_path.push_back(e.name()); + auto package_parent = ctx.get_namespace(); + auto package_path = package_parent | e.name(); - auto usn = util::split(ctx.config().using_namespace()[0], "::"); + auto usn = ctx.config().using_namespace(); - if (ctx.config().should_include_package(util::join(package_path, "::"))) { + if (ctx.config().should_include_package(package_path)) { auto p = std::make_unique(usn); - util::remove_prefix(package_path, usn); + package_path = package_path.relative_to(usn); p->set_name(e.name()); p->set_namespace(package_parent); @@ -267,8 +266,7 @@ void translation_unit_visitor::process_enum_declaration( return; } - auto e_ptr = std::make_unique( - util::split(ctx.config().using_namespace()[0], "::")); + auto e_ptr = std::make_unique(ctx.config().using_namespace()); auto &e = *e_ptr; e.set_name(enm.name()); e.set_namespace(ctx.get_namespace()); @@ -312,8 +310,7 @@ void translation_unit_visitor::process_class_declaration( const cppast::cpp_class &cls, type_safe::optional_ref tspec) { - auto c_ptr = std::make_unique( - util::split(ctx.config().using_namespace()[0], "::")); + auto c_ptr = std::make_unique(ctx.config().using_namespace()); auto &c = *c_ptr; c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t); // c.set_name(cx::util::full_name(ctx.get_namespace(), cls)); @@ -1275,8 +1272,7 @@ bool translation_unit_visitor::find_relationships_in_template_instantiation( const auto [ns, base_name] = cx::util::split_ns(fn); - auto ns_and_name = ns; - ns_and_name.push_back(base_name); + auto ns_and_name = ns | base_name; auto full_name = fmt::format("{}", fmt::join(ns_and_name, "::")); @@ -1403,8 +1399,7 @@ std::unique_ptr translation_unit_visitor::build_template_instantiation( std::optional parent) { // Create class_ instance to hold the template instantiation - auto tinst_ptr = std::make_unique( - util::split(ctx.config().using_namespace()[0], "::")); + auto tinst_ptr = std::make_unique(ctx.config().using_namespace()); auto &tinst = *tinst_ptr; std::string full_template_name; @@ -1430,7 +1425,7 @@ std::unique_ptr translation_unit_visitor::build_template_instantiation( // Extract namespace from base template name const auto [ns, name] = cx::util::split_ns(tinst_full_name); tinst.set_name(name); - if (ns.empty()) + if (ns.is_empty()) tinst.set_namespace(ctx.get_namespace()); else tinst.set_namespace(ns); diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 4451e6fd..6169c183 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -83,11 +83,10 @@ void generator::generate_config_layout_hints(std::ostream &ostr) const for (const auto &hint : hints) { std::stringstream hint_str; try { - hint_str << m_model.to_alias(ns_relative(uns, entity)) + hint_str << m_model.to_alias(uns.relative(entity)) << " -[hidden]" << clanguml::config::to_string(hint.hint) << "- " - << m_model.to_alias(ns_relative(uns, hint.entity)) - << '\n'; + << m_model.to_alias(uns.relative(hint.entity)) << '\n'; ostr << hint_str.str(); } catch (clanguml::error::uml_alias_missing &e) { @@ -103,12 +102,14 @@ template void generator::generate_plantuml_directives( std::ostream &ostr, const std::vector &directives) const { + using common::model::namespace_; + for (const auto &b : directives) { std::string note{b}; std::tuple alias_match; while (util::find_element_alias(note, alias_match)) { - auto alias = m_model.to_alias(util::ns_relative( - m_config.using_namespace(), std::get<0>(alias_match))); + auto alias = m_model.to_alias( + m_config.using_namespace().relative(std::get<0>(alias_match))); note.replace( std::get<1>(alias_match), std::get<2>(alias_match), alias); } diff --git a/src/common/model/element.cc b/src/common/model/element.cc index e5044cf3..aa8c0427 100644 --- a/src/common/model/element.cc +++ b/src/common/model/element.cc @@ -26,12 +26,10 @@ namespace clanguml::common::model { std::atomic_uint64_t element::m_nextId = 1; -element::element(const std::vector &using_namespaces) - : using_namespace_{using_namespaces} +element::element(const namespace_ &using_namespace) + : using_namespace_{using_namespace} , m_id{m_nextId++} { - for (const auto &n : using_namespace_) - assert(!util::contains(n, "::")); } std::string element::alias() const { return fmt::format("C_{:010}", m_id); } @@ -59,18 +57,12 @@ void element::add_relationship(relationship &&cr) relationships_.emplace_back(std::move(cr)); } -void element::set_using_namespaces(const std::vector &un) +void element::set_using_namespaces(const namespace_ &un) { - for (const auto &n : un) - assert(!util::contains(n, "::")); - using_namespace_ = un; } -const std::vector &element::using_namespace() const -{ - return using_namespace_; -} +const namespace_ &element::using_namespace() const { return ns_; } std::vector &element::relationships() { return relationships_; } @@ -88,9 +80,8 @@ bool operator==(const element &l, const element &r) std::ostream &operator<<(std::ostream &out, const element &rhs) { - out << "(" << rhs.name() << ", ns=[" - << util::join(rhs.get_namespace(), "::") << "], full_name=[" - << rhs.full_name(true) << "])"; + out << "(" << rhs.name() << ", ns=[" << rhs.get_namespace().to_string() + << "], full_name=[" << rhs.full_name(true) << "])"; return out; } diff --git a/src/common/model/element.h b/src/common/model/element.h index 40e26cbf..bb8985ba 100644 --- a/src/common/model/element.h +++ b/src/common/model/element.h @@ -18,6 +18,7 @@ #pragma once #include "decorated_element.h" +#include "namespace.h" #include "relationship.h" #include "util/util.h" @@ -30,7 +31,7 @@ namespace clanguml::common::model { class element : public decorated_element { public: - element(const std::vector &using_namespaces); + element(const namespace_ &using_namespace); virtual ~element() = default; @@ -42,27 +43,24 @@ public: std::string name_and_ns() const { - auto ns = namespace_; - ns.push_back(name()); - return util::join(ns, "::"); + auto ns = ns_ | name(); + return ns.to_string(); } - void set_namespace(const std::vector &ns) { namespace_ = ns; } + void set_namespace(const namespace_ &ns) { ns_ = ns; } - std::vector get_namespace() const { return namespace_; } + namespace_ get_namespace() const { return ns_; } - std::vector get_relative_namespace() const + namespace_ get_relative_namespace() const { - auto relative_ns = namespace_; - util::remove_prefix(relative_ns, using_namespace_); - return relative_ns; + return ns_.relative_to(using_namespace_); } virtual std::string full_name(bool relative) const { return name(); } - void set_using_namespaces(const std::vector &un); + void set_using_namespaces(const namespace_ &un); - const std::vector &using_namespace() const; + const namespace_ &using_namespace() const; std::vector &relationships(); @@ -81,8 +79,8 @@ protected: private: std::string name_; - std::vector namespace_; - std::vector using_namespace_; + namespace_ ns_; + namespace_ using_namespace_; std::vector relationships_; static std::atomic_uint64_t m_nextId; diff --git a/src/common/model/namespace.cc b/src/common/model/namespace.cc new file mode 100644 index 00000000..0cc2c139 --- /dev/null +++ b/src/common/model/namespace.cc @@ -0,0 +1,213 @@ +/** + * src/common/model/namespace.h + * + * Copyright (c) 2021-2022 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 "namespace.h" + +#include "util/util.h" + +namespace clanguml::common::model { + +namespace_::namespace_(std::initializer_list ns) +{ + if ((ns.size() == 1) && util::contains(*ns.begin(), "::")) + namespace_path_ = util::split(*ns.begin(), "::"); + else + namespace_path_ = ns; +} + +namespace_::namespace_(const std::vector &ns) +{ + if ((ns.size() == 1) && util::contains(*ns.begin(), "::")) + namespace_path_ = util::split(*ns.begin(), "::"); + else + namespace_path_ = ns; +} + +namespace_::namespace_(const std::string &ns) +{ + namespace_path_ = util::split(ns, "::"); +} + +namespace_::namespace_( + container_type::const_iterator begin, container_type::const_iterator end) +{ + std::copy(begin, end, std::back_inserter(namespace_path_)); +} + +std::string namespace_::to_string() const +{ + return fmt::format("{}", fmt::join(namespace_path_, "::")); +} + +size_t namespace_::size() const { return namespace_path_.size(); } + +bool namespace_::is_empty() const { return namespace_path_.empty(); } + +namespace_::container_type::iterator namespace_::begin() +{ + return namespace_path_.begin(); +} +namespace_::container_type::iterator namespace_::end() +{ + return namespace_path_.end(); +} + +namespace_::container_type::const_iterator namespace_::cbegin() const +{ + return namespace_path_.cbegin(); +} +namespace_::container_type::const_iterator namespace_::cend() const +{ + return namespace_path_.cend(); +} + +namespace_::container_type::const_iterator namespace_::begin() const +{ + return namespace_path_.begin(); +} +namespace_::container_type::const_iterator namespace_::end() const +{ + return namespace_path_.end(); +} + +void namespace_::append(const std::string &ns) +{ + namespace_path_.push_back(ns); +} + +void namespace_::append(const namespace_ &ns) +{ + for (const auto &n : ns) { + append(n); + } +} + +void namespace_::pop_back() { namespace_path_.pop_back(); } + +namespace_ namespace_::operator|(const namespace_ &right) const +{ + namespace_ res{*this}; + res.append(right); + return res; +} + +void namespace_::operator|=(const namespace_ &right) { append(right); } + +namespace_ namespace_::operator|(const std::string &right) const +{ + namespace_ res{*this}; + res.append(right); + return res; +} + +void namespace_::operator|=(const std::string &right) { append(right); } + +std::string &namespace_::operator[](const int index) +{ + return namespace_path_[index]; +} + +const std::string &namespace_::operator[](const int index) const +{ + return namespace_path_[index]; +} + +bool namespace_::starts_with(const namespace_ &right) const +{ + return util::starts_with(namespace_path_, right.namespace_path_); +} + +namespace_ namespace_::common_path(const namespace_ &right) const +{ + namespace_ res{}; + for (auto i = 0U; i < std::min(size(), right.size()); i++) { + if (namespace_path_[i] == right[i]) + res |= namespace_path_[i]; + else + break; + } + return res; +} + +namespace_ namespace_::relative_to(const namespace_ &right) const +{ + namespace_ res{*this}; + + if (res.starts_with(right)) + util::remove_prefix(res.namespace_path_, right.namespace_path_); + + return res; +} + +std::string namespace_::relative(const std::string &name) const +{ + /* + std::vector namespaces_sorted{namespaces}; + + std::sort(namespaces_sorted.rbegin(), namespaces_sorted.rend()); + + auto res = name; + + for (const auto &ns : namespaces_sorted) { + if (ns.empty()) + continue; + + if (name == ns) + return split(n, "::").back(); + + auto ns_prefix = ns + "::"; + auto it = res.find(ns_prefix); + while (it != std::string::npos) { + res.erase(it, ns_prefix.size()); + it = res.find(ns_prefix); + } + } + return res; + */ + + if (is_empty()) + return name; + + if (name == to_string()) + return name; + + auto res = name; + auto ns_prefix = to_string() + "::"; + + auto it = res.find(ns_prefix); + while (it != std::string::npos) { + res.erase(it, ns_prefix.size()); + it = res.find(ns_prefix); + } + + return res; +} + +bool operator==(const namespace_ &left, const namespace_ &right) +{ + return left.namespace_path_ == right.namespace_path_; +} + +std::string namespace_::name() const +{ + assert(size() > 0); + + return namespace_path_.back(); +} + +} \ No newline at end of file diff --git a/src/common/model/namespace.h b/src/common/model/namespace.h new file mode 100644 index 00000000..d38a5a16 --- /dev/null +++ b/src/common/model/namespace.h @@ -0,0 +1,87 @@ +/** + * src/common/model/namespace.h + * + * Copyright (c) 2021-2022 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. + */ +#pragma once + +#include +#include + +namespace clanguml::common::model { + +class namespace_ { + using container_type = std::vector; + +public: + namespace_() = default; + + namespace_(const std::string &ns); + + namespace_(container_type::const_iterator begin, + container_type::const_iterator end); + + namespace_(const namespace_ &right) noexcept = default; + + namespace_ &operator=(const namespace_ &right) noexcept = default; + + namespace_(namespace_ &&right) noexcept = default; + + namespace_ &operator=(namespace_ &&right) noexcept = default; + + friend bool operator==(const namespace_ &left, const namespace_ &right); + + namespace_(std::initializer_list ns); + + explicit namespace_(const std::vector &ns); + + std::string to_string() const; + + bool is_empty() const; + + size_t size() const; + + namespace_ operator|(const namespace_ &right) const; + void operator|=(const namespace_ &right); + namespace_ operator|(const std::string &right) const; + void operator|=(const std::string &right); + + std::string &operator[](const int index); + const std::string &operator[](const int index) const; + + void append(const std::string &ns); + + void append(const namespace_ &ns); + + void pop_back(); + + bool starts_with(const namespace_ &right) const; + namespace_ common_path(const namespace_ &right) const; + namespace_ relative_to(const namespace_ &right) const; + std::string relative(const std::string &name) const; + std::string name() const; + + container_type::iterator begin(); + container_type::iterator end(); + container_type::const_iterator begin() const; + container_type::const_iterator end() const; + container_type::const_iterator cbegin() const; + container_type::const_iterator cend() const; + +private: + container_type namespace_path_; +}; + +} \ No newline at end of file diff --git a/src/common/model/nested_trait.h b/src/common/model/nested_trait.h index 31de7363..4c2de809 100644 --- a/src/common/model/nested_trait.h +++ b/src/common/model/nested_trait.h @@ -52,58 +52,59 @@ public: } template - void add_element(std::vector path, std::unique_ptr p) + void add_element(namespace_ ns, std::unique_ptr p) { assert(p); - LOG_DBG("Adding nested element {} at path {}", p->name(), - fmt::join(path, "::")); + LOG_DBG( + "Adding nested element {} at path {}", p->name(), ns.to_string()); - if (path.empty()) { + if (ns.is_empty()) { add_element(std::move(p)); return; } - auto parent = get_element(path); + auto parent = get_element(ns); if (parent && dynamic_cast *>(&parent.value())) dynamic_cast &>(parent.value()) .template add_element(std::move(p)); else { - spdlog::error( - "No parent element found at: {}", fmt::join(path, "::")); - throw std::runtime_error("No parent element found"); + spdlog::error("No parent element found at: {}", ns.to_string()); + throw std::runtime_error( + "No parent element found for " + ns.to_string()); } } - template - auto get_element(std::vector path) const + template auto get_element(const namespace_ &path) const { - LOG_DBG("Getting nested element at path: {}", fmt::join(path, "::")); + LOG_DBG("Getting nested element at path: {}", path.to_string()); - if (path.empty() || !has_element(path.at(0))) { - LOG_WARN("Nested element {} not found in element", - fmt::join(path, "::")); + if (path.is_empty() || !has_element(path[0])) { + LOG_WARN( + "Nested element {} not found in element", path.to_string()); return type_safe::optional_ref{}; } if (path.size() == 1) - return get_element(path.at(0)); + return get_element(path[0]); - auto p = get_element(path.at(0)); + auto p = get_element(path[0]); if (!p) return type_safe::optional_ref{}; if (dynamic_cast *>(&p.value())) return dynamic_cast &>(p.value()).get_element( - std::vector(path.begin() + 1, path.end())); + namespace_{path.begin() + 1, path.end()}); return type_safe::optional_ref{}; } template auto get_element(const std::string &name) const { + assert(!util::contains(name, "::")); + auto it = std::find_if(elements_.cbegin(), elements_.cend(), [&](const auto &p) { return name == p->name(); }); diff --git a/src/common/model/package.cc b/src/common/model/package.cc index d628b09b..27eb8679 100644 --- a/src/common/model/package.cc +++ b/src/common/model/package.cc @@ -23,24 +23,33 @@ #include namespace clanguml::common::model { -package::package(const std::vector &using_namespaces) - : element{using_namespaces} +package::package(const common::model::namespace_ &using_namespace) + : element{using_namespace} { } std::string package::full_name(bool relative) const { - auto fn = get_namespace(); - auto ns = using_namespace(); - - if (relative && (fn.size() >= ns.size())) { - if (util::starts_with(fn, ns)) - fn = std::vector(fn.begin() + ns.size(), fn.end()); + if (relative) { + auto res = get_namespace().relative_to(using_namespace()) | name(); + return res.to_string(); } - fn.push_back(name()); + return (get_namespace().relative_to(using_namespace()) | name()) + .to_string(); - return fmt::format("{}", fmt::join(fn, "::")); + // auto fn = get_namespace(); + // auto ns = using_namespace(); + // + // if (relative && (fn.size() >= ns.size())) { + // if (fn.starts_with(using_namespace()) + // fn = std::vector(fn.begin() + ns.size(), + // fn.end()); + // } + // + // fn.push_back(name()); + // + // return fmt::format("{}", fmt::join(fn, "::")); } bool package::is_deprecated() const { return is_deprecated_; } diff --git a/src/common/model/package.h b/src/common/model/package.h index e11fafdb..46325c79 100644 --- a/src/common/model/package.h +++ b/src/common/model/package.h @@ -35,7 +35,7 @@ class package : public element, public stylable_element, public nested_trait { public: - package(const std::vector &using_namespaces); + package(const common::model::namespace_ &using_namespace); package(const package &) = delete; package(package &&) = default; diff --git a/src/config/config.cc b/src/config/config.cc index 8248907e..c3b64b35 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -130,17 +130,22 @@ bool diagram::should_include_relationship(const std::string &rel) } bool diagram::should_include( - const std::pair, std::string> &name) const + const std::pair &name) const { return should_include(std::get<0>(name), std::get<1>(name)); } +// bool diagram::should_include( +// const common::model::namespace_ &ns, const std::string &name) const +//{ +// auto ns_and_name = ns | name; +// return should_include(ns_and_name.to_string()); +//} + bool diagram::should_include( - const std::vector &ns, const std::string &name) const + const common::model::namespace_ &ns, const std::string &name) const { - auto ns_and_name = ns; - ns_and_name.push_back(name); - return should_include(util::join(ns_and_name, "::")); + return should_include(ns | name); } bool diagram::should_include(const std::string &name_) const @@ -148,7 +153,7 @@ bool diagram::should_include(const std::string &name_) const auto name = clanguml::util::unqualify(name_); for (const auto &ex : exclude().namespaces) { - if (name.find(ex) == 0) { + if (ex.starts_with(name)) { LOG_DBG("Skipping from diagram: {}", name); return false; } @@ -160,7 +165,7 @@ bool diagram::should_include(const std::string &name_) const return true; for (const auto &in : include().namespaces) { - if (name.find(in) == 0) + if (name.find(in.to_string()) == 0) return true; } @@ -169,11 +174,22 @@ bool diagram::should_include(const std::string &name_) const return false; } +bool diagram::should_include(const common::model::namespace_ &path) const +{ + return should_include(path.to_string()); +} + +bool diagram::should_include_package( + const common::model::namespace_ &path) const +{ + return should_include_package(path.to_string()); +} + bool diagram::should_include_package(const std::string &name) const { for (const auto &ex : exclude().namespaces) { - if (name.find(ex) == 0) { + if (name.find(ex.to_string()) == 0) { LOG_DBG("Skipping from diagram: {}", name); return false; } @@ -185,7 +201,7 @@ bool diagram::should_include_package(const std::string &name) const return true; for (const auto &in : include().namespaces) { - if (in.find(name) == 0 || name.find(in) == 0) + if (in.to_string().find(name) == 0 || name.find(in.to_string()) == 0) return true; } @@ -283,6 +299,21 @@ void get_option(const Node &node, clanguml::config::option &option) option.set(node[option.name].template as()); } +template <> +void get_option(const Node &node, + clanguml::config::option &option) +{ + if (node[option.name]) { + if (node[option.name].Type() == NodeType::Scalar) + option.set(node[option.name].template as()); + else if (node[option.name].Type() == NodeType::Sequence) + option.set( + node[option.name].template as>()[0]); + else + throw std::runtime_error("Invalid using_namespace value"); + } +} + template <> void get_option( const Node &node, clanguml::config::option &option) @@ -393,8 +424,12 @@ template <> struct convert { template <> struct convert { static bool decode(const Node &node, filter &rhs) { - if (node["namespaces"]) - rhs.namespaces = node["namespaces"].as(); + if (node["namespaces"]) { + auto namespace_list = + node["namespaces"].as>(); + for (const auto &ns : namespace_list) + rhs.namespaces.push_back(ns); + } if (node["relationships"]) rhs.relationships = diff --git a/src/config/config.h b/src/config/config.h index 14cee6c2..7a7c607d 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -46,7 +46,7 @@ struct plantuml { }; struct filter { - std::vector namespaces; + std::vector namespaces; // Valid values are: // - inheritance @@ -79,7 +79,7 @@ std::string to_string(const hint_t t); struct inheritable_diagram_options { option> glob{"glob"}; - option> using_namespace{"using_namespace"}; + option using_namespace{"using_namespace"}; option include_relations_also_as_members{ "include_relations_also_as_members", true}; option include{"include"}; @@ -105,15 +105,24 @@ struct diagram : public inheritable_diagram_options { bool should_include_package(const std::string &name) const; - bool should_include( - const std::pair, std::string> &name) const; + bool should_include_package(const common::model::namespace_ &path) const; bool should_include( - const std::vector &ns, const std::string &name) const; + const std::pair &name) const; + + // bool should_include( + // const std::vector &ns, const std::string &name) + // const; + + bool should_include( + const common::model::namespace_ &ns, const std::string &name) const; bool should_include(const common::model::scope_t scope) const; + bool should_include(const std::string &name_) const; + bool should_include(const common::model::namespace_ &path) const; + private: }; diff --git a/src/config/option.h b/src/config/option.h index 0fe1d17b..7d27efe1 100644 --- a/src/config/option.h +++ b/src/config/option.h @@ -28,7 +28,7 @@ template struct option { option(const std::string &name_, option_inherit_mode im = option_inherit_mode::override) : name{name_} - , value{{}} + , value{} { } option(const std::string &name_, const T &initial_value, diff --git a/src/cx/util.cc b/src/cx/util.cc index fb4f0fdf..4907b56e 100644 --- a/src/cx/util.cc +++ b/src/cx/util.cc @@ -39,7 +39,7 @@ std::string to_string(CXString &&cxs) } std::string full_name( - const std::vector ¤t_ns, const cppast::cpp_entity &e) + const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e) { if (e.name().empty()) return ""; @@ -126,12 +126,13 @@ bool is_inside_class(const cppast::cpp_entity &e) return false; } -std::pair, std::string> split_ns( +std::pair split_ns( const std::string &full_name) { auto name_before_template = ::clanguml::util::split(full_name, "<")[0]; - auto ns = ::clanguml::util::split(name_before_template, "::"); - auto name = ns.back(); + auto ns = common::model::namespace_{ + ::clanguml::util::split(name_before_template, "::")}; + auto name = ns.name(); ns.pop_back(); return {ns, name}; } @@ -197,7 +198,7 @@ std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx) } std::string fully_prefixed( - const std::vector ¤t_ns, const cppast::cpp_entity &e) + const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e) { if (e.name().find("::") != std::string::npos) { // the name already contains namespace, but it could be not diff --git a/src/cx/util.h b/src/cx/util.h index 94fe8265..139d1490 100644 --- a/src/cx/util.h +++ b/src/cx/util.h @@ -17,6 +17,8 @@ */ #pragma once +#include "common/model/namespace.h" + #include #include #include @@ -41,13 +43,13 @@ namespace util { std::string to_string(CXString &&cxs); std::string full_name( - const std::vector ¤t_ns, const cppast::cpp_entity &e); + const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e); std::string full_name(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx, bool inside_class); std::string fully_prefixed( - const std::vector ¤t_ns, const cppast::cpp_entity &e); + const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e); const cppast::cpp_type &unreferenced(const cppast::cpp_type &t); @@ -58,7 +60,7 @@ type_safe::optional_ref entity_ns( std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx); -std::pair, std::string> split_ns( +std::pair split_ns( const std::string &full_name); bool is_inside_class(const cppast::cpp_entity &e); diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index d4ff8b11..2b093ff1 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -39,9 +39,9 @@ void generator::generate_relationships( for (const auto &r : p.relationships()) { std::stringstream relstr; try { - relstr << m_model.to_alias(ns_relative(uns, p.full_name(false))) + relstr << m_model.to_alias(uns.relative(p.full_name(false))) << " ..> " - << m_model.to_alias(ns_relative(uns, r.destination())) + << m_model.to_alias(uns.relative(r.destination())) << '\n'; ostr << relstr.str(); } diff --git a/src/package_diagram/model/diagram.cc b/src/package_diagram/model/diagram.cc index 04748b43..1fb2c1c6 100644 --- a/src/package_diagram/model/diagram.cc +++ b/src/package_diagram/model/diagram.cc @@ -27,17 +27,17 @@ std::string diagram::to_alias(const std::string &full_name) const { LOG_DBG("Looking for alias for {}", full_name); - auto fn = util::split(full_name, "::"); + auto path = common::model::namespace_{full_name}; - if (fn.empty()) + if (path.is_empty()) throw error::uml_alias_missing( - fmt::format("Missing alias for '{}'", full_name)); + fmt::format("Missing alias for '{}'", path.to_string())); - auto package = get_element(fn); + auto package = get_element(path); if (!package) throw error::uml_alias_missing( - fmt::format("Missing alias for '{}'", full_name)); + fmt::format("Missing alias for '{}'", path.to_string())); return package.value().alias(); } diff --git a/src/package_diagram/visitor/translation_unit_context.cc b/src/package_diagram/visitor/translation_unit_context.cc index 6cbd7de6..38f8c2d9 100644 --- a/src/package_diagram/visitor/translation_unit_context.cc +++ b/src/package_diagram/visitor/translation_unit_context.cc @@ -153,12 +153,12 @@ translation_unit_context::get_type_alias_template( void translation_unit_context::push_namespace(const std::string &ns) { - namespace_.push_back(ns); + namespace_ |= ns; } void translation_unit_context::pop_namespace() { namespace_.pop_back(); } -const std::vector &translation_unit_context::get_namespace() const +const common::model::namespace_ &translation_unit_context::get_namespace() const { return namespace_; } diff --git a/src/package_diagram/visitor/translation_unit_context.h b/src/package_diagram/visitor/translation_unit_context.h index 65522418..fbb075a6 100644 --- a/src/package_diagram/visitor/translation_unit_context.h +++ b/src/package_diagram/visitor/translation_unit_context.h @@ -68,7 +68,7 @@ public: void pop_namespace(); - const std::vector &get_namespace() const; + const common::model::namespace_ &get_namespace() const; const cppast::cpp_entity_index &entity_index() const; @@ -82,7 +82,7 @@ public: private: // Current visitor namespace - std::vector namespace_; + common::model::namespace_ namespace_; // Reference to the cppast entity index cppast::cpp_entity_index &entity_index_; diff --git a/src/package_diagram/visitor/translation_unit_visitor.cc b/src/package_diagram/visitor/translation_unit_visitor.cc index a0867a33..ea14f4e9 100644 --- a/src/package_diagram/visitor/translation_unit_visitor.cc +++ b/src/package_diagram/visitor/translation_unit_visitor.cc @@ -18,6 +18,8 @@ #include "translation_unit_visitor.h" +#include "common/model/namespace.h" + #include #include #include @@ -89,20 +91,17 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file) if (!ns_declaration.is_anonymous() && !ns_declaration.is_inline()) { - std::vector package_parent = - ctx.get_namespace(); - auto package_path = package_parent; - package_path.push_back(e.name()); + auto package_parent = ctx.get_namespace(); + auto package_path = package_parent | e.name(); + auto usn = common::model::namespace_{ + ctx.config().using_namespace()}; - auto usn = util::split( - ctx.config().using_namespace()[0], "::"); - - if (!util::starts_with(usn, package_path)) { + if (!usn.starts_with(package_path)) { auto p = std::make_unique(usn); - util::remove_prefix(package_path, usn); + package_path = package_path.relative_to(usn); p->set_name(e.name()); - p->set_namespace(package_parent); + p->set_namespace(package_path); if (ns_declaration.comment().has_value()) p->add_decorators(decorators::parse( @@ -303,10 +302,10 @@ void translation_unit_visitor::process_class_declaration( } for (const auto &dependency : relationships) { - auto destination = util::split(std::get<0>(dependency), "::"); + auto destination = common::model::namespace_{std::get<0>(dependency)}; - if (!util::starts_with(ctx.get_namespace(), destination) && - !util::starts_with(destination, ctx.get_namespace())) { + if (!ctx.get_namespace().starts_with(destination) && + !destination.starts_with(ctx.get_namespace())) { relationship r{ relationship_t::kDependency, std::get<0>(dependency)}; current_package.value().add_relationship(std::move(r)); @@ -330,10 +329,10 @@ void translation_unit_visitor::process_function(const cppast::cpp_function &f) f.return_type(), relationships, relationship_t::kDependency); for (const auto &dependency : relationships) { - auto destination = util::split(std::get<0>(dependency), "::"); + auto destination = common::model::namespace_{std::get<0>(dependency)}; - if (!util::starts_with(ctx.get_namespace(), destination) && - !util::starts_with(destination, ctx.get_namespace())) { + if (!ctx.get_namespace().starts_with(destination) && + !destination.starts_with(ctx.get_namespace())) { relationship r{ relationship_t::kDependency, std::get<0>(dependency)}; current_package.value().add_relationship(std::move(r)); @@ -350,8 +349,8 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, const auto fn = cx::util::full_name( resolve_alias(cppast::remove_cv(t_)), ctx.entity_index(), false); - auto t_ns = util::split(fn, "::"); - auto t_name = t_ns.back(); + auto t_ns = common::model::namespace_{fn}; + auto t_name = t_ns.name(); t_ns.pop_back(); const auto &t_raw = resolve_alias(cppast::remove_cv(t_)); @@ -371,13 +370,13 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, const auto &t_raw_ns_final = cx::util::ns(t_raw_ns.value()) + "::" + cx::util::full_name({}, t_raw_ns.value()); - t_ns = util::split(t_raw_ns_final, "::"); + t_ns = common::model::namespace_{t_raw_ns_final}; } } std::vector possible_matches; - possible_matches.push_back(util::join(t_ns, "::")); + possible_matches.push_back(t_ns.to_string()); const auto fn_ns = cx::util::ns(cppast::remove_cv(t_), ctx.entity_index()); diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 76b6277f..fc98907d 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -44,8 +44,8 @@ generator::generator( void generator::generate_call(const message &m, std::ostream &ostr) const { - const auto from = ns_relative(m_config.using_namespace(), m.from); - const auto to = ns_relative(m_config.using_namespace(), m.to); + const auto from = m_config.using_namespace().relative(m.from); + const auto to = m_config.using_namespace().relative(m.to); ostr << '"' << from << "\" " << common::generators::plantuml::to_plantuml(message_t::kCall) << " \"" @@ -57,8 +57,8 @@ void generator::generate_return(const message &m, std::ostream &ostr) const // Add return activity only for messages between different actors and // only if the return type is different than void if ((m.from != m.to) && (m.return_type != "void")) { - const auto from = ns_relative(m_config.using_namespace(), m.from); - const auto to = ns_relative(m_config.using_namespace(), m.to); + const auto from = m_config.using_namespace().relative(m.from); + const auto to = m_config.using_namespace().relative(m.to); ostr << '"' << to << "\" " << common::generators::plantuml::to_plantuml(message_t::kReturn) @@ -69,7 +69,7 @@ void generator::generate_return(const message &m, std::ostream &ostr) const void generator::generate_activity(const activity &a, std::ostream &ostr) const { for (const auto &m : a.messages) { - const auto to = ns_relative(m_config.using_namespace(), m.to); + const auto to = m_config.using_namespace().relative(m.to); generate_call(m, ostr); ostr << "activate " << '"' << to << '"' << std::endl; if (m_model.sequences.find(m.to_usr) != m_model.sequences.end()) diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index 29614816..e999fdd4 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -18,6 +18,7 @@ #include "translation_unit_visitor.h" +#include "common/model/namespace.h" #include "translation_unit_context.h" #include @@ -81,7 +82,7 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e) m.from = cx::util::ns(caller) + "::" + caller.name(); if (!ctx.config().should_include( - util::split(cx::util::ns(caller), "::"), caller.name())) + common::model::namespace_{cx::util::ns(caller)}, caller.name())) continue; if (caller.kind() == cpp_entity_kind::function_t) @@ -98,7 +99,7 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e) m.to += "()"; if (!ctx.config().should_include( - util::split(cx::util::ns(callee), "::"), callee.name())) + common::model::namespace_{cx::util::ns(callee)}, callee.name())) continue; m.to_usr = type_safe::get(function_call.get_callee_method_id()); diff --git a/src/util/util.cc b/src/util/util.cc index 92e79db3..69926a49 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -68,6 +68,7 @@ std::string join(const std::vector &toks, std::string delimiter) return fmt::format("{}", fmt::join(toks, delimiter)); } +/* std::string ns_relative( const std::vector &namespaces, const std::string &n) { @@ -93,6 +94,7 @@ std::string ns_relative( } return res; } +*/ std::string unqualify(const std::string &s) { diff --git a/src/util/util.h b/src/util/util.h index d929f41a..a349aa30 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -83,8 +83,8 @@ std::string join(const std::vector &toks, std::string delimiter); * * @return Identifier relative to one of the matching namespaces. */ -std::string ns_relative( - const std::vector &namespaces, const std::string &n); +// std::string ns_relative( +// const std::vector &namespaces, const std::string &n); /** * @brief Remove any qualifiers (e.g. const) from type. diff --git a/tests/t00002/test_case.h b/tests/t00002/test_case.h index 4c46f175..2b7856bf 100644 --- a/tests/t00002/test_case.h +++ b/tests/t00002/test_case.h @@ -26,7 +26,8 @@ TEST_CASE("t00002", "[test-case][class]") REQUIRE(diagram->include().namespaces.size() == 1); REQUIRE_THAT(diagram->include().namespaces, - VectorContains(std::string{"clanguml::t00002"})); + VectorContains( + clanguml::common::model::namespace_{"clanguml::t00002"})); REQUIRE(diagram->exclude().namespaces.size() == 0); diff --git a/tests/t00003/test_case.h b/tests/t00003/test_case.h index acbc547f..d5309310 100644 --- a/tests/t00003/test_case.h +++ b/tests/t00003/test_case.h @@ -25,8 +25,6 @@ TEST_CASE("t00003", "[test-case][class]") REQUIRE(diagram->name == "t00003_class"); REQUIRE(diagram->include().namespaces.size() == 1); - REQUIRE_THAT(diagram->include().namespaces, - VectorContains(std::string{"clanguml::t00003"})); REQUIRE(diagram->exclude().namespaces.size() == 0); diff --git a/tests/t00004/test_case.h b/tests/t00004/test_case.h index 10fb7cc4..daafd155 100644 --- a/tests/t00004/test_case.h +++ b/tests/t00004/test_case.h @@ -25,9 +25,6 @@ TEST_CASE("t00004", "[test-case][class]") REQUIRE(diagram->name == "t00004_class"); REQUIRE(diagram->include().namespaces.size() == 1); - REQUIRE_THAT(diagram->include().namespaces, - VectorContains(std::string{"clanguml::t00004"})); - REQUIRE(diagram->exclude().namespaces.size() == 0); REQUIRE(diagram->should_include("clanguml::t00004::A")); diff --git a/tests/test_config.cc b/tests/test_config.cc index 56cb4e88..cc11a991 100644 --- a/tests/test_config.cc +++ b/tests/test_config.cc @@ -53,7 +53,7 @@ TEST_CASE("Test config inherited", "[unit-test]") CHECK(cus.type() == clanguml::config::diagram_type::class_diagram); CHECK(cus.glob().size() == 1); CHECK(cus.glob()[0] == "src/main.cc"); - CHECK(clanguml::util::contains(cus.using_namespace(), "clanguml::ns1")); + CHECK(cus.using_namespace().starts_with({"clanguml::ns1"})); CHECK(cus.include_relations_also_as_members()); CHECK(def.generate_packages() == false); } @@ -76,7 +76,7 @@ TEST_CASE("Test config includes", "[unit-test]") CHECK(cus.type() == clanguml::config::diagram_type::class_diagram); CHECK(cus.glob().size() == 1); CHECK(cus.glob()[0] == "src/main.cc"); - CHECK(clanguml::util::contains(cus.using_namespace(), "clanguml::ns1")); + CHECK(cus.using_namespace().starts_with({"clanguml::ns1"})); CHECK(cus.include_relations_also_as_members()); CHECK(cus.generate_method_arguments() == clanguml::config::method_arguments::none); diff --git a/tests/test_config_data/simple.yml b/tests/test_config_data/simple.yml index 7b0e0952..698cd3e8 100644 --- a/tests/test_config_data/simple.yml +++ b/tests/test_config_data/simple.yml @@ -6,8 +6,7 @@ diagrams: glob: - src/**/*.cc - src/**/*.h - using_namespace: - - clanguml + using_namespace: clanguml generate_method_arguments: full generate_packages: true include: diff --git a/tests/test_model.cc b/tests/test_model.cc new file mode 100644 index 00000000..8a8350ac --- /dev/null +++ b/tests/test_model.cc @@ -0,0 +1,72 @@ +/** + * tests/test_model.cc + * + * Copyright (c) 2021-2022 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. + */ +#define CATCH_CONFIG_MAIN + +#include "catch.h" + +#include "common/model/namespace.h" + +TEST_CASE("Test namespace_", "[unit-test]") +{ + using clanguml::common::model::namespace_; + + namespace_ ns1{}; + CHECK(ns1.is_empty()); + + namespace_ ns2{"aaa", "bbb", "ccc"}; + CHECK(ns2.size() == 3); + CHECK(ns2[0] == "aaa"); + CHECK(ns2[1] == "bbb"); + CHECK(ns2[2] == "ccc"); + + namespace_ ns3 = ns1 | "aaa" | "bbb" | "ccc"; + CHECK(ns3.size() == 3); + CHECK(ns3[0] == "aaa"); + CHECK(ns3[1] == "bbb"); + CHECK(ns3[2] == "ccc"); + + namespace_ ns4 = namespace_{"aaa", "bbb"} | namespace_{"ccc"}; + CHECK(ns4.size() == 3); + CHECK(ns4[0] == "aaa"); + CHECK(ns4[1] == "bbb"); + CHECK(ns4[2] == "ccc"); + + namespace_ ns5{"aaa::bbb::ccc"}; + CHECK(ns5.size() == 3); + CHECK(ns5[0] == "aaa"); + CHECK(ns5[1] == "bbb"); + CHECK(ns5[2] == "ccc"); + + CHECK(ns4 == ns5); + + namespace_ ns6a{"aaa::bbb::ccc"}; + namespace_ ns6b{"aaa::bbb::ddd::eee"}; + auto ns6 = ns6a.common_path(ns6b); + + CHECK(ns6 == namespace_{"aaa", "bbb"}); + CHECK(ns6b.starts_with({"aaa", "bbb", "ddd"})); + + namespace_ ns7a{"aaa::bbb"}; + namespace_ ns7b{"aaa::bbb::ccc::ddd"}; + CHECK(ns7b.relative_to(ns7a) == namespace_{"ccc", "ddd"}); + CHECK(ns7a.relative_to(ns7b) == namespace_{"aaa::bbb"}); + + namespace_ ns8{"aaa::bbb"}; + const std::string name{"aaa::bbb::ccc>"}; + CHECK(ns8.relative(name) == "ccc>"); +} \ No newline at end of file diff --git a/tests/test_util.cc b/tests/test_util.cc index 8e7b93fa..884a430b 100644 --- a/tests/test_util.cc +++ b/tests/test_util.cc @@ -35,19 +35,19 @@ TEST_CASE("Test split", "[unit-test]") CHECK(split("std::vector::detail::", "::") == C{"std", "vector", "detail"}); } - -TEST_CASE("Test ns_relative", "[unit-test]") -{ - using namespace clanguml::util; - - CHECK(ns_relative({}, "std::vector") == "std::vector"); - CHECK(ns_relative({"std"}, "std::vector") == "vector"); - CHECK(ns_relative({"std"}, "const std::vector&") == "const vector&"); - CHECK(ns_relative({"std", "clanguml::t0"}, - "static const std::vector&") == - "static const vector&"); - CHECK(ns_relative({"clanguml::t0"}, "clanguml::t0") == "t0"); -} +// +// TEST_CASE("Test ns_relative", "[unit-test]") +//{ +// using namespace clanguml::util; +// +// CHECK(ns_relative({}, "std::vector") == "std::vector"); +// CHECK(ns_relative({"std"}, "std::vector") == "vector"); +// CHECK(ns_relative({"std"}, "const std::vector&") == "const vector&"); +// CHECK(ns_relative({"std", "clanguml::t0"}, +// "static const std::vector&") == +// "static const vector&"); +// CHECK(ns_relative({"clanguml::t0"}, "clanguml::t0") == "t0"); +//} TEST_CASE("Test abbreviate", "[unit-test]") { From f84e86ca6d35571d63765cf9d0a8fd0be44d1a8d Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 5 Mar 2022 18:46:29 +0100 Subject: [PATCH 04/14] Fixed tests after refactoring namespace handling --- src/class_diagram/model/class.cc | 13 +++++----- src/class_diagram/model/diagram.cc | 3 ++- src/common/model/element.cc | 2 +- src/common/model/namespace.cc | 26 +------------------ src/config/config.cc | 2 +- .../visitor/translation_unit_visitor.cc | 7 +++-- 6 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc index 004797f1..4ad31d2a 100644 --- a/src/class_diagram/model/class.cc +++ b/src/class_diagram/model/class.cc @@ -1,5 +1,5 @@ /** - * src/class_diagram/model/class.h + * src/class_diagram/model/class.cc * * Copyright (c) 2021-2022 Bartek Kryza * @@ -115,15 +115,14 @@ std::string class_::full_name(bool relative) const using clanguml::common::model::namespace_; std::ostringstream ostr; - // if (relative && starts_with(get_namespace(), using_namespace())) - if (relative) - ostr << namespace_{name()}.relative_to(using_namespace()).to_string(); - else - ostr << name_and_ns(); + ostr << name_and_ns(); render_template_params(ostr); - return ostr.str(); + if (relative) + return using_namespace().relative(ostr.str()); + else + return ostr.str(); } std::ostringstream &class_::render_template_params( std::ostringstream &ostr) const diff --git a/src/class_diagram/model/diagram.cc b/src/class_diagram/model/diagram.cc index 00687c11..1200e889 100644 --- a/src/class_diagram/model/diagram.cc +++ b/src/class_diagram/model/diagram.cc @@ -66,7 +66,8 @@ void diagram::add_package(std::unique_ptr &&p) void diagram::add_class(std::unique_ptr &&c) { - LOG_DBG("Adding class: {}, {}", c->name(), c->full_name()); + LOG_DBG("Adding class: {}::{}, {}", c->get_namespace().to_string(), + c->name(), c->full_name()); if (util::contains(c->name(), "::")) throw std::runtime_error("Name cannot contain namespace: " + c->name()); diff --git a/src/common/model/element.cc b/src/common/model/element.cc index aa8c0427..3c912c36 100644 --- a/src/common/model/element.cc +++ b/src/common/model/element.cc @@ -62,7 +62,7 @@ void element::set_using_namespaces(const namespace_ &un) using_namespace_ = un; } -const namespace_ &element::using_namespace() const { return ns_; } +const namespace_ &element::using_namespace() const { return using_namespace_; } std::vector &element::relationships() { return relationships_; } diff --git a/src/common/model/namespace.cc b/src/common/model/namespace.cc index 0cc2c139..359bf654 100644 --- a/src/common/model/namespace.cc +++ b/src/common/model/namespace.cc @@ -1,5 +1,5 @@ /** - * src/common/model/namespace.h + * src/common/model/namespace.cc * * Copyright (c) 2021-2022 Bartek Kryza * @@ -156,30 +156,6 @@ namespace_ namespace_::relative_to(const namespace_ &right) const std::string namespace_::relative(const std::string &name) const { - /* - std::vector namespaces_sorted{namespaces}; - - std::sort(namespaces_sorted.rbegin(), namespaces_sorted.rend()); - - auto res = name; - - for (const auto &ns : namespaces_sorted) { - if (ns.empty()) - continue; - - if (name == ns) - return split(n, "::").back(); - - auto ns_prefix = ns + "::"; - auto it = res.find(ns_prefix); - while (it != std::string::npos) { - res.erase(it, ns_prefix.size()); - it = res.find(ns_prefix); - } - } - return res; - */ - if (is_empty()) return name; diff --git a/src/config/config.cc b/src/config/config.cc index c3b64b35..c40de9a1 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -153,7 +153,7 @@ bool diagram::should_include(const std::string &name_) const auto name = clanguml::util::unqualify(name_); for (const auto &ex : exclude().namespaces) { - if (ex.starts_with(name)) { + if (name.find(ex.to_string()) == 0) { LOG_DBG("Skipping from diagram: {}", name); return false; } diff --git a/src/package_diagram/visitor/translation_unit_visitor.cc b/src/package_diagram/visitor/translation_unit_visitor.cc index ea14f4e9..043729cc 100644 --- a/src/package_diagram/visitor/translation_unit_visitor.cc +++ b/src/package_diagram/visitor/translation_unit_visitor.cc @@ -93,15 +93,14 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file) auto package_parent = ctx.get_namespace(); auto package_path = package_parent | e.name(); - auto usn = common::model::namespace_{ - ctx.config().using_namespace()}; + auto usn = ctx.config().using_namespace(); - if (!usn.starts_with(package_path)) { + if (ctx.config().should_include_package(package_path)) { auto p = std::make_unique(usn); package_path = package_path.relative_to(usn); p->set_name(e.name()); - p->set_namespace(package_path); + p->set_namespace(package_parent); if (ns_declaration.comment().has_value()) p->add_decorators(decorators::parse( From 768faaa1c8af8cc0cb5146cd2f9121f03149c503 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 5 Mar 2022 20:15:59 +0100 Subject: [PATCH 05/14] Fixed skipping using_namespace when generating packages --- .../plantuml/class_diagram_generator.cc | 26 +++++++++++----- src/class_diagram/model/method_parameter.cc | 5 ++-- .../plantuml/package_diagram_generator.cc | 30 +++++++++++-------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index 3d2e7ce5..c3bd0b3a 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -281,19 +281,25 @@ void generator::generate( void generator::generate(const package &p, std::ostream &ostr, std::ostream &relationships_ostr) const { + const auto &uns = m_config.using_namespace(); + if (m_config.generate_packages()) { LOG_DBG("Generating package {}", p.name()); - ostr << "package [" << p.name() << "] "; - ostr << "as " << p.alias(); + // Don't generate packages from namespaces filtered out by + // using_namespace + if (!uns.starts_with(p.full_name(false))) { + ostr << "package [" << p.name() << "] "; + ostr << "as " << p.alias(); - if (p.is_deprecated()) - ostr << " <>"; + if (p.is_deprecated()) + ostr << " <>"; - if (!p.style().empty()) - ostr << " " << p.style(); + if (!p.style().empty()) + ostr << " " << p.style(); - ostr << " {" << '\n'; + ostr << " {" << '\n'; + } } for (const auto &subpackage : p) { @@ -316,7 +322,11 @@ void generator::generate(const package &p, std::ostream &ostr, } if (m_config.generate_packages()) { - ostr << "}" << '\n'; + // Don't generate packages from namespaces filtered out by + // using_namespace + if (!uns.starts_with(p.full_name(false))) { + ostr << "}" << '\n'; + } } generate_notes(ostr, p); diff --git a/src/class_diagram/model/method_parameter.cc b/src/class_diagram/model/method_parameter.cc index 2464e458..3942d43d 100644 --- a/src/class_diagram/model/method_parameter.cc +++ b/src/class_diagram/model/method_parameter.cc @@ -41,9 +41,8 @@ std::string method_parameter::to_string( const common::model::namespace_ &using_namespace) const { using namespace clanguml::util; - auto type_ns = common::model::namespace_{type()} - .relative_to(using_namespace) - .to_string(); + auto type_ns = + using_namespace.relative(common::model::namespace_{type()}.to_string()); if (default_value().empty()) return fmt::format("{} {}", type_ns, name()); diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index 2b093ff1..86512a82 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -66,22 +66,28 @@ void generator::generate(const package &p, std::ostream &ostr) const const auto &uns = m_config.using_namespace(); - ostr << "package [" << p.name() << "] "; - ostr << "as " << p.alias(); + // Don't generate packages from namespaces filtered out by + // using_namespace + if (!uns.starts_with(p.full_name(false))) { + ostr << "package [" << p.name() << "] "; + ostr << "as " << p.alias(); - if (p.is_deprecated()) - ostr << " <>"; + if (p.is_deprecated()) + ostr << " <>"; - if (!p.style().empty()) - ostr << " " << p.style(); + if (!p.style().empty()) + ostr << " " << p.style(); - ostr << " {" << '\n'; + ostr << " {" << '\n'; + } for (const auto &subpackage : p) { generate(dynamic_cast(*subpackage), ostr); } - ostr << "}" << '\n'; + if (!uns.starts_with(p.full_name(false))) { + ostr << "}" << '\n'; + } generate_notes(ostr, p); } @@ -92,11 +98,9 @@ void generator::generate(std::ostream &ostr) const generate_plantuml_directives(ostr, m_config.puml().before); - if (m_config.should_include_entities("packages")) { - for (const auto &p : m_model) { - generate(dynamic_cast(*p), ostr); - ostr << '\n'; - } + for (const auto &p : m_model) { + generate(dynamic_cast(*p), ostr); + ostr << '\n'; } // Process package relationships From 2583661d31e1adf8952fbab3e4a0385d5c14b631 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 5 Mar 2022 20:21:21 +0100 Subject: [PATCH 06/14] Updated test cases documentation --- docs/test_cases/t00036_class.svg | 129 ++++++++++++++--------------- docs/test_cases/t30001_package.svg | 26 +++--- docs/test_cases/t30002_package.svg | 64 +++++++------- docs/test_cases/t30003_package.svg | 16 ++-- docs/test_cases/t30004_package.svg | 32 +++---- docs/test_cases/t30005_package.svg | 24 +++--- docs/test_cases/t30006_package.svg | 20 ++--- docs/test_cases/t30007_package.svg | 22 ++--- 8 files changed, 165 insertions(+), 168 deletions(-) diff --git a/docs/test_cases/t00036_class.svg b/docs/test_cases/t00036_class.svg index 8c605353..2b8b0d86 100644 --- a/docs/test_cases/t00036_class.svg +++ b/docs/test_cases/t00036_class.svg @@ -1,6 +1,6 @@ - + - + @@ -8,69 +8,66 @@ - - - ns1 - - - ns11 - - - ns111 - - - ns2 - - - ns22 - - - clanguml - - - - E - - blue - yellow - - - - - A - - T - - - a : T - - - - - A - - int - - - - - - B - - - a_int : A<int> - - - - - C - - - - - - - - a_int + + + ns1 + + + ns11 + + + ns111 + + + ns2 + + + ns22 + + + + E + + blue + yellow + + + + + A + + T + + + a : T + + + + + A + + int + + + + + + B + + + a_int : A<int> + + + + + C + + + + + + + + a_int diff --git a/docs/test_cases/t30001_package.svg b/docs/test_cases/t30001_package.svg index 5fe708ff..e44279fb 100644 --- a/docs/test_cases/t30001_package.svg +++ b/docs/test_cases/t30001_package.svg @@ -1,6 +1,6 @@ - + @@ -8,39 +8,39 @@ - + A - + AA - + B - + AA - + AAA - + BBB - + BB - + AAA - + BBB - + BB - + A AAA note... - + diff --git a/docs/test_cases/t30002_package.svg b/docs/test_cases/t30002_package.svg index 1c52a720..3fca4f33 100644 --- a/docs/test_cases/t30002_package.svg +++ b/docs/test_cases/t30002_package.svg @@ -1,6 +1,6 @@ - + @@ -8,85 +8,85 @@ - + A - + AA - + B - + BB - + A1 - + A2 - + A3 - + A4 - + A5 - + A6 - + A7 - + A8 - + A9 - + A10 - + A11 - + A12 - + A13 - + BBB - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/test_cases/t30003_package.svg b/docs/test_cases/t30003_package.svg index 5c271413..ff4b1151 100644 --- a/docs/test_cases/t30003_package.svg +++ b/docs/test_cases/t30003_package.svg @@ -1,6 +1,6 @@ - + @@ -8,27 +8,27 @@ - + ns1 - + ns3 «deprecated» - + ns1 - + ns2_v1_0_0 - + ns2_v0_9_0 «deprecated» - + ns2 - + diff --git a/docs/test_cases/t30004_package.svg b/docs/test_cases/t30004_package.svg index c31fa15a..b3ae59d8 100644 --- a/docs/test_cases/t30004_package.svg +++ b/docs/test_cases/t30004_package.svg @@ -1,6 +1,6 @@ - + @@ -8,40 +8,40 @@ - + A - + Package AAA. - + Package BBB. - + CCCC package note. - + Another CCC note. - + We skipped DDD. - + AAA - + BBB - + CCC - + EEE - - - - - + + + + + diff --git a/docs/test_cases/t30005_package.svg b/docs/test_cases/t30005_package.svg index 961fed2c..6c275b65 100644 --- a/docs/test_cases/t30005_package.svg +++ b/docs/test_cases/t30005_package.svg @@ -1,6 +1,6 @@ - + @@ -8,36 +8,36 @@ - + A - + AA - + B - + BB - + C - + CC - + AAA - + BBB - + CCC - + - + diff --git a/docs/test_cases/t30006_package.svg b/docs/test_cases/t30006_package.svg index bdb0cbb4..70c21ea4 100644 --- a/docs/test_cases/t30006_package.svg +++ b/docs/test_cases/t30006_package.svg @@ -1,6 +1,6 @@ - + @@ -8,26 +8,26 @@ - + B - + A - + C - + Top A note. - + Bottom A note. - - - + + + - + diff --git a/docs/test_cases/t30007_package.svg b/docs/test_cases/t30007_package.svg index 5ab9d3b9..273ed380 100644 --- a/docs/test_cases/t30007_package.svg +++ b/docs/test_cases/t30007_package.svg @@ -1,6 +1,6 @@ - + @@ -8,29 +8,29 @@ - + A - + B - + AA - + C - + Compare layout with t30006. - + Bottom A note. - - - + + + - + From 17de8b7ded42a2be56f4f2a1c44c9dafe6a36f35 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 5 Mar 2022 22:10:27 +0100 Subject: [PATCH 07/14] Prevent infinite recursion during alias resolution #18 --- src/class_diagram/visitor/translation_unit_context.cc | 7 ++++++- src/class_diagram/visitor/translation_unit_visitor.cc | 7 +++++-- src/cx/util.cc | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/class_diagram/visitor/translation_unit_context.cc b/src/class_diagram/visitor/translation_unit_context.cc index dd66ed05..ae2fe3fb 100644 --- a/src/class_diagram/visitor/translation_unit_context.cc +++ b/src/class_diagram/visitor/translation_unit_context.cc @@ -115,7 +115,12 @@ translation_unit_context::get_type_alias_final(const cppast::cpp_type &t) const cx::util::full_name(cppast::remove_cv(t), entity_index_, false); if (has_type_alias(type_full_name)) { - return get_type_alias_final(alias_index_.at(type_full_name).get()); + const auto &alias_type = alias_index_.at(type_full_name).get(); + // Prevent infinite recursion + if (type_full_name != + cx::util::full_name( + cppast::remove_cv(alias_type), entity_index_, false)) + return get_type_alias_final(alias_type); } return type_safe::ref(t); diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 0f98de94..7b2661ec 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -1349,8 +1349,11 @@ bool translation_unit_visitor::find_relationships_in_user_defined_type( if (ctx.has_type_alias(fn)) { LOG_DBG("Find relationship in alias of {} | {}", fn, cppast::to_string(ctx.get_type_alias(fn).get())); - found = find_relationships( - ctx.get_type_alias(fn).get(), relationships, relationship_type); + if (cppast::to_string(t_) == fn) + found = true; + else + found = find_relationships( + ctx.get_type_alias(fn).get(), relationships, relationship_type); } return found; } diff --git a/src/cx/util.cc b/src/cx/util.cc index 4907b56e..7c780a6a 100644 --- a/src/cx/util.cc +++ b/src/cx/util.cc @@ -88,6 +88,10 @@ std::string ns(const cppast::cpp_entity &e) } it = it.value().parent(); } + + if (res.empty()) + return ""; + std::reverse(res.begin(), res.end()); return fmt::format("{}", fmt::join(res, "::")); From ebe39fe3cf37e643cbad3eefe80a7c8971e9d394 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 6 Mar 2022 00:21:46 +0100 Subject: [PATCH 08/14] Added support for anonymous nested structs --- .../generators/plantuml/class_diagram_generator.cc | 12 ++++++++---- src/class_diagram/model/class.cc | 12 ++++++++++-- .../visitor/translation_unit_visitor.cc | 14 +++++++++----- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index c3bd0b3a..dccfadd9 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -33,12 +33,16 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const if (c.is_abstract()) class_type = "abstract"; - auto full_name = c.full_name(); - + std::string full_name; if (m_config.generate_packages()) - ostr << class_type << " \"" << c.full_name_no_ns(); + full_name = c.full_name_no_ns(); else - ostr << class_type << " \"" << c.full_name(); + full_name = c.full_name(); + + if (full_name.empty()) + full_name = "<>"; + + ostr << class_type << " \"" << full_name; ostr << "\" as " << c.alias() << '\n'; } diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc index 4ad31d2a..de519deb 100644 --- a/src/class_diagram/model/class.cc +++ b/src/class_diagram/model/class.cc @@ -119,11 +119,19 @@ std::string class_::full_name(bool relative) const ostr << name_and_ns(); render_template_params(ostr); + std::string res; + if (relative) - return using_namespace().relative(ostr.str()); + res = using_namespace().relative(ostr.str()); else - return ostr.str(); + res = ostr.str(); + + if(res.empty()) + return "<>"; + + return res; } + std::ostringstream &class_::render_template_params( std::ostringstream &ostr) const { diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 7b2661ec..4fc7ce58 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -313,7 +313,7 @@ void translation_unit_visitor::process_class_declaration( auto c_ptr = std::make_unique(ctx.config().using_namespace()); auto &c = *c_ptr; c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t); - // c.set_name(cx::util::full_name(ctx.get_namespace(), cls)); + c.set_name(cls.name()); c.set_namespace(ctx.get_namespace()); @@ -711,8 +711,12 @@ void translation_unit_visitor::process_field( { bool template_instantiation_added_as_aggregation{false}; - class_member m{detail::cpp_access_specifier_to_scope(as), mv.name(), - cppast::to_string(mv.type())}; + auto type_name = cppast::to_string(mv.type()); + if (type_name.empty()) + type_name = "<>"; + + class_member m{ + detail::cpp_access_specifier_to_scope(as), mv.name(), type_name}; if (mv.comment().has_value()) m.add_decorators(decorators::parse(mv.comment().value())); @@ -722,6 +726,8 @@ void translation_unit_visitor::process_field( auto &tr = cx::util::unreferenced(cppast::remove_cv(mv.type())); + auto tr_declaration = cppast::to_string(tr); + #ifndef __APPLE__ LOG_DBG("Processing field {} with unreferenced type of kind {}", mv.name(), tr.kind()); @@ -748,8 +754,6 @@ void translation_unit_visitor::process_field( // TODO } - auto tr_declaration = cppast::to_string(tr); - if (!m.skip_relationship() && !template_instantiation_added_as_aggregation && (tr.kind() != cppast::cpp_type_kind::builtin_t) && From db3de87e8acb93efdd64f3b75a25c497dd9c8dfc Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 6 Mar 2022 00:24:11 +0100 Subject: [PATCH 09/14] Added anonymous struct test case --- tests/t00037/.clang-uml | 13 ++++++++++++ tests/t00037/t00037.cc | 26 ++++++++++++++++++++++++ tests/t00037/test_case.h | 44 ++++++++++++++++++++++++++++++++++++++++ tests/test_cases.cc | 1 + tests/test_cases.yaml | 3 +++ 5 files changed, 87 insertions(+) create mode 100644 tests/t00037/.clang-uml create mode 100644 tests/t00037/t00037.cc create mode 100644 tests/t00037/test_case.h diff --git a/tests/t00037/.clang-uml b/tests/t00037/.clang-uml new file mode 100644 index 00000000..9a8cd532 --- /dev/null +++ b/tests/t00037/.clang-uml @@ -0,0 +1,13 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t00037_class: + type: class + generate_packages: true + glob: + - ../../tests/t00037/t00037.cc + using_namespace: + - clanguml::t00037 + include: + namespaces: + - clanguml::t00037 \ No newline at end of file diff --git a/tests/t00037/t00037.cc b/tests/t00037/t00037.cc new file mode 100644 index 00000000..c2b53adb --- /dev/null +++ b/tests/t00037/t00037.cc @@ -0,0 +1,26 @@ +namespace clanguml { +namespace t00037 { + +struct ST { + struct { + double t; + double x; + double y; + double z; + } dimensions; +}; + +struct A { + A() + { + st.dimensions.t = -1; + st.dimensions.x = 1; + st.dimensions.y = 1; + st.dimensions.z = 1; + } + + ST st; +}; + +} // namespace t00037 +} // namespace clanguml diff --git a/tests/t00037/test_case.h b/tests/t00037/test_case.h new file mode 100644 index 00000000..87927d99 --- /dev/null +++ b/tests/t00037/test_case.h @@ -0,0 +1,44 @@ +/** + * tests/t00037/test_case.cc + * + * Copyright (c) 2021-2022 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. + */ + +TEST_CASE("t00037", "[test-case][class]") +{ + auto [config, db] = load_config("t00037"); + + auto diagram = config.diagrams["t00037_class"]; + + REQUIRE(diagram->name == "t00037_class"); + REQUIRE(diagram->generate_packages() == true); + + auto model = generate_class_diagram(db, diagram); + + REQUIRE(model.name() == "t00037_class"); + + auto puml = generate_class_puml(diagram, model); + AliasMatcher _A(puml); + + REQUIRE_THAT(puml, StartsWith("@startuml")); + REQUIRE_THAT(puml, EndsWith("@enduml\n")); + + REQUIRE_THAT(puml, IsClass(_A("ST"))); + REQUIRE_THAT(puml, IsClass(_A("A"))); + REQUIRE_THAT(puml, IsInnerClass(_A("ST"), _A("<>"))); + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 30e3727c..2257c8c1 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -179,6 +179,7 @@ using namespace clanguml::test::matchers; #include "t00034/test_case.h" #include "t00035/test_case.h" #include "t00036/test_case.h" +#include "t00037/test_case.h" // // Sequence diagram tests diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 6a50c833..6c93e7e4 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -105,6 +105,9 @@ test_cases: - name: t00036 title: Class diagram with namespaces generated as packages description: + - name: t00037 + title: Anonymous nested struct test case + description: Sequence diagrams: - name: t20001 title: Basic sequence diagram test case From d79cead4ce9ca95078593a766c67f58eae02a33a Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 6 Mar 2022 00:24:32 +0100 Subject: [PATCH 10/14] Fixed formatting --- src/class_diagram/model/class.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc index de519deb..0e05acd0 100644 --- a/src/class_diagram/model/class.cc +++ b/src/class_diagram/model/class.cc @@ -126,7 +126,7 @@ std::string class_::full_name(bool relative) const else res = ostr.str(); - if(res.empty()) + if (res.empty()) return "<>"; return res; From 2c066c321a59d93d495e45dcf536ba4346fbf1dc Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 6 Mar 2022 00:25:42 +0100 Subject: [PATCH 11/14] Updated test cases documentation --- docs/test_cases.md | 1 + docs/test_cases/t00037.md | 50 +++++++++++++++++++++++ docs/test_cases/t00037_class.svg | 52 ++++++++++++++++++++++++ docs/test_cases/t30001_package.svg | 26 ++++++------ docs/test_cases/t30002_package.svg | 64 +++++++++++++++--------------- docs/test_cases/t30003_package.svg | 16 ++++---- docs/test_cases/t30004_package.svg | 32 +++++++-------- docs/test_cases/t30005_package.svg | 24 +++++------ docs/test_cases/t30006_package.svg | 20 +++++----- docs/test_cases/t30007_package.svg | 22 +++++----- 10 files changed, 205 insertions(+), 102 deletions(-) create mode 100644 docs/test_cases/t00037.md create mode 100644 docs/test_cases/t00037_class.svg diff --git a/docs/test_cases.md b/docs/test_cases.md index f4cc24d9..b762f598 100644 --- a/docs/test_cases.md +++ b/docs/test_cases.md @@ -35,6 +35,7 @@ * [t00034](./test_cases/t00034.md) - Template metaprogramming type function test case * [t00035](./test_cases/t00035.md) - PlantUML class diagram layout hints test case * [t00036](./test_cases/t00036.md) - Class diagram with namespaces generated as packages + * [t00037](./test_cases/t00037.md) - Anonymous nested struct test case ## Sequence diagrams * [t20001](./test_cases/t20001.md) - Basic sequence diagram test case * [t20002](./test_cases/t20002.md) - Free function sequence diagram test case diff --git a/docs/test_cases/t00037.md b/docs/test_cases/t00037.md new file mode 100644 index 00000000..d8369733 --- /dev/null +++ b/docs/test_cases/t00037.md @@ -0,0 +1,50 @@ +# t00037 - Anonymous nested struct test case +## Config +```yaml +compilation_database_dir: .. +output_directory: puml +diagrams: + t00037_class: + type: class + generate_packages: true + glob: + - ../../tests/t00037/t00037.cc + using_namespace: + - clanguml::t00037 + include: + namespaces: + - clanguml::t00037 +``` +## Source code +File t00037.cc +```cpp +namespace clanguml { +namespace t00037 { + +struct ST { + struct { + double t; + double x; + double y; + double z; + } dimensions; +}; + +struct A { + A() + { + st.dimensions.t = -1; + st.dimensions.x = 1; + st.dimensions.y = 1; + st.dimensions.z = 1; + } + + ST st; +}; + +} // namespace t00037 +} // namespace clanguml + +``` +## Generated UML diagrams +![t00037_class](./t00037_class.svg "Anonymous nested struct test case") diff --git a/docs/test_cases/t00037_class.svg b/docs/test_cases/t00037_class.svg new file mode 100644 index 00000000..e8dfe26c --- /dev/null +++ b/docs/test_cases/t00037_class.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + ST + + + dimensions : «anonymous» + + + + + <<anonymous>> + + + t : double + + x : double + + y : double + + z : double + + + + + A + + + st : ST + + + A() : void + + + + + + + + st + + diff --git a/docs/test_cases/t30001_package.svg b/docs/test_cases/t30001_package.svg index e44279fb..fdce9ac3 100644 --- a/docs/test_cases/t30001_package.svg +++ b/docs/test_cases/t30001_package.svg @@ -1,6 +1,6 @@ - + @@ -8,39 +8,39 @@ - + A - + AA - + B - + AA - + AAA - + BBB - + BB - + AAA - + BBB - + BB - + A AAA note... - + diff --git a/docs/test_cases/t30002_package.svg b/docs/test_cases/t30002_package.svg index 3fca4f33..f6c1be0b 100644 --- a/docs/test_cases/t30002_package.svg +++ b/docs/test_cases/t30002_package.svg @@ -1,6 +1,6 @@ - + @@ -8,85 +8,85 @@ - + A - + AA - + B - + BB - + A1 - + A2 - + A3 - + A4 - + A5 - + A6 - + A7 - + A8 - + A9 - + A10 - + A11 - + A12 - + A13 - + BBB - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/test_cases/t30003_package.svg b/docs/test_cases/t30003_package.svg index ff4b1151..8651276a 100644 --- a/docs/test_cases/t30003_package.svg +++ b/docs/test_cases/t30003_package.svg @@ -1,6 +1,6 @@ - + @@ -8,27 +8,27 @@ - + ns1 - + ns3 «deprecated» - + ns1 - + ns2_v1_0_0 - + ns2_v0_9_0 «deprecated» - + ns2 - + diff --git a/docs/test_cases/t30004_package.svg b/docs/test_cases/t30004_package.svg index b3ae59d8..5dd0c78a 100644 --- a/docs/test_cases/t30004_package.svg +++ b/docs/test_cases/t30004_package.svg @@ -1,6 +1,6 @@ - + @@ -8,40 +8,40 @@ - + A - + Package AAA. - + Package BBB. - + CCCC package note. - + Another CCC note. - + We skipped DDD. - + AAA - + BBB - + CCC - + EEE - - - - - + + + + + diff --git a/docs/test_cases/t30005_package.svg b/docs/test_cases/t30005_package.svg index 6c275b65..026a4238 100644 --- a/docs/test_cases/t30005_package.svg +++ b/docs/test_cases/t30005_package.svg @@ -1,6 +1,6 @@ - + @@ -8,36 +8,36 @@ - + A - + AA - + B - + BB - + C - + CC - + AAA - + BBB - + CCC - + - + diff --git a/docs/test_cases/t30006_package.svg b/docs/test_cases/t30006_package.svg index 70c21ea4..d2854297 100644 --- a/docs/test_cases/t30006_package.svg +++ b/docs/test_cases/t30006_package.svg @@ -1,6 +1,6 @@ - + @@ -8,26 +8,26 @@ - + B - + A - + C - + Top A note. - + Bottom A note. - - - + + + - + diff --git a/docs/test_cases/t30007_package.svg b/docs/test_cases/t30007_package.svg index 273ed380..f216c56a 100644 --- a/docs/test_cases/t30007_package.svg +++ b/docs/test_cases/t30007_package.svg @@ -1,6 +1,6 @@ - + @@ -8,29 +8,29 @@ - + A - + B - + AA - + C - + Compare layout with t30006. - + Bottom A note. - - - + + + - + From cd4b0099335bccc9dcd90f75ddb75d2f217a6246 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 6 Mar 2022 19:19:16 +0100 Subject: [PATCH 12/14] Updated cppast ref --- thirdparty/cppast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/cppast b/thirdparty/cppast index b2b871c9..7c460ccc 160000 --- a/thirdparty/cppast +++ b/thirdparty/cppast @@ -1 +1 @@ -Subproject commit b2b871c97e360c2155650f52613df4670e859ebd +Subproject commit 7c460cccc32d7ee692b35380316bd80b0e000ffa From 1a9b338ff03d8cc758a75bec0fca605a6fe69cee Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 6 Mar 2022 19:26:33 +0100 Subject: [PATCH 13/14] Added unexposed nested template test case --- tests/t00038/.clang-uml | 13 +++++++ tests/t00038/t00038.cc | 41 +++++++++++++++++++++ tests/t00038/test_case.h | 78 ++++++++++++++++++++++++++++++++++++++++ tests/test_cases.cc | 1 + 4 files changed, 133 insertions(+) create mode 100644 tests/t00038/.clang-uml create mode 100644 tests/t00038/t00038.cc create mode 100644 tests/t00038/test_case.h diff --git a/tests/t00038/.clang-uml b/tests/t00038/.clang-uml new file mode 100644 index 00000000..29318d35 --- /dev/null +++ b/tests/t00038/.clang-uml @@ -0,0 +1,13 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t00038_class: + type: class + generate_packages: true + glob: + - ../../tests/t00038/t00038.cc + using_namespace: + - clanguml::t00038 + include: + namespaces: + - clanguml::t00038 \ No newline at end of file diff --git a/tests/t00038/t00038.cc b/tests/t00038/t00038.cc new file mode 100644 index 00000000..531a44fe --- /dev/null +++ b/tests/t00038/t00038.cc @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +namespace clanguml { +namespace t00038 { + +enum class property_t { property_a, property_b, property_c }; + +struct A { +}; +struct B { +}; +struct C { +}; + +struct key_t { + std::string key; +}; + +template struct map; + +template <> +struct map> : A { +}; + +template <> +struct map< + std::vector>> + : B { +}; + +template <> +struct map>>> + : C { +}; + +} // namespace t00038 +} // namespace clanguml diff --git a/tests/t00038/test_case.h b/tests/t00038/test_case.h new file mode 100644 index 00000000..6f429bbb --- /dev/null +++ b/tests/t00038/test_case.h @@ -0,0 +1,78 @@ +/** + * tests/t00038/test_case.cc + * + * Copyright (c) 2021-2022 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. + */ + +TEST_CASE("t00038", "[test-case][class]") +{ + auto [config, db] = load_config("t00038"); + + auto diagram = config.diagrams["t00038_class"]; + + REQUIRE(diagram->name == "t00038_class"); + REQUIRE(diagram->generate_packages() == true); + + auto model = generate_class_diagram(db, diagram); + + REQUIRE(model.name() == "t00038_class"); + + auto puml = generate_class_puml(diagram, model); + AliasMatcher _A(puml); + + REQUIRE_THAT(puml, StartsWith("@startuml")); + REQUIRE_THAT(puml, EndsWith("@enduml\n")); + + REQUIRE_THAT(puml, IsClass(_A("A"))); + REQUIRE_THAT(puml, IsClass(_A("B"))); + REQUIRE_THAT(puml, IsClass(_A("C"))); + REQUIRE_THAT(puml, IsClass(_A("key_t"))); + REQUIRE_THAT(puml, IsClassTemplate("map", "T")); + REQUIRE_THAT(puml, + IsClassTemplate("map", + "std::integral_constant")); + REQUIRE_THAT(puml, + IsClassTemplate("map", + "std::vector>")); + REQUIRE_THAT(puml, + IsClassTemplate("map", + "std::map>>")); + + REQUIRE_THAT(puml, IsEnum(_A("property_t"))); + + REQUIRE_THAT(puml, + IsInstantiation(_A("map"), + _A("map>>>"))); + + // TODO: Add parsing of unexposed template arguments to infer + // additional relationships + /* + REQUIRE_THAT(puml, + IsDependency(_A("map>"), + _A("property_t"))); + + REQUIRE_THAT(puml, + IsDependency(_A("map>>>"), + _A("key_t"))); + */ + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 2257c8c1..f6e3a939 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -180,6 +180,7 @@ using namespace clanguml::test::matchers; #include "t00035/test_case.h" #include "t00036/test_case.h" #include "t00037/test_case.h" +#include "t00038/test_case.h" // // Sequence diagram tests From b5479efb2c257e73ced962dbfbda683a1977a078 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 6 Mar 2022 19:28:11 +0100 Subject: [PATCH 14/14] Updated test cases documentation --- docs/test_cases.md | 1 + docs/test_cases/t00038.md | 65 +++++++++++++++++++++ docs/test_cases/t00038_class.svg | 91 ++++++++++++++++++++++++++++++ docs/test_cases/t30001_package.svg | 26 ++++----- docs/test_cases/t30002_package.svg | 64 ++++++++++----------- docs/test_cases/t30003_package.svg | 16 +++--- docs/test_cases/t30004_package.svg | 32 +++++------ docs/test_cases/t30005_package.svg | 24 ++++---- docs/test_cases/t30006_package.svg | 20 +++---- docs/test_cases/t30007_package.svg | 22 ++++---- tests/test_cases.yaml | 3 + 11 files changed, 262 insertions(+), 102 deletions(-) create mode 100644 docs/test_cases/t00038.md create mode 100644 docs/test_cases/t00038_class.svg diff --git a/docs/test_cases.md b/docs/test_cases.md index b762f598..9b5a3647 100644 --- a/docs/test_cases.md +++ b/docs/test_cases.md @@ -36,6 +36,7 @@ * [t00035](./test_cases/t00035.md) - PlantUML class diagram layout hints test case * [t00036](./test_cases/t00036.md) - Class diagram with namespaces generated as packages * [t00037](./test_cases/t00037.md) - Anonymous nested struct test case + * [t00038](./test_cases/t00038.md) - Template instantiation with unexposed nested templates ## Sequence diagrams * [t20001](./test_cases/t20001.md) - Basic sequence diagram test case * [t20002](./test_cases/t20002.md) - Free function sequence diagram test case diff --git a/docs/test_cases/t00038.md b/docs/test_cases/t00038.md new file mode 100644 index 00000000..7e692ca2 --- /dev/null +++ b/docs/test_cases/t00038.md @@ -0,0 +1,65 @@ +# t00038 - Template instantiation with unexposed nested templates +## Config +```yaml +compilation_database_dir: .. +output_directory: puml +diagrams: + t00038_class: + type: class + generate_packages: true + glob: + - ../../tests/t00038/t00038.cc + using_namespace: + - clanguml::t00038 + include: + namespaces: + - clanguml::t00038 +``` +## Source code +File t00038.cc +```cpp +#include +#include +#include +#include + +namespace clanguml { +namespace t00038 { + +enum class property_t { property_a, property_b, property_c }; + +struct A { +}; +struct B { +}; +struct C { +}; + +struct key_t { + std::string key; +}; + +template struct map; + +template <> +struct map> : A { +}; + +template <> +struct map< + std::vector>> + : B { +}; + +template <> +struct map>>> + : C { +}; + +} // namespace t00038 +} // namespace clanguml + +``` +## Generated UML diagrams +![t00038_class](./t00038_class.svg "Template instantiation with unexposed nested templates") diff --git a/docs/test_cases/t00038_class.svg b/docs/test_cases/t00038_class.svg new file mode 100644 index 00000000..d98ca2dd --- /dev/null +++ b/docs/test_cases/t00038_class.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + property_t + + property_a + property_b + property_c + + + + + A + + + + + + B + + + + + + C + + + + + + key_t + + + key : std::string + + + + + map + + T + + + + + + map + + std::integral_constant<property_t,property_t::property_a> + + + + + + map + + std::vector<std::integral_constant<property_t,property_t::property_b>> + + + + + + map + + std::map<key_t,std::vector<std::integral_constant<property_t,property_t::property_c>>> + + + + + + + + + + + + + + + + diff --git a/docs/test_cases/t30001_package.svg b/docs/test_cases/t30001_package.svg index fdce9ac3..5a619080 100644 --- a/docs/test_cases/t30001_package.svg +++ b/docs/test_cases/t30001_package.svg @@ -1,6 +1,6 @@ - + @@ -8,39 +8,39 @@ - + A - + AA - + B - + AA - + AAA - + BBB - + BB - + AAA - + BBB - + BB - + A AAA note... - + diff --git a/docs/test_cases/t30002_package.svg b/docs/test_cases/t30002_package.svg index f6c1be0b..edba7654 100644 --- a/docs/test_cases/t30002_package.svg +++ b/docs/test_cases/t30002_package.svg @@ -1,6 +1,6 @@ - + @@ -8,85 +8,85 @@ - + A - + AA - + B - + BB - + A1 - + A2 - + A3 - + A4 - + A5 - + A6 - + A7 - + A8 - + A9 - + A10 - + A11 - + A12 - + A13 - + BBB - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/test_cases/t30003_package.svg b/docs/test_cases/t30003_package.svg index 8651276a..80850b58 100644 --- a/docs/test_cases/t30003_package.svg +++ b/docs/test_cases/t30003_package.svg @@ -1,6 +1,6 @@ - + @@ -8,27 +8,27 @@ - + ns1 - + ns3 «deprecated» - + ns1 - + ns2_v1_0_0 - + ns2_v0_9_0 «deprecated» - + ns2 - + diff --git a/docs/test_cases/t30004_package.svg b/docs/test_cases/t30004_package.svg index 5dd0c78a..fa521c04 100644 --- a/docs/test_cases/t30004_package.svg +++ b/docs/test_cases/t30004_package.svg @@ -1,6 +1,6 @@ - + @@ -8,40 +8,40 @@ - + A - + Package AAA. - + Package BBB. - + CCCC package note. - + Another CCC note. - + We skipped DDD. - + AAA - + BBB - + CCC - + EEE - - - - - + + + + + diff --git a/docs/test_cases/t30005_package.svg b/docs/test_cases/t30005_package.svg index 026a4238..af71db87 100644 --- a/docs/test_cases/t30005_package.svg +++ b/docs/test_cases/t30005_package.svg @@ -1,6 +1,6 @@ - + @@ -8,36 +8,36 @@ - + A - + AA - + B - + BB - + C - + CC - + AAA - + BBB - + CCC - + - + diff --git a/docs/test_cases/t30006_package.svg b/docs/test_cases/t30006_package.svg index d2854297..9e9a5585 100644 --- a/docs/test_cases/t30006_package.svg +++ b/docs/test_cases/t30006_package.svg @@ -1,6 +1,6 @@ - + @@ -8,26 +8,26 @@ - + B - + A - + C - + Top A note. - + Bottom A note. - - - + + + - + diff --git a/docs/test_cases/t30007_package.svg b/docs/test_cases/t30007_package.svg index f216c56a..e86c10b7 100644 --- a/docs/test_cases/t30007_package.svg +++ b/docs/test_cases/t30007_package.svg @@ -1,6 +1,6 @@ - + @@ -8,29 +8,29 @@ - + A - + B - + AA - + C - + Compare layout with t30006. - + Bottom A note. - - - + + + - + diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 6c93e7e4..d25f560b 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -108,6 +108,9 @@ test_cases: - name: t00037 title: Anonymous nested struct test case description: + - name: t00038 + title: Template instantiation with unexposed nested templates + description: Sequence diagrams: - name: t20001 title: Basic sequence diagram test case