1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Check that annotation present in the AST are either primitive or user-declared
16 # There is no verification on the syntax or the semantic of the annotation: just the name is checked
18 # Specific phases or tools have to process their annotation and check them correclty.
19 module check_annotation
22 private import annotation
24 redef class ToolContext
25 # Check for unknown annotation in each module
26 var check_annotation_phase
: Phase = new CheckAnnotationPhase(self, null)
29 private class CheckAnnotationPhase
32 # The map of all declared user annotation
33 # note: lazy because toolcontex is set in the init
34 var declared_annotations
= new MModuleMultiData[String](toolcontext
.modelbuilder
.model
) is lazy
37 var mmodule
: nullable MModule = null
39 redef fun process_nmodule
(nmodule
)
42 var mmodule
= nmodule
.mmodule
43 if mmodule
== null then return
44 self.mmodule
= mmodule
46 # If no decl block then quit
47 var nmoduledecl
= nmodule
.n_moduledecl
48 if nmoduledecl
== null then return
50 var modelbuilder
= toolcontext
.modelbuilder
52 # Get all the new annotations
53 var annots
= nmoduledecl
.get_annotations
("new_annotation")
55 var super_mmodules
= declared_annotations
.lookup_all_modules
(mmodule
, private_visibility
)
57 # Add each new annotations in the map
58 for annot
in annots
do
59 var name
= annot
.arg_as_id
(modelbuilder
)
60 if name
== null then continue
62 for m
in super_mmodules
do
63 if declared_annotations
[m
].has
(name
) then
64 modelbuilder
.warning
(annot
, "multiple-annotation-declarations", "Warning: an annotation `{name}` is already declared in module `{m}`.")
69 declared_annotations
[mmodule
].add
(name
)
70 #annot.debug "add {mmodule}: {name}"
74 # Raw new-line separated list of primitive annotation
75 # Note: empty-lines will be ignored since there is no annotation named by the empty string.
76 var primtives_annotations_list
= """
109 # Efficient set build from `primtives_annotations_list`
110 var primtives_annotations
= new HashSet[String].from
(primtives_annotations_list
.split
("\n"))
112 # All user-declared annotations for each mmodule
113 var user_annotations
= new HashMap[MModule, HashSet[String]]
115 redef fun process_annotated_node
(node
, nat
)
118 if primtives_annotations
.has
(name
) then return
120 var mmodule
= self.mmodule
121 if mmodule
== null then return
123 # Lazily build the full user-list
124 var annots
= user_annotations
.get_or_null
(mmodule
)
125 if annots
== null then
126 annots
= new HashSet[String]
127 annots
.add_all
(declared_annotations
.lookup_joined_values
(mmodule
, private_visibility
))
128 user_annotations
[mmodule
] = annots
130 #nat.debug "for {mmodule}: {annots.join(" ")}"
132 if annots
.has
(name
) then return
134 toolcontext
.modelbuilder
.warning
(nat
, "unknown-annotation", "Warning: unknown annotation `{name}`.")
136 annots
.add
(name
) # to avoid multiple errors on the same name