Skip to content

Commit

Permalink
Preprocessor: pragma pe23_ignore_has_include (#592)
Browse files Browse the repository at this point in the history
  • Loading branch information
BrettMayson authored Nov 2, 2023
1 parent 960f55b commit 8d3596b
Show file tree
Hide file tree
Showing 14 changed files with 243 additions and 23 deletions.
7 changes: 7 additions & 0 deletions bin/src/modules/rapifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ pub fn rapify(path: WorkspacePath, ctx: &Context) -> RapifyResult {
))),
);
}
if processed.no_rapify() {
debug!(
"skipping rapify for {}, as instructed by preprocessor",
path.as_str()
);
return (messages, Ok(()));
}
let out = if path.filename().to_lowercase() == "config.cpp" {
path.parent().join("config.bin").unwrap()
} else {
Expand Down
11 changes: 11 additions & 0 deletions book/analysis/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ The scope can be one of the following, if not specified, the scope will be `line
| file | Suppresses the warning for the remainder of the current file, not including includes |
| config | Suppresses the warning for the remainder of the current config, including includes |

## Preprocessor Flags

HEMTT provides a few preprocessor flags to control the behavior of the preprocessor.

| Flag | Description |
| ---- | ----------- |
| pw3_ignore_arr | Ignore padded arguments in `ARR_N` macros |
| pe23_ignore_has_include| Assume any `#if __has_include` is false |

The scope of these flags is the same as the warning suppression scope.

## Preprocessor Warnings

### [PW1] Redefine Macro
Expand Down
11 changes: 11 additions & 0 deletions libs/common/src/reporting/processed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ pub struct Processed {

/// Warnings
warnings: Vec<Box<dyn Code>>,

/// The preprocessor was able to check the file, but it should not be rapified
no_rapify: bool,
}

fn append_token(
Expand Down Expand Up @@ -175,13 +178,15 @@ impl Processed {
#[cfg(feature = "lsp")] usage: HashMap<Position, Vec<Position>>,
#[cfg(feature = "lsp")] declarations: HashMap<Position, Position>,
warnings: Vec<Box<dyn Code>>,
no_rapify: bool,
) -> Result<Self, Error> {
let mut processed = Self {
#[cfg(feature = "lsp")]
declarations,
#[cfg(feature = "lsp")]
usage,
warnings,
no_rapify,
..Default::default()
};
let mut string_stack = Vec::new();
Expand Down Expand Up @@ -248,6 +253,12 @@ impl Processed {
pub fn warnings(&self) -> &[Box<dyn Code>] {
&self.warnings
}

#[must_use]
/// Returns whether the file should not be rapified
pub const fn no_rapify(&self) -> bool {
self.no_rapify
}
}

#[derive(Debug)]
Expand Down
1 change: 1 addition & 0 deletions libs/preprocessor/src/codes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod pe1_unexpected_token;
pub mod pe20_pragma_invalid_scope;
pub mod pe21_pragma_invalid_suppress;
pub mod pe22_pragma_invalid_flag;
pub mod pe23_if_has_include;
pub mod pe2_unexpected_eof;
pub mod pe3_expected_ident;
pub mod pe4_unknown_directive;
Expand Down
4 changes: 3 additions & 1 deletion libs/preprocessor/src/codes/pe21_pragma_invalid_suppress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use ariadne::{ColorGenerator, Fmt, Label, Report, ReportKind, Source};
use hemtt_common::reporting::{Annotation, AnnotationLevel, Code, Token};
use tracing::error;

use crate::processor::pragma::Suppress;

use super::similar_values;

#[allow(unused)]
Expand Down Expand Up @@ -39,7 +41,7 @@ impl Code for PragmaInvalidSuppress {
}

fn help(&self) -> Option<String> {
let similar = similar_values(self.token.to_string().as_str(), &["pw3_padded_arg"]);
let similar = similar_values(self.token.to_string().as_str(), Suppress::as_slice());
if similar.is_empty() {
None
} else {
Expand Down
4 changes: 3 additions & 1 deletion libs/preprocessor/src/codes/pe22_pragma_invalid_flag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use ariadne::{ColorGenerator, Fmt, Label, Report, ReportKind, Source};
use hemtt_common::reporting::{Annotation, AnnotationLevel, Code, Token};
use tracing::error;

use crate::processor::pragma::Flag;

use super::similar_values;

#[allow(unused)]
Expand Down Expand Up @@ -33,7 +35,7 @@ impl Code for PragmaInvalidFlag {
}

fn help(&self) -> Option<String> {
let similar = similar_values(self.token.to_string().as_str(), &["pw3_ignore_arr"]);
let similar = similar_values(self.token.to_string().as_str(), Flag::as_slice());
if similar.is_empty() {
None
} else {
Expand Down
102 changes: 102 additions & 0 deletions libs/preprocessor/src/codes/pe23_if_has_include.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use ariadne::{ColorGenerator, Fmt, Label, Report, ReportKind, Source};
use hemtt_common::reporting::{Annotation, AnnotationLevel, Code, Token};
use tracing::error;

#[allow(unused)]
/// An unknown `#pragma hemtt flag` code
///
/// ```cpp
/// #pragma hemtt flag unknown
/// ```
pub struct IfHasInclude {
/// The [`Token`] of the code
pub(crate) token: Box<Token>,
}

impl Code for IfHasInclude {
fn ident(&self) -> &'static str {
"PE23"
}

fn token(&self) -> Option<&Token> {
Some(&self.token)
}

fn message(&self) -> String {
"use of `#if __has_include`".to_string()
}

fn label_message(&self) -> String {
"use of `#if __has_include`".to_string()
}

fn help(&self) -> Option<String> {
Some(String::from("use `#pragma hemtt flag pe23_ignore_has_include` to have HEMTT act as if the include was not found"))
}

fn report_generate(&self) -> Option<String> {
let mut colors = ColorGenerator::default();
let color_token = colors.next();
let mut out = Vec::new();
let mut report = Report::build(
ReportKind::Error,
self.token.position().path().as_str(),
self.token.position().start().offset(),
)
.with_code(self.ident())
.with_message(self.message())
.with_label(
Label::new((
self.token.position().path().as_str(),
self.token.position().start().offset()..self.token.position().end().offset(),
))
.with_color(color_token)
.with_message(format!(
"use of `{}`",
self.token.symbol().to_string().fg(color_token)
)),
);
if let Some(help) = self.help() {
report = report.with_help(help);
}
if let Err(e) = report.finish().write_for_stdout(
(
self.token.position().path().as_str(),
Source::from(
self.token
.position()
.path()
.read_to_string()
.unwrap_or_default(),
),
),
&mut out,
) {
error!("while reporting: {e}");
return None;
}
Some(String::from_utf8(out).unwrap_or_default())
}

fn ci_generate(&self) -> Vec<Annotation> {
vec![self.annotation(
AnnotationLevel::Error,
self.token.position().path().as_str().to_string(),
self.token.position(),
)]
}

#[cfg(feature = "lsp")]
fn generate_lsp(&self) -> Option<(VfsPath, Diagnostic)> {
let Some(path) = self.token.position().path() else {
return None;
};
Some((
path.clone(),
self.diagnostic(Range {
start: self.token.position().start().to_lsp() - 1,
end: self.token.position().end().to_lsp(),
}),
))
}
}
9 changes: 6 additions & 3 deletions libs/preprocessor/src/processor/defines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use crate::{
Error,
};

use super::{pragma::Pragma, Processor};
use super::{
pragma::{Flag, Pragma, Suppress},
Processor,
};

impl Processor {
/// Reads the arguments of a macro call
Expand Down Expand Up @@ -215,8 +218,8 @@ impl Processor {
}
let mut arg_defines = HashMap::new();
for (arg, value) in function.args().iter().zip(args) {
if !pragma.is_suppressed("pw3_padded_arg")
&& (!pragma.is_flagged("pw3_ignore_arr")
if !pragma.is_suppressed(&Suppress::Pw3PaddedArg)
&& (!pragma.is_flagged(&Flag::Pw3IgnoreArr)
|| !ident_string.starts_with("ARR_"))
{
for token in [value.first(), value.last()] {
Expand Down
28 changes: 23 additions & 5 deletions libs/preprocessor/src/processor/directives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@ use hemtt_common::{
reporting::{Output, Symbol, Token},
};
use peekmore::{PeekMore, PeekMoreIterator};
use tracing::debug;

use crate::{
codes::{
pe12_include_not_found::IncludeNotFound, pe13_include_not_encased::IncludeNotEncased,
pe14_include_unexpected_suffix::IncludeUnexpectedSuffix,
pe15_if_invalid_operator::IfInvalidOperator,
pe16_if_incompatible_types::IfIncompatibleType, pe19_pragma_unknown::PragmaUnknown,
pe20_pragma_invalid_scope::PragmaInvalidScope, pe2_unexpected_eof::UnexpectedEOF,
pe3_expected_ident::ExpectedIdent, pe4_unknown_directive::UnknownDirective,
pe6_change_builtin::ChangeBuiltin, pe7_if_unit_or_function::IfUnitOrFunction,
pe8_if_undefined::IfUndefined, pw1_redefine::RedefineMacro,
pe20_pragma_invalid_scope::PragmaInvalidScope, pe23_if_has_include::IfHasInclude,
pe2_unexpected_eof::UnexpectedEOF, pe3_expected_ident::ExpectedIdent,
pe4_unknown_directive::UnknownDirective, pe6_change_builtin::ChangeBuiltin,
pe7_if_unit_or_function::IfUnitOrFunction, pe8_if_undefined::IfUndefined,
pw1_redefine::RedefineMacro,
},
defines::Defines,
definition::{Definition, FunctionDefinition},
ifstate::IfState,
processor::pragma::Flag,
Error,
};

Expand Down Expand Up @@ -71,7 +74,7 @@ impl Processor {
Ok(())
}
("if", true) => {
self.directive_if(command, stream)?;
self.directive_if(pragma, command, stream)?;
Ok(())
}
("ifdef", true) => self.directive_ifdef(command, true, stream),
Expand Down Expand Up @@ -289,6 +292,7 @@ impl Processor {
#[allow(clippy::too_many_lines)]
pub(crate) fn directive_if(
&mut self,
pragma: &Pragma,
command: Rc<Token>,
stream: &mut PeekMoreIterator<impl Iterator<Item = Rc<Token>>>,
) -> Result<(), Error> {
Expand All @@ -305,6 +309,20 @@ impl Processor {
Ok((vec![token], false))
}
let left = self.next_value(stream, None)?;
if &Symbol::Word(String::from("__has_include")) == left.symbol() {
if pragma.is_flagged(&Flag::Pe23IgnoreIfHasInclude) {
debug!(
"ignoring __has_include due to pragma flag, this config will not be rapified"
);
self.no_rapify = true;
self.ifstates.push_if(command, false);
self.skip_to_after_newline(stream, None);
return Ok(());
}
return Err(Error::Code(Box::new(IfHasInclude {
token: Box::new(left.as_ref().clone()),
})));
}
let (left, left_defined) = value(&mut self.defines, left)?;
self.skip_whitespace(stream, None);
let mut operators = Vec::with_capacity(2);
Expand Down
6 changes: 5 additions & 1 deletion libs/preprocessor/src/processor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use self::pragma::Pragma;

mod defines;
mod directives;
mod pragma;
pub mod pragma;
mod whitespace;

#[derive(Default)]
Expand All @@ -44,6 +44,9 @@ pub struct Processor {

/// Warnings
pub(crate) warnings: Vec<Box<dyn Code>>,

/// The preprocessor was able to run checks, but the output should not be rapified
pub(crate) no_rapify: bool,
}

impl Processor {
Expand Down Expand Up @@ -88,6 +91,7 @@ impl Processor {
#[cfg(feature = "lsp")]
processor.declarations,
processor.warnings,
processor.no_rapify,
)
.map_err(Into::into)
}
Expand Down
Loading

0 comments on commit 8d3596b

Please sign in to comment.