slicec 0.4.0

The Slice parser and other core components for Slice compilers.
Documentation
// Copyright (c) ZeroC, Inc.

use super::*;

/// All the valid arguments that can be supplied to the `allow` metadata, or the `--allow` command line option.
pub const ALLOWABLE_LINT_IDENTIFIERS: [&str; 6] = [
    "All",
    "DuplicateFile",
    "Deprecated",
    "MalformedDocComment",
    "IncorrectDocComment",
    "BrokenDocLink",
];

#[derive(Debug)]
pub struct Allow {
    pub allowed_lints: Vec<String>,
}

impl Allow {
    pub fn parse_from(Unparsed { directive, args }: &Unparsed, span: &Span, diagnostics: &mut Diagnostics) -> Self {
        debug_assert_eq!(directive, Self::directive());

        check_argument_count_is_within(1..usize::MAX, args, Self::directive(), span, diagnostics);

        for arg in args {
            let mut is_valid = ALLOWABLE_LINT_IDENTIFIERS.contains(&arg.as_str());

            // The `DuplicateFile` lint can't be configured by attributes because it's a command-line specific lint.
            if arg == "DuplicateFile" {
                is_valid = false;
            }

            // Report an error if the argument wasn't valid.
            if !is_valid {
                // TODO we should emit a link to the lint page when we write it!
                let mut error = Diagnostic::from_error(Error::InvalidAttributeArgument {
                    directive: "allow".to_owned(),
                    argument: arg.to_owned(),
                })
                .set_span(span);

                // Check if the argument only differs in case from a valid one.
                let suggestion = ALLOWABLE_LINT_IDENTIFIERS
                    .iter()
                    .find(|identifier| identifier.eq_ignore_ascii_case(arg));
                if let Some(identifier) = suggestion {
                    let message = format!("attribute arguments are case sensitive, perhaps you meant '{identifier}'?");
                    error = error.add_note(message, None);
                }

                error.push_into(diagnostics);
            }
        }

        let allowed_lints = args.clone();
        Allow { allowed_lints }
    }

    pub fn validate_on(&self, applied_on: Attributables, span: &Span, diagnostics: &mut Diagnostics) {
        if matches!(applied_on, Attributables::Module(_) | Attributables::TypeRef(_)) {
            report_invalid_attribute(self, span, None, diagnostics);
        }
    }
}

implement_attribute_kind_for!(Allow, "allow", true);