1 # Implementing Annotations
3 **How to use the internal API to implement built-in annotations in `tao_idl` or a
4 compiler that uses `tao_idl`.**
8 * [IDL Annotations](#idl-annotations)
9 * [What Can Be Annotated](#what-can-be-annotated)
10 * [Special Cases of Annotations](#special-cases-of-annotations)
11 * [Union Discriminators](#union-discriminators)
12 * [Base Types in Sequences](#base-types-in-sequences)
13 * [Base Types in Arrays](#base-types-in-arrays)
14 * [Defining Annotations](#defining-annotations)
15 * [`@document` Example](#document-example)
16 * [What Can Go in Annotations](#what-can-go-in-annotations)
17 * [Reading Annotations in the AST](#reading-annotations-in-the-ast)
18 * [Reading `@document` Annotations](#reading-document-annotations)
19 * [Reading Annotations Manually](#reading-annotations-manually)
20 * [Reading Special Cases of Annotations](#reading-special-cases-of-annotations)
21 * [Union Discriminators](#union-discriminators-1)
22 * [Base Types in Sequences](#base-types-in-sequences-1)
23 * [Base Types in Arrays](#base-types-in-arrays-1)
24 * [Extending Annotation Support](#extending-annotation-support)
25 * [Limitations](#limitations)
27 * [TAO 2.5.5](#tao-255)
28 * [TAO 2.5.6](#tao-256)
29 * [TAO 2.5.7](#tao-257)
30 * [TAO 2.5.10](#tao-2510)
34 Annotations are a feature of IDLv4 that allows IDL authors to pass hints to the
35 IDL compiler that can change compiler behavior and code generation. They are
36 similar to some uses of `#pragma`, but are more powerful because they are
37 integrated with IDL and are more expressive. In the latest IDL specification as
38 of writing, version 4.2, they are described in section 7.4.15.1.
40 The concept behind annotations exists in other languages like Java and Python,
41 as decorators, and in C++11 and C#, as attributes. Like Java and Python,
42 annotations can appear in front of declarations, have `@` at the beginning, and
43 look like function calls.
45 Here is an example of what IDL using some OMG standard annotations might look
51 @default_literal INFORMATIVE,
57 typedef short Hours_t;
60 typedef unsigned long Days_t;
82 ## What Can Be Annotated
84 Annotations "may be applied to any IDL constructs or sub-constructs", as
85 defined by the OMG. This is very vague and the OMG has not clarified this as of
86 IDL 4.2 [(Limitation #1)](#limitation1). Because of the lack of standardization
87 of what can be annotated and how, annotations for specific IDL elements have to
88 be added on a as-needed basis.
90 You can put annotations before the following things in IDL and a backend using
91 TAO IDL's front-end library can read them:
96 - structures and their member values
97 - unions and their cases
98 - enumerations and their enumerators
99 - interfaces, porttypes, eventtypes, components and all of their direct
101 - valuetypes and most of their direct contents with the exception of these
102 kinds of valuetype statements:
103 - import: not supported by TAO
104 - typeid: not supported by TAO within valuetypes
105 - typeprefix: No corresponding AST Node to attach annotations to
107 These are the general cases. The rest of the cases are defined in the next
108 section. If an annotation application isn't listed in the general case list or
109 the special case section, it is almost certainly not supported and might cause
110 warnings if the usage is a general case and syntax errors if the usage a
111 special case. See ["Extending Annotation
112 Support"](#extending-annotation-support) if you're interested in adding it and
113 are familiar with GNU Bison.
115 ### Special Cases of Annotations
117 The annotations on all the elements in the list above can be accessed using the
118 `annotations()` method covered later in [Reading Annotations in the
119 AST](#reading-annotations-in-the-ast). In the cases listed below, the
120 annotation is used within the declaration and therefore require special access
121 methods. See ["Reading Special Cases of
122 Annotations"](#reading-special-cases-of-annotations) for how to have a backend
123 read these kinds of annotations.
125 #### Union Discriminators
127 **[See Compiler Example](#union-discriminators-1)**
130 enum GradingSystem_t {
135 union Grade_t switch (@key GradingSystem_t) {
145 #### Base Types in Sequences
147 **[See Compiler Example](#base-types-in-sequences-1)**
153 typedef sequence<@external Report, 12> Dozen_Events;
156 #### Base Types in Arrays
158 **[See Compiler Example](#base-types-in-arrays-1)**
164 typedef Dozen_Events Event @external [12];
167 ## Defining Annotations
169 Annotations should be defined after the AST is initialized and ready to be
170 used, but before any user defined IDL is processed. The recommended place for
171 this is `BE_post_init ()` which is located in `be/be_init.cpp` in `tao_idl`.
172 Annotations are nodes in the AST and could be defined by hand, simulating what
173 happens in `fe/idl.yy`. However a string parsing utility has been added just
174 for this purpose, `idl_global->eval (const char* idl, bool disable_output =
175 false)`. `eval ()` processes IDL as if it were in an IDL file so annotations
176 can be defined using the IDL annotation notation. You can disable warning and
177 error messages generated by parsing by passing `true` as the second argument.
179 ### `@document` Example
181 As a simple example, if we wanted to make an annotation that inserted comments
182 into the product files for documentation purposes, we could design an
183 annotation like this:
186 @annotation document {
193 API_Type api_type default INTERNAL_API;
194 boolean deprecated default FALSE;
198 To use it without defining it in every IDL file, we need to embed it into
202 void BE_post_init (char *[], long)
205 if (idl_global->idl_version_ > IDL_VERSION_3)
208 "@annotation document {\n"
215 " API_Type api_type default INTERNAL_API;\n"
216 " boolean deprecated default FALSE;\n"
224 The new lines aren't strictly necessary but might help if a error occurs during
225 `eval` because it will refer to the line number of this string as though it was
226 a file called `builtin-N`, where `N` is times `eval` has been called.
228 By default TAO\_IDL uses IDL3 and this will cause an error when parsing the
229 annotations. Version is controlled using `--idl-version` command line argument
230 and ultimately `idl_global->idl_version_`. In the example above we would have
231 to pass `--idl-version 4`.
233 We can set it to use IDL4 by default in `BE_init ()`:
236 int BE_init (int &, ACE_TCHAR *[])
239 idl_global->default_idl_version_ = IDL_VERSION_4;
243 void BE_post_init (char *[], long)
249 In TAO\_IDL, `idl_global->default_idl_version_` sets `idl_global->idl_version_`
250 after `BE_init` is called but before arguments are parsed. This gives the user
251 a chance to override it if they really want to and allows them to query the
252 version we're setting using `--default-idl-version`.
254 Alternatively if it is desired to retain compatibility with older versions of
255 TAO, use the `TAO_IDL_HAS_ANNOTATIONS` macro.
258 int BE_init (int &, ACE_TCHAR *[])
261 #ifdef TAO_IDL_HAS_ANNOTATIONS
262 idl_global->default_idl_version_ = IDL_VERSION_4;
267 void BE_post_init (char *[], long)
270 #ifdef TAO_IDL_HAS_ANNOTATIONS
271 if (idl_global->idl_version_ > IDL_VERSION_3)
282 This would also be used when reading the annotations later.
284 <a name="document-usage"></a>
285 Once the annotation is declared, it can be used in IDL:
288 @document("Struct with 1 member")
294 comment="Struct with 2 members",
302 comment="Struct with 3 members",
311 However it won't do anything because nothing using the AST is looking for it,
312 so it will be ignored. To make the program aware of the annotations, see
313 ["Reading Annotations in the AST"](#reading-annotations-in-the-ast) below.
315 ### What Can Go in Annotations
317 - Annotation members can be of any type that constants can be. This includes
318 booleans, integers, floats, enumerations, characters, and strings.
319 - Enumerations, constants, and typedefs can be declared inside the annotation
320 declaration, however they can not used outside the annotation expect for when
321 passing them as parameters to the same annotation. Otherwise normal scope rules
322 apply: Valid constant types and values from outside the annotation can be used
325 ## Reading Annotations in the AST
327 To get the annotations for most nodes types, use
328 `node->annotations ().find (annotation_decl)` where `annotation_decl` can be the
329 `AST_Annotation_Decl` object or its canonical internal TAO IDL name (see next
330 paragraph). This will return the last `AST_Annotation_Appl*` of that type on
331 the node or `NULL` if there no annotation of that type. Because
332 `AST_Annotation_Appls::find` can take a `AST_Annotation_Decl`, they can be looked
333 up after `idl_eval` creates them and cached for a slightly faster
336 Internally, annotation local names are prefixed with `@` to prevent clashes
337 with other elements in IDL with the same name. For example when trying to use
338 `AST_Annotation_Appls::find (const char*)` with annotation named `bar` in a module
339 named `foo`, the proper internal scoped name to pass as the second argument is
340 either `foo::@bar` or `::foo::@bar` if we want to be explicit that `foo` is in
341 the root module. In IDL, this annotation's full name would be `@foo::bar`or
344 After that check, you can use index operators `[const char*]` on the annotation
345 to get the individual members and `value()` to get the value.
347 The last part is not straightforward, as the value is an `AST_Expression` object
348 and `AST_Expression` is a complex class that handles constant values in
349 TAO\_IDL. There are examples below but see `AST_Expression::AST_ExprValue` for
350 how values can be accessed.
352 See `include/ast_expression.h` and `ast/ast_expression.cpp` for how
353 to use `AST_Expression`.
355 ### Reading `@document` Annotations
357 In this example we will use the [`@document` annotation defined
358 above](#document-example) to generate Doxygen comments in the C++ code
359 generated. For simplicity's sake, we will limit this example to `struct`s defined
360 in TAO client headers. This can be accomplished by modifying the struct
361 visitor in `be/be_visitor_structure/structure_ch.cpp`.
363 At the top of the file, these includes should be added:
366 #include "ast_annotation_member.h"
367 #include "utl_string.h"
368 #include "ast_enum_val.h"
371 About midway though the file, in
372 `int be_visitor_structure_ch::visit_structure (be_structure *node)`
378 these lines would also need to be added:
381 AST_Annotation_Appl *document = node->annotations ().find ("::@document");
384 const char *comment =
385 dynamic_cast<AST_Annotation_Member *> ((*document)["comment"])->
386 value ()->ev ()->u.strval->get_string ();
389 dynamic_cast<AST_Annotation_Member *> ((*document)["deprecated"])->
390 value ()->ev ()->u.bval;
393 * This is more complicated because we are trying to get the name of
394 * the enumerator. If we just wanted the number value, we could treat the
395 * AST_Expresssion from the annotation member as an unsigned long by using
398 const char *api_type = 0;
399 AST_Expression *api_type_val =
400 dynamic_cast<AST_Annotation_Member *> ((*document)["api_type"])->
402 AST_Enum *api_type_enum = api_type_val->enum_parent();
405 AST_EnumVal *enum_val =
406 api_type_enum->lookup_by_value (api_type_val);
409 api_type = enum_val->local_name ()->get_string ();
415 << " * " << comment << be_nl
422 << " * API_TYPE: " << api_type << be_nl
430 << " * \\deprecated This is deprecated" << be_nl
437 Using the [`@document` use example from above](#document-usage), these are
438 inserted into the client header file:
443 * Struct with 1 member
445 * API_TYPE: INTERNAL_API
455 * Struct with 2 members
465 * Struct with 3 members
467 * API_TYPE: LEGACY_API
469 * \deprecated This is deprecated
478 #### Reading Annotations Manually
480 `AST_Annotation_Appls::find ()` is convenient but only returns the last
481 annotation of the passed annotation type. If we want the first one, handle
482 multiple annotations of the same type, read all the annotations, or some other
483 subset, we will have to do what `find ()` is doing for us, which is just
484 iterating over the `AST_Annotation_Appl`s and checking `annotation_decl ()`.
487 AST_Annotation_Appls &annotations = /* ... */;
488 AST_Annotation_Decl *annotation = /* ... */;
489 for (AST_Annotation_Appls::iterator i = annotations.begin ();
490 i != annotations.end (); ++i)
492 AST_Annotation_Appl *appl = i->get ();
493 if (appl && appl->annotation_decl () == annotation)
495 // Do work with annotation application
500 ### Reading Special Cases of Annotations
502 Annotations placed before a definition in a scope are interpreted as annotating
503 the node that is being defined. Annotations in other places require special
504 grammar and special handling in the API.
506 The following cases show how to read annotations from these special cases.
508 **NOTE:** To access these methods on a type that has been "`typedef`-ed", it
509 must be resolved completely using `AST_Type *primitive_base_type ()` and a
510 `dynamic_cast` to the correct type as these methods are specific to these
513 #### Union Discriminators
515 **[See IDL Example](#union-discriminators)**
518 AST_Union *node = /* ... */;
519 AST_Annotation_Appl *document = node->disc_annotations ().find ("::@key");
522 #### Base Types in Sequences
524 **[See IDL Example](#base-types-in-sequences)**
527 AST_Sequence *node = /* ... */;
528 AST_Annotation_Appl *document = node->base_type_annotations ().find ("::@external");
531 #### Base Types in Arrays
533 **[See IDL Example](#base-types-in-arrays)**
536 AST_Array *node = /* ... */;
537 AST_Annotation_Appl *document = node->base_type_annotations ().find ("::@external");
540 ## Extending Annotation Support
542 **NOTE: This section assumes familarity with GNU Bison and only covers the
543 general concept of extending annotation support.**
545 How to extend support for annotations on a particular IDL element depends on a
546 few things. In the `fe/idl.ypp` bison file, if the annotation would be matched
547 by the `at_least_one_definition` token, like it would when annotating a
548 structure, or by the `at_least_one_export` token, like it would be when
549 annotating a interface operation, the change is simple in principle:
551 1. Make sure the `AST_Decl*` node of what you want to annotate is being passed
552 up the to generic annotation code in `at_least_one_export` or
553 `at_least_one_definition`.
555 1. Implement `virutal bool annotatable() const` in the `AST_*` files of the
556 node type to return `true`. The default implementation of `AST_Decl` returns
559 If you want to implement a annotation that goes within an IDL element, like
560 annotating a union discriminator, that is more complicated. It will involve
561 modifying the grammar to accept the annotations and adding a special cases
562 method to the node's class, like in ["Reading Special Cases of
563 Annotations"](#reading-special-cases-of-annotations).
565 Finally, if you do extend annotation support, please update the annotation test
566 in `$TAO_ROOT/tests/IDLv4/annotations/be_init.cpp` and this file, specifically
567 the ["What Can Be Annotated"](#what-can-be-annotated) and ["History"](#history)
568 sections. Also update ["Reading Special Cases of
569 Annotations"](#reading-special-cases-of-annotations) if you've added support for
574 The current limitations exist in TAO\_IDL annotation implementation as of writing:
576 <a name="limitation1"></a>
577 1. Because of lack of any specification in IDL for where annotations can go,
578 annotations in places other than what's listed in ["What Can be
579 Annotated"](#what-can-be-annotated) can cause syntax errors, even if the IDL
580 works with other IDL tools.
582 2. Even though this is implicitly allowed by the IDL specification, Annotations
583 whose local names clash with IDL keywords are not supported. This includes
584 the OMG standard annotations `default` and `oneway`.
590 **Any usage of `UTL_find_annotation(X, Y)` should be replaced with `X.find(Y)`.**
592 After TAO 2.5.4 was released, which introduced annotations, there was a change
593 to fix memory leaks caused by annotations. This change involved replacing
594 `typedef ACE_Vector<AST_Annotation_Appl> AST_Annotation_Appls` with a class of
595 the same name. This also allowed for moving `UTL_find_annotation` into
596 `AST_Annotation_Appls` as `find` for a nicer design.
600 The TAO IDL Frontend no longer internally prefixes annotation names and
601 annotation member names with `_cxx_` if they are also a C++ keyword.
605 - The TAO IDL Frontend now supports annotations on interfaces, operations, and
608 - `idl_global->eval` now will produce error and warning messages. This can be
609 silenced by passing `true` as a second argument.
611 - Expanded documentation on what can be annotated and how to extend annotation
616 - Annotation support extended:
617 - All the direct contents of interfaces
618 - The porttypes, eventtypes, components and all their direct contents
619 - Valuetypes and most of their direct contents