11# Flag each occurrence of a membership test of the form:
22# X in Subtype_Of_X
3+ # X in Subtype_Of_X'Range
34# X in Subtype_Of_X'First .. Subtype_Of_X'Last
45
56fun valid_attr(node) =
@@ -22,6 +23,7 @@ fun membership_for_validity(node) =
2223 |" Two forms of membership tests are flagged:
2324 |"
2425 |" * X in Subtype_Of_X
26+ |" * X in Subtype_Of_Y'Range
2527 |" * X in Subtype_Of_X'First .. Subtype_Of_X'Last
2628 |"
2729 |" where X is a data object except for a loop parameter, and ``Subtype_Of_X``
@@ -38,17 +40,31 @@ fun membership_for_validity(node) =
3840 |" begin
3941 |" if X in My_Int then -- FLAG
4042 node is MembershipExpr(f_expr: var@Name)
41- when not node.f_membership_exprs[2]
42- and match node.f_membership_exprs[1]
43- | n@Name => type_of(var) == n.p_referenced_decl()
44- | b@BinOp(f_op: OpDoubleDot,
45- f_left: at1@AttributeRef(f_prefix: typ1@Name)
46- when at1.f_attribute.p_name_is("First"),
47- f_right: at2@AttributeRef(f_prefix: typ2@Name)
48- when at2.f_attribute.p_name_is("Last")) =>
49- {
50- val var_type = type_of(var);
51- var_type == typ1.p_referenced_decl() and
52- var_type == typ2.p_referenced_decl()
53- }
54- | * => false
43+ when {
44+ val type = type_of(var);
45+
46+ fun is_of_type(ref) =
47+ # Return whether ref is of the type of this MembershipExpr's expr type
48+ ref is Name(p_referenced_decl(): typ@BaseTypeDecl when typ == type);
49+
50+ type != null
51+ and not node.f_membership_exprs[2]
52+ and node.f_membership_exprs[1] is (
53+ n@Name when is_of_type(n)
54+
55+ | bin_op@BinOp(f_op: OpDoubleDot,
56+ f_left: at1@AttributeRef(f_prefix: typ1)
57+ when at1.f_attribute.p_name_is("First")
58+ and at1.f_prefix is Name,
59+ f_right: at2@AttributeRef(f_prefix: typ2)
60+ when at2.f_attribute.p_name_is("Last")
61+ and at2.f_prefix is Name)
62+ when (
63+ typ1.p_referenced_decl() == typ2.p_referenced_decl()
64+ and type == typ1.p_referenced_decl()
65+ )
66+
67+ | attr_ref@AttributeRef(f_prefix: pfx when is_of_type(pfx),
68+ f_attribute: "Range")
69+ )
70+ }
0 commit comments