The e Reflection API allows you to perform various queries on entities in your own code, and to figure out which types, fields, methods, and so on have been declared in the code, the relations between them, and their source information. However, what the Reflection API does not provide is an ability to figure out if those entities are actually used, and if so, where they are used. For example, you have declared a method foo(), but is this method actually called? And if it is, where is it called?
Such an ability can be helpful for various purposes. For example, you may need to create a linting utility, or to add a new custom check for e linting with HAL, where you want to warn about certain usages of a type or a method. Or, you may want to get rid of dead code – code that is never used – for example, you defined a type but you never declared anything to belong to that type. You may also want to deprecate some field or method declared in your code, and you need to find all places in the code that actually use the deprecated entity, so that you can to fix them.
You can, of course, use the simple ‘grep’ utility in order to find occurrences of a given text in the code, and this works. But this method of finding references to an entity is very time consuming and unreliable, as it uses a purely textual search in the code. It is also hard to automate. Specman provides a much better way to find where code entities are referred to – the entity_reference API.
Using the entity_reference API is simple. Once your code is loaded or compiled, you can perform queries to find references to all entities, to all entities of given kinds, or to one specific entity. You can also refine the query to find references that reside in certain modules only, or references to entities whose name matches a given pattern, and so on.
TheAPI provides the following query methods, all belonging to lint_manager:
get_all_entity_references(kinds: list of entity_kind = {}, name_pattern: string = "",
module_pattern: string = "", include_extensions: bool = TRUE): list of entity_reference
get_entity_references(entity: rf_named_entity, module_pattern: string = "",
include_extensions: bool = TRUE): list of entity_reference
get_entity_references_in_context(context: rf_definition_element,
entity: rf_named_entity): list of entity_reference
get_all_entity_references_in_context (context: rf_definition_element,
kinds: list of entity_kind = {}): list of entity_reference
get_all_entity_references() by default finds and returns a list of all references to all entities of all kinds, and optional parameters can be used to limit the search to certain entity kinds, to a certain entity name pattern, to a source module pattern, or to exclude extensions. (By default, an extension of an entity, such as an extend statement for a type or an is also extension for a method, is also considered an entity reference.)
get_entity_references() finds references to one specific entity passed as parameter.
get_entity_references_in_context() and get_all_entity_references_in_context() find references that occur in the context of a specific definition element, such as a method layer.
The resulting list contain objects of the pre-defined type entity_reference, which provides information on a given reference, including the entity itself, the context in which the reference occurs, the source information for the reference. See the Specman manuals for more details.
For example, assume that you have a method my_struct.foo() and you have decided to deprecate it. Now you want to find all places where this method is actually called, in order to fix them. You can do it as follows:
extend sys {
find_references_to_foo() is {
var m: rf_method =
rf_manager.get_struct_by_name("my_struct").get_method("foo");
var all_refs: list of entity_reference =
lint_manager.get_entity_references(m, "", FALSE);
if not all_refs.is_empty() then {
out("Method my_struct.foo() is called at the following locations:");
for each (ref) in all_refs do {
out("at line ", ref.get_source_line_num(), " in @",
ref.get_source_module().get_name());
};
};
};
};
If you use the entity reference API for implementing custom lint checks, you can also use it as part of a lint_manager.user_analysis() hook called as part of HAL linting.
One important point to remember: To be able to use the entity reference API on a given code with standalone Specman (without HAL), you must turn on the following configuration flag: config misc -lint_mode. This flag ensures that relevant information is collected during load/compilation. In code compiled without this flag, entity references will not be found.
Yuri Tsoglin
e Language team, Specman R&D