extract out diagnostics parser. pls submit AMD lint output in github issues

This commit is contained in:
Noah Santschi-Cooney 2022-03-19 23:27:33 +00:00
parent d3c0869288
commit f8dd31ca81
No known key found for this signature in database
GPG key ID: 3B22282472C8AE48
4 changed files with 128 additions and 80 deletions

View file

@ -0,0 +1,110 @@
use std::{collections::HashMap, path::Path};
use once_cell::sync::OnceCell;
use regex::Regex;
use rust_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
use url::Url;
use crate::{consts, opengl};
static RE_DIAGNOSTIC: OnceCell<Regex> = OnceCell::new();
fn diagnostics_regex<T>(vendor: &T) -> &'static Regex
where
T: opengl::ShaderValidator + ?Sized,
{
RE_DIAGNOSTIC.get_or_init(|| match vendor.vendor().as_str() {
"NVIDIA" => {
Regex::new(r#"^(?P<filepath>[^?<>*|"]+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#).unwrap()
}
_ => {
Regex::new(r#"^(?P<severity>ERROR|WARNING): (?P<filepath>[^?<>*|"\n]+):(?P<linenum>\d+): '[a-z]*' : (?P<output>.+)$"#).unwrap()
}
})
}
static LINE_NUM_OFFSET: OnceCell<u32> = OnceCell::new();
fn line_number_offset<T>(vendor: &T) -> &'static u32
where
T: opengl::ShaderValidator + ?Sized,
{
LINE_NUM_OFFSET.get_or_init(|| match vendor.vendor().as_str() {
"ATI Technologies" => 0,
_ => 2,
})
}
pub fn parse_diagnostics_output<T>(output: String, uri: &Path, vendor_querier: &T) -> HashMap<Url, Vec<Diagnostic>>
where
T: opengl::ShaderValidator + ?Sized,
{
let output_lines = output.split('\n');
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(output_lines.count());
let output_lines = output.split('\n');
for line in output_lines {
let diagnostic_capture = match diagnostics_regex(vendor_querier).captures(line) {
Some(d) => d,
None => continue,
};
// info!("match {:?}", diagnostic_capture);
let msg = diagnostic_capture.name("output").unwrap().as_str();
let line = match diagnostic_capture.name("linenum") {
Some(c) => c.as_str().parse::<u32>().unwrap_or(0),
None => 0,
} - line_number_offset(vendor_querier);
// TODO: line matching maybe
/* let line_text = source_lines[line as usize];
let leading_whitespace = line_text.len() - line_text.trim_start().len(); */
let severity = match diagnostic_capture.name("severity") {
Some(c) => match c.as_str().to_lowercase().as_str() {
"error" => DiagnosticSeverity::Error,
"warning" => DiagnosticSeverity::Warning,
_ => DiagnosticSeverity::Information,
},
_ => DiagnosticSeverity::Information,
};
let origin = match diagnostic_capture.name("filepath") {
Some(o) => {
if o.as_str() == "0" {
uri.to_str().unwrap().to_string()
} else {
o.as_str().to_string()
}
}
None => uri.to_str().unwrap().to_string(),
};
let diagnostic = Diagnostic {
range: Range::new(
/* Position::new(line, leading_whitespace as u64),
Position::new(line, line_text.len() as u64) */
Position::new(line, 0),
Position::new(line, 1000),
),
code: None,
severity: Some(severity),
source: Some(consts::SOURCE.into()),
message: msg.trim().into(),
related_information: None,
tags: None,
code_description: Option::None,
data: Option::None,
};
let origin_url = Url::from_file_path(origin).unwrap();
match diagnostics.get_mut(&origin_url) {
Some(d) => d.push(diagnostic),
None => {
diagnostics.insert(origin_url, vec![diagnostic]);
}
};
}
diagnostics
}

View file

@ -39,6 +39,7 @@ use regex::Regex;
use lazy_static::lazy_static;
mod commands;
mod diagnostics_parser;
mod configuration;
mod consts;
mod dfs;
@ -53,7 +54,6 @@ mod url_norm;
mod test;
lazy_static! {
static ref RE_DIAGNOSTIC: Regex = Regex::new(r#"^(?P<filepath>[^?<>*|"]+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#).unwrap();
static ref RE_VERSION: Regex = Regex::new(r#"#version [\d]{3}"#).unwrap();
static ref RE_INCLUDE: Regex = Regex::new(r#"^(?:\s)*?(?:#include) "(.+)"\r?"#).unwrap();
static ref RE_INCLUDE_EXTENSION: Regex = Regex::new(r#"#extension GL_GOOGLE_include_directive ?: ?require"#).unwrap();
@ -352,7 +352,7 @@ impl MinecraftShaderLanguageServer {
return Ok(diagnostics);
}
};
diagnostics.extend(self.parse_validator_stdout(uri, stdout, ""));
diagnostics.extend(diagnostics_parser::parse_diagnostics_output(stdout, uri, self.opengl_context.as_ref()));
} else {
let mut all_trees: Vec<(TreeType, Vec<(NodeIndex, Option<_>)>)> = Vec::new();
@ -402,7 +402,7 @@ impl MinecraftShaderLanguageServer {
Some(s) => s,
None => continue,
};
diagnostics.extend(self.parse_validator_stdout(uri, stdout, ""));
diagnostics.extend(diagnostics_parser::parse_diagnostics_output(stdout, uri, self.opengl_context.as_ref()));
}
};
@ -410,78 +410,6 @@ impl MinecraftShaderLanguageServer {
Ok(diagnostics)
}
fn parse_validator_stdout(&self, uri: &Path, stdout: String, _source: &str) -> HashMap<Url, Vec<Diagnostic>> {
let stdout_lines = stdout.split('\n');
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(stdout_lines.count());
let stdout_lines = stdout.split('\n');
for line in stdout_lines {
let diagnostic_capture = match RE_DIAGNOSTIC.captures(line) {
Some(d) => d,
None => continue
};
eprintln!("match {:?}", diagnostic_capture);
let msg = diagnostic_capture.name("output").unwrap().as_str();
let line = match diagnostic_capture.name("linenum") {
Some(c) => c.as_str().parse::<u32>().unwrap_or(0),
None => 0,
} - 2;
// TODO: line matching maybe
/* let line_text = source_lines[line as usize];
let leading_whitespace = line_text.len() - line_text.trim_start().len(); */
let severity = match diagnostic_capture.name("severity") {
Some(c) => match c.as_str() {
"error" => DiagnosticSeverity::Error,
"warning" => DiagnosticSeverity::Warning,
_ => DiagnosticSeverity::Information,
}
_ => DiagnosticSeverity::Information,
};
let origin = match diagnostic_capture.name("filepath") {
Some(o) => {
if o.as_str() == "0" {
uri.to_str().unwrap().to_string()
} else {
o.as_str().to_string()
}
},
None => uri.to_str().unwrap().to_string(),
};
let diagnostic = Diagnostic {
range: Range::new(
/* Position::new(line, leading_whitespace as u64),
Position::new(line, line_text.len() as u64) */
Position::new(line, 0),
Position::new(line, 1000),
),
code: None,
severity: Some(severity),
source: Some(consts::SOURCE.into()),
message: msg.trim().into(),
related_information: None,
tags: None,
code_description: Option::None,
data: Option::None,
};
let origin_url = Url::from_file_path(origin).unwrap();
match diagnostics.get_mut(&origin_url) {
Some(d) => d.push(diagnostic),
None => {
diagnostics.insert(origin_url, vec![diagnostic]);
},
};
}
diagnostics
}
pub fn get_dfs_for_node(&self, root: NodeIndex) -> Result<Vec<(NodeIndex, Option<NodeIndex>)>, dfs::error::CycleError> {
let graph_ref = self.graph.borrow();

View file

@ -9,6 +9,7 @@ use mockall::automock;
#[cfg_attr(test, automock)]
pub trait ShaderValidator {
fn validate(&self, tree_type: super::TreeType, source: String) -> Option<String>;
fn vendor(&self) -> String;
}
pub struct OpenGlContext {
@ -103,4 +104,8 @@ impl ShaderValidator for OpenGlContext {
result
}
fn vendor(&self) -> String {
unsafe { String::from_utf8(CStr::from_ptr(gl::GetString(gl::VENDOR) as *const _).to_bytes().to_vec()).unwrap() }
}
}

View file

@ -6,8 +6,8 @@ use std::io::Result;
use hamcrest2::prelude::*;
use pretty_assertions::assert_eq;
use slog::Logger;
use slog::o;
use slog::Logger;
use tempdir::TempDir;
use petgraph::algo::is_cyclic_directed;
@ -898,11 +898,12 @@ fn test_nvidia_diagnostics() {
let output = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh(9) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\"";
let results = server.parse_validator_stdout(
&PathBuf::from_str("/home/noah/.minecraft/shaderpacks/test").unwrap(),
let results = diagnostics_parser::parse_diagnostics_output(
output.to_string(),
"",
&PathBuf::from_str("/home/noah/.minecraft/shaderpacks/test").unwrap(),
server.opengl_context.as_ref(),
);
assert_eq!(results.len(), 1);
let first = results.into_iter().next().unwrap();
assert_eq!(
@ -923,7 +924,11 @@ ERROR: 0:10: '' : syntax error: #line
ERROR: 0:15: 'varying' : syntax error: syntax error
";
let results = server.parse_validator_stdout(&PathBuf::from_str("/home/test").unwrap(), output.to_string(), "");
let results = diagnostics_parser::parse_diagnostics_output(
output.to_string(),
&PathBuf::from_str("/home/test").unwrap(),
server.opengl_context.as_ref(),
);
assert_eq!(results.len(), 1);
let first = results.into_iter().next().unwrap();
assert_eq!(first.1.len(), 3);