11import stdlib
22
3- fun get_derived(t, derived) = {
4- |" Return the element from derived corresponding to t, if any, or ""
5- val name = t.p_canonical_type()
6- .p_canonical_fully_qualified_name();
7- val res = [n for n in derived if name == n.split(":")[1]].to_list;
8- if not res then "" else res[res.length]
9- }
10-
113fun is_class_access(type_decl) =
124 |" Given a TypeDecl node, return whether the declared type is an access
135 |" to classwide values.
@@ -191,6 +183,8 @@ fun identifier_prefixes(
191183 |" Exc_2 : exception; -- FLAG
192184 |" end Foo;
193185 {
186+ val str_prefix = " does not start with ";
187+
194188 fun check_exclusive(
195189 str,
196190 type_exclusive=true,
@@ -215,167 +209,191 @@ fun identifier_prefixes(
215209 );
216210
217211 fun check_enum(str) =
218- (enum != "-" and not str.starts_with(enum))
219- or check_exclusive(str, enum_exclusive=false);
220-
221- val str_prefix = " does not start with ";
212+ if (
213+ (enum != "-" and not str.starts_with(enum))
214+ or check_exclusive(str, enum_exclusive=false)
215+ )
216+ then str_prefix & "enumeration prefix " & enum
217+ else ();
222218
223- [{message: n.text &
224- (match n.parent
225- | p@(TaskTypeDecl | ProtectedTypeDecl |
226- SubtypeDecl(p_canonical_type(): TaskTypeDecl | ProtectedTypeDecl))
227- when p is not SingleTaskTypeDecl and concurrent != "-"
228- => str_prefix & "concurrent prefix " & concurrent
229- | (TypeDecl(f_type_def: TypeAccessDef(f_subtype_indication: *(f_name:
230- AttributeRef(f_attribute: Identifier(p_name_is("Class"): true))))) |
231- SubtypeDecl(p_canonical_type(): TypeDecl(f_type_def:
232- TypeAccessDef(f_subtype_indication: *(f_name:
233- AttributeRef(f_attribute: Identifier(p_name_is("Class"): true)))))))
234- when class_access != "-" => str_prefix & "access-to-class prefix " & class_access
235- | (TypeDecl(f_type_def: AccessToSubpDef) |
236- SubtypeDecl(p_canonical_type():
237- TypeDecl(f_type_def: AccessToSubpDef)))
238- when subprogram_access != "-" =>
239- str_prefix & "access-to-subprogram prefix " & subprogram_access
240- | (TypeDecl(f_type_def: AccessDef) |
241- SubtypeDecl(p_canonical_type(): TypeDecl(f_type_def: AccessDef)))
242- when access != "-" => str_prefix & "access prefix " & access
219+ @memoized
220+ fun get_derived(t) = {
221+ |" Return the element from derived corresponding to t, if any, or ""
222+ val name = t.p_canonical_type()
223+ .p_canonical_fully_qualified_name();
224+ val res = [n for n in derived if name == n.split(":")[1]].to_list;
225+ if not res then "" else res[res.length]
226+ };
243227
244- | p@(TypeDecl(f_type_def: DerivedTypeDef) | SubtypeDecl)
245- when derived != [] and
246- p.p_canonical_type().p_base_type() is t@BaseTypeDecl
247- when get_derived(t, derived) != ""
248- => {
249- val t = p.p_canonical_type().p_base_type();
250- str_prefix & "derived prefix " & get_derived(t, derived)
251- .split(":")[2]
252- }
228+ fun check_prefix(name) =
229+ |" Given a DefiningName, check that it is validating all expressed
230+ |" prefix constraints. Returns a string containing the message
231+ |" explaining the constraint violation if the defining name is
232+ |" invalid, unit else.
233+ match name.parent
234+ # Concurrent types
235+ | p@(TaskTypeDecl | ProtectedTypeDecl | TaskBody | ProtectedBody
236+ | SubtypeDecl(p_canonical_type(): TaskTypeDecl | ProtectedTypeDecl))
237+ when p is not SingleTaskTypeDecl
238+ and concurrent != "-"
239+ =>
240+ if (
241+ p.p_previous_part() is (null | IncompleteTypeDecl) and (
242+ not name.f_name.text.starts_with(concurrent)
243+ or check_exclusive(name.f_name.text, concurrent_exclusive=false)
244+ )
245+ )
246+ then str_prefix & "concurrent prefix " & concurrent
247+ else ()
253248
254- | BaseTypeDecl => str_prefix & "subtype prefix " & type
255- | EnumLiteralDecl => str_prefix & "enumeration prefix " & enum
256- | p => match p.parent
257- | (ObjectDecl | NumberDecl) =>
258- str_prefix & "constant prefix " & constant
259- | SubpRenamingDecl => str_prefix & "enumeration prefix " & enum
260- | ExceptionDecl => str_prefix & "exception prefix " & exception
261- | * => " does not have an exclusive prefix"),
262- loc: n}
263- for n in from unit.root select node@DefiningName when match node.parent
264- # Concurrent types
265- | p@(TaskTypeDecl | ProtectedTypeDecl | TaskBody | ProtectedBody |
266- SubtypeDecl(p_canonical_type(): TaskTypeDecl | ProtectedTypeDecl))
267- when p is not SingleTaskTypeDecl and concurrent != "-"
268- =>
269- p.p_previous_part() is (null | IncompleteTypeDecl) and
270- (
271- if node.f_name.text.starts_with(concurrent)
272- then check_exclusive(node.f_name.text, concurrent_exclusive=false)
273- )
249+ # 'Class access
250+ | (
251+ p@TypeDecl when is_class_access(p)
252+ | p@SubtypeDecl(
253+ p_canonical_type(): td@TypeDecl when is_class_access(td)
254+ )
255+ ) when class_access != "-"
256+ =>
257+ if (
258+ p.p_previous_part() is (null | IncompleteTypeDecl) and (
259+ not name.f_name.text.starts_with(class_access)
260+ or check_exclusive(name.f_name.text, class_access_exclusive=false)
261+ )
262+ )
263+ then str_prefix & "access-to-class prefix " & class_access
264+ else ()
274265
275- # 'Class access
276- | (
277- p@TypeDecl when is_class_access(p) |
278- p@SubtypeDecl(
279- p_canonical_type(): td@TypeDecl when is_class_access(td)
280- )
281- ) when class_access != "-"
282- =>
283- p?.p_previous_part() is (null | IncompleteTypeDecl)
284- and (
285- if node.f_name.text.starts_with(class_access)
286- then check_exclusive(node.f_name.text, class_access_exclusive=false)
287- )
266+ # Subprogram access
267+ | (
268+ p@TypeDecl(f_type_def: AccessToSubpDef)
269+ | p@SubtypeDecl(
270+ p_canonical_type(): TypeDecl(f_type_def: AccessToSubpDef)
271+ )
272+ ) when subprogram_access != "-"
273+ =>
274+ if (
275+ p.p_previous_part() is (null | IncompleteTypeDecl) and (
276+ not name.f_name.text.starts_with(subprogram_access)
277+ or check_exclusive(name.f_name.text, subprogram_access_exclusive=false)
278+ )
279+ )
280+ then str_prefix & "access-to-subprogram prefix " & subprogram_access
281+ else ()
288282
289- # Subprogram access
290- | (
291- p@TypeDecl(f_type_def: AccessToSubpDef)
292- | p@SubtypeDecl(
293- p_canonical_type(): TypeDecl(f_type_def: AccessToSubpDef)
294- )
295- ) when subprogram_access != "-"
296- =>
297- p?.p_previous_part() is (null | IncompleteTypeDecl)
298- and (
299- if node.f_name.text.starts_with(subprogram_access)
300- then check_exclusive(node.f_name.text, subprogram_access_exclusive=false)
301- )
283+ # Other access types
284+ | (
285+ p@TypeDecl(f_type_def: AccessDef)
286+ | p@SubtypeDecl(
287+ p_canonical_type(): TypeDecl(f_type_def: AccessDef)
288+ )
289+ ) when access != "-"
290+ =>
291+ if (
292+ p.p_previous_part() is (null | IncompleteTypeDecl) and (
293+ not name.f_name.text.starts_with(access)
294+ or check_exclusive(
295+ name.f_name.text,
296+ access_exclusive=false,
297+ # If both an Access prefix and a Type prefix are
298+ # set and the type prefix is a prefix of the access
299+ # prefix, we don't want to flag this access because
300+ # it broke the exclusivity of the type prefix.
301+ type_exclusive=false
302+ )
303+ )
304+ )
305+ then str_prefix & "access prefix " & access
306+ else ()
302307
303- # Other access types
304- | (
305- p@TypeDecl(f_type_def: AccessDef)
306- | p@SubtypeDecl(p_canonical_type(): TypeDecl(f_type_def: AccessDef))
307- ) when access != "-"
308- =>
309- p?.p_previous_part() is (null | IncompleteTypeDecl)
310- and (
311- if node.f_name.text.starts_with(access)
312- then check_exclusive(
313- node.f_name.text,
314- access_exclusive=false,
315- # If both an Access prefix and a Type prefix are
316- # set and the type prefix is a prefix of the access
317- # prefix, we don't want to flag this access because
318- # it broke the exclusivity of the type prefix.
319- type_exclusive=false
308+ # (Sub)Types derived from `derived`
309+ | p@(TypeDecl(f_type_def: DerivedTypeDef) | SubtypeDecl)
310+ when derived != []
311+ and p.p_canonical_type().p_base_type() is t@BaseTypeDecl
312+ when get_derived(t) != ""
313+ => {
314+ val derived_res = get_derived(p.p_canonical_type().p_base_type());
315+ if (
316+ p.p_previous_part() is (null | IncompleteTypeDecl) and (
317+ derived_res != ""
318+ and not name.f_name.text.starts_with(derived_res.split(":")[2])
319+ )
320320 )
321- )
321+ then str_prefix & "derived prefix " & derived_res.split(":")[2]
322+ else ()
323+ }
322324
323- # (Sub)Types derived from `derived`
324- | p@(TypeDecl(f_type_def: DerivedTypeDef) | SubtypeDecl)
325- when derived != []
326- and p.p_canonical_type().p_base_type() is t@BaseTypeDecl
327- when get_derived(t, derived) != ""
328- => {
329- val t = p.p_canonical_type().p_base_type();
330- p.p_previous_part() is (null | IncompleteTypeDecl)
331- and not node.f_name.text.starts_with(
332- get_derived(t, derived).split(":")[2]
333- )
334- }
325+ # Exclude IncompleteTypeDecl
326+ | IncompleteTypeDecl => ()
335327
336- # Exclude IncompleteTypeDecl
337- | IncompleteTypeDecl => false
328+ # Other types and subtypes
329+ | p@BaseTypeDecl
330+ when p is not SingleTaskTypeDecl
331+ =>
332+ if (
333+ p.p_previous_part() is (null | IncompleteTypeDecl) and (
334+ (type != "-" and not name.f_name.text.starts_with(type))
335+ or check_exclusive(name.f_name.text, type_exclusive=false)
336+ )
337+ )
338+ then str_prefix & "subtype prefix " & type
339+ else ()
338340
339- # Other types and subtypes
340- | p@BaseTypeDecl when p is not SingleTaskTypeDecl =>
341- p.p_previous_part() is (null | IncompleteTypeDecl)
342- and (
343- (type != "-" and not node.f_name.text.starts_with(type))
344- or check_exclusive(node.f_name.text, type_exclusive=false)
345- )
341+ # Enums
342+ | EnumLiteralDecl => check_enum(name.f_name.text)
346343
347- # Enums
348- | EnumLiteralDecl => check_enum(node.f_name.text)
344+ # Look one level up for remaining cases
345+ | p => match p.parent
346+ # Constants
347+ | (
348+ ObjectDecl(p_is_constant_object(): true)
349+ | NumberDecl
350+ ) =>
351+ if (
352+ name.p_previous_part() is null and (
353+ (constant != "-" and not name.f_name.text.starts_with(constant))
354+ or check_exclusive(name.f_name.text, constant_exclusive=false)
355+ )
356+ )
357+ then str_prefix & "constant prefix " & constant
358+ else ()
349359
350- # Look one level up for remaining cases
351- | p => match p.parent
352- # Constants
353- | (
354- ObjectDecl(p_is_constant_object(): true) when not node.p_previous_part()
355- | NumberDecl
356- ) =>
357- (constant != "-" and not node.f_name.text.starts_with(constant))
358- or check_exclusive(node.f_name.text, constant_exclusive=false)
359360
361+ # Function renaming an enum literal
362+ | r@SubpRenamingDecl
363+ when r.f_renames?.f_renamed_object?.p_referenced_decl?() is EnumLiteralDecl
364+ =>
365+ check_enum(name.f_name.text)
366+
367+ # Exceptions
368+ | ExceptionDecl =>
369+ if (
370+ (exception != "-" and not name.f_name.text.starts_with(exception))
371+ or check_exclusive(name.f_name.text, exception_exclusive=false)
372+ )
373+ then str_prefix & "exception prefix " & exception
374+ else ()
360375
361- # Function renaming an enum literal
362- | r@SubpRenamingDecl
363- when r.f_renames?.f_renamed_object?.p_referenced_decl() is EnumLiteralDecl
364- => check_enum(node.f_name.text)
376+ # Avoid checking declaration completions
377+ | p@(BodyNode | SubpRenamingDecl | ObjectDecl) => {
378+ val n = if p is ObjectDecl then name else p;
379+ if n.p_previous_part() is null and check_exclusive(name.f_name.text)
380+ then " does not have an exclusive prefix"
381+ else ()
382+ }
365383
366- # Exceptions
367- | ExceptionDecl =>
368- (exception != "-" and not node.f_name.text.starts_with(exception))
369- or check_exclusive(node.f_name.text, exception_exclusive=false)
384+ # All other cases, check the exclusivity
385+ | * =>
386+ if check_exclusive(name.f_name.text)
387+ then " does not have an exclusive prefix"
388+ else ();
370389
371- # Check all other defining names for exclusion except for completions
372- # and renaming-as-body
373- | p2 =>
374- (
375- if p2 is (BodyNode | SubpRenamingDecl)
376- then not p2.p_previous_part()
377- ) and (
378- if p2 is ObjectDecl
379- then not node.p_previous_part()
380- ) and check_exclusive(node.f_name.text)]
390+ # Iterate over all defining names and check prefixes for each
391+ [
392+ {message: s[1].text & s[2], loc: s[1]}
393+ for s in [
394+ (n, check_prefix(n))
395+ for n in from unit.root select DefiningName
396+ ]
397+ if s[2] != ()
398+ ]
381399 }
0 commit comments