W0084 - attribute_order
Severity: Warning
Problem
This diagnostic fires when module-level attributes do not follow the order configured for the linter.
-module(main).
-compile(warn_missing_spec_all).
-oncall("an_oncall").
%% ^^^^^^^^^^^^^^^^^^^ 💡 warning: W0084: `-oncall` must appear before `-compile`.
Explanation
Some codebases mandate a fixed ordering for module-level attributes so that file
headers stay consistent and easy to scan. This diagnostic enforces the order you
configure in the [attribute_order] section of .elp_lint.toml:
[attribute_order]
order = [
"module",
"author",
"oncall",
"moduledoc",
"compile",
"behaviour",
"export",
"export_type",
["include", "include_lib"],
["type", "opaque", "nominal", "define", "record"],
]
Each entry is either a single attribute name or a group — a list of names
that share one rank, so any order among them is accepted. Above, -include and
-include_lib are interchangeable.
-type / -opaque / -nominal, -define and -record are grouped together
on purpose: Erlang requires a record or macro used inside a type to be declared
before it, so a fixed order among them (e.g. type before record) would
flag — and a reorder would break — otherwise-valid modules. Keeping them in one
rank enforces only that definitions come after the header block, not their
internal order.
Attributes are matched by name. Custom (wild) attributes — e.g. -author,
-oncall, or a project-specific -my_attr — match their literal name.
Structured attributes are matched by a canonical keyword:
module, moduledoc, doc, compile, behaviour (covers both -behaviour
and -behavior), callback, optional_callbacks, export, export_type,
import, import_record, export_record, deprecated, feature, include,
include_lib, type, opaque, nominal, define, and record.
Only the names listed in order are checked, and a listed name that doesn't
match any attribute in a given file is simply ignored — it never triggers or
anchors a violation. Only Erlang modules (.erl) are checked; header files
(.hrl) are skipped, so the include-guard idiom — a -define guard preceding
the file's -include_lib directives — is never reported. Ordering is checked
per module, so attributes pulled in from an included header are not mixed with
the including module's attributes.
The linter is enabled by default but is a no-op until an order is
configured — without an order section it reports nothing.
Fix
Reorder the attributes to match the configured order.