@@ -10,7 +10,6 @@ call the Render() function and this will return a string with the class diagram.
1010
1111See github.com/jfeliu007/goplantuml/cmd/goplantuml/main.go for a command that uses this functions and outputs the text to
1212the console.
13-
1413*/
1514package parser
1615
@@ -267,7 +266,6 @@ func (p *ClassParser) parseFileDeclarations(node ast.Decl) {
267266}
268267
269268func (p * ClassParser ) handleFuncDecl (decl * ast.FuncDecl ) {
270-
271269 if decl .Recv != nil {
272270 if decl .Recv .List == nil {
273271 return
@@ -296,24 +294,30 @@ func (p *ClassParser) handleFuncDecl(decl *ast.FuncDecl) {
296294 }
297295}
298296
299- func handleGenDecStructType (p * ClassParser , typeName string , c * ast.StructType ) {
297+ func handleGenDecStructType (p * ClassParser , typeName string , c * ast.StructType , typeParams * ast. FieldList ) {
300298 for _ , f := range c .Fields .List {
301299 p .getOrCreateStruct (typeName ).AddField (f , p .allImports )
302300 }
301+
302+ if typeParams == nil {
303+ return
304+ }
305+
306+ for _ , tp := range typeParams .List {
307+ p .getOrCreateStruct (typeName ).AddTypeParam (tp )
308+ }
303309}
304310
305311func handleGenDecInterfaceType (p * ClassParser , typeName string , c * ast.InterfaceType ) {
306312 for _ , f := range c .Methods .List {
307313 switch t := f .Type .(type ) {
308314 case * ast.FuncType :
309315 p .getOrCreateStruct (typeName ).AddMethod (f , p .allImports )
310- break
311316 case * ast.Ident :
312317 f , _ := getFieldType (t , p .allImports )
313318 st := p .getOrCreateStruct (typeName )
314319 f = replacePackageConstant (f , st .PackageName )
315320 st .AddToComposition (f )
316- break
317321 }
318322 }
319323}
@@ -338,7 +342,7 @@ func (p *ClassParser) processSpec(spec ast.Spec) {
338342 switch c := v .Type .(type ) {
339343 case * ast.StructType :
340344 declarationType = "class"
341- handleGenDecStructType (p , typeName , c )
345+ handleGenDecStructType (p , typeName , c , v . TypeParams )
342346 case * ast.InterfaceType :
343347 declarationType = "interface"
344348 handleGenDecInterfaceType (p , typeName , c )
@@ -379,7 +383,6 @@ func (p *ClassParser) processSpec(spec ast.Spec) {
379383 p .allRenamedStructs [pack [0 ]][renamedClass ] = pack [1 ]
380384 }
381385 }
382- return
383386}
384387
385388// If this element is an array or a pointer, this function will return the type that is closer to these
@@ -465,7 +468,7 @@ func (p *ClassParser) renderStructures(pack string, structures map[string]*Struc
465468 str .WriteLineWithDepth (2 , aliasComplexNameComment )
466469 str .WriteLineWithDepth (1 , "}" )
467470 }
468- str .WriteLineWithDepth (0 , fmt . Sprintf ( `}` ) )
471+ str .WriteLineWithDepth (0 , `}` )
469472 if p .renderingOptions .Compositions {
470473 str .WriteLineWithDepth (0 , composition .String ())
471474 }
@@ -479,7 +482,6 @@ func (p *ClassParser) renderStructures(pack string, structures map[string]*Struc
479482}
480483
481484func (p * ClassParser ) renderAliases (str * LineStringBuilder ) {
482-
483485 aliasString := ""
484486 if p .renderingOptions .ConnectionLabels {
485487 aliasString = aliasOf
@@ -505,7 +507,6 @@ func (p *ClassParser) renderAliases(str *LineStringBuilder) {
505507}
506508
507509func (p * ClassParser ) renderStructure (structure * Struct , pack string , name string , str * LineStringBuilder , composition * LineStringBuilder , extends * LineStringBuilder , aggregations * LineStringBuilder ) {
508-
509510 privateFields := & LineStringBuilder {}
510511 publicFields := & LineStringBuilder {}
511512 privateMethods := & LineStringBuilder {}
@@ -518,9 +519,24 @@ func (p *ClassParser) renderStructure(structure *Struct, pack string, name strin
518519 case "alias" :
519520 sType = "<< (T, #FF7700) >> "
520521 renderStructureType = "class"
522+ }
521523
524+ types := ""
525+ if structure .Generics .exists () {
526+ types = "<"
527+ for t := range structure .Generics .Types {
528+ types += fmt .Sprintf ("%s, " , t )
529+ }
530+ types = strings .TrimSuffix (types , ", " )
531+ types += " constrains "
532+ for _ , n := range structure .Generics .Names {
533+ types += fmt .Sprintf ("%s, " , n )
534+ }
535+ types = strings .TrimSuffix (types , ", " )
536+ types += ">"
522537 }
523- str .WriteLineWithDepth (1 , fmt .Sprintf (`%s %s %s {` , renderStructureType , name , sType ))
538+
539+ str .WriteLineWithDepth (1 , fmt .Sprintf (`%s %s%s %s {` , renderStructureType , name , types , sType ))
524540 p .renderStructFields (structure , privateFields , publicFields )
525541 p .renderStructMethods (structure , privateMethods , publicMethods )
526542 p .renderCompositions (structure , name , composition )
@@ -538,7 +554,7 @@ func (p *ClassParser) renderStructure(structure *Struct, pack string, name strin
538554 if publicMethods .Len () > 0 {
539555 str .WriteLineWithDepth (0 , publicMethods .String ())
540556 }
541- str .WriteLineWithDepth (1 , fmt . Sprintf ( `}` ) )
557+ str .WriteLineWithDepth (1 , `}` )
542558}
543559
544560func (p * ClassParser ) renderCompositions (structure * Struct , name string , composition * LineStringBuilder ) {
@@ -562,7 +578,6 @@ func (p *ClassParser) renderCompositions(structure *Struct, name string, composi
562578}
563579
564580func (p * ClassParser ) renderAggregations (structure * Struct , name string , aggregations * LineStringBuilder ) {
565-
566581 aggregationMap := structure .Aggregations
567582 if p .renderingOptions .AggregatePrivateMembers {
568583 p .updatePrivateAggregations (structure , aggregationMap )
@@ -571,7 +586,6 @@ func (p *ClassParser) renderAggregations(structure *Struct, name string, aggrega
571586}
572587
573588func (p * ClassParser ) updatePrivateAggregations (structure * Struct , aggregationsMap map [string ]struct {}) {
574-
575589 for agg := range structure .PrivateAggregations {
576590 aggregationsMap [agg ] = struct {}{}
577591 }
@@ -600,13 +614,13 @@ func (p *ClassParser) renderAggregationMap(aggregationMap map[string]struct{}, s
600614}
601615
602616func (p * ClassParser ) getPackageName (t string , st * Struct ) string {
603-
604617 packageName := st .PackageName
605618 if isPrimitiveString (t ) {
606619 packageName = builtinPackageName
607620 }
608621 return packageName
609622}
623+
610624func (p * ClassParser ) renderExtends (structure * Struct , name string , extends * LineStringBuilder ) {
611625
612626 orderedExtends := []string {}
@@ -628,7 +642,6 @@ func (p *ClassParser) renderExtends(structure *Struct, name string, extends *Lin
628642}
629643
630644func (p * ClassParser ) renderStructMethods (structure * Struct , privateMethods * LineStringBuilder , publicMethods * LineStringBuilder ) {
631-
632645 for _ , method := range structure .Functions {
633646 accessModifier := "+"
634647 if unicode .IsLower (rune (method .Name [0 ])) {
@@ -685,6 +698,7 @@ func (p *ClassParser) getOrCreateStruct(name string) *Struct {
685698 Functions : make ([]* Function , 0 ),
686699 Fields : make ([]* Field , 0 ),
687700 Type : "" ,
701+ Generics : NewGeneric (),
688702 Composition : make (map [string ]struct {}, 0 ),
689703 Extends : make (map [string ]struct {}, 0 ),
690704 Aggregations : make (map [string ]struct {}, 0 ),
0 commit comments