jfeliu007 / goplantuml

PlantUML Class Diagram Generator for golang projects
MIT License
1.84k stars 172 forks source link

doesn't draw the IS-A relation when type implements an interface in different packages #106

Open hitzhangjie opened 3 years ago

hitzhangjie commented 3 years ago

image

Type helloworldServiceImpl implements the interface defined in package helloworld, the IS-A relation is not drawed.

the generated plantuml is :

@startuml

package "main" {
    class "helloworldServiceImpl" as main.helloworldServiceImpl <<E,#FFCC00>> {
        +Hello(ctx: context.Context, req: *helloworld.Request, rsp: *helloworld.Response): error
    }
}

    main.helloworldServiceImpl ..> helloworld.Request : <<use>> 
    main.helloworldServiceImpl ..> helloworld.Response : <<use>> 

package "helloworld" {
    interface "HelloworldClientProxy" as helloworld.HelloworldClientProxy {
        +Hello(ctx: context.Context, req: *helloworld.Request, opts: client.Option): (rsp: *helloworld.Response, err: error)
    }
}

    helloworld.HelloworldClientProxy ..> helloworld.Request : <<use>> 
    helloworld.HelloworldClientProxy ..> helloworld.Response : <<return>> 

package "helloworld" {
    class "HelloworldClientProxyImpl" as helloworld.HelloworldClientProxyImpl <<V,Orchid>> {
        -client: client.Client
        -opts: client.Option
        +Hello(ctx: context.Context, req: *helloworld.Request, opts: client.Option): (rsp: *helloworld.Response, err: error)
    }
}

    helloworld.HelloworldClientProxyImpl ..> helloworld.Request : <<use>> 
    helloworld.HelloworldClientProxyImpl ..> helloworld.Response : <<return>> 

package "helloworld" {
    interface "HelloworldService" as helloworld.HelloworldService {
        +Hello(ctx: context.Context, req: *helloworld.Request, rsp: *helloworld.Response): err: error
    }
}

    helloworld.HelloworldService ..> helloworld.Request : <<use>> 
    helloworld.HelloworldService ..> helloworld.Response : <<use>> 

package "helloworld" {
    class "Request" as helloworld.Request <<E,#FFCC00>> {
        -state: impl.MessageState
        -sizeCache: int32
        -unknownFields: []byte
        +Reset()
        +String(): string
        +ProtoMessage()
        +ProtoReflect(): protoreflect.Message
        +Descriptor(): ([]byte, []int)
    }
}

package "helloworld" {
    class "Response" as helloworld.Response <<E,#FFCC00>> {
        -state: impl.MessageState
        -sizeCache: int32
        -unknownFields: []byte
        +Reset()
        +String(): string
        +ProtoMessage()
        +ProtoReflect(): protoreflect.Message
        +Descriptor(): ([]byte, []int)
    }
}

    helloworld.HelloworldClientProxyImpl -up-|> helloworld.HelloworldClientProxy

@enduml
jfeliu007 commented 3 years ago

It would be interesting to see the code, since the example you posted has two different signatures in the Hello Method.

Hello(ctx: context.Context, req: *helloworld.Request, opts: client.Option): (rsp: *helloworld.Response, err: error) Hello(ctx: context.Context, req: *helloworld.Request, rsp: *helloworld.Response): err: error

Notice the parameters and the returns are different. If the code is the same, then this means this tool just helped you see it :) . If not, then the tools is taking the information wrong :(. Is it possible for you to confirm this? Notice that the HelloworldClientProxyImpl does have the correct signature and it does indeed represents the correct relationship with the interface

hitzhangjie commented 3 years ago

they have the same signature: Hello(ctx: context.Context, req: *helloworld.Request, rsp: *helloworld.Response): err: error

jfeliu007 commented 3 years ago

I see, my mistake. Usually in my code I don't reference the package within the same package. For example. Plantuml has the following structure

type Struct struct {
    PackageName         string
    Functions           []*Function
    Fields              []*Field
    Type                string
    Composition         map[string]struct{}
    Extends             map[string]struct{}
    Aggregations        map[string]struct{}
    PrivateAggregations map[string]struct{}
}

and the following function

func (st *Struct) ImplementsInterface(inter *Struct) bool {
...
}

notice I am not using (inter *parser.Struct) which is the case for you. I am not sure if that is the problem with the parsing of the relationship. Since the parser will assume the package and make the relationship with it. Maybe the interface needs to be defined as

Hello(ctx: context.Context, req: *Request, rsp: *Response): err: error

Instead, since Request and Response both belong to that package. I'd like to try what you are doing to see what the parser returns. If you could share the code it will help me see what is going on. I understand sometimes it is no possible, so something that compiles and produces a similar outcome will help me reproduce it.

hitzhangjie commented 3 years ago

@jfeliu007 Thanks for your sharing, I'll check and test it later.

jfeliu007 commented 3 years ago

Hi @hitzhangjie , is this still an issue?

hitzhangjie commented 3 years ago

Yes, I think the problem still exists.

hello.zip

I uploaded an attachment. This contains a complete project based on some microservice framework, and a file.puml generated by the latest gouml.