diff --git a/Makefile b/Makefile index fa43cc4f..1eebfe73 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,7 @@ clanguml_diagrams: debug mkdir -p docs/diagrams debug/clang-uml plantuml -tsvg docs/diagrams/*.puml + python3 util/format_svg.py docs/diagrams/*.svg .PHONY: submodules submodules: diff --git a/docs/configuration_file.md b/docs/configuration_file.md index ddd9dc82..d8c1914a 100644 --- a/docs/configuration_file.md +++ b/docs/configuration_file.md @@ -11,17 +11,21 @@ * `glob` - list of glob patterns to match source code files for analysis * `include_relations_also_as_members` - when set to `false`, class members for relationships are rendered in UML are skipped from class definition (default: `true`) * `generate_method_arguments` - determines whether the class diagrams methods contain full arguments (`full`), are abbreviated (`abbreviated`) or skipped (`none`) -* `using_namespace` - similar to C++ `using namespace`, a `A::B` value here will render a class `A::B::C::MyClass` in the diagram as `C::MyClass` +* `using_namespace` - similar to C++ `using namespace`, a `A::B` value here will render a class `A::B::C::MyClass` in the diagram as `C::MyClass`, at most 1 value is supported * `include` - definition of inclusion patterns: * `namespaces` - list of namespaces to include * `relationships` - list of relationships to include - * `entity_types` - list of entity types to include (e.g. `class`, `enum`) - * `scopes` - list of visibility scopes to include (e.g. `private`) + * `elements` - list of elements, i.e. specific classes, enums, templates to include + * `access` - list of visibility scopes to include (e.g. `private`) + * `subclasses` - include only subclasses of specified classes (and themselves) + * `context` - include only entities in direct relationship with specified classes * `exclude` - definition of excqlusion patterns: * `namespaces` - list of namespaces to exclude * `relationships` - list of relationships to exclude - * `entity_types` - list of entity types to exclude (e.g. `class`, `enum`) - * `scopes` - list of visibility scopes to exclude (e.g. `private`) + * `elements` - list of elements, i.e. specific classes, enums, templates to exclude + * `access` - list of visibility scopes to exclude (e.g. `private`) + * `subclasses` - exclude subclasses of specified classes (and themselves) + * `context` - exclude only entities in direct relationship with specified classes * `layout` - add layout hints for entities (classes, packages) * `plantuml` - verbatim PlantUML directives which should be added to a diagram * `before` - list of directives which will be added before the generated diagram @@ -79,9 +83,12 @@ diagrams: namespaces: - clanguml::common::model - clanguml::class_diagram::model + # Only include elements in direct relationship with ClassA + context: + - ClassA exclude: # Do not include private members and methods in the diagram - scopes: + access: - private layout: # Add layout hints for PlantUML diff --git a/docs/test_cases.md b/docs/test_cases.md index 9b5a3647..50a10212 100644 --- a/docs/test_cases.md +++ b/docs/test_cases.md @@ -37,6 +37,9 @@ * [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 + * [t00039](./test_cases/t00039.md) - Subclass class diagram filter test + * [t00040](./test_cases/t00040.md) - Relationship and access filter test + * [t00041](./test_cases/t00041.md) - Context diagram filter test ## 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/t00002_class.svg b/docs/test_cases/t00002_class.svg index f727a875..82e7b14d 100644 --- a/docs/test_cases/t00002_class.svg +++ b/docs/test_cases/t00002_class.svg @@ -1,145 +1,146 @@ - + + - - + + 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 65531da2..8b07705b 100644 --- a/docs/test_cases/t00003_class.svg +++ b/docs/test_cases/t00003_class.svg @@ -1,201 +1,202 @@ - + + - - + + 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 744ab16c..f8195895 100644 --- a/docs/test_cases/t00004_class.svg +++ b/docs/test_cases/t00004_class.svg @@ -1,45 +1,46 @@ - + + - - + + A - + - + foo() const : void - + - + foo2() const : void - - + + AA - - + + Lights @@ -49,23 +50,23 @@ Red - - + + AAA - + - + - + diff --git a/docs/test_cases/t00005_class.svg b/docs/test_cases/t00005_class.svg index c7645dbe..0f3ddaeb 100644 --- a/docs/test_cases/t00005_class.svg +++ b/docs/test_cases/t00005_class.svg @@ -1,245 +1,246 @@ - + + - - + + 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 17a9940c..6d655087 100644 --- a/docs/test_cases/t00006_class.svg +++ b/docs/test_cases/t00006_class.svg @@ -1,143 +1,144 @@ - + + - - + + A - - + + B - - + + C - - + + D - - + + E - - + + F - - + + G - - + + H - - + + I - - + + J - - + + K - - + + L - - + + M - - + + N - - + + NN - - + + NNN - - + + custom_container @@ -145,15 +146,15 @@ T - + - + data : std::vector<T> - + custom_container @@ -161,159 +162,159 @@ 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 cd8df63d..f6fa6e5d 100644 --- a/docs/test_cases/t00007_class.svg +++ b/docs/test_cases/t00007_class.svg @@ -1,73 +1,74 @@ - + + - - + + 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 15d5c562..32db5eb7 100644 --- a/docs/test_cases/t00008_class.svg +++ b/docs/test_cases/t00008_class.svg @@ -1,15 +1,16 @@ - + + - - + + A @@ -17,51 +18,51 @@ T,P,CMP,int N - + - + value : T - + - + pointer : T* - + - + reference : T& - + - + values : std::vector<P> - + - + ints : std::array<int,N> - + - + comparator : CMP - - + + Vector @@ -69,16 +70,16 @@ T - + - + values : std::vector<T> - - + + B @@ -86,15 +87,15 @@ T,C<> - + - + template_template : C<T> - + B @@ -102,31 +103,31 @@ 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 1e144c92..13d224e2 100644 --- a/docs/test_cases/t00009_class.svg +++ b/docs/test_cases/t00009_class.svg @@ -1,15 +1,16 @@ - + + - - + + A @@ -17,15 +18,15 @@ T - + - + value : T - + A @@ -33,7 +34,7 @@ int - + A @@ -41,7 +42,7 @@ std::string - + A @@ -49,50 +50,50 @@ 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 356995e2..bbc31508 100644 --- a/docs/test_cases/t00010_class.svg +++ b/docs/test_cases/t00010_class.svg @@ -1,15 +1,16 @@ - + + - - + + A @@ -17,22 +18,22 @@ T,P - + - + first : T - + - + second : P - + A @@ -40,8 +41,8 @@ T,std::string - - + + B @@ -49,15 +50,15 @@ T - + - + astring : A<T,std::string> - + B @@ -65,30 +66,30 @@ int - - + + C - + - + aintstring : B<int> - + - + astring - + - + aintstring diff --git a/docs/test_cases/t00011_class.svg b/docs/test_cases/t00011_class.svg index 2872ba64..78537d30 100644 --- a/docs/test_cases/t00011_class.svg +++ b/docs/test_cases/t00011_class.svg @@ -1,15 +1,16 @@ - + - + + - - + + D @@ -17,57 +18,58 @@ T - + - + value : T - - + + A - + - + foo() : void - - + + B - + - + m_a : A* - + - + foo() : void - - - «friend» - - - - m_a + + + + «friend» + + + + m_a diff --git a/docs/test_cases/t00012_class.svg b/docs/test_cases/t00012_class.svg index c28eecbc..fcd8a4c2 100644 --- a/docs/test_cases/t00012_class.svg +++ b/docs/test_cases/t00012_class.svg @@ -1,15 +1,16 @@ - + + - - + + A @@ -17,23 +18,23 @@ T,Ts... - + - + value : T - + - + values : int - - + + B @@ -42,15 +43,15 @@ - + - + ints : std::array<int,sizeof...(Is)> - - + + C @@ -59,14 +60,14 @@ - + - + ints : std::array<T,sizeof...(Is)> - + A @@ -74,7 +75,7 @@ int,std::string,float - + A @@ -82,7 +83,7 @@ int,std::string,bool - + B @@ -90,7 +91,7 @@ 3,2,1 - + B @@ -98,7 +99,7 @@ 1,1,1,1 - + C @@ -106,79 +107,79 @@ 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 e74b8e62..00d045e5 100644 --- a/docs/test_cases/t00013_class.svg +++ b/docs/test_cases/t00013_class.svg @@ -1,15 +1,16 @@ - + + - - + + ABCD::F @@ -17,83 +18,83 @@ T - + - + f : T - - + + A - + - + a : int - - + + B - + - + b : int - - + + C - + - + c : int - - + + D - + - + d : int - + - + print(R* r) : void - - + + E @@ -101,15 +102,15 @@ T - + - + e : T - + E @@ -117,7 +118,7 @@ int - + F @@ -125,7 +126,7 @@ int - + E @@ -133,123 +134,123 @@ 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 6efb1c97..d07ffa4b 100644 --- a/docs/test_cases/t00014_class.svg +++ b/docs/test_cases/t00014_class.svg @@ -1,15 +1,16 @@ - + + - - + + A @@ -17,22 +18,22 @@ T,P - + - + t : T - + - + p : P - + A @@ -40,22 +41,22 @@ T,std::string - - + + B - + - + value : std::string - + A @@ -63,7 +64,7 @@ bool,std::string - + AString @@ -71,7 +72,7 @@ float - + AString @@ -79,7 +80,7 @@ int - + AString @@ -87,7 +88,7 @@ std::string - + GeneralCallback @@ -95,115 +96,115 @@ 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 fe9eda6d..832850d6 100644 --- a/docs/test_cases/t00015_class.svg +++ b/docs/test_cases/t00015_class.svg @@ -1,58 +1,59 @@ - + + - - + + 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 9c6d4fc5..9e19bcdd 100644 --- a/docs/test_cases/t00016_class.svg +++ b/docs/test_cases/t00016_class.svg @@ -1,15 +1,16 @@ - + + - - + + is_numeric<> @@ -18,8 +19,8 @@ value : enum - - + + is_numeric @@ -30,8 +31,8 @@ value : enum - - + + is_numeric @@ -42,8 +43,8 @@ value : enum - - + + is_numeric @@ -54,8 +55,8 @@ value : enum - - + + is_numeric @@ -66,13 +67,13 @@ value : enum - + - + - + - + diff --git a/docs/test_cases/t00017_class.svg b/docs/test_cases/t00017_class.svg index 9c736dbd..dbd3e31f 100644 --- a/docs/test_cases/t00017_class.svg +++ b/docs/test_cases/t00017_class.svg @@ -1,183 +1,184 @@ - + + - - + + 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 0026b519..cf056069 100644 --- a/docs/test_cases/t00018_class.svg +++ b/docs/test_cases/t00018_class.svg @@ -1,130 +1,131 @@ - + + - - + + 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 7f0a608c..d2ec0e29 100644 --- a/docs/test_cases/t00019_class.svg +++ b/docs/test_cases/t00019_class.svg @@ -1,15 +1,16 @@ - + + - - + + Layer2 @@ -18,51 +19,51 @@ - + - + all_calls_count() const : int - - + + Base - + - + Base() : void - + - + ~Base() : void - + - + m1() : int - + - + m2() : std::string - - + + Layer1 @@ -71,22 +72,22 @@ - + - + m1() : int - + - + m2() : std::string - - + + Layer3 @@ -94,50 +95,50 @@ LowerLayer - + - + m_m1_calls : int - + - + m_m2_calls : int - + - + m1() : int - + - + m2() : std::string - + - + m1_calls() const : int - + - + m2_calls() const : int - + Layer3 @@ -145,7 +146,7 @@ Base - + Layer2 @@ -153,7 +154,7 @@ Layer3<Base> - + Layer1 @@ -161,40 +162,40 @@ 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 53d028cb..23d91945 100644 --- a/docs/test_cases/t00020_class.svg +++ b/docs/test_cases/t00020_class.svg @@ -1,202 +1,203 @@ - + + - - + + 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 4f9e4d1f..38801577 100644 --- a/docs/test_cases/t00021_class.svg +++ b/docs/test_cases/t00021_class.svg @@ -1,191 +1,192 @@ - + + - - + + 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 fe0c156b..451e4c6e 100644 --- a/docs/test_cases/t00022_class.svg +++ b/docs/test_cases/t00022_class.svg @@ -1,89 +1,90 @@ - + + - - + + 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 e0f74bce..7c837b84 100644 --- a/docs/test_cases/t00023_class.svg +++ b/docs/test_cases/t00023_class.svg @@ -1,118 +1,119 @@ - + + - - + + 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 530eddfa..8c7101a2 100644 --- a/docs/test_cases/t00024_class.svg +++ b/docs/test_cases/t00024_class.svg @@ -1,133 +1,134 @@ - + + - - + + 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 8ec44b8d..9731d133 100644 --- a/docs/test_cases/t00025_class.svg +++ b/docs/test_cases/t00025_class.svg @@ -1,59 +1,60 @@ - + + - - + + Target1 - + - + m1() : void - + - + m2() : void - - + + Target2 - + - + m1() : void - + - + m2() : void - - + + Proxy @@ -61,36 +62,36 @@ T - + - + m_target : std::shared_ptr<T> - + - + Proxy(std::shared_ptr<T> target) : void - + - + m1() : void - + - + m2() : void - + Proxy @@ -98,7 +99,7 @@ Target1 - + Proxy @@ -106,41 +107,41 @@ 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 f21f1cbb..4107e405 100644 --- a/docs/test_cases/t00026_class.svg +++ b/docs/test_cases/t00026_class.svg @@ -1,15 +1,16 @@ - + + - - + + Memento @@ -17,30 +18,30 @@ T - + - + m_value : T - + - + Memento(T&& v) : void - + - + value() const : T - - + + Originator @@ -48,51 +49,51 @@ 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 @@ -100,29 +101,29 @@ 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 @@ -130,7 +131,7 @@ std::string - + Originator @@ -138,45 +139,45 @@ 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 0bdc0f16..825c00ac 100644 --- a/docs/test_cases/t00027_class.svg +++ b/docs/test_cases/t00027_class.svg @@ -1,37 +1,38 @@ - + + - - + + Shape - + - + display() = 0 : void - + - + ~Shape() : void - - + + Line @@ -40,15 +41,15 @@ - + - + display() : void - - + + Text @@ -57,30 +58,30 @@ - + - + display() : void - - + + ShapeDecorator - + - + display() = 0 : void - - + + Color @@ -89,15 +90,15 @@ - + - + display() : void - - + + Weight @@ -106,14 +107,14 @@ - + - + display() : void - + Line @@ -121,7 +122,7 @@ Color,Weight - + Line @@ -129,7 +130,7 @@ Color - + Text @@ -137,7 +138,7 @@ Color,Weight - + Text @@ -145,71 +146,71 @@ 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 a46c146e..e6ba4850 100644 --- a/docs/test_cases/t00028_class.svg +++ b/docs/test_cases/t00028_class.svg @@ -1,75 +1,76 @@ - + + - - + + 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 @@ -77,27 +78,27 @@ T - + - + param : T - + E template class note. - - + + G - - + + F @@ -107,13 +108,13 @@ three - + F enum note. - + F enum note. - + E @@ -121,97 +122,97 @@ 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 4cd06884..cb589208 100644 --- a/docs/test_cases/t00029_class.svg +++ b/docs/test_cases/t00029_class.svg @@ -1,23 +1,24 @@ - + + - - + + A - - + + C @@ -25,16 +26,16 @@ T - + - + param : T - - + + E @@ -44,72 +45,72 @@ 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 cb4b0d2e..59a90a82 100644 --- a/docs/test_cases/t00030_class.svg +++ b/docs/test_cases/t00030_class.svg @@ -1,98 +1,99 @@ - + + - - + + 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 diff --git a/docs/test_cases/t00031_class.svg b/docs/test_cases/t00031_class.svg index ceba61a7..0dba7e6b 100644 --- a/docs/test_cases/t00031_class.svg +++ b/docs/test_cases/t00031_class.svg @@ -1,32 +1,33 @@ - + - + - + + - - - + + + A - - + + B @@ -36,8 +37,8 @@ three - - + + @@ -46,23 +47,23 @@ T - + - + ttt : T - - + + D - + C @@ -70,57 +71,57 @@ 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 7f78d0c5..1a02ffed 100644 --- a/docs/test_cases/t00032_class.svg +++ b/docs/test_cases/t00032_class.svg @@ -1,76 +1,77 @@ - + + - - + + Base - - + + TBase - - + + A - + - + operator()() : void - - + + B - + - + operator()() : void - - + + C - + - + operator()() : void - - + + Overload @@ -78,15 +79,15 @@ T,L,Ts... - + - + counter : L - + Overload @@ -94,42 +95,42 @@ 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 083403ba..1fc558ff 100644 --- a/docs/test_cases/t00033_class.svg +++ b/docs/test_cases/t00033_class.svg @@ -1,15 +1,16 @@ - + + - - + + A @@ -17,16 +18,16 @@ T - + - + aaa : T - - + + B @@ -34,16 +35,16 @@ T - + - + bbb : T - - + + C @@ -51,30 +52,30 @@ T - + - + ccc : T - - + + D - + - + ddd : int - + C @@ -82,7 +83,7 @@ D - + B @@ -90,7 +91,7 @@ std::unique_ptr<C<D>> - + A @@ -98,34 +99,34 @@ 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 5a126006..c30b7c8d 100644 --- a/docs/test_cases/t00034_class.svg +++ b/docs/test_cases/t00034_class.svg @@ -1,37 +1,38 @@ - + + - - + + Void - + - + operator==(Void const& ) const : bool - + - + operator!=(Void const& ) const : bool - - + + lift_void @@ -40,8 +41,8 @@ - - + + lift_void @@ -50,8 +51,8 @@ - - + + drop_void @@ -60,8 +61,8 @@ - - + + drop_void @@ -70,43 +71,43 @@ - - + + 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 f0937dde..69058bc7 100644 --- a/docs/test_cases/t00035_class.svg +++ b/docs/test_cases/t00035_class.svg @@ -1,47 +1,48 @@ - + + - - + + Top - - + + Left - - + + Center - - + + Bottom - - + + Right diff --git a/docs/test_cases/t00036_class.svg b/docs/test_cases/t00036_class.svg index 57782899..56a28096 100644 --- a/docs/test_cases/t00036_class.svg +++ b/docs/test_cases/t00036_class.svg @@ -1,30 +1,31 @@ - + + - + ns1 - + ns11 - + ns111 - + ns2 - + ns22 - - + + E @@ -33,8 +34,8 @@ yellow - - + + A @@ -42,15 +43,15 @@ T - + - + a : T - + A @@ -58,32 +59,32 @@ int - - + + B - + - + a_int : A<int> - - + + C - + - + a_int diff --git a/docs/test_cases/t00037_class.svg b/docs/test_cases/t00037_class.svg index d2dddc84..167ee043 100644 --- a/docs/test_cases/t00037_class.svg +++ b/docs/test_cases/t00037_class.svg @@ -1,91 +1,92 @@ - + + - - + + ST - + - + dimensions : «anonymous» - - + + <<anonymous>> - + - + t : double - + - + x : double - + - + y : double - + - + z : double - - + + A - + - + st : ST - + - + A() : void - + - + st diff --git a/docs/test_cases/t00038_class.svg b/docs/test_cases/t00038_class.svg index ed083346..ed262556 100644 --- a/docs/test_cases/t00038_class.svg +++ b/docs/test_cases/t00038_class.svg @@ -1,15 +1,16 @@ - + + - - + + thirdparty::ns1::color_t @@ -19,16 +20,16 @@ blue - - + + thirdparty::ns1::E - - + + property_t @@ -38,47 +39,47 @@ property_c - - + + A - - + + B - - + + C - - + + key_t - + - + key : std::string - - + + map @@ -87,8 +88,8 @@ - - + + map @@ -97,8 +98,8 @@ - - + + map @@ -107,8 +108,8 @@ - - + + map @@ -117,8 +118,8 @@ - - + + map @@ -127,31 +128,31 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/test_cases/t00039.md b/docs/test_cases/t00039.md new file mode 100644 index 00000000..40948b07 --- /dev/null +++ b/docs/test_cases/t00039.md @@ -0,0 +1,72 @@ +# t00039 - Subclass class diagram filter test +## Config +```yaml +compilation_database_dir: .. +output_directory: puml +diagrams: + t00039_class: + type: class + generate_packages: false + glob: + - ../../tests/t00039/t00039.cc + using_namespace: + - clanguml::t00039 + include: + subclasses: + - clanguml::t00039::A + - clanguml::t00039::ns3::F + relationships: + - inheritance +``` +## Source code +File t00039.cc +```cpp +#include + +namespace clanguml::t00039 { +struct B { +}; + +namespace ns1 { +struct BB : public B { +}; +} // namespace ns1 + +struct A { +}; + +struct AA : public A { +}; + +struct AAA : public AA { + B *b; +}; + +namespace ns2 { +struct AAAA : public AAA { +}; +} // namespace ns2 + +namespace ns3 { +template struct F { + T *t; +}; + +template struct FF : public F { + M *m; +}; + +template struct FE : public F { + M *m; +}; + +template struct FFF : public FF { + N *n; +}; + +} // namespace ns3 +} // namespace clanguml::t00039 + +``` +## Generated UML diagrams +![t00039_class](./t00039_class.svg "Subclass class diagram filter test") diff --git a/docs/test_cases/t00039_class.svg b/docs/test_cases/t00039_class.svg new file mode 100644 index 00000000..8117f628 --- /dev/null +++ b/docs/test_cases/t00039_class.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + A + + + + + + + + AA + + + + + + + + AAA + + + + + + + + b : B* + + + + + + + ns2::AAAA + + + + + + + + ns3::F + + T + + + + + + + + t : T* + + + + + + + ns3::FF + + T,M + + + + + + + + m : M* + + + + + + + ns3::FE + + T,M + + + + + + + + m : M* + + + + + + + ns3::FFF + + T,M,N + + + + + + + + n : N* + + + + + + + + + + + + + + + + diff --git a/docs/test_cases/t00040.md b/docs/test_cases/t00040.md new file mode 100644 index 00000000..fd62d589 --- /dev/null +++ b/docs/test_cases/t00040.md @@ -0,0 +1,68 @@ +# t00040 - Relationship and access filter test +## Config +```yaml +compilation_database_dir: .. +output_directory: puml +diagrams: + t00040_class: + type: class + generate_packages: false + glob: + - ../../tests/t00040/t00040.cc + using_namespace: + - clanguml::t00040 + include: + namespaces: + - clanguml::t00040 + access: + - public + - protected + exclude: + relationships: + - dependency + elements: + - clanguml::t00040::B +``` +## Source code +File t00040.cc +```cpp +namespace clanguml::t00040 { + +struct B { +}; + +struct A { +public: + int get_a() { return hidden_a_; } + +protected: + int ii_; + +private: + void foo() { } + + int hidden_a_; +}; + +class AA : public A { +public: +}; + +class AAA : public AA { +public: + int get_aaa() { return hidden_aaa_; } + B *b; + +private: + int hidden_aaa_; +}; + +struct R { + void foo(A *a) { } +}; + +} // namespace clanguml::t00040 + +``` +## Generated UML diagrams +![t00040_class](./t00040_class.svg "Relationship and access filter test") diff --git a/docs/test_cases/t00040_class.svg b/docs/test_cases/t00040_class.svg new file mode 100644 index 00000000..f2f2460c --- /dev/null +++ b/docs/test_cases/t00040_class.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + A + + + + + + + + ii_ : int + + + + + + + + get_a() : int + + + + + + AA + + + + + + + + AAA + + + + + + + + b : B* + + + + + + + + get_aaa() : int + + + + + + R + + + + + + + + + foo(A* a) : void + + + + + + + diff --git a/docs/test_cases/t00041.md b/docs/test_cases/t00041.md new file mode 100644 index 00000000..ab17251e --- /dev/null +++ b/docs/test_cases/t00041.md @@ -0,0 +1,74 @@ +# t00041 - Context diagram filter test +## Config +```yaml +compilation_database_dir: .. +output_directory: puml +diagrams: + t00041_class: + type: class + generate_packages: false + glob: + - ../../tests/t00041/t00041.cc + using_namespace: + - clanguml::t00041 + include: + namespaces: + - clanguml::t00041 + context: + - clanguml::t00041::RR + subclasses: + - clanguml::t00041::ns1::N +``` +## Source code +File t00041.cc +```cpp +namespace clanguml::t00041 { + +struct B { +}; + +struct A { +}; + +class AA : public A { +}; + +struct R { +}; + +struct RR; + +struct D { + RR *rr; +}; + +struct E { +}; + +struct F { +}; + +struct RR : public R { + E *e; + F *f; +}; + +struct RRR : public RR { +}; + +namespace ns1 { +struct N { +}; + +struct NN : public N { +}; + +struct NM : public N { +}; +} + +} // namespace clanguml::t00041 + +``` +## Generated UML diagrams +![t00041_class](./t00041_class.svg "Context diagram filter test") diff --git a/docs/test_cases/t00041_class.svg b/docs/test_cases/t00041_class.svg new file mode 100644 index 00000000..e00c3a92 --- /dev/null +++ b/docs/test_cases/t00041_class.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + R + + + + + + + + D + + + + + + + + rr : RR* + + + + + + + E + + + + + + + + F + + + + + + + + RR + + + + + + + + e : E* + + + + + + + f : F* + + + + + + + RRR + + + + + + + + ns1::N + + + + + + + + ns1::NN + + + + + + + + ns1::NM + + + + + + + rr + + + +e + + + +f + + + + + + + + + + diff --git a/docs/test_cases/t20001_sequence.svg b/docs/test_cases/t20001_sequence.svg index bbbcbdff..470e2953 100644 --- a/docs/test_cases/t20001_sequence.svg +++ b/docs/test_cases/t20001_sequence.svg @@ -6,6 +6,7 @@ + diff --git a/docs/test_cases/t20002_sequence.svg b/docs/test_cases/t20002_sequence.svg index d8e94f30..568a2b80 100644 --- a/docs/test_cases/t20002_sequence.svg +++ b/docs/test_cases/t20002_sequence.svg @@ -6,6 +6,7 @@ + diff --git a/docs/test_cases/t30001_package.svg b/docs/test_cases/t30001_package.svg index 94383a86..19cfccfc 100644 --- a/docs/test_cases/t30001_package.svg +++ b/docs/test_cases/t30001_package.svg @@ -1,66 +1,67 @@ - + + - - + + 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 ae5fa916..2f90ac61 100644 --- a/docs/test_cases/t30002_package.svg +++ b/docs/test_cases/t30002_package.svg @@ -1,128 +1,129 @@ - + + - - + + 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 5997775a..abfcdeaa 100644 --- a/docs/test_cases/t30003_package.svg +++ b/docs/test_cases/t30003_package.svg @@ -1,46 +1,47 @@ - + + - - + + 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 8fe51741..0a766e61 100644 --- a/docs/test_cases/t30004_package.svg +++ b/docs/test_cases/t30004_package.svg @@ -1,57 +1,58 @@ - + + - - + + 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 21c5dacd..aefc641c 100644 --- a/docs/test_cases/t30005_package.svg +++ b/docs/test_cases/t30005_package.svg @@ -1,61 +1,62 @@ - + + - - + + 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 b0b5cd09..7eced5db 100644 --- a/docs/test_cases/t30006_package.svg +++ b/docs/test_cases/t30006_package.svg @@ -1,39 +1,40 @@ - + + - - + + 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 29f44063..59f9ad5b 100644 --- a/docs/test_cases/t30007_package.svg +++ b/docs/test_cases/t30007_package.svg @@ -1,44 +1,45 @@ - + + - - + + 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 37c80296..64b6d962 100644 --- a/docs/test_cases/t90000_class.svg +++ b/docs/test_cases/t90000_class.svg @@ -6,6 +6,7 @@ + diff --git a/examples/cppast/.clang-uml b/examples/cppast/.clang-uml index 92e51154..63cb2b0f 100644 --- a/examples/cppast/.clang-uml +++ b/examples/cppast/.clang-uml @@ -25,7 +25,7 @@ diagrams: exclude: namespaces: - cppast::detail - scopes: + access: - public - protected - private @@ -73,7 +73,7 @@ diagrams: - cppast::detail entity_types: - enums - scopes: + access: - public - protected - private @@ -93,7 +93,7 @@ diagrams: exclude: namespaces: - cppast::detail - scopes: + access: - public - protected - private diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index b90601fb..9b458fdb 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -110,7 +110,7 @@ void generator::generate( // Process methods // for (const auto &m : c.methods()) { - if (!m_config.should_include(m.scope())) + if (!m_model.should_include(m.access())) continue; if (m.is_pure_virtual()) @@ -121,7 +121,7 @@ void generator::generate( std::string type{m.type()}; - ostr << plantuml_common::to_plantuml(m.scope()) << m.name(); + ostr << plantuml_common::to_plantuml(m.access()) << m.name(); ostr << "("; if (m_config.generate_method_arguments() != @@ -168,8 +168,7 @@ void generator::generate( std::stringstream all_relations_str; std::set unique_relations; for (const auto &r : c.relationships()) { - if (!m_config.should_include_relationship( - common::model::to_string(r.type()))) + if (!m_model.should_include(r.type())) continue; LOG_DBG("== Processing relationship {}", @@ -196,7 +195,7 @@ void generator::generate( << m_model.to_alias(uns.relative(destination)); if (!r.label().empty()) { - relstr << " : " << plantuml_common::to_plantuml(r.scope()) + relstr << " : " << plantuml_common::to_plantuml(r.access()) << r.label(); rendered_relations.emplace(r.label()); } @@ -223,7 +222,7 @@ void generator::generate( // Process members // for (const auto &m : c.members()) { - if (!m_config.should_include(m.scope())) + if (!m_model.should_include(m.access())) continue; if (!m_config.include_relations_also_as_members() && @@ -233,7 +232,7 @@ void generator::generate( if (m.is_static()) ostr << "{static} "; - ostr << plantuml_common::to_plantuml(m.scope()) << m.name() << " : " + ostr << plantuml_common::to_plantuml(m.access()) << m.name() << " : " << uns.relative(m.type()); if (m_config.generate_links) { @@ -245,7 +244,7 @@ void generator::generate( ostr << "}" << '\n'; - if (m_config.should_include_relationship("inheritance")) { + if (m_model.should_include(relationship_t::kExtension)) { for (const auto &b : c.parents()) { std::stringstream relstr; try { @@ -288,8 +287,7 @@ void generator::generate( ostr << "}" << '\n'; for (const auto &r : e.relationships()) { - if (!m_config.should_include_relationship( - common::model::to_string(r.type()))) + if (!m_model.should_include(r.type())) continue; std::string destination; @@ -357,14 +355,18 @@ void generator::generate(const package &p, std::ostream &ostr, generate(sp, ostr, relationships_ostr); } else if (dynamic_cast(subpackage.get())) { - generate_alias(dynamic_cast(*subpackage), ostr); - generate( - dynamic_cast(*subpackage), ostr, relationships_ostr); + if (m_model.should_include(*subpackage)) { + generate_alias(dynamic_cast(*subpackage), ostr); + generate(dynamic_cast(*subpackage), ostr, + relationships_ostr); + } } else if (dynamic_cast(subpackage.get())) { - generate_alias(dynamic_cast(*subpackage), ostr); - generate( - dynamic_cast(*subpackage), ostr, relationships_ostr); + if (m_model.should_include(*subpackage)) { + generate_alias(dynamic_cast(*subpackage), ostr); + generate(dynamic_cast(*subpackage), ostr, + relationships_ostr); + } } } @@ -394,12 +396,16 @@ void generator::generate(std::ostream &ostr) const generate(sp, ostr, relationships_ostr); } else if (dynamic_cast(p.get())) { - generate_alias(dynamic_cast(*p), ostr); - generate(dynamic_cast(*p), ostr, relationships_ostr); + if (m_model.should_include(*p)) { + generate_alias(dynamic_cast(*p), ostr); + generate(dynamic_cast(*p), ostr, relationships_ostr); + } } else if (dynamic_cast(p.get())) { - generate_alias(dynamic_cast(*p), ostr); - generate(dynamic_cast(*p), ostr, relationships_ostr); + if (m_model.should_include(*p)) { + generate_alias(dynamic_cast(*p), ostr); + generate(dynamic_cast(*p), ostr, relationships_ostr); + } } ostr << '\n'; } diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h index 74119724..9b8ec30d 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -49,9 +49,9 @@ using common_generator = using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::enum_; +using clanguml::common::model::access_t; using clanguml::common::model::package; using clanguml::common::model::relationship_t; -using clanguml::common::model::scope_t; using namespace clanguml::util; diff --git a/src/class_diagram/model/class_element.cc b/src/class_diagram/model/class_element.cc index 65688e14..8c21456f 100644 --- a/src/class_diagram/model/class_element.cc +++ b/src/class_diagram/model/class_element.cc @@ -20,15 +20,15 @@ namespace clanguml::class_diagram::model { -class_element::class_element(common::model::scope_t scope, +class_element::class_element(common::model::access_t access, const std::string &name, const std::string &type) - : scope_{scope} + : access_{access} , name_{name} , type_{type} { } -common::model::scope_t class_element::scope() const { return scope_; } +common::model::access_t class_element::access() const { return access_; } std::string class_element::name() const { return name_; } @@ -39,7 +39,7 @@ inja::json class_element::context() const inja::json ctx; ctx["name"] = name(); ctx["type"] = type(); - ctx["scope"] = to_string(scope()); + ctx["access"] = to_string(access()); return ctx; } } diff --git a/src/class_diagram/model/class_element.h b/src/class_diagram/model/class_element.h index 765fce87..441c26c9 100644 --- a/src/class_diagram/model/class_element.h +++ b/src/class_diagram/model/class_element.h @@ -29,17 +29,17 @@ namespace clanguml::class_diagram::model { class class_element : public common::model::decorated_element, public common::model::source_location { public: - class_element(common::model::scope_t scope, const std::string &name, + class_element(common::model::access_t scope, const std::string &name, const std::string &type); - common::model::scope_t scope() const; + common::model::access_t access() const; std::string name() const; std::string type() const; virtual inja::json context() const; private: - common::model::scope_t scope_; + common::model::access_t access_; std::string name_; std::string type_; }; diff --git a/src/class_diagram/model/class_member.cc b/src/class_diagram/model/class_member.cc index 360f76b0..8bf041e6 100644 --- a/src/class_diagram/model/class_member.cc +++ b/src/class_diagram/model/class_member.cc @@ -20,9 +20,9 @@ namespace clanguml::class_diagram::model { -class_member::class_member(common::model::scope_t scope, +class_member::class_member(common::model::access_t access, const std::string &name, const std::string &type) - : class_element{scope, name, type} + : class_element{access, name, type} { } diff --git a/src/class_diagram/model/class_member.h b/src/class_diagram/model/class_member.h index f339d4cb..39b29983 100644 --- a/src/class_diagram/model/class_member.h +++ b/src/class_diagram/model/class_member.h @@ -25,7 +25,7 @@ namespace clanguml::class_diagram::model { class class_member : public class_element { public: - class_member(common::model::scope_t scope, const std::string &name, + class_member(common::model::access_t access, const std::string &name, const std::string &type); bool is_relationship() const; diff --git a/src/class_diagram/model/class_method.cc b/src/class_diagram/model/class_method.cc index 38f44bfe..cef773cd 100644 --- a/src/class_diagram/model/class_method.cc +++ b/src/class_diagram/model/class_method.cc @@ -20,9 +20,9 @@ namespace clanguml::class_diagram::model { -class_method::class_method(common::model::scope_t scope, +class_method::class_method(common::model::access_t access, const std::string &name, const std::string &type) - : class_element{scope, name, type} + : class_element{access, name, type} { } diff --git a/src/class_diagram/model/class_method.h b/src/class_diagram/model/class_method.h index 024fbac7..f35ad492 100644 --- a/src/class_diagram/model/class_method.h +++ b/src/class_diagram/model/class_method.h @@ -27,7 +27,7 @@ namespace clanguml::class_diagram::model { class class_method : public class_element { public: - class_method(common::model::scope_t scope, const std::string &name, + class_method(common::model::access_t access, const std::string &name, const std::string &type); bool is_pure_virtual() const; diff --git a/src/class_diagram/model/diagram.cc b/src/class_diagram/model/diagram.cc index 1200e889..26ba79e8 100644 --- a/src/class_diagram/model/diagram.cc +++ b/src/class_diagram/model/diagram.cc @@ -36,6 +36,11 @@ const std::vector> diagram::enums() const return enums_; } +common::model::diagram_t diagram::type() const +{ + return common::model::diagram_t::kClass; +} + bool diagram::has_class(const class_ &c) const { return std::any_of(classes_.cbegin(), classes_.cend(), @@ -48,6 +53,18 @@ bool diagram::has_enum(const enum_ &e) const [&e](const auto &ee) { return ee.get().full_name() == e.full_name(); }); } +type_safe::optional_ref diagram::get_class( + const std::string &name) const +{ + for (const auto &c : classes_) { + if (c.get().full_name(false) == name) { + return {c}; + } + } + + return type_safe::nullopt; +} + void diagram::add_type_alias(std::unique_ptr &&ta) { LOG_DBG( @@ -107,6 +124,26 @@ void diagram::add_enum(std::unique_ptr &&e) LOG_DBG("Enum {} already in the model", e->name()); } +void diagram::get_parents( + std::unordered_set> &parents) const +{ + bool found_new = false; + for (const auto &parent : parents) { + for (const auto &pp : parent.get().parents()) { + const auto p = get_class(pp.name()); + if (p.has_value()) { + auto [it, found] = parents.emplace(p.value()); + if (found) + found_new = true; + } + } + } + + if (found_new) { + get_parents(parents); + } +} + std::string diagram::to_alias(const std::string &full_name) const { LOG_DBG("Looking for alias for {}", full_name); diff --git a/src/class_diagram/model/diagram.h b/src/class_diagram/model/diagram.h index 86f8acd7..cf372240 100644 --- a/src/class_diagram/model/diagram.h +++ b/src/class_diagram/model/diagram.h @@ -25,6 +25,7 @@ #include "type_alias.h" #include +#include #include namespace clanguml::class_diagram::model { @@ -40,6 +41,8 @@ public: diagram &operator=(const diagram &) = delete; diagram &operator=(diagram &&) = default; + common::model::diagram_t type() const override; + const std::vector> classes() const; const std::vector> enums() const; @@ -48,6 +51,9 @@ public: bool has_enum(const enum_ &e) const; + type_safe::optional_ref get_class( + const std::string &name) const; + void add_type_alias(std::unique_ptr &&ta); void add_class(std::unique_ptr &&c); @@ -58,6 +64,9 @@ public: std::string to_alias(const std::string &full_name) const; + void get_parents( + std::unordered_set> &parents) const; + friend void print_diagram_tree(const diagram &d, const int level); private: @@ -66,3 +75,18 @@ private: std::map> type_aliases_; }; } + +namespace std { + +template <> +struct hash< + type_safe::object_ref> { + std::size_t operator()(const type_safe::object_ref< + const clanguml::class_diagram::model::class_> &key) const + { + using clanguml::class_diagram::model::class_; + + return std::hash{}(key.get().full_name(false)); + } +}; +} diff --git a/src/class_diagram/visitor/translation_unit_context.cc b/src/class_diagram/visitor/translation_unit_context.cc index 0031d010..83655608 100644 --- a/src/class_diagram/visitor/translation_unit_context.cc +++ b/src/class_diagram/visitor/translation_unit_context.cc @@ -184,6 +184,12 @@ clanguml::class_diagram::model::diagram &translation_unit_context::diagram() return diagram_; } +clanguml::class_diagram::model::diagram & +translation_unit_context::diagram() const +{ + return diagram_; +} + void translation_unit_context::set_current_package( type_safe::optional_ref p) { diff --git a/src/class_diagram/visitor/translation_unit_context.h b/src/class_diagram/visitor/translation_unit_context.h index 714f7eae..62cb7293 100644 --- a/src/class_diagram/visitor/translation_unit_context.h +++ b/src/class_diagram/visitor/translation_unit_context.h @@ -74,6 +74,8 @@ public: clanguml::class_diagram::model::diagram &diagram(); + clanguml::class_diagram::model::diagram &diagram() const; + void set_current_package(type_safe::optional_ref p); type_safe::optional_ref get_current_package() const; diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index aea10efe..9320c680 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -46,28 +46,27 @@ using clanguml::class_diagram::model::type_alias; using clanguml::common::model::access_t; using clanguml::common::model::relationship; using clanguml::common::model::relationship_t; -using clanguml::common::model::scope_t; namespace detail { -scope_t cpp_access_specifier_to_scope( +access_t cpp_access_specifier_to_access( cppast::cpp_access_specifier_kind access_specifier) { - scope_t scope = scope_t::kPublic; + auto access = access_t::kPublic; switch (access_specifier) { case cppast::cpp_access_specifier_kind::cpp_public: - scope = scope_t::kPublic; + access = access_t::kPublic; break; case cppast::cpp_access_specifier_kind::cpp_private: - scope = scope_t::kPrivate; + access = access_t::kPrivate; break; case cppast::cpp_access_specifier_kind::cpp_protected: - scope = scope_t::kProtected; + access = access_t::kProtected; break; default: break; } - return scope; + return access; } } @@ -146,7 +145,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file) } } - if (ctx.config().should_include( + if (ctx.diagram().should_include( ctx.get_namespace(), cls.name())) process_class_declaration(cls); } @@ -157,7 +156,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file) auto &enm = static_cast(e); - if (ctx.config().should_include( + if (ctx.diagram().should_include( ctx.get_namespace(), enm.name())) process_enum_declaration(enm); } @@ -214,7 +213,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.diagram().should_include(tinst->get_namespace(), tinst->name())) ctx.diagram().add_class(std::move(tinst)); } } @@ -241,13 +240,13 @@ void translation_unit_visitor::process_namespace( auto usn = ctx.config().using_namespace(); - if (ctx.config().should_include_package(package_path)) { - auto p = std::make_unique(usn); - package_path = package_path.relative_to(usn); + auto p = std::make_unique(usn); + package_path = package_path.relative_to(usn); - p->set_name(e.name()); - p->set_namespace(package_parent); + p->set_name(e.name()); + p->set_namespace(package_parent); + if (ctx.diagram().should_include(*p)) { if (e.comment().has_value()) p->set_comment(e.comment().value()); @@ -397,7 +396,8 @@ void translation_unit_visitor::process_class_declaration( fmt::ptr(reinterpret_cast(&cls))); assert(c_ptr); - if (ctx.config().should_include(c.full_name(false))) + + if (ctx.diagram().should_include(c)) ctx.diagram().add_class(std::move(c_ptr)); } @@ -579,7 +579,8 @@ void translation_unit_visitor::process_class_bases( cx::util::ns(base.type(), ctx.entity_index())}; base_ns = base_ns | common::model::namespace_{base.name()}.name(); cp.set_name( - base_ns.relative_to(ctx.config().using_namespace()).to_string()); + // base_ns.relative_to(ctx.config().using_namespace()).to_string()); + base_ns.to_string()); cp.is_virtual(base.is_virtual()); switch (base.access_specifier()) { @@ -660,7 +661,7 @@ void translation_unit_visitor::process_class_children( child.scope_name() ? child.scope_name().value().name() : ""); - process_friend(fr, c); + process_friend(fr, c, last_access_specifier); } else if (cppast::is_friended(child)) { auto &fr = @@ -668,7 +669,7 @@ void translation_unit_visitor::process_class_children( LOG_DBG("Found friend template: {}", child.name()); - process_friend(fr, c); + process_friend(fr, c, last_access_specifier); } else { LOG_DBG("Found some other class child: {} ({})", child.name(), @@ -715,7 +716,7 @@ bool translation_unit_visitor::process_field_with_template_instantiation( relationship_type = relationship_t::kAggregation; relationship rr{relationship_type, tinst.full_name(), - detail::cpp_access_specifier_to_scope(as), mv.name()}; + detail::cpp_access_specifier_to_access(as), mv.name()}; rr.set_style(m.style_spec()); // Process field decorators @@ -729,7 +730,7 @@ bool translation_unit_visitor::process_field_with_template_instantiation( } } - if (ctx.config().should_include(tinst.get_namespace(), tinst.name())) { + if (ctx.diagram().should_include(tinst.get_namespace(), tinst.name())) { LOG_DBG("Adding field instantiation relationship {} {} {} : {}", rr.destination(), clanguml::common::model::to_string(rr.type()), c.full_name(), rr.label()); @@ -763,7 +764,7 @@ void translation_unit_visitor::process_field( type_name = "<>"; class_member m{ - detail::cpp_access_specifier_to_scope(as), mv.name(), type_name}; + detail::cpp_access_specifier_to_access(as), mv.name(), type_name}; if (mv.location().has_value()) { m.set_file(mv.location().value().file); @@ -814,7 +815,7 @@ void translation_unit_visitor::process_field( for (const auto &[type, relationship_type] : relationships) { if (relationship_type != relationship_t::kNone) { - relationship r{relationship_type, type, m.scope(), m.name()}; + relationship r{relationship_type, type, m.access(), m.name()}; r.set_style(m.style_spec()); auto [decorator_rtype, decorator_rmult] = m.get_relationship(); @@ -846,7 +847,7 @@ void translation_unit_visitor::process_anonymous_enum( for (const auto &ev : en) { if (ev.kind() == cppast::cpp_entity_kind::enum_value_t) { class_member m{ - detail::cpp_access_specifier_to_scope(as), ev.name(), "enum"}; + detail::cpp_access_specifier_to_access(as), ev.name(), "enum"}; c.add_member(std::move(m)); } } @@ -856,7 +857,7 @@ void translation_unit_visitor::process_static_field( const cppast::cpp_variable &mv, class_ &c, cppast::cpp_access_specifier_kind as) { - class_member m{detail::cpp_access_specifier_to_scope(as), mv.name(), + class_member m{detail::cpp_access_specifier_to_access(as), mv.name(), cppast::to_string(mv.type())}; if (mv.location().has_value()) { @@ -879,7 +880,7 @@ void translation_unit_visitor::process_method( const cppast::cpp_member_function &mf, class_ &c, cppast::cpp_access_specifier_kind as) { - class_method m{detail::cpp_access_specifier_to_scope(as), + class_method m{detail::cpp_access_specifier_to_access(as), util::trim(mf.name()), cppast::to_string(mf.return_type())}; m.is_pure_virtual(cppast::is_pure(mf.virtual_info())); m.is_virtual(cppast::is_virtual(mf.virtual_info())); @@ -921,8 +922,8 @@ void translation_unit_visitor::process_template_method( static_cast(mf.function()) .return_type()); - class_method m{ - detail::cpp_access_specifier_to_scope(as), util::trim(mf.name()), type}; + class_method m{detail::cpp_access_specifier_to_access(as), + util::trim(mf.name()), type}; m.is_pure_virtual(false); m.is_virtual(false); m.is_const(cppast::is_const( @@ -962,7 +963,7 @@ void translation_unit_visitor::process_static_method( const cppast::cpp_function &mf, class_ &c, cppast::cpp_access_specifier_kind as) { - class_method m{detail::cpp_access_specifier_to_scope(as), + class_method m{detail::cpp_access_specifier_to_access(as), util::trim(mf.name()), cppast::to_string(mf.return_type())}; m.is_pure_virtual(false); m.is_virtual(false); @@ -996,7 +997,7 @@ void translation_unit_visitor::process_constructor( const cppast::cpp_constructor &mf, class_ &c, cppast::cpp_access_specifier_kind as) { - class_method m{detail::cpp_access_specifier_to_scope(as), + class_method m{detail::cpp_access_specifier_to_access(as), util::trim(mf.name()), "void"}; m.is_pure_virtual(false); m.is_virtual(false); @@ -1028,7 +1029,7 @@ void translation_unit_visitor::process_destructor( const cppast::cpp_destructor &mf, class_ &c, cppast::cpp_access_specifier_kind as) { - class_method m{detail::cpp_access_specifier_to_scope(as), + class_method m{detail::cpp_access_specifier_to_access(as), util::trim(mf.name()), "void"}; m.is_pure_virtual(false); m.is_virtual(cppast::is_virtual(mf.virtual_info())); @@ -1100,7 +1101,8 @@ void translation_unit_visitor::process_function_parameter( relationship_t::kDependency); for (const auto &[type, relationship_type] : relationships) { - if (ctx.config().should_include(cx::util::split_ns(type)) && + auto [type_ns, type_name] = cx::util::split_ns(type); + if (ctx.diagram().should_include(type_ns, type_name) && (relationship_type != relationship_t::kNone) && (type != c.name_and_ns())) { relationship r{relationship_t::kDependency, type}; @@ -1165,7 +1167,7 @@ void translation_unit_visitor:: // arguments string } - if (!ctx.config().should_include(ctx.get_namespace(), + if (!ctx.diagram().should_include(ctx.get_namespace(), template_instantiation_type.primary_template() .get(ctx.entity_index())[0] .get() @@ -1202,7 +1204,7 @@ void translation_unit_visitor:: c.add_relationship(std::move(rr)); - if (ctx.config().should_include(c.full_name(false))) + if (ctx.diagram().should_include(c)) ctx.diagram().add_class(std::move(tinst_ptr)); } } @@ -1227,8 +1229,8 @@ void translation_unit_visitor::process_template_template_parameter( parent.add_template({"", t.name() + "<>"}); } -void translation_unit_visitor::process_friend( - const cppast::cpp_friend &f, class_ &parent) +void translation_unit_visitor::process_friend(const cppast::cpp_friend &f, + class_ &parent, cppast::cpp_access_specifier_kind as) { // Only process friends to other classes or class templates if (!f.entity() || @@ -1237,8 +1239,8 @@ void translation_unit_visitor::process_friend( cppast::cpp_entity_kind::class_template_t)) return; - relationship r{ - relationship_t::kFriendship, "", scope_t::kNone, "<>"}; + relationship r{relationship_t::kFriendship, "", + detail::cpp_access_specifier_to_access(as), "<>"}; if (f.comment().has_value()) r.add_decorators(decorators::parse(f.comment().value())); @@ -1249,7 +1251,7 @@ void translation_unit_visitor::process_friend( if (f.type()) { const auto [name_with_ns, name] = cx::util::split_ns(cppast::to_string(f.type().value())); - if (!ctx.config().should_include(name_with_ns, name)) + if (!ctx.diagram().should_include(name_with_ns, name)) return; LOG_DBG("Type friend declaration {}", name); @@ -1288,7 +1290,7 @@ void translation_unit_visitor::process_friend( name = cx::util::full_name(ctx.get_namespace(), f.entity().value()); } - if (!ctx.config().should_include(ctx.get_namespace(), name)) + if (!ctx.diagram().should_include(ctx.get_namespace(), name)) return; r.set_destination(name); @@ -1398,7 +1400,7 @@ bool translation_unit_visitor::find_relationships_in_template_instantiation( LOG_DBG("Failed to process template argument of std::vector at: {}", fn); } - else if (ctx.config().should_include(ns, name)) { + else if (ctx.diagram().should_include(ns, name)) { LOG_DBG("User defined template instantiation: {} | {}", cppast::to_string(t_), cppast::to_string(t_.canonical())); @@ -1509,7 +1511,7 @@ bool translation_unit_visitor::find_relationships_in_unexposed_template_params( type_with_namespace = common::model::namespace_{ct.type()}; } - if (ctx.config().should_include(type_with_namespace.value())) { + if (ctx.diagram().should_include(type_with_namespace.value().to_string())) { relationships.emplace_back(type_with_namespace.value().to_string(), relationship_t::kDependency); found = true; @@ -1704,7 +1706,7 @@ void translation_unit_visitor:: auto nested_tinst = build_template_instantiation(nested_template_parameter, - ctx.config().should_include(tinst_ns, tinst_name) + ctx.diagram().should_include(tinst_ns, tinst_name) ? std::make_optional(&tinst) : parent); @@ -1713,11 +1715,11 @@ void translation_unit_visitor:: auto nested_tinst_full_name = nested_tinst->full_name(); - if (ctx.config().should_include(fn_ns, fn_name)) { + if (ctx.diagram().should_include(fn_ns, fn_name)) { ctx.diagram().add_class(std::move(nested_tinst)); } - if (ctx.config().should_include(tinst_ns, tinst_name) + if (ctx.diagram().should_include(tinst_ns, tinst_name) // TODO: check why this breaks t00033: // && ctx.config().should_include( // cx::util::split_ns(tinst_dependency.destination())) @@ -1753,7 +1755,7 @@ void translation_unit_visitor:: "type {} -> {}", tinst.full_name(), tinst_dependency.destination()); - if (ctx.config().should_include(fn_ns, fn_name)) { + if (ctx.diagram().should_include(fn_ns, fn_name)) { tinst.add_relationship(std::move(tinst_dependency)); } else if (parent) { diff --git a/src/class_diagram/visitor/translation_unit_visitor.h b/src/class_diagram/visitor/translation_unit_visitor.h index 07bcc5e5..0a611b5b 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.h +++ b/src/class_diagram/visitor/translation_unit_visitor.h @@ -124,7 +124,8 @@ public: clanguml::class_diagram::model::class_ &parent); void process_friend(const cppast::cpp_friend &t, - clanguml::class_diagram::model::class_ &parent); + clanguml::class_diagram::model::class_ &parent, + cppast::cpp_access_specifier_kind as); void process_namespace(const cppast::cpp_entity &e, const cppast::cpp_namespace &ns_declaration); diff --git a/src/common/generators/plantuml/generator.cc b/src/common/generators/plantuml/generator.cc index 139a04b8..eea26a9c 100644 --- a/src/common/generators/plantuml/generator.cc +++ b/src/common/generators/plantuml/generator.cc @@ -42,14 +42,14 @@ std::string to_plantuml(relationship_t r, std::string style) } } -std::string to_plantuml(scope_t scope) +std::string to_plantuml(access_t scope) { switch (scope) { - case scope_t::kPublic: + case access_t::kPublic: return "+"; - case scope_t::kProtected: + case access_t::kProtected: return "#"; - case scope_t::kPrivate: + case access_t::kPrivate: return "-"; default: return ""; diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 29aebf4e..4d40604f 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -17,6 +17,7 @@ */ #pragma once +#include "common/model/diagram_filter.h" #include "config/config.h" #include "util/error.h" #include "util/util.h" @@ -29,13 +30,13 @@ namespace clanguml::common::generators::plantuml { +using clanguml::common::model::access_t; using clanguml::common::model::element; using clanguml::common::model::message_t; using clanguml::common::model::relationship_t; -using clanguml::common::model::scope_t; std::string to_plantuml(relationship_t r, std::string style); -std::string to_plantuml(scope_t scope); +std::string to_plantuml(access_t scope); std::string to_plantuml(message_t r); template class generator { @@ -224,17 +225,20 @@ void generator::generate_link( template -DiagramModel generate(const cppast::libclang_compilation_database &db, - const std::string &name, DiagramConfig &diagram, bool verbose = false) +std::unique_ptr generate( + const cppast::libclang_compilation_database &db, const std::string &name, + DiagramConfig &config, bool verbose = false) { LOG_INFO("Generating diagram {}.puml", name); - DiagramModel d; - d.set_name(name); + auto diagram = std::make_unique(); + diagram->set_name(name); + diagram->set_filter( + std::make_unique(*diagram, config)); // Get all translation units matching the glob from diagram // configuration std::vector translation_units{}; - for (const auto &g : diagram.glob()) { + for (const auto &g : config.glob()) { LOG_DBG("Processing glob: {}", g); const auto matches = glob::rglob(g); std::copy(matches.begin(), matches.end(), @@ -248,12 +252,14 @@ DiagramModel generate(const cppast::libclang_compilation_database &db, type_safe::ref(idx), std::move(logger)}; // Process all matching translation units - DiagramVisitor ctx(idx, d, diagram); + DiagramVisitor ctx(idx, *diagram, config); cppast::parse_files(parser, translation_units, db); for (auto &file : parser.files()) ctx(file); - return std::move(d); + diagram->set_complete(true); + + return std::move(diagram); } template void generator::init_context() diff --git a/src/common/model/diagram.cc b/src/common/model/diagram.cc index 1f4263f5..7330236c 100644 --- a/src/common/model/diagram.cc +++ b/src/common/model/diagram.cc @@ -18,10 +18,71 @@ #include "diagram.h" +#include "diagram_filter.h" +#include "namespace.h" + namespace clanguml::common::model { +diagram::diagram() = default; + +diagram::~diagram() = default; + +diagram::diagram(diagram &&) = default; + +diagram &diagram::operator=(diagram &&) = default; + std::string diagram::name() const { return name_; } void diagram::set_name(const std::string &name) { name_ = name; } +void diagram::set_filter(std::unique_ptr filter) +{ + filter_ = std::move(filter); +} + +void diagram::set_complete(bool complete) { complete_ = complete; } + +bool diagram::complete() const { return complete_; } + +bool diagram::should_include(const element &e) const +{ + if (filter_.get() == nullptr) + return true; + + return filter_->should_include(e); +} + +bool diagram::should_include(const std::string &name) const +{ + if (filter_.get() == nullptr) + return true; + + return filter_->should_include(name); +} + +bool diagram::should_include(const relationship_t r) const +{ + if (filter_.get() == nullptr) + return true; + + return filter_->should_include(r); +} + +bool diagram::should_include(const access_t s) const +{ + if (filter_.get() == nullptr) + return true; + + return filter_->should_include(s); +} + +bool diagram::should_include( + const namespace_ &ns, const std::string &name) const +{ + if (filter_.get() == nullptr) + return true; + + return filter_->should_include(ns, name); +} + } \ No newline at end of file diff --git a/src/common/model/diagram.h b/src/common/model/diagram.h index 3e4f95b0..71483f4d 100644 --- a/src/common/model/diagram.h +++ b/src/common/model/diagram.h @@ -17,18 +17,50 @@ */ #pragma once +#include "enums.h" + +#include #include namespace clanguml::common::model { +class diagram_filter; +class namespace_; +class element; +class relationship; + class diagram { public: - std::string name() const; + diagram(); + virtual ~diagram(); + + virtual diagram_t type() const = 0; + + diagram(const diagram &) = delete; + diagram(diagram &&); + diagram &operator=(const diagram &) = delete; + diagram &operator=(diagram &&); void set_name(const std::string &name); + std::string name() const; + + void set_filter(std::unique_ptr filter); + + void set_complete(bool complete); + bool complete() const; + + // TODO: refactor to a template method + bool should_include(const element &e) const; + bool should_include(const std::string &e) const; + bool should_include(const relationship r) const; + bool should_include(const relationship_t r) const; + bool should_include(const access_t s) const; + bool should_include(const namespace_ &ns, const std::string &name) const; private: std::string name_; + std::unique_ptr filter_; + bool complete_{false}; }; } diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc new file mode 100644 index 00000000..0d3d0d50 --- /dev/null +++ b/src/common/model/diagram_filter.cc @@ -0,0 +1,337 @@ +/** + * src/common/model/diagram_filter.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. + */ + +#include "diagram_filter.h" + +namespace clanguml::common::model { + +filter_visitor::filter_visitor(filter_t type) + : type_{type} +{ +} + +tvl::value_t filter_visitor::match( + const diagram &d, const common::model::element &e) const +{ + return {}; +} + +tvl::value_t filter_visitor::match( + const diagram &d, const common::model::relationship_t &r) const +{ + return {}; +} + +tvl::value_t filter_visitor::match( + const diagram &d, const common::model::access_t &a) const +{ + return {}; +} + +tvl::value_t filter_visitor::match( + const diagram &d, const common::model::namespace_ &ns) const +{ + return {}; +} + +bool filter_visitor::is_inclusive() const +{ + return type_ == filter_t::kInclusive; +} + +bool filter_visitor::is_exclusive() const +{ + return type_ == filter_t::kExclusive; +} + +filter_t filter_visitor::type() const { return type_; } + +anyof_filter::anyof_filter( + filter_t type, std::vector> filters) + : filter_visitor{type} + , filters_{std::move(filters)} +{ +} + +tvl::value_t anyof_filter::match( + const diagram &d, const common::model::element &e) const +{ + return tvl::any_of(filters_.begin(), filters_.end(), + [&d, &e](const auto &f) { return f->match(d, e); }); +} + +namespace_filter::namespace_filter( + filter_t type, std::vector namespaces) + : filter_visitor{type} + , namespaces_{namespaces} +{ +} + +tvl::value_t namespace_filter::match( + const diagram &d, const namespace_ &ns) const +{ + if (ns.is_empty()) + return {}; + + return tvl::any_of(namespaces_.begin(), namespaces_.end(), + [&ns](const auto &nsit) { return ns.starts_with(nsit) || ns == nsit; }); +} + +tvl::value_t namespace_filter::match(const diagram &d, const element &e) const +{ + if (dynamic_cast(&e) != nullptr) { + return tvl::any_of( + namespaces_.begin(), namespaces_.end(), [&e](const auto &nsit) { + return (e.get_namespace() | e.name()).starts_with(nsit) || + nsit.starts_with(e.get_namespace() | e.name()) || + (e.get_namespace() | e.name()) == nsit; + }); + } + else { + return tvl::any_of( + namespaces_.begin(), namespaces_.end(), [&e](const auto &nsit) { + return e.get_namespace().starts_with(nsit); + }); + } +} + +element_filter::element_filter(filter_t type, std::vector elements) + : filter_visitor{type} + , elements_{elements} +{ +} + +tvl::value_t element_filter::match(const diagram &d, const element &e) const +{ + return tvl::any_of(elements_.begin(), elements_.end(), + [&e](const auto &el) { return e.full_name(false) == el; }); +} + +subclass_filter::subclass_filter(filter_t type, std::vector roots) + : filter_visitor{type} + , roots_{roots} +{ +} + +tvl::value_t subclass_filter::match(const diagram &d, const element &e) const +{ + if (d.type() != diagram_t::kClass) + return {}; + + if (roots_.empty()) + return {}; + + if (!d.complete()) + return {}; + + const auto &cd = dynamic_cast(d); + + // First get all parents of element e + std::unordered_set< + type_safe::object_ref> + parents; + + const auto &fn = e.full_name(false); + auto class_ref = cd.get_class(fn); + + if (!class_ref.has_value()) + return false; + + parents.emplace(class_ref.value()); + + cd.get_parents(parents); + + // Now check if any of the parents matches the roots specified in the + // filter config + for (const auto &root : roots_) { + for (const auto &parent : parents) { + if (root == parent.get().full_name(false)) + return true; + } + } + + return false; +} + +relationship_filter::relationship_filter( + filter_t type, std::vector relationships) + : filter_visitor{type} + , relationships_{relationships} +{ +} + +tvl::value_t relationship_filter::match( + const diagram &d, const relationship_t &r) const +{ + return tvl::any_of(relationships_.begin(), relationships_.end(), + [&r](const auto &rel) { return r == rel; }); +} + +access_filter::access_filter(filter_t type, std::vector access) + : filter_visitor{type} + , access_{access} +{ +} + +tvl::value_t access_filter::match(const diagram &d, const access_t &a) const +{ + return tvl::any_of(access_.begin(), access_.end(), + [&a](const auto &access) { return a == access; }); +} + +context_filter::context_filter(filter_t type, std::vector context) + : filter_visitor{type} + , context_{context} +{ +} + +tvl::value_t context_filter::match(const diagram &d, const element &e) const +{ + if (d.type() != diagram_t::kClass) + return {}; + + if (!d.complete()) + return {}; + + return tvl::any_of(context_.begin(), context_.end(), + [&e, &d](const auto &context_root_name) { + const auto &context_root = + static_cast(d).get_class( + context_root_name); + + if (context_root.has_value()) { + // This is a direct match to the context root + if (context_root.value().full_name(false) == e.full_name(false)) + return true; + + // Return a positive match if the element e is in a direct + // relationship with any of the context_root's + for (const relationship &rel : + context_root.value().relationships()) { + if (rel.destination() == e.full_name(false)) + return true; + } + for (const relationship &rel : e.relationships()) { + if (rel.destination() == + context_root.value().full_name(false)) + return true; + } + + // Return a positive match if the context_root is a parent + // of the element + for (const class_diagram::model::class_parent &p : + context_root.value().parents()) { + if (p.name() == e.full_name(false)) + return true; + } + if (dynamic_cast(&e) != + nullptr) { + for (const class_diagram::model::class_parent &p : + static_cast(e) + .parents()) { + if (p.name() == context_root.value().full_name(false)) + return true; + } + } + } + + return false; + }); +} + +diagram_filter::diagram_filter( + const common::model::diagram &d, const config::diagram &c) + : diagram_{d} +{ + init_filters(c); +} + +void diagram_filter::add_inclusive_filter(std::unique_ptr fv) +{ + inclusive_.emplace_back(std::move(fv)); +} + +void diagram_filter::add_exclusive_filter(std::unique_ptr fv) +{ + exclusive_.emplace_back(std::move(fv)); +} + +bool diagram_filter::should_include( + namespace_ ns, const std::string &name) const +{ + if (should_include(ns)) { + element e{namespace_{}}; + e.set_name(name); + e.set_namespace(ns); + + return should_include(e); + } + + return false; +} + +void diagram_filter::init_filters(const config::diagram &c) +{ + // Process inclusive filters + if (c.include) { + inclusive_.emplace_back(std::make_unique( + filter_t::kInclusive, c.include().namespaces)); + inclusive_.emplace_back(std::make_unique( + filter_t::kInclusive, c.include().relationships)); + inclusive_.emplace_back(std::make_unique( + filter_t::kInclusive, c.include().access)); + + // Include any of these matches even if one them does not match + std::vector> element_filters; + element_filters.emplace_back(std::make_unique( + filter_t::kInclusive, c.include().elements)); + element_filters.emplace_back(std::make_unique( + filter_t::kInclusive, c.include().subclasses)); + element_filters.emplace_back(std::make_unique( + filter_t::kInclusive, c.include().context)); + + inclusive_.emplace_back(std::make_unique( + filter_t::kInclusive, std::move(element_filters))); + } + + // Process exclusive filters + if (c.exclude) { + exclusive_.emplace_back(std::make_unique( + filter_t::kExclusive, c.exclude().namespaces)); + exclusive_.emplace_back(std::make_unique( + filter_t::kExclusive, c.exclude().elements)); + exclusive_.emplace_back(std::make_unique( + filter_t::kExclusive, c.exclude().relationships)); + exclusive_.emplace_back(std::make_unique( + filter_t::kExclusive, c.exclude().access)); + exclusive_.emplace_back(std::make_unique( + filter_t::kExclusive, c.exclude().subclasses)); + exclusive_.emplace_back(std::make_unique( + filter_t::kExclusive, c.exclude().context)); + } +} + +template <> +bool diagram_filter::should_include(const std::string &name) const +{ + auto [ns, n] = cx::util::split_ns(name); + + return should_include(ns, n); +} + +} diff --git a/src/common/model/diagram_filter.h b/src/common/model/diagram_filter.h new file mode 100644 index 00000000..dfbc8886 --- /dev/null +++ b/src/common/model/diagram_filter.h @@ -0,0 +1,166 @@ +/** + * src/common/model/diagram_filter.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 "class_diagram/model/diagram.h" +#include "common/model/diagram.h" +#include "common/model/element.h" +#include "common/model/enums.h" +#include "common/model/namespace.h" +#include "config/config.h" +#include "cx/util.h" +#include "diagram.h" +#include "tvl.h" + +namespace clanguml::common::model { + +enum filter_t { kInclusive, kExclusive }; + +class filter_visitor { +public: + filter_visitor(filter_t type); + + virtual tvl::value_t match( + const diagram &d, const common::model::element &e) const; + + virtual tvl::value_t match( + const diagram &d, const common::model::relationship_t &r) const; + + virtual tvl::value_t match( + const diagram &d, const common::model::access_t &a) const; + + virtual tvl::value_t match( + const diagram &d, const common::model::namespace_ &ns) const; + + bool is_inclusive() const; + bool is_exclusive() const; + + filter_t type() const; + +private: + filter_t type_; +}; + +struct anyof_filter : public filter_visitor { + anyof_filter( + filter_t type, std::vector> filters); + + tvl::value_t match( + const diagram &d, const common::model::element &e) const override; + +private: + std::vector> filters_; +}; + +struct namespace_filter : public filter_visitor { + namespace_filter(filter_t type, std::vector namespaces); + + tvl::value_t match(const diagram &d, const namespace_ &ns) const override; + + tvl::value_t match(const diagram &d, const element &e) const override; + +private: + std::vector namespaces_; +}; + +struct element_filter : public filter_visitor { + element_filter(filter_t type, std::vector elements); + + tvl::value_t match(const diagram &d, const element &e) const override; + +private: + std::vector elements_; +}; + +struct subclass_filter : public filter_visitor { + subclass_filter(filter_t type, std::vector roots); + + tvl::value_t match(const diagram &d, const element &e) const override; + +private: + std::vector roots_; +}; + +struct relationship_filter : public filter_visitor { + relationship_filter( + filter_t type, std::vector relationships); + + tvl::value_t match( + const diagram &d, const relationship_t &r) const override; + +private: + std::vector relationships_; +}; + +struct access_filter : public filter_visitor { + access_filter(filter_t type, std::vector access); + + tvl::value_t match(const diagram &d, const access_t &a) const override; + +private: + std::vector access_; +}; + +struct context_filter : public filter_visitor { + context_filter(filter_t type, std::vector context); + + tvl::value_t match(const diagram &d, const element &r) const override; + +private: + std::vector context_; +}; + +class diagram_filter { +public: + diagram_filter(const common::model::diagram &d, const config::diagram &c); + + void add_inclusive_filter(std::unique_ptr fv); + + void add_exclusive_filter(std::unique_ptr fv); + + bool should_include(namespace_ ns, const std::string &name) const; + + template bool should_include(const T &e) const + { + auto exc = tvl::any_of(exclusive_.begin(), exclusive_.end(), + [this, &e](const auto &ex) { return ex->match(diagram_, e); }); + + if (tvl::is_true(exc)) + return false; + + auto inc = tvl::all_of(inclusive_.begin(), inclusive_.end(), + [this, &e](const auto &in) { return in->match(diagram_, e); }); + + if (tvl::is_undefined(inc) || tvl::is_true(inc)) + return true; + + return false; + } + +private: + void init_filters(const config::diagram &c); + + std::vector> inclusive_; + std::vector> exclusive_; + + const common::model::diagram &diagram_; +}; + +template <> +bool diagram_filter::should_include(const std::string &name) const; +} \ No newline at end of file diff --git a/src/common/model/element.h b/src/common/model/element.h index 3adeec0b..74173a89 100644 --- a/src/common/model/element.h +++ b/src/common/model/element.h @@ -59,7 +59,7 @@ public: return ns_.relative_to(using_namespace_); } - virtual std::string full_name(bool relative) const { return name(); } + virtual std::string full_name(bool relative) const { return name_and_ns(); } void set_using_namespaces(const namespace_ &un); diff --git a/src/common/model/enums.cc b/src/common/model/enums.cc index df734e6d..f1336fa6 100644 --- a/src/common/model/enums.cc +++ b/src/common/model/enums.cc @@ -49,22 +49,6 @@ std::string to_string(relationship_t r) } } -std::string to_string(scope_t s) -{ - switch (s) { - case scope_t::kPublic: - return "public"; - case scope_t::kProtected: - return "protected"; - case scope_t::kPrivate: - return "private"; - case scope_t::kNone: - return "none"; - default: - assert(false); - } -} - std::string to_string(access_t a) { switch (a) { diff --git a/src/common/model/enums.h b/src/common/model/enums.h index 2b553562..e102a67c 100644 --- a/src/common/model/enums.h +++ b/src/common/model/enums.h @@ -21,9 +21,9 @@ namespace clanguml::common::model { -enum class access_t { kPublic, kProtected, kPrivate }; +enum class diagram_t { kClass, kSequence, kPackage }; -enum class scope_t { kPublic, kProtected, kPrivate, kNone }; +enum class access_t { kPublic, kProtected, kPrivate }; enum class relationship_t { kNone, @@ -42,8 +42,6 @@ enum class message_t { kCall, kReturn }; std::string to_string(relationship_t r); -std::string to_string(scope_t r); - std::string to_string(access_t r); std::string to_string(message_t r); diff --git a/src/common/model/namespace.cc b/src/common/model/namespace.cc index ed25e50a..2e6c6012 100644 --- a/src/common/model/namespace.cc +++ b/src/common/model/namespace.cc @@ -140,7 +140,6 @@ const std::string &namespace_::operator[](const int index) const bool namespace_::starts_with(const namespace_ &right) const { - return util::starts_with(namespace_path_, right.namespace_path_); } diff --git a/src/common/model/relationship.cc b/src/common/model/relationship.cc index f384e40a..28b0d961 100644 --- a/src/common/model/relationship.cc +++ b/src/common/model/relationship.cc @@ -21,12 +21,12 @@ namespace clanguml::common::model { relationship::relationship(relationship_t type, const std::string &destination, - scope_t scope, const std::string &label, + access_t access, const std::string &label, const std::string &multiplicity_source, const std::string &multiplicity_destination) : type_{type} , destination_{destination} - , scope_{scope} + , access_{access} , label_{label} , multiplicity_source_{multiplicity_source} , multiplicity_destination_{multiplicity_destination} @@ -70,9 +70,9 @@ void relationship::set_label(const std::string &label) { label_ = label; } std::string relationship::label() const { return label_; } -void relationship::set_scope(scope_t scope) noexcept { scope_ = scope; } +void relationship::set_access(access_t access) noexcept { access_ = access; } -scope_t relationship::scope() const noexcept { return scope_; } +access_t relationship::access() const noexcept { return access_; } bool operator==(const relationship &l, const relationship &r) { diff --git a/src/common/model/relationship.h b/src/common/model/relationship.h index d75addf8..6a695528 100644 --- a/src/common/model/relationship.h +++ b/src/common/model/relationship.h @@ -28,7 +28,7 @@ class relationship : public common::model::decorated_element, public common::model::stylable_element { public: relationship(relationship_t type, const std::string &destination, - scope_t scope = scope_t::kNone, const std::string &label = "", + access_t access = access_t::kPublic, const std::string &label = "", const std::string &multiplicity_source = "", const std::string &multiplicity_destination = ""); @@ -50,8 +50,8 @@ public: void set_label(const std::string &label); std::string label() const; - void set_scope(scope_t scope) noexcept; - scope_t scope() const noexcept; + void set_access(access_t scope) noexcept; + access_t access() const noexcept; friend bool operator==(const relationship &l, const relationship &r); @@ -61,6 +61,6 @@ private: std::string multiplicity_source_; std::string multiplicity_destination_; std::string label_; - scope_t scope_{scope_t::kNone}; + access_t access_{access_t::kPublic}; }; } diff --git a/src/common/model/tvl.h b/src/common/model/tvl.h new file mode 100644 index 00000000..7889c789 --- /dev/null +++ b/src/common/model/tvl.h @@ -0,0 +1,74 @@ +/** + * src/class_diagram/model/tvl.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::tvl { + +using value_t = std::optional; + +inline bool is_true(const value_t &v) { return v.has_value() && v.value(); } + +inline bool is_false(const value_t &v) { return v.has_value() && !v.value(); } + +inline bool is_undefined(const value_t &v) { return !v.has_value(); } + +template +inline value_t all_of(InputIterator first, InputIterator last, Predicate pred) +{ + value_t res{}; + + for (InputIterator it = first; it != last; it++) { + value_t m = pred(*it); + if (m.has_value()) { + if (m.value() == true) { + res = true; + } + else { + res = false; + break; + } + } + } + + return res; +} + +template +inline value_t any_of(InputIterator first, InputIterator last, Predicate pred) +{ + value_t res{}; + + for (InputIterator it = first; it != last; it++) { + value_t m = pred(*it); + if (m.has_value()) { + if (m.value() == true) { + res = true; + break; + } + else { + res = false; + } + } + } + + return res; +} +}; \ No newline at end of file diff --git a/src/config/config.cc b/src/config/config.cc index 9e7d00dd..6084be63 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -108,134 +108,6 @@ void inheritable_diagram_options::inherit( git.override(parent.git); } -bool diagram::should_include_entities(const std::string &ent) -{ - for (const auto &ex : exclude().entity_types) { - if (ent == ex) - return false; - } - - if (include().entity_types.empty()) - return true; - - for (const auto &in : include().entity_types) { - if (ent == in) - return true; - } - - return false; -} - -bool diagram::should_include_relationship(const std::string &rel) -{ - for (const auto &ex : exclude().relationships) { - if (rel == ex) - return false; - } - - if (include().relationships.empty()) - return true; - - for (const auto &in : include().relationships) { - if (rel == in) - return true; - } - - return false; -} - -bool diagram::should_include( - 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 -{ - return should_include(ns | name); -} - -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.to_string()) == 0) { - LOG_DBG("Skipping from diagram: {}", name); - return false; - } - } - - // If no inclusive namespaces are provided, - // allow all - if (include().namespaces.empty()) - return true; - - for (const auto &in : include().namespaces) { - if (name.find(in.to_string()) == 0) - return true; - } - - LOG_DBG("Skipping from diagram: {}", name); - - 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.to_string()) == 0) { - LOG_DBG("Skipping from diagram: {}", name); - return false; - } - } - - // If no inclusive namespaces are provided, - // allow all - if (include().namespaces.empty()) - return true; - - for (const auto &in : include().namespaces) { - if (in.to_string().find(name) == 0 || name.find(in.to_string()) == 0) - return true; - } - - LOG_DBG("Skipping from diagram: {}", name); - - return false; -} - -bool diagram::should_include(const clanguml::common::model::scope_t scope) const -{ - for (const auto &s : exclude().scopes) { - if (s == scope) - return false; - } - - if (include().scopes.empty()) - return true; - - for (const auto &s : include().scopes) { - if (s == scope) - return true; - } - - return false; -} - diagram_type class_diagram::type() const { return diagram_type::class_diagram; } bool class_diagram::has_class(std::string clazz) @@ -279,7 +151,8 @@ template <> void append_value(plantuml &l, const plantuml &r) } namespace YAML { -using clanguml::common::model::scope_t; +using clanguml::common::model::access_t; +using clanguml::common::model::relationship_t; using clanguml::config::class_diagram; using clanguml::config::config; using clanguml::config::filter; @@ -361,15 +234,65 @@ std::shared_ptr parse_diagram_config(const Node &d) return {}; } -template <> struct convert { - static bool decode(const Node &node, scope_t &rhs) +// +// config access_t decoder +// +template <> struct convert { + static bool decode(const Node &node, access_t &rhs) { if (node.as() == "public") - rhs = scope_t::kPublic; + rhs = access_t::kPublic; else if (node.as() == "protected") - rhs = scope_t::kProtected; + rhs = access_t::kProtected; else if (node.as() == "private") - rhs = scope_t::kPrivate; + rhs = access_t::kPrivate; + else + return false; + + return true; + } +}; + +// +// config relationship_t decoder +// +template <> struct convert { + static bool decode(const Node &node, relationship_t &rhs) + { + assert(node.Type() == NodeType::Scalar); + + auto relationship_name = node.as(); + if (relationship_name == "extension" || + relationship_name == "inheritance") { + rhs = relationship_t::kExtension; + } + else if (relationship_name == "composition") { + rhs = relationship_t::kComposition; + } + else if (relationship_name == "aggregation") { + rhs = relationship_t::kAggregation; + } + else if (relationship_name == "containment") { + rhs = relationship_t::kContainment; + } + else if (relationship_name == "ownership") { + rhs = relationship_t::kOwnership; + } + else if (relationship_name == "association") { + rhs = relationship_t::kAssociation; + } + else if (relationship_name == "instantiation") { + rhs = relationship_t::kInstantiation; + } + else if (relationship_name == "friendship") { + rhs = relationship_t::kFriendship; + } + else if (relationship_name == "dependency") { + rhs = relationship_t::kDependency; + } + else if (relationship_name == "none") { + rhs = relationship_t::kNone; + } else return false; @@ -445,12 +368,17 @@ template <> struct convert { rhs.relationships = node["relationships"].as(); - if (node["entity_types"]) - rhs.entity_types = - node["entity_types"].as(); + if (node["elements"]) + rhs.elements = node["elements"].as(); - if (node["scopes"]) - rhs.scopes = node["scopes"].as(); + if (node["access"]) + rhs.access = node["access"].as(); + + if (node["subclasses"]) + rhs.subclasses = node["subclasses"].as(); + + if (node["context"]) + rhs.context = node["context"].as(); return true; } diff --git a/src/config/config.h b/src/config/config.h index 3ebabf55..11db75fe 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -48,21 +48,23 @@ struct plantuml { struct filter { std::vector namespaces; - // Valid values are: - // - inheritance - // - dependency - // - instantiation - std::vector relationships; + std::vector elements; // E.g.: - // - classes - // - enums - std::vector entity_types; + // - inheritance/extension + // - dependency + // - instantiation + std::vector relationships; // E.g.: // - public + // - protected // - private - std::vector scopes; + std::vector access; + + std::vector subclasses; + + std::vector context; }; enum class hint_t { up, down, left, right }; @@ -111,26 +113,6 @@ struct diagram : public inheritable_diagram_options { virtual diagram_type type() const = 0; - bool should_include_entities(const std::string &ent); - - bool should_include_relationship(const std::string &rel); - - bool should_include_package(const std::string &name) const; - - bool should_include_package(const common::model::namespace_ &path) const; - - bool should_include( - const std::pair &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; - std::string name; }; diff --git a/src/cx/util.cc b/src/cx/util.cc index f43859a0..77520069 100644 --- a/src/cx/util.cc +++ b/src/cx/util.cc @@ -236,7 +236,7 @@ std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx) static_cast(t) .primary_template(); if (!primary_template.is_overloaded()) { - LOG_WARN( + LOG_DBG( "Cannot establish namespace for ", cppast::to_string(t)); return ""; } diff --git a/src/main.cc b/src/main.cc index b1ca2acc..d7a4d1c8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -152,7 +152,7 @@ void generate_diagram(const std::string &od, const std::string &name, dynamic_cast(*diagram), verbose); ofs << clanguml::class_diagram::generators::plantuml::generator( - dynamic_cast(*diagram), model); + dynamic_cast(*diagram), *model); } else if (diagram->type() == diagram_type::sequence_diagram) { using diagram_config = sequence_diagram; @@ -167,7 +167,7 @@ void generate_diagram(const std::string &od, const std::string &name, ofs << clanguml::sequence_diagram::generators::plantuml::generator( dynamic_cast(*diagram), - model); + *model); } else if (diagram->type() == diagram_type::package_diagram) { using diagram_config = package_diagram; @@ -181,7 +181,7 @@ void generate_diagram(const std::string &od, const std::string &name, dynamic_cast(*diagram), verbose); ofs << clanguml::package_diagram::generators::plantuml::generator( - dynamic_cast(*diagram), model); + dynamic_cast(*diagram), *model); } LOG_INFO("Written {} diagram to {}", name, path.string()); diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index cebe62d4..f03a5be7 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -35,7 +35,7 @@ void generator::generate_relationships( const auto &uns = m_config.using_namespace(); // Generate this packages relationship - if (m_config.should_include_relationship("dependency")) { + if (m_model.should_include(relationship_t::kDependency)) { for (const auto &r : p.relationships()) { std::stringstream relstr; try { diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.h b/src/package_diagram/generators/plantuml/package_diagram_generator.h index 075bcef0..bc416afa 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.h +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.h @@ -46,9 +46,9 @@ template using common_generator = clanguml::common::generators::plantuml::generator; +using clanguml::common::model::access_t; using clanguml::common::model::package; using clanguml::common::model::relationship_t; -using clanguml::common::model::scope_t; using namespace clanguml::util; class generator : public common_generator { diff --git a/src/package_diagram/model/diagram.cc b/src/package_diagram/model/diagram.cc index 1fb2c1c6..f8835711 100644 --- a/src/package_diagram/model/diagram.cc +++ b/src/package_diagram/model/diagram.cc @@ -23,6 +23,11 @@ namespace clanguml::package_diagram::model { +common::model::diagram_t diagram::type() const +{ + return common::model::diagram_t::kPackage; +} + std::string diagram::to_alias(const std::string &full_name) const { LOG_DBG("Looking for alias for {}", full_name); diff --git a/src/package_diagram/model/diagram.h b/src/package_diagram/model/diagram.h index ba092552..f84fd1ad 100644 --- a/src/package_diagram/model/diagram.h +++ b/src/package_diagram/model/diagram.h @@ -38,6 +38,8 @@ public: diagram &operator=(const diagram &) = delete; diagram &operator=(diagram &&) = default; + common::model::diagram_t type() const override; + std::string to_alias(const std::string &full_name) const; }; } diff --git a/src/package_diagram/visitor/translation_unit_visitor.cc b/src/package_diagram/visitor/translation_unit_visitor.cc index ee15c3b7..b0632fc9 100644 --- a/src/package_diagram/visitor/translation_unit_visitor.cc +++ b/src/package_diagram/visitor/translation_unit_visitor.cc @@ -42,29 +42,28 @@ using clanguml::common::model::access_t; using clanguml::common::model::package; using clanguml::common::model::relationship; using clanguml::common::model::relationship_t; -using clanguml::common::model::scope_t; using clanguml::package_diagram::model::diagram; namespace detail { -scope_t cpp_access_specifier_to_scope( +access_t cpp_access_specifier_to_access( cppast::cpp_access_specifier_kind access_specifier) { - scope_t scope = scope_t::kPublic; + access_t access = access_t::kPublic; switch (access_specifier) { case cppast::cpp_access_specifier_kind::cpp_public: - scope = scope_t::kPublic; + access = access_t::kPublic; break; case cppast::cpp_access_specifier_kind::cpp_private: - scope = scope_t::kPrivate; + access = access_t::kPrivate; break; case cppast::cpp_access_specifier_kind::cpp_protected: - scope = scope_t::kProtected; + access = access_t::kProtected; break; default: break; } - return scope; + return access; } } @@ -95,18 +94,18 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file) auto package_path = package_parent | e.name(); auto usn = ctx.config().using_namespace(); - if (ctx.config().should_include_package(package_path)) { - auto p = std::make_unique(usn); - package_path = package_path.relative_to(usn); + auto p = std::make_unique(usn); + package_path = package_path.relative_to(usn); - if (e.location().has_value()) { - p->set_file(e.location().value().file); - p->set_line(e.location().value().line); - } + if (e.location().has_value()) { + p->set_file(e.location().value().file); + p->set_line(e.location().value().line); + } - p->set_name(e.name()); - p->set_namespace(package_parent); + p->set_name(e.name()); + p->set_namespace(package_parent); + if (ctx.diagram().should_include(*p)) { if (ns_declaration.comment().has_value()) p->add_decorators(decorators::parse( ns_declaration.comment().value())); @@ -465,7 +464,7 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, found = find_relationships(args[0u].type().value(), relationships, relationship_t::kDependency); } - else if (ctx.config().should_include(t_ns, t_name)) { + else if (ctx.diagram().should_include(t_ns, t_name)) { LOG_DBG("User defined template instantiation: {} | {}", cppast::to_string(t_), cppast::to_string(t_.canonical())); diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index b83869ce..779322ae 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -18,17 +18,16 @@ #include "diagram.h" -#include -#include -#include - #include #include -#include -#include namespace clanguml::sequence_diagram::model { +common::model::diagram_t diagram::type() const +{ + return common::model::diagram_t::kSequence; +} + std::string diagram::to_alias(const std::string &full_name) const { return full_name; diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index 50b4eede..c846fdd2 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -34,6 +34,8 @@ public: diagram &operator=(const diagram &) = delete; diagram &operator=(diagram &&) = default; + common::model::diagram_t type() const override; + std::string to_alias(const std::string &full_name) const; bool started{false}; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index e999fdd4..001de746 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -81,7 +81,7 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e) .value(); m.from = cx::util::ns(caller) + "::" + caller.name(); - if (!ctx.config().should_include( + if (!ctx.diagram().should_include( common::model::namespace_{cx::util::ns(caller)}, caller.name())) continue; @@ -98,7 +98,7 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e) if (callee.kind() == cpp_entity_kind::function_t) m.to += "()"; - if (!ctx.config().should_include( + if (!ctx.diagram().should_include( common::model::namespace_{cx::util::ns(callee)}, callee.name())) continue; diff --git a/tests/t00002/test_case.h b/tests/t00002/test_case.h index 2b7856bf..fd3995bb 100644 --- a/tests/t00002/test_case.h +++ b/tests/t00002/test_case.h @@ -31,14 +31,14 @@ TEST_CASE("t00002", "[test-case][class]") REQUIRE(diagram->exclude().namespaces.size() == 0); - REQUIRE(diagram->should_include({"clanguml", "t00002"}, "A")); - REQUIRE(!diagram->should_include({"std"}, "vector")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00002_class"); + REQUIRE(model->name() == "t00002_class"); - auto puml = generate_class_puml(diagram, model); + REQUIRE(model->should_include({"clanguml", "t00002"}, "A")); + REQUIRE(!model->should_include({"std"}, "vector")); + + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00003/test_case.h b/tests/t00003/test_case.h index d5309310..23ad9731 100644 --- a/tests/t00003/test_case.h +++ b/tests/t00003/test_case.h @@ -28,13 +28,12 @@ TEST_CASE("t00003", "[test-case][class]") REQUIRE(diagram->exclude().namespaces.size() == 0); - REQUIRE(diagram->should_include("clanguml::t00003::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00003_class"); + REQUIRE(model->name() == "t00003_class"); + REQUIRE(model->should_include(std::string("clanguml::t00003::A"))); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00004/test_case.h b/tests/t00004/test_case.h index daafd155..6f224ebf 100644 --- a/tests/t00004/test_case.h +++ b/tests/t00004/test_case.h @@ -27,15 +27,15 @@ TEST_CASE("t00004", "[test-case][class]") REQUIRE(diagram->include().namespaces.size() == 1); REQUIRE(diagram->exclude().namespaces.size() == 0); - REQUIRE(diagram->should_include("clanguml::t00004::A")); - REQUIRE(diagram->should_include("clanguml::t00004::A::AA")); - REQUIRE(diagram->should_include("clanguml::t00004::A:::AAA")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00004_class"); + REQUIRE(model->name() == "t00004_class"); + REQUIRE(!model->should_include("std::vector")); + REQUIRE(model->should_include("clanguml::t00004::A")); + REQUIRE(model->should_include("clanguml::t00004::A::AA")); + REQUIRE(model->should_include("clanguml::t00004::A:::AAA")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00005/test_case.h b/tests/t00005/test_case.h index b1b9a6da..aa4f1753 100644 --- a/tests/t00005/test_case.h +++ b/tests/t00005/test_case.h @@ -24,16 +24,15 @@ TEST_CASE("t00005", "[test-case][class]") REQUIRE(diagram->name == "t00005_class"); - REQUIRE(diagram->should_include("clanguml::t00005::A")); - REQUIRE(diagram->should_include("clanguml::t00005::B")); - REQUIRE(diagram->should_include("clanguml::t00005::C")); - REQUIRE(diagram->should_include("clanguml::t00005::D")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00005_class"); + REQUIRE(model->name() == "t00005_class"); + REQUIRE(model->should_include("clanguml::t00005::A")); + REQUIRE(model->should_include("clanguml::t00005::B")); + REQUIRE(model->should_include("clanguml::t00005::C")); + REQUIRE(model->should_include("clanguml::t00005::D")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00006/test_case.h b/tests/t00006/test_case.h index fa6d7b4d..9037f669 100644 --- a/tests/t00006/test_case.h +++ b/tests/t00006/test_case.h @@ -24,17 +24,17 @@ TEST_CASE("t00006", "[test-case][class]") REQUIRE(diagram->name == "t00006_class"); - REQUIRE(diagram->should_include("clanguml::t00006::A")); - REQUIRE(diagram->should_include("clanguml::t00006::B")); - REQUIRE(diagram->should_include("clanguml::t00006::C")); - REQUIRE(diagram->should_include("clanguml::t00006::D")); - REQUIRE(diagram->should_include("clanguml::t00006::E")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00006_class"); + REQUIRE(model->name() == "t00006_class"); - auto puml = generate_class_puml(diagram, model); + REQUIRE(model->should_include("clanguml::t00006::A")); + REQUIRE(model->should_include("clanguml::t00006::B")); + REQUIRE(model->should_include("clanguml::t00006::C")); + REQUIRE(model->should_include("clanguml::t00006::D")); + REQUIRE(model->should_include("clanguml::t00006::E")); + + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00007/test_case.h b/tests/t00007/test_case.h index e3f8ce87..af0c02a0 100644 --- a/tests/t00007/test_case.h +++ b/tests/t00007/test_case.h @@ -24,17 +24,11 @@ TEST_CASE("t00007", "[test-case][class]") REQUIRE(diagram->name == "t00007_class"); - REQUIRE(diagram->should_include("clanguml::t00007::A")); - REQUIRE(diagram->should_include("clanguml::t00007::B")); - REQUIRE(diagram->should_include("clanguml::t00007::C")); - REQUIRE(diagram->should_include("clanguml::t00007::D")); - REQUIRE(diagram->should_include("clanguml::t00007::E")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00007_class"); + REQUIRE(model->name() == "t00007_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00008/test_case.h b/tests/t00008/test_case.h index b2361adc..ce30cc75 100644 --- a/tests/t00008/test_case.h +++ b/tests/t00008/test_case.h @@ -24,14 +24,11 @@ TEST_CASE("t00008", "[test-case][class]") REQUIRE(diagram->name == "t00008_class"); - REQUIRE(diagram->should_include("clanguml::t00008::A")); - REQUIRE(diagram->should_include("clanguml::t00008::B")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00008_class"); + REQUIRE(model->name() == "t00008_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00009/test_case.h b/tests/t00009/test_case.h index b63c7e87..4faedca7 100644 --- a/tests/t00009/test_case.h +++ b/tests/t00009/test_case.h @@ -24,14 +24,11 @@ TEST_CASE("t00009", "[test-case][class]") REQUIRE(diagram->name == "t00009_class"); - REQUIRE(diagram->should_include("clanguml::t00009::A")); - REQUIRE(diagram->should_include("clanguml::t00009::B")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00009_class"); + REQUIRE(model->name() == "t00009_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00010/test_case.h b/tests/t00010/test_case.h index 22754c08..19dc49f1 100644 --- a/tests/t00010/test_case.h +++ b/tests/t00010/test_case.h @@ -24,14 +24,11 @@ TEST_CASE("t00010", "[test-case][class]") REQUIRE(diagram->name == "t00010_class"); - REQUIRE(diagram->should_include("clanguml::t00010::A")); - REQUIRE(diagram->should_include("clanguml::t00010::B")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00010_class"); + REQUIRE(model->name() == "t00010_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00011/test_case.h b/tests/t00011/test_case.h index 8fb39319..da15bf51 100644 --- a/tests/t00011/test_case.h +++ b/tests/t00011/test_case.h @@ -24,14 +24,11 @@ TEST_CASE("t00011", "[test-case][class]") REQUIRE(diagram->name == "t00011_class"); - REQUIRE(diagram->should_include("clanguml::t00011::A")); - REQUIRE(diagram->should_include("clanguml::t00011::B")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00011_class"); + REQUIRE(model->name() == "t00011_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); @@ -40,7 +37,7 @@ TEST_CASE("t00011", "[test-case][class]") REQUIRE_THAT(puml, IsClass(_A("B"))); REQUIRE_THAT(puml, IsClass(_A("D"))); - REQUIRE_THAT(puml, IsFriend(_A("A"), _A("B"))); + REQUIRE_THAT(puml, IsFriend(_A("A"), _A("B"))); // REQUIRE_THAT(puml, IsFriend(_A("A"), _A("D"))); save_puml( diff --git a/tests/t00012/test_case.h b/tests/t00012/test_case.h index 2f8e2057..1a8dd1cd 100644 --- a/tests/t00012/test_case.h +++ b/tests/t00012/test_case.h @@ -24,14 +24,11 @@ TEST_CASE("t00012", "[test-case][class]") REQUIRE(diagram->name == "t00012_class"); - REQUIRE(diagram->should_include("clanguml::t00012::A")); - REQUIRE(diagram->should_include("clanguml::t00012::B")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00012_class"); + REQUIRE(model->name() == "t00012_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00013/test_case.h b/tests/t00013/test_case.h index ca91b368..5bcf89c4 100644 --- a/tests/t00013/test_case.h +++ b/tests/t00013/test_case.h @@ -24,15 +24,14 @@ TEST_CASE("t00013", "[test-case][class]") REQUIRE(diagram->name == "t00013_class"); - REQUIRE(diagram->should_include("clanguml::t00013::A")); - REQUIRE(diagram->should_include("clanguml::t00013::B")); - REQUIRE(diagram->should_include("ABCD::F")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00013_class"); + REQUIRE(model->name() == "t00013_class"); + REQUIRE(model->should_include("clanguml::t00013::A")); + REQUIRE(model->should_include("clanguml::t00013::B")); + REQUIRE(model->should_include("ABCD::F")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00014/test_case.h b/tests/t00014/test_case.h index ec4e5cd7..70a414af 100644 --- a/tests/t00014/test_case.h +++ b/tests/t00014/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00014", "[test-case][class]") REQUIRE(diagram->name == "t00014_class"); - REQUIRE(diagram->should_include("clanguml::t00014::S")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00014_class"); + REQUIRE(model->name() == "t00014_class"); + REQUIRE(model->should_include("clanguml::t00014::B")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00015/test_case.h b/tests/t00015/test_case.h index 5ac0dbd3..91a9d094 100644 --- a/tests/t00015/test_case.h +++ b/tests/t00015/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00015", "[test-case][class]") REQUIRE(diagram->name == "t00015_class"); - REQUIRE(diagram->should_include("clanguml::t00015::ns1::ns2::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00015_class"); + REQUIRE(model->name() == "t00015_class"); + REQUIRE(model->should_include("clanguml::t00015::ns1::ns2::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00016/test_case.h b/tests/t00016/test_case.h index 21232329..7efc05d8 100644 --- a/tests/t00016/test_case.h +++ b/tests/t00016/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00016", "[test-case][class]") REQUIRE(diagram->name == "t00016_class"); - REQUIRE(diagram->should_include("clanguml::t00016::is_numeric")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00016_class"); + REQUIRE(model->name() == "t00016_class"); + REQUIRE(model->should_include("clanguml::t00016::is_numeric")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00017/test_case.h b/tests/t00017/test_case.h index 2d5ecb47..147bae53 100644 --- a/tests/t00017/test_case.h +++ b/tests/t00017/test_case.h @@ -24,16 +24,11 @@ TEST_CASE("t00017", "[test-case][class]") REQUIRE(diagram->name == "t00017_class"); - REQUIRE(diagram->should_include("clanguml::t00017::A")); - REQUIRE(diagram->should_include("clanguml::t00017::B")); - REQUIRE(diagram->should_include("clanguml::t00017::C")); - REQUIRE(diagram->should_include("clanguml::t00017::D")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00017_class"); + REQUIRE(model->name() == "t00017_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00018/test_case.h b/tests/t00018/test_case.h index 05e065d2..c1b54842 100644 --- a/tests/t00018/test_case.h +++ b/tests/t00018/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00018", "[test-case][class]") REQUIRE(diagram->name == "t00018_class"); - REQUIRE(diagram->should_include("clanguml::t00018::widget")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00018_class"); + REQUIRE(model->name() == "t00018_class"); + REQUIRE(model->should_include("clanguml::t00018::widget")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00019/test_case.h b/tests/t00019/test_case.h index fc9328b0..cddbdb28 100644 --- a/tests/t00019/test_case.h +++ b/tests/t00019/test_case.h @@ -24,16 +24,11 @@ TEST_CASE("t00019", "[test-case][class]") REQUIRE(diagram->name == "t00019_class"); - REQUIRE(diagram->should_include("clanguml::t00019::Layer1")); - REQUIRE(diagram->should_include("clanguml::t00019::Layer2")); - REQUIRE(diagram->should_include("clanguml::t00019::Layer3")); - REQUIRE(diagram->should_include("clanguml::t00019::Base")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00019_class"); + REQUIRE(model->name() == "t00019_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00020/test_case.h b/tests/t00020/test_case.h index 8a15d02b..8ee87691 100644 --- a/tests/t00020/test_case.h +++ b/tests/t00020/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00020", "[test-case][class]") REQUIRE(diagram->name == "t00020_class"); - REQUIRE(diagram->should_include("clanguml::t00020::ProductA")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00020_class"); + REQUIRE(model->name() == "t00020_class"); + REQUIRE(model->should_include("clanguml::t00020::ProductA")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00021/test_case.h b/tests/t00021/test_case.h index f956b6df..fafa3b82 100644 --- a/tests/t00021/test_case.h +++ b/tests/t00021/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00021", "[test-case][class]") REQUIRE(diagram->name == "t00021_class"); - REQUIRE(diagram->should_include("clanguml::t00021::Visitor")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00021_class"); + REQUIRE(model->name() == "t00021_class"); + REQUIRE(model->should_include("clanguml::t00021::Visitor")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00022/test_case.h b/tests/t00022/test_case.h index 3585d0ea..426894fb 100644 --- a/tests/t00022/test_case.h +++ b/tests/t00022/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00022", "[test-case][class]") REQUIRE(diagram->name == "t00022_class"); - REQUIRE(diagram->should_include("clanguml::t00022::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00022_class"); + REQUIRE(model->name() == "t00022_class"); + REQUIRE(model->should_include("clanguml::t00022::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00023/test_case.h b/tests/t00023/test_case.h index 90c381a5..dffcbcd9 100644 --- a/tests/t00023/test_case.h +++ b/tests/t00023/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00023", "[test-case][class]") REQUIRE(diagram->name == "t00023_class"); - REQUIRE(diagram->should_include("clanguml::t00023::Visitor")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00023_class"); + REQUIRE(model->name() == "t00023_class"); + REQUIRE(model->should_include("clanguml::t00023::Visitor")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00024/test_case.h b/tests/t00024/test_case.h index 1a9b5fa7..3b1acd59 100644 --- a/tests/t00024/test_case.h +++ b/tests/t00024/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00024", "[test-case][class]") REQUIRE(diagram->name == "t00024_class"); - REQUIRE(diagram->should_include("clanguml::t00024::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00024_class"); + REQUIRE(model->name() == "t00024_class"); + REQUIRE(model->should_include("clanguml::t00024::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00025/test_case.h b/tests/t00025/test_case.h index f37bf07b..078af9f2 100644 --- a/tests/t00025/test_case.h +++ b/tests/t00025/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00025", "[test-case][class]") REQUIRE(diagram->name == "t00025_class"); - REQUIRE(diagram->should_include("clanguml::t00025::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00025_class"); + REQUIRE(model->name() == "t00025_class"); + REQUIRE(model->should_include("clanguml::t00025::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00026/test_case.h b/tests/t00026/test_case.h index d7509334..9e4ab933 100644 --- a/tests/t00026/test_case.h +++ b/tests/t00026/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00026", "[test-case][class]") REQUIRE(diagram->name == "t00026_class"); - REQUIRE(diagram->should_include("clanguml::t00026::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00026_class"); + REQUIRE(model->name() == "t00026_class"); + REQUIRE(model->should_include("clanguml::t00026::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00027/test_case.h b/tests/t00027/test_case.h index c9fe40f5..f073b50b 100644 --- a/tests/t00027/test_case.h +++ b/tests/t00027/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00027", "[test-case][class]") REQUIRE(diagram->name == "t00027_class"); - REQUIRE(diagram->should_include("clanguml::t00027::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00027_class"); + REQUIRE(model->name() == "t00027_class"); + REQUIRE(model->should_include("clanguml::t00027::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00028/test_case.h b/tests/t00028/test_case.h index 89ef3fbb..9cb64281 100644 --- a/tests/t00028/test_case.h +++ b/tests/t00028/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00028", "[test-case][class]") REQUIRE(diagram->name == "t00028_class"); - REQUIRE(diagram->should_include("clanguml::t00028::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00028_class"); + REQUIRE(model->name() == "t00028_class"); + REQUIRE(model->should_include("clanguml::t00028::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00029/test_case.h b/tests/t00029/test_case.h index f4e02f56..7ba0d045 100644 --- a/tests/t00029/test_case.h +++ b/tests/t00029/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00029", "[test-case][class]") REQUIRE(diagram->name == "t00029_class"); - REQUIRE(diagram->should_include("clanguml::t00029::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00029_class"); + REQUIRE(model->name() == "t00029_class"); + REQUIRE(model->should_include("clanguml::t00029::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00030/test_case.h b/tests/t00030/test_case.h index 87aacb9b..76f7b362 100644 --- a/tests/t00030/test_case.h +++ b/tests/t00030/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00030", "[test-case][class]") REQUIRE(diagram->name == "t00030_class"); - REQUIRE(diagram->should_include("clanguml::t00030::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00030_class"); + REQUIRE(model->name() == "t00030_class"); + REQUIRE(model->should_include("clanguml::t00030::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00031/test_case.h b/tests/t00031/test_case.h index 25a6488e..338c1b90 100644 --- a/tests/t00031/test_case.h +++ b/tests/t00031/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00031", "[test-case][class]") REQUIRE(diagram->name == "t00031_class"); - REQUIRE(diagram->should_include("clanguml::t00031::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00031_class"); + REQUIRE(model->name() == "t00031_class"); + REQUIRE(model->should_include("clanguml::t00031::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00032/test_case.h b/tests/t00032/test_case.h index fc6b3abc..28baa3de 100644 --- a/tests/t00032/test_case.h +++ b/tests/t00032/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00032", "[test-case][class]") REQUIRE(diagram->name == "t00032_class"); - REQUIRE(diagram->should_include("clanguml::t00032::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00032_class"); + REQUIRE(model->name() == "t00032_class"); + REQUIRE(model->should_include("clanguml::t00032::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00033/test_case.h b/tests/t00033/test_case.h index 35025cc4..f65c1c8d 100644 --- a/tests/t00033/test_case.h +++ b/tests/t00033/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00033", "[test-case][class]") REQUIRE(diagram->name == "t00033_class"); - REQUIRE(diagram->should_include("clanguml::t00033::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00033_class"); + REQUIRE(model->name() == "t00033_class"); + REQUIRE(model->should_include("clanguml::t00033::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00034/test_case.h b/tests/t00034/test_case.h index affcb3a8..44a64a88 100644 --- a/tests/t00034/test_case.h +++ b/tests/t00034/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00034", "[test-case][class]") REQUIRE(diagram->name == "t00034_class"); - REQUIRE(diagram->should_include("clanguml::t00034::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00034_class"); + REQUIRE(model->name() == "t00034_class"); + REQUIRE(model->should_include("clanguml::t00034::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00035/test_case.h b/tests/t00035/test_case.h index 7cbf4163..8a0c3694 100644 --- a/tests/t00035/test_case.h +++ b/tests/t00035/test_case.h @@ -24,13 +24,12 @@ TEST_CASE("t00035", "[test-case][class]") REQUIRE(diagram->name == "t00035_class"); - REQUIRE(diagram->should_include("clanguml::t00035::A")); - auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00035_class"); + REQUIRE(model->name() == "t00035_class"); + REQUIRE(model->should_include("clanguml::t00035::A")); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00036/test_case.h b/tests/t00036/test_case.h index ee8a3ae4..30393389 100644 --- a/tests/t00036/test_case.h +++ b/tests/t00036/test_case.h @@ -27,9 +27,9 @@ TEST_CASE("t00036", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00036_class"); + REQUIRE(model->name() == "t00036_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00037/test_case.h b/tests/t00037/test_case.h index 87927d99..46b74998 100644 --- a/tests/t00037/test_case.h +++ b/tests/t00037/test_case.h @@ -27,9 +27,9 @@ TEST_CASE("t00037", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00037_class"); + REQUIRE(model->name() == "t00037_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00038/test_case.h b/tests/t00038/test_case.h index 8ca2b260..992d94b4 100644 --- a/tests/t00038/test_case.h +++ b/tests/t00038/test_case.h @@ -27,9 +27,9 @@ TEST_CASE("t00038", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t00038_class"); + REQUIRE(model->name() == "t00038_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t00039/.clang-uml b/tests/t00039/.clang-uml new file mode 100644 index 00000000..89ff7ef5 --- /dev/null +++ b/tests/t00039/.clang-uml @@ -0,0 +1,16 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t00039_class: + type: class + generate_packages: false + glob: + - ../../tests/t00039/t00039.cc + using_namespace: + - clanguml::t00039 + include: + subclasses: + - clanguml::t00039::A + - clanguml::t00039::ns3::F + relationships: + - inheritance \ No newline at end of file diff --git a/tests/t00039/t00039.cc b/tests/t00039/t00039.cc new file mode 100644 index 00000000..2944ed5e --- /dev/null +++ b/tests/t00039/t00039.cc @@ -0,0 +1,45 @@ +#include + +namespace clanguml::t00039 { +struct B { +}; + +namespace ns1 { +struct BB : public B { +}; +} // namespace ns1 + +struct A { +}; + +struct AA : public A { +}; + +struct AAA : public AA { + B *b; +}; + +namespace ns2 { +struct AAAA : public AAA { +}; +} // namespace ns2 + +namespace ns3 { +template struct F { + T *t; +}; + +template struct FF : public F { + M *m; +}; + +template struct FE : public F { + M *m; +}; + +template struct FFF : public FF { + N *n; +}; + +} // namespace ns3 +} // namespace clanguml::t00039 diff --git a/tests/t00039/test_case.h b/tests/t00039/test_case.h new file mode 100644 index 00000000..6a2caf2c --- /dev/null +++ b/tests/t00039/test_case.h @@ -0,0 +1,56 @@ +/** + * tests/t00039/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("t00039", "[test-case][class]") +{ + auto [config, db] = load_config("t00039"); + + auto diagram = config.diagrams["t00039_class"]; + + REQUIRE(diagram->name == "t00039_class"); + REQUIRE(diagram->generate_packages() == false); + + auto model = generate_class_diagram(db, diagram); + + REQUIRE(model->name() == "t00039_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("AA"))); + REQUIRE_THAT(puml, IsClass(_A("AAA"))); + REQUIRE_THAT(puml, IsClass(_A("ns2::AAAA"))); + REQUIRE_THAT(puml, IsBaseClass(_A("A"), _A("AA"))); + REQUIRE_THAT(puml, IsBaseClass(_A("AA"), _A("AAA"))); + REQUIRE_THAT(puml, IsBaseClass(_A("AAA"), _A("ns2::AAAA"))); + + REQUIRE_THAT(puml, !IsClass(_A("B"))); + REQUIRE_THAT(puml, !IsClass(_A("ns1::BB"))); + + REQUIRE_THAT(puml, IsClassTemplate("ns3::F", "T")); + REQUIRE_THAT(puml, IsClassTemplate("ns3::FF", "T,M")); + REQUIRE_THAT(puml, IsClassTemplate("ns3::FE", "T,M")); + REQUIRE_THAT(puml, IsClassTemplate("ns3::FFF", "T,M,N")); + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/t00040/.clang-uml b/tests/t00040/.clang-uml new file mode 100644 index 00000000..20744d33 --- /dev/null +++ b/tests/t00040/.clang-uml @@ -0,0 +1,21 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t00040_class: + type: class + generate_packages: false + glob: + - ../../tests/t00040/t00040.cc + using_namespace: + - clanguml::t00040 + include: + namespaces: + - clanguml::t00040 + access: + - public + - protected + exclude: + relationships: + - dependency + elements: + - clanguml::t00040::B \ No newline at end of file diff --git a/tests/t00040/t00040.cc b/tests/t00040/t00040.cc new file mode 100644 index 00000000..21b76dd2 --- /dev/null +++ b/tests/t00040/t00040.cc @@ -0,0 +1,36 @@ +namespace clanguml::t00040 { + +struct B { +}; + +struct A { +public: + int get_a() { return hidden_a_; } + +protected: + int ii_; + +private: + void foo() { } + + int hidden_a_; +}; + +class AA : public A { +public: +}; + +class AAA : public AA { +public: + int get_aaa() { return hidden_aaa_; } + B *b; + +private: + int hidden_aaa_; +}; + +struct R { + void foo(A *a) { } +}; + +} // namespace clanguml::t00040 diff --git a/tests/t00040/test_case.h b/tests/t00040/test_case.h new file mode 100644 index 00000000..1019a385 --- /dev/null +++ b/tests/t00040/test_case.h @@ -0,0 +1,50 @@ +/** + * tests/t00040/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("t00040", "[test-case][class]") +{ + auto [config, db] = load_config("t00040"); + + auto diagram = config.diagrams["t00040_class"]; + + REQUIRE(diagram->name == "t00040_class"); + REQUIRE(diagram->generate_packages() == false); + + auto model = generate_class_diagram(db, diagram); + + REQUIRE(model->name() == "t00040_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("AA"))); + REQUIRE_THAT(puml, IsClass(_A("AAA"))); + REQUIRE_THAT(puml, IsBaseClass(_A("A"), _A("AA"))); + REQUIRE_THAT(puml, IsBaseClass(_A("AA"), _A("AAA"))); + + REQUIRE_THAT(puml, !IsClass(_A("B"))); + + REQUIRE_THAT(puml, !IsDependency(_A("R"), _A("A"))); + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/t00041/.clang-uml b/tests/t00041/.clang-uml new file mode 100644 index 00000000..2ec91634 --- /dev/null +++ b/tests/t00041/.clang-uml @@ -0,0 +1,17 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t00041_class: + type: class + generate_packages: false + glob: + - ../../tests/t00041/t00041.cc + using_namespace: + - clanguml::t00041 + include: + namespaces: + - clanguml::t00041 + context: + - clanguml::t00041::RR + subclasses: + - clanguml::t00041::ns1::N \ No newline at end of file diff --git a/tests/t00041/t00041.cc b/tests/t00041/t00041.cc new file mode 100644 index 00000000..c6099308 --- /dev/null +++ b/tests/t00041/t00041.cc @@ -0,0 +1,46 @@ +namespace clanguml::t00041 { + +struct B { +}; + +struct A { +}; + +class AA : public A { +}; + +struct R { +}; + +struct RR; + +struct D { + RR *rr; +}; + +struct E { +}; + +struct F { +}; + +struct RR : public R { + E *e; + F *f; +}; + +struct RRR : public RR { +}; + +namespace ns1 { +struct N { +}; + +struct NN : public N { +}; + +struct NM : public N { +}; +} + +} // namespace clanguml::t00041 diff --git a/tests/t00041/test_case.h b/tests/t00041/test_case.h new file mode 100644 index 00000000..a4fbb4b1 --- /dev/null +++ b/tests/t00041/test_case.h @@ -0,0 +1,66 @@ +/** + * tests/t00041/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("t00041", "[test-case][class]") +{ + auto [config, db] = load_config("t00041"); + + auto diagram = config.diagrams["t00041_class"]; + + REQUIRE(diagram->name == "t00041_class"); + REQUIRE(diagram->generate_packages() == false); + + auto model = generate_class_diagram(db, diagram); + + REQUIRE(model->name() == "t00041_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("AA"))); + REQUIRE_THAT(puml, !IsClass(_A("AAA"))); + + REQUIRE_THAT(puml, !IsClass(_A("B"))); + + REQUIRE_THAT(puml, IsClass(_A("D"))); + REQUIRE_THAT(puml, IsClass(_A("E"))); + REQUIRE_THAT(puml, IsClass(_A("F"))); + REQUIRE_THAT(puml, IsClass(_A("R"))); + REQUIRE_THAT(puml, IsClass(_A("RR"))); + REQUIRE_THAT(puml, IsClass(_A("RRR"))); + + REQUIRE_THAT(puml, IsBaseClass(_A("R"), _A("RR"))); + REQUIRE_THAT(puml, IsBaseClass(_A("RR"), _A("RRR"))); + + REQUIRE_THAT(puml, IsAssociation(_A("D"), _A("RR"), "+rr")); + REQUIRE_THAT(puml, IsAssociation(_A("RR"), _A("E"), "+e")); + REQUIRE_THAT(puml, IsAssociation(_A("RR"), _A("F"), "+f")); + + REQUIRE_THAT(puml, IsClass(_A("ns1::N"))); + REQUIRE_THAT(puml, IsClass(_A("ns1::NN"))); + REQUIRE_THAT(puml, IsClass(_A("ns1::NM"))); + REQUIRE_THAT(puml, IsBaseClass(_A("ns1::N"), _A("ns1::NN"))); + REQUIRE_THAT(puml, IsBaseClass(_A("ns1::N"), _A("ns1::NM"))); + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/t20001/test_case.h b/tests/t20001/test_case.h index 66319027..d330bfd9 100644 --- a/tests/t20001/test_case.h +++ b/tests/t20001/test_case.h @@ -22,17 +22,17 @@ TEST_CASE("t20001", "[test-case][sequence]") auto diagram = config.diagrams["t20001_sequence"]; - REQUIRE(diagram->should_include("clanguml::t20001::A")); - REQUIRE(!diagram->should_include("clanguml::t20001::detail::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t20001_sequence"); auto model = generate_sequence_diagram(db, diagram); - REQUIRE(model.name() == "t20001_sequence"); + REQUIRE(model->name() == "t20001_sequence"); - auto puml = generate_sequence_puml(diagram, model); + REQUIRE(model->should_include("clanguml::t20001::A")); + REQUIRE(!model->should_include("clanguml::t20001::detail::C")); + REQUIRE(!model->should_include("std::vector")); + + auto puml = generate_sequence_puml(diagram, *model); REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); diff --git a/tests/t20002/test_case.h b/tests/t20002/test_case.h index 24cc8501..a5ab0472 100644 --- a/tests/t20002/test_case.h +++ b/tests/t20002/test_case.h @@ -26,9 +26,9 @@ TEST_CASE("t20002", "[test-case][sequence]") auto model = generate_sequence_diagram(db, diagram); - REQUIRE(model.name() == "t20002_sequence"); + REQUIRE(model->name() == "t20002_sequence"); - auto puml = generate_sequence_puml(diagram, model); + auto puml = generate_sequence_puml(diagram, *model); REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); diff --git a/tests/t30001/test_case.h b/tests/t30001/test_case.h index 8ed7251f..15c6a261 100644 --- a/tests/t30001/test_case.h +++ b/tests/t30001/test_case.h @@ -22,17 +22,17 @@ TEST_CASE("t30001", "[test-case][package]") auto diagram = config.diagrams["t30001_package"]; - REQUIRE(diagram->should_include("clanguml::t30001::A")); - REQUIRE(!diagram->should_include("clanguml::t30001::detail::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t30001_package"); auto model = generate_package_diagram(db, diagram); - REQUIRE(model.name() == "t30001_package"); + REQUIRE(model->name() == "t30001_package"); - auto puml = generate_package_puml(diagram, model); + REQUIRE(model->should_include("clanguml::t30001::A")); + REQUIRE(!model->should_include("clanguml::t30001::detail::C")); + REQUIRE(!model->should_include("std::vector")); + + auto puml = generate_package_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t30002/test_case.h b/tests/t30002/test_case.h index 5cddd8ed..e77e7b05 100644 --- a/tests/t30002/test_case.h +++ b/tests/t30002/test_case.h @@ -22,17 +22,13 @@ TEST_CASE("t30002", "[test-case][package]") auto diagram = config.diagrams["t30002_package"]; - REQUIRE(diagram->should_include("clanguml::t30002::A")); - REQUIRE(!diagram->should_include("clanguml::t30002::detail::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t30002_package"); auto model = generate_package_diagram(db, diagram); - REQUIRE(model.name() == "t30002_package"); + REQUIRE(model->name() == "t30002_package"); - auto puml = generate_package_puml(diagram, model); + auto puml = generate_package_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t30003/test_case.h b/tests/t30003/test_case.h index 5d508026..faa29614 100644 --- a/tests/t30003/test_case.h +++ b/tests/t30003/test_case.h @@ -22,17 +22,13 @@ TEST_CASE("t30003", "[test-case][package]") auto diagram = config.diagrams["t30003_package"]; - REQUIRE(diagram->should_include("clanguml::t30003::A")); - REQUIRE(diagram->should_include("clanguml::t30003::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t30003_package"); auto model = generate_package_diagram(db, diagram); - REQUIRE(model.name() == "t30003_package"); + REQUIRE(model->name() == "t30003_package"); - auto puml = generate_package_puml(diagram, model); + auto puml = generate_package_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t30004/test_case.h b/tests/t30004/test_case.h index fbc2a03c..e850084b 100644 --- a/tests/t30004/test_case.h +++ b/tests/t30004/test_case.h @@ -22,17 +22,13 @@ TEST_CASE("t30004", "[test-case][package]") auto diagram = config.diagrams["t30004_package"]; - REQUIRE(diagram->should_include("clanguml::t30004::A")); - REQUIRE(diagram->should_include("clanguml::t30004::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t30004_package"); auto model = generate_package_diagram(db, diagram); - REQUIRE(model.name() == "t30004_package"); + REQUIRE(model->name() == "t30004_package"); - auto puml = generate_package_puml(diagram, model); + auto puml = generate_package_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t30005/test_case.h b/tests/t30005/test_case.h index d1186ef5..30c181f3 100644 --- a/tests/t30005/test_case.h +++ b/tests/t30005/test_case.h @@ -22,17 +22,13 @@ TEST_CASE("t30005", "[test-case][package]") auto diagram = config.diagrams["t30005_package"]; - REQUIRE(diagram->should_include("clanguml::t30005::A")); - REQUIRE(diagram->should_include("clanguml::t30005::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t30005_package"); auto model = generate_package_diagram(db, diagram); - REQUIRE(model.name() == "t30005_package"); + REQUIRE(model->name() == "t30005_package"); - auto puml = generate_package_puml(diagram, model); + auto puml = generate_package_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t30006/test_case.h b/tests/t30006/test_case.h index 174d2612..4991f12a 100644 --- a/tests/t30006/test_case.h +++ b/tests/t30006/test_case.h @@ -22,17 +22,13 @@ TEST_CASE("t30006", "[test-case][package]") auto diagram = config.diagrams["t30006_package"]; - REQUIRE(diagram->should_include("clanguml::t30006::A")); - REQUIRE(diagram->should_include("clanguml::t30006::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t30006_package"); auto model = generate_package_diagram(db, diagram); - REQUIRE(model.name() == "t30006_package"); + REQUIRE(model->name() == "t30006_package"); - auto puml = generate_package_puml(diagram, model); + auto puml = generate_package_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t30007/test_case.h b/tests/t30007/test_case.h index 130f1e96..03850092 100644 --- a/tests/t30007/test_case.h +++ b/tests/t30007/test_case.h @@ -22,17 +22,13 @@ TEST_CASE("t30007", "[test-case][package]") auto diagram = config.diagrams["t30007_package"]; - REQUIRE(diagram->should_include("clanguml::t30007::A")); - REQUIRE(diagram->should_include("clanguml::t30007::C")); - REQUIRE(!diagram->should_include("std::vector")); - REQUIRE(diagram->name == "t30007_package"); auto model = generate_package_diagram(db, diagram); - REQUIRE(model.name() == "t30007_package"); + REQUIRE(model->name() == "t30007_package"); - auto puml = generate_package_puml(diagram, model); + auto puml = generate_package_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/t90000/test_case.h b/tests/t90000/test_case.h index 068416ce..425d5dc9 100644 --- a/tests/t90000/test_case.h +++ b/tests/t90000/test_case.h @@ -24,9 +24,9 @@ TEST_CASE("t90000", "[test-case][config]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name() == "t90000_class"); + REQUIRE(model->name() == "t90000_class"); - auto puml = generate_class_puml(diagram, model); + auto puml = generate_class_puml(diagram, *model); AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); diff --git a/tests/test_cases.cc b/tests/test_cases.cc index f8a0c6cf..3487f740 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -51,8 +51,8 @@ std::pair load_config2( return std::make_pair(std::move(config), std::move(db)); } -clanguml::sequence_diagram::model::diagram generate_sequence_diagram( - cppast::libclang_compilation_database &db, +std::unique_ptr +generate_sequence_diagram(cppast::libclang_compilation_database &db, std::shared_ptr diagram) { using diagram_config = clanguml::config::sequence_diagram; @@ -66,10 +66,10 @@ clanguml::sequence_diagram::model::diagram generate_sequence_diagram( diagram_config, diagram_visitor>(db, diagram->name, dynamic_cast(*diagram)); - return model; + return std::move(model); } -clanguml::class_diagram::model::diagram generate_class_diagram( +std::unique_ptr generate_class_diagram( cppast::libclang_compilation_database &db, std::shared_ptr diagram) { @@ -84,11 +84,11 @@ clanguml::class_diagram::model::diagram generate_class_diagram( diagram_config, diagram_visitor>( db, diagram->name, dynamic_cast(*diagram)); - return model; + return std::move(model); } -clanguml::package_diagram::model::diagram generate_package_diagram( - cppast::libclang_compilation_database &db, +std::unique_ptr +generate_package_diagram(cppast::libclang_compilation_database &db, std::shared_ptr diagram) { using diagram_config = clanguml::config::package_diagram; @@ -197,6 +197,9 @@ using namespace clanguml::test::matchers; #include "t00036/test_case.h" #include "t00037/test_case.h" #include "t00038/test_case.h" +#include "t00039/test_case.h" +#include "t00040/test_case.h" +#include "t00041/test_case.h" // // Sequence diagram tests diff --git a/tests/test_cases.h b/tests/test_cases.h index 7d6e20fd..030f9849 100644 --- a/tests/test_cases.h +++ b/tests/test_cases.h @@ -245,7 +245,7 @@ ContainsMatcher IsInnerClass(std::string const &parent, } ContainsMatcher IsAssociation(std::string const &from, std::string const &to, - std::string const &label, std::string multiplicity_source = "", + std::string const &label = "", std::string multiplicity_source = "", std::string multiplicity_dest = "", CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) { @@ -264,13 +264,6 @@ ContainsMatcher IsAssociation(std::string const &from, std::string const &to, fmt::format(format_string, from, to, label), caseSensitivity)); } -ContainsMatcher IsFriend(std::string const &from, std::string const &to, - CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) -{ - return ContainsMatcher(CasedString( - fmt::format("{} <.. {} : <>", from, to), caseSensitivity)); -} - ContainsMatcher IsComposition(std::string const &from, std::string const &to, std::string const &label, std::string multiplicity_source = "", std::string multiplicity_dest = "", @@ -424,6 +417,24 @@ ContainsMatcher IsField(std::string const &name, CasedString(pattern + " : " + type, caseSensitivity)); } +template +ContainsMatcher IsFriend(std::string const &from, std::string const &to, + CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) +{ + std::string pattern; + + if constexpr (has_type()) + pattern = "+"; + else if constexpr (has_type()) + pattern = "#"; + else + pattern = "-"; + + return ContainsMatcher( + CasedString(fmt::format("{} <.. {} : {}<>", from, to, pattern), + caseSensitivity)); +} + ContainsMatcher IsPackage(std::string const &str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) { diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index d25f560b..ab6edccd 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -111,6 +111,15 @@ test_cases: - name: t00038 title: Template instantiation with unexposed nested templates description: + - name: t00039 + title: Subclass class diagram filter test + description: + - name: t00040 + title: Relationship and access filter test + description: + - name: t00041 + title: Context diagram filter test + description: Sequence diagrams: - name: t20001 title: Basic sequence diagram test case diff --git a/uml/class_model_class_diagram.yml b/uml/class_model_class_diagram.yml index 35e896a1..6e45a9cf 100644 --- a/uml/class_model_class_diagram.yml +++ b/uml/class_model_class_diagram.yml @@ -11,6 +11,9 @@ include: namespaces: - clanguml::common::model - clanguml::class_diagram::model +exclude: + relationships: + - dependency using_namespace: - clanguml plantuml: diff --git a/uml/common_model_class_diagram.yml b/uml/common_model_class_diagram.yml index 267f3f77..483ad638 100644 --- a/uml/common_model_class_diagram.yml +++ b/uml/common_model_class_diagram.yml @@ -6,6 +6,9 @@ glob: include: namespaces: - clanguml::common::model +exclude: + relationships: + - dependency using_namespace: - clanguml::common::model plantuml: diff --git a/uml/diagram_model_class_diagram.yml b/uml/diagram_model_class_diagram.yml index e19b60d7..d98deac6 100644 --- a/uml/diagram_model_class_diagram.yml +++ b/uml/diagram_model_class_diagram.yml @@ -16,6 +16,9 @@ include: - clanguml::class_diagram::model - clanguml::sequence_diagram::model - clanguml::package_diagram::model +exclude: + relationships: + - dependency using_namespace: - clanguml plantuml: diff --git a/uml/package_model_class_diagram.yml b/uml/package_model_class_diagram.yml index d5648a54..7086e6cc 100644 --- a/uml/package_model_class_diagram.yml +++ b/uml/package_model_class_diagram.yml @@ -12,6 +12,9 @@ include: - clanguml::package_diagram::model using_namespace: - clanguml::package_diagram::model +exclude: + relationships: + - dependency plantuml: before: - 'title clang-uml package diagram model' \ No newline at end of file diff --git a/uml/sequence_model_class_diagram.yml b/uml/sequence_model_class_diagram.yml index 03de4ba9..30902016 100644 --- a/uml/sequence_model_class_diagram.yml +++ b/uml/sequence_model_class_diagram.yml @@ -10,6 +10,9 @@ include: namespaces: - clanguml::common::model - clanguml::sequence_diagram::model +exclude: + relationships: + - dependency using_namespace: - clanguml::sequence_diagram::model plantuml: diff --git a/util/format_svg.py b/util/format_svg.py index 1539f88d..5b6abf3f 100755 --- a/util/format_svg.py +++ b/util/format_svg.py @@ -20,6 +20,7 @@ import sys from lxml import etree +import lxml.html def main(argv): if len(argv) < 1: @@ -35,6 +36,12 @@ def main(argv): # Parse SVG XML tree = etree.fromstring(bytes(xml, encoding='utf8')) + # Add style color for links + defs = tree.xpath('//svg:defs', namespaces={'svg':'http://www.w3.org/2000/svg'})[0] + style = etree.SubElement(defs, 'style') + style.text = 'a:hover { text-decoration: underline; }' + style.set('type', 'text/css') + # Remove comments from SVG, to minimize diff # when updating diagrams in Git comments = tree.xpath('//comment()')