Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to ignore warnings from dependencies in foundry.toml #69

Merged
merged 19 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions src/artifacts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#![allow(ambiguous_glob_reexports)]

use crate::{
compile::*, error::SolcIoError, remappings::Remapping, utils, ProjectPathsConfig, SolcError,
compile::*, error::SolcIoError, output::ErrorFilter, remappings::Remapping, utils,
ProjectPathsConfig, SolcError,
};
use alloy_primitives::hex;
use md5::Digest;
Expand All @@ -16,7 +17,6 @@ use std::{
str::FromStr,
sync::Arc,
};

loocapro marked this conversation as resolved.
Show resolved Hide resolved
pub mod error;
pub use error::*;

Expand Down Expand Up @@ -1570,14 +1570,26 @@ impl CompilerOutput {
self.errors.iter().any(|err| err.severity.is_error())
}

/// Whether the output contains a compiler warning
pub fn has_warning(&self, ignored_error_codes: &[u64]) -> bool {
self.errors.iter().any(|err| {
if err.severity.is_warning() {
err.error_code.as_ref().map_or(false, |code| !ignored_error_codes.contains(code))
} else {
false
/// Checks if there are any compiler warnings that are not ignored by the specified error codes
/// and file paths.
pub fn has_warning<'a>(&self, filter: impl Into<ErrorFilter<'a>>) -> bool {
let filter: ErrorFilter<'_> = filter.into();
self.errors.iter().any(|error| {
if !error.severity.is_warning() {
return false;
}

let is_code_ignored = filter.is_code_ignored(error.error_code);

let is_file_ignored = error
.source_location
.as_ref()
.map_or(false, |location| filter.is_file_ignored(&PathBuf::from(&location.file)));
loocapro marked this conversation as resolved.
Show resolved Hide resolved

// Only consider warnings that are not ignored by either code or file path.
// Hence, return `true` for warnings that are not ignored, making the function
// return `true` if any such warnings exist.
!(is_code_ignored || is_file_ignored)
})
}

Expand Down
116 changes: 101 additions & 15 deletions src/compile/output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ use crate::{
use contracts::{VersionedContract, VersionedContracts};
use semver::Version;
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, fmt, path::Path};
use std::{
borrow::Cow,
collections::BTreeMap,
fmt,
path::{Path, PathBuf},
};
use yansi::Paint;

pub mod contracts;
Expand All @@ -32,6 +37,8 @@ pub struct ProjectCompileOutput<T: ArtifactOutput = ConfigurableArtifacts> {
pub(crate) cached_artifacts: Artifacts<T::Artifact>,
/// errors that should be omitted
pub(crate) ignored_error_codes: Vec<u64>,
/// paths that should be omitted
pub(crate) ignored_file_paths: Vec<PathBuf>,
/// set minimum level of severity that is treated as an error
pub(crate) compiler_severity_filter: Severity,
}
Expand Down Expand Up @@ -245,12 +252,17 @@ impl<T: ArtifactOutput> ProjectCompileOutput<T> {

/// Returns whether any errors were emitted by the compiler.
pub fn has_compiler_errors(&self) -> bool {
self.compiler_output.has_error(&self.ignored_error_codes, &self.compiler_severity_filter)
self.compiler_output.has_error(
&self.ignored_error_codes,
&self.ignored_file_paths,
&self.compiler_severity_filter,
)
}

/// Returns whether any warnings were emitted by the compiler.
pub fn has_compiler_warnings(&self) -> bool {
self.compiler_output.has_warning(&self.ignored_error_codes)
self.compiler_output
.has_warning((self.ignored_error_codes.as_slice(), self.ignored_file_paths.as_slice()))
}

/// Panics if any errors were emitted by the compiler.
Expand Down Expand Up @@ -463,7 +475,11 @@ impl<T: ArtifactOutput> fmt::Display for ProjectCompileOutput<T> {
f.write_str("Nothing to compile")
} else {
self.compiler_output
.diagnostics(&self.ignored_error_codes, self.compiler_severity_filter)
.diagnostics(
&self.ignored_error_codes,
&self.ignored_file_paths,
self.compiler_severity_filter,
)
.fmt(f)
}
}
Expand All @@ -484,6 +500,45 @@ pub struct AggregatedCompilerOutput {
pub build_infos: BTreeMap<Version, RawBuildInfo>,
}

pub struct ErrorFilter<'a> {
error_codes: Cow<'a, [u64]>,
ignored_file_paths: Cow<'a, [PathBuf]>,
loocapro marked this conversation as resolved.
Show resolved Hide resolved
}

impl<'a> ErrorFilter<'a> {
loocapro marked this conversation as resolved.
Show resolved Hide resolved
// Helper function to check if an error code is ignored
pub(crate) fn is_code_ignored(&self, code: Option<u64>) -> bool {
match code {
Some(code) => self.error_codes.contains(&code),
None => false,
}
}

// Helper function to check if an error's file path is ignored
pub(crate) fn is_file_ignored(&self, file_path: &Path) -> bool {
self.ignored_file_paths.iter().any(|ignored_path| file_path.starts_with(ignored_path))
}
}

impl<'a> From<(&'a [u64], &'a [PathBuf])> for ErrorFilter<'a> {
loocapro marked this conversation as resolved.
Show resolved Hide resolved
loocapro marked this conversation as resolved.
Show resolved Hide resolved
fn from(tuple: (&'a [u64], &'a [PathBuf])) -> Self {
let (error_codes, ignored_file_paths) = tuple;
ErrorFilter {
error_codes: Cow::Borrowed(error_codes),
ignored_file_paths: Cow::Borrowed(ignored_file_paths),
}
}
}

impl<'a> From<&'a [u64]> for ErrorFilter<'a> {
fn from(error_codes: &'a [u64]) -> Self {
ErrorFilter {
error_codes: Cow::Borrowed(error_codes),
ignored_file_paths: Cow::Borrowed(&[]),
}
}
}

impl AggregatedCompilerOutput {
/// Converts all `\\` separators in _all_ paths to `/`
pub fn slash_paths(&mut self) {
Expand All @@ -495,36 +550,56 @@ impl AggregatedCompilerOutput {
pub fn has_error(
&self,
ignored_error_codes: &[u64],
ignored_file_paths: &[PathBuf],
compiler_severity_filter: &Severity,
) -> bool {
self.errors.iter().any(|err| {
if compiler_severity_filter.ge(&err.severity) {
if compiler_severity_filter.is_warning() {
return self.has_warning(ignored_error_codes);
// skip ignored error codes and file path from warnings
return self.has_warning((ignored_error_codes, ignored_file_paths));
}
return true;
}
false
})
}

/// Whether the output contains a compiler warning
pub fn has_warning(&self, ignored_error_codes: &[u64]) -> bool {
self.errors.iter().any(|err| {
if err.severity.is_warning() {
err.error_code.as_ref().map_or(false, |code| !ignored_error_codes.contains(code))
} else {
false
/// Checks if there are any compiler warnings that are not ignored by the specified error codes
/// and file paths.
pub fn has_warning<'a>(&self, filter: impl Into<ErrorFilter<'a>>) -> bool {
let filter: ErrorFilter<'_> = filter.into();
self.errors.iter().any(|error| {
if !error.severity.is_warning() {
return false;
}

let is_code_ignored = filter.is_code_ignored(error.error_code);

let is_file_ignored = error
.source_location
.as_ref()
.map_or(false, |location| filter.is_file_ignored(&PathBuf::from(&location.file)));

// Only consider warnings that are not ignored by either code or file path.
// Hence, return `true` for warnings that are not ignored, making the function
// return `true` if any such warnings exist.
!(is_code_ignored || is_file_ignored)
})
}

pub fn diagnostics<'a>(
&'a self,
ignored_error_codes: &'a [u64],
ignored_file_paths: &'a [PathBuf],
compiler_severity_filter: Severity,
) -> OutputDiagnostics<'a> {
OutputDiagnostics { compiler_output: self, ignored_error_codes, compiler_severity_filter }
OutputDiagnostics {
compiler_output: self,
ignored_error_codes,
ignored_file_paths,
compiler_severity_filter,
}
}

pub fn is_empty(&self) -> bool {
Expand Down Expand Up @@ -784,19 +859,25 @@ pub struct OutputDiagnostics<'a> {
compiler_output: &'a AggregatedCompilerOutput,
/// the error codes to ignore
ignored_error_codes: &'a [u64],
/// the file paths to ignore
ignored_file_paths: &'a [PathBuf],
/// set minimum level of severity that is treated as an error
compiler_severity_filter: Severity,
}

impl<'a> OutputDiagnostics<'a> {
/// Returns true if there is at least one error of high severity
pub fn has_error(&self) -> bool {
self.compiler_output.has_error(self.ignored_error_codes, &self.compiler_severity_filter)
self.compiler_output.has_error(
self.ignored_error_codes,
self.ignored_file_paths,
&self.compiler_severity_filter,
)
}

/// Returns true if there is at least one warning
pub fn has_warning(&self) -> bool {
self.compiler_output.has_warning(self.ignored_error_codes)
self.compiler_output.has_warning((self.ignored_error_codes, self.ignored_file_paths))
}

/// Returns true if the contract is a expected to be a test
Expand Down Expand Up @@ -833,6 +914,11 @@ impl<'a> fmt::Display for OutputDiagnostics<'a> {
// from a test file we skip
ignored =
self.is_test(&source_location.file) && (code == 1878 || code == 5574);

// we ignore warnings coming from ignored files
ignored |= self
.ignored_file_paths
.starts_with(&[PathBuf::from(&source_location.file)]);
loocapro marked this conversation as resolved.
Show resolved Hide resolved
}

ignored |= self.ignored_error_codes.contains(&code);
Expand Down
12 changes: 9 additions & 3 deletions src/compile/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,11 @@ impl<'a, T: ArtifactOutput> CompiledState<'a, T> {
ctx,
&project.paths,
)
} else if output.has_error(&project.ignored_error_codes, &project.compiler_severity_filter)
{
} else if output.has_error(
&project.ignored_error_codes,
&project.ignored_file_paths,
&project.compiler_severity_filter,
) {
trace!("skip writing cache file due to solc errors: {:?}", output.errors);
project.artifacts_handler().output_to_artifacts(
&output.contracts,
Expand Down Expand Up @@ -352,8 +355,10 @@ impl<'a, T: ArtifactOutput> ArtifactsState<'a, T> {
let ArtifactsState { output, cache, compiled_artifacts } = self;
let project = cache.project();
let ignored_error_codes = project.ignored_error_codes.clone();
let ignored_file_paths = project.ignored_file_paths.clone();
let compiler_severity_filter = project.compiler_severity_filter;
let has_error = output.has_error(&ignored_error_codes, &compiler_severity_filter);
let has_error =
output.has_error(&ignored_error_codes, &ignored_file_paths, &compiler_severity_filter);
let skip_write_to_disk = project.no_artifacts || has_error;
trace!(has_error, project.no_artifacts, skip_write_to_disk, cache_path=?project.cache_path(),"prepare writing cache file");

Expand All @@ -363,6 +368,7 @@ impl<'a, T: ArtifactOutput> ArtifactsState<'a, T> {
compiled_artifacts,
cached_artifacts,
ignored_error_codes,
ignored_file_paths,
compiler_severity_filter,
})
}
Expand Down
14 changes: 14 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ pub struct Project<T: ArtifactOutput = ConfigurableArtifacts> {
pub artifacts: T,
/// Errors/Warnings which match these error codes are not going to be logged
pub ignored_error_codes: Vec<u64>,
/// Errors/Warnings which match these file paths are not going to be logged
pub ignored_file_paths: Vec<PathBuf>,
/// The minimum severity level that is treated as a compiler error
pub compiler_severity_filter: Severity,
/// The paths which will be allowed for library inclusion
Expand Down Expand Up @@ -565,6 +567,8 @@ pub struct ProjectBuilder<T: ArtifactOutput = ConfigurableArtifacts> {
artifacts: T,
/// Which error codes to ignore
pub ignored_error_codes: Vec<u64>,
/// Which file paths to ignore
pub ignored_file_paths: Vec<PathBuf>,
/// The minimum severity level that is treated as a compiler error
compiler_severity_filter: Severity,
/// All allowed paths for solc's `--allowed-paths`
Expand All @@ -589,6 +593,7 @@ impl<T: ArtifactOutput> ProjectBuilder<T> {
slash_paths: true,
artifacts,
ignored_error_codes: Vec::new(),
ignored_file_paths: Vec::new(),
compiler_severity_filter: Severity::Error,
allowed_paths: Default::default(),
include_paths: Default::default(),
Expand Down Expand Up @@ -628,6 +633,11 @@ impl<T: ArtifactOutput> ProjectBuilder<T> {
self
}

pub fn ignore_paths(mut self, paths: Vec<PathBuf>) -> Self {
self.ignored_file_paths = paths;
self
}

#[must_use]
pub fn set_compiler_severity_filter(mut self, compiler_severity_filter: Severity) -> Self {
self.compiler_severity_filter = compiler_severity_filter;
Expand Down Expand Up @@ -739,6 +749,7 @@ impl<T: ArtifactOutput> ProjectBuilder<T> {
offline,
build_info,
slash_paths,
ignored_file_paths,
..
} = self;
ProjectBuilder {
Expand All @@ -752,6 +763,7 @@ impl<T: ArtifactOutput> ProjectBuilder<T> {
slash_paths,
artifacts,
ignored_error_codes,
ignored_file_paths,
compiler_severity_filter,
allowed_paths,
include_paths,
Expand Down Expand Up @@ -810,6 +822,7 @@ impl<T: ArtifactOutput> ProjectBuilder<T> {
auto_detect,
artifacts,
ignored_error_codes,
ignored_file_paths,
compiler_severity_filter,
mut allowed_paths,
include_paths,
Expand Down Expand Up @@ -842,6 +855,7 @@ impl<T: ArtifactOutput> ProjectBuilder<T> {
auto_detect,
artifacts,
ignored_error_codes,
ignored_file_paths,
compiler_severity_filter,
allowed_paths,
include_paths,
Expand Down
8 changes: 8 additions & 0 deletions src/project_util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,14 @@ impl TempProject<ConfigurableArtifacts> {
Ok(Self::create_new(tmp_dir, inner)?)
}

pub fn dapptools_with_ignore_paths(paths_to_ignore: Vec<PathBuf>) -> Result<Self> {
let tmp_dir = tempdir("tmp_dapp")?;
let paths = ProjectPathsConfig::dapptools(tmp_dir.path())?;

let inner = Project::builder().paths(paths).ignore_paths(paths_to_ignore).build()?;
Ok(Self::create_new(tmp_dir, inner)?)
}

/// Creates an initialized dapptools style workspace in a new temporary dir
pub fn dapptools_init() -> Result<Self> {
let mut project = Self::dapptools()?;
Expand Down
Loading