1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use anyhow::{Ok, Result};
use serde::Serialize;
use std::{collections::HashMap, ffi, path::PathBuf};

#[derive(Default, Debug, Clone, Serialize)]
pub struct RawLintInfo {
    pub id: ffi::CString,
    pub name: ffi::CString,
    pub short_message: ffi::CString,
    pub long_message: ffi::CString,
    pub severity: ffi::CString,
    pub help: ffi::CString,
    pub vulnerability_class: ffi::CString,
}

#[derive(Default, Debug, Clone, Serialize)]
pub struct LintInfo {
    pub id: String,
    pub name: String,
    pub short_message: String,
    pub long_message: String,
    pub severity: String,
    pub help: String,
    pub vulnerability_class: String,
}

impl From<&RawLintInfo> for LintInfo {
    fn from(info: &RawLintInfo) -> Self {
        LintInfo {
            id: info.id.to_str().unwrap().to_string(),
            name: info.name.to_str().unwrap().to_string(),
            short_message: info.short_message.to_str().unwrap().to_string(),
            long_message: info.long_message.to_str().unwrap().to_string(),
            severity: info.severity.to_str().unwrap().to_string(),
            help: info.help.to_str().unwrap().to_string(),
            vulnerability_class: info.vulnerability_class.to_str().unwrap().to_string(),
        }
    }
}

type LintInfoFunc = unsafe fn(info: &mut RawLintInfo);

pub fn get_detectors_info(detectors_paths: &Vec<PathBuf>) -> Result<HashMap<String, LintInfo>> {
    let mut lint_store = HashMap::<String, LintInfo>::default();

    for detector_path in detectors_paths {
        unsafe {
            let lib_res = libloading::os::unix::Library::open(
                Some(detector_path),
                libloading::os::unix::RTLD_LAZY | libloading::os::unix::RTLD_LOCAL,
            );

            let lib = lib_res.unwrap();
            let lint_info_func_res = lib.get::<LintInfoFunc>(b"lint_info");
            if lint_info_func_res.is_ok() {
                let lint_info_func = lint_info_func_res.unwrap();
                let mut info = RawLintInfo::default();
                lint_info_func(&mut info);
                let lint_info = LintInfo::from(&info);
                lint_store.insert(lint_info.id.clone(), lint_info);
            }
        }
    }
    Ok(lint_store)
}