VHDL-LS / rust_hdl

Other
347 stars 64 forks source link

Guess elaboration of component/entity binding when unambiguous #111

Closed pidgeon777 closed 1 year ago

pidgeon777 commented 3 years ago

Actually in my ENTITY_TOP I have an instance like this:

  ENTITY_1_1 : ENTITY_1
  generic map(
    GEN => GEN
  )
  port map(
    INP => INP
  );

All of the source files are correctly added to the project, and parsed.

The fact is that when I try to look at the definition of ENTITY_1, it jumps to its component declaration, in ENTITY_TOP:

  component ENTITY_1
    generic (
      GEN : integer := 0
    );
    port (
      INP : in std_logic
    );
  end component;

I would have expected it to jump to the entity, instead:

entity ENTITY_1 is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

Also, references between entity, component and instances are not found. As if a link was missing between the top and submodule sources.

This is solved by an instantiation like the following:

  ENTITY_1_1 : entity work.ENTITY_1(arch1)
  generic map(
    GEN => GEN
  )
  port map(
    INP => INP
  );

When looking at the references of ENTITY_1, then those are all detected:

The fact is that in my project, none of the instances are declared according to this format:

LABEL_INSTANCE : entity lib.ENTITY(arch)

but only the following:

LABEL_INSTANCE : ENTITY

Not being able to correctly jump to entity definitions and list all of the instances is a huge miss.

My question is: to solve this issue, is there a quick workaround to consider all of the instances/entities as belonging to the same library, unless otherwise stated, maybe by adding an option to the project file, or even a command-line argument? Thus without having to refractory all of my project source files just to allow complete references browsing.

maehne commented 3 years ago

I would not consider it a bug, but expected behaviour. You are instantiating in your top entity components, which are only bound to the actual entities at elaboration time. That a component is automatically bound to an entity with a matching name and interface is only the default behaviour, which maybe overridden per component instance using a configuration. However, many configurations may exist for the same entity. So, it's rather difficult for rust_hdl to know, which entity will be bound to which component instance.

pidgeon777 commented 3 years ago

In almost every project we developed, our code is structured so that only one architecture/configuration exists for each entity, and no multiple entities with the same name exist.

Also, we consider all of these belonging to the same work library unless otherwise specified.

I also noticed that in many online projects, this form is used when instancing:

LABEL_INSTANCE : COMPONENT_NAME

Thus it would be a pity to miss all of the cross-references between components, entities and instances.

What I propose, is to add an option so that the instantiations in the above form get ideally "replaced" when parsed as it follows:

LABEL_INSTANCE : entity lib.COMPONENT_NAME

This could be an easy and quick workaround to enable references and jump to definitions.

Maybe, in the project file it could be added some special flag/tag so that when source files are listed under it, then all of the instances with the missing entity lib.XXX could be parsed as belonging to the library specified by the flag/tag (e.g. work). The first architecture/configuration of the parsed corresponding entity would be selected, and that would be the only downside, but this would make rust_hdl much more robust to these "incomplete" instantiations, thus allowing complete code navigation.

kraigher commented 1 year ago

In the VHDL standard the mechanism that maps component instances to entities is called elaboration. Elaboration starts at a top level entity and works it way down, even generics could affect the component mapping. So this is not a bug it is just something that we do not try to do yet.

A language server for VHDL could try to be smart about this to help the user for common patterns and make suggestions but we do not do it today so I label it enhancement.

However if you are only having one entity per instance you could might as well use entity instantiation in your project and skip a lot of redundant code.

kraigher commented 1 year ago

As of release v0.57.0 I have implemented the "Goto Implementation" method of the LSP protocol. It supports two uses.

  1. Clicking "Goto implementation" on a component declaration or a reference to a component declaration takes you to the matching entity in the same library.
  2. Clicking "Goto implementation" on an entity declaration takes you to any matching component declaration of the entity.

To find all instances of a component you can still run "Find references" on the component declaration.

Any feedback on the above is welcome before I close the issue.

pidgeon777 commented 1 year ago

This is excellent news! I'll do some in-depth tests and inform you about the outcome πŸ‘.

pidgeon777 commented 1 year ago

So far, it seems to work great πŸ‘.