fn validate_library(metadata: &ContractMetadata, diagnostics: &mut Vec<Diagnostic>) {
if !metadata.is_library {
return;
}
if matches!(
metadata.name.as_str(),
"Runtime" | "Storage" | "Syscalls" | "NativeCalls" | "Neo" | "abi"
) {
return;
}
for state in &metadata.state_variables {
if !state.is_constant {
diagnostics.push(
Diagnostic::error(format!(
"library '{}' cannot have state variable '{}'; \
libraries are stateless and cannot hold mutable storage",
metadata.name,
state.name.as_deref().unwrap_or("<unnamed>"),
))
.with_suggestion(
"move the state variable into a contract, or declare it as 'constant'",
),
);
}
}
for method in &metadata.methods {
if matches!(method.kind, FunctionKind::Constructor) {
diagnostics.push(
Diagnostic::error(format!(
"library '{}' cannot have a constructor; \
libraries are not deployable and cannot be initialized",
metadata.name,
))
.with_suggestion("remove the constructor from the library"),
);
}
}
for method in &metadata.methods {
if !matches!(method.kind, FunctionKind::Regular) {
continue;
}
match method.visibility {
VisibilityKind::External => {
diagnostics.push(
Diagnostic::warning(format!(
"library '{}' function '{}' is declared `external`; \
on NeoVM, user-defined library functions are inlined into \
the consuming contract, so `external` visibility is \
normalized to an internal helper",
metadata.name, method.name,
))
.with_code("W124")
.with_suggestion(
"prefer `internal` visibility for library helpers to match Neo lowering semantics",
),
);
}
VisibilityKind::Public => {
diagnostics.push(
Diagnostic::warning(format!(
"library '{}' function '{}' is declared `public`; \
on NeoVM, library functions are inlined into the calling \
contract and `public` visibility has no effect",
metadata.name, method.name,
))
.with_code("W120")
.with_suggestion(
"use `internal` or `pure` visibility for library functions",
),
);
}
_ => {}
}
}
}