Skip to content

How names are resolved

These rules decide where Go to Declaration, Find Usages, Rename and the undeclared name check look for a declaration. Read this page when one of them goes somewhere you did not expect. They follow the name lookup rules of IEEE 1800 (the SystemVerilog standard), with the exceptions noted below and in Known limitations.

Starting at the scope the name is in (a block, loop, function or task, class, module, interface, program or package) and moving outwards one scope at a time, the plugin checks, for each scope in turn:

  1. the names declared in that scope;
  2. for a class: the members it inherits through extends, all the way up the chain; for an out-of-block method function c::f(): the members of class c;
  3. the names imported into that scope: explicit imports (import pkg::x;) win over wildcard imports (import pkg::*;). A package also provides the names it re-exports (export other::*;, export other::x;, export *::*;), also through pkg::x. The plugin follows exports without checking that the exporting package itself uses the name, so it may resolve a name a strict tool rejects.

In a file that other files `include (a class file included into a package, as UVM testbenches do), the walk goes on at each `include that names the file, as if the text were there: the package around it, its own declarations and its imports. For example (illustrative; these files are not in the sample project), RxFifoDepth in uart_scoreboard.sv, included into uart_env_pkg, resolves to the parameter of uart_reg_pkg that uart_env_pkg imports. This goes through include chains, and a file included in several places sees all of them: Go to Declaration then offers each place’s declaration, and renaming one of them is a conflict, since the shared file would change for the others too. A file included in more than 32 places is not looked up through them. Includes are matched as the IDE finds them (by the path, else by the file name), and every name of the including scope counts, also one declared after the `include. When several files of the project have the name an `include gives (a design copied into several trees, its headers found through +incdir+), the one the compile file’s +incdir+ order finds is taken; without one, the ones closest to the including file in the directory tree, so each tree’s package includes its own copy.

The first scope where the name is found wins. So a name imported into a module with import pkg::*; wins over a declaration of the same name at file level, and a member inherited from a base class wins over a variable of the same name in the package around the class.

If no enclosing scope has the name, the whole project is searched: modules, interfaces, programs, packages, classes and functions declared at file level in any file (including files attached as libraries).

  • pkg::x and c::x look only in the package or class.
  • obj.x looks in the type of obj: its class (and base classes), interface, struct or module instance. This works for chains (env.agt.drv.vif), this.x, super.x, indexed handles (q[i].x), generate blocks (g_lane[0].busy) and clocking blocks (vif.cb.req).
  • .port(...) in an instantiation looks in the instantiated module; #(.P(...)) looks at its parameters.

Following IEEE 1800 §3.13, modules, interfaces and programs share one name space, packages have their own, and everything else is scoped. A module and a signal with the same name do not clash, and neither do a package and a variable.

In bind dut chk u_chk(.clk(clk)); the port expressions (clk) are resolved inside the target module dut, wherever the bind statement is written. The bound instance u_chk becomes part of dut: u_chk.flag resolves inside dut, and u_dut.u_chk.flag resolves through an instance u_dut of dut. Bind files in libraries count too.

When a name does not resolve as you expect

Section titled “When a name does not resolve as you expect”
  • The file must be in the opened project folder, and indexing (the progress bar at the bottom right) must have finished.
  • Code in an inactive `ifdef branch is not resolved: see Conditional compilation.
  • Some include cases are not followed (a header included in many files, a continuous assignment at the top of a module-body fragment): see Known limitations.
  • For an “undeclared name” report, see Undeclared names.