extern crate rustc_ast;
use rustc_ast::{Item, ItemKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use crate::lint_utils::is_in_api_rest_folder;
dylint_linting::declare_pre_expansion_lint! {
#[doc = include_str!("../../docs/de02_api_layer/de0203_dtos_must_use_api_dto/README.md")]
pub DE0203_DTOS_MUST_USE_API_DTO,
Deny,
"DTO types must use the api_dto macro (DE0203)"
}
impl EarlyLintPass for De0203DtosMustUseApiDto {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
check_dto_uses_api_dto(cx, item);
}
}
fn check_dto_uses_api_dto(cx: &EarlyContext<'_>, item: &Item) {
if !matches!(item.kind, ItemKind::Struct(..) | ItemKind::Enum(..)) {
return;
}
if !is_in_api_rest_folder(cx.sess().source_map(), item.span) {
return;
}
let item_name = match &item.kind {
ItemKind::Struct(ident, _, _) => ident.name.as_str(),
ItemKind::Enum(ident, _, _) => ident.name.as_str(),
_ => return,
};
let item_name_lower = item_name.to_lowercase();
if !item_name_lower.ends_with("dto") {
return;
}
if crate::lint_utils::has_api_dto_attribute(item) {
return;
}
cx.span_lint(DE0203_DTOS_MUST_USE_API_DTO, item.span, |diag| {
diag.primary_message("api/rest DTO type must use the api_dto macro (DE0203)");
diag.help("Use #[modkit_macros::api_dto(request)] for request DTOs, #[modkit_macros::api_dto(response)] for response DTOs, or #[modkit_macros::api_dto(request, response)] for both");
});
}