Attribute hygiene
This module provides hygiene for attributes. The goal is to report misuses of attributes to the user as soon as possible so that no mistyped attribute get silently ignored.
Type of declared attribute.
The 'context
type parameter describes where the attribute is expected and the
'payload
one what its payload should contain.
declare fully_qualified_name context payload_pattern k
declares an attribute. k
is
used to build the value resulting from parsing the payload.
For instance if a rewriter named "foo" expect the attribute @@default
on record
field declaration with an expression as payload:
let default =
Attribute.declare "foo.default"
Attribute.Context.label_declaration
Ast_pattern.(pstr (pstr_eval __ nil))
(fun x -> x)
;;
fully_qualified_name
is expected to be a dot-separated list of names. When matching,
any full suffix will be accepted. So for instance an attribute declared with name
"foo.bar.default" will match exactly these attribute names: "default", "bar.default"
and "foo.bar.default".
When matching against a list of attributes on an item, if several matches are
possible, the longest one is used. For instance using the attribute "foo.default"
declared in the previous example, on this code it will match the @foo.default 0
attribute:
type t =
{ x : int [@default 42] [@foo.default 0]
}
This is to allow the user to specify a @default
attribute for all re-writers that
use it but still put a specific one for one specific re-writer.
It is not allowed to declare an attribute with a name that matches a previously-defined one on the same context. For instance trying to declare the same attribute twice will fail.
reserve_namespace "foo"
has two implications:
check_unused
This is here to insure that the rewriter cohabits well with other rewriter or tools (e.g. merlin) which might leave attribute on the AST.
N.B. the "merlin" namespace is reserved by default.
consume t x
returns the value associated to attribute t
on x
if present as well
as x
with t
removed.
Code that is voluntarily dropped by a rewriter needs to be given to this object. All attributes inside will be marked as handled.
Raise if there are unused attributes
Replace all attribute names by a String.copy
and collect them. To be used in
conjuction with check_all_seen.
Check that all attributes collected by freshen_and_collect have been:
check_unused
(to allow white-listed attributed to pass through)This helps with faulty ppx rewriters that silently drop attributes.
Mark an attribute as seen and handled. This is only to make ppx rewriters that don't use ppx_core works well with ppx_driver.
Return the list of attributes that have been dropped so far: attributes that haven't been marked and are not present in the given AST. This is used to debug extensions that drop attributes.