Skip to main content

luaur_analysis/functions/
lint.rs

1//! C++ free function `lint` (`Analysis/src/Linter.cpp:3517`).
2
3use alloc::vec::Vec;
4
5use luaur_ast::records::ast_name_table::AstNameTable;
6use luaur_ast::records::ast_stat::AstStat;
7use luaur_ast::records::hot_comment::HotComment;
8use luaur_config::enums::code::Code;
9use luaur_config::records::lint_options::LintOptions;
10use luaur_config::records::lint_warning::LintWarning;
11
12use crate::functions::fill_builtin_globals::fill_builtin_globals;
13use crate::functions::has_native_comment_directive::has_native_comment_directive;
14use crate::functions::lint_comments::lint_comments;
15use crate::records::lint_context::LintContext;
16use crate::records::lint_deprecated_api::LintDeprecatedApi;
17use crate::records::lint_duplicate_condition::LintDuplicateCondition;
18use crate::records::lint_duplicate_function::LintDuplicateFunction;
19use crate::records::lint_duplicate_local::LintDuplicateLocal;
20use crate::records::lint_for_range::LintForRange;
21use crate::records::lint_format_string::LintFormatString;
22use crate::records::lint_global_local::LintGlobalLocal;
23use crate::records::lint_integer_parsing::LintIntegerParsing;
24use crate::records::lint_misleading_and_or::LintMisleadingAndOr;
25use crate::records::lint_multi_line_statement::LintMultiLineStatement;
26use crate::records::lint_same_line_statement::LintSameLineStatement;
27use crate::records::lint_table_literal::LintTableLiteral;
28use crate::records::lint_table_operations::LintTableOperations;
29use crate::records::lint_uninitialized_local::LintUninitializedLocal;
30use crate::records::lint_unreachable_code::LintUnreachableCode;
31use crate::records::lint_unused_function::LintUnusedFunction;
32use crate::records::warning_comparator::WarningComparator;
33use crate::type_aliases::scope_ptr_type::ScopePtr;
34
35use crate::methods::lint_implicit_return_process::lint_implicit_return_process;
36use crate::methods::lint_local_hygiene_process::lint_local_hygiene_process;
37use crate::methods::lint_redundant_native_attribute_process::lint_redundant_native_attribute_process;
38use crate::methods::lint_unbalanced_assignment_process::lint_unbalanced_assignment_process;
39use crate::methods::lint_unknown_type_process::lint_unknown_type_process;
40use crate::records::lint_comparison_precedence::LintComparisonPrecedence;
41
42use crate::records::module::Module;
43
44pub fn lint(
45    root: *mut AstStat,
46    names: &AstNameTable,
47    env: &ScopePtr,
48    module: *const Module,
49    hotcomments: &[HotComment],
50    options: &LintOptions,
51) -> Vec<LintWarning> {
52    let mut context = LintContext {
53        result: Vec::new(),
54        options: *options,
55        root,
56        placeholder: names.get(c"_".as_ptr()),
57        builtin_globals: luaur_common::records::dense_hash_map::DenseHashMap::new(
58            luaur_ast::records::ast_name::AstName::new(),
59        ),
60        scope: env.clone(),
61        module,
62    };
63
64    fill_builtin_globals(&mut context, names, env);
65
66    if context.warning_enabled(Code::Code_UnknownGlobal)
67        || context.warning_enabled(Code::Code_DeprecatedGlobal)
68        || context.warning_enabled(Code::Code_GlobalUsedAsLocal)
69        || context.warning_enabled(Code::Code_PlaceholderRead)
70        || context.warning_enabled(Code::Code_BuiltinGlobalWrite)
71    {
72        LintGlobalLocal::process(&mut context);
73    }
74
75    if context.warning_enabled(Code::Code_MultiLineStatement) {
76        LintMultiLineStatement::new(core::ptr::null_mut()).process(&mut context);
77    }
78
79    if context.warning_enabled(Code::Code_SameLineStatement) {
80        LintSameLineStatement::new(core::ptr::null_mut()).process(&mut context);
81    }
82
83    if context.warning_enabled(Code::Code_LocalShadow)
84        || context.warning_enabled(Code::Code_FunctionUnused)
85        || context.warning_enabled(Code::Code_ImportUnused)
86        || context.warning_enabled(Code::Code_LocalUnused)
87    {
88        lint_local_hygiene_process(&mut context);
89    }
90
91    if context.warning_enabled(Code::Code_FunctionUnused) {
92        LintUnusedFunction::new().process(&mut context);
93    }
94
95    if context.warning_enabled(Code::Code_UnreachableCode) {
96        LintUnreachableCode::process(&mut context);
97    }
98
99    if context.warning_enabled(Code::Code_UnknownType) {
100        lint_unknown_type_process(&mut context);
101    }
102
103    if context.warning_enabled(Code::Code_ForRange) {
104        LintForRange::process(&mut context);
105    }
106
107    if context.warning_enabled(Code::Code_UnbalancedAssignment) {
108        lint_unbalanced_assignment_process(&mut context);
109    }
110
111    if context.warning_enabled(Code::Code_ImplicitReturn) {
112        lint_implicit_return_process(&mut context);
113    }
114
115    if context.warning_enabled(Code::Code_FormatString) {
116        LintFormatString {
117            context: core::ptr::null_mut(),
118        }
119        .process(&mut context);
120    }
121
122    if context.warning_enabled(Code::Code_TableLiteral) {
123        LintTableLiteral {
124            context: core::ptr::null_mut(),
125        }
126        .process(&mut context);
127    }
128
129    if context.warning_enabled(Code::Code_UninitializedLocal) {
130        LintUninitializedLocal::process(&mut context);
131    }
132
133    if context.warning_enabled(Code::Code_DuplicateFunction) {
134        LintDuplicateFunction::new(&mut context as *mut LintContext).process();
135    }
136
137    if context.warning_enabled(Code::Code_DeprecatedApi) {
138        LintDeprecatedApi {
139            context: core::ptr::null_mut(),
140            function_type_scope_stack: Vec::new(),
141        }
142        .process(&mut context);
143    }
144
145    if context.warning_enabled(Code::Code_TableOperations) {
146        LintTableOperations::process(&mut context);
147    }
148
149    if context.warning_enabled(Code::Code_DuplicateCondition) {
150        LintDuplicateCondition {
151            context: &mut context as *mut LintContext,
152        }
153        .process();
154    }
155
156    if context.warning_enabled(Code::Code_DuplicateLocal) {
157        LintDuplicateLocal::process(&mut context);
158    }
159
160    if context.warning_enabled(Code::Code_MisleadingAndOr) {
161        LintMisleadingAndOr {
162            context: core::ptr::null_mut(),
163        }
164        .process(&mut context);
165    }
166
167    if context.warning_enabled(Code::Code_CommentDirective) {
168        lint_comments(&mut context, hotcomments);
169    }
170
171    if context.warning_enabled(Code::Code_IntegerParsing) {
172        LintIntegerParsing::process(&mut context);
173    }
174
175    if context.warning_enabled(Code::Code_ComparisonPrecedence) {
176        LintComparisonPrecedence::process(&mut context);
177    }
178
179    if context.warning_enabled(Code::Code_RedundantNativeAttribute) {
180        if has_native_comment_directive(hotcomments) {
181            lint_redundant_native_attribute_process(&mut context);
182        }
183    }
184
185    let comparator = WarningComparator::default();
186    context.result.sort_by(|lhs, rhs| {
187        let c = comparator.compare_location_location(&lhs.location, &rhs.location);
188        if c != 0 {
189            return c.cmp(&0);
190        }
191        (lhs.code as i32).cmp(&(rhs.code as i32))
192    });
193
194    context.result
195}