use crate::assemble::line_no;
use crate::diagnostics::{Diag, Severity};
use std::path::Path;
pub fn run_lints(target: &Path, source: &str) -> Vec<Diag> {
let mut out = Vec::new();
es3_legacy(target, source, &mut out);
out
}
fn es3_legacy(target: &Path, source: &str, out: &mut Vec<Diag>) {
let is_es3 = source.lines().any(|l| {
let t = l.trim_start();
t.starts_with("#version") && t.contains("300") && t.contains("es")
});
if !is_es3 {
return;
}
const REMOVED: &[(&str, &str)] = &[
(
"gl_FragColor",
"`gl_FragColor` was removed in GLSL ES 3.00 — declare `out vec4` and write to it",
),
(
"gl_FragData",
"`gl_FragData` was removed in GLSL ES 3.00 — use a user-declared `out` array",
),
(
"texture2D(",
"`texture2D()` was removed in GLSL ES 3.00 — use `texture()`",
),
(
"texture2DLod(",
"`texture2DLod()` was removed in GLSL ES 3.00 — use `textureLod()`",
),
(
"textureCube(",
"`textureCube()` was removed in GLSL ES 3.00 — use `texture()`",
),
];
const QUALIFIERS: &[(&str, &str)] = &[
(
"varying ",
"`varying` is GLSL ES 1.00 — use `in`/`out` in ES 3.00",
),
(
"attribute ",
"`attribute` is GLSL ES 1.00 — use `in` in ES 3.00",
),
];
for (i, line) in source.lines().enumerate() {
let code = line.split("//").next().unwrap_or(line);
let lineno = line_no(i);
for (needle, msg) in REMOVED {
if let Some(byte) = code.find(needle) {
out.push(Diag {
path: target.to_path_buf(),
line: lineno,
col: char_col(code, byte),
len: needle.trim_end_matches('(').chars().count() as u32,
severity: Severity::Warning,
message: (*msg).to_string(),
source: "lint",
});
}
}
let trimmed = code.trim_start();
for (needle, msg) in QUALIFIERS {
if trimmed.starts_with(needle) {
let indent = code.len() - trimmed.len();
out.push(Diag {
path: target.to_path_buf(),
line: lineno,
col: char_col(code, indent),
len: needle.trim_end().chars().count() as u32,
severity: Severity::Warning,
message: (*msg).to_string(),
source: "lint",
});
}
}
}
}
fn char_col(line: &str, byte: usize) -> u32 {
line[..byte].chars().count() as u32 + 1
}