diff --git a/.cargo/config.toml b/.cargo/config.toml index eb89fa1e55..7e4e7a0f90 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,8 +1,8 @@ [alias] xtask = "run --package xtask --" -# @fb-only: [build] -# @fb-only: target-dir = "../../../buck-out/elp" +# @fb-only +# @fb-only [profile.release] codegen-units = 1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9980283f2..0a2bb2508f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - platform-arch: [ubuntu-22.04-x64, ubuntu-22.04-arm, macos-15-x64, macos-latest-arm, windows-2022-x64] + platform-arch: [ubuntu-22.04-x64, ubuntu-22.04-arm, macos-13-x64, macos-latest-arm, windows-2022-x64] otp-version: [26.2, 27.3, 28.0] include: - otp-version: 26.2 @@ -55,8 +55,8 @@ jobs: os: linux target: aarch64-unknown-linux-gnu vscode-target: linux-arm64 - - platform-arch: macos-15-x64 - platform: macos-15-intel + - platform-arch: macos-13-x64 + platform: macos-13 os: macos target: x86_64-apple-darwin vscode-target: darwin-x64 @@ -97,8 +97,6 @@ jobs: run: | sudo apt-get update sudo apt-get install -y crossbuild-essential-arm64 - - name: Install Buck2 - uses: dtolnay/install-buck2@latest - id: setup-erlang uses: ./.github/actions/setup-erlang with: @@ -137,7 +135,7 @@ jobs: - name: Test elp # Do not run the tests in case of cross-compilation or on Windows if: matrix.platform-arch != 'macos-latest-arm' && matrix.os != 'windows' - run: 'cargo test --workspace --target ${{ matrix.target }}' + run: 'cargo test --no-default-features --workspace --target ${{ matrix.target }}' - name: Build elp (No Windows) if: matrix.os != 'windows' run: 'cargo build --release --target ${{ matrix.target }} --config target.aarch64-unknown-linux-gnu.linker=\"aarch64-linux-gnu-gcc\"' diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7572a84e98..51f0340659 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,7 +4,7 @@ { "label": "ELP: build (debug)", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh build", + // @fb-only "command": "cargo build", // @oss-only "group": { "kind": "build", @@ -19,7 +19,7 @@ { "label": "ELP: build (release)", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh build --release", + // @fb-only "command": "cargo build --release", // @oss-only "group": { "kind": "build", @@ -34,7 +34,7 @@ { "label": "ELP: build (release-thin)", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh build --profile release-thin --bins", + // @fb-only "command": "cargo build --profile release-thin --bins", // @oss-only "group": { "kind": "build", @@ -49,7 +49,7 @@ { "label": "ELP: run clippy on workspace", "type": "shell", - // @fb-only: "command": "./meta/clippy.sh --workspace --tests", + // @fb-only "command": "cargo clippy --workspace --tests", // @oss-only "group": { "kind": "build", @@ -64,7 +64,7 @@ { "label": "ELP: run clippy on workspace, apply fixes", "type": "shell", - // @fb-only: "command": "./meta/clippy.sh --workspace --tests --fix", + // @fb-only "command": "cargo clippy --workspace --tests --fix", // @oss-only "group": { "kind": "build", @@ -79,7 +79,7 @@ { "label": "ELP: run tests on workspace", "type": "shell", - // @fb-only: "command": "./meta/cargo.sh test --workspace", + // @fb-only "command": "cargo test --workspace", // @oss-only "group": { "kind": "build", diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index cd1328d14d..d6d2205ce9 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs @@ -87,7 +87,6 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { let (fixture, change) = ChangeFixture::parse(fixture_str); let mut db = Self::default(); change.apply(&mut db, &|path| fixture.resolve_file_id(path)); - fixture.validate(&db); (db, fixture) } } @@ -102,7 +101,6 @@ pub struct ChangeFixture { pub diagnostics_enabled: DiagnosticsEnabled, pub tags: FxHashMap)>>, pub annotations: FxHashMap>, - pub expect_parse_errors: bool, } struct Builder { @@ -174,7 +172,6 @@ impl ChangeFixture { let FixtureWithProjectMeta { fixture, mut diagnostics_enabled, - expect_parse_errors, } = fixture_with_meta.clone(); let builder = Builder::new(diagnostics_enabled.clone()); @@ -347,7 +344,6 @@ impl ChangeFixture { diagnostics_enabled, tags, annotations, - expect_parse_errors, }, change, project, @@ -409,64 +405,6 @@ impl ChangeFixture { .get(&VfsPath::from(path.clone())) .cloned() } - - /// Validate all files in the fixture for syntax errors. - /// Panics with context if any syntax errors are found. - /// Skips validation if `expect_parse_errors` is set to true. - #[track_caller] - pub fn validate(&self, db: &DB) { - if self.expect_parse_errors { - return; - } - - let mut errors_found = Vec::new(); - - for file_id in &self.files { - let parse = db.parse(*file_id); - let errors = parse.errors(); - - if !errors.is_empty() { - let path = self - .files_by_path - .iter() - .find_map(|(vfs_path, id)| { - if id == file_id { - Some( - vfs_path - .as_path() - .map(|p| p.to_string()) - .unwrap_or_else(|| format!("{:?}", vfs_path)), - ) - } else { - None - } - }) - .unwrap_or_else(|| format!("FileId({:?})", file_id)); - - let file_text = SourceDatabaseExt::file_text(db, *file_id); - let tree = parse.tree(); - errors_found.push((path, file_text.to_string(), errors.to_vec(), tree)); - } - } - - if !errors_found.is_empty() { - let mut message = - String::from("Fixture validation failed: syntax errors found in test fixture\n\n"); - - for (path, text, errors, tree) in errors_found { - message.push_str(&format!("File: {}\n", path)); - message.push_str(&format!("Errors: {:?}\n", errors)); - message.push_str(&format!("Content:\n{}\n", text)); - message.push_str(&format!("Parse Tree:\n{:#?}\n", tree)); - message.push_str("---\n"); - } - message.push_str( - "If this is expected, add `//- expect_parse_errors` to the start of the fixture\n", - ); - - panic!("{}", message); - } - } } fn inc_file_id(file_id: &mut FileId) { diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 0cd8df74c9..6b3757ff43 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs @@ -32,7 +32,7 @@ mod module_index; // Public API pub mod fixture; -// @fb-only: mod meta_only; +// @fb-only pub mod test_utils; pub use change::Change; pub use elp_project_model::AppType; @@ -476,7 +476,7 @@ static ref IGNORED_SOURCES: Vec = { let regexes: Vec> = vec![ vec![Regex::new(r"^.*_SUITE_data/.+$").unwrap()], //ignore sources goes here - // @fb-only: meta_only::ignored_sources_regexes() + // @fb-only ]; regexes.into_iter().flatten().collect::>() }; diff --git a/crates/elp/src/arc_types.rs b/crates/elp/src/arc_types.rs index 374dcdba2f..c113311661 100644 --- a/crates/elp/src/arc_types.rs +++ b/crates/elp/src/arc_types.rs @@ -8,8 +8,8 @@ * above-listed licenses. */ -// @fb-only: /// Types as defined in https://www.internalfb.com/intern/wiki/Linting/adding-linters/#flow-type -// @fb-only: /// and https://www.internalfb.com/code/fbsource/[1238f73dac0efd4009443fee6a345a680dc9401b]/whatsapp/server/erl/tools/lint/arcanist.py?lines=17 +// @fb-only +// @fb-only use std::path::Path; use serde::Serialize; diff --git a/crates/elp/src/bin/args.rs b/crates/elp/src/bin/args.rs index c9790e9314..0f057ce1e6 100644 --- a/crates/elp/src/bin/args.rs +++ b/crates/elp/src/bin/args.rs @@ -72,17 +72,6 @@ pub struct ParseAllElp { /// Report system memory usage and other statistics #[bpaf(long("report-system-stats"))] pub report_system_stats: bool, - /// Minimum severity level to report. Valid values: error, warning, weak_warning, information - #[bpaf( - argument("SEVERITY"), - complete(severity_completer), - fallback(None), - guard( - severity_guard, - "Please use error, warning, weak_warning, or information" - ) - )] - pub severity: Option, } #[derive(Clone, Debug, Bpaf)] @@ -155,6 +144,8 @@ pub struct EqwalizeAll { /// Also eqwalize opted-in generated modules from project (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// Exit with a non-zero status code if any errors are found pub bail_on_error: bool, /// Print statistics when done @@ -171,6 +162,8 @@ pub struct EqwalizeTarget { /// Also eqwalize opted-in generated modules from application (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// Exit with a non-zero status code if any errors are found pub bail_on_error: bool, /// target, like //erl/chatd/... @@ -189,6 +182,8 @@ pub struct EqwalizeApp { /// Also eqwalize opted-in generated modules from project (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// Run with rebar pub rebar: bool, /// Exit with a non-zero status code if any errors are found @@ -211,6 +206,8 @@ pub struct EqwalizeStats { /// Also eqwalize opted-in generated modules from project (deprecated) #[bpaf(hide)] pub include_generated: bool, + /// Also eqwalize test modules from project + pub include_tests: bool, /// If specified, use the provided CLI severity mapping instead of the default one pub use_cli_severity: bool, } @@ -786,25 +783,6 @@ fn format_guard(format: &Option) -> bool { } } -fn severity_completer(_: &Option) -> Vec<(String, Option)> { - vec![ - ("error".to_string(), None), - ("warning".to_string(), None), - ("weak_warning".to_string(), None), - ("information".to_string(), None), - ] -} - -fn severity_guard(severity: &Option) -> bool { - match severity { - None => true, - Some(s) if s == "error" || s == "warning" || s == "weak_warning" || s == "information" => { - true - } - _ => false, - } -} - fn macros_completer(_: &Option) -> Vec<(String, Option)> { vec![ ("expand".to_string(), None), @@ -911,7 +889,7 @@ impl Lint { /// To prevent flaky test results we allow disabling streaming when applying fixes pub fn skip_stream_print(&self) -> bool { - self.apply_fix || self.no_stream + self.apply_fix && self.no_stream } } diff --git a/crates/elp/src/bin/elp_parse_cli.rs b/crates/elp/src/bin/elp_parse_cli.rs index 770ab60456..16d4675d7d 100644 --- a/crates/elp/src/bin/elp_parse_cli.rs +++ b/crates/elp/src/bin/elp_parse_cli.rs @@ -57,35 +57,6 @@ use crate::args::ParseAllElp; use crate::reporting; use crate::reporting::print_memory_usage; -fn parse_severity(severity: &str) -> Option { - match severity { - "error" => Some(diagnostics::Severity::Error), - "warning" => Some(diagnostics::Severity::Warning), - "weak_warning" => Some(diagnostics::Severity::WeakWarning), - "information" => Some(diagnostics::Severity::Information), - _ => None, - } -} - -fn severity_rank(severity: diagnostics::Severity) -> u8 { - match severity { - diagnostics::Severity::Error => 1, - diagnostics::Severity::Warning => 2, - diagnostics::Severity::WeakWarning => 3, - diagnostics::Severity::Information => 4, - } -} - -fn meets_severity_threshold( - diag_severity: diagnostics::Severity, - min_severity: Option, -) -> bool { - match min_severity { - None => true, - Some(min) => severity_rank(diag_severity) <= severity_rank(min), - } -} - #[derive(Debug)] struct ParseResult { name: String, @@ -176,19 +147,6 @@ pub fn parse_all( let memory_end = MemoryUsage::now(); let memory_used = memory_end - memory_start; - let min_severity = args - .severity - .as_ref() - .and_then(|s| parse_severity(s.as_str())); - - res.retain(|parse_result| { - parse_result - .diagnostics - .diagnostics_for(parse_result.file_id) - .iter() - .any(|diag| meets_severity_threshold(diag.severity, min_severity)) - }); - if res.is_empty() { if args.is_format_normal() { writeln!(cli, "No errors reported")?; @@ -207,7 +165,6 @@ pub fn parse_all( for diags in res { let mut combined: Vec = diags.diagnostics.diagnostics_for(diags.file_id); - combined.retain(|diag| meets_severity_threshold(diag.severity, min_severity)); if args.is_format_normal() { writeln!(cli, " {}: {}", diags.name, combined.len())?; } diff --git a/crates/elp/src/bin/eqwalizer_cli.rs b/crates/elp/src/bin/eqwalizer_cli.rs index 141b2157d0..a91bcdd869 100644 --- a/crates/elp/src/bin/eqwalizer_cli.rs +++ b/crates/elp/src/bin/eqwalizer_cli.rs @@ -186,7 +186,10 @@ pub fn do_eqwalize_all( .par_bridge() .progress_with(pb.clone()) .map_with(analysis.clone(), |analysis, (name, _source, file_id)| { - if analysis.should_eqwalize(file_id).unwrap() && !otp_file_to_ignore(analysis, file_id) + if analysis + .should_eqwalize(file_id, args.include_tests) + .unwrap() + && !otp_file_to_ignore(analysis, file_id) { if args.stats { add_stat(name.to_string()); @@ -266,7 +269,9 @@ pub fn do_eqwalize_app( .iter_own() .filter_map(|(_name, _source, file_id)| { if analysis.file_app_name(file_id).ok()? == Some(AppName(args.app.clone())) - && analysis.should_eqwalize(file_id).unwrap() + && analysis + .should_eqwalize(file_id, args.include_tests) + .unwrap() && !otp_file_to_ignore(analysis, file_id) { Some(file_id) @@ -334,7 +339,9 @@ pub fn eqwalize_target( let vfs_path = VfsPath::from(src.clone()); if let Some((file_id, _)) = loaded.vfs.file_id(&vfs_path) { at_least_one_found = true; - if analysis.should_eqwalize(file_id).unwrap() + if analysis + .should_eqwalize(file_id, args.include_tests) + .unwrap() && !otp_file_to_ignore(analysis, file_id) { file_ids.push(file_id); @@ -401,7 +408,9 @@ pub fn eqwalize_stats( .par_bridge() .progress_with(pb.clone()) .map_with(analysis.clone(), |analysis, (name, _source, file_id)| { - if analysis.should_eqwalize(file_id).expect("cancelled") + if analysis + .should_eqwalize(file_id, args.include_tests) + .expect("cancelled") && !otp_file_to_ignore(analysis, file_id) { analysis diff --git a/crates/elp/src/bin/glean.rs b/crates/elp/src/bin/glean.rs index cb420261d2..c31d45dc9e 100644 --- a/crates/elp/src/bin/glean.rs +++ b/crates/elp/src/bin/glean.rs @@ -84,7 +84,7 @@ const REC_ARITY: u32 = 99; const HEADER_ARITY: u32 = 100; const FACTS_FILE: &str = "facts.json"; -// @fb-only: mod meta_only; +// @fb-only #[derive(Serialize, Debug, Eq, Hash, PartialEq, Clone)] struct GleanFileId(u32); @@ -994,7 +994,7 @@ impl GleanIndexer { .filter(|text| !text.is_empty()) }); - // @fb-only: let exdoc_link = elp_ide::meta_only::exdoc_links::module_exdoc_link(&module, &sema); + // @fb-only let exdoc_link: Option = None; // @oss-only ModuleFact::new( @@ -1532,7 +1532,7 @@ impl GleanIndexer { }) => { let def = macro_def.as_ref()?; let mut resolved = Self::resolve_macro_v2(sema, def, source_file, ctx)?; - // @fb-only: meta_only::resolve_macro_expansion(sema, *expansion, ctx, &mut resolved); + // @fb-only Some(resolved) } hir::AnyExpr::Pat(Pat::MacroCall { macro_def, .. }) @@ -1560,7 +1560,7 @@ impl GleanIndexer { vars: FxHashMap<&Location, &String>, ) -> Vec { let mut result = vec![]; - if !db.is_eqwalizer_enabled(file_id) { + if !db.is_eqwalizer_enabled(file_id, false) { return result; } let module_diagnostics = db.eqwalizer_diagnostics_by_project(project_id, vec![file_id]); @@ -1875,9 +1875,9 @@ impl GleanIndexer { let source_file = sema.parse(file_id); let range = Self::find_range(sema, ctx, &source_file, &expr_source)?; - // @fb-only: use elp_ide::meta_only::wam_links; - // @fb-only: let wam_ctx = wam_links::WamEventCtx::new(sema.db.upcast()); - // @fb-only: let wam_url = wam_ctx.build_wam_link(name).map(|link| link.url()); + // @fb-only + // @fb-only + // @fb-only let wam_url = None; // @oss-only Some(XRef { @@ -2335,10 +2335,10 @@ mod tests { fn xref_types_test() { let spec = r#" //- /glean/app_glean/src/glean_module81.erl - -type small() :: {non_neg_integer() | infinity}. + -type small() :: #{non_neg_integer() | infinity}. //- /glean/app_glean/src/glean_module8.erl - -type huuuge() :: {non_neg_integer() | infinity}. + -type huuuge() :: #{non_neg_integer() | infinity}. -spec baz( A :: huuuge(), %% ^^^^^^ glean_module8/huuuge/0 @@ -2393,10 +2393,10 @@ mod tests { fn xref_types_v2_test() { let spec = r#" //- /glean/app_glean/src/glean_module81.erl - -type small() :: {non_neg_integer() | infinity}. + -type small() :: #{non_neg_integer() | infinity}. //- /glean/app_glean/src/glean_module8.erl - -type huuuge() :: {non_neg_integer() | infinity}. + -type huuuge() :: #{non_neg_integer() | infinity}. -spec baz( A :: huuuge(), %% ^^^^^^ glean_module8.erl/type/huuuge/0 diff --git a/crates/elp/src/bin/lint_cli.rs b/crates/elp/src/bin/lint_cli.rs index 241a3d4481..f7ac4ff114 100644 --- a/crates/elp/src/bin/lint_cli.rs +++ b/crates/elp/src/bin/lint_cli.rs @@ -295,7 +295,7 @@ pub fn do_codemod( let res; let streamed_err_in_diag; let mut any_diagnostics_printed = false; - let mut initial_diags = { + let initial_diags = { // We put this in its own block so that analysis is // freed before we apply lints. To apply lints // recursively, we need to update the underlying @@ -394,54 +394,30 @@ pub fn do_codemod( let mut err_in_diag = streamed_err_in_diag; // At this point, the analysis variable from above is dropped - // When streaming is disabled (--no-stream) and we're not applying fixes, - // we need to print diagnostics now since they weren't printed during streaming - if args.no_stream && !args.apply_fix && !initial_diags.is_empty() { - let analysis = loaded.analysis(); - let mut module_count = 0; - initial_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); - for result in &initial_diags { - let printed = print_diagnostic_result( - cli, - &analysis, - diagnostics_config, - args, - loaded, - &args.module, - &mut err_in_diag, - &mut module_count, - result, - )?; - any_diagnostics_printed = any_diagnostics_printed || printed; + // Print "No diagnostics reported" if no diagnostics were found after filtering + if !any_diagnostics_printed { + if args.is_format_normal() { + writeln!(cli, "No diagnostics reported")?; } - } - - // Handle apply_fix case separately since it needs to filter diagnostics anyway - if args.apply_fix { - if diagnostics_config.enabled.all_enabled() { + } else { + if args.apply_fix && diagnostics_config.enabled.all_enabled() { bail!( "We cannot apply fixes if all diagnostics enabled. Perhaps provide --diagnostic-filter" ); } - - let mut filtered_diags = { - let analysis = loaded.analysis(); - filter_diagnostics( - &analysis, - &args.module, - Some(&diagnostics_config.enabled), - &initial_diags, - &FxHashSet::default(), - )? - }; - - if filtered_diags.is_empty() { - if args.is_format_normal() { - writeln!(cli, "No diagnostics reported")?; - } - } else { + if args.apply_fix && !diagnostics_config.enabled.all_enabled() { + let mut initial_diags = { + let analysis = loaded.analysis(); + filter_diagnostics( + &analysis, + &args.module, + Some(&diagnostics_config.enabled), + &initial_diags, + &FxHashSet::default(), + )? + }; if args.skip_stream_print() { - filtered_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); + initial_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); let module_count: &mut i32 = &mut 0; let has_diagnostics: &mut bool = &mut false; if args.is_format_json() { @@ -452,7 +428,7 @@ pub fn do_codemod( &mut err_in_diag, module_count, has_diagnostics, - &filtered_diags, + &initial_diags, )?; } else { { @@ -466,7 +442,7 @@ pub fn do_codemod( &mut err_in_diag, module_count, has_diagnostics, - &filtered_diags, + &initial_diags, )?; // Analysis is dropped here } @@ -480,7 +456,7 @@ pub fn do_codemod( &mut loaded.vfs, args, &mut changed_files, - filtered_diags, + initial_diags, ); // We handle the fix application result here, so // the overall status of whether error-severity @@ -492,19 +468,8 @@ pub fn do_codemod( writeln!(cli, "Apply fix failed: {err:#}").ok(); } }; - - if err_in_diag { - bail!("Errors found") - } } - } else { - // Non-apply-fix case: rely on any_diagnostics_printed which is set - // correctly based on filtered diagnostics during streaming/batch printing - if !any_diagnostics_printed { - if args.is_format_normal() { - writeln!(cli, "No diagnostics reported")?; - } - } else if err_in_diag { + if err_in_diag { bail!("Errors found") } } diff --git a/crates/elp/src/bin/main.rs b/crates/elp/src/bin/main.rs index 56535e4492..2ecb900759 100644 --- a/crates/elp/src/bin/main.rs +++ b/crates/elp/src/bin/main.rs @@ -40,7 +40,7 @@ mod erlang_service_cli; mod explain_cli; mod glean; mod lint_cli; -// @fb-only: mod meta_only; +// @fb-only mod reporting; mod shell; mod ssr_cli; @@ -110,7 +110,7 @@ fn setup_cli_telemetry(args: &Args) { } _ => { // Initialize CLI telemetry, if used - // @fb-only: meta_only::initialize_telemetry(); + // @fb-only } } } @@ -288,7 +288,7 @@ mod tests { let (_stdout, stderr, code) = elp(args_vec![ "parse-all", "--project", - "../../test/test_projects/standard", + "../../test_projects/standard", "--to", tmp.path(), ]); @@ -306,7 +306,7 @@ mod tests { fn parse_all_complete(project: &str) -> Result { // Just check the command returns. - let project_path = format!("../../test/test_projects/{project}"); + let project_path = format!("../../test_projects/{project}"); let tmp = Builder::new().prefix("elp_parse_all_").tempdir().unwrap(); let (_stdout, _stderr, code) = elp(args_vec![ "parse-all", @@ -443,34 +443,33 @@ mod tests { }) .unwrap(); - let exp_path = expect_file!(format!( - "../resources/test/{}/{}/{}.pretty", - project, - app, - module.as_str(), - )); - let (stdout, _) = cli.to_strings(); - let otp_version = OTP_VERSION.as_ref().expect("MISSING OTP VERSION"); let otp_version_regex = - regex::bytes::Regex::new(&format!("{}OTP([0-9]+)Only", "@")).unwrap(); + regex::bytes::Regex::new(&format!("{}OTPVersionDependent", "@")) + .unwrap(); let contents = analysis.file_text(file_id).unwrap(); - let otp_version_capture = otp_version_regex - .captures(&contents.as_bytes()[0..(2001.min(contents.len()))]); - if let Some((_, [otp_version_only])) = - otp_version_capture.map(|cap| cap.extract()) - { - if otp_version_only == otp_version.as_bytes() { - assert_normalised_file( - exp_path, - &stdout, - project_path.into(), - false, - ); + let otp_version_dependent = otp_version_regex + .is_match(&contents.as_bytes()[0..(2001.min(contents.len()))]); + let exp_path = { + if otp_version_dependent { + expect_file!(format!( + "../resources/test/{}/{}/{}-OTP-{}.pretty", + project, + app, + module.as_str(), + otp_version, + )) + } else { + expect_file!(format!( + "../resources/test/{}/{}/{}.pretty", + project, + app, + module.as_str(), + )) } - } else { - assert_normalised_file(exp_path, &stdout, project_path.into(), false); - } + }; + let (stdout, _) = cli.to_strings(); + assert_normalised_file(exp_path, &stdout, project_path.into(), false); } } EqwalizerDiagnostics::NoAst { module } => { @@ -605,7 +604,10 @@ mod tests { fn eqwalize_target_diagnostics_match_snapshot_pretty() { if cfg!(feature = "buck") { simple_snapshot( - args_vec!["eqwalize-target", "//standard:app_a",], + args_vec![ + "eqwalize-target", + "//whatsapp/elp/test_projects/standard:app_a", + ], "standard", expect_file!("../resources/test/standard/eqwalize_target_diagnostics.pretty"), true, @@ -669,24 +671,6 @@ mod tests { ); } - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn parse_all_diagnostics_severity(buck: bool) { - simple_snapshot_expect_error( - args_vec![ - "parse-elp", - "--module", - "diagnostics", - "--severity", - "error" - ], - "diagnostics", - expect_file!("../resources/test/diagnostics/parse_all_diagnostics_error.stdout"), - buck, - None, - ); - } - #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn parse_elp_file_attribute(buck: bool) { @@ -970,9 +954,7 @@ mod tests { assert!(tmp_file.clone().exists()); let content = fs::read_to_string(tmp_file).unwrap(); let mut buck_config = BuckConfig::default(); - buck_config.buck_root = Some(AbsPathBuf::assert_utf8( - current_dir().unwrap().join(path_str.clone()), - )); + buck_config.buck_root = Some(AbsPathBuf::assert_utf8(current_dir().unwrap())); let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); let prelude_cell = prelude_cell.strip_prefix("/").unwrap(); let content = content.replace(prelude_cell, "/[prelude]/"); @@ -984,13 +966,38 @@ mod tests { Some(AbsPathBuf::assert(Utf8PathBuf::from_path_buf(abs).unwrap())); let content = normalise_prelude_path(content, buck_config); - let content = sort_json(&content); - expect![[r#" { "apps": [ { + "name": "test_exec", + "dir": "/[prelude]//erlang/common_test/test_exec/src", + "src_dirs": [ + "" + ], + "extra_src_dirs": [], + "include_dirs": [], + "macros": {} + }, + { + "name": "diagnostics_app_a", + "dir": "app_a", + "src_dirs": [ + "src" + ], + "extra_src_dirs": [], + "include_dirs": [ + "include" + ], + "macros": { + "COMMON_TEST": "true", + "TEST": "true" + } + }, + { + "name": "app_a_SUITE", "dir": "app_a/test", + "src_dirs": [], "extra_src_dirs": [ "" ], @@ -998,88 +1005,61 @@ mod tests { "macros": { "COMMON_TEST": "true", "TEST": "true" - }, - "name": "app_a_SUITE", - "src_dirs": [] + } }, { - "dir": "/[prelude]//erlang/common_test/test_exec/src", - "extra_src_dirs": [], - "include_dirs": [], - "macros": {}, - "name": "test_exec", - "src_dirs": [ - "" - ] - }, - { - "dir": "/[prelude]//erlang/common_test/common", - "extra_src_dirs": [], - "include_dirs": [ - "include" - ], - "macros": {}, "name": "common", + "dir": "/[prelude]//erlang/common_test/common", "src_dirs": [ "src" - ] - }, - { - "dir": "/[prelude]//erlang/common_test/cth_hooks/src", - "extra_src_dirs": [], - "include_dirs": [ - "" ], - "macros": {}, - "name": "cth_hooks", - "src_dirs": [ - "" - ] - }, - { - "dir": "/[prelude]//erlang/shell/src", - "extra_src_dirs": [], - "include_dirs": [], - "macros": {}, - "name": "buck2_shell_utils", - "src_dirs": [ - "" - ] - }, - { - "dir": "app_a", "extra_src_dirs": [], "include_dirs": [ "include" ], - "macros": { - "COMMON_TEST": "true", - "TEST": "true" - }, - "name": "diagnostics_app_a", - "src_dirs": [ - "src" - ] + "macros": {} }, { - "dir": "/[prelude]//erlang/common_test/test_binary/src", + "name": "cth_hooks", + "dir": "/[prelude]//erlang/common_test/cth_hooks/src", + "src_dirs": [ + "" + ], + "extra_src_dirs": [], + "include_dirs": [ + "" + ], + "macros": {} + }, + { + "name": "buck2_shell_utils", + "dir": "/[prelude]//erlang/shell/src", + "src_dirs": [ + "" + ], "extra_src_dirs": [], "include_dirs": [], - "macros": {}, + "macros": {} + }, + { "name": "test_binary", + "dir": "/[prelude]//erlang/common_test/test_binary/src", "src_dirs": [ "" - ] - }, - { - "dir": "/[prelude]//erlang/common_test/test_cli_lib/src", + ], "extra_src_dirs": [], "include_dirs": [], - "macros": {}, + "macros": {} + }, + { "name": "test_cli_lib", + "dir": "/[prelude]//erlang/common_test/test_cli_lib/src", "src_dirs": [ "" - ] + ], + "extra_src_dirs": [], + "include_dirs": [], + "macros": {} } ], "deps": [] @@ -1094,12 +1074,6 @@ mod tests { content.replace(prelude_cell, "/[prelude]/") } - fn sort_json(content: &str) -> String { - let mut json: serde_json::Value = serde_json::from_str(content).unwrap(); - json.sort_all_objects(); - serde_json::to_string_pretty(&json).unwrap() - } - #[test] #[ignore] fn build_info_json_buck_bxl_generated() { @@ -1113,7 +1087,7 @@ mod tests { "--to", tmp_file.clone(), "--project", - path_str.clone() + path_str ]; let (stdout, stderr, code) = elp(args); assert_eq!( @@ -1128,9 +1102,7 @@ mod tests { assert!(tmp_file.clone().exists()); let content = fs::read_to_string(tmp_file).unwrap(); let mut buck_config = BuckConfig::default(); - buck_config.buck_root = Some(AbsPathBuf::assert_utf8( - current_dir().unwrap().join(path_str.clone()), - )); + buck_config.buck_root = Some(AbsPathBuf::assert_utf8(current_dir().unwrap())); let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); let prelude_cell = prelude_cell.strip_prefix("/").unwrap(); let content = content.replace(prelude_cell, "/[prelude]/"); @@ -1454,7 +1426,7 @@ mod tests { "lint", "--experimental", "--config-file", - "../../test/test_projects/linter/does_not_exist.toml" + "../../test_projects/linter/does_not_exist.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_custom_config_invalid_output.stdout"), @@ -1466,7 +1438,7 @@ mod tests { &[], false, Some(expect![[r#" - unable to read "../../test/test_projects/linter/does_not_exist.toml": No such file or directory (os error 2) + unable to read "../../test_projects/linter/does_not_exist.toml": No such file or directory (os error 2) "#]]), ) .expect("bad test"); @@ -1482,7 +1454,7 @@ mod tests { "lint", "--experimental", "--config-file", - "../../test/test_projects/linter/elp_lint_test1.toml" + "../../test_projects/linter/elp_lint_test1.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_custom_config_output.stdout"), @@ -1508,7 +1480,7 @@ mod tests { "lint", "--experimental", "--config-file", - "../../test/test_projects/linter/elp_lint_adhoc.toml", + "../../test_projects/linter/elp_lint_adhoc.toml", "--module", "app_b", "--apply-fix", @@ -1539,7 +1511,7 @@ mod tests { "--diagnostic-ignore", "W0011", "--config-file", - "../../test/test_projects/linter/elp_lint_test_ignore.toml" + "../../test_projects/linter/elp_lint_test_ignore.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_ignore.stdout"), @@ -1583,7 +1555,7 @@ mod tests { &[], false, Some(expect![[r#" - failed to read "../../test/test_projects/linter_bad_config/.elp_lint.toml":expected a right bracket, found an identifier at line 6 column 4 + failed to read "../../test_projects/linter_bad_config/.elp_lint.toml":expected a right bracket, found an identifier at line 6 column 4 "#]]), ) .expect("bad test"); @@ -1601,20 +1573,6 @@ mod tests { ); } - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn lint_no_stream_produces_output(buck: bool) { - if otp::supports_eep66_sigils() { - simple_snapshot_expect_error( - args_vec!["lint", "--no-stream"], - "diagnostics", - expect_file!("../resources/test/diagnostics/lint_no_stream.stdout"), - buck, - None, - ); - } - } - #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn lint_no_diagnostics_filter_all_enabled_json(buck: bool) { @@ -1649,7 +1607,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test/test_projects/linter/elp_lint_test2.toml" + "../../test_projects/linter/elp_lint_test2.toml" ], "linter", expect_file!("../resources/test/linter/parse_elp_lint_explicit_enable_output.stdout"), @@ -1952,8 +1910,7 @@ mod tests { simple_snapshot_expect_stderror( args_vec!["lint",], "buck_bad_config", - // @fb-only: expect_file!("../resources/test/buck_bad_config/bxl_error_message.stdout"), - expect_file!("../resources/test/buck_bad_config/bxl_error_message_oss.stdout"), // @oss-only + expect_file!("../resources/test/buck_bad_config/bxl_error_message.stdout"), true, None, true, @@ -1968,7 +1925,7 @@ mod tests { "lint", "--no-stream" "--config-file", - "../../test/test_projects/linter/elp_lint_warnings_as_errors.toml" + "../../test_projects/linter/elp_lint_warnings_as_errors.toml" ], "linter", expect_file!("../resources/test/linter/warnings_as_errors.stdout"), @@ -1983,7 +1940,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test/test_projects/linter/elp_lint_custom_function_matches.toml", + "../../test_projects/linter/elp_lint_custom_function_matches.toml", "--module", "custom_function_matches" ], @@ -2000,7 +1957,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test/test_projects/xref/elp_lint_unavailable_type.toml", + "../../test_projects/xref/elp_lint_unavailable_type.toml", "--module", "unavailable_type" ], @@ -2017,7 +1974,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test/test_projects/linter/elp_lint_ssr_adhoc.toml", + "../../test_projects/linter/elp_lint_ssr_adhoc.toml", ], "linter", expect_file!("../resources/test/linter/ssr_ad_hoc.stdout"), @@ -2032,7 +1989,7 @@ mod tests { args_vec![ "lint", "--config-file", - "../../test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml", + "../../test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml", ], "linter", expect_file!("../resources/test/linter/ssr_ad_hoc_parse_fail.stdout"), @@ -2218,41 +2175,6 @@ mod tests { #[test_case(false ; "rebar")] #[test_case(true ; "buck")] - fn ssr_exclude_generated_by_default(buck: bool) { - simple_snapshot( - args_vec!["ssr", "--module", "erlang_diagnostics_errors_gen", "ok"], - "diagnostics", - expect_file!("../resources/test/diagnostics/ssr_exclude_generated.stdout"), - buck, - None, - ); - } - - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn ssr_include_generated_when_requested(buck: bool) { - simple_snapshot( - args_vec![ - "ssr", - "--module", - "erlang_diagnostics_errors_gen", - "--include-generated", - "ok" - ], - "diagnostics", - expect_file!("../resources/test/diagnostics/ssr_include_generated.stdout"), - buck, - None, - ); - } - - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - // We cannot use `should_panic` for this test, since the OSS CI runs with the `buck` feature disabled. - // When this happens the test is translated into a no-op, which does not panic. - // TODO(T248259687): Switch to should_panic once Buck2 is available on GitHub. - // Or remove the ignore once hierarchical support is implemented. - #[ignore] // Support for hierarchical config is not implemented yet fn lint_hierarchical_config_basic(buck: bool) { simple_snapshot_sorted( args_vec!["lint", "--read-config"], @@ -2263,18 +2185,6 @@ mod tests { ); } - #[test_case(false ; "rebar")] - #[test_case(true ; "buck")] - fn lint_linter_config_basic(buck: bool) { - simple_snapshot_sorted( - args_vec!["lint", "--read-config", "--no-stream"], - "linter_config", - expect_file!("../resources/test/linter_config/basic.stdout"), - buck, - None, - ); - } - #[test_case(false ; "rebar")] #[test_case(true ; "buck")] fn eqwalizer_tests_check(buck: bool) { @@ -3136,7 +3046,7 @@ mod tests { } fn project_path(project: &str) -> String { - format!("../../test/test_projects/{project}") + format!("../../test_projects/{project}") } fn strip_ansi_codes(s: &str) -> String { diff --git a/crates/elp/src/bin/reporting.rs b/crates/elp/src/bin/reporting.rs index 7ab10459fe..fe38287629 100644 --- a/crates/elp/src/bin/reporting.rs +++ b/crates/elp/src/bin/reporting.rs @@ -227,6 +227,9 @@ impl Reporter for JsonReporter<'_> { diagnostics: &[EqwalizerDiagnostic], ) -> Result<()> { let line_index = self.analysis.line_index(file_id)?; + // Pass include_Tests = false so that errors for tests files that are not opted-in are tagged as + // arc_types::Severity::Disabled and don't break CI. + let eqwalizer_enabled = self.analysis.is_eqwalizer_enabled(file_id, false).unwrap(); let file_path = &self.loaded.vfs.file_path(file_id); let root_path = &self .analysis @@ -235,8 +238,12 @@ impl Reporter for JsonReporter<'_> { .root_dir; let relative_path = get_relative_path(root_path, file_path); for diagnostic in diagnostics { - let diagnostic = - convert::eqwalizer_to_arc_diagnostic(diagnostic, &line_index, relative_path); + let diagnostic = convert::eqwalizer_to_arc_diagnostic( + diagnostic, + &line_index, + relative_path, + eqwalizer_enabled, + ); let diagnostic = serde_json::to_string(&diagnostic)?; writeln!(self.cli, "{diagnostic}")?; } diff --git a/crates/elp/src/bin/shell.rs b/crates/elp/src/bin/shell.rs index 13ff79ed36..84ab218710 100644 --- a/crates/elp/src/bin/shell.rs +++ b/crates/elp/src/bin/shell.rs @@ -157,9 +157,10 @@ impl ShellCommand { } "eqwalize-app" => { let include_generated = options.contains(&"--include-generated"); + let include_tests = options.contains(&"--include-tests"); if let Some(other) = options .into_iter() - .find(|&opt| opt != "--include-generated") + .find(|&opt| opt != "--include-generated" && opt != "--include-tests") { return Err(ShellError::UnexpectedOption( "eqwalize-app".into(), @@ -176,6 +177,7 @@ impl ShellCommand { rebar, app: app.into(), include_generated, + include_tests, bail_on_error: false, }))); } @@ -183,9 +185,10 @@ impl ShellCommand { } "eqwalize-all" => { let include_generated = options.contains(&"--include-generated"); + let include_tests = options.contains(&"--include-tests"); if let Some(other) = options .into_iter() - .find(|&opt| opt != "--include-generated") + .find(|&opt| opt != "--include-generated" && opt != "--include-tests") { return Err(ShellError::UnexpectedOption( "eqwalize-all".into(), @@ -201,6 +204,7 @@ impl ShellCommand { rebar, format: None, include_generated, + include_tests, bail_on_error: false, stats: false, list_modules: false, @@ -222,8 +226,10 @@ COMMANDS: eqwalize Eqwalize specified modules --clause-coverage Use experimental clause coverage checker eqwalize-all Eqwalize all modules in the current project + --include-tests Also eqwalize test modules from project --clause-coverage Use experimental clause coverage checker eqwalize-app Eqwalize all modules in specified application + --include-tests Also eqwalize test modules from project --clause-coverage Use experimental clause coverage checker "; diff --git a/crates/elp/src/bin/ssr_cli.rs b/crates/elp/src/bin/ssr_cli.rs index 36f26d4554..f5729034b2 100644 --- a/crates/elp/src/bin/ssr_cli.rs +++ b/crates/elp/src/bin/ssr_cli.rs @@ -401,9 +401,6 @@ fn do_parse_one( name: &str, args: &Ssr, ) -> Result)>> { - if !args.include_generated && db.is_generated(file_id)? { - return Ok(None); - } if !args.include_tests && db.is_test_suite_or_test_helper(file_id)?.unwrap_or(false) { return Ok(None); } diff --git a/crates/elp/src/config.rs b/crates/elp/src/config.rs index 681a022261..2637eae5a2 100644 --- a/crates/elp/src/config.rs +++ b/crates/elp/src/config.rs @@ -30,7 +30,7 @@ use serde::de::DeserializeOwned; use serde_json::json; use crate::from_json; -// @fb-only: use crate::meta_only; +// @fb-only // Defines the server-side configuration of ELP. We generate *parts* // of VS Code's `package.json` config from this. @@ -180,7 +180,7 @@ impl Config { return; } self.data = ConfigData::from_json(json); - // @fb-only: meta_only::harmonise_gks(self); + // @fb-only } pub fn update_gks(&mut self, json: serde_json::Value) { diff --git a/crates/elp/src/convert.rs b/crates/elp/src/convert.rs index c8db07a5d0..3715353c11 100644 --- a/crates/elp/src/convert.rs +++ b/crates/elp/src/convert.rs @@ -126,11 +126,18 @@ pub fn eqwalizer_to_arc_diagnostic( d: &EqwalizerDiagnostic, line_index: &LineIndex, relative_path: &Path, + eqwalizer_enabled: bool, ) -> arc_types::Diagnostic { let pos = position(line_index, d.range.start()); let line_num = pos.line + 1; let character = Some(pos.character + 1); - let severity = arc_types::Severity::Error; + let severity = if eqwalizer_enabled { + arc_types::Severity::Error + } else { + // We use Severity::Disabled so that diagnostics are reported in cont lint + // but not in CI. + arc_types::Severity::Disabled + }; // formatting: https://fburl.com/max_wiki_link_to_phabricator_rich_text let explanation = match &d.explanation { Some(s) => format!("```\n{s}\n```"), diff --git a/crates/elp/src/lib.rs b/crates/elp/src/lib.rs index f462141e39..0e9a2e28e6 100644 --- a/crates/elp/src/lib.rs +++ b/crates/elp/src/lib.rs @@ -37,7 +37,7 @@ pub mod line_endings; pub mod lsp_ext; mod mem_docs; pub mod memory_usage; -// @fb-only: mod meta_only; +// @fb-only mod op_queue; mod project_loader; pub mod reload; @@ -108,7 +108,7 @@ pub fn otp_file_to_ignore(db: &Analysis, file_id: FileId) -> bool { "redbug_dtop", ] .iter() - // @fb-only: .chain(meta_only::FILES_TO_IGNORE.iter()) + // @fb-only .map(SmolStr::new) .collect(); } diff --git a/crates/elp/src/resources/test/buck_bad_config/bxl_error_message_oss.stdout b/crates/elp/src/resources/test/buck_bad_config/bxl_error_message_oss.stdout deleted file mode 100644 index f5225605a5..0000000000 --- a/crates/elp/src/resources/test/buck_bad_config/bxl_error_message_oss.stdout +++ /dev/null @@ -1 +0,0 @@ -Project Initialisation Failed: invalid or missing buck 2 configuration diff --git a/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout b/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout deleted file mode 100644 index eef1c92c6d..0000000000 --- a/crates/elp/src/resources/test/diagnostics/lint_no_stream.stdout +++ /dev/null @@ -1,138 +0,0 @@ -Reporting all diagnostics codes -Diagnostics reported: -app_a/src/app_a.erl:52:3-52:23::[Warning] [W0006] this statement has no effect -app_a/src/app_a.erl:3:10-3:21::[WeakWarning] [W0037] Unspecific include. -app_a/src/app_a.erl:27:3-27:9::[Warning] [W0017] Function 'foo:ok/0' is undefined. -app_a/src/app_a.erl:28:4-28:11::[Warning] [W0017] Function 'mod:foo/0' is undefined. -app_a/src/app_a.erl:72:4-72:11::[Warning] [W0017] Function 'foo:bar/2' is undefined. -app_a/src/app_a.erl:37:11-37:28::[Warning] [W0017] Function 'mod_name:fun_name/2' is undefined. -app_a/src/app_a.erl:58:11-58:24::[WeakWarning] [W0051] Binary string can be written using sigil syntax. -app_a/src/app_a.erl:4:1-4:41::[Warning] [W0020] Unused file: inets/include/httpd.hrl -app_a/src/app_a.erl:39:7-39:28::[Error] [L1267] variable 'A' shadowed in 'named fun' -app_a/src/app_a.erl:55:32-55:35::[Error] [L1295] type uri/0 undefined -app_a/src/app_a.erl:56:20-56:26::[Error] [L1295] type binary/1 undefined -app_a/src/app_a.erl:72:3-72:34::[Error] [L1252] record record undefined -app_a/src/app_a.erl:75:5-75:16::[Error] [L1252] record record undefined -app_a/src/app_a.erl:35:1-35:2::[Warning] [L1230] function g/1 is unused -app_a/src/app_a.erl:35:3-35:4::[Warning] [L1268] variable 'A' is unused -app_a/src/app_a.erl:36:3-36:4::[Warning] [L1268] variable 'F' is unused -app_a/src/app_a.erl:37:3-37:4::[Warning] [L1268] variable 'G' is unused -app_a/src/app_a.erl:38:3-38:4::[Warning] [L1268] variable 'H' is unused -app_a/src/app_a.erl:39:3-39:4::[Warning] [L1268] variable 'I' is unused -app_a/src/app_a.erl:39:7-39:28::[Warning] [L1268] variable 'A' is unused -app_a/src/app_a.erl:41:1-41:2::[Warning] [L1230] function h/0 is unused -app_a/src/app_a.erl:45:1-45:2::[Warning] [L1230] function i/0 is unused -app_a/src/app_a.erl:50:1-50:2::[Warning] [L1230] function j/2 is unused -app_a/src/app_a.erl:50:15-50:16::[Warning] [L1268] variable 'A' is unused -app_a/src/app_a.erl:50:23-50:24::[Warning] [L1268] variable 'B' is unused -app_a/src/app_a.erl:55:1-55:46::[Warning] [L1296] type session(_) is unused -app_a/src/app_a.erl:55:1-55:46::[Warning] [L1313] opaque type session(_) is not exported -app_a/src/app_a.erl:56:7-56:13::[Warning] [L1296] type source(_) is unused -app_a/src/app_a.erl:58:1-58:4::[Warning] [L1230] function map/2 is unused -app_a/src/app_a.erl:60:1-60:9::[Warning] [L1230] function with_dot/0 is unused -app_a/src/app_a.erl:62:1-62:9::[Warning] [L1230] function lang_dir/1 is unused -app_a/src/app_a.erl:66:1-66:7::[Warning] [L1230] function escape/1 is unused -app_a/src/app_a.erl:66:13-66:17::[Warning] [L1268] variable 'T' is unused -app_a/src/app_a.erl:67:9-67:25::[Warning] [L1260] record all_configs_file is unused -app_a/src/app_a.erl:71:1-71:2::[Warning] [L1230] function k/0 is unused -app_a/src/app_a.erl:74:1-74:2::[Warning] [L1230] function l/1 is unused -app_a/src/app_a.erl:77:1-77:2::[Warning] [L1230] function m/0 is unused -app_a/src/broken_parse_trans.erl:10:21-10:22::[Error] [L1256] field b undefined in record a -app_a/src/broken_parse_trans.erl:10:32-10:33::[Error] [L1262] variable 'B' is unbound -app_a/src/cascading.erl:9:5-9:6::[Error] [W0004] Missing ')' - 3:10-3:15: function foo/0 undefined - 6:10-6:15: function foo/0 undefined - 8:7-8:10: spec for undefined function foo/0 -app_a/src/diagnostics.erl:3:10-3:27::[WeakWarning] [W0037] Unspecific include. -app_a/src/diagnostics.erl:4:10-4:34::[WeakWarning] [W0037] Unspecific include. -app_a/src/diagnostics.erl:12:8-12:12::[Warning] [W0060] Match on a bound variable -app_a/src/diagnostics.erl:4:1-4:36::[Error] [L0000] Issue in included file - [app_a/include/broken_diagnostics.hrl] 1:8-1:15: P1702: bad attribute - [app_a/include/broken_diagnostics.hrl] 3:6-3:15: P1702: bad attribute -app_a/src/diagnostics.erl:6:31-6:45::[Error] [L1295] type undefined_type/0 undefined -app_a/src/diagnostics.erl:7:1-7:5::[Warning] [L1230] function main/1 is unused -app_a/src/diagnostics.erl:10:1-10:4::[Warning] [L1230] function foo/0 is unused -app_a/src/lint_recursive.erl:23:5-23:14::[Warning] [W0006] this statement has no effect -app_a/src/lint_recursive.erl:6:5-6:7::[Warning] [W0006] this statement has no effect -app_a/src/lint_recursive.erl:14:5-14:12::[Warning] [L1268] variable 'Config1' is unused -app_a/src/lint_recursive.erl:19:5-19:12::[Warning] [L1268] variable 'Config1' is unused -app_a/src/lints.erl:5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch' - 4:1-4:14: Mismatched clause name -app_a/src/lints.erl:4:22-4:23::[Warning] [W0018] Unexpected ';' -app_a/src/lints.erl:2:10-2:25::[Error] [L1227] function head_mismatch/1 undefined -app_a/src/otp27_docstrings.erl:34:9-34:24::[Warning] [W0002] Unused macro (THIS_IS_THE_END) -app_a/src/otp27_docstrings.erl:24:5-24:6::[Warning] [W0060] Match on a bound variable -app_a/src/otp27_docstrings.erl:30:5-30:6::[Warning] [W0060] Match on a bound variable -app_a/src/otp27_sigils.erl:11:6-11:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:12:5-12:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:13:5-13:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:14:5-14:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:15:5-15:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:17:6-17:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:18:5-18:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:19:5-19:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:20:5-20:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:21:5-21:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:23:6-23:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:24:5-24:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:25:5-25:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:26:5-26:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:27:5-27:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:29:6-29:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:30:5-30:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:31:5-31:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:32:5-32:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:33:5-33:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:35:6-35:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:36:5-36:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:37:5-37:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:38:5-38:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:39:5-39:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:41:6-41:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:42:5-42:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:43:5-43:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:44:5-44:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:45:5-45:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:47:6-47:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:48:5-48:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:49:5-49:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:50:5-50:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:51:5-51:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:53:6-53:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:53:6-53:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:54:5-54:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:54:5-54:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:55:5-55:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:55:5-55:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:56:5-56:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:57:5-57:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:59:6-59:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:60:5-60:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:61:5-61:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:62:5-62:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:63:5-63:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:65:6-65:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:66:5-66:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:67:5-67:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:68:5-68:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:69:5-69:24::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:76:5-79:8::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:76:5-79:8::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:80:5-84:9::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:80:5-84:9::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:85:5-89:10::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:85:5-89:10::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:90:5-94:11::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:95:5-99:12::[Warning] [W0006] this statement has no effect -app_a/src/otp27_sigils.erl:102:5-102:24::[WeakWarning] [W0051] Binary string can be written using sigil syntax. -app_a/src/otp27_sigils.erl:128:9-128:24::[Warning] [W0002] Unused macro (THIS_IS_THE_END) -app_a/src/otp27_sigils.erl:112:4-112:5::[Error] [P1711] syntax error before: X - 4:15-4:18: function g/0 undefined - 74:7-74:8: spec for undefined function g/0 -app_a/src/otp27_sigils.erl:71:5-71:6::[Warning] [L1268] variable 'X' is unused -app_a/src/otp_7655.erl:5:1-5:28::[Error] [L1201] no module definition -app_a/src/parse_error_a_cascade.erl:10:20-11:1::[Error] [W0004] Missing 'atom' - 6:6-6:11: function bar/0 undefined -app_a/src/suppressed.erl:8:5-8:9::[Warning] [L1268] variable 'Life' is unused -app_a/src/syntax.erl:5:46-5:47::[Error] [P1711] syntax error before: ')' -app_a/src/syntax.erl:11:9-11:10::[Error] [W0004] Missing ')' diff --git a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout index 4b0a155055..7fe610f781 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout +++ b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics1.stdout @@ -1,10 +1,9 @@ module specified: diagnostics Diagnostics reported in 1 modules: - diagnostics: 7 + diagnostics: 6 2:9-2:26::[Hint] [W0037] Unspecific include. 3:0-3:35::[Error] [L0000] Issue in included file 3:9-3:33::[Hint] [W0037] Unspecific include. 5:30-5:44::[Error] [L1295] type undefined_type/0 undefined 6:0-6:4::[Warning] [L1230] function main/1 is unused 9:0-9:3::[Warning] [L1230] function foo/0 is unused - 11:7-11:11::[Warning] [W0060] Match on a bound variable diff --git a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_error.stdout b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_error.stdout deleted file mode 100644 index 3af8bfb086..0000000000 --- a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_error.stdout +++ /dev/null @@ -1,5 +0,0 @@ -module specified: diagnostics -Diagnostics reported in 1 modules: - diagnostics: 2 - 3:0-3:35::[Error] [L0000] Issue in included file - 5:30-5:44::[Error] [L1295] type undefined_type/0 undefined diff --git a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout index ede82c7c5f..0c3e5ae9a3 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout +++ b/crates/elp/src/resources/test/diagnostics/parse_all_diagnostics_json.stdout @@ -4,4 +4,3 @@ {"path":"app_a/src/diagnostics.erl","line":6,"char":31,"code":"ELP","severity":"error","name":"L1295 (L1295)","original":null,"replacement":null,"description":"type undefined_type/0 undefined\n\nFor more information see: /erlang-error-index/l/L1295","docPath":null} {"path":"app_a/src/diagnostics.erl","line":7,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function main/1 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} {"path":"app_a/src/diagnostics.erl","line":10,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function foo/0 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null} -{"path":"app_a/src/diagnostics.erl","line":12,"char":8,"code":"ELP","severity":"warning","name":"W0060 (bound_var_in_lhs)","original":null,"replacement":null,"description":"Match on a bound variable\n\nFor more information see: /erlang-error-index/w/W0060","docPath":"website/docs/erlang-error-index/w/W0060.md"} diff --git a/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl b/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl index c34c9037db..5e286c673f 100644 --- a/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl +++ b/crates/elp/src/resources/test/diagnostics/parse_otp27_docstrings.jsonl @@ -1,6 +1,4 @@ module specified: otp27_docstrings Diagnostics reported in 1 modules: - otp27_docstrings: 3 - 23:4-23:5::[Warning] [W0060] Match on a bound variable - 29:4-29:5::[Warning] [W0060] Match on a bound variable + otp27_docstrings: 1 33:8-33:23::[Warning] [W0002] Unused macro (THIS_IS_THE_END) diff --git a/crates/elp/src/resources/test/diagnostics/ssr_exclude_generated.stdout b/crates/elp/src/resources/test/diagnostics/ssr_exclude_generated.stdout deleted file mode 100644 index 1cef26124c..0000000000 --- a/crates/elp/src/resources/test/diagnostics/ssr_exclude_generated.stdout +++ /dev/null @@ -1,2 +0,0 @@ -module specified: erlang_diagnostics_errors_gen -No matches found diff --git a/crates/elp/src/resources/test/diagnostics/ssr_include_generated.stdout b/crates/elp/src/resources/test/diagnostics/ssr_include_generated.stdout deleted file mode 100644 index 2b88b6e10c..0000000000 --- a/crates/elp/src/resources/test/diagnostics/ssr_include_generated.stdout +++ /dev/null @@ -1,5 +0,0 @@ -module specified: erlang_diagnostics_errors_gen - erlang_diagnostics_errors_gen: 1 - 6:5-6:7::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ok. - -Matches found in 1 modules diff --git a/crates/elp/src/resources/test/eqwalize_all_help.stdout b/crates/elp/src/resources/test/eqwalize_all_help.stdout index 67497c4000..43f66a0a3a 100644 --- a/crates/elp/src/resources/test/eqwalize_all_help.stdout +++ b/crates/elp/src/resources/test/eqwalize_all_help.stdout @@ -1,10 +1,11 @@ -Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--bail-on-error] [--stats] [--list-modules] +Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--include-tests] [--bail-on-error] [--stats] [--list-modules] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) --as Rebar3 profile to pickup (default is test) --format Show diagnostics in JSON format --rebar Run with rebar + --include-tests Also eqwalize test modules from project --bail-on-error Exit with a non-zero status code if any errors are found --stats Print statistics when done --list-modules When printing statistics, include the list of modules parsed diff --git a/crates/elp/src/resources/test/eqwalize_app.stdout b/crates/elp/src/resources/test/eqwalize_app.stdout index bb128f249a..eaf1d3126a 100644 --- a/crates/elp/src/resources/test/eqwalize_app.stdout +++ b/crates/elp/src/resources/test/eqwalize_app.stdout @@ -1,4 +1,4 @@ -Usage: [--project PROJECT] [--as PROFILE] [--rebar] [--bail-on-error] +Usage: [--project PROJECT] [--as PROFILE] [--include-tests] [--rebar] [--bail-on-error] Available positional items: app name @@ -6,6 +6,7 @@ Available positional items: Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) --as Rebar3 profile to pickup (default is test) + --include-tests Also eqwalize test modules from project --rebar Run with rebar --bail-on-error Exit with a non-zero status code if any errors are found -h, --help Prints help information diff --git a/crates/elp/src/resources/test/eqwalize_target_help.stdout b/crates/elp/src/resources/test/eqwalize_target_help.stdout index e9a01166dd..eec74e4938 100644 --- a/crates/elp/src/resources/test/eqwalize_target_help.stdout +++ b/crates/elp/src/resources/test/eqwalize_target_help.stdout @@ -1,9 +1,10 @@ -Usage: [--project PROJECT] [--bail-on-error] +Usage: [--project PROJECT] [--include-tests] [--bail-on-error] Available positional items: target, like //erl/chatd/... Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) + --include-tests Also eqwalize test modules from project --bail-on-error Exit with a non-zero status code if any errors are found -h, --help Prints help information diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-26.pretty new file mode 100644 index 0000000000..63be36e638 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-26.pretty @@ -0,0 +1,14 @@ +error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) + ┌─ check/src/callbacks3_neg.erl:12:1 + │ +12 │ -behavior(gen_server). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}, Got: 'wrong_ret'. + │ + + 'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} + because + 'wrong_ret' is not compatible with {'noreply', term()} + +1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-27.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-27.pretty new file mode 100644 index 0000000000..63be36e638 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-27.pretty @@ -0,0 +1,14 @@ +error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) + ┌─ check/src/callbacks3_neg.erl:12:1 + │ +12 │ -behavior(gen_server). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}, Got: 'wrong_ret'. + │ + + 'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} + because + 'wrong_ret' is not compatible with {'noreply', term()} + +1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-28.pretty new file mode 100644 index 0000000000..a24c7a6a48 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg-OTP-28.pretty @@ -0,0 +1,14 @@ +error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) + ┌─ check/src/callbacks3_neg.erl:12:1 + │ +12 │ -behavior(gen_server). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), gen_server:action()} | {'stop', term(), term()}, Got: 'wrong_ret'. + │ + + 'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), gen_server:action()} | {'stop', term(), term()} + because + 'wrong_ret' is not compatible with {'noreply', term()} + +1 ERROR diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg.pretty deleted file mode 100644 index 6cb2012096..0000000000 --- a/crates/elp/src/resources/test/eqwalizer_tests/check/callbacks3_neg.pretty +++ /dev/null @@ -1,27 +0,0 @@ -error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) - ┌─ check/src/callbacks3_neg.erl:13:1 - │ -13 │ -behavior(gen_server). - │ ^^^^^^^^^^^^^^^^^^^^^ Incorrect return type for implementation of gen_server:handle_cast/2. -Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} -Got: 'wrong_ret' - -error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation) - ┌─ check/src/callbacks3_neg.erl:13:1 - │ -13 │ -behavior(gen_server). - │ ^^^^^^^^^^^^^^^^^^^^^ - │ │ - │ Incorrect return type for implementation of gen_server:handle_info/2. -Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()} -Got: {'noreply', 'ok', 'wrong_atom'} - │ - -Because in the expression's type: - { 'noreply', 'ok', - Here the type is: 'wrong_atom' - Context expects type: 'infinity' | number() | 'hibernate' | {'continue', term()} - No candidate matches in the expected union. - } - -2 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty new file mode 100644 index 0000000000..370f7689e9 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-26.pretty @@ -0,0 +1,3258 @@ +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:26:5 + │ +26 │ element(4, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(4, Tup). +Expression has type: #{dynamic() => dynamic()} +Context expected type: atom() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:30:5 + │ +30 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 3 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:40:5 + │ +40 │ element(2, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(2, Tup). +Expression has type: number() | string() | atom() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:44:16 + │ +44 │ element(2, Tup). + │ ^^^ + │ │ + │ Tup. +Expression has type: {atom(), string()} | [dynamic()] +Context expected type: tuple() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {atom(), string()} + However the following candidate: [dynamic()] + Differs from the expected type: tuple() + +------------------------------ Detailed message ------------------------------ + + {atom(), string()} | [dynamic()] is not compatible with tuple() + because + [dynamic()] is not compatible with tuple() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:48:5 + │ +48 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 2 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:54:5 + │ +54 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(N, Tup). +Expression has type: atom() | number() | string() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:58:5 + │ +58 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Tup). +Expression has type: atom() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + atom() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:68:5 + │ +68 │ element(1, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(1, Tup). +Expression has type: dynamic() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: dynamic() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:86:5 + │ +86 │ element(N, Rec). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Rec). +Expression has type: 'foo' | 'ok' | 'error' | number() | string() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'error' | 'foo' | 'ok' + However the following candidate: string() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + 'foo' | 'ok' | 'error' | number() | string() is not compatible with atom() + because + string() is not compatible with atom() + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:91:1 + │ +91 │ ╭ element_2_none_1(Tup) -> +92 │ │ element(42, Tup). + │ ╰────────────────────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:95:1 + │ +95 │ ╭ element_2_none_2(N, Tup) -> +96 │ │ element(N, Tup). + │ ╰───────────────────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:108:5 + │ +108 │ maps:get(K, M). + │ ^^^^^^^^^^^^^^ maps:get(K, M). +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:128:5 + │ +128 │ Res. + │ ^^^ Res. +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:154:12 + │ +154 │ get(a, M). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:160:23 + │ +160 │ Res = maps:get(a, M), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:167:17 + │ +167 │ maps:get(a, M, false). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:173:23 + │ +173 │ Res = maps:get(a, M, false), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:193:5 + │ +193 │ maps:get(K, M, 0). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(K, M, 0). +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:200:5 + │ +200 │ Res. + │ ^^^ + │ │ + │ Res. +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:206:5 + │ +206 │ ╭ ╭ { +207 │ │ │ maps:get(a, M, undefined), +208 │ │ │ maps:get(n, M, undefined) +209 │ │ │ }. + │ ╰─│─────^ {maps:get('a', M, 'undefined'), maps:get('n', M, 'undefined')}. +Expression has type: {atom(), 'undefined' | number()} +Context expected type: {atom(), number()} + │ ╰─────' + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: 'undefined' + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), 'undefined' | number()} is not compatible with {atom(), number()} + because + 'undefined' | number() is not compatible with number() + because + 'undefined' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:221:27 + │ +221 │ map_get_2_17_neg(V, M) -> maps:get(V, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M). +Expression has type: 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' + +------------------------------ Detailed message ------------------------------ + + 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:233:27 + │ +233 │ map_get_3_19_neg(V, M) -> maps:get(V, M, undefined). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M, 'undefined'). +Expression has type: 'undefined' | 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' | 'undefined' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'undefined' | 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' | 'undefined' + +------------------------------ Detailed message ------------------------------ + + 'undefined' | 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:309:5 + │ +309 │ Res. + │ ^^^ Res. +Expression has type: {'value', #{}} | 'false' +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:363:23 + │ +363 │ fun (_, _) -> self() end, + │ ^^^^^^ erlang:self(). +Expression has type: pid() +Context expected type: boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:382:17 + │ +382 │ maps:filter(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> boolean()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:389:17 + │ +389 │ maps:filter(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((T) -> boolean()), [T]) -> [T]) with 1 type parameter +Context expected type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun()/2 with 1 type parameter + Context expects type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:413:37 + │ +413 │ maps:filter(fun erlang:'=:='/2, X). + │ ^ + │ │ + │ X. +Expression has type: #{K => V} | 'a' +Context expected type: #{term() => term()} | maps:iterator() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: #{K => V} + However the following candidate: 'a' + Differs from the expected type: #{term() => term()} | maps:iterator() + +------------------------------ Detailed message ------------------------------ + + #{K => V} | 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:425:20 + │ +425 │ maps:filter(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:454:5 + │ +454 │ ╭ ╭ maps:map( +455 │ │ │ fun (_, _) -> self() end, +456 │ │ │ M +457 │ │ │ ). + │ ╰─│─────^ maps:map(fun, M). +Expression has type: #{number() => pid()} +Context expected type: #{number() => boolean()} + │ ╰─────' + +Because in the expression's type: + #{ number() => + Here the type is: pid() + Context expects type: boolean() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{number() => pid()} is not compatible with #{number() => boolean()} + the default associations are not compatible + because + pid() is not compatible with boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:474:14 + │ +474 │ maps:map(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> term()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:481:14 + │ +481 │ maps:map(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters +Context expected type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters + Context expects type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:497:5 + │ +497 │ maps:map(F, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:map(F, M). +Expression has type: #{a := boolean(), b := boolean()} +Context expected type: #{a => 'a', b => 'b'} + │ + +Because in the expression's type: + #{ a => + Here the type is: boolean() + Context expects type: 'a' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + at key `a`: + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + boolean() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:503:17 + │ +503 │ maps:map(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:538:9 + │ +538 │ fun (K, V) -> [K, V] end, [], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ fun. +fun with arity 2 used as fun with 3 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:544:5 + │ +544 │ ╭ ╭ maps:fold( +545 │ │ │ fun (_, _, Acc) -> [Acc] end, +546 │ │ │ [], +547 │ │ │ M +548 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [[[]]] +Context expected type: [number() | 'a' | 'b'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: [[]] + Context expects type: number() | 'a' | 'b' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [[[]]] is not compatible with [number() | 'a' | 'b'] + because + [[]] is not compatible with number() | 'a' | 'b' + because + [[]] is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:545:28 + │ +545 │ fun (_, _, Acc) -> [Acc] end, + │ ^^^^^ + │ │ + │ [Acc]. +Expression has type: [[[[]]]] +Context expected type: [[[]]] + │ + +Because in the expression's type: + [ + [ + [ + Here the type is: [] + Context expects type: none() + ] + ] + ] + +------------------------------ Detailed message ------------------------------ + + [[[[]]]] is not compatible with [[[]]] + because + [[[]]] is not compatible with [[]] + because + [[]] is not compatible with [] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:552:5 + │ +552 │ ╭ maps:fold( +553 │ │ fun (_, _, Acc) -> Acc end, +554 │ │ [], +555 │ │ non_kv +556 │ │ ). + │ ╰─────^ maps:fold(fun, [], 'non_kv'). +Expression has type: [] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:555:9 + │ +555 │ non_kv + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:560:1 + │ +560 │ ╭ maps_fold_3_6(None) -> +561 │ │ maps:fold( +562 │ │ None, +563 │ │ #{}, +564 │ │ #{1 => 1} +565 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:568:1 + │ +568 │ ╭ maps_fold_3_7(None) -> +569 │ │ maps:fold( +570 │ │ None, +571 │ │ None, +572 │ │ None +573 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:578:5 + │ +578 │ ╭ ╭ maps:fold( +579 │ │ │ fun (_K, A, _Acc) -> A end, +580 │ │ │ [], +581 │ │ │ M +582 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [] | atom() +Context expected type: atom() + │ ╰─────' + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: [] + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + [] | atom() is not compatible with atom() + because + [] is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', []) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun((number(), 'a', []) -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> [] | dynamic()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:636:5 + │ +636 │ ╭ ╭ maps:fold( +637 │ │ │ fun +638 │ │ │ (_K, {i, I}, Acc) -> +639 │ │ │ [I | Acc]; + · │ │ +646 │ │ │ M +647 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [number() | binary() | atom()] +Context expected type: [binary()] | [number()] | [atom()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: number() + Differs from the expected type: binary() + ] + +------------------------------ Detailed message ------------------------------ + + [number() | binary() | atom()] is not compatible with [binary()] | [number()] | [atom()] + because + [number() | binary() | atom()] is not compatible with [binary()] + because + number() | binary() | atom() is not compatible with binary() + because + number() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:671:41 + │ +671 │ maps_to_list_7_neg(Num) -> maps:to_list(Num). + │ ^^^ + │ │ + │ Num. +Expression has type: number() +Context expected type: #{term() => term()} | maps:iterator() + │ + + number() is not compatible with #{term() => term()} | maps:iterator() + because + number() is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:675:25 + │ +675 │ maps_merge_1(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:679:25 + │ +679 │ maps_merge_2(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number() | boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number() | boolean(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:683:25 + │ +683 │ maps_merge_3(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a := string(), b := boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:697:44 + │ +697 │ maps_merge_7_neg(M1, M2) -> maps:merge(M1, M2). + │ ^^ M2. +Expression has type: number() +Context expected type: #{a => binary()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:701:25 + │ +701 │ maps_merge_8(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'a' | 'b' => atom() | number()} +Context expected type: #{a := atom(), b := number()} | #{a := atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} | #{a := atom()} + because + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} + keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:721:9 + │ +721 │ fun erlang:binary_to_list/1, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:binary_to_list/1. +Expression has type: fun((binary()) -> [number()]) +Context expected type: fun((number()) -> boolean() | {'true', term()}) + │ + +Because in the expression's type: + fun((binary()) -> + Here the type is: [number()] + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((binary()) -> [number()]) is not compatible with fun((number()) -> boolean() | {'true', term()}) + because + [number()] is not compatible with boolean() | {'true', term()} + because + [number()] is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:739:20 + │ +739 │ (3) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:749:9 + │ +749 │ not_a_list + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:791:17 + │ +791 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: {'true', 'a'} | 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {'true', 'a'} + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | {'true', term()} + +------------------------------ Detailed message ------------------------------ + + {'true', 'a'} | 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:827:9 + │ +827 │ ╭ ╭ fun (a) -> [a]; +828 │ │ │ (b) -> true; +829 │ │ │ (c) -> wrong_ret end, + │ ╰─│────────────────────────────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰────────────────────────────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'true' + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'true' | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:829:20 + │ +829 │ (c) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:9 + │ +837 │ ╭ ╭ fun (1) -> {true, a}; +838 │ │ │ (2) -> true end, + │ ╰─│───────────────────────────^ fun. +Expression has type: fun((dynamic()) -> {'true', 'a'} | 'true') +Context expected type: fun((Item) -> boolean() | [Item]) + │ ╰───────────────────────────' + +Because in the expression's type: + fun((dynamic()) -> + Here the type is a union type with some valid candidates: 'true' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | [Item] + ) + +------------------------------ Detailed message ------------------------------ + + fun((dynamic()) -> {'true', 'a'} | 'true') is not compatible with fun((Item) -> boolean() | [Item]) + because + {'true', 'a'} | 'true' is not compatible with boolean() | [Item] + because + {'true', 'a'} is not compatible with boolean() | [Item] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:20 + │ +837 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | [dynamic()] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(Item) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[Item], [Item]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(Item) + because + 'not_a_queue' is not compatible with {[Item], [Item]} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(dynamic()) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[dynamic()], [dynamic()]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(dynamic()) + because + 'not_a_queue' is not compatible with {[dynamic()], [dynamic()]} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:846:9 + │ +846 │ ╭ fun (wrong, arity) -> +847 │ │ [a] +848 │ │ end, + │ ╰───────────^ fun. +fun with arity 2 used as fun with 1 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:9 + │ +857 │ ╭ ╭ fun (1) -> {true, a}; +858 │ │ │ (X) -> case X of +859 │ │ │ true -> +860 │ │ │ [a]; + · │ │ +863 │ │ │ end +864 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'false' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'false' | {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + because + {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:20 + │ +857 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:873:9 + │ +873 │ ╭ ╭ fun (a) -> [a]; +874 │ │ │ (X) -> +875 │ │ │ Res = case X of +876 │ │ │ true -> + · │ │ +881 │ │ │ Res +882 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:881:17 + │ +881 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: ['a'] | 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + +------------------------------ Detailed message ------------------------------ + + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun((dynamic()) -> boolean() | [dynamic()]) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun((dynamic()) -> boolean() | [dynamic()]) + because + atom() is not compatible with boolean() | [dynamic()] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + atom() is not compatible with boolean() | ['a' | 'b'] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:925:1 + │ +925 │ ╭ queue_filter_13_neg(Q) -> +926 │ │ queue:filter( +927 │ │ fun atom_to_list/1, +928 │ │ Q +929 │ │ ), +930 │ │ ok. + │ ╰──────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:955:5 + │ +955 │ ╭ lists:keystore( +956 │ │ a, 1, +957 │ │ [{foo, b}, {c, d}], +958 │ │ non_tuple +959 │ │ ). + │ ╰─────^ lists:keystore('a', 1, [{'foo', 'b'}, {'c', 'd'}], 'non_tuple'). +Expression has type: [{'foo', 'b'} | {'c', 'd'} | dynamic()] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:958:9 + │ +958 │ non_tuple + │ ^^^^^^^^^ 'non_tuple'. +Expression has type: 'non_tuple' +Context expected type: tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:966:5 + │ +966 │ ╭ lists:keystore( +967 │ │ a, 1, +968 │ │ [non_tuple], +969 │ │ {replacement} +970 │ │ ). + │ ╰─────^ lists:keystore('a', 1, ['non_tuple'], {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:968:9 + │ +968 │ [non_tuple], + │ ^^^^^^^^^^^ + │ │ + │ ['non_tuple']. +Expression has type: ['non_tuple'] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: 'non_tuple' + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + ['non_tuple'] is not compatible with [tuple()] + because + 'non_tuple' is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:975:5 + │ +975 │ ╭ lists:keystore( +976 │ │ a, 1, +977 │ │ non_list, +978 │ │ {replacement} +979 │ │ ). + │ ╰─────^ lists:keystore('a', 1, 'non_list', {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:977:9 + │ +977 │ non_list, + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [tuple()] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:983:1 + │ +983 │ ╭ keystore_7(None) -> +984 │ │ lists:keystore( +985 │ │ a, 1, +986 │ │ None, +987 │ │ {replacement} +988 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:991:1 + │ +991 │ ╭ keystore_8(None) -> +992 │ │ lists:keystore( +993 │ │ a, 1, +994 │ │ None, +995 │ │ None +996 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1021:22 + │ +1021 │ lists:keytake(a, non_num, []), + │ ^^^^^^^ 'non_num'. +Expression has type: 'non_num' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1038:15 + │ +1038 │ lists:sum([a, 1]). + │ ^^^^^^ + │ │ + │ ['a', 1]. +Expression has type: ['a' | number()] +Context expected type: [number()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: 'a' + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + ['a' | number()] is not compatible with [number()] + because + 'a' | number() is not compatible with number() + because + 'a' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1042:15 + │ +1042 │ lists:sum(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1100:5 + │ +1100 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' + │ + + term() is not compatible with pid() | 'undefined' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1106:5 + │ +1106 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' | 'v' + │ + + term() is not compatible with pid() | 'undefined' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1111:5 + │ +1111 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1117:5 + │ +1117 │ proplists:get_value(k, L, 3). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 3). +Expression has type: term() +Context expected type: pid() | number() + │ + + term() is not compatible with pid() | number() + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1123:5 + │ +1123 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v1' | 'v2' | 'my_default' + │ + + term() is not compatible with 'v1' | 'v2' | 'my_default' + because + term() is not compatible with 'v1' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1129:5 + │ +1129 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1134:28 + │ +1134 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1139:5 + │ +1139 │ proplists:get_value(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', []). +Expression has type: term() +Context expected type: 'default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1144:1 + │ +1144 │ proplists:get_value(k, [], my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', [], 'my_default'). +Expression has type: term() +Context expected type: 'my_default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1149:28 + │ +1149 │ proplists:get_value(k, b, my_default). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1154:5 + │ +1154 │ proplists:get_bool(b, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_bool('b', L). +Expression has type: boolean() +Context expected type: 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1160:5 + │ +1160 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default'] + because + term() is not compatible with pid() | 'default' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1166:5 + │ +1166 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default' | 'v'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' | 'v' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default' | 'v'] + because + term() is not compatible with pid() | 'default' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1171:5 + │ +1171 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid()] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid()] + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1176:5 + │ +1176 │ proplists:get_all_values(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', []). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:5 + │ +1181 │ proplists:get_all_values(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', 'b'). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:33 + │ +1181 │ proplists:get_all_values(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1186:27 + │ +1186 │ proplists:get_bool(b, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1191:5 + │ +1191 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'c' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['c'] + because + term() is not compatible with 'c' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1197:5 + │ +1197 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['a' | 'b' | 'c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' | 'b' | 'c' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a' | 'b' | 'c'] + because + term() is not compatible with 'a' | 'b' | 'c' + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1202:24 + │ +1202 │ proplists:get_keys(a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1207:5 + │ +1207 │ ╭ ╭ proplists:get_keys( +1208 │ │ │ [{a, b, c}] +1209 │ │ │ ). + │ ╰─│─────^ proplists:get_keys([{'a', 'b', 'c'}]). +Expression has type: [term()] +Context expected type: ['a'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a'] + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1215:5 + │ +1215 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:5 + │ +1220 │ proplists:get_value(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', 'b'). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:28 + │ +1220 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1225:1 + │ +1225 │ proplists:lookup(self(), [a, {b, true}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup(erlang:self(), ['a', {'b', 'true'}]). +Expression has type: 'none' | tuple() +Context expected type: {'b', 'true'} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: tuple() + However the following candidate: 'none' + Differs from the expected type: {'b', 'true'} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1229:25 + │ +1229 │ proplists:lookup(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1239:5 + │ +1239 │ proplists:lookup(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup('k', []). +Expression has type: 'none' | tuple() +Context expected type: 'none' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'none' + However the following candidate: tuple() + Differs from the expected type: 'none' + +------------------------------ Detailed message ------------------------------ + + 'none' | tuple() is not compatible with 'none' + because + tuple() is not compatible with 'none' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1252:29 + │ +1252 │ proplists:lookup_all(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1265:5 + │ +1265 │ ╭ ╭ proplists:lookup_all( +1266 │ │ │ self(), +1267 │ │ │ [] +1268 │ │ │ ). + │ ╰─│─────^ proplists:lookup_all(erlang:self(), []). +Expression has type: [tuple()] +Context expected type: [] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: tuple() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1291:34 + │ +1291 │ proplists:is_defined(self(), b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [A] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1311:5 + │ +1311 │ proplists:split(L, Ks). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:split(L, Ks). +Expression has type: {[[term()]], [term()]} +Context expected type: {[plist('a', 'b')], plist('a', 'b')} + │ + +Because in the expression's type: + { + [ + [ + Here the type is: term() + Context expects type: 'a' | {'a', 'b'} + No candidate matches in the expected union. + ] + ] + , [term()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[[term()]], [term()]} is not compatible with {[plist('a', 'b')], plist('a', 'b')} + because + [[term()]] is not compatible with [plist('a', 'b')] + because + [term()] is not compatible with plist('a', 'b') + because + [term()] is not compatible with ['a' | {'a', 'b'}] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1315:21 + │ +1315 │ proplists:split(b, []). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1319:25 + │ +1319 │ proplists:split([], b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1324:22 + │ +1324 │ proplists:to_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [atom() | {term(), term()} | term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{K => V} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1363:5 + │ +1363 │ proplists:get_value(a, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1368:5 + │ +1368 │ proplists:get_value(X, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value(X, ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1373:5 + │ +1373 │ proplists:get_value(a, [a], b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a'], 'b'). +Expression has type: term() +Context expected type: 'true' | 'b' + │ + + term() is not compatible with 'true' | 'b' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1416:5 + │ +1416 │ file:consult(some_file). + │ ^^^^^^^^^^^^^^^^^^^^^^^ file:consult('some_file'). +Expression has type: {'ok', [dynamic()]} | {'error', {number(), atom(), term()} | 'terminated' | 'badarg' | file:posix() | 'system_limit'} +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1428:5 + │ +1428 │ lists:keysort(2, [{a, c}, {b, d}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:keysort(2, [{'a', 'c'}, {'b', 'd'}]). +Expression has type: [{'a', 'c'} | {'b', 'd'}] +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1432:22 + │ +1432 │ lists:keysort(1, [3]). + │ ^^^ + │ │ + │ [3]. +Expression has type: [number()] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: number() + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [tuple()] + because + number() is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1448:5 + │ +1448 │ ╭ ╭ lists:filtermap( +1449 │ │ │ fun(X) when X div 2 =:= 0 -> +1450 │ │ │ {true, integer_to_list(X)}; +1451 │ │ │ (X) -> + · │ │ +1454 │ │ │ [1, 2, 3, 4] +1455 │ │ │ ). + │ ╰─│─────^ lists:filtermap(fun, [1, 2, 3, 4]). +Expression has type: [string() | number()] +Context expected type: [number()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: string() + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + [string() | number()] is not compatible with [number()] + because + string() | number() is not compatible with number() + because + string() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1482:5 + │ +1482 │ erlang:min(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:min(X, Y). +Expression has type: number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1497:5 + │ +1497 │ erlang:max(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:max(X, Y). +Expression has type: atom() | number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1523:9 + │ +1523 │ abs(Atom). + │ ^^^^ Atom. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1536:31 + │ +1536 │ seq3_4_wip_neg() -> lists:seq(a, 2, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1539:30 + │ +1539 │ seq3_5_neg() -> lists:seq(1, a, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1542:33 + │ +1542 │ seq3_6_neg() -> lists:seq(1, 2, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1570:31 + │ +1570 │ seq2_4_wip_neg() -> lists:seq(a, 2). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1573:30 + │ +1573 │ seq2_5_neg() -> lists:seq(1, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1622:5 + │ +1622 │ ╭ timer:tc( +1623 │ │ fun() -> +1624 │ │ err +1625 │ │ end +1626 │ │ ). + │ ╰─────^ timer:tc(fun). +Expression has type: {number(), 'err'} +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1635:5 + │ +1635 │ ets:lookup(tab, Any). + │ ^^^^^^^^^^^^^^^^^^^^ ets:lookup('tab', Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:5 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ets:lookup(string_lit, Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:16 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1663:18 + │ +1663 │ ets:tab2list("not atom"). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1702:23 + │ +1702 │ lists:flatten([], 1). + │ ^ 1. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1711:19 + │ +1711 │ lists:flatten(3). + │ ^ 3. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1724:8 + │ +1724 │ -> lists:flatten(X). + │ ^^^^^^^^^^^^^^^^ + │ │ + │ lists:flatten(X). +Expression has type: [{A, B} | {B, A}] +Context expected type: [{A, B}] + │ + +Because in the expression's type: + [ + { + Here the type is: B + Context expects type: A + , A} + ] + +------------------------------ Detailed message ------------------------------ + + [{A, B} | {B, A}] is not compatible with [{A, B}] + because + {A, B} | {B, A} is not compatible with {A, B} + because + at tuple index 1: + {B, A} is not compatible with {A, B} + because + B is not compatible with A + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1757:5 + │ +1757 │ ╭ ╭ maps:without( +1758 │ │ │ [a, c, DOrE], +1759 │ │ │ #{ +1760 │ │ │ a => ka, + · │ │ +1764 │ │ │ } +1765 │ │ │ ). + │ ╰─│─────^ maps:without(['a', 'c', DOrE], #{..}). +Expression has type: #{a => 'ka', b => atom(), c => pid(), d => 'kd'} +Context expected type: #{b => atom()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ...} + Context expects type: #{...} + The expected map has no corresponding key for: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared in the former but not in the latter and the latter map has no default association + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1769:18 + │ +1769 │ maps:without(non_list, #{}). + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1773:22 + │ +1773 │ maps:without([], non_map). + │ ^^^^^^^ 'non_map'. +Expression has type: 'non_map' +Context expected type: #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:1808:1 + │ +1808 │ ╭ maps_without_12_neg(None) -> +1809 │ │ maps:without( +1810 │ │ [a, b], +1811 │ │ None +1812 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1818:5 + │ +1818 │ ╭ ╭ maps:without( +1819 │ │ │ Keys, +1820 │ │ │ #{a => self(), b => self()} +1821 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1826:5 + │ +1826 │ ╭ ╭ maps:without( +1827 │ │ │ [a | improper_tail], +1828 │ │ │ #{a => self(), b => self()} +1829 │ │ │ ). + │ ╰─│─────^ maps:without(['a' | 'improper_tail'], #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1827:12 + │ +1827 │ [a | improper_tail], + │ ^^^^^^^^^^^^^^^^ 'improper_tail'. +Expression has type: 'improper_tail' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1837:5 + │ +1837 │ ╭ ╭ maps:without( +1838 │ │ │ Keys, +1839 │ │ │ #{a => ka, b => self()} +1840 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => 'ka', b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1854:5 + │ +1854 │ maps:without([a, b], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:without(['a', 'b'], M). +Expression has type: #{c := 'cv', d := 'dv'} | #{c := 'cv', e => 'ev'} +Context expected type: #{c := atom()} + │ + +Because in the expression's type: + Here the type is: #{d := ...} + Context expects type: #{...} + The expected map has no corresponding key for: d. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1916:23 + │ +1916 │ custom_overloaded(X). + │ ^ + │ │ + │ X. +Expression has type: term() +Context expected type: atom() | binary() + │ + + term() is not compatible with atom() | binary() + because + term() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1939:5 + │ +1939 │ {A, N}. + │ ^^^^^^ + │ │ + │ {A, N}. +Expression has type: {atom(), number() | pid()} +Context expected type: {atom(), number()} + │ + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: pid() + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), number() | pid()} is not compatible with {atom(), number()} + because + number() | pid() is not compatible with number() + because + pid() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2041:5 + │ +2041 │ filename:join(["server", "erl"]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2046:5 + │ +2046 │ filename:join(["server", <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, <<..>>]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2051:5 + │ +2051 │ filename:join([<<>>, ""]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2066:5 + │ +2066 │ filename:join([<<>>, <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, <<..>>]). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2081:19 + │ +2081 │ filename:join([<<>>, self()]). + │ ^^^^^^^^^^^^^^ + │ │ + │ [<<..>>, erlang:self()]. +Expression has type: [binary() | pid()] +Context expected type: [file:name_all()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: pid() + Differs from the expected type: string() | atom() | file:deep_list() | binary() + ] + +------------------------------ Detailed message ------------------------------ + + [binary() | pid()] is not compatible with [file:name_all()] + because + binary() | pid() is not compatible with file:name_all() + because + binary() | pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2086:5 + │ +2086 │ filename:join("server", "erl"). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2091:5 + │ +2091 │ filename:join("server", <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, <<..>>). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2096:5 + │ +2096 │ filename:join(<<>>, ""). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(<<..>>, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2111:5 + │ +2111 │ filename:join(atom, <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join('atom', <<..>>). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2121:25 + │ +2121 │ filename:join(<<>>, self()). + │ ^^^^^^ + │ │ + │ erlang:self(). +Expression has type: pid() +Context expected type: file:name_all() + │ + +Because in the expression's type: + Here the type is: pid() + Context expects type: string() | atom() | file:deep_list() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + pid() is not compatible with file:name_all() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2150:5 + │ +2150 │ ╭ ╭ queue:filter( +2151 │ │ │ fun my_filter1/1, +2152 │ │ │ Q +2153 │ │ │ ). + │ ╰─│─────^ queue:filter(my_filter1/1, Q). +Expression has type: queue:queue(atom() | number()) +Context expected type: queue:queue(number()) + │ ╰─────' + +Because in the expression's type: + { + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: atom() + Differs from the expected type: number() + ] + , [atom() | number()]} + +------------------------------ Detailed message ------------------------------ + + queue:queue(atom() | number()) is not compatible with queue:queue(number()) + because + {[atom() | number()], [atom() | number()]} is not compatible with queue:queue(number()) + because + at tuple index 1: + {[atom() | number()], [atom() | number()]} is not compatible with {[number()], [number()]} + because + [atom() | number()] is not compatible with [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2191:5 + │ +2191 │ M3. + │ ^^ + │ │ + │ M3. +Expression has type: #{count := number(), module := 'foo'} | #{module := 'foo'} +Context expected type: state1() + │ + +Because in the expression's type: + The type is a union type with some valid candidates: #{count := number(), module := 'foo'} + However, the following candidate doesn't match: + Here the type is: #{...} + Context expects type: #{count := ..., ...} + The type of the expression is missing the following required keys: count. + +------------------------------ Detailed message ------------------------------ + + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with state1() + because + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + because + #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + key `count` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2223:13 + │ +2223 │ Atom + Sum + │ ^^^^ Atom. +Expression has type: atom() +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2279:5 + │ +2279 │ maps:remove(A, M). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:remove(A, M). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2320:5 + │ +2320 │ ╭ ╭ maps:filtermap( +2321 │ │ │ fun +2322 │ │ │ (a, V) -> true; +2323 │ │ │ (b, V) -> {true, atom_to_binary(V)}; + · │ │ +2326 │ │ │ M +2327 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{a => atom() | binary(), b => atom() | binary(), c => atom() | binary()} +Context expected type: #{a := atom(), b := binary()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ..., b => ..., ...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2342:5 + │ +2342 │ ╭ ╭ maps:filtermap( +2343 │ │ │ fun (_, V) -> +2344 │ │ │ {true, atom_to_binary(V)} +2345 │ │ │ end, +2346 │ │ │ M +2347 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2354:23 + │ +2354 │ fun (_, _) -> err end, + │ ^^^ + │ │ + │ 'err'. +Expression has type: 'err' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'err' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'err' is not compatible with boolean() | {'true', term()} + because + 'err' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2362:5 + │ +2362 │ ╭ ╭ maps:filtermap( +2363 │ │ │ fun (_, V) -> {true, atom_to_binary(V)} end, +2364 │ │ │ M +2365 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2363:45 + │ +2363 │ fun (_, V) -> {true, atom_to_binary(V)} end, + │ ^ V. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2377:5 + │ +2377 │ re:replace(Subj, "+", "-", [{return, binary}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'binary'}]). +Expression has type: binary() +Context expected type: string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2381:5 + │ +2381 │ re:replace(Subj, "+", "-", [{return, list}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'list'}]). +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2385:22 + │ +2385 │ Res = re:replace(Subj, "+", "-", [{return, list}]), + │ ^^^^ + │ │ + │ Subj. +Expression has type: atom() +Context expected type: iodata() | unicode:charlist() + │ + +Because in the expression's type: + Here the type is: atom() + Context expects type: iolist() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + atom() is not compatible with iodata() | unicode:charlist() + because + atom() is not compatible with iolist() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2386:5 + │ +2386 │ Res. + │ ^^^ Res. +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2390:38 + │ +2390 │ Res = re:replace(Subj, "+", "-", [{return, something}]), + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ [{'return', 'something'}]. +Expression has type: [{'return', 'something'}] +Context expected type: [{'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + │ + +Because in the expression's type: + [ + { 'return', + Here the type is: 'something' + Context expects type: 'iodata' | 'list' | 'binary' + No candidate matches in the expected union. + } + ] + +------------------------------ Detailed message ------------------------------ + + [{'return', 'something'}] is not compatible with [{'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + because + {'return', 'something'} is not compatible with {'newline', 'cr' | 'lf' | 'any' | 'crlf' | 'anycrlf'} | 'notempty_atstart' | 'noteol' | 'bsr_unicode' | 'notbol' | 'global' | {'match_limit_recursion', number()} | 'bsr_anycrlf' | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored' + because + at tuple index 2: + {'return', 'something'} is not compatible with {'return', 'iodata' | 'list' | 'binary'} + because + 'something' is not compatible with 'iodata' | 'list' | 'binary' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2506:5 + │ +2506 │ lists:partition(fun is_number/1, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[number()], [atom()]} +Context expected type: {[atom()], [number()]} + │ + +Because in the expression's type: + { + [ + Here the type is: number() + Context expects type: atom() + ] + , [atom()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[number()], [atom()]} is not compatible with {[atom()], [number()]} + because + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2518:5 + │ +2518 │ lists:partition(fun({_Term, V}) -> is_number(V) end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{term(), number()}], [{term(), atom()}]} +Context expected type: {[{term(), atom()}], [{term(), number()}]} + │ + +Because in the expression's type: + { + [ + { term(), + Here the type is: number() + Context expects type: atom() + } + ] + , [{term(), atom()}]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[{term(), number()}], [{term(), atom()}]} is not compatible with {[{term(), atom()}], [{term(), number()}]} + because + [{term(), number()}] is not compatible with [{term(), atom()}] + because + at tuple index 2: + {term(), number()} is not compatible with {term(), atom()} + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2536:5 + │ +2536 │ lists:partition(fun({ok, _}) -> true; (_) -> false end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} +Context expected type: {[{'ok', atom()}], [{'error', term()}]} + │ + +Because in the expression's type: + { [{'ok', atom()}], + [ + { + Here the type is: 'ok' + Context expects type: 'error' + , atom()} + ] + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} is not compatible with {[{'ok', atom()}], [{'error', term()}]} + because + [{'ok', atom()} | {'error', term()}] is not compatible with [{'error', term()}] + because + {'ok', atom()} | {'error', term()} is not compatible with {'error', term()} + because + at tuple index 1: + {'ok', atom()} is not compatible with {'error', term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2576:33 + │ +2576 │ maps_intersect_2_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2586:33 + │ +2586 │ maps_intersect_4_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a => 'true'} + │ + +Because in the expression's type: + #{ a => + Here the type is: number() + Context expects type: 'true' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a => number()} is not compatible with #{a => 'true'} + because + at key `a`: + #{a => number()} is not compatible with #{a => 'true'} + because + number() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2596:33 + │ +2596 │ maps_intersect_6_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2709:40 + │ +2709 │ (foo, A) -> binary_to_atom(A); + │ ^ A. +Expression has type: atom() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2710:40 + │ +2710 │ (bar, B) -> atom_to_binary(B); + │ ^ B. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2711:50 + │ +2711 │ ({foo, bar}, I) -> binary_to_integer(I); + │ ^ I. +Expression has type: number() +Context expected type: binary() + +202 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-27.pretty similarity index 100% rename from crates/elp/src/resources/test/eqwalizer_tests/check/custom.pretty rename to crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-27.pretty diff --git a/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-28.pretty b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-28.pretty new file mode 100644 index 0000000000..ec107b3c14 --- /dev/null +++ b/crates/elp/src/resources/test/eqwalizer_tests/check/custom-OTP-28.pretty @@ -0,0 +1,3258 @@ +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:26:5 + │ +26 │ element(4, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(4, Tup). +Expression has type: #{dynamic() => dynamic()} +Context expected type: atom() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:30:5 + │ +30 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 3 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:40:5 + │ +40 │ element(2, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(2, Tup). +Expression has type: number() | string() | atom() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:44:16 + │ +44 │ element(2, Tup). + │ ^^^ + │ │ + │ Tup. +Expression has type: {atom(), string()} | [dynamic()] +Context expected type: tuple() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {atom(), string()} + However the following candidate: [dynamic()] + Differs from the expected type: tuple() + +------------------------------ Detailed message ------------------------------ + + {atom(), string()} | [dynamic()] is not compatible with tuple() + because + [dynamic()] is not compatible with tuple() + +error: index_out_of_bounds (See https://fb.me/eqwalizer_errors#index_out_of_bounds) + ┌─ check/src/custom.erl:48:5 + │ +48 │ element(42, Tup). + │ ^^^^^^^^^^^^^^^^ 42. +Tried to access element 42 of a tuple with 2 elements + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:54:5 + │ +54 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ erlang:element(N, Tup). +Expression has type: atom() | number() | string() +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:58:5 + │ +58 │ element(N, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Tup). +Expression has type: atom() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + atom() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:68:5 + │ +68 │ element(1, Tup). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(1, Tup). +Expression has type: dynamic() | number() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: dynamic() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + dynamic() | number() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:86:5 + │ +86 │ element(N, Rec). + │ ^^^^^^^^^^^^^^^ + │ │ + │ erlang:element(N, Rec). +Expression has type: 'foo' | 'ok' | 'error' | number() | string() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'error' | 'foo' | 'ok' + However the following candidate: string() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + 'foo' | 'ok' | 'error' | number() | string() is not compatible with atom() + because + string() is not compatible with atom() + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:91:1 + │ +91 │ ╭ element_2_none_1(Tup) -> +92 │ │ element(42, Tup). + │ ╰────────────────────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:95:1 + │ +95 │ ╭ element_2_none_2(N, Tup) -> +96 │ │ element(N, Tup). + │ ╰───────────────────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:108:5 + │ +108 │ maps:get(K, M). + │ ^^^^^^^^^^^^^^ maps:get(K, M). +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:128:5 + │ +128 │ Res. + │ ^^^ Res. +Expression has type: number() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:154:12 + │ +154 │ get(a, M). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:160:23 + │ +160 │ Res = maps:get(a, M), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:167:17 + │ +167 │ maps:get(a, M, false). + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:173:23 + │ +173 │ Res = maps:get(a, M, false), + │ ^ M. +Expression has type: term() +Context expected type: #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:193:5 + │ +193 │ maps:get(K, M, 0). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(K, M, 0). +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:200:5 + │ +200 │ Res. + │ ^^^ + │ │ + │ Res. +Expression has type: number() | atom() +Context expected type: atom() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: number() + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + number() | atom() is not compatible with atom() + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:206:5 + │ +206 │ ╭ ╭ { +207 │ │ │ maps:get(a, M, undefined), +208 │ │ │ maps:get(n, M, undefined) +209 │ │ │ }. + │ ╰─│─────^ {maps:get('a', M, 'undefined'), maps:get('n', M, 'undefined')}. +Expression has type: {atom(), 'undefined' | number()} +Context expected type: {atom(), number()} + │ ╰─────' + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: 'undefined' + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), 'undefined' | number()} is not compatible with {atom(), number()} + because + 'undefined' | number() is not compatible with number() + because + 'undefined' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:221:27 + │ +221 │ map_get_2_17_neg(V, M) -> maps:get(V, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M). +Expression has type: 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' + +------------------------------ Detailed message ------------------------------ + + 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' | 'b_v' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:233:27 + │ +233 │ map_get_3_19_neg(V, M) -> maps:get(V, M, undefined). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:get(V, M, 'undefined'). +Expression has type: 'undefined' | 'a_v' | 'c_v' +Context expected type: 'a_v' | 'b_v' | 'undefined' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'undefined' | 'a_v' + However the following candidate: 'c_v' + Differs from the expected type: 'a_v' | 'b_v' | 'undefined' + +------------------------------ Detailed message ------------------------------ + + 'undefined' | 'a_v' | 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' | 'b_v' | 'undefined' + because + 'c_v' is not compatible with 'a_v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:309:5 + │ +309 │ Res. + │ ^^^ Res. +Expression has type: {'value', #{}} | 'false' +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:363:23 + │ +363 │ fun (_, _) -> self() end, + │ ^^^^^^ erlang:self(). +Expression has type: pid() +Context expected type: boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:382:17 + │ +382 │ maps:filter(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> boolean()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:389:17 + │ +389 │ maps:filter(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((T) -> boolean()), [T]) -> [T]) with 1 type parameter +Context expected type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun()/2 with 1 type parameter + Context expects type: fun((number(), 'a' | 'b') -> boolean()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:413:37 + │ +413 │ maps:filter(fun erlang:'=:='/2, X). + │ ^ + │ │ + │ X. +Expression has type: #{K => V} | 'a' +Context expected type: #{term() => term()} | maps:iterator() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: #{K => V} + However the following candidate: 'a' + Differs from the expected type: #{term() => term()} | maps:iterator() + +------------------------------ Detailed message ------------------------------ + + #{K => V} | 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} | maps:iterator() + because + 'a' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:425:20 + │ +425 │ maps:filter(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:454:5 + │ +454 │ ╭ ╭ maps:map( +455 │ │ │ fun (_, _) -> self() end, +456 │ │ │ M +457 │ │ │ ). + │ ╰─│─────^ maps:map(fun, M). +Expression has type: #{number() => pid()} +Context expected type: #{number() => boolean()} + │ ╰─────' + +Because in the expression's type: + #{ number() => + Here the type is: pid() + Context expects type: boolean() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{number() => pid()} is not compatible with #{number() => boolean()} + the default associations are not compatible + because + pid() is not compatible with boolean() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:474:14 + │ +474 │ maps:map(F, M). + │ ^ F. +Expression has type: fun(() -> pid()) +Context expected type: fun((number(), 'a' | 'b') -> term()) + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:481:14 + │ +481 │ maps:map(F, M). + │ ^ + │ │ + │ F. +Expression has type: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters +Context expected type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((fun((A) -> B), [A]) -> [B]) with 2 type parameters + Context expects type: fun((number(), 'a' | 'b') -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:497:5 + │ +497 │ maps:map(F, M). + │ ^^^^^^^^^^^^^^ + │ │ + │ maps:map(F, M). +Expression has type: #{a := boolean(), b := boolean()} +Context expected type: #{a => 'a', b => 'b'} + │ + +Because in the expression's type: + #{ a => + Here the type is: boolean() + Context expects type: 'a' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + at key `a`: + #{a := boolean(), b := boolean()} is not compatible with #{a => 'a', b => 'b'} + because + boolean() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:503:17 + │ +503 │ maps:map(F, non_kv), + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:538:9 + │ +538 │ fun (K, V) -> [K, V] end, [], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ fun. +fun with arity 2 used as fun with 3 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:544:5 + │ +544 │ ╭ ╭ maps:fold( +545 │ │ │ fun (_, _, Acc) -> [Acc] end, +546 │ │ │ [], +547 │ │ │ M +548 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [[[]]] +Context expected type: [number() | 'a' | 'b'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: [[]] + Context expects type: number() | 'a' | 'b' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [[[]]] is not compatible with [number() | 'a' | 'b'] + because + [[]] is not compatible with number() | 'a' | 'b' + because + [[]] is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:545:28 + │ +545 │ fun (_, _, Acc) -> [Acc] end, + │ ^^^^^ + │ │ + │ [Acc]. +Expression has type: [[[[]]]] +Context expected type: [[[]]] + │ + +Because in the expression's type: + [ + [ + [ + Here the type is: [] + Context expects type: none() + ] + ] + ] + +------------------------------ Detailed message ------------------------------ + + [[[[]]]] is not compatible with [[[]]] + because + [[[]]] is not compatible with [[]] + because + [[]] is not compatible with [] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:552:5 + │ +552 │ ╭ maps:fold( +553 │ │ fun (_, _, Acc) -> Acc end, +554 │ │ [], +555 │ │ non_kv +556 │ │ ). + │ ╰─────^ maps:fold(fun, [], 'non_kv'). +Expression has type: [] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:555:9 + │ +555 │ non_kv + │ ^^^^^^ + │ │ + │ 'non_kv'. +Expression has type: 'non_kv' +Context expected type: #{term() => term()} | maps:iterator() + │ + + 'non_kv' is not compatible with #{term() => term()} | maps:iterator() + because + 'non_kv' is not compatible with #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:560:1 + │ +560 │ ╭ maps_fold_3_6(None) -> +561 │ │ maps:fold( +562 │ │ None, +563 │ │ #{}, +564 │ │ #{1 => 1} +565 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:568:1 + │ +568 │ ╭ maps_fold_3_7(None) -> +569 │ │ maps:fold( +570 │ │ None, +571 │ │ None, +572 │ │ None +573 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:578:5 + │ +578 │ ╭ ╭ maps:fold( +579 │ │ │ fun (_K, A, _Acc) -> A end, +580 │ │ │ [], +581 │ │ │ M +582 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [] | atom() +Context expected type: atom() + │ ╰─────' + +Because in the expression's type: + Here the type is a union type with some valid candidates: atom() + However the following candidate: [] + Differs from the expected type: atom() + +------------------------------ Detailed message ------------------------------ + + [] | atom() is not compatible with atom() + because + [] is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', []) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun((number(), 'a', []) -> term()) with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> term()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:601:9 + │ +601 │ fun folder_bad/3, + │ ^^^^^^^^^^^^^^^^ + │ │ + │ folder_bad/3. +Expression has type: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter +Context expected type: fun((number(), 'a', [] | dynamic()) -> [] | dynamic()) with 0 type parameters + │ + +Because in the expression's type: + Here the type is: fun((term(), term(), Acc) -> [Acc]) with 1 type parameter + Context expects type: fun()/3 with 0 type parameters + The number of type parameters doesn't match. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:636:5 + │ +636 │ ╭ ╭ maps:fold( +637 │ │ │ fun +638 │ │ │ (_K, {i, I}, Acc) -> +639 │ │ │ [I | Acc]; + · │ │ +646 │ │ │ M +647 │ │ │ ). + │ ╰─│─────^ maps:fold(fun, [], M). +Expression has type: [number() | binary() | atom()] +Context expected type: [binary()] | [number()] | [atom()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: number() + Differs from the expected type: binary() + ] + +------------------------------ Detailed message ------------------------------ + + [number() | binary() | atom()] is not compatible with [binary()] | [number()] | [atom()] + because + [number() | binary() | atom()] is not compatible with [binary()] + because + number() | binary() | atom() is not compatible with binary() + because + number() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:671:41 + │ +671 │ maps_to_list_7_neg(Num) -> maps:to_list(Num). + │ ^^^ + │ │ + │ Num. +Expression has type: number() +Context expected type: #{term() => term()} | maps:iterator() + │ + + number() is not compatible with #{term() => term()} | maps:iterator() + because + number() is not compatible with #{term() => term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:675:25 + │ +675 │ maps_merge_1(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:679:25 + │ +679 │ maps_merge_2(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a => string(), b => number() | boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{'b' | 'a' | 'c' => number() | string() | atom()} + Context expects type: #{...} (no default association) + The expected map has no default association while the type of the expression has one. + +------------------------------ Detailed message ------------------------------ + + #{'b' | 'a' | 'c' => number() | string() | atom()} is not compatible with #{a => string(), b => number() | boolean(), c => atom()} + key a is not present in the former map but is incompatible with its default association + because + number() | string() | atom() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:683:25 + │ +683 │ maps_merge_3(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'b' | 'a' | 'c' => number() | string() | atom()} +Context expected type: #{a := string(), b := boolean(), c => atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:697:44 + │ +697 │ maps_merge_7_neg(M1, M2) -> maps:merge(M1, M2). + │ ^^ M2. +Expression has type: number() +Context expected type: #{a => binary()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:701:25 + │ +701 │ maps_merge_8(M1, M2) -> maps:merge(M1, M2). + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:merge(M1, M2). +Expression has type: #{'a' | 'b' => atom() | number()} +Context expected type: #{a := atom(), b := number()} | #{a := atom()} + │ + +Because in the expression's type: + Here the type is: #{...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} | #{a := atom()} + because + #{'a' | 'b' => atom() | number()} is not compatible with #{a := atom(), b := number()} + keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:721:9 + │ +721 │ fun erlang:binary_to_list/1, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:binary_to_list/1. +Expression has type: fun((binary()) -> [number()]) +Context expected type: fun((number()) -> boolean() | {'true', term()}) + │ + +Because in the expression's type: + fun((binary()) -> + Here the type is: [number()] + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((binary()) -> [number()]) is not compatible with fun((number()) -> boolean() | {'true', term()}) + because + [number()] is not compatible with boolean() | {'true', term()} + because + [number()] is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:739:20 + │ +739 │ (3) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:749:9 + │ +749 │ not_a_list + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:791:17 + │ +791 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: {'true', 'a'} | 'wrong_ret' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: {'true', 'a'} + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | {'true', term()} + +------------------------------ Detailed message ------------------------------ + + {'true', 'a'} | 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with boolean() | {'true', term()} + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:827:9 + │ +827 │ ╭ ╭ fun (a) -> [a]; +828 │ │ │ (b) -> true; +829 │ │ │ (c) -> wrong_ret end, + │ ╰─│────────────────────────────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰────────────────────────────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'true' + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'true' | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'true' | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:829:20 + │ +829 │ (c) -> wrong_ret end, + │ ^^^^^^^^^ + │ │ + │ 'wrong_ret'. +Expression has type: 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: 'wrong_ret' + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:9 + │ +837 │ ╭ ╭ fun (1) -> {true, a}; +838 │ │ │ (2) -> true end, + │ ╰─│───────────────────────────^ fun. +Expression has type: fun((dynamic()) -> {'true', 'a'} | 'true') +Context expected type: fun((Item) -> boolean() | [Item]) + │ ╰───────────────────────────' + +Because in the expression's type: + fun((dynamic()) -> + Here the type is a union type with some valid candidates: 'true' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | [Item] + ) + +------------------------------ Detailed message ------------------------------ + + fun((dynamic()) -> {'true', 'a'} | 'true') is not compatible with fun((Item) -> boolean() | [Item]) + because + {'true', 'a'} | 'true' is not compatible with boolean() | [Item] + because + {'true', 'a'} is not compatible with boolean() | [Item] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:837:20 + │ +837 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | [dynamic()] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(Item) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[Item], [Item]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(Item) + because + 'not_a_queue' is not compatible with {[Item], [Item]} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:839:9 + │ +839 │ not_a_queue + │ ^^^^^^^^^^^ + │ │ + │ 'not_a_queue'. +Expression has type: 'not_a_queue' +Context expected type: queue:queue(dynamic()) + │ + +Because in the expression's type: + Here the type is: 'not_a_queue' + Context expects type: {[dynamic()], [dynamic()]} + +------------------------------ Detailed message ------------------------------ + + 'not_a_queue' is not compatible with queue:queue(dynamic()) + because + 'not_a_queue' is not compatible with {[dynamic()], [dynamic()]} + +error: fun_arity_mismatch (See https://fb.me/eqwalizer_errors#fun_arity_mismatch) + ┌─ check/src/custom.erl:846:9 + │ +846 │ ╭ fun (wrong, arity) -> +847 │ │ [a] +848 │ │ end, + │ ╰───────────^ fun. +fun with arity 2 used as fun with 1 arguments + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:9 + │ +857 │ ╭ ╭ fun (1) -> {true, a}; +858 │ │ │ (X) -> case X of +859 │ │ │ true -> +860 │ │ │ [a]; + · │ │ +863 │ │ │ end +864 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] | 'false' + However the following candidate: {'true', 'a'} + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'false' | {'true', 'a'}) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'false' | {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + because + {'true', 'a'} is not compatible with boolean() | ['a' | 'b'] + expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:857:20 + │ +857 │ fun (1) -> {true, a}; + │ ^^^^^^^^^ + │ │ + │ {'true', 'a'}. +Expression has type: {'true', 'a'} +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is: {'true', 'a'} + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + +expected union does not contain any tuple type of size 2 + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:873:9 + │ +873 │ ╭ ╭ fun (a) -> [a]; +874 │ │ │ (X) -> +875 │ │ │ Res = case X of +876 │ │ │ true -> + · │ │ +881 │ │ │ Res +882 │ │ │ end, + │ ╰─│───────────^ fun. +Expression has type: fun(('a' | 'b') -> ['a'] | 'wrong_ret') +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ ╰───────────' + +Because in the expression's type: + fun(('a' | 'b') -> + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + ) + +------------------------------ Detailed message ------------------------------ + + fun(('a' | 'b') -> ['a'] | 'wrong_ret') is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:881:17 + │ +881 │ Res + │ ^^^ + │ │ + │ Res. +Expression has type: ['a'] | 'wrong_ret' +Context expected type: boolean() | ['a' | 'b'] + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: ['a'] + However the following candidate: 'wrong_ret' + Differs from the expected type: 'false' | 'true' | ['a' | 'b'] + +------------------------------ Detailed message ------------------------------ + + ['a'] | 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with boolean() | ['a' | 'b'] + because + 'wrong_ret' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun((dynamic()) -> boolean() | [dynamic()]) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | [dynamic()] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun((dynamic()) -> boolean() | [dynamic()]) + because + atom() is not compatible with boolean() | [dynamic()] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:891:9 + │ +891 │ fun list_to_atom/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:list_to_atom/1. +Expression has type: fun((string()) -> atom()) +Context expected type: fun(('a' | 'b') -> boolean() | ['a' | 'b']) + │ + +Because in the expression's type: + fun((string()) -> + Here the type is: atom() + Context expects type: 'false' | 'true' | ['a' | 'b'] + No candidate matches in the expected union. + ) + +------------------------------ Detailed message ------------------------------ + + fun((string()) -> atom()) is not compatible with fun(('a' | 'b') -> boolean() | ['a' | 'b']) + because + atom() is not compatible with boolean() | ['a' | 'b'] + because + atom() is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:900:9 + │ +900 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:909:9 + │ +909 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:919:9 + │ +919 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:925:1 + │ +925 │ ╭ queue_filter_13_neg(Q) -> +926 │ │ queue:filter( +927 │ │ fun atom_to_list/1, +928 │ │ Q +929 │ │ ), +930 │ │ ok. + │ ╰──────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((atom()) -> boolean() | [atom()]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [atom()] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((atom()) -> boolean() | [atom()]) + because + string() is not compatible with boolean() | [atom()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:927:9 + │ +927 │ fun atom_to_list/1, + │ ^^^^^^^^^^^^^^^^^^ + │ │ + │ erlang:atom_to_list/1. +Expression has type: fun((atom()) -> string()) +Context expected type: fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + │ + +Because in the expression's type: + fun((atom()) -> + Here the type is: string() + Context expects type: boolean() | [dynamic(atom())] + ) + +------------------------------ Detailed message ------------------------------ + + fun((atom()) -> string()) is not compatible with fun((dynamic(atom())) -> boolean() | [dynamic(atom())]) + because + string() is not compatible with boolean() | [dynamic(atom())] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:955:5 + │ +955 │ ╭ lists:keystore( +956 │ │ a, 1, +957 │ │ [{foo, b}, {c, d}], +958 │ │ non_tuple +959 │ │ ). + │ ╰─────^ lists:keystore('a', 1, [{'foo', 'b'}, {'c', 'd'}], 'non_tuple'). +Expression has type: [{'foo', 'b'} | {'c', 'd'} | dynamic()] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:958:9 + │ +958 │ non_tuple + │ ^^^^^^^^^ 'non_tuple'. +Expression has type: 'non_tuple' +Context expected type: tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:966:5 + │ +966 │ ╭ lists:keystore( +967 │ │ a, 1, +968 │ │ [non_tuple], +969 │ │ {replacement} +970 │ │ ). + │ ╰─────^ lists:keystore('a', 1, ['non_tuple'], {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:968:9 + │ +968 │ [non_tuple], + │ ^^^^^^^^^^^ + │ │ + │ ['non_tuple']. +Expression has type: ['non_tuple'] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: 'non_tuple' + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + ['non_tuple'] is not compatible with [tuple()] + because + 'non_tuple' is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:975:5 + │ +975 │ ╭ lists:keystore( +976 │ │ a, 1, +977 │ │ non_list, +978 │ │ {replacement} +979 │ │ ). + │ ╰─────^ lists:keystore('a', 1, 'non_list', {'replacement'}). +Expression has type: [dynamic() | {'replacement'}] +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:977:9 + │ +977 │ non_list, + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [tuple()] + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:983:1 + │ +983 │ ╭ keystore_7(None) -> +984 │ │ lists:keystore( +985 │ │ a, 1, +986 │ │ None, +987 │ │ {replacement} +988 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:991:1 + │ +991 │ ╭ keystore_8(None) -> +992 │ │ lists:keystore( +993 │ │ a, 1, +994 │ │ None, +995 │ │ None +996 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1011:25 + │ +1011 │ lists:keytake(a, 1, non_tup), + │ ^^^^^^^ 'non_tup'. +Expression has type: 'non_tup' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [Tuple] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1016:25 + │ +1016 │ lists:keytake(a, 1, non_list), + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1021:22 + │ +1021 │ lists:keytake(a, non_num, []), + │ ^^^^^^^ 'non_num'. +Expression has type: 'non_num' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1038:15 + │ +1038 │ lists:sum([a, 1]). + │ ^^^^^^ + │ │ + │ ['a', 1]. +Expression has type: ['a' | number()] +Context expected type: [number()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: 'a' + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + ['a' | number()] is not compatible with [number()] + because + 'a' | number() is not compatible with number() + because + 'a' is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1042:15 + │ +1042 │ lists:sum(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1062:15 + │ +1062 │ lists:max(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [T] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1082:15 + │ +1082 │ lists:min(not_a_list). + │ ^^^^^^^^^^ 'not_a_list'. +Expression has type: 'not_a_list' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1100:5 + │ +1100 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' + │ + + term() is not compatible with pid() | 'undefined' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1106:5 + │ +1106 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() | 'undefined' | 'v' + │ + + term() is not compatible with pid() | 'undefined' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1111:5 + │ +1111 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L). +Expression has type: term() +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1117:5 + │ +1117 │ proplists:get_value(k, L, 3). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 3). +Expression has type: term() +Context expected type: pid() | number() + │ + + term() is not compatible with pid() | number() + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1123:5 + │ +1123 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v1' | 'v2' | 'my_default' + │ + + term() is not compatible with 'v1' | 'v2' | 'my_default' + because + term() is not compatible with 'v1' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1129:5 + │ +1129 │ proplists:get_value(k, L, my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', L, 'my_default'). +Expression has type: term() +Context expected type: 'v' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1134:28 + │ +1134 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1139:5 + │ +1139 │ proplists:get_value(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', []). +Expression has type: term() +Context expected type: 'default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1144:1 + │ +1144 │ proplists:get_value(k, [], my_default). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_value('k', [], 'my_default'). +Expression has type: term() +Context expected type: 'my_default' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1149:28 + │ +1149 │ proplists:get_value(k, b, my_default). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1154:5 + │ +1154 │ proplists:get_bool(b, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^ proplists:get_bool('b', L). +Expression has type: boolean() +Context expected type: 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1160:5 + │ +1160 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default'] + because + term() is not compatible with pid() | 'default' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1166:5 + │ +1166 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid() | 'default' | 'v'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() | 'default' | 'v' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid() | 'default' | 'v'] + because + term() is not compatible with pid() | 'default' | 'v' + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1171:5 + │ +1171 │ proplists:get_all_values(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', L). +Expression has type: [term()] +Context expected type: [pid()] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: pid() + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with [pid()] + because + term() is not compatible with pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1176:5 + │ +1176 │ proplists:get_all_values(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', []). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:5 + │ +1181 │ proplists:get_all_values(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_all_values('k', 'b'). +Expression has type: [term()] +Context expected type: [] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1181:33 + │ +1181 │ proplists:get_all_values(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1186:27 + │ +1186 │ proplists:get_bool(b, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1191:5 + │ +1191 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'c' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['c'] + because + term() is not compatible with 'c' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1197:5 + │ +1197 │ proplists:get_keys(L). + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_keys(L). +Expression has type: [term()] +Context expected type: ['a' | 'b' | 'c'] + │ + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' | 'b' | 'c' + No candidate matches in the expected union. + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a' | 'b' | 'c'] + because + term() is not compatible with 'a' | 'b' | 'c' + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1202:24 + │ +1202 │ proplists:get_keys(a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1207:5 + │ +1207 │ ╭ ╭ proplists:get_keys( +1208 │ │ │ [{a, b, c}] +1209 │ │ │ ). + │ ╰─│─────^ proplists:get_keys([{'a', 'b', 'c'}]). +Expression has type: [term()] +Context expected type: ['a'] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: term() + Context expects type: 'a' + ] + +------------------------------ Detailed message ------------------------------ + + [term()] is not compatible with ['a'] + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1215:5 + │ +1215 │ proplists:get_value(k, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', L). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:5 + │ +1220 │ proplists:get_value(k, b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('k', 'b'). +Expression has type: term() +Context expected type: 'a' | pid() + │ + + term() is not compatible with 'a' | pid() + because + term() is not compatible with 'a' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1220:28 + │ +1220 │ proplists:get_value(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1225:1 + │ +1225 │ proplists:lookup(self(), [a, {b, true}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup(erlang:self(), ['a', {'b', 'true'}]). +Expression has type: 'none' | tuple() +Context expected type: {'b', 'true'} + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: tuple() + However the following candidate: 'none' + Differs from the expected type: {'b', 'true'} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1229:25 + │ +1229 │ proplists:lookup(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1239:5 + │ +1239 │ proplists:lookup(k, []). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:lookup('k', []). +Expression has type: 'none' | tuple() +Context expected type: 'none' + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: 'none' + However the following candidate: tuple() + Differs from the expected type: 'none' + +------------------------------ Detailed message ------------------------------ + + 'none' | tuple() is not compatible with 'none' + because + tuple() is not compatible with 'none' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1252:29 + │ +1252 │ proplists:lookup_all(a, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1265:5 + │ +1265 │ ╭ ╭ proplists:lookup_all( +1266 │ │ │ self(), +1267 │ │ │ [] +1268 │ │ │ ). + │ ╰─│─────^ proplists:lookup_all(erlang:self(), []). +Expression has type: [tuple()] +Context expected type: [] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is: tuple() + Context expects type: none() + ] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1291:34 + │ +1291 │ proplists:is_defined(self(), b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [A] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1295:25 + │ +1295 │ proplists:delete(k, b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [dynamic()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1311:5 + │ +1311 │ proplists:split(L, Ks). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:split(L, Ks). +Expression has type: {[[term()]], [term()]} +Context expected type: {[plist('a', 'b')], plist('a', 'b')} + │ + +Because in the expression's type: + { + [ + [ + Here the type is: term() + Context expects type: 'a' | {'a', 'b'} + No candidate matches in the expected union. + ] + ] + , [term()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[[term()]], [term()]} is not compatible with {[plist('a', 'b')], plist('a', 'b')} + because + [[term()]] is not compatible with [plist('a', 'b')] + because + [term()] is not compatible with plist('a', 'b') + because + [term()] is not compatible with ['a' | {'a', 'b'}] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1315:21 + │ +1315 │ proplists:split(b, []). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1319:25 + │ +1319 │ proplists:split([], b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1324:22 + │ +1324 │ proplists:to_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: [atom() | {term(), term()} | term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{K => V} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1358:24 + │ +1358 │ proplists:from_map(b). + │ ^ 'b'. +Expression has type: 'b' +Context expected type: #{dynamic() => dynamic()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1363:5 + │ +1363 │ proplists:get_value(a, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1368:5 + │ +1368 │ proplists:get_value(X, [a]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value(X, ['a']). +Expression has type: term() +Context expected type: 'true' | 'undefined' + │ + + term() is not compatible with 'true' | 'undefined' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1373:5 + │ +1373 │ proplists:get_value(a, [a], b). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ proplists:get_value('a', ['a'], 'b'). +Expression has type: term() +Context expected type: 'true' | 'b' + │ + + term() is not compatible with 'true' | 'b' + because + term() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1416:5 + │ +1416 │ file:consult(some_file). + │ ^^^^^^^^^^^^^^^^^^^^^^^ file:consult('some_file'). +Expression has type: {'ok', [dynamic()]} | {'error', {number(), atom(), term()} | 'terminated' | 'badarg' | file:posix() | 'system_limit'} +Context expected type: 'nok' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1428:5 + │ +1428 │ lists:keysort(2, [{a, c}, {b, d}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lists:keysort(2, [{'a', 'c'}, {'b', 'd'}]). +Expression has type: [{'a', 'c'} | {'b', 'd'}] +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1432:22 + │ +1432 │ lists:keysort(1, [3]). + │ ^^^ + │ │ + │ [3]. +Expression has type: [number()] +Context expected type: [tuple()] + │ + +Because in the expression's type: + [ + Here the type is: number() + Context expects type: tuple() + ] + +------------------------------ Detailed message ------------------------------ + + [number()] is not compatible with [tuple()] + because + number() is not compatible with tuple() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1448:5 + │ +1448 │ ╭ ╭ lists:filtermap( +1449 │ │ │ fun(X) when X div 2 =:= 0 -> +1450 │ │ │ {true, integer_to_list(X)}; +1451 │ │ │ (X) -> + · │ │ +1454 │ │ │ [1, 2, 3, 4] +1455 │ │ │ ). + │ ╰─│─────^ lists:filtermap(fun, [1, 2, 3, 4]). +Expression has type: [string() | number()] +Context expected type: [number()] + │ ╰─────' + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: string() + Differs from the expected type: number() + ] + +------------------------------ Detailed message ------------------------------ + + [string() | number()] is not compatible with [number()] + because + string() | number() is not compatible with number() + because + string() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1482:5 + │ +1482 │ erlang:min(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:min(X, Y). +Expression has type: number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1497:5 + │ +1497 │ erlang:max(X, Y). + │ ^^^^^^^^^^^^^^^^ erlang:max(X, Y). +Expression has type: atom() | number() +Context expected type: none() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1523:9 + │ +1523 │ abs(Atom). + │ ^^^^ Atom. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1536:31 + │ +1536 │ seq3_4_wip_neg() -> lists:seq(a, 2, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1539:30 + │ +1539 │ seq3_5_neg() -> lists:seq(1, a, 1). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1542:33 + │ +1542 │ seq3_6_neg() -> lists:seq(1, 2, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1570:31 + │ +1570 │ seq2_4_wip_neg() -> lists:seq(a, 2). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1573:30 + │ +1573 │ seq2_5_neg() -> lists:seq(1, a). + │ ^ 'a'. +Expression has type: 'a' +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1622:5 + │ +1622 │ ╭ timer:tc( +1623 │ │ fun() -> +1624 │ │ err +1625 │ │ end +1626 │ │ ). + │ ╰─────^ timer:tc(fun). +Expression has type: {number(), 'err'} +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1635:5 + │ +1635 │ ets:lookup(tab, Any). + │ ^^^^^^^^^^^^^^^^^^^^ ets:lookup('tab', Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:5 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ets:lookup(string_lit, Any). +Expression has type: [dynamic()] +Context expected type: pid() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1639:16 + │ +1639 │ ets:lookup("not atom", Any). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1663:18 + │ +1663 │ ets:tab2list("not atom"). + │ ^^^^^^^^^^ string_lit. +Expression has type: string() +Context expected type: ets:tab() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1702:23 + │ +1702 │ lists:flatten([], 1). + │ ^ 1. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1711:19 + │ +1711 │ lists:flatten(3). + │ ^ 3. +Expression has type: number() +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1724:8 + │ +1724 │ -> lists:flatten(X). + │ ^^^^^^^^^^^^^^^^ + │ │ + │ lists:flatten(X). +Expression has type: [{A, B} | {B, A}] +Context expected type: [{A, B}] + │ + +Because in the expression's type: + [ + { + Here the type is: B + Context expects type: A + , A} + ] + +------------------------------ Detailed message ------------------------------ + + [{A, B} | {B, A}] is not compatible with [{A, B}] + because + {A, B} | {B, A} is not compatible with {A, B} + because + at tuple index 1: + {B, A} is not compatible with {A, B} + because + B is not compatible with A + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1757:5 + │ +1757 │ ╭ ╭ maps:without( +1758 │ │ │ [a, c, DOrE], +1759 │ │ │ #{ +1760 │ │ │ a => ka, + · │ │ +1764 │ │ │ } +1765 │ │ │ ). + │ ╰─│─────^ maps:without(['a', 'c', DOrE], #{..}). +Expression has type: #{a => 'ka', b => atom(), c => pid(), d => 'kd'} +Context expected type: #{b => atom()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ...} + Context expects type: #{...} + The expected map has no corresponding key for: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared in the former but not in the latter and the latter map has no default association + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1769:18 + │ +1769 │ maps:without(non_list, #{}). + │ ^^^^^^^^ 'non_list'. +Expression has type: 'non_list' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1773:22 + │ +1773 │ maps:without([], non_map). + │ ^^^^^^^ 'non_map'. +Expression has type: 'non_map' +Context expected type: #{term() => term()} + +error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered) + ┌─ check/src/custom.erl:1808:1 + │ +1808 │ ╭ maps_without_12_neg(None) -> +1809 │ │ maps:without( +1810 │ │ [a, b], +1811 │ │ None +1812 │ │ ). + │ ╰─────^ Clause is not covered by spec + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1818:5 + │ +1818 │ ╭ ╭ maps:without( +1819 │ │ │ Keys, +1820 │ │ │ #{a => self(), b => self()} +1821 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1826:5 + │ +1826 │ ╭ ╭ maps:without( +1827 │ │ │ [a | improper_tail], +1828 │ │ │ #{a => self(), b => self()} +1829 │ │ │ ). + │ ╰─│─────^ maps:without(['a' | 'improper_tail'], #{..}). +Expression has type: #{a => pid(), b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1827:12 + │ +1827 │ [a | improper_tail], + │ ^^^^^^^^^^^^^^^^ 'improper_tail'. +Expression has type: 'improper_tail' +Context expected type: [term()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1837:5 + │ +1837 │ ╭ ╭ maps:without( +1838 │ │ │ Keys, +1839 │ │ │ #{a => ka, b => self()} +1840 │ │ │ ). + │ ╰─│─────^ maps:without(Keys, #{..}). +Expression has type: #{a => 'ka', b => pid()} +Context expected type: #{b := pid()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{b => ..., ...} + Context expects type: #{b := ..., ...} + The type of the expression is missing the following required keys: b. + +------------------------------ Detailed message ------------------------------ + +key `b` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1854:5 + │ +1854 │ maps:without([a, b], M). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:without(['a', 'b'], M). +Expression has type: #{c := 'cv', d := 'dv'} | #{c := 'cv', e => 'ev'} +Context expected type: #{c := atom()} + │ + +Because in the expression's type: + Here the type is: #{d := ...} + Context expects type: #{...} + The expected map has no corresponding key for: d. + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1916:23 + │ +1916 │ custom_overloaded(X). + │ ^ + │ │ + │ X. +Expression has type: term() +Context expected type: atom() | binary() + │ + + term() is not compatible with atom() | binary() + because + term() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:1939:5 + │ +1939 │ {A, N}. + │ ^^^^^^ + │ │ + │ {A, N}. +Expression has type: {atom(), number() | pid()} +Context expected type: {atom(), number()} + │ + +Because in the expression's type: + { atom(), + Here the type is a union type with some valid candidates: number() + However the following candidate: pid() + Differs from the expected type: number() + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {atom(), number() | pid()} is not compatible with {atom(), number()} + because + number() | pid() is not compatible with number() + because + pid() is not compatible with number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2041:5 + │ +2041 │ filename:join(["server", "erl"]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2046:5 + │ +2046 │ filename:join(["server", <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([string_lit, <<..>>]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2051:5 + │ +2051 │ filename:join([<<>>, ""]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, string_lit]). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2066:5 + │ +2066 │ filename:join([<<>>, <<>>]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join([<<..>>, <<..>>]). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2081:19 + │ +2081 │ filename:join([<<>>, self()]). + │ ^^^^^^^^^^^^^^ + │ │ + │ [<<..>>, erlang:self()]. +Expression has type: [binary() | pid()] +Context expected type: [file:name_all()] + │ + +Because in the expression's type: + [ + Here the type is a union type with some valid candidates: binary() + However the following candidate: pid() + Differs from the expected type: string() | atom() | file:deep_list() | binary() + ] + +------------------------------ Detailed message ------------------------------ + + [binary() | pid()] is not compatible with [file:name_all()] + because + binary() | pid() is not compatible with file:name_all() + because + binary() | pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2086:5 + │ +2086 │ filename:join("server", "erl"). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2091:5 + │ +2091 │ filename:join("server", <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(string_lit, <<..>>). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2096:5 + │ +2096 │ filename:join(<<>>, ""). + │ ^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join(<<..>>, string_lit). +Expression has type: file:filename_all() +Context expected type: file:filename() + │ + +Because in the expression's type: + Here the type is: string() | binary() + Context expects type: string() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with file:filename() + because + string() | binary() is not compatible with file:filename() + because + string() | binary() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2111:5 + │ +2111 │ filename:join(atom, <<>>). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ filename:join('atom', <<..>>). +Expression has type: file:filename_all() +Context expected type: binary() + │ + +Because in the expression's type: + Here the type is a union type with some valid candidates: binary() + However the following candidate: string() + Differs from the expected type: binary() + +------------------------------ Detailed message ------------------------------ + + file:filename_all() is not compatible with binary() + because + string() | binary() is not compatible with binary() + because + string() is not compatible with binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2121:25 + │ +2121 │ filename:join(<<>>, self()). + │ ^^^^^^ + │ │ + │ erlang:self(). +Expression has type: pid() +Context expected type: file:name_all() + │ + +Because in the expression's type: + Here the type is: pid() + Context expects type: string() | atom() | file:deep_list() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + pid() is not compatible with file:name_all() + because + pid() is not compatible with string() | atom() | file:deep_list() | binary() + because + pid() is not compatible with string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2150:5 + │ +2150 │ ╭ ╭ queue:filter( +2151 │ │ │ fun my_filter1/1, +2152 │ │ │ Q +2153 │ │ │ ). + │ ╰─│─────^ queue:filter(my_filter1/1, Q). +Expression has type: queue:queue(atom() | number()) +Context expected type: queue:queue(number()) + │ ╰─────' + +Because in the expression's type: + { + [ + Here the type is a union type with some valid candidates: number() + However the following candidate: atom() + Differs from the expected type: number() + ] + , [atom() | number()]} + +------------------------------ Detailed message ------------------------------ + + queue:queue(atom() | number()) is not compatible with queue:queue(number()) + because + {[atom() | number()], [atom() | number()]} is not compatible with queue:queue(number()) + because + at tuple index 1: + {[atom() | number()], [atom() | number()]} is not compatible with {[number()], [number()]} + because + [atom() | number()] is not compatible with [number()] + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2191:5 + │ +2191 │ M3. + │ ^^ + │ │ + │ M3. +Expression has type: #{count := number(), module := 'foo'} | #{module := 'foo'} +Context expected type: state1() + │ + +Because in the expression's type: + The type is a union type with some valid candidates: #{count := number(), module := 'foo'} + However, the following candidate doesn't match: + Here the type is: #{...} + Context expects type: #{count := ..., ...} + The type of the expression is missing the following required keys: count. + +------------------------------ Detailed message ------------------------------ + + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with state1() + because + #{count := number(), module := 'foo'} | #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + because + #{module := 'foo'} is not compatible with #{count := number(), module := atom()} + key `count` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2223:13 + │ +2223 │ Atom + Sum + │ ^^^^ Atom. +Expression has type: atom() +Context expected type: number() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2279:5 + │ +2279 │ maps:remove(A, M). + │ ^^^^^^^^^^^^^^^^^ + │ │ + │ maps:remove(A, M). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2320:5 + │ +2320 │ ╭ ╭ maps:filtermap( +2321 │ │ │ fun +2322 │ │ │ (a, V) -> true; +2323 │ │ │ (b, V) -> {true, atom_to_binary(V)}; + · │ │ +2326 │ │ │ M +2327 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{a => atom() | binary(), b => atom() | binary(), c => atom() | binary()} +Context expected type: #{a := atom(), b := binary()} + │ ╰─────' + +Because in the expression's type: + Here the type is: #{a => ..., b => ..., ...} + Context expects type: #{a := ..., b := ..., ...} + The type of the expression is missing the following required keys: a, b. + +------------------------------ Detailed message ------------------------------ + +keys `a`, `b` are declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2342:5 + │ +2342 │ ╭ ╭ maps:filtermap( +2343 │ │ │ fun (_, V) -> +2344 │ │ │ {true, atom_to_binary(V)} +2345 │ │ │ end, +2346 │ │ │ M +2347 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2354:23 + │ +2354 │ fun (_, _) -> err end, + │ ^^^ + │ │ + │ 'err'. +Expression has type: 'err' +Context expected type: boolean() | {'true', term()} + │ + +Because in the expression's type: + Here the type is: 'err' + Context expects type: 'false' | 'true' | {'true', term()} + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + 'err' is not compatible with boolean() | {'true', term()} + because + 'err' is not compatible with 'false' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2362:5 + │ +2362 │ ╭ ╭ maps:filtermap( +2363 │ │ │ fun (_, V) -> {true, atom_to_binary(V)} end, +2364 │ │ │ M +2365 │ │ │ ). + │ ╰─│─────^ maps:filtermap(fun, M). +Expression has type: #{atom() => binary()} +Context expected type: #{atom() => atom()} + │ ╰─────' + +Because in the expression's type: + #{ atom() => + Here the type is: binary() + Context expects type: atom() + , ... } + +------------------------------ Detailed message ------------------------------ + + #{atom() => binary()} is not compatible with #{atom() => atom()} + the default associations are not compatible + because + binary() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2363:45 + │ +2363 │ fun (_, V) -> {true, atom_to_binary(V)} end, + │ ^ V. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2377:5 + │ +2377 │ re:replace(Subj, "+", "-", [{return, binary}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'binary'}]). +Expression has type: binary() +Context expected type: string() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2381:5 + │ +2381 │ re:replace(Subj, "+", "-", [{return, list}]). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re:replace(Subj, string_lit, string_lit, [{'return', 'list'}]). +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2385:22 + │ +2385 │ Res = re:replace(Subj, "+", "-", [{return, list}]), + │ ^^^^ + │ │ + │ Subj. +Expression has type: atom() +Context expected type: iodata() | unicode:charlist() + │ + +Because in the expression's type: + Here the type is: atom() + Context expects type: iolist() | binary() + No candidate matches in the expected union. + +------------------------------ Detailed message ------------------------------ + + atom() is not compatible with iodata() | unicode:charlist() + because + atom() is not compatible with iolist() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2386:5 + │ +2386 │ Res. + │ ^^^ Res. +Expression has type: string() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2390:38 + │ +2390 │ Res = re:replace(Subj, "+", "-", [{return, something}]), + │ ^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ [{'return', 'something'}]. +Expression has type: [{'return', 'something'}] +Context expected type: ['notempty_atstart' | 'noteol' | 'notbol' | 'global' | {'match_limit_recursion', number()} | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + │ + +Because in the expression's type: + [ + { 'return', + Here the type is: 'something' + Context expects type: 'iodata' | 'list' | 'binary' + No candidate matches in the expected union. + } + ] + +------------------------------ Detailed message ------------------------------ + + [{'return', 'something'}] is not compatible with ['notempty_atstart' | 'noteol' | 'notbol' | 'global' | {'match_limit_recursion', number()} | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored'] + because + {'return', 'something'} is not compatible with 'notempty_atstart' | 'noteol' | 'notbol' | 'global' | {'match_limit_recursion', number()} | re:compile_option() | {'match_limit', number()} | {'offset', number()} | 'notempty' | {'return', 'iodata' | 'list' | 'binary'} | 'anchored' + because + at tuple index 2: + {'return', 'something'} is not compatible with {'return', 'iodata' | 'list' | 'binary'} + because + 'something' is not compatible with 'iodata' | 'list' | 'binary' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2506:5 + │ +2506 │ lists:partition(fun is_number/1, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[number()], [atom()]} +Context expected type: {[atom()], [number()]} + │ + +Because in the expression's type: + { + [ + Here the type is: number() + Context expects type: atom() + ] + , [atom()]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[number()], [atom()]} is not compatible with {[atom()], [number()]} + because + [number()] is not compatible with [atom()] + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2518:5 + │ +2518 │ lists:partition(fun({_Term, V}) -> is_number(V) end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{term(), number()}], [{term(), atom()}]} +Context expected type: {[{term(), atom()}], [{term(), number()}]} + │ + +Because in the expression's type: + { + [ + { term(), + Here the type is: number() + Context expects type: atom() + } + ] + , [{term(), atom()}]} + +------------------------------ Detailed message ------------------------------ + + at tuple index 1: + {[{term(), number()}], [{term(), atom()}]} is not compatible with {[{term(), atom()}], [{term(), number()}]} + because + [{term(), number()}] is not compatible with [{term(), atom()}] + because + at tuple index 2: + {term(), number()} is not compatible with {term(), atom()} + because + number() is not compatible with atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2536:5 + │ +2536 │ lists:partition(fun({ok, _}) -> true; (_) -> false end, L). + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ lists:partition(fun, L). +Expression has type: {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} +Context expected type: {[{'ok', atom()}], [{'error', term()}]} + │ + +Because in the expression's type: + { [{'ok', atom()}], + [ + { + Here the type is: 'ok' + Context expects type: 'error' + , atom()} + ] + } + +------------------------------ Detailed message ------------------------------ + + at tuple index 2: + {[{'ok', atom()}], [{'ok', atom()} | {'error', term()}]} is not compatible with {[{'ok', atom()}], [{'error', term()}]} + because + [{'ok', atom()} | {'error', term()}] is not compatible with [{'error', term()}] + because + {'ok', atom()} | {'error', term()} is not compatible with {'error', term()} + because + at tuple index 1: + {'ok', atom()} is not compatible with {'error', term()} + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2576:33 + │ +2576 │ maps_intersect_2_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2586:33 + │ +2586 │ maps_intersect_4_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a => 'true'} + │ + +Because in the expression's type: + #{ a => + Here the type is: number() + Context expects type: 'true' + , ... } + +------------------------------ Detailed message ------------------------------ + + #{a => number()} is not compatible with #{a => 'true'} + because + at key `a`: + #{a => number()} is not compatible with #{a => 'true'} + because + number() is not compatible with 'true' + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2596:33 + │ +2596 │ maps_intersect_6_neg(M1, M2) -> maps:intersect(M1, M2). + │ ^^^^^^^^^^^^^^^^^^^^^^ + │ │ + │ maps:intersect(M1, M2). +Expression has type: #{a => number()} +Context expected type: #{a := number()} + │ + +Because in the expression's type: + Here the type is: #{a => ..., ...} + Context expects type: #{a := ..., ...} + The type of the expression is missing the following required keys: a. + +------------------------------ Detailed message ------------------------------ + +key `a` is declared as required in the latter but not in the former + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2709:40 + │ +2709 │ (foo, A) -> binary_to_atom(A); + │ ^ A. +Expression has type: atom() +Context expected type: binary() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2710:40 + │ +2710 │ (bar, B) -> atom_to_binary(B); + │ ^ B. +Expression has type: binary() +Context expected type: atom() + +error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) + ┌─ check/src/custom.erl:2711:50 + │ +2711 │ ({foo, bar}, I) -> binary_to_integer(I); + │ ^ I. +Expression has type: number() +Context expected type: binary() + +202 ERRORS diff --git a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty index b5f637ead3..037e6b14a6 100644 --- a/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty +++ b/crates/elp/src/resources/test/eqwalizer_tests/eqwater/eqwater_maps.pretty @@ -70,20 +70,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: #{a := dynamic(), dynamic() => dynamic()} Context expected type: 'err' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ eqwater/src/eqwater_maps.erl:70:29 - │ -70 │ (_, #{a := V}) -> is_ok(V) - │ ^ - │ │ - │ V. -Expression has type: 'ok' | 'err' -Context expected type: 'ok' - │ - -Because in the expression's type: - Here the type is a union type with some valid candidates: 'ok' - However the following candidate: 'err' - Differs from the expected type: 'ok' - -6 ERRORS +5 ERRORS diff --git a/crates/elp/src/resources/test/hierarchical_config/basic.stdout b/crates/elp/src/resources/test/hierarchical_config/basic.stdout index de8cb63308..b0ccc8796b 100644 --- a/crates/elp/src/resources/test/hierarchical_config/basic.stdout +++ b/crates/elp/src/resources/test/hierarchical_config/basic.stdout @@ -1,5 +1,6 @@ Diagnostics reported: Reporting all diagnostics codes +app_a/src/app_a.erl:4:9-4:16::[Warning] [W0002] Unused macro (MACRO_B) app_a/src/app_a.erl:6:1-6:5::[Warning] [L1230] function main/0 is unused app_b/src/app_b.erl:4:9-4:16::[Warning] [W0002] Unused macro (MACRO_B) -app_b/src/app_b.erl:6:1-6:5::[Warning] [L1230] function main/0 is unused +app_b/src/app_b.erl:6:1-6:5::[Warning] [L1230] function main/0 is unused \ No newline at end of file diff --git a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout index 5a42009118..3d59c453e3 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_lint_ignore_apps_b.stdout @@ -1,3 +1,3 @@ Diagnostics reported: -app_a/src/app_a.erl:9:6-9:7::[Warning] [W0010] this variable is unused app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [W0010] this variable is unused +app_a/src/app_a.erl:9:6-9:7::[Warning] [W0010] this variable is unused diff --git a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout index 7b6a1e705c..6e07ea2bba 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_json_output.stdout @@ -5,8 +5,6 @@ {"path":"app_a/src/app_a.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"W0011 (application_get_env)","original":null,"replacement":null,"description":"module `app_a` belongs to app `app_a`, but reads env for `misc`\n\nFor more information see: /erlang-error-index/w/W0011","docPath":"website/docs/erlang-error-index/w/W0011.md"} {"path":"app_a/src/app_a.erl","line":8,"char":7,"code":"ELP","severity":"warning","name":"W0018 (unexpected_semi_or_dot)","original":null,"replacement":null,"description":"Unexpected ';'\n\nFor more information see: /erlang-error-index/w/W0018","docPath":"website/docs/erlang-error-index/w/W0018.md"} {"path":"app_a/src/app_a.erl","line":9,"char":1,"code":"ELP","severity":"error","name":"P1700 (head_mismatch)","original":null,"replacement":null,"description":"head mismatch 'fooX' vs 'food'\n\nFor more information see: /erlang-error-index/p/P1700","docPath":null} -{"path":"app_a/src/app_a_ssr.erl","line":7,"char":6,"code":"ELP","severity":"warning","name":"W0060 (bound_var_in_lhs)","original":null,"replacement":null,"description":"Match on a bound variable\n\nFor more information see: /erlang-error-index/w/W0060","docPath":"website/docs/erlang-error-index/w/W0060.md"} -{"path":"app_a/src/app_a_ssr.erl","line":8,"char":6,"code":"ELP","severity":"warning","name":"W0060 (bound_var_in_lhs)","original":null,"replacement":null,"description":"Match on a bound variable\n\nFor more information see: /erlang-error-index/w/W0060","docPath":"website/docs/erlang-error-index/w/W0060.md"} {"path":"app_a/src/app_a_unused_param.erl","line":5,"char":5,"code":"ELP","severity":"warning","name":"L1268 (L1268)","original":null,"replacement":null,"description":"variable 'X' is unused\n\nFor more information see: /erlang-error-index/l/L1268","docPath":null} {"path":"app_a/src/custom_function_matches.erl","line":13,"char":5,"code":"ELP","severity":"warning","name":"W0017 (undefined_function)","original":null,"replacement":null,"description":"Function 'excluded:function/0' is undefined.\n\nFor more information see: /erlang-error-index/w/W0017","docPath":"website/docs/erlang-error-index/w/W0017.md"} {"path":"app_a/src/custom_function_matches.erl","line":14,"char":5,"code":"ELP","severity":"warning","name":"W0017 (undefined_function)","original":null,"replacement":null,"description":"Function 'not_excluded:function/0' is undefined.\n\nFor more information see: /erlang-error-index/w/W0017","docPath":"website/docs/erlang-error-index/w/W0017.md"} diff --git a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout index 5bcd503e10..9f7a5405b4 100644 --- a/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout +++ b/crates/elp/src/resources/test/linter/parse_elp_no_lint_specified_output.stdout @@ -8,8 +8,6 @@ app_a/src/app_a.erl:20:1-20:4::[Warning] [L1230] function bat/2 is unused app_a/src/app_a.erl:5:5-5:35::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` app_a/src/app_a.erl:8:7-8:8::[Warning] [W0018] Unexpected ';' app_a/src/app_a.erl:9:1-9:5::[Error] [P1700] head mismatch 'fooX' vs 'food' -app_a/src/app_a_ssr.erl:7:6-7:7::[Warning] [W0060] Match on a bound variable -app_a/src/app_a_ssr.erl:8:6-8:7::[Warning] [W0060] Match on a bound variable app_a/src/app_a_unused_param.erl:5:5-5:6::[Warning] [L1268] variable 'X' is unused app_a/src/custom_function_matches.erl:13:5-13:22::[Warning] [W0017] Function 'excluded:function/0' is undefined. app_a/src/custom_function_matches.erl:14:5-14:26::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. diff --git a/crates/elp/src/resources/test/linter/warnings_as_errors.stdout b/crates/elp/src/resources/test/linter/warnings_as_errors.stdout index 01007e94c4..00d8506230 100644 --- a/crates/elp/src/resources/test/linter/warnings_as_errors.stdout +++ b/crates/elp/src/resources/test/linter/warnings_as_errors.stdout @@ -8,8 +8,6 @@ app_a/src/app_a.erl:20:1-20:4::[Error] [L1230] function bat/2 is unused app_a/src/app_a.erl:5:5-5:35::[Warning] [W0011] module `app_a` belongs to app `app_a`, but reads env for `misc` app_a/src/app_a.erl:8:7-8:8::[Warning] [W0018] Unexpected ';' app_a/src/app_a.erl:9:1-9:5::[Error] [P1700] head mismatch 'fooX' vs 'food' -app_a/src/app_a_ssr.erl:7:6-7:7::[Warning] [W0060] Match on a bound variable -app_a/src/app_a_ssr.erl:8:6-8:7::[Warning] [W0060] Match on a bound variable app_a/src/app_a_unused_param.erl:5:5-5:6::[Error] [L1268] variable 'X' is unused app_a/src/custom_function_matches.erl:13:5-13:22::[Warning] [W0017] Function 'excluded:function/0' is undefined. app_a/src/custom_function_matches.erl:14:5-14:26::[Warning] [W0017] Function 'not_excluded:function/0' is undefined. diff --git a/crates/elp/src/resources/test/linter_config/basic.stdout b/crates/elp/src/resources/test/linter_config/basic.stdout deleted file mode 100644 index 946fd7dc9a..0000000000 --- a/crates/elp/src/resources/test/linter_config/basic.stdout +++ /dev/null @@ -1,5 +0,0 @@ -Diagnostics reported: -Reporting all diagnostics codes -app_a/src/app_a.erl:3:9-3:16::[Warning] [W0002] Unused macro (MACRO_A) -app_a/src/app_a.erl:4:9-4:14::[Warning] [L1260] record rec_a is unused -app_b/src/app_b.erl:3:9-3:16::[Warning] [W0002] Unused macro (MACRO_B) \ No newline at end of file diff --git a/crates/elp/src/resources/test/parse_elp_help.stdout b/crates/elp/src/resources/test/parse_elp_help.stdout index 75cc38354e..1457aed5c5 100644 --- a/crates/elp/src/resources/test/parse_elp_help.stdout +++ b/crates/elp/src/resources/test/parse_elp_help.stdout @@ -1,4 +1,4 @@ -Usage: [--project PROJECT] [--module MODULE] [--file ARG] [--to TO] [--no-diags] [--experimental] [--as PROFILE] [--dump-includes] [--rebar] [--include-generated] [--serial] [--use-cli-severity] [[--format FORMAT]] [--report-system-stats] [[--severity SEVERITY]] +Usage: [--project PROJECT] [--module MODULE] [--file ARG] [--to TO] [--no-diags] [--experimental] [--as PROFILE] [--dump-includes] [--rebar] [--include-generated] [--serial] [--use-cli-severity] [[--format FORMAT]] [--report-system-stats] Available options: --project Path to directory with project, or to a JSON file (defaults to `.`) @@ -15,5 +15,4 @@ Available options: --use-cli-severity If specified, use the provided CLI severity mapping instead of the default one --format Show diagnostics in JSON format --report-system-stats Report system memory usage and other statistics - --severity Minimum severity level to report. Valid values: error, warning, weak_warning, information -h, --help Prints help information diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty b/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty index 1d868bbbc6..bfbe45f508 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_all_bail_on_error_failure.pretty @@ -192,14 +192,6 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_b/src/app_b.erl:16:5 │ @@ -208,4 +200,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: [T] Context expected type: T -21 ERRORS +20 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl index b311705d68..8636389098 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl +++ b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.jsonl @@ -17,5 +17,4 @@ {"path":"app_a/src/app_a_mod2.erl","line":22,"char":1,"code":"ELP","severity":"error","name":"eqWAlizer: type_alias_is_non_productive","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nrecursive type invalid/0 is not productive\n```\n\n> [docs on `type_alias_is_non_productive`](https://fb.me/eqwalizer_errors#type_alias_is_non_productive)","docPath":null} {"path":"app_a/src/app_a_mod2.erl","line":31,"char":9,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'an_atom'","replacement":null,"description":"```lang=error,counterexample\n`'an_atom'`.\n\nExpression has type: 'an_atom'\nContext expected type: number()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/test/app_a_test_helpers.erl","line":6,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'wrong_ret'","replacement":null,"description":"```lang=error,counterexample\n`'wrong_ret'`.\n\nExpression has type: 'wrong_ret'\nContext expected type: 'error'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/test/app_a_test_helpers_not_opted_in.erl","line":5,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'error'","replacement":null,"description":"```lang=error,counterexample\n`'error'`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_b/src/app_b.erl","line":16,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"L","replacement":null,"description":"```lang=error,counterexample\n`L`.\n\nExpression has type: [T]\nContext expected type: T\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty index 1d868bbbc6..bfbe45f508 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics.pretty @@ -192,14 +192,6 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) ┌─ app_b/src/app_b.erl:16:5 │ @@ -208,4 +200,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: [T] Context expected type: T -21 ERRORS +20 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl index b311705d68..8636389098 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl +++ b/crates/elp/src/resources/test/standard/eqwalize_all_diagnostics_gen.jsonl @@ -17,5 +17,4 @@ {"path":"app_a/src/app_a_mod2.erl","line":22,"char":1,"code":"ELP","severity":"error","name":"eqWAlizer: type_alias_is_non_productive","original":null,"replacement":null,"description":"```lang=error,counterexample\n\nrecursive type invalid/0 is not productive\n```\n\n> [docs on `type_alias_is_non_productive`](https://fb.me/eqwalizer_errors#type_alias_is_non_productive)","docPath":null} {"path":"app_a/src/app_a_mod2.erl","line":31,"char":9,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'an_atom'","replacement":null,"description":"```lang=error,counterexample\n`'an_atom'`.\n\nExpression has type: 'an_atom'\nContext expected type: number()\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_a/test/app_a_test_helpers.erl","line":6,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'wrong_ret'","replacement":null,"description":"```lang=error,counterexample\n`'wrong_ret'`.\n\nExpression has type: 'wrong_ret'\nContext expected type: 'error'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} -{"path":"app_a/test/app_a_test_helpers_not_opted_in.erl","line":5,"char":11,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"'error'","replacement":null,"description":"```lang=error,counterexample\n`'error'`.\n\nExpression has type: 'error'\nContext expected type: 'ok'\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} {"path":"app_b/src/app_b.erl","line":16,"char":5,"code":"ELP","severity":"error","name":"eqWAlizer: incompatible_types","original":"L","replacement":null,"description":"```lang=error,counterexample\n`L`.\n\nExpression has type: [T]\nContext expected type: T\n```\n\n> [docs on `incompatible_types`](https://fb.me/eqwalizer_errors#incompatible_types)","docPath":null} diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty index 043aa00af0..67d78913b6 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_gen_rebar.pretty @@ -192,12 +192,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -20 ERRORS +19 ERRORS diff --git a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty index 043aa00af0..67d78913b6 100644 --- a/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty +++ b/crates/elp/src/resources/test/standard/eqwalize_app_diagnostics_rebar.pretty @@ -192,12 +192,4 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types Expression has type: 'wrong_ret' Context expected type: 'error' -error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types) - ┌─ app_a/test/app_a_test_helpers_not_opted_in.erl:5:11 - │ -5 │ fail() -> error. - │ ^^^^^ 'error'. -Expression has type: 'error' -Context expected type: 'ok' - -20 ERRORS +19 ERRORS diff --git a/crates/elp/src/resources/test/xref/unavailable_type.stdout b/crates/elp/src/resources/test/xref/unavailable_type.stdout index 688be17de3..7064c359ff 100644 --- a/crates/elp/src/resources/test/xref/unavailable_type.stdout +++ b/crates/elp/src/resources/test/xref/unavailable_type.stdout @@ -1,5 +1,5 @@ Reporting all diagnostics codes module specified: unavailable_type Diagnostics reported: -app_a/src/unavailable_type.erl:10:43-10:58::[Warning] [W0059] The type 'app_c:my_type_c/0' is defined in application 'app_c', but the application is not a dependency of 'app_a' (defined in 'root//xref:app_a'). -app_a/src/unavailable_type.erl:6:16-6:31::[Warning] [W0059] The type 'app_c:my_type_c/0' is defined in application 'app_c', but the application is not a dependency of 'app_a' (defined in 'root//xref:app_a'). +app_a/src/unavailable_type.erl:10:43-10:58::[Warning] [W0059] The type 'app_c:my_type_c/0' is defined in application 'app_c', but the application is not a dependency of 'app_a' (defined in 'fbcode//whatsapp/elp/test_projects/xref:app_a'). +app_a/src/unavailable_type.erl:6:16-6:31::[Warning] [W0059] The type 'app_c:my_type_c/0' is defined in application 'app_c', but the application is not a dependency of 'app_a' (defined in 'fbcode//whatsapp/elp/test_projects/xref:app_a'). diff --git a/crates/elp/src/server.rs b/crates/elp/src/server.rs index 98890640bc..65c75a1bbc 100644 --- a/crates/elp/src/server.rs +++ b/crates/elp/src/server.rs @@ -2073,7 +2073,7 @@ impl Server { }; for (_, _, file_id) in module_index.iter_own() { - match snapshot.analysis.should_eqwalize(file_id) { + match snapshot.analysis.should_eqwalize(file_id, false) { Ok(true) => { files.push(file_id); } diff --git a/crates/elp/src/server/setup.rs b/crates/elp/src/server/setup.rs index 4b8615e07c..8dba975e73 100644 --- a/crates/elp/src/server/setup.rs +++ b/crates/elp/src/server/setup.rs @@ -33,7 +33,7 @@ use super::FILE_WATCH_LOGGER_NAME; use super::logger::LspLogger; use crate::config::Config; use crate::from_json; -// @fb-only: use crate::meta_only::get_log_dir; +// @fb-only use crate::server::Handle; use crate::server::LOGGER_NAME; use crate::server::Server; @@ -126,7 +126,7 @@ impl ServerSetup { // Set up a logger for tracking down why we are seeing stale // results when branches are switched, as per T218973130 - // @fb-only: let log_dir = get_log_dir(); + // @fb-only let log_dir = format!("{}/elp", std::env::temp_dir().display()); // @oss-only let _ = fs::create_dir_all(&log_dir); let log_file = format!( diff --git a/crates/elp/src/snapshot.rs b/crates/elp/src/snapshot.rs index 69ea6b97e0..e79251f73a 100644 --- a/crates/elp/src/snapshot.rs +++ b/crates/elp/src/snapshot.rs @@ -36,11 +36,9 @@ use parking_lot::Mutex; use parking_lot::RwLock; use serde::Deserialize; use serde::Serialize; -use vfs::AnchoredPathBuf; use crate::config::Config; use crate::convert; -use crate::convert::url_from_abs_path; use crate::line_endings::LineEndings; use crate::mem_docs::MemDocs; use crate::server::EqwalizerTypes; @@ -188,14 +186,6 @@ impl Snapshot { self.line_ending_map.read()[&id] } - pub(crate) fn anchored_path(&self, path: &AnchoredPathBuf) -> Option { - let mut base = self.vfs.read().file_path(path.anchor).clone(); - base.pop(); - let path = base.join(&path.path)?; - let path = path.as_path()?; - Some(url_from_abs_path(path)) - } - pub fn update_cache_for_file( &self, file_id: FileId, @@ -203,7 +193,7 @@ impl Snapshot { ) -> Result<()> { let _ = self.analysis.def_map(file_id)?; if optimize_for_eqwalizer { - let should_eqwalize = self.analysis.should_eqwalize(file_id)?; + let should_eqwalize = self.analysis.should_eqwalize(file_id, false)?; if should_eqwalize { let _ = self.analysis.module_ast(file_id)?; } @@ -252,7 +242,7 @@ impl Snapshot { let file_ids: Vec = module_index .iter_own() .filter_map(|(_, _, file_id)| { - if let Ok(true) = self.analysis.should_eqwalize(file_id) { + if let Ok(true) = self.analysis.should_eqwalize(file_id, false) { Some(file_id) } else { None diff --git a/crates/elp/src/to_proto.rs b/crates/elp/src/to_proto.rs index 3e5b1fd1e1..70d316d5c6 100644 --- a/crates/elp/src/to_proto.rs +++ b/crates/elp/src/to_proto.rs @@ -10,7 +10,6 @@ //! Conversion of rust-analyzer specific types to lsp_types equivalents. -use std::mem; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; @@ -48,7 +47,6 @@ use elp_ide::elp_ide_db::elp_base_db::FileId; use elp_ide::elp_ide_db::elp_base_db::FilePosition; use elp_ide::elp_ide_db::elp_base_db::FileRange; use elp_ide::elp_ide_db::rename::RenameError; -use elp_ide::elp_ide_db::source_change::FileSystemEdit; use elp_ide::elp_ide_db::source_change::SourceChange; use elp_ide_db::text_edit::Indel; use elp_ide_db::text_edit::TextEdit; @@ -123,9 +121,9 @@ pub(crate) fn optional_versioned_text_document_identifier( pub(crate) fn text_document_edit( snap: &Snapshot, file_id: FileId, - text_document: lsp_types::OptionalVersionedTextDocumentIdentifier, edit: TextEdit, ) -> Result { + let text_document = optional_versioned_text_document_identifier(snap, file_id); let line_index = snap.analysis.line_index(file_id)?; let line_endings = snap.line_endings(file_id); let edits: Vec> = edit @@ -133,131 +131,34 @@ pub(crate) fn text_document_edit( .map(|it| lsp_types::OneOf::Left(text_edit(&line_index, line_endings, it))) .collect(); + // if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() { + // for edit in &mut edits { + // edit.annotation_id = Some(outside_workspace_annotation_id()) + // } + // } Ok(lsp_types::TextDocumentEdit { text_document, edits, }) } -pub(crate) fn text_document_ops( - snap: &Snapshot, - file_system_edit: FileSystemEdit, -) -> Cancellable> { - let mut ops = Vec::new(); - match file_system_edit { - FileSystemEdit::CreateFile { - dst, - initial_contents, - } => { - if let Some(uri) = snap.anchored_path(&dst) { - let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile { - uri: uri.clone(), - options: None, - annotation_id: None, - }); - ops.push(lsp_types::DocumentChangeOperation::Op(create_file)); - if !initial_contents.is_empty() { - let text_document = - lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; - let text_edit = lsp_types::TextEdit { - range: lsp_types::Range::default(), - new_text: initial_contents, - }; - let edit_file = lsp_types::TextDocumentEdit { - text_document, - edits: vec![lsp_types::OneOf::Left(text_edit)], - }; - ops.push(lsp_types::DocumentChangeOperation::Edit(edit_file)); - } - } else { - log::warn!("create file failed: {:?}", dst); - } - } - FileSystemEdit::MoveFile { src, dst } => { - if let Some(new_uri) = snap.anchored_path(&dst) { - let old_uri = snap.file_id_to_url(src); - let rename_file = lsp_types::RenameFile { - old_uri, - new_uri, - options: None, - annotation_id: None, - }; - ops.push(lsp_types::DocumentChangeOperation::Op( - lsp_types::ResourceOp::Rename(rename_file), - )) - } else { - log::warn!("rename file failed: {:?} -> {:?}", src, dst); - } - } - } - Ok(ops) -} - pub(crate) fn workspace_edit( snap: &Snapshot, - mut source_change: SourceChange, + source_change: SourceChange, ) -> Result { - let mut document_changes: Vec = Vec::new(); - - // This is copying RA's order of operations, first file creates, - // then edits, then file moves. - - // This allows us to apply edits to the file once it has - // moved. Except we have no FileId at that point - for op in &mut source_change.file_system_edits { - if let FileSystemEdit::CreateFile { - dst, - initial_contents, - } = op - { - // replace with a placeholder to avoid cloning the edit - let op = FileSystemEdit::CreateFile { - dst: dst.clone(), - initial_contents: mem::take(initial_contents), - }; - let ops = text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); - } - } - - for op in source_change.file_system_edits { - if !matches!(op, FileSystemEdit::CreateFile { .. }) { - let ops = text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); - } - } - + let mut edits: Vec<_> = vec![]; for (file_id, edit) in source_change.source_file_edits { - let text_document = optional_versioned_text_document_identifier(snap, file_id); - let edit = text_document_edit(snap, file_id, text_document, edit)?; - document_changes.push(lsp_types::DocumentChangeOperation::Edit( - lsp_types::TextDocumentEdit { - text_document: edit.text_document, - edits: edit.edits.into_iter().collect(), - }, - )); + // let edit = snippet_text_document_edit(snap, source_change.is_snippet, file_id, edit)?; + let edit = text_document_edit(snap, file_id, edit)?; + edits.push(lsp_types::TextDocumentEdit { + text_document: edit.text_document, + edits: edit.edits.into_iter().collect(), + }); } - - // Edits on renamed files. The LineIndex from the original can be used. - for (file_ref, edit) in source_change.new_file_edits { - if let Some(uri) = snap.anchored_path(&file_ref.clone().into()) { - let version = snap.url_file_version(&uri); - let text_document = lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version }; - let edit = text_document_edit(snap, file_ref.anchor, text_document, edit)?; - document_changes.push(lsp_types::DocumentChangeOperation::Edit( - lsp_types::TextDocumentEdit { - text_document: edit.text_document, - edits: edit.edits.into_iter().collect(), - }, - )); - } else { - log::warn!("new file edit failed: {:?}", file_ref); - } - } - + let document_changes = lsp_types::DocumentChanges::Edits(edits); let workspace_edit = lsp_types::WorkspaceEdit { changes: None, - document_changes: Some(lsp_types::DocumentChanges::Operations(document_changes)), + document_changes: Some(document_changes), change_annotations: None, }; Ok(workspace_edit) @@ -281,6 +182,10 @@ pub(crate) fn code_action( ) -> Result { let mut res = lsp_types::CodeAction { title: assist.label.to_string(), + // group: assist + // .group + // .filter(|_| snap.config.code_action_group()) + // .map(|gr| gr.0), kind: Some(code_action_kind(assist.id.1)), edit: None, is_preferred: None, diff --git a/crates/elp/tests/slow-tests/buck_tests.rs b/crates/elp/tests/slow-tests/buck_tests.rs index 91f2b234d9..e76fdb8bad 100644 --- a/crates/elp/tests/slow-tests/buck_tests.rs +++ b/crates/elp/tests/slow-tests/buck_tests.rs @@ -31,7 +31,7 @@ mod tests { #[test] #[ignore] fn test_success_case() { - let path_str = "../../test/test_projects/buck_tests"; + let path_str = "../../test_projects/buck_tests"; let path: PathBuf = path_str.into(); let cli = Fake::default(); @@ -65,7 +65,7 @@ mod tests { let ast = analysis.module_ast(file_id).unwrap(); assert_eq!(ast.errors, vec![]); let eq_enabled = analysis - .is_eqwalizer_enabled(file_id) + .is_eqwalizer_enabled(file_id, false) .unwrap_or_else(|_| panic!("Failed to check if eqwalizer enabled for {module}")); assert_eq!(eq_enabled, eqwalizer_enabled); let project_data = analysis.project_data(file_id).unwrap(); @@ -76,7 +76,7 @@ mod tests { #[test] #[ignore] fn test_load_buck_targets() { - let path_str = "../../test/test_projects/buck_tests"; + let path_str = "../../test_projects/buck_tests"; let path: PathBuf = path_str.into(); let (elp_config, buck_config) = diff --git a/crates/elp/tests/slow-tests/main.rs b/crates/elp/tests/slow-tests/main.rs index e256ce2c62..60167593fd 100644 --- a/crates/elp/tests/slow-tests/main.rs +++ b/crates/elp/tests/slow-tests/main.rs @@ -36,7 +36,7 @@ use crate::support::diagnostic_project; fn test_run_mock_lsp() { if cfg!(feature = "buck") { let workspace_root = AbsPathBuf::assert( - Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/test_projects/end_to_end"), + Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test_projects/end_to_end"), ); // Sanity check @@ -70,7 +70,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -99,7 +99,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -128,7 +128,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -157,7 +157,7 @@ fn test_run_mock_lsp() { } ], "textDocument": { - "uri": "file:///[..]/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", + "uri": "file:///[..]/test_projects/end_to_end/assist_examples/src/head_mismatch.erl", "version": 0 } } @@ -175,7 +175,7 @@ fn test_run_mock_lsp() { fn test_e2e_eqwalizer_module() { if cfg!(feature = "buck") { let workspace_root = AbsPathBuf::assert( - Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/test_projects/standard"), + Utf8Path::new(env!("CARGO_WORKSPACE_DIR")).join("test_projects/standard"), ); // Sanity check @@ -321,7 +321,7 @@ fn test_e2e_eqwalizer_module() { "source": "eqWAlizer" } ], - "uri": "file:///[..]/test/test_projects/standard/app_a/src/app_a.erl", + "uri": "file:///[..]/test_projects/standard/app_a/src/app_a.erl", "version": 0 }"#]], ); @@ -334,7 +334,7 @@ fn test_e2e_eqwalizer_module() { // #[test] // fn test_e2e_eqwalizer_header() { // let workspace_root = -// AbsPathBuf::assert(Path::new(env!("CARGO_WORKSPACE_DIR")).join("test/test_projects/standard")); +// AbsPathBuf::assert(Path::new(env!("CARGO_WORKSPACE_DIR")).join("test_projects/standard")); // // Sanity check // assert!(std::fs::metadata(&workspace_root).is_ok()); diff --git a/crates/hir/src/body/scope.rs b/crates/hir/src/body/scope.rs index 4ac4e366d8..dd1da23e94 100644 --- a/crates/hir/src/body/scope.rs +++ b/crates/hir/src/body/scope.rs @@ -865,7 +865,7 @@ mod tests { f() -> As = [1,2,3], Bs = [4,5,6], - [{X,Y, ~} || X <- As && Y <- Bs] + [{X,Y}~ || X <- As && Y <- Bs] . ", &["Y", "X", "As", "Bs"], diff --git a/crates/hir/src/body/tests.rs b/crates/hir/src/body/tests.rs index eab603a76d..c616df812d 100644 --- a/crates/hir/src/body/tests.rs +++ b/crates/hir/src/body/tests.rs @@ -448,7 +448,6 @@ foo(#record.field) -> #record.field. fn record() { check( r#" -//- expect_parse_errors foo1(#record{field = 1}) -> #record{field = A + B}. foo2(#record{field}) -> #record{field = }. "#, @@ -474,7 +473,6 @@ foo2(#record{field}) -> #record{field = }. fn record_update() { check( r#" -//- expect_parse_errors foo1() -> Expr#record{field = undefined}. foo2() -> Expr#record{field = ok, missing = }. "#, @@ -559,7 +557,7 @@ fn case() { r#" foo() -> case 1 + 2 of - X when X andalso true; X =< 100, X >= 5 -> ok; + X when X andalso true; X <= 100, X >= 5 -> ok; _ -> error end. "#, @@ -568,7 +566,7 @@ foo() -> case (1 + 2) of X when (X andalso true); - (X =< 100), + (X < 100), (X >= 5) -> ok; @@ -838,7 +836,6 @@ foo() -> fn parens() { check( r#" -//- expect_parse_errors foo((ok), ()) -> (ok), (). @@ -998,7 +995,6 @@ foo(fun() -> ok end) -> ok. fn invalid_comprehension() { check( r#" -//- expect_parse_errors foo(<>, [Byte || Byte <- List]]) -> ok. "#, expect![[r#" @@ -1396,7 +1392,6 @@ fn call_type_erlang_bif() { fn record_type() { check( r#" -//- expect_parse_errors -type foo1() :: #record{}. -type foo2(B) :: #record{a :: integer(), b :: B}. -type foo3() :: #record{a ::}. @@ -1534,7 +1529,6 @@ fn record_definition() { fn simple_term() { check( r#" -//- expect_parse_errors -foo(ok). -missing_value(). "#, @@ -2699,7 +2693,6 @@ fn verbatim_binary_sigil_in_type() { // Note: \~ gets replaced by ~ in the fixture parsing check( r#" - //- expect_parse_errors -type foo() :: \~B"ab\"c\"\d"). -type bar() :: "hello"). "#, @@ -2730,7 +2723,6 @@ fn verbatim_binary_sigil_in_term() { fn lowering_with_error_nodes() { check( r#" - //- expect_parse_errors f(1a) -> ok begin 1 end. "#, expect![[r#" @@ -2997,10 +2989,8 @@ fn tree_print_record() { #[test] fn tree_print_attribute() { - // TODO: fix wild attribute parsing, T246546041, to remove expect_parse_errors check_ast( r#" - //- expect_parse_errors -wild(foo, []). -compile({inline, [foo/1]}). -compile({a/a, 1/1}). diff --git a/crates/hir/src/body/tree_print.rs b/crates/hir/src/body/tree_print.rs index d6b956690f..4aa6591d84 100644 --- a/crates/hir/src/body/tree_print.rs +++ b/crates/hir/src/body/tree_print.rs @@ -2340,7 +2340,7 @@ mod tests { r#" foo() -> case 1 + 2 of - X when X andalso true; X =< 100, X >= 5 -> ok; + X when X andalso true; X <= 100, X >= 5 -> ok; _ -> error end. "#, @@ -2381,7 +2381,7 @@ mod tests { rhs Expr<8>:Literal(Integer(100)) op - CompOp(Ord { ordering: Less, strict: false }), + CompOp(Ord { ordering: Less, strict: true }), }, Expr<12>:Expr::BinaryOp { lhs @@ -3114,7 +3114,6 @@ mod tests { fn type_record() { check( r#" - //- expect_parse_errors -type foo1() :: #record{}. -type foo2(B) :: #record{a :: integer(), b :: B}. -type foo3() :: #record{a ::}. @@ -3499,7 +3498,6 @@ mod tests { fn top_level_forms() { check( r#" - //- expect_parse_errors -module(main). bug -compile([export_all]). diff --git a/crates/hir/src/fold.rs b/crates/hir/src/fold.rs index 59b12be6fd..78cd442592 100644 --- a/crates/hir/src/fold.rs +++ b/crates/hir/src/fold.rs @@ -339,7 +339,7 @@ pub enum ParentId { #[derive(Debug)] pub struct AnyCallBackCtx<'a> { - pub in_macro: Option<(HirIdx, Option>)>, + pub in_macro: Option, pub parents: &'a Vec, pub item_id: AnyExprId, pub item: AnyExpr, @@ -426,7 +426,7 @@ pub struct FoldCtx<'a, T> { body_origin: BodyOrigin, body: &'a FoldBody<'a>, strategy: Strategy, - macro_stack: Vec<(HirIdx, Option>)>, + macro_stack: Vec, parents: Vec, callback: AnyCallBack<'a, T>, } @@ -594,7 +594,7 @@ impl<'a, T> FoldCtx<'a, T> { .do_fold_pat(pat_id, initial) } - fn in_macro(&self) -> Option<(HirIdx, Option>)> { + fn in_macro(&self) -> Option { self.macro_stack.first().copied() } @@ -752,19 +752,16 @@ impl<'a, T> FoldCtx<'a, T> { crate::Expr::MacroCall { expansion, args, - macro_def, + macro_def: _, macro_name: _, } => { if self.strategy.macros == MacroStrategy::DoNotExpand { self.do_fold_exprs(args, acc) } else { - self.macro_stack.push(( - HirIdx { - body_origin: self.body_origin, - idx: AnyExprId::Expr(expr_id), - }, - *macro_def, - )); + self.macro_stack.push(HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::Expr(expr_id), + }); let e = self.do_fold_expr(*expansion, acc); self.macro_stack.pop(); e @@ -953,19 +950,16 @@ impl<'a, T> FoldCtx<'a, T> { crate::Pat::MacroCall { expansion, args, - macro_def, + macro_def: _, macro_name: _, } => { if self.strategy.macros == MacroStrategy::DoNotExpand { self.do_fold_exprs(args, acc) } else { - self.macro_stack.push(( - HirIdx { - body_origin: self.body_origin, - idx: AnyExprId::Pat(pat_id), - }, - *macro_def, - )); + self.macro_stack.push(HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::Pat(pat_id), + }); let e = self.do_fold_pat(*expansion, acc); self.macro_stack.pop(); e @@ -1171,19 +1165,16 @@ impl<'a, T> FoldCtx<'a, T> { TypeExpr::MacroCall { expansion, args, - macro_def, + macro_def: _, macro_name: _, } => { if self.strategy.macros == MacroStrategy::DoNotExpand { self.do_fold_exprs(args, acc) } else { - self.macro_stack.push(( - HirIdx { - body_origin: self.body_origin, - idx: AnyExprId::TypeExpr(type_expr_id), - }, - *macro_def, - )); + self.macro_stack.push(HirIdx { + body_origin: self.body_origin, + idx: AnyExprId::TypeExpr(type_expr_id), + }); let e = self.do_fold_type_expr(*expansion, acc); self.macro_stack.pop(); e @@ -2221,9 +2212,7 @@ bar() -> #[test] fn traverse_attribute() { - // TODO: fix wild attribute parsing, T246546041, to remove expect_parse_errors let fixture_str = r#" - //- expect_parse_errors -module(foo). -wild(r1, {f1, f~oo}). "#; diff --git a/crates/hir/src/form_list/tests.rs b/crates/hir/src/form_list/tests.rs index 79f542fd0d..00a5ec4020 100644 --- a/crates/hir/src/form_list/tests.rs +++ b/crates/hir/src/form_list/tests.rs @@ -318,7 +318,6 @@ fn export() { fn import() { check( r#" -//- expect_parse_errors -import(, []). -import(foo, []). -import(foo, [foo/1]). diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 751a2f4907..1ec75fd25e 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -155,7 +155,7 @@ pub use name::MacroName; pub use name::Name; pub use name::NameArity; pub use name::known; -// @fb-only: pub use name::meta_only; +// @fb-only pub use sema::AtomDef; pub use sema::CallDef; pub use sema::DefinitionOrReference; @@ -232,10 +232,6 @@ impl HirIdx { } } - pub fn file_id(&self) -> FileId { - self.body_origin.file_id() - } - /// This function is used to print a representation of the HIR AST /// corresponding to the given `HirIdx`. It is used for debugging /// and testing. diff --git a/crates/hir/src/name.rs b/crates/hir/src/name.rs index f94f139d38..00ce2f89f1 100644 --- a/crates/hir/src/name.rs +++ b/crates/hir/src/name.rs @@ -10,7 +10,7 @@ //! See [`Name`]. -// @fb-only: pub mod meta_only; +// @fb-only use std::borrow::Cow; use std::collections::HashSet; diff --git a/crates/hir/src/sema.rs b/crates/hir/src/sema.rs index 68577d2a2e..78a7db7c3c 100644 --- a/crates/hir/src/sema.rs +++ b/crates/hir/src/sema.rs @@ -102,7 +102,7 @@ use crate::resolver::Resolution; use crate::resolver::Resolver; mod find; -// @fb-only: pub mod meta_only; +// @fb-only pub mod to_def; pub struct ModuleIter(Arc); @@ -1006,28 +1006,6 @@ impl Semantic<'_> { // Folds end // ----------------------------------------------------------------- - pub fn bound_vars_by_function( - &self, - file_id: FileId, - ) -> FxHashMap> { - let bound_vars = self.bound_vars_in_pattern_diagnostic(file_id); - let mut bound_vars_by_function: FxHashMap> = - FxHashMap::default(); - bound_vars.iter().for_each(|(function_id, pat_id, _var)| { - bound_vars_by_function - .entry(function_id.value) - .and_modify(|vars| { - vars.insert(*pat_id); - }) - .or_insert_with(|| { - let mut vars = FxHashSet::default(); - vars.insert(*pat_id); - vars - }); - }); - bound_vars_by_function - } - pub fn bound_vars_in_pattern_diagnostic( &self, file_id: FileId, diff --git a/crates/hir/src/sema/to_def.rs b/crates/hir/src/sema/to_def.rs index 01d17278a2..5918054fc5 100644 --- a/crates/hir/src/sema/to_def.rs +++ b/crates/hir/src/sema/to_def.rs @@ -42,7 +42,7 @@ use crate::macro_exp; use crate::macro_exp::BuiltInMacro; use crate::macro_exp::MacroExpCtx; use crate::resolver::Resolver; -// @fb-only: use crate::sema::meta_only; +// @fb-only pub trait ToDef: Clone { type Def; @@ -567,7 +567,7 @@ pub fn resolve_call_target( let fn_name: Name = sema.db.lookup_atom(body[*name].as_atom()?); let mo = None; // @oss-only - // @fb-only: meta_only::resolve_handle_call_target(sema, arity, file_id, &module_name, &fn_name); + // @fb-only if let Some(r) = mo { r } else { @@ -885,183 +885,12 @@ fn add_dynamic_call_patterns(patterns: &mut FxHashMap Self { - Self { - index, - arg_type: ModuleArgType::Atom, - } - } - - /// Creates a pattern where the argument is a list of module atoms. - pub const fn list(index: usize) -> Self { - Self { - index, - arg_type: ModuleArgType::List, - } - } - - /// Creates a pattern where the argument can be either a single atom or a list. - pub const fn atom_or_list(index: usize) -> Self { - Self { - index, - arg_type: ModuleArgType::AtomOrList, - } - } - - /// Returns true if this pattern accepts a single atom. - pub const fn accepts_atom(&self) -> bool { - matches!( - self.arg_type, - ModuleArgType::Atom | ModuleArgType::AtomOrList - ) - } - - /// Returns true if this pattern accepts a list of atoms. - pub const fn accepts_list(&self) -> bool { - matches!( - self.arg_type, - ModuleArgType::List | ModuleArgType::AtomOrList - ) - } -} - -fn add_module_argument_patterns(patterns: &mut FxHashMap) { - // Each entry follows the format: - // (module, function, arity) -> ModuleArgPattern - // - // Where: - // module: Module name (Some("meck"), Some("application"), etc.) - // function: Function name as string literal (e.g., "new", "get_env") - // arity: Number of arguments this function pattern expects - // ModuleArgPattern: Contains the argument index and the expected type - // - // All indexes are 0-based. - - // meck - mocking library - // meck:new/2 accepts either a single module atom or a list of modules - patterns.insert((Some("meck"), "called", 3), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "called", 4), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "capture", 5), ModuleArgPattern::atom(1)); - patterns.insert((Some("meck"), "capture", 6), ModuleArgPattern::atom(1)); - patterns.insert( - (Some("meck"), "delete", 3), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "delete", 4), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "expect", 3), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "expect", 4), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "expects", 2), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert((Some("meck"), "history", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "history", 2), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "loop", 4), ModuleArgPattern::atom_or_list(0)); - patterns.insert((Some("meck"), "new", 1), ModuleArgPattern::atom_or_list(0)); - patterns.insert((Some("meck"), "new", 2), ModuleArgPattern::atom_or_list(0)); - patterns.insert((Some("meck"), "num_calls", 3), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "num_calls", 4), ModuleArgPattern::atom(0)); - patterns.insert( - (Some("meck"), "reset", 1), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "sequence", 4), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "unload", 1), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert( - (Some("meck"), "validate", 1), - ModuleArgPattern::atom_or_list(0), - ); - patterns.insert((Some("meck"), "wait", 4), ModuleArgPattern::atom(0)); - patterns.insert((Some("meck"), "wait", 5), ModuleArgPattern::atom(1)); - patterns.insert((Some("meck"), "wait", 6), ModuleArgPattern::atom(1)); - - // code module - module loading and management - // These functions from the Erlang stdlib take module() as their argument - patterns.insert((Some("code"), "load_file", 1), ModuleArgPattern::atom(0)); - patterns.insert( - (Some("code"), "ensure_loaded", 1), - ModuleArgPattern::atom(0), - ); - patterns.insert((Some("code"), "delete", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "purge", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "soft_purge", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "is_loaded", 1), ModuleArgPattern::atom(0)); - patterns.insert( - (Some("code"), "get_object_code", 1), - ModuleArgPattern::atom(0), - ); - patterns.insert((Some("code"), "module_md5", 1), ModuleArgPattern::atom(0)); - patterns.insert((Some("code"), "is_sticky", 1), ModuleArgPattern::atom(0)); -} - -// Lazy static initialization for the patterns maps +// Lazy static initialization for the patterns map lazy_static! { static ref DYNAMIC_CALL_PATTERNS: FxHashMap = { let mut patterns = FxHashMap::default(); add_dynamic_call_patterns(&mut patterns); - // @fb-only: meta_only::add_dynamic_call_patterns(&mut patterns); - patterns - }; - static ref MODULE_ARGUMENT_PATTERNS: FxHashMap = { - let mut patterns = FxHashMap::default(); - add_module_argument_patterns(&mut patterns); - // @fb-only: meta_only::add_module_argument_patterns(&mut patterns); - patterns - }; - /// Combined patterns for module argument positions. - /// Merges dynamic call patterns (that have module_arg_index) with simple module argument patterns. - /// Used by rename operations where we only care about the module argument position. - static ref COMBINED_MODULE_ARG_PATTERNS: FxHashMap = { - let mut patterns: FxHashMap = FxHashMap::default(); - // Add module_arg_index from dynamic call patterns (where present) - for (key, pattern) in DYNAMIC_CALL_PATTERNS.iter() { - if let Some(module_idx) = pattern.module_arg_index { - patterns.insert(*key, ModuleArgPattern::atom(module_idx)); - } - } - // Add from simple module argument patterns - for (key, module_arg_pattern) in MODULE_ARGUMENT_PATTERNS.iter() { - patterns.insert(*key, *module_arg_pattern); - } + // @fb-only patterns }; } @@ -1070,10 +899,6 @@ fn get_dynamic_call_patterns() -> &'static FxHashMap &'static FxHashMap { - &COMBINED_MODULE_ARG_PATTERNS -} - fn look_for_dynamic_call( sema: &Semantic, file_id: FileId, diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index d0ae18c158..6cbdd3469c 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -17,7 +17,7 @@ use elp_syntax::TextRange; use fxhash::FxHashMap; use fxhash::FxHashSet; -// @fb-only: use crate::meta_only; +// @fb-only use crate::runnables::Runnable; use crate::runnables::runnables; @@ -57,11 +57,11 @@ pub struct Link { } #[rustfmt::skip] -// @fb-only: pub(crate) fn annotations(db: &RootDatabase, file_id: FileId) -> Vec { +// @fb-only pub(crate) fn annotations(_db: &RootDatabase, _file_id: FileId) -> Vec { // @oss-only - // @fb-only: let mut annotations = Vec::default(); + // @fb-only let annotations = Vec::default(); // @oss-only - // @fb-only: meta_only::annotations(db, file_id, &mut annotations); + // @fb-only annotations } diff --git a/crates/ide/src/codemod_helpers.rs b/crates/ide/src/codemod_helpers.rs index 2ecd21e82c..e06ceafd61 100644 --- a/crates/ide/src/codemod_helpers.rs +++ b/crates/ide/src/codemod_helpers.rs @@ -573,8 +573,8 @@ pub(crate) fn find_call_in_function( }; if let Some(extra) = check_call(context) { // Got one. - let call_expr_id = if let Some((hir_idx, _macro_def)) = ctx.in_macro { - hir_idx.idx + let call_expr_id = if let Some(expr_id) = ctx.in_macro { + expr_id.idx } else { ctx.item_id }; diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index eb6bae611b..f9373e25b4 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -50,7 +50,6 @@ use elp_ide_db::text_edit::TextEdit; use elp_ide_ssr::Match; use elp_ide_ssr::SsrSearchScope; use elp_ide_ssr::match_pattern; -use elp_project_model::AppName; use elp_syntax::NodeOrToken; use elp_syntax::Parse; use elp_syntax::SourceFile; @@ -97,13 +96,13 @@ mod application_env; mod atoms_exhaustion; mod binary_string_to_sigil; mod boolean_precedence; -mod bound_variable; mod could_be_a_string_literal; mod cross_node_eval; mod debugging_function; mod dependent_header; mod deprecated_function; mod duplicate_module; +mod edoc; mod effect_free_statement; mod equality_check_with_unnecessary_operator; mod eqwalizer_assists; @@ -118,7 +117,7 @@ mod macro_precedence_suprise; mod map_find_to_syntax; mod map_insertion_to_syntax; mod meck; -// @fb-only: mod meta_only; +// @fb-only mod missing_compile_warn_missing_spec; mod missing_module; mod missing_separator; @@ -132,7 +131,6 @@ mod no_garbage_collect; mod no_nowarn_suppressions; mod no_size; mod nonstandard_integer_formatting; -mod old_edoc_syntax; mod record_tuple_match; mod redundant_assignment; mod replace_call; @@ -551,37 +549,12 @@ pub(crate) trait Linter { } } -fn should_process_app( - app_name: &Option, - config: &DiagnosticsConfig, - diagnostic_code: &DiagnosticCode, -) -> bool { - let app = match app_name { - Some(app) => app.to_string(), - None => return true, - }; - - if let Some(lint_config) = config.lint_config.as_ref() - && let Some(linter_config) = lint_config.linters.get(diagnostic_code) - && let Some(ref excluded) = linter_config.exclude_apps - && excluded.contains(&app) - { - return false; - } - - true -} - fn should_run( linter: &dyn Linter, config: &DiagnosticsConfig, - app_name: &Option, is_generated: bool, is_test: bool, ) -> bool { - if !should_process_app(app_name, config, &linter.id()) { - return false; - } let is_enabled = if let Some(lint_config) = config.lint_config.as_ref() { lint_config .get_is_enabled_override(&linter.id()) @@ -892,7 +865,6 @@ pub(crate) trait GenericLinter: Linter { fn fixes( &self, _context: &Self::Context, - _range: TextRange, _sema: &Semantic, _file_id: FileId, ) -> Option> { @@ -926,7 +898,7 @@ impl GenericDiagnostics for T { if let Some(matches) = self.matches(sema, file_id) { for matched in matches { let message = self.match_description(&matched.context); - let fixes = self.fixes(&matched.context, matched.range, sema, file_id); + let fixes = self.fixes(&matched.context, sema, file_id); let tag = self.tag(&matched.context); let mut d = Diagnostic::new(self.id(), message, matched.range) .with_fixes(fixes) @@ -1244,16 +1216,6 @@ impl LintConfig { self.linters.get(diagnostic_code)?.experimental } - /// Get the exclude_apps override for a linter based on its diagnostic code. - pub fn get_exclude_apps_override( - &self, - diagnostic_code: &DiagnosticCode, - ) -> Option> { - self.linters - .get(diagnostic_code) - .and_then(|c| c.exclude_apps.clone()) - } - pub fn get_function_call_linter_config( &self, diagnostic_code: &DiagnosticCode, @@ -1377,7 +1339,6 @@ pub struct LinterConfig { pub include_tests: Option, pub include_generated: Option, pub experimental: Option, - pub exclude_apps: Option>, #[serde(flatten)] pub config: Option, } @@ -1398,7 +1359,6 @@ impl LinterConfig { include_tests: other.include_tests.or(self.include_tests), include_generated: other.include_generated.or(self.include_generated), experimental: other.experimental.or(self.experimental), - exclude_apps: other.exclude_apps.or(self.exclude_apps), config: merged_config, } } @@ -1564,7 +1524,7 @@ pub fn native_diagnostics( config .lints_from_config .get_diagnostics(&mut res, &sema, file_id); - // @fb-only: meta_only::diagnostics(&mut res, &sema, file_id, file_kind, config); + // @fb-only syntax_diagnostics(&sema, &parse, &mut res, file_id); diagnostics_from_descriptors( &mut res, @@ -1593,7 +1553,6 @@ pub fn native_diagnostics( } else { FxHashMap::default() }; - let app_name = db.file_app_name(file_id); let metadata = db.elp_metadata(file_id); // TODO: can we ever disable DiagnosticCode::SyntaxError? // In which case we must check labeled_syntax_errors @@ -1602,7 +1561,6 @@ pub fn native_diagnostics( && (config.experimental && d.has_category(Category::Experimental) || !d.has_category(Category::Experimental)) && !d.should_be_suppressed(&metadata, config) - && should_process_app(&app_name, config, &d.code) }); LabeledDiagnostics { @@ -1653,20 +1611,20 @@ pub fn diagnostics_from_descriptors( .db .is_test_suite_or_test_helper(file_id) .unwrap_or(false); - let app_name = sema.db.file_app_name(file_id); descriptors.iter().for_each(|descriptor| { if descriptor.conditions.enabled(config, is_generated, is_test) { - let mut diags: Vec = Vec::default(); - (descriptor.checker)(&mut diags, sema, file_id, file_kind); - for diag in diags { - // Check if this diagnostic is enabled (for default_disabled descriptors) - // and if the app is not excluded for this diagnostic code - let is_enabled = - !descriptor.conditions.default_disabled || config.enabled.contains(&diag.code); - let app_allowed = should_process_app(&app_name, config, &diag.code); - if is_enabled && app_allowed { - res.push(diag); + if descriptor.conditions.default_disabled { + // Filter the returned diagnostics to ensure they are + // enabled + let mut diags: Vec = Vec::default(); + (descriptor.checker)(&mut diags, sema, file_id, file_kind); + for diag in diags { + if config.enabled.contains(&diag.code) { + res.push(diag); + } } + } else { + (descriptor.checker)(res, sema, file_id, file_kind); } } }); @@ -1723,12 +1681,11 @@ const GENERIC_LINTERS: &[&dyn GenericDiagnostics] = &[ &duplicate_module::LINTER, &no_nowarn_suppressions::LINTER, ¯o_precedence_suprise::LINTER, - &old_edoc_syntax::LINTER, + &edoc::LINTER, &missing_module::LINTER, &unused_include::LINTER, &misspelled_attribute::LINTER, &boolean_precedence::LINTER, - &bound_variable::LINTER, ]; /// Unified registry for all types of linters @@ -1757,7 +1714,7 @@ pub(crate) fn linters() -> Vec { ); // Add meta-only linters - // @fb-only: all_linters.extend(meta_only::linters()); + // @fb-only all_linters } @@ -1774,12 +1731,11 @@ fn diagnostics_from_linters( .db .is_test_suite_or_test_helper(file_id) .unwrap_or(false); - let app_name = sema.db.file_app_name(file_id); for l in linters { let linter = l.as_linter(); if linter.should_process_file_id(sema, file_id) - && should_run(linter, config, &app_name, is_generated, is_test) + && should_run(linter, config, is_generated, is_test) { let severity = if let Some(lint_config) = config.lint_config.as_ref() { lint_config @@ -2341,14 +2297,11 @@ pub fn erlang_service_diagnostics( diags }; - let app_name = db.file_app_name(file_id); let metadata = db.elp_metadata(file_id); let diags = diags .into_iter() .filter(|(_file_id, d)| { - !d.should_be_suppressed(&metadata, config) - && !config.disabled.contains(&d.code) - && should_process_app(&app_name, config, &d.code) + !d.should_be_suppressed(&metadata, config) && !config.disabled.contains(&d.code) }) .map(|(file_id, d)| { ( @@ -2639,7 +2592,7 @@ pub fn ct_diagnostics( CommonTestInfo::Result { all, groups } => { let testcases = common_test::runnable_names(&sema, file_id, all, groups).ok(); common_test::unreachable_test(&mut res, &sema, file_id, &testcases); - // @fb-only: meta_only::ct_diagnostics(&mut res, &sema, file_id, testcases); + // @fb-only } CommonTestInfo::EvalError(_error) => { // The error currently does not contain anything useful, so we ignore it @@ -3236,7 +3189,6 @@ mod tests { fn syntax_error() { check_diagnostics( r#" -//- expect_parse_errors -module(main). foo() -> XX 3.0. %% ^^ error: P1711: Syntax Error @@ -3414,7 +3366,6 @@ main(X) -> #[test] fn label_syntax_error_not_function() { let fixture_str = r#" - //- expect_parse_errors -module(main). -record(person, {(name + XXX)}). %% ^^^^^^^ error: P1711: Syntax Error @@ -3430,7 +3381,7 @@ main(X) -> expect![[r#" Some( Range( - 5..45, + 24..56, ), ) "#]] @@ -3589,7 +3540,6 @@ main(X) -> config, &extra_diags, r#" - //- expect_parse_errors -module(main). -export([foo/0,bar/0]). @@ -3610,7 +3560,7 @@ main(X) -> #[test] fn group_related_diagnostics_elp_only() { // Demonstrate that ELP does not pick up a syntax error in the - // spec, same code as in test/test_projects/diagnostics/app_a/src/syntax.erl + // spec, same code as in test_projects/diagnostics/app_a/src/syntax.erl check_diagnostics( r#" -module(main). @@ -3627,7 +3577,6 @@ main(X) -> check_diagnostics( r#" //- erlang_service - //- expect_parse_errors //- /src/a_mod.erl app:app_a -module(a_mod). -export([foo/0]). @@ -3646,7 +3595,6 @@ main(X) -> check_diagnostics( r#" //- erlang_service - //- expect_parse_errors //- native //- /src/a_mod.erl app:app_a -module(a_mod). @@ -3725,7 +3673,6 @@ main(X) -> fn test_nested_syntax_errors() { check_diagnostics( r#" - //- expect_parse_errors -module(main). run() -> ExitCode = @@ -4039,7 +3986,6 @@ main(X) -> include_tests: None, include_generated: None, experimental: None, - exclude_apps: None, config: None, }, ); @@ -4082,7 +4028,6 @@ main(X) -> include_tests: Some(true), include_generated: None, experimental: None, - exclude_apps: None, config: None, }, ); @@ -4124,7 +4069,6 @@ main(X) -> include_tests: None, include_generated: Some(true), experimental: None, - exclude_apps: None, config: None, }, ); @@ -4167,7 +4111,6 @@ main(X) -> include_tests: None, include_generated: None, experimental: Some(true), - exclude_apps: None, config: None, }, ); @@ -4212,7 +4155,6 @@ main(X) -> include_tests: None, include_generated: None, experimental: None, - exclude_apps: None, config: None, }, ); @@ -4243,47 +4185,6 @@ main(X) -> ); } - #[test] - fn test_linter_exclude_apps_override() { - let mut lint_config = LintConfig::default(); - lint_config.linters.insert( - DiagnosticCode::NoGarbageCollect, - LinterConfig { - is_enabled: Some(false), - severity: None, - include_tests: None, - include_generated: None, - experimental: None, - exclude_apps: Some(vec!["my_app".to_string()]), - config: None, - }, - ); - - let config = DiagnosticsConfig::default() - .configure_diagnostics( - &lint_config, - &Some("no_garbage_collect".to_string()), - &None, - FallBackToAll::No, - ) - .unwrap(); - check_diagnostics_with_config( - config, - r#" - //- /src/main.erl app:my_app - -module(main). - -export([warning/0]). - - warning() -> - erlang:garbage_collect(). - //- /opt/lib/stdlib-3.17/src/erlang.erl otp_app:/opt/lib/stdlib-3.17 - -module(erlang). - -export([garbage_collect/0]). - garbage_collect() -> ok. - "#, - ); - } - #[test] fn no_unused_macro_in_macro_rhs_for_function_name() { let config = DiagnosticsConfig::default() @@ -4331,7 +4232,6 @@ main(X) -> include_tests: None, include_generated: None, experimental: None, - exclude_apps: None, config: Some(LinterTraitConfig::FunctionCallLinterConfig( FunctionCallLinterConfig { include: Some(vec![FunctionMatch::mf("mod_a", "func_a")]), @@ -4364,7 +4264,6 @@ main(X) -> include_tests: Some(true), include_generated: None, experimental: None, - exclude_apps: None, config: Some(LinterTraitConfig::FunctionCallLinterConfig( FunctionCallLinterConfig { include: Some(vec![FunctionMatch::mf("mod_b", "func_b")]), @@ -4382,7 +4281,6 @@ main(X) -> include_tests: None, include_generated: Some(true), experimental: None, - exclude_apps: None, config: None, }, ); diff --git a/crates/ide/src/diagnostics/application_env.rs b/crates/ide/src/diagnostics/application_env.rs index 615b7801f9..1e4fe7c4cf 100644 --- a/crates/ide/src/diagnostics/application_env.rs +++ b/crates/ide/src/diagnostics/application_env.rs @@ -28,7 +28,7 @@ use crate::codemod_helpers::CheckCallCtx; use crate::codemod_helpers::FunctionMatch; use crate::codemod_helpers::MatchCtx; use crate::codemod_helpers::find_call_in_function; -// @fb-only: use crate::diagnostics; +// @fb-only use crate::diagnostics::DiagnosticCode; use crate::diagnostics::Severity; @@ -36,7 +36,7 @@ pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { conditions: DiagnosticConditions { experimental: false, include_generated: true, - include_tests: false, + include_tests: true, default_disabled: false, }, checker: &|diags, sema, file_id, _ext| { @@ -108,7 +108,7 @@ fn check_function(diags: &mut Vec, sema: &Semantic, def: &FunctionDe vec![2, 3], BadEnvCallAction::AppArg(0), ), - // @fb-only: diagnostics::meta_only::application_env_bad_matches(), + // @fb-only ] .into_iter() .flatten() diff --git a/crates/ide/src/diagnostics/atoms_exhaustion.rs b/crates/ide/src/diagnostics/atoms_exhaustion.rs index 56a43a50ca..4708e35b1f 100644 --- a/crates/ide/src/diagnostics/atoms_exhaustion.rs +++ b/crates/ide/src/diagnostics/atoms_exhaustion.rs @@ -13,7 +13,7 @@ use hir::Semantic; use crate::FunctionMatch; use crate::codemod_helpers::CheckCallCtx; -// @fb-only: use crate::diagnostics; +// @fb-only use crate::diagnostics::DiagnosticCode; use crate::diagnostics::FunctionCallLinter; use crate::diagnostics::Linter; @@ -35,9 +35,9 @@ impl Linter for AtomsExhaustionLinter { false } #[rustfmt::skip] - // @fb-only: fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { + // @fb-only fn should_process_file_id(&self, _sema: &Semantic, _file_id: FileId) -> bool { // @oss-only - // @fb-only: diagnostics::meta_only::is_relevant_file(sema.db.upcast(), file_id) + // @fb-only true // @oss-only } } @@ -56,16 +56,16 @@ impl FunctionCallLinter for AtomsExhaustionLinter { // FunctionMatch::mfa("erlang", "binary_to_term", 2), ] .into_iter() - // @fb-only: .chain(diagnostics::meta_only::atoms_exhaustion_matches().into_iter()) + // @fb-only .collect::>() ] } fn check_match(&self, context: &CheckCallCtx<'_, ()>) -> Option { #[rustfmt::skip] - // @fb-only: let sema = context.in_clause.sema; - // @fb-only: let is_safe = - // @fb-only: diagnostics::meta_only::atoms_exhaustion_is_safe(sema, context.in_clause, context.parents); + // @fb-only + // @fb-only + // @fb-only let is_safe = false; // @oss-only if !is_safe { match context.args.as_slice() { diff --git a/crates/ide/src/diagnostics/boolean_precedence.rs b/crates/ide/src/diagnostics/boolean_precedence.rs index f8f7851f8a..21e374a4f5 100644 --- a/crates/ide/src/diagnostics/boolean_precedence.rs +++ b/crates/ide/src/diagnostics/boolean_precedence.rs @@ -66,6 +66,7 @@ impl Linter for BooleanPrecedenceLinter { #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct Context { + range: TextRange, preceding_ws_range: TextRange, op: Op, lhs_complex: bool, @@ -100,7 +101,6 @@ impl GenericLinter for BooleanPrecedenceLinter { fn fixes( &self, context: &Self::Context, - range: TextRange, _sema: &Semantic, file_id: FileId, ) -> Option> { @@ -109,36 +109,36 @@ impl GenericLinter for BooleanPrecedenceLinter { // Add "replace with preferred operator" fix let assist_message = format!("Replace '{}' with '{}'", context.op, context.op.preferred()); let edit = TextEdit::replace( - context.op.range(range, context.preceding_ws_range), + context.op.range(context.range, context.preceding_ws_range), context.op.preferred().to_string(), ); fixes.push(fix( "replace_boolean_operator", &assist_message, SourceChange::from_text_edit(file_id, edit), - range, + context.range, )); // Add "add parens" fixes if applicable if context.lhs_complex { - fixes.push(parens_fix("LHS", file_id, context, range)); + fixes.push(parens_fix("LHS", file_id, context)); } if context.rhs_complex { - fixes.push(parens_fix("RHS", file_id, context, range)); + fixes.push(parens_fix("RHS", file_id, context)); } Some(fixes) } } -fn parens_fix(side: &str, file_id: FileId, context: &Context, range: TextRange) -> Assist { +fn parens_fix(side: &str, file_id: FileId, context: &Context) -> Assist { let assist_message = format!("Add parens to {side}"); let edit = add_parens_edit(&context.add_parens_range); fix( "replace_boolean_operator_add_parens", &assist_message, SourceChange::from_text_edit(file_id, edit), - range, + context.range, ) } @@ -231,6 +231,7 @@ fn collect_match( matches.push(GenericLinterMatchContext { range, context: Context { + range, preceding_ws_range, op: binop, lhs_complex, diff --git a/crates/ide/src/diagnostics/bound_variable.rs b/crates/ide/src/diagnostics/bound_variable.rs deleted file mode 100644 index 92f0edadfa..0000000000 --- a/crates/ide/src/diagnostics/bound_variable.rs +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is dual-licensed under either the MIT license found in the - * LICENSE-MIT file in the root directory of this source tree or the Apache - * License, Version 2.0 found in the LICENSE-APACHE file in the root directory - * of this source tree. You may select, at your option, one of the - * above-listed licenses. - */ - -// Diagnostic: bound_variable -// -// Return a warning if the LHS of a match already contains a bound variable. -// - -use elp_ide_db::elp_base_db::FileId; -use hir::AnyExpr; -use hir::Expr; -use hir::Semantic; -use hir::Strategy; -use hir::fold::MacroStrategy; -use hir::fold::ParenStrategy; - -use crate::diagnostics::DiagnosticCode; -use crate::diagnostics::GenericLinter; -use crate::diagnostics::GenericLinterMatchContext; -use crate::diagnostics::Linter; - -pub(crate) struct BoundVariableLinter; - -impl Linter for BoundVariableLinter { - fn id(&self) -> DiagnosticCode { - DiagnosticCode::BoundVarInLhs - } - - fn description(&self) -> &'static str { - "Match on a bound variable" - } -} - -impl GenericLinter for BoundVariableLinter { - type Context = (); - - fn matches( - &self, - sema: &Semantic, - file_id: FileId, - ) -> Option>> { - let bound_vars_by_function = sema.bound_vars_by_function(file_id); - let mut res = Vec::new(); - sema.def_map(file_id) - .get_function_clauses() - .for_each(|(_, def)| { - if def.file.file_id == file_id - && let Some(bound_vars) = bound_vars_by_function.get(&def.function_clause_id) - { - let in_clause = def.in_clause(sema, def); - in_clause.fold_clause( - Strategy { - macros: MacroStrategy::ExpandButIncludeMacroCall, - parens: ParenStrategy::InvisibleParens, - }, - (), - &mut |acc, ctx| { - if let AnyExpr::Expr(Expr::Match { lhs, rhs: _ }) = ctx.item - && bound_vars.contains(&lhs) - && let Some(range) = in_clause.range_for_pat(lhs) - && range.file_id == def.file.file_id - && ctx.in_macro.is_none() - { - res.push(GenericLinterMatchContext { - range: range.range, - context: (), - }); - }; - acc - }, - ); - } - }); - - Some(res) - } -} - -pub static LINTER: BoundVariableLinter = BoundVariableLinter; - -#[cfg(test)] -mod test { - use elp_ide_db::DiagnosticCode; - use expect_test::Expect; - - use crate::diagnostics::DiagnosticsConfig; - use crate::tests::check_diagnostics_with_config; - use crate::tests::check_fix_with_config; - - #[track_caller] - pub(crate) fn check_diagnostics(fixture: &str) { - let config = DiagnosticsConfig::default().disable(DiagnosticCode::UndefinedFunction); - check_diagnostics_with_config(config, fixture) - } - - #[track_caller] - pub(crate) fn check_fix(fixture_before: &str, fixture_after: Expect) { - let config = DiagnosticsConfig::default().disable(DiagnosticCode::UndefinedFunction); - check_fix_with_config(config, fixture_before, fixture_after) - } - #[test] - fn bound_variable() { - check_diagnostics( - r#" - //- /src/bound.erl - -module(bound). - - foo() -> - AA = bar(), - AA = bar(). - %% ^^ 💡 warning: W0060: Match on a bound variable - - "#, - ) - } - - #[test] - fn bound_variable_not_reported_in_case() { - check_diagnostics( - r#" - //- /src/bound.erl - -module(bound). - - foo(Val) -> - case Val of - undefined -> ok; - Val when is_list(Val) -> ok - end. - - "#, - ) - } - - #[test] - fn bound_variable_not_reported_in_macro() { - check_diagnostics( - r#" - //- /src/bound.erl - -module(bound). - -include("inc.hrl"). - - foo(Val) -> - ?A_MACRO(Val). - //- /src/inc.hrl - -define(A_MACRO(X), X=X). - "#, - ) - } - - #[test] - fn bound_variable_ignore_fix() { - check_fix( - r#" - //- /src/bound.erl - -module(bound). - - foo() -> - AA = bar(), - A~A = bar(). - "#, - expect_test::expect![[r#" - -module(bound). - - foo() -> - AA = bar(), - % elp:ignore W0060 (bound_var_in_lhs) - AA = bar(). - "#]], - ) - } -} diff --git a/crates/ide/src/diagnostics/debugging_function.rs b/crates/ide/src/diagnostics/debugging_function.rs index 1f0099781d..94c3d11364 100644 --- a/crates/ide/src/diagnostics/debugging_function.rs +++ b/crates/ide/src/diagnostics/debugging_function.rs @@ -22,7 +22,7 @@ use crate::diagnostics::DiagnosticCode; use crate::diagnostics::FunctionCallLinter; use crate::diagnostics::Linter; use crate::diagnostics::Severity; -// @fb-only: use crate::diagnostics::meta_only; +// @fb-only use crate::lazy_function_matches; pub(crate) struct NoDebuggingFunctionLinter; @@ -52,7 +52,7 @@ impl FunctionCallLinter for NoDebuggingFunctionLinter { lazy_function_matches![ vec![FunctionMatch::m("redbug")] .into_iter() - // @fb-only: .chain(meta_only::debugging_function_matches().into_iter()) + // @fb-only .collect::>() ] } diff --git a/crates/ide/src/diagnostics/deprecated_function.rs b/crates/ide/src/diagnostics/deprecated_function.rs index b353d824d2..540edfcca3 100644 --- a/crates/ide/src/diagnostics/deprecated_function.rs +++ b/crates/ide/src/diagnostics/deprecated_function.rs @@ -41,7 +41,7 @@ use super::DiagnosticDescriptor; use super::Severity; use crate::codemod_helpers::FunctionMatch; use crate::codemod_helpers::FunctionMatcher; -// @fb-only: use crate::diagnostics; +// @fb-only use crate::fix; pub(crate) static DESCRIPTOR: DiagnosticDescriptor = DiagnosticDescriptor { @@ -88,7 +88,7 @@ fn deprecated_function(diagnostics: &mut Vec, sema: &Semantic, file_ lazy_static! { static ref DEPRECATED_FUNCTIONS: Vec<(FunctionMatch, DeprecationDetails)> = { let matches: Vec> = vec![ - // @fb-only: diagnostics::meta_only::deprecated_function_matches(), + // @fb-only ]; matches.into_iter() .flatten() @@ -134,8 +134,8 @@ fn check_function( ); let details = match_result.map(|(_match, details)| details.clone()); if target_def.deprecated || match_result.is_some() { - let expr_id = if let Some((hir_idx, _macro_def)) = ctx.in_macro { - hir_idx.idx + let expr_id = if let Some(expr_id) = ctx.in_macro { + expr_id.idx } else { ctx.item_id }; diff --git a/crates/ide/src/diagnostics/old_edoc_syntax.rs b/crates/ide/src/diagnostics/edoc.rs similarity index 97% rename from crates/ide/src/diagnostics/old_edoc_syntax.rs rename to crates/ide/src/diagnostics/edoc.rs index da4c3f2430..ead44d7331 100644 --- a/crates/ide/src/diagnostics/old_edoc_syntax.rs +++ b/crates/ide/src/diagnostics/edoc.rs @@ -8,7 +8,7 @@ * above-listed licenses. */ -// Diagnostic: old_edoc_syntax +// Diagnostic: edoc use elp_ide_assists::Assist; use elp_ide_assists::helpers; @@ -31,10 +31,11 @@ use super::DiagnosticCode; use super::GenericLinter; use super::GenericLinterMatchContext; use super::Linter; +use super::Severity; -pub(crate) struct OldEdocSyntaxLinter; +pub(crate) struct EdocLinter; -impl Linter for OldEdocSyntaxLinter { +impl Linter for EdocLinter { fn id(&self) -> DiagnosticCode { DiagnosticCode::OldEdocSyntax } @@ -43,8 +44,11 @@ impl Linter for OldEdocSyntaxLinter { "EDoc style comments are deprecated. Please use Markdown instead." } - fn should_process_test_files(&self) -> bool { - false + fn severity(&self, sema: &Semantic, file_id: FileId) -> Severity { + match sema.db.is_test_suite_or_test_helper(file_id) { + Some(true) => Severity::WeakWarning, + _ => Severity::Warning, + } } } @@ -52,9 +56,10 @@ impl Linter for OldEdocSyntaxLinter { pub struct Context { header_ptr: Option>, doc_start: TextSize, + range: TextRange, } -impl GenericLinter for OldEdocSyntaxLinter { +impl GenericLinter for EdocLinter { type Context = Context; fn matches( @@ -72,6 +77,7 @@ impl GenericLinter for OldEdocSyntaxLinter { context: Context { header_ptr: Some(*header_ptr), doc_start, + range: doc.range, }, }); } @@ -82,6 +88,7 @@ impl GenericLinter for OldEdocSyntaxLinter { context: Context { header_ptr: Some(*header_ptr), doc_start, + range: equiv.range, }, }); } @@ -92,6 +99,7 @@ impl GenericLinter for OldEdocSyntaxLinter { context: Context { header_ptr: Some(*header_ptr), doc_start, + range: deprecated.range, }, }); } @@ -103,6 +111,7 @@ impl GenericLinter for OldEdocSyntaxLinter { context: Context { header_ptr: Some(*header_ptr), doc_start, + range: hidden.range, }, }); } @@ -114,7 +123,6 @@ impl GenericLinter for OldEdocSyntaxLinter { fn fixes( &self, context: &Self::Context, - range: TextRange, sema: &Semantic, file_id: FileId, ) -> Option> { @@ -126,12 +134,12 @@ impl GenericLinter for OldEdocSyntaxLinter { file_id, header, context.doc_start, - range, + context.range, )]) } } -pub static LINTER: OldEdocSyntaxLinter = OldEdocSyntaxLinter; +pub static LINTER: EdocLinter = EdocLinter; fn old_edoc_syntax_fix( sema: &Semantic, @@ -294,6 +302,22 @@ mod tests { ) } + #[test] + fn test_function_doc_in_test_file() { + check_diagnostics( + r#" + //- /test/main_SUITE.erl extra:test + -module(main_SUITE). + %% @doc This is the main function documentation. + %% ^^^^ 💡 weak: W0038: EDoc style comments are deprecated. Please use Markdown instead. + main() -> + dep(). + + dep() -> ok. + "#, + ) + } + #[test] fn test_function_doc_different_arities() { check_diagnostics( diff --git a/crates/ide/src/diagnostics/macro_precedence_suprise.rs b/crates/ide/src/diagnostics/macro_precedence_suprise.rs index 6cd5fe2429..838ddb3d9c 100644 --- a/crates/ide/src/diagnostics/macro_precedence_suprise.rs +++ b/crates/ide/src/diagnostics/macro_precedence_suprise.rs @@ -35,7 +35,9 @@ use crate::diagnostics::Linter; use crate::fix; #[derive(Debug, Default, Clone, PartialEq)] -pub(crate) struct MacroPrecedenceContext; +pub(crate) struct MacroPrecedenceContext { + range: TextRange, +} pub(crate) struct MacroPrecedenceSupriseLinter; @@ -94,9 +96,10 @@ impl GenericLinter for MacroPrecedenceSupriseLinter { { let range = ast.range(); if range.file_id == file_id { + let context = MacroPrecedenceContext { range: range.range }; res.push(GenericLinterMatchContext { range: range.range, - context: MacroPrecedenceContext, + context, }); } } @@ -110,17 +113,16 @@ impl GenericLinter for MacroPrecedenceSupriseLinter { fn fixes( &self, - _context: &Self::Context, - range: TextRange, + context: &Self::Context, _sema: &Semantic, file_id: FileId, ) -> Option> { - let edit = add_parens_edit(&range); + let edit = add_parens_edit(&context.range); let fix = fix( "macro_precedence_add_parens", "Add parens to macro call", SourceChange::from_text_edit(file_id, edit), - range, + context.range, ); Some(vec![fix]) } diff --git a/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs b/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs index dd0b677dce..b1f24eb60f 100644 --- a/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs +++ b/crates/ide/src/diagnostics/missing_compile_warn_missing_spec.rs @@ -75,6 +75,7 @@ impl Linter for MissingCompileWarnMissingSpec { pub struct Context { found: Found, compile_option_id: Option, + target_range: TextRange, } impl GenericLinter for MissingCompileWarnMissingSpec { @@ -93,6 +94,7 @@ impl GenericLinter for MissingCompileWarnMissingSpec { context: Context { found: Found::No, compile_option_id: None, + target_range: DIAGNOSTIC_WHOLE_FILE_RANGE, }, }); } @@ -147,6 +149,7 @@ impl GenericLinter for MissingCompileWarnMissingSpec { context: Context { found: what.0, compile_option_id: what.1, + target_range: range, }, }); } @@ -157,7 +160,6 @@ impl GenericLinter for MissingCompileWarnMissingSpec { fn fixes( &self, context: &Self::Context, - range: TextRange, sema: &Semantic, file_id: FileId, ) -> Option> { @@ -182,7 +184,7 @@ impl GenericLinter for MissingCompileWarnMissingSpec { "add_warn_missing_spec_all", "Add compile option 'warn_missing_spec_all'", edit, - range, + context.target_range, )]) } } diff --git a/crates/ide/src/diagnostics/misspelled_attribute.rs b/crates/ide/src/diagnostics/misspelled_attribute.rs index 15ad1dd9d8..f328f57b20 100644 --- a/crates/ide/src/diagnostics/misspelled_attribute.rs +++ b/crates/ide/src/diagnostics/misspelled_attribute.rs @@ -55,6 +55,7 @@ impl Linter for MisspelledAttributeLinter { #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct Context { + range: TextRange, attr_name: String, suggested_rename: String, } @@ -87,6 +88,7 @@ impl GenericLinter for MisspelledAttributeLinter { res.push(GenericLinterMatchContext { range: attr_name_range, context: Context { + range: attr_name_range, attr_name: attr.name.to_string(), suggested_rename: suggested_rename.to_string(), }, @@ -108,17 +110,16 @@ impl GenericLinter for MisspelledAttributeLinter { fn fixes( &self, context: &Self::Context, - range: TextRange, _sema: &Semantic, file_id: FileId, ) -> Option> { - let edit = TextEdit::replace(range, context.suggested_rename.clone()); + let edit = TextEdit::replace(context.range, context.suggested_rename.clone()); let msg = format!("Change to '{}'", context.suggested_rename); Some(vec![fix( "fix_misspelled_attribute", &msg, SourceChange::from_text_edit(file_id, edit), - range, + context.range, )]) } } diff --git a/crates/ide/src/diagnostics/mutable_variable.rs b/crates/ide/src/diagnostics/mutable_variable.rs index 6878c90d57..52fe32eccf 100644 --- a/crates/ide/src/diagnostics/mutable_variable.rs +++ b/crates/ide/src/diagnostics/mutable_variable.rs @@ -27,8 +27,12 @@ // use elp_ide_db::elp_base_db::FileId; +use fxhash::FxHashMap; +use fxhash::FxHashSet; use hir::AnyExpr; use hir::Expr; +use hir::FunctionClauseId; +use hir::PatId; use hir::Semantic; use hir::Strategy; use hir::fold::MacroStrategy; @@ -56,7 +60,21 @@ fn mutable_variable_bug( sema: &Semantic, file_id: FileId, ) -> Option<()> { - let bound_vars_by_function = sema.bound_vars_by_function(file_id); + let mut bound_vars_by_function: FxHashMap> = + FxHashMap::default(); + let bound_vars = sema.bound_vars_in_pattern_diagnostic(file_id); + bound_vars.iter().for_each(|(function_id, pat_id, _var)| { + bound_vars_by_function + .entry(function_id.value) + .and_modify(|vars| { + vars.insert(pat_id); + }) + .or_insert_with(|| { + let mut vars = FxHashSet::default(); + vars.insert(pat_id); + vars + }); + }); sema.def_map(file_id) .get_function_clauses() .for_each(|(_, def)| { diff --git a/crates/ide/src/diagnostics/no_error_logger.rs b/crates/ide/src/diagnostics/no_error_logger.rs index 46f3d15e3e..d587d3f3c7 100644 --- a/crates/ide/src/diagnostics/no_error_logger.rs +++ b/crates/ide/src/diagnostics/no_error_logger.rs @@ -29,9 +29,6 @@ impl Linter for NoErrorLoggerLinter { fn severity(&self, _sema: &Semantic, _file_id: FileId) -> Severity { Severity::Error } - fn should_process_test_files(&self) -> bool { - false - } } impl FunctionCallLinter for NoErrorLoggerLinter { diff --git a/crates/ide/src/diagnostics/undefined_function.rs b/crates/ide/src/diagnostics/undefined_function.rs index 52fa2cfa3c..189edf06f5 100644 --- a/crates/ide/src/diagnostics/undefined_function.rs +++ b/crates/ide/src/diagnostics/undefined_function.rs @@ -43,13 +43,6 @@ impl Linter for UndefinedFunctionLinter { fn should_process_generated_files(&self) -> bool { true } - // Ideally, we would like to report undefined functions in all files, but - // there are too many false positives in test files to do so. - // This is often due to mocked modules and test suite cleverness. - // We can revisit this decision in the future. See T249044930. - fn should_process_test_files(&self) -> bool { - false - } } impl FunctionCallLinter for UndefinedFunctionLinter { diff --git a/crates/ide/src/diagnostics/undocumented_module.rs b/crates/ide/src/diagnostics/undocumented_module.rs index 1b2c80cfc9..eeb4caf7b1 100644 --- a/crates/ide/src/diagnostics/undocumented_module.rs +++ b/crates/ide/src/diagnostics/undocumented_module.rs @@ -48,7 +48,9 @@ impl Linter for UndocumentedModuleLinter { } #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Context; +pub struct Context { + module_name_range: TextRange, +} impl GenericLinter for UndocumentedModuleLinter { type Context = Context; @@ -69,21 +71,16 @@ impl GenericLinter for UndocumentedModuleLinter { if module_has_no_docs { let module_name = module_attribute.name()?; let module_name_range = module_name.syntax().text_range(); + let context = Context { module_name_range }; res.push(GenericLinterMatchContext { range: module_name_range, - context: Context, + context, }); } Some(res) } - fn fixes( - &self, - _context: &Context, - range: TextRange, - sema: &Semantic, - file_id: FileId, - ) -> Option> { + fn fixes(&self, context: &Context, sema: &Semantic, file_id: FileId) -> Option> { let insert_offset = helpers::moduledoc_insert_offset(sema, file_id)?; let mut builder = SourceChangeBuilder::new(file_id); builder.insert(insert_offset, "-moduledoc false.\n"); @@ -92,7 +89,7 @@ impl GenericLinter for UndocumentedModuleLinter { "add_moduledoc_false", "Add `-moduledoc false.` attribute", source_change, - range, + context.module_name_range, ); Some(vec![fix]) } diff --git a/crates/ide/src/diagnostics/unexported_function.rs b/crates/ide/src/diagnostics/unexported_function.rs index 2e1ebf7f54..7aae73a9f1 100644 --- a/crates/ide/src/diagnostics/unexported_function.rs +++ b/crates/ide/src/diagnostics/unexported_function.rs @@ -27,7 +27,7 @@ use crate::codemod_helpers::CheckCallCtx; use crate::codemod_helpers::MatchCtx; use crate::diagnostics::FunctionCallLinter; use crate::diagnostics::Linter; -// @fb-only: use crate::diagnostics::meta_only; +// @fb-only use crate::fix; use crate::lazy_function_matches; @@ -45,9 +45,9 @@ impl Linter for UnexportedFunctionLinter { } #[rustfmt::skip] fn should_process_file_id(&self, _sema: &Semantic, _file_id: FileId) -> bool { // @oss-only - // @fb-only: fn should_process_file_id(&self, sema: &Semantic, file_id: FileId) -> bool { + // @fb-only true // @oss-only - // @fb-only: meta_only::should_check_for_unexported(sema, file_id) + // @fb-only } } diff --git a/crates/ide/src/diagnostics/unspecific_include.rs b/crates/ide/src/diagnostics/unspecific_include.rs index 431740c085..f7405c798a 100644 --- a/crates/ide/src/diagnostics/unspecific_include.rs +++ b/crates/ide/src/diagnostics/unspecific_include.rs @@ -152,7 +152,7 @@ fn replace_include_path( #[cfg(test)] mod tests { use elp_ide_db::DiagnosticCode; - // @fb-only: use elp_ide_db::meta_only::MetaOnlyDiagnosticCode; + // @fb-only use expect_test::Expect; use expect_test::expect; @@ -173,7 +173,7 @@ mod tests { #[track_caller] fn check_fix(fixture_before: &str, fixture_after: Expect) { let config = DiagnosticsConfig::default() - // @fb-only: .disable(DiagnosticCode::MetaOnly(MetaOnlyDiagnosticCode::MalformedInclude)) + // @fb-only .disable(DiagnosticCode::UnusedInclude); tests::check_fix_with_config(config, fixture_before, fixture_after) } diff --git a/crates/ide/src/diagnostics/unused_include.rs b/crates/ide/src/diagnostics/unused_include.rs index eb26bcd923..eed17b3c5c 100644 --- a/crates/ide/src/diagnostics/unused_include.rs +++ b/crates/ide/src/diagnostics/unused_include.rs @@ -137,7 +137,6 @@ impl GenericLinter for UnusedIncludeLinter { fn fixes( &self, context: &Self::Context, - _range: TextRange, _sema: &Semantic, file_id: FileId, ) -> Option> { diff --git a/crates/ide/src/diagnostics/unused_macro.rs b/crates/ide/src/diagnostics/unused_macro.rs index 6ea8756b91..089371f85b 100644 --- a/crates/ide/src/diagnostics/unused_macro.rs +++ b/crates/ide/src/diagnostics/unused_macro.rs @@ -88,13 +88,7 @@ impl GenericLinter for UnusedMacroLinter { Some(DiagnosticTag::Unused) } - fn fixes( - &self, - context: &Context, - _range: TextRange, - _sema: &Semantic, - file_id: FileId, - ) -> Option> { + fn fixes(&self, context: &Context, _sema: &Semantic, file_id: FileId) -> Option> { Some(vec![delete_unused_macro( file_id, context.delete_range, diff --git a/crates/ide/src/diagnostics_collection.rs b/crates/ide/src/diagnostics_collection.rs index fe1fc759aa..4abe143dd9 100644 --- a/crates/ide/src/diagnostics_collection.rs +++ b/crates/ide/src/diagnostics_collection.rs @@ -415,7 +415,6 @@ mod tests { config, &extra_diags, r#" - //- expect_parse_errors -module(main). -export([foo/0,bar/0]). diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 6a85ab3dc3..d13befe8bb 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -15,9 +15,9 @@ use elp_syntax::AstNode; use hir::InFile; use hir::Semantic; -// @fb-only: use crate::meta_only::exdoc_links; +// @fb-only -// @fb-only: mod meta_only; +// @fb-only mod otp_links; #[derive(Debug, Clone, PartialEq, Eq)] @@ -40,10 +40,10 @@ pub(crate) fn external_docs(db: &RootDatabase, position: &FilePosition) -> Optio if let Some(class) = SymbolClass::classify(&sema, in_file_token.clone()) { class.iter().for_each(|def| { otp_links::links(&mut doc_links, &sema, &def); - // @fb-only: exdoc_links::links(&mut doc_links, &sema, &def); + // @fb-only }); } - // @fb-only: meta_only::links(&mut doc_links, node, position); + // @fb-only Some(doc_links) } diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index a5a6f759fc..95735a904d 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -83,7 +83,7 @@ mod tests { check( r#" -module(foo). -bar() -> ?L~INE. +-bar() -> ?L~INE. "#, expect![[r#" LINE @@ -97,7 +97,7 @@ bar() -> ?L~INE. check( r#" -module(foo). -bar() -> ?F~ILE. +-bar() -> ?F~ILE. "#, expect![[r#" FILE @@ -420,7 +420,7 @@ baz() -> maps:get(type, ExpectedQr, missing_expected_type); _ -> Type - end + end, ). baz() -> ?asser~tQrs(AliceWID, ?WA_QR_TYPE_MESSAGE, []), diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index 88a95e86d7..cf16198dfe 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -259,7 +259,6 @@ main() -> fn param_hints_variables_missing_param() { check_params( r#" -//- expect_parse_errors -module(main).~ -compile(export_all). sum(A, B) -> A + B. diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index ad5c1bb680..dcaff6de70 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -110,7 +110,7 @@ pub mod diagnostics; pub mod diagnostics_collection; pub mod diff; mod highlight_related; -// @fb-only: pub mod meta_only; +// @fb-only pub use annotations::Annotation; pub use annotations::AnnotationKind; @@ -251,9 +251,9 @@ impl Analysis { }) } - pub fn should_eqwalize(&self, file_id: FileId) -> Cancellable { + pub fn should_eqwalize(&self, file_id: FileId, include_tests: bool) -> Cancellable { let is_in_app = self.file_app_type(file_id).ok() == Some(Some(AppType::App)); - Ok(is_in_app && self.is_eqwalizer_enabled(file_id)?) + Ok(is_in_app && self.is_eqwalizer_enabled(file_id, include_tests)?) } /// Computes the set of eqwalizer diagnostics for the given files, @@ -383,8 +383,8 @@ impl Analysis { /// - the app (the module belongs to) has `.eqwalizer` marker in the roof /// - or the module has `-typing([eqwalizer]).` pragma /// - or the whole project has `enable_all=true` in its `.elp.toml` file - pub fn is_eqwalizer_enabled(&self, file_id: FileId) -> Cancellable { - self.with_db(|db| db.is_eqwalizer_enabled(file_id)) + pub fn is_eqwalizer_enabled(&self, file_id: FileId, include_tests: bool) -> Cancellable { + self.with_db(|db| db.is_eqwalizer_enabled(file_id, include_tests)) } /// ETF for the module's abstract forms diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index ee5bfb7219..0cedbe1d90 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -194,53 +194,35 @@ pub fn rename_var( #[cfg(test)] pub(crate) mod tests { - use elp_ide_db::RootDatabase; - use elp_ide_db::elp_base_db::AnchoredPathBuf; - use elp_ide_db::elp_base_db::FileId; - use elp_ide_db::elp_base_db::VfsPath; use elp_ide_db::elp_base_db::assert_eq_text; - use elp_ide_db::elp_base_db::fixture::ChangeFixture; use elp_ide_db::elp_base_db::fixture::WithFixture as _; - use elp_ide_db::source_change::FileSystemEdit; use elp_ide_db::text_edit::TextEdit; use elp_project_model::test_fixture::trim_indent; use elp_syntax::AstNode; use elp_syntax::algo; use elp_syntax::ast; - use fxhash::FxHashSet; use hir::AnyExprId; use hir::InFile; use hir::Semantic; use super::rename_var; - use crate::AnalysisHost; use crate::fixture; #[track_caller] pub(crate) fn check_rename(new_name: &str, fixture_before: &str, fixture_after_str: &str) { let fixture_after_str = &trim_indent(fixture_after_str); + let analysis_after = fixture::multi_file(fixture_after_str); - let (db_before, fixture) = RootDatabase::with_fixture(fixture_before); - let host_before = AnalysisHost { db: db_before }; - let analysis = host_before.analysis(); - let position = fixture.position(); - - let (db_after, fixture_after) = RootDatabase::with_fixture(fixture_after_str); - let host_after = AnalysisHost { db: db_after }; - let analysis_after = host_after.analysis(); - + let (analysis, position, _) = fixture::position(fixture_before); let rename_result = analysis .rename(position, new_name) .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}")); match rename_result { Ok(source_change) => { - let mut file_ids: FxHashSet = FxHashSet::default(); for edit in source_change.source_file_edits { let mut text_edit_builder = TextEdit::builder(); let file_id = edit.0; - // New and old file_id are the same - file_ids.insert(file_id); for indel in edit.1.into_iter() { text_edit_builder.replace(indel.delete, indel.insert); } @@ -250,82 +232,6 @@ pub(crate) mod tests { let expected = analysis_after.file_text(file_id).unwrap().to_string(); assert_eq_text!(&*expected, &*result); } - for op in source_change.file_system_edits { - let expected; - let new_file_id; - match op { - FileSystemEdit::CreateFile { - dst, - initial_contents, - } => { - let new_file = - find_new_file_id(&fixture_after, &dst).unwrap_or_else(|| { - panic!( - "Fixture after:could not find file created as '{}'", - &dst.path - ) - }); - new_file_id = *new_file.1; - expected = initial_contents; - let actual = analysis_after.file_text(new_file_id).unwrap().to_string(); - assert_eq_text!(&*expected, &*actual); - } - FileSystemEdit::MoveFile { src: _, dst } => { - let new_file = - find_new_file_id(&fixture_after, &dst).unwrap_or_else(|| { - panic!( - "Fixture after:could not find file renamed to '{}'", - &dst.path - ) - }); - new_file_id = *new_file.1; - // We simply record the new file id for checking in `fixture_after``. - // The expected value will be updated by the new_file_edits below, - // and the result asserted there - } - } - file_ids.insert(new_file_id); - } - for (dst, op) in source_change.new_file_edits { - // When renaming a module, we move the original file, then apply fixup edits - // to the new file - let anchored_dst = AnchoredPathBuf { - anchor: dst.anchor, - path: dst.path, - }; - let new_file = - find_new_file_id(&fixture_after, &anchored_dst).unwrap_or_else(|| { - panic!( - "Fixture after:could not find file created as '{}'", - &anchored_dst.path - ) - }); - - let mut text_edit_builder = TextEdit::builder(); - let file_id = *new_file.1; - // New and old file_id are the same - file_ids.insert(file_id); - for indel in op.iter() { - text_edit_builder.replace(indel.delete, indel.insert.to_string()); - } - let mut result = analysis.file_text(file_id).unwrap().to_string(); - let edit = text_edit_builder.finish(); - edit.apply(&mut result); - let expected = analysis_after.file_text(file_id).unwrap().to_string(); - assert_eq_text!(&*expected, &*result); - } - // Check the balance of the expectations in the new fixture. - for file_id in &fixture_after.files { - if !file_ids.contains(file_id) { - let actual = analysis_after.file_text(*file_id).unwrap().to_string(); - let expected = if fixture.files.contains(file_id) { - analysis.file_text(*file_id).unwrap().to_string() - } else { - format!("File {:?} not present in original fixture", file_id) - }; - assert_eq_text!(&*expected, &*actual); - } - } } Err(err) => { if fixture_after_str.starts_with("error:") { @@ -341,16 +247,6 @@ pub(crate) mod tests { }; } - fn find_new_file_id<'a>( - fixture: &'a ChangeFixture, - dst: &'a AnchoredPathBuf, - ) -> Option<(&'a VfsPath, &'a FileId)> { - fixture - .files_by_path - .iter() - .find(|(name, _)| name.as_path().unwrap().to_string().ends_with(&dst.path)) - } - #[test] fn test_rename_var_1() { check_rename("Y", r#"main() -> I~ = 1."#, r#"main() -> Y = 1."#); @@ -1239,326 +1135,6 @@ pub(crate) mod tests { ); } - // --------------------------------- - // Renaming modules - - #[test] - fn rename_module_fails_name_exists() { - check_rename( - "main_2", - r#" - //- /app_a/src/main.erl - -module(ma~in). - //- /app_a_/src/main_2.erl - -module(main_2). - "#, - r#"error: module 'main_2' already exists"#, - ); - } - - #[test] - fn rename_module_fails_bad_name_1() { - check_rename( - "Main", - r#" - //- /app_a/src/main.erl - -module(ma~in). - //- /app_a_/src/main_2.erl - -module(main_2). - "#, - r#"error: Invalid new module name: 'Main'"#, - ); - } - - #[test] - fn rename_module_simple() { - check_rename( - "main_2", - r#" - //- /app_a/src/main.erl - -module(ma~in). - "#, - r#" - //- /app_a/src/main_2.erl - -module(main_2). - "#, - ); - } - - #[test] - fn rename_module_fails_dup_name() { - check_rename( - "main_2", - r#" - //- /app_a/src/main_2.erl - -module(main_2). - -export([foo/0]). - foo() -> ok. - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/0]). - foo() -> ok. - bar() -> main:foo(). - baz() -> main:bar(). - - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - bar() -> main:foo(). - "#, - r#"error: module 'main_2' already exists"#, - ); - } - - #[test] - fn rename_module_with_usage_internal() { - check_rename( - "main_2", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/0]). - foo() -> ok. - bar() -> main:foo(). - baz() -> main:bar(). - - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - bar() -> main:foo(). - "#, - //------------------ - r#" - //- /app_a/src/main_2.erl - -module(main_2). - -export([foo/0]). - foo() -> ok. - bar() -> main_2:foo(). - baz() -> main_2:bar(). - - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - bar() -> main_2:foo(). - "#, - ); - } - #[test] - fn rename_module_with_usage_type() { - // TODO: check for compile errors in the fixture - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main:foo(). - bar() -> ok. - "#, - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main_3:foo(). - bar() -> ok. - "#, - ); - } - - #[test] - fn rename_module_with_usage_record() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main:foo(). - bar() -> ok. - -record(main, {field :: main:foo()}). - "#, - //------------------ - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main_3:foo(). - bar() -> ok. - -record(main, {field :: main_3:foo()}). - "#, - ); - } - - #[test] - fn rename_module_with_usage_fun_arg() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main:foo(). - bar() -> - meck:new(main, [passthrough]), - meck:new([other, main] , [passthrough]), - meck:unload(main), - apply(main, foo, []), - ok. - -record(main, {field :: main:foo()}). - "#, - //------------------ - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export_type([foo/0]). - -type foo() :: ok. - //- /app_a/src/other.erl - -module(other). - -export([bar/0]). - -spec bar() -> main_3:foo(). - bar() -> - meck:new(main_3, [passthrough]), - meck:new([other, main_3] , [passthrough]), - meck:unload(main_3), - apply(main_3, foo, []), - ok. - -record(main, {field :: main_3:foo()}). - "#, - ); - } - - #[test] - fn rename_module_with_usage_fun() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/1]). - foo(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main:foo/1, [U], []} || U <- UStrings], - ok. - "#, - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export([foo/1]). - foo(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main_3:foo/1, [U], []} || U <- UStrings], - ok. - "#, - ); - } - - #[test] - fn rename_module_with_usage_fun_as_module() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([main/1]). - main(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main:main/1, [U], []} || U <- UStrings], - ok. - "#, - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export([main/1]). - main(X) -> {X}. - //- /app_a/src/other.erl - -module(other). - -export([bar/1]). - -spec bar(term()) -> ok. - bar(UStrings) -> - Jobs = [{fun main_3:main/1, [U], []} || U <- UStrings], - ok. - "#, - ); - } - - #[test] - fn rename_module_with_usage_define() { - check_rename( - "main_3", - r#" - //- /app_a/src/main.erl - -module(ma~in). - -export([foo/1]). - foo(X) -> {X}. - - //- /app_a/src/definer.hrl - -define(FOO(X), main:foo(X)). - - //- /app_a/src/other.erl - -module(other). - -include("definer.hrl"). - -export([bar/0]). - -spec bar(term()) -> ok. - bar(U) -> - main:foo(U), - ?FOO(U), - ok. - "#, - //------------------ - r#" - //- /app_a/src/main_3.erl - -module(main_3). - -export([foo/1]). - foo(X) -> {X}. - - //- /app_a/src/definer.hrl - -define(FOO(X), main_3:foo(X)). - - //- /app_a/src/other.erl - -module(other). - -include("definer.hrl"). - -export([bar/0]). - -spec bar(term()) -> ok. - bar(U) -> - main_3:foo(U), - ?FOO(U), - ok. - "#, - ); - } - // --------------------------------- #[track_caller] diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 0aa731c8c9..4b2348f610 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -243,7 +243,7 @@ mod tests { //- /my_app/src/runnables.erl ~ -module(runnables). - -export([all/0]). + -export([all/]). main() -> ok. "#, diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index d09ec201f8..fba6d12d73 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -311,7 +311,6 @@ mod tests { fn test_fn_signature_local_two_args() { check( r#" -//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -344,7 +343,6 @@ main() -> ); check( r#" -//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -377,7 +375,6 @@ main() -> ); check( r#" -//- expect_parse_errors -module(main). -spec add(integer(), integer()) -> integer(). @@ -414,7 +411,6 @@ main() -> fn test_fn_signature_remote_two_args() { check( r#" -//- expect_parse_errors //- /one.erl -module(one). @@ -453,7 +449,6 @@ main() -> ); check( r#" -//- expect_parse_errors //- /one.erl -module(one). @@ -492,7 +487,6 @@ main() -> ); check( r#" -//- expect_parse_errors //- /one.erl -module(one). @@ -535,7 +529,6 @@ main() -> fn test_fn_signature_quoted_remote_two_args() { check( r#" -//- expect_parse_errors //- /Elixir.One.erl -module('Elixir.One'). @@ -583,7 +576,6 @@ main() -> fn test_fn_signature_unclosed_call() { check( r#" -//- expect_parse_errors -module(main). -compile(export_all). @@ -634,7 +626,6 @@ main() -> fn test_fn_signature_doc() { check( r#" -//- expect_parse_errors -module(main). -compile(export_all). @@ -694,7 +685,6 @@ main() -> if supports_eep59_doc_attributes() { check( r#" -//- expect_parse_errors -module(main). -compile(export_all). @@ -763,7 +753,6 @@ main() -> fn test_fn_signature_local_imported() { check( r#" -//- expect_parse_errors //- /one.erl -module(one). -compile(export_all). @@ -805,7 +794,6 @@ main() -> fn test_fn_signature_spec_arg_names() { check( r#" -//- expect_parse_errors //- /one.erl -module(one). -compile(export_all). diff --git a/crates/ide/src/tests.rs b/crates/ide/src/tests.rs index 55e9494e48..86f0a57555 100644 --- a/crates/ide/src/tests.rs +++ b/crates/ide/src/tests.rs @@ -378,7 +378,6 @@ pub(crate) fn check_diagnostics(fixture: &str) { .disable(DiagnosticCode::UnspecificInclude) .disable(DiagnosticCode::BinaryStringToSigil) .disable(DiagnosticCode::HirUnresolvedMacro) - .disable(DiagnosticCode::BoundVarInLhs) .disable(DiagnosticCode::HirUnresolvedInclude); check_diagnostics_with_config(config, fixture) } @@ -696,7 +695,6 @@ mod test { fn filtered_diagnostics_passes_syntax_errors() { check_filtered_diagnostics( r#" - //- expect_parse_errors %%<^^^^^^^^^^^^ 💡 error: L1201: no module definition foo() -> bug bug. diff --git a/crates/ide_completion/src/attributes.rs b/crates/ide_completion/src/attributes.rs index f381df147d..fc97832d30 100644 --- a/crates/ide_completion/src/attributes.rs +++ b/crates/ide_completion/src/attributes.rs @@ -166,7 +166,6 @@ mod test { fn test_error_recovery() { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample1). % U.S. English @@ -181,7 +180,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample1). % U.K. English @@ -199,7 +197,6 @@ mod test { fn test_typing_attribute() { check( r#" - //- expect_parse_errors -module(sample). -typ~ "#, @@ -214,7 +211,6 @@ mod test { fn test_module_attribute() { check( r#" - //- expect_parse_errors -mod~ "#, None, @@ -228,7 +224,6 @@ mod test { fn test_module_attribute_hyphen() { check( r#" - //- expect_parse_errors //- /src/my-module.erl -mod~ "#, @@ -243,7 +238,6 @@ mod test { fn test_module_attribute_at() { check( r#" - //- expect_parse_errors //- /src/my@module.erl -mod~ "#, @@ -258,7 +252,6 @@ mod test { fn test_module_attribute_underscore() { check( r#" - //- expect_parse_errors //- /src/my_module.erl -mod~ "#, @@ -273,7 +266,6 @@ mod test { fn test_module_attribute_uppercase() { check( r#" - //- expect_parse_errors //- /src/Module.erl -mod~ "#, @@ -288,7 +280,6 @@ mod test { fn test_module_attribute_uppercase_middle() { check( r#" - //- expect_parse_errors //- /src/moDule.erl -mod~ "#, diff --git a/crates/ide_completion/src/ctx.rs b/crates/ide_completion/src/ctx.rs index 0d9381e7ec..22e385e3fa 100644 --- a/crates/ide_completion/src/ctx.rs +++ b/crates/ide_completion/src/ctx.rs @@ -281,7 +281,6 @@ mod ctx_tests { fn expr_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> ~X. @@ -291,7 +290,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> case 1 of. @@ -303,7 +301,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> fun(_) -> ~X end. @@ -313,7 +310,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> try 1 @@ -357,7 +353,6 @@ mod ctx_tests { fn ctx_pattern() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> ~Y = X. @@ -367,7 +362,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(X) -> case rand:uniform(1) of @@ -379,7 +373,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(X) -> fun(X~) -> 1 end. @@ -389,7 +382,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> receive @@ -401,7 +393,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> try [1] @@ -416,7 +407,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(X) -> if @@ -439,7 +429,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -451,7 +440,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -469,7 +457,6 @@ mod ctx_tests { fn ctx_pattern_error_recovery_wip() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -482,7 +469,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test(Y, X) -> try ok of @@ -499,7 +485,6 @@ mod ctx_tests { fn test_type_param_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type ty(s~) :: ok. "#), @@ -511,7 +496,6 @@ mod ctx_tests { fn test_export_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -export([ f~ @@ -525,7 +509,6 @@ mod ctx_tests { fn test_export_type_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -export_type([ t~ @@ -539,7 +522,6 @@ mod ctx_tests { fn test_spec_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec t~ table() -> ok. @@ -553,7 +535,6 @@ mod ctx_tests { fn test_type_ctx() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test() -> ~ test() -> ok. @@ -563,7 +544,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test() -> o~k test() -> ok. @@ -573,7 +553,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test(o~) -> ok. test() -> ok. @@ -583,7 +562,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -record(foo, {field1, field2 :: X~}). "#), @@ -592,7 +570,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -opaque test() :: ~. "#), @@ -601,7 +578,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -nominal test() :: ~. "#), @@ -610,7 +586,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type test() :: m~ "#), @@ -619,7 +594,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -spec test() -> ~ok. "#), @@ -631,7 +605,6 @@ mod ctx_tests { fn test_ctx_error_recovery() { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> ~ @@ -641,7 +614,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> X + ~ @@ -651,7 +623,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> X + ~. @@ -661,7 +632,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> case rand:uniform(1) of @@ -673,7 +643,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> (erlang:term_to_binary(~ @@ -684,7 +653,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). test() -> (erlang:term_to_binary(~. @@ -695,7 +663,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type ty() :: ~ "#), @@ -704,7 +671,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -type ty() :: l~. "#), @@ -713,7 +679,6 @@ mod ctx_tests { assert_eq!( ctx(r#" - //- expect_parse_errors -module(sample). -record(rec, {field = lists:map(fun(X) -> X + 1 end, [1, ~])}). "#), diff --git a/crates/ide_completion/src/export_functions.rs b/crates/ide_completion/src/export_functions.rs index ef803eb9ab..f362ea830a 100644 --- a/crates/ide_completion/src/export_functions.rs +++ b/crates/ide_completion/src/export_functions.rs @@ -83,7 +83,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -export([ foo~ @@ -107,7 +106,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -export([ function_a/0, diff --git a/crates/ide_completion/src/export_types.rs b/crates/ide_completion/src/export_types.rs index c21a37339e..9e80828b66 100644 --- a/crates/ide_completion/src/export_types.rs +++ b/crates/ide_completion/src/export_types.rs @@ -79,7 +79,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -export_type([ foo~ diff --git a/crates/ide_completion/src/functions.rs b/crates/ide_completion/src/functions.rs index eab033765f..4ce641d0e9 100644 --- a/crates/ide_completion/src/functions.rs +++ b/crates/ide_completion/src/functions.rs @@ -243,7 +243,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -266,7 +265,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -340,7 +338,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -363,7 +360,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -383,14 +379,12 @@ mod test { {label:foon/2, kind:Function, contents:Snippet("foon(${1:A}, ${2:B})"), position:Some(FilePosition { file_id: FileId(1), offset: 86 })}"#]], ); } - #[test] fn test_remote_calls_deprecated() { assert!(serde_json::to_string(&lsp_types::CompletionItemKind::MODULE).unwrap() == "9"); check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -419,7 +413,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -448,7 +441,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -474,7 +466,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -593,7 +584,6 @@ mod test { fn test_remote_fun_exprs_with_trigger() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). main(_) -> @@ -617,7 +607,6 @@ mod test { fn test_local_fun_exprs_with_trigger() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -633,7 +622,6 @@ mod test { fn test_local_fun_exprs_no_trigger() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -649,7 +637,6 @@ mod test { fn function_error_recovery() { check( r#" - //- expect_parse_errors -module(sample1). foo() -> b~ @@ -663,7 +650,6 @@ mod test { ); check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -682,7 +668,6 @@ mod test { fn test_local_and_remote() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). samba() -> ok. @@ -703,7 +688,6 @@ mod test { fn test_remote_call_broken_case() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). test() -> @@ -725,7 +709,6 @@ mod test { fn test_local_call_broken_case() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). foo() -> ok. @@ -819,7 +802,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -838,7 +820,6 @@ mod test { ); check( r#" -//- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -858,7 +839,6 @@ foo(X, Y) -> ok. ); check( r#" -//- expect_parse_errors //- /src/sample1.erl -module(sample1). local() -> @@ -922,7 +902,6 @@ foo(X, Y) -> ok. fn test_remote_call_same_module_macro_prefix() { check( r#" - //- expect_parse_errors -module(main). -export([main/0, do_not_use_me/0]). -deprecated({do_not_use_me, 0, "Because I said so"}). @@ -943,7 +922,6 @@ foo(X, Y) -> ok. fn test_in_dialyzer_attribute() { check( r#" - //- expect_parse_errors -module(main). -export([ foo/1, @@ -964,7 +942,6 @@ foo(X, Y) -> ok. fn test_quoted_local_call() { check( r#" - //- expect_parse_errors -module(sample). test() -> fo~(something). diff --git a/crates/ide_completion/src/keywords.rs b/crates/ide_completion/src/keywords.rs index dc60ae8158..734afc80a5 100644 --- a/crates/ide_completion/src/keywords.rs +++ b/crates/ide_completion/src/keywords.rs @@ -141,7 +141,6 @@ mod test { fn test_no_keywords() { check( r#" - //- expect_parse_errors -module(sample). test(X) -> a~ @@ -151,7 +150,6 @@ mod test { ); check( r#" - //- expect_parse_errors -module(sample). test(~X) -> X. @@ -162,7 +160,6 @@ mod test { check( r#" - //- expect_parse_errors -module(m~). "#, None, @@ -171,7 +168,6 @@ mod test { check( r#" - //- expect_parse_errors -module(m). -~ "#, @@ -181,7 +177,6 @@ mod test { check( r#" - //- expect_parse_errors -module(m). -type foo() :: ~. "#, @@ -196,7 +191,6 @@ mod test { fn test_keywords_error_recovery() { check( r#" - //- expect_parse_errors -module(sample). test(X) -> X ~ @@ -240,7 +234,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). test(X) -> ~ diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index f41aecdd67..71b4ff02c0 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -40,7 +40,7 @@ mod helpers; mod keywords; mod macros; mod maps; -// @fb-only: mod meta_only; +// @fb-only mod modules; mod records; mod spec; @@ -176,7 +176,7 @@ pub fn completions( } CtxKind::Other => { let _ = attributes::add_completions(&mut acc, ctx) - // @fb-only: || meta_only::add_completions(&mut acc, ctx) + // @fb-only || vars::add_completions(&mut acc, ctx) || maps::add_completions(&mut acc, ctx) || records::add_completions(&mut acc, ctx); diff --git a/crates/ide_completion/src/macros.rs b/crates/ide_completion/src/macros.rs index e86cf3ba93..3c4b77cfad 100644 --- a/crates/ide_completion/src/macros.rs +++ b/crates/ide_completion/src/macros.rs @@ -253,7 +253,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample1). -define(FOO, 1). -define(FOO(), 1). @@ -272,7 +271,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample1). -define(FOO, 1). -define(BAR, 1). @@ -284,7 +282,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample1). -define(FOO, ok). -define(BAR, 1). diff --git a/crates/ide_completion/src/maps.rs b/crates/ide_completion/src/maps.rs index e232a7d8bc..4371793356 100644 --- a/crates/ide_completion/src/maps.rs +++ b/crates/ide_completion/src/maps.rs @@ -214,7 +214,6 @@ mod test { fn test_local_type() { check( r#" - //- expect_parse_errors -module(test_local_type). -type my_map() :: #{field1 := integer(), field2 => boolean()}. foo(X) -> #~ @@ -230,7 +229,6 @@ mod test { fn test_included_type() { check( r#" - //- expect_parse_errors //- /include/test_included_type.hrl include_path:/include -type my_included_map() :: #{field1 := integer(), field2 => integer()}. //- /src/test_included_type.erl @@ -252,7 +250,6 @@ mod test { fn test_empty_map_type() { check( r#" - //- expect_parse_errors -module(test_empty_map_type). -type my_map() :: #{}. foo(X) -> #~ @@ -268,7 +265,6 @@ mod test { fn test_arity_1_map_type() { check( r#" - //- expect_parse_errors -module(test_arity_1_map_type). -type my_map() :: #{field1 := true }. foo(X) -> #~ @@ -284,7 +280,6 @@ mod test { fn test_mixed_map_and_record_types() { check( r#" - //- expect_parse_errors -module(test_mixed_map_and_record_types). -type my_map() :: #{field1 := true }. -record(my_record, {field1}). @@ -302,7 +297,6 @@ mod test { fn test_nested_map_type() { check( r#" - //- expect_parse_errors -module(test_nested_map_type). -type my_map() :: #{field1 := true, field2 => false}. -type my_nested_map() :: #{field1 := #{field1 => my_map()}}. @@ -321,12 +315,11 @@ mod test { fn test_type_from_spec() { check( r#" - //- expect_parse_errors //- /src/one.erl -module(one). -type my_map(X) :: #{field1 := X}. -export_type([my_map/0]). - + //- /src/two.erl -module(two). -spec foo(one:my_map(integer())) -> one:my_map(integer()). @@ -345,12 +338,11 @@ mod test { fn test_type_from_unowned_spec() { check( r#" - //- expect_parse_errors //- /src/one.erl -module(one). -type my_map(X) :: #{field1 := X}. -export_type([my_map/0]). - + //- /src/two.erl -module(two). -spec foo(one:my_map(integer())) -> one:my_map(integer()). @@ -367,7 +359,6 @@ mod test { fn test_local_type_in_function_argument() { check( r#" - //- expect_parse_errors -module(test_local_type). -type my_map() :: #{field1 := integer(), field2 => boolean()}. foo(#~ diff --git a/crates/ide_completion/src/modules.rs b/crates/ide_completion/src/modules.rs index 3823339f78..820d04cfe8 100644 --- a/crates/ide_completion/src/modules.rs +++ b/crates/ide_completion/src/modules.rs @@ -132,7 +132,6 @@ foo() -> check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). -export([ diff --git a/crates/ide_completion/src/records.rs b/crates/ide_completion/src/records.rs index d66e054423..cf8e0abc7c 100644 --- a/crates/ide_completion/src/records.rs +++ b/crates/ide_completion/src/records.rs @@ -320,7 +320,6 @@ mod test { fn test_record_name() { check( r#" - //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -335,7 +334,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -355,7 +353,6 @@ mod test { // Irregular names are quoted. check( r#" - //- expect_parse_errors -module(sample). -record('this.record', {field1=1, field2=2}). -record('that$record', {}). @@ -372,7 +369,6 @@ mod test { fn test_record_error_recovery() { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> #rec{field1 = 1, field2~. @@ -385,7 +381,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> X#rec{field1 = 1, field2~. @@ -398,7 +393,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -410,7 +404,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -424,7 +417,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1=1, field2=2}). foo(X) -> case ok of @@ -441,7 +433,6 @@ mod test { fn test_record_name_in_function_signature() { check( r#" - //- expect_parse_errors -module(sample). -record(this_record, {field1=1, field2=2}). -record(that_record, {}). @@ -459,7 +450,6 @@ mod test { fn test_record_field_in_function_signature() { check( r#" - //- expect_parse_errors -module(sample). -record(rec, {field1, field2, other}). foo(#rec{fie~ diff --git a/crates/ide_completion/src/spec.rs b/crates/ide_completion/src/spec.rs index cc853af865..6a0061e914 100644 --- a/crates/ide_completion/src/spec.rs +++ b/crates/ide_completion/src/spec.rs @@ -109,7 +109,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). frog() -> ok. @@ -130,7 +129,6 @@ mod test { check( r#" - //- expect_parse_errors -module(sample). frog(A, B) -> {A, B}. diff --git a/crates/ide_completion/src/types.rs b/crates/ide_completion/src/types.rs index e232ab2944..3800a97b5c 100644 --- a/crates/ide_completion/src/types.rs +++ b/crates/ide_completion/src/types.rs @@ -169,7 +169,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -type alias() :: ok. @@ -198,7 +197,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -type alias() :: ok. @@ -227,7 +225,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample2:~. @@ -251,7 +248,6 @@ mod test { // something reasonable (show nothing) check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample~:. @@ -267,7 +263,6 @@ mod test { check( r#" - //- expect_parse_errors //- /src/sample.erl -module(sample). -spec foo() -> sample~:. diff --git a/crates/ide_completion/src/vars.rs b/crates/ide_completion/src/vars.rs index 5544475ed3..65740d56a4 100644 --- a/crates/ide_completion/src/vars.rs +++ b/crates/ide_completion/src/vars.rs @@ -100,7 +100,6 @@ mod test { fn test_local_variables_1() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). test(AnArg1,Blah) -> @@ -118,7 +117,6 @@ mod test { fn test_local_variables_limit_to_current_function() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). another(AnArgNotMatched) -> @@ -144,7 +142,6 @@ mod test { fn test_local_variables_none_if_space() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). test(AnArg1,Blah) -> @@ -160,7 +157,6 @@ mod test { fn test_local_variables_no_duplicates() { check( r#" - //- expect_parse_errors //- /src/sample1.erl -module(sample1). handle_update(Config, Contents) -> diff --git a/crates/ide_db/src/diagnostic_code.rs b/crates/ide_db/src/diagnostic_code.rs index ec1e1d76cf..957caecb09 100644 --- a/crates/ide_db/src/diagnostic_code.rs +++ b/crates/ide_db/src/diagnostic_code.rs @@ -20,9 +20,9 @@ use serde::de; use strum::IntoEnumIterator; use strum_macros::EnumIter; -// @fb-only: use crate::meta_only::MetaOnlyDiagnosticCode; +// @fb-only -// @fb-only: pub const BASE_URL: &str = crate::meta_only::BASE_URL; +// @fb-only pub const BASE_URL: &str = "https://whatsapp.github.io/erlang-language-platform/docs"; // @oss-only #[derive(Clone, Debug, PartialEq, Eq, Hash, EnumIter)] @@ -93,7 +93,6 @@ pub enum DiagnosticCode { ListsReverseAppend, HirUnresolvedMacro, HirUnresolvedInclude, - BoundVarInLhs, // Wrapper for erlang service diagnostic codes ErlangService(String), @@ -101,7 +100,7 @@ pub enum DiagnosticCode { Eqwalizer(String), // Used for ad-hoc diagnostics via lints/codemods AdHoc(String), - // @fb-only: MetaOnly(MetaOnlyDiagnosticCode), + // @fb-only } // These namespaces map the error codes returned by the Erlang Service. @@ -117,7 +116,7 @@ pub enum Namespace { Parser, EDoc, WhatsApp, - // @fb-only: MetaOnly, + // @fb-only } impl fmt::Display for Namespace { @@ -132,7 +131,7 @@ impl fmt::Display for Namespace { Namespace::Parser => "p", Namespace::EDoc => "o", Namespace::WhatsApp => "w", - // @fb-only: Namespace::MetaOnly => "meta_only", + // @fb-only }; write!(f, "{namespace}") } @@ -165,7 +164,7 @@ impl Namespace { pub fn supports_doc_path(&self) -> bool { match self { Namespace::WhatsApp => true, - // @fb-only: Namespace::MetaOnly => true, + // @fb-only _ => false, } } @@ -257,11 +256,10 @@ impl DiagnosticCode { DiagnosticCode::HirUnresolvedMacro => "W0057".to_string(), DiagnosticCode::HirUnresolvedInclude => "W0058".to_string(), DiagnosticCode::UnavailableType => "W0059".to_string(), - DiagnosticCode::BoundVarInLhs => "W0060".to_string(), DiagnosticCode::ErlangService(c) => c.to_string(), DiagnosticCode::Eqwalizer(c) => format!("eqwalizer: {c}"), DiagnosticCode::AdHoc(c) => format!("ad-hoc: {c}"), - // @fb-only: DiagnosticCode::MetaOnly(c) => c.as_code(), + // @fb-only } } @@ -273,7 +271,6 @@ impl DiagnosticCode { DiagnosticCode::HeadMismatch => "head_mismatch".to_string(), DiagnosticCode::SyntaxError => "syntax_error".to_string(), DiagnosticCode::BoundVarInPattern => "bound_var_in_pattern".to_string(), - DiagnosticCode::BoundVarInLhs => "bound_var_in_lhs".to_string(), DiagnosticCode::ModuleMismatch => "module_mismatch".to_string(), DiagnosticCode::UnusedMacro => "unused_macro".to_string(), DiagnosticCode::UnusedRecordField => "unused_record_field".to_string(), @@ -363,7 +360,7 @@ impl DiagnosticCode { DiagnosticCode::ErlangService(c) => c.to_string(), DiagnosticCode::Eqwalizer(c) => c.to_string(), DiagnosticCode::AdHoc(c) => format!("ad-hoc: {c}"), - // @fb-only: DiagnosticCode::MetaOnly(c) => c.as_label(), + // @fb-only } } @@ -374,7 +371,7 @@ impl DiagnosticCode { pub fn maybe_from_string(s: &str) -> Option { DIAGNOSTIC_CODE_LOOKUPS .get(s).cloned() - // @fb-only: .or_else(|| MetaOnlyDiagnosticCode::from_str(s).ok().map(DiagnosticCode::MetaOnly)) + // @fb-only .or_else( || // Look for ErlangService and AdHoc if let Some(code) = Self::is_adhoc(s) { @@ -391,7 +388,7 @@ impl DiagnosticCode { match self { DiagnosticCode::DefaultCodeForEnumIter => None, DiagnosticCode::AdHoc(_) => None, - // @fb-only: DiagnosticCode::MetaOnly(_) => Some(Namespace::MetaOnly), + // @fb-only DiagnosticCode::ErlangService(code) => Namespace::from_str(code).ok(), _ => Namespace::from_str(&self.as_code()).ok(), } @@ -400,7 +397,7 @@ impl DiagnosticCode { pub fn supports_doc_path(&self) -> bool { match self { DiagnosticCode::DefaultCodeForEnumIter => false, - // @fb-only: DiagnosticCode::MetaOnly(MetaOnlyDiagnosticCode::DefaultCodeForEnumIter) => false, + // @fb-only _ => true, } } @@ -489,7 +486,6 @@ impl DiagnosticCode { DiagnosticCode::ModuleMismatch => false, DiagnosticCode::UnusedInclude => false, DiagnosticCode::BoundVarInPattern => false, - DiagnosticCode::BoundVarInLhs => false, DiagnosticCode::UnusedMacro => false, DiagnosticCode::UnusedRecordField => false, DiagnosticCode::MutableVarBug => false, @@ -545,7 +541,7 @@ impl DiagnosticCode { DiagnosticCode::ErlangService(_) => false, DiagnosticCode::Eqwalizer(_) => false, DiagnosticCode::AdHoc(_) => false, - // @fb-only: DiagnosticCode::MetaOnly(code) => code.allows_fixme_comment(), + // @fb-only } } diff --git a/crates/ide_db/src/eqwalizer.rs b/crates/ide_db/src/eqwalizer.rs index fca577bb21..4deed79778 100644 --- a/crates/ide_db/src/eqwalizer.rs +++ b/crates/ide_db/src/eqwalizer.rs @@ -12,6 +12,7 @@ use std::sync::Arc; use elp_base_db::FileId; use elp_base_db::FileRange; +use elp_base_db::FileSource; use elp_base_db::ModuleName; use elp_base_db::ProjectId; use elp_base_db::SourceDatabase; @@ -88,7 +89,7 @@ pub trait EqwalizerDatabase: fn types_for_file(&self, file_id: FileId) -> Option>>; fn has_eqwalizer_module_marker(&self, file_id: FileId) -> bool; fn has_eqwalizer_ignore_marker(&self, file_id: FileId) -> bool; - fn is_eqwalizer_enabled(&self, file_id: FileId) -> bool; + fn is_eqwalizer_enabled(&self, file_id: FileId, include_tests: bool) -> bool; } pub fn eqwalizer_diagnostics_by_project( @@ -113,7 +114,7 @@ fn type_at_position( db: &dyn EqwalizerDatabase, range: FileRange, ) -> Option> { - if !db.is_eqwalizer_enabled(range.file_id) { + if !db.is_eqwalizer_enabled(range.file_id, false) { return None; } let project_id = db.file_app_data(range.file_id)?.project_id; @@ -148,7 +149,7 @@ fn type_at_position( } fn types_for_file(db: &dyn EqwalizerDatabase, file_id: FileId) -> Option>> { - if !db.is_eqwalizer_enabled(file_id) { + if !db.is_eqwalizer_enabled(file_id, false) { return None; } let project_id = db.file_app_data(file_id)?.project_id; @@ -161,7 +162,7 @@ fn types_for_file(db: &dyn EqwalizerDatabase, file_id: FileId) -> Option bool { +fn is_eqwalizer_enabled(db: &dyn EqwalizerDatabase, file_id: FileId, include_tests: bool) -> bool { if !otp_supported_by_eqwalizer() { return false; } @@ -177,8 +178,11 @@ fn is_eqwalizer_enabled(db: &dyn EqwalizerDatabase, file_id: FileId) -> bool { let project = db.project_data(project_id); let eqwalizer_config = &project.eqwalizer_config; let module_index = db.module_index(project_id); + let is_src = module_index.file_source_for_file(file_id) == Some(FileSource::Src); + let is_test_opted_in = db.is_test_suite_or_test_helper(file_id) == Some(true) && include_tests; let global_opt_in = eqwalizer_config.enable_all; - let opt_in = global_opt_in || db.has_eqwalizer_module_marker(file_id); + let opt_in = + (global_opt_in && (is_src || is_test_opted_in)) || db.has_eqwalizer_module_marker(file_id); let ignored_in_config = if let Some(module_name) = module_index.module_for_file(file_id) { eqwalizer_config .ignore_modules_compiled_patterns diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index 038b41f0be..c92be86f5f 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs @@ -43,22 +43,11 @@ pub fn pick_best_token( tokens.max_by_key(move |t| f(t.kind())) } -/// Given a syntax node, check it it is immediately enclosed in a call, -/// which can represent a function call or a type. -/// For a remote call, the node can be the module or the function name. -/// In the former case, there is an extra level of nesting, so we need -/// to check up to 3 steps up pub fn get_call(syntax: &SyntaxNode) -> Option { - ast::Call::cast(syntax.parent()?) - .or_else(|| ast::Call::cast(syntax.parent()?.parent()?)) - .or_else(|| ast::Call::cast(syntax.parent()?.parent()?.parent()?)) -} - -pub fn get_external_fun(syntax: &SyntaxNode) -> Option { - if let Some(external_fun) = ast::ExternalFun::cast(syntax.parent()?) { - Some(external_fun) + if let Some(call) = ast::Call::cast(syntax.parent()?) { + Some(call) } else { - ast::ExternalFun::cast(syntax.parent()?.parent()?) + ast::Call::cast(syntax.parent()?.parent()?) } } diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index aecfd86473..a00ea1f0d9 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs @@ -57,7 +57,7 @@ pub mod docs; pub mod eqwalizer; mod erl_ast; mod line_index; -// @fb-only: pub mod meta_only; +// @fb-only pub mod metadata; mod search; pub mod text_edit; @@ -385,7 +385,7 @@ impl TypedSemantic for RootDatabase { let project_id = app_data.project_id; - let eqwalizer_enabled = self.is_eqwalizer_enabled(file_id); + let eqwalizer_enabled = self.is_eqwalizer_enabled(file_id, false); if !eqwalizer_enabled { return Some(vec![]); } @@ -448,17 +448,4 @@ mod tests { let position = fixture.position(); debug_assert_eq!(db.clamp_offset(position.file_id, 2000.into()), 15.into()) } - - #[test] - #[should_panic(expected = "Fixture validation failed: syntax errors found in test fixture")] - fn validate_fixture_with_parse_error() { - let fixture = r#" -//- /src/test.erl --module(test). -foo( -> ok. -"#; - - let (db, fixture) = RootDatabase::with_fixture(fixture); - fixture.validate(&db); - } } diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs index bd5a49f8cf..889569ca4e 100644 --- a/crates/ide_db/src/rename.rs +++ b/crates/ide_db/src/rename.rs @@ -15,10 +15,8 @@ use std::fmt; use std::iter::once; -use elp_base_db::AnchoredPathBuf; use elp_base_db::FileId; use elp_base_db::FileRange; -use elp_base_db::ModuleName; use elp_syntax::AstNode; use elp_syntax::ast; use elp_syntax::ast::in_erlang_module; @@ -27,12 +25,9 @@ use hir::Semantic; use crate::SymbolDefinition; use crate::helpers::get_call; -use crate::helpers::get_external_fun; use crate::search::NameLike; -use crate::source_change::FileSystemEdit; use crate::source_change::SourceChange; use crate::text_edit::TextEdit; -use crate::text_edit::TextEditBuilder; pub type RenameResult = Result; @@ -111,18 +106,6 @@ pub fn is_valid_type_name(new_name: &String) -> bool { false } -// Delegate checking module name validity to the parser -pub fn is_valid_module_name(new_name: &String) -> bool { - let parse = ast::SourceFile::parse_text(format!("-module({}).", new_name).as_str()); - match parse.tree().forms().next() { - Some(ast::Form::ModuleAttribute(ma)) => match ma.name() { - Some(ast::Name::Atom(atom)) => atom.syntax().text().to_string() == *new_name, - _ => false, - }, - _ => false, - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SafetyChecks { Yes, @@ -139,10 +122,7 @@ impl SymbolDefinition { ) -> RenameResult { match self.clone() { SymbolDefinition::Module(_) => { - if safety_check == SafetyChecks::Yes && !is_valid_module_name(new_name) { - rename_error!("Invalid new module name: '{}'", new_name); - } - self.rename_reference(sema, new_name, parens_needed_in_context, safety_check) + rename_error!("Cannot rename module") } SymbolDefinition::Function(fun) => { if safety_check == SafetyChecks::Yes && !is_valid_function_name(new_name) { @@ -395,7 +375,6 @@ impl SymbolDefinition { ); Ok(source_change) } - SymbolDefinition::Module(_module) => self.rename_module(sema, new_name, safety_check), // Note: This is basically an internal error, this function is called from // SymbolDefinition::rename which already weeds them out _ => { @@ -403,184 +382,6 @@ impl SymbolDefinition { } } } - - fn rename_module( - &self, - sema: &Semantic, - new_name: &str, - safety_check: SafetyChecks, - ) -> RenameResult { - let file_id = self.file().file_id; - if let Some(project_id) = sema.db.file_project_id(file_id) { - let module_index = sema.db.module_index(project_id); - if safety_check == SafetyChecks::Yes { - let new_name_module = ModuleName::new(new_name); - if module_index - .all_modules() - .iter() - .any(|name| name == &new_name_module) - { - rename_error!("module '{}' already exists", new_name); - } - } - - let mut source_change = SourceChange::default(); - // Step 1, rename all references - let usages = self.clone().usages(sema).all(); - let mut renamed_module_edit: TextEdit = TextEdit::default(); - rename_remote_module_call_refs( - usages, - file_id, - new_name, - &mut source_change, - &mut renamed_module_edit, - ); - - // Step 2: Rename the module attribute in the module being renamed - let form_list = sema.form_list(file_id); - if let Some(module_attribute) = form_list.module_attribute() { - let ast = module_attribute.form_id.get_ast(sema.db, file_id); - if let Some(name) = ast.name() { - let range = name.syntax().text_range(); - let mut builder = TextEdit::builder(); - builder.replace(range, new_name.to_string()); - renamed_module_edit - .union(builder.finish()) - .expect("Could not combine TextEdits"); - } - } - - let anchor = file_id; - let path = format!("{new_name}.erl"); - let dst = AnchoredPathBuf { anchor, path }; - source_change.insert_new_source_edit(dst.clone().into(), renamed_module_edit); - source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst }); - Ok(source_change) - } else { - rename_error!( - "Could not find project for '{:?}'", - self.file().name(sema.db.upcast()) - ) - } - } -} - -fn rename_remote_module_call_refs( - usages: crate::UsageSearchResult, - file_id: FileId, - new_name: &str, - source_change: &mut SourceChange, - renamed_module_edit: &mut TextEdit, -) { - usages.iter().for_each(|(usage_file_id, refs)| { - if let Some(edit) = rename_module_in_refs(refs, new_name) { - if usage_file_id == file_id { - renamed_module_edit - .union(edit) - .expect("Could not combine TextEdits"); - } else { - source_change.insert_source_edit(usage_file_id, edit); - } - }; - }); -} - -fn rename_module_in_refs(refs: &[NameLike], new_name: &str) -> Option { - let mut builder = TextEdit::builder(); - for usage in refs { - // Note: we cannot blindly replace all occurrences of an - // atom that happens to be a module name - // We will flesh out other usages as we need them - let _ = rename_call_module_in_ref(usage, &mut builder, new_name); - let _ = rename_external_fun_module_in_ref(usage, &mut builder, new_name); - } - Some(builder.finish()) -} - -fn rename_call_module_in_ref( - usage: &NameLike, - builder: &mut TextEditBuilder, - new_name: &str, -) -> Option<()> { - let call = get_call(usage.syntax())?; - // We can only rename an atom usage - let usage_atom = match usage { - NameLike::Name(ast::Name::Atom(atom)) => atom, - _ => return Some(()), - }; - - // First check if this is the module part of a remote call (e.g., module:function()) - if let Some(ast::Expr::Remote(remote)) = call.expr() - && let Some(module) = remote.module() - && let Some(ast::ExprMax::Atom(mod_atom)) = module.module() - && mod_atom.syntax() == usage_atom.syntax() - { - builder.replace(usage_atom.syntax().text_range(), new_name.to_string()); - return Some(()); - } - - // Check if this is a known function call that takes a module as an argument - // Extract function name and optional module name based on call type - let (module_name, function_name) = match call.expr()? { - ast::Expr::Remote(remote) => { - let module = remote.module()?; - let mod_atom = match module.module()? { - ast::ExprMax::Atom(atom) => atom, - _ => return Some(()), - }; - let fun_atom = match remote.fun()? { - ast::ExprMax::Atom(atom) => atom, - _ => return Some(()), - }; - (Some(mod_atom.text()?), fun_atom.text()?) - } - ast::Expr::ExprMax(ast::ExprMax::Atom(fun_atom)) => (None, fun_atom.text()?), - _ => return Some(()), - }; - - let args = call.args()?; - let args_vec: Vec<_> = args.args().collect(); - let arity = args_vec.len(); - let pattern_key = (module_name.as_deref(), function_name.as_str(), arity); - - // Use combined patterns that merge dynamic call patterns and module argument patterns - let combined_patterns = hir::sema::to_def::get_module_arg_patterns(); - if let Some(pattern) = combined_patterns.get(&pattern_key) - && let Some(arg) = args_vec.get(pattern.index) - { - match arg { - ast::Expr::ExprMax(ast::ExprMax::Atom(arg_atom)) - if pattern.accepts_atom() && arg_atom.syntax() == usage_atom.syntax() => - { - builder.replace(usage_atom.syntax().text_range(), new_name.to_string()); - } - ast::Expr::ExprMax(ast::ExprMax::List(list)) if pattern.accepts_list() => { - // Handle list of modules (e.g., meck:new([mod1, mod2], Options)) - for expr in list.exprs() { - if let ast::Expr::ExprMax(ast::ExprMax::Atom(list_atom)) = expr - && list_atom.syntax() == usage_atom.syntax() - { - builder.replace(usage_atom.syntax().text_range(), new_name.to_string()); - break; - } - } - } - _ => {} - } - } - - Some(()) -} - -fn rename_external_fun_module_in_ref( - usage: &NameLike, - builder: &mut TextEditBuilder, - new_name: &str, -) -> Option<()> { - let external_fun = get_external_fun(usage.syntax())?; - let module = external_fun.module()?; - builder.replace(module.name()?.syntax().text_range(), new_name.to_string()); - Some(()) } fn source_edit_from_usages( diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 1e66598359..20b4f050b4 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs @@ -325,7 +325,7 @@ impl<'a> FindUsages<'a> { /// Represents possible ast reference points - /// a string for header, or ast::Name for everything else -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum NameLike { Name(ast::Name), String(ast::String), diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs index 60b62279fe..e4afbd8742 100644 --- a/crates/ide_db/src/source_change.rs +++ b/crates/ide_db/src/source_change.rs @@ -30,36 +30,9 @@ use crate::text_edit::TextEdit; use crate::text_edit::TextEditBuilder; use crate::tree_diff::diff; -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)] -pub struct HashableAnchoredPathBuf { - /// File that this path is relative to. - pub anchor: FileId, - /// Path relative to `anchor`'s containing directory. - pub path: String, -} - -impl From for HashableAnchoredPathBuf { - fn from(value: AnchoredPathBuf) -> Self { - HashableAnchoredPathBuf { - anchor: value.anchor, - path: value.path, - } - } -} - -impl From for AnchoredPathBuf { - fn from(value: HashableAnchoredPathBuf) -> Self { - AnchoredPathBuf { - anchor: value.anchor, - path: value.path, - } - } -} - #[derive(Default, Debug, Clone)] pub struct SourceChange { pub source_file_edits: FxHashMap, - pub new_file_edits: FxHashMap, pub file_system_edits: Vec, pub is_snippet: bool, } @@ -73,7 +46,6 @@ impl SourceChange { ) -> Self { SourceChange { source_file_edits, - new_file_edits: FxHashMap::default(), file_system_edits, is_snippet: false, } @@ -102,22 +74,6 @@ impl SourceChange { } } - /// Inserts a [`TextEdit`] for the given [`AnchoredPathBuf`]. This properly handles merging existing - /// edits for a file if some already exist. - pub fn insert_new_source_edit(&mut self, file_id: HashableAnchoredPathBuf, edit: TextEdit) { - match self.new_file_edits.entry(file_id) { - Entry::Occupied(mut entry) => { - never!( - entry.get_mut().union(edit).is_err(), - "overlapping edits for same file" - ); - } - Entry::Vacant(entry) => { - entry.insert(edit); - } - } - } - pub fn push_file_system_edit(&mut self, edit: FileSystemEdit) { self.file_system_edits.push(edit); } @@ -129,15 +85,12 @@ impl SourceChange { pub fn merge(mut self, other: SourceChange) -> SourceChange { self.extend(other.source_file_edits); self.extend(other.file_system_edits); - self.extend(other.new_file_edits); self.is_snippet |= other.is_snippet; self } pub fn is_empty(&self) -> bool { - self.source_file_edits.is_empty() - && self.file_system_edits.is_empty() - && self.new_file_edits.is_empty() + self.source_file_edits.is_empty() && self.file_system_edits.is_empty() } pub fn text_range(&self, file_id: FileId) -> Option { @@ -163,18 +116,10 @@ impl Extend for SourceChange { } } -impl Extend<(HashableAnchoredPathBuf, TextEdit)> for SourceChange { - fn extend>(&mut self, iter: T) { - iter.into_iter() - .for_each(|(file_id, edit)| self.insert_new_source_edit(file_id, edit)); - } -} - impl From> for SourceChange { fn from(source_file_edits: FxHashMap) -> SourceChange { SourceChange { source_file_edits, - new_file_edits: FxHashMap::default(), file_system_edits: Vec::new(), is_snippet: false, } @@ -320,7 +265,6 @@ impl From for SourceChange { fn from(edit: FileSystemEdit) -> SourceChange { SourceChange { source_file_edits: Default::default(), - new_file_edits: Default::default(), file_system_edits: vec![edit], is_snippet: false, } diff --git a/crates/ide_ssr/src/tests.rs b/crates/ide_ssr/src/tests.rs index 881a5ac123..108680853e 100644 --- a/crates/ide_ssr/src/tests.rs +++ b/crates/ide_ssr/src/tests.rs @@ -1288,7 +1288,7 @@ fn ssr_do_not_match_pattern_missing() { r#" g() -> <<$",$\\,194,181,$A,$">> = - """ + ~b""" "\\µA" """. "#, @@ -1327,7 +1327,7 @@ fn ssr_comments_in_match() { <<{ % preceding comment 3}, { 3 % following comment - }>>. + >>. "#; let strategy = Strategy { macros: MacroStrategy::Expand, @@ -1536,7 +1536,7 @@ fn ssr_predicates_on_match_expr_pat() { %-compile({"str", var, atom}). %-type foo(V) :: {"str", V, atom}. foo({"hello", Var, atom}) -> {"str", Var, aa}. - + "#; let strategy = Strategy { macros: MacroStrategy::Expand, @@ -1636,7 +1636,7 @@ fn ssr_predicates_on_match_type() { let pattern = "ssr: {_@V, _@A}."; let code = r#" -type foo(V) :: {V, atom}. - + "#; let strategy = Strategy { macros: MacroStrategy::Expand, diff --git a/crates/project_model/src/buck.rs b/crates/project_model/src/buck.rs index 45c6b7f732..013f3cbc87 100644 --- a/crates/project_model/src/buck.rs +++ b/crates/project_model/src/buck.rs @@ -58,7 +58,6 @@ lazy_static! { } const ERL_EXT: &str = "erl"; -const BUCK_ISOLATION_DIR: &str = "lsp"; #[derive( Debug, @@ -109,7 +108,7 @@ impl BuckConfig { cmd.env_remove("RUST_BACKTRACE") .env_remove("RUST_LIB_BACKTRACE"); cmd.arg("--isolation-dir"); - cmd.arg(BUCK_ISOLATION_DIR); + cmd.arg("lsp"); cmd.current_dir(self.buck_root()); CommandProxy::new(guard, cmd) } @@ -1363,56 +1362,36 @@ fn include_path_from_file(path: &AbsPath) -> AbsPathBuf { } } -fn check_buck_output_success(mut command: CommandProxy<'_>) -> Result { - let output = command.output()?; - if output.status.success() { - return String::from_utf8(output.stdout) - .map_err(|e| anyhow::anyhow!("Invalid UTF-8 in stdout for `{command}`: {e}")); - } - let reason = match output.status.code() { - Some(code) => format!("Exited with status code: {code}"), - None => "Process terminated by signal".to_string(), - }; - let details = String::from_utf8(output.stderr).unwrap_or_default(); - bail!("Command `{command}` failed. Reason: {reason}. Details: {details}"); -} - /// This is used in tests pub fn get_prelude_cell(buck_config: &BuckConfig) -> Result { - let mut command = buck_config.buck_command(); - command + let output = buck_config + .buck_command() .arg("audit") .arg("cell") .arg("prelude") - .arg("--json"); - let raw_output = check_buck_output_success(command)?; - - let json: serde_json::Value = serde_json::from_str(&raw_output)?; - let prelude_path = json - .get("prelude") - .and_then(|v| v.as_str()) - .ok_or_else(|| anyhow::anyhow!("Could not find prelude path in Buck2 output"))? - .to_string(); - - if Path::new(&prelude_path).exists() { - Ok(prelude_path) - } else { - get_prelude_cell_bundled(buck_config) + .output()?; + if !output.status.success() { + let reason = match output.status.code() { + Some(code) => format!("Exited with status code: {code}"), + None => "Process terminated by signal".to_string(), + }; + let details = match String::from_utf8(output.stderr) { + Ok(err) => err, + Err(_) => "".to_string(), + }; + bail!("Error evaluating Buck2 query Reason: {reason}. Details: {details}",); } -} + let raw_output = String::from_utf8(output.stdout)?; -fn get_prelude_cell_bundled(buck_config: &BuckConfig) -> Result { - let mut command = buck_config.buck_command(); - command.arg("root"); - let root = check_buck_output_success(command)?; - let root = root.trim(); - let bundled_prelude_path = Path::new(&root) - .join("buck-out") - .join(BUCK_ISOLATION_DIR) - .join("external_cells") - .join("bundled") - .join("prelude"); - Ok(bundled_prelude_path.to_string_lossy().to_string()) + lazy_static! { + static ref RE: Regex = Regex::new(r"^prelude: ([^\s]+)").unwrap(); + } + let string = RE + .captures_iter(&raw_output) + .next() + .map(|c| c[1].to_string()) + .unwrap(); + Ok(string) } #[cfg(test)] @@ -1643,66 +1622,72 @@ mod tests { assert_eq!(expected, actual) } + // TODO: enable when buck is properly set up on github project + // @fb-only + const BUCK_TESTS_ENABLED: bool = false; // @oss-only + #[track_caller] fn check_buck_bxl_query(build_generated: bool, expect: Expect) { - let buck_root = to_abs_path_buf(&std::env::current_dir().unwrap()).unwrap(); - // We only need buck_config to get the buck command, everything but the buck root is ignored. - let buck_config = BuckConfig { - config_path: None, - buck_root: Some(buck_root), - enabled: true, - deps_target: None, - deps_targets: vec![], - build_deps: false, - included_targets: vec![], - excluded_targets: vec![], - source_root: None, - test_application_labels: vec!["test_application".to_string()], - }; - let generated_args = if build_generated { - vec!["--build_generated_code", "true"] - } else { - vec![] - }; - let output = buck_config - .buck_command() - .arg("bxl") - .arg("prelude//erlang/elp.bxl:elp_config") - .arg("--") - .args(generated_args) - .arg("--included_targets") - .arg("root//buck_tests_2/auto_gen/...") - .output() - .unwrap(); - if !output.status.success() { - panic!("{output:#?}"); - } - let string = String::from_utf8(output.stdout).unwrap(); - let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); - let string = string.replace(&prelude_cell, "/[prelude]/"); + if BUCK_TESTS_ENABLED { + let buck_root = to_abs_path_buf(&std::env::current_dir().unwrap()).unwrap(); + // We only need buck_config to get the buck command, everything but the buck root is ignored. + let buck_config = BuckConfig { + config_path: None, + buck_root: Some(buck_root), + enabled: true, + deps_target: None, + deps_targets: vec![], + build_deps: false, + included_targets: vec![], + excluded_targets: vec![], + source_root: None, + test_application_labels: vec!["test_application".to_string()], + }; + let generated_args = if build_generated { + vec!["--build_generated_code", "true"] + } else { + vec![] + }; + let output = buck_config + .buck_command() + .arg("bxl") + .arg("prelude//erlang/elp.bxl:elp_config") + .arg("--") + .args(generated_args) + .arg("--included_targets") + .arg("fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/...") + .output() + .unwrap(); + if !output.status.success() { + panic!("{output:#?}"); + } + let string = String::from_utf8(output.stdout).unwrap(); + let prelude_cell = get_prelude_cell(&buck_config).expect("could not get prelude"); + let string = string.replace(&prelude_cell, "/[prelude]/"); - let to_replace = env!("CARGO_WORKSPACE_DIR"); - let string = string.replace(to_replace, "/[..]/"); - expect.assert_eq(&string); + let to_replace = env!("CARGO_WORKSPACE_DIR"); + let string = string.replace(to_replace, "/[..]/"); + expect.assert_eq(&string); + } } #[test] #[ignore] fn build_info_buck_bxl_query() { - if cfg!(feature = "buck") { + if BUCK_TESTS_ENABLED { check_buck_bxl_query( false, expect![[r#" { - "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { "name": "auto_gen_a", "app_name": null, "suite": null, "srcs": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" ], "includes": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" ], "labels": [ "user_application" @@ -1712,7 +1697,7 @@ mod tests { "included_apps": [], "origin": "app" }, - "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { "name": "generated_srcs", "app_name": null, "suite": null, @@ -1855,23 +1840,23 @@ mod tests { #[test] #[ignore] fn build_info_buck_bxl_generated_query() { - if cfg!(feature = "buck") { + if BUCK_TESTS_ENABLED { // Note that there is now a value for `srcs` in the - // "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs" + // "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs" // target check_buck_bxl_query( true, expect![[r#" { - "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:auto_gen_a": { "name": "auto_gen_a", "app_name": null, "suite": null, "srcs": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl" ], "includes": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/include" ], "labels": [ "user_application" @@ -1881,12 +1866,12 @@ mod tests { "included_apps": [], "origin": "app" }, - "root//buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { + "fbcode//whatsapp/elp/test_projects/buck_tests_2/auto_gen/auto_gen_a:generated_srcs": { "name": "generated_srcs", "app_name": null, "suite": null, "srcs": [ - "/[..]/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl" + "/[..]/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl" ], "includes": [], "labels": [ diff --git a/crates/project_model/src/test_fixture.rs b/crates/project_model/src/test_fixture.rs index 140baec0ee..ac60d3b7c2 100644 --- a/crates/project_model/src/test_fixture.rs +++ b/crates/project_model/src/test_fixture.rs @@ -187,7 +187,6 @@ impl DiagnosticsEnabled { pub struct FixtureWithProjectMeta { pub fixture: Vec, pub diagnostics_enabled: DiagnosticsEnabled, - pub expect_parse_errors: bool, } impl FixtureWithProjectMeta { @@ -205,7 +204,6 @@ impl FixtureWithProjectMeta { let mut fixture = fixture.as_str(); let mut res: Vec = Vec::new(); let mut diagnostics_enabled = DiagnosticsEnabled::default(); - let mut expect_parse_errors = false; // --------------------------------------- // Each of the following is optional, but they must always @@ -234,12 +232,6 @@ impl FixtureWithProjectMeta { fixture = remain; } - if let Some(meta) = fixture.strip_prefix("//- expect_parse_errors") { - let (_meta, remain) = meta.split_once('\n').unwrap(); - expect_parse_errors = true; - fixture = remain; - } - if let Some(meta) = fixture.strip_prefix("//- native") { let (_meta, remain) = meta.split_once('\n').unwrap(); diagnostics_enabled.use_native = true; @@ -285,12 +277,6 @@ impl FixtureWithProjectMeta { if let Some(entry) = res.last_mut() { entry.text.push_str(line); - } else if line.chars().any(|c| !c.is_whitespace()) { - panic!( - "Fixture has content before the first file marker (`//- /path/to/file.erl`). \ - Did you forget to add a file marker at the beginning?\n\ - The offending line: {line:?}" - ); } } } @@ -312,7 +298,6 @@ impl FixtureWithProjectMeta { FixtureWithProjectMeta { fixture: res, diagnostics_enabled, - expect_parse_errors, } } @@ -853,19 +838,6 @@ mod tests { use crate::test_fixture::extract_tags; use crate::test_fixture::remove_annotations; - #[test] - #[should_panic(expected = "Fixture has content before the first file marker")] - fn parse_fixture_panics_on_content_before_first_file_marker() { - FixtureWithProjectMeta::parse( - r#" - -module(main). - foo() -> ok. - //- /src/erl_eval.erl - -module(erl_eval). - "#, - ); - } - #[test] #[should_panic] fn parse_fixture_checks_further_indented_metadata() { diff --git a/editors/code/README.md b/editors/code/README.md index ff5663d5ca..b03ce757f2 100644 --- a/editors/code/README.md +++ b/editors/code/README.md @@ -1,82 +1,19 @@ # Erlang Language Platform -The **Erlang Language Platform (ELP)** is a modern Language Server Protocol -(LSP) implementation for Erlang, developed by WhatsApp. ELP provides -comprehensive IDE support for Erlang development, bringing features you'd expect -from modern development tools to the Erlang ecosystem. - -Built with scalability and performance in mind, ELP uses incremental analysis to -handle large codebases efficiently, making it suitable for projects of any size. +Provide support for the [Erlang](https://www.erlang.org/) Programming Language. ## Features -### Code Intelligence - -- **📍 Go To Definition** - Jump to function, type, record definitions, etc -- **🔍 Find References** - Find all usages of functions, types, and variables -- **✨ Auto-completion** - Intelligent code completion for functions, variables, - modules and more -- **🏷️ Hover Information** - View documentation and type information on hover -- **📞 Call Hierarchy** - Explore caller/callee relationships -- **✍️ Signature Help** - Parameter hints while typing function calls -- **📋 Inlay Hints** - Display parameter names inline -- **🎨 Syntax Highlighting** - Full Erlang syntax support -- **📝 Code Lenses** - Inline actions for running tests and debugging -- **🔄 Workspace Symbol Search** - Quickly find symbols across your project - -### Code Quality - -- **🔧 Diagnostics** - Real-time error and warning detection -- **💡 Code Actions** - Quick fixes and refactoring suggestions -- **🧪 Eqwalizer Integration** - Type checking with - [Eqwalizer](https://github.com/WhatsApp/eqwalizer) - -### Debugging & Testing - -- **🐞 Integrated Debugger** - Debug Erlang applications with breakpoints and - variable inspection +* Syntax Highlighting +* Go To Definition +* Find References +* Auto-completion +* Call Hierarchy +* Signature Help +* Diagnostics +* Inlay Hints +* ... ## Documentation -For comprehensive documentation, visit: - -- **📚 - [Official Documentation](https://whatsapp.github.io/erlang-language-platform/)** -- **🚀 - [Getting Started Guide](https://whatsapp.github.io/erlang-language-platform/docs/get-started/)** -- **⚙️ - [Configuration Reference](https://whatsapp.github.io/erlang-language-platform/docs/configuration/)** -- **❓ [FAQ](https://whatsapp.github.io/erlang-language-platform/docs/faq/)** - -## Contributing - -We welcome contributions! Please see our -[Contributing Guide](https://github.com/WhatsApp/erlang-language-platform/blob/main/CONTRIBUTING.md) -for details. - -## Community & Support - -- **🐛 Issues**: - [GitHub Issues](https://github.com/WhatsApp/erlang-language-platform/issues) -- **💬 Discussions**: - [GitHub Discussions](https://github.com/WhatsApp/erlang-language-platform/discussions) - -## License - -ELP is dual-licensed under: - -- [Apache License 2.0](https://github.com/WhatsApp/erlang-language-platform/blob/main/LICENSE-APACHE) -- [MIT License](https://github.com/WhatsApp/erlang-language-platform/blob/main/LICENSE-MIT) - -## Acknowledgments - -ELP was designed at **WhatsApp** and inspired by the -[Rust Analyzer](https://rust-analyzer.github.io/) project. Special thanks to all -[contributors](https://github.com/WhatsApp/erlang-language-platform/graphs/contributors) -who have helped make ELP better. - ---- - -

- Made with ❤️ by the WhatsApp team -

+See https://whatsapp.github.io/erlang-language-platform/ for more information. diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 6309d4c81e..66d227ce12 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -1,12 +1,12 @@ { "name": "erlang-language-platform", - "version": "0.47.0", + "version": "0.45.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "erlang-language-platform", - "version": "0.47.0", + "version": "0.45.0", "hasInstallScript": true, "license": "Apache2", "devDependencies": { diff --git a/editors/code/package.json b/editors/code/package.json index eb7ced3148..ae34cde798 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1,10 +1,9 @@ { "name": "erlang-language-platform", - "displayName": "Erlang Language Platform", - "description": "Erlang Language Support for VS Code, by WhatsApp.", + "description": "Erlang language server", "author": "Meta Platforms, Inc", "license": "Apache2", - "version": "0.47.0", + "version": "0.45.0", "icon": "images/elp-logo-color.png", "homepage": "https://whatsapp.github.io/erlang-language-platform/", "repository": { @@ -21,8 +20,7 @@ "Testing" ], "keywords": [ - "elp", - "erlang" + "elp" ], "engines": { "vscode": "^1.75.0" diff --git a/eqwalizer b/eqwalizer index 0f514eb389..1e0f24c5b8 160000 --- a/eqwalizer +++ b/eqwalizer @@ -1 +1 @@ -Subproject commit 0f514eb3893fa7070835c83ecb49fbea31b0426d +Subproject commit 1e0f24c5b8f2b023fdd53d4571c3240430d31f69 diff --git a/erlang_service/src/elp_lint.erl b/erlang_service/src/elp_lint.erl index 31d2c70248..609e8c0712 100644 --- a/erlang_service/src/elp_lint.erl +++ b/erlang_service/src/elp_lint.erl @@ -4372,14 +4372,14 @@ is_format_function(io, fwrite) -> true; is_format_function(io, format) -> true; is_format_function(io_lib, fwrite) -> true; is_format_function(io_lib, format) -> true; -% @fb-only: is_format_function(wa_log, send_if) -> true; -% @fb-only: is_format_function(wa_string, format) -> true; +% @fb-only +% @fb-only is_format_function(M, F) when is_atom(M), is_atom(F) -> false. %% check_format_1([Arg]) -> ok | {warn,Level,Format,[Arg]}. -% @fb-only[end= ]: format_args(wa_log, send_if, [_Level, _Meta, _Opts, Format, Args]) -> [Format, Args]; -% @fb-only[end= ]: format_args(wa_string, format, [Format, Args, _Options]) -> [Format, Args]; +% @fb-only +% @fb-only format_args(_M, _F, As) -> As. diff --git a/test/test_projects/.buckconfig b/test/test_projects/.buckconfig deleted file mode 100644 index f14e564a7d..0000000000 --- a/test/test_projects/.buckconfig +++ /dev/null @@ -1,24 +0,0 @@ -[cells] - root = . - prelude = prelude - toolchains = toolchains - none = none - -[cell_aliases] - config = prelude - ovr_config = prelude - fbcode = none - fbsource = none - fbcode_macros = none - buck = none - -[external_cells] - prelude = bundled - -[parser] - target_platform_detector_spec = target:root//...->prelude//platforms:default \ - target:prelude//...->prelude//platforms:default \ - target:toolchains//...->prelude//platforms:default - -[build] - execution_platforms = prelude//platforms:default diff --git a/test/test_projects/.buckroot b/test/test_projects/.buckroot deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/test_projects/buck_bad_config/.elp.toml b/test/test_projects/buck_bad_config/.elp.toml deleted file mode 100644 index 963072284c..0000000000 --- a/test/test_projects/buck_bad_config/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//buck_bad_config/..." ] -source_root = "buck_bad_config" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/buck_bad_config/BUCK b/test/test_projects/buck_bad_config/BUCK deleted file mode 100644 index 498c769dac..0000000000 --- a/test/test_projects/buck_bad_config/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "bad_app", - srcs = glob(["src/*.erl"]), - applications = [ - "root//buck_bad_config/non_existent:missing", - ], - includes = glob( - ["include/*.hrl"], - exclude = ["include/junk.hrl"], - ), - version = "1.0.0", -) diff --git a/test/test_projects/buck_tests/.elp.toml b/test/test_projects/buck_tests/.elp.toml deleted file mode 100644 index b38d6f043f..0000000000 --- a/test/test_projects/buck_tests/.elp.toml +++ /dev/null @@ -1,9 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//buck_tests/..." ] -excluded_targets = [ "buck_tests:test_elp_ignored" ] -source_root = "buck_tests" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/buck_tests_2/.elp.toml b/test/test_projects/buck_tests_2/.elp.toml deleted file mode 100644 index e71eb6a819..0000000000 --- a/test/test_projects/buck_tests_2/.elp.toml +++ /dev/null @@ -1,12 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ - "root//buck_tests_2/util/app_a/...", - "root//buck_tests_2:check_include" - ] -excluded_targets = [ "root//buck_tests_2:test_elp_ignored" ] -source_root = "buck_tests_2" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/buck_tests_2/BUCK b/test/test_projects/buck_tests_2/BUCK deleted file mode 100644 index b01fdb868c..0000000000 --- a/test/test_projects/buck_tests_2/BUCK +++ /dev/null @@ -1,41 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "check_include", - srcs = [ - "check_include/src/top_includer.erl", - ], - applications = [ - "common_test", - "stdlib", - "root//buck_tests_2:check_include_separate_1", - "root//buck_tests_2:check_include_separate_2", - ], - includes = [], - labels = [], - resources = [], -) - -erlang_application( - name = "check_include_separate_1", - srcs = glob([ - "src/*.erl", - ]), - applications = [ - ], - includes = [ - "check_include_separate_1/include/top_includer.hrl", - ], - resources = [], -) - -erlang_application( - name = "check_include_separate_2", - srcs = glob([ - "src/*.erl", - ]), - applications = [ - ], - includes = glob(["check_include_separate_2/include/*.hrl"]), - resources = [], -) diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/BUCK b/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/BUCK deleted file mode 100644 index f021317020..0000000000 --- a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/BUCK +++ /dev/null @@ -1,25 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "auto_gen_a", - srcs = glob([ - "src/*.erl", - "src/*.hrl", - ]), - includes = glob(["include/*.hrl"]), - visibility = ["//buck_tests_2/..."], -) - -erlang_application( - name = "generated_srcs", - srcs = [ - ":generated.erl", - ], - labels = ["generated"], - visibility = ["//buck_tests_2/..."], -) - -export_file( - name = "generated.erl", - src = "out/pretend_generated.erl", -) diff --git a/test/test_projects/buck_tests_2/generated/BUCK b/test/test_projects/buck_tests_2/generated/BUCK deleted file mode 100644 index 8eec40830b..0000000000 --- a/test/test_projects/buck_tests_2/generated/BUCK +++ /dev/null @@ -1,12 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "generated_headers", - includes = [ - "out/generated_header.hrl", - ], - labels = ["generated"], - visibility = [ - "PUBLIC", - ], -) diff --git a/test/test_projects/buck_tests_2/util/app_a/BUCK b/test/test_projects/buck_tests_2/util/app_a/BUCK deleted file mode 100644 index 4231c1c6e8..0000000000 --- a/test/test_projects/buck_tests_2/util/app_a/BUCK +++ /dev/null @@ -1,16 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a_target", - srcs = glob(["src/*.erl"]), - app_name = "app_a", - applications = [ - "root//buck_tests_2/auto_gen/auto_gen_a:auto_gen_a", - "root//buck_tests_2/generated:generated_headers", - ], - includes = glob( - ["include/*.hrl"], - exclude = ["include/junk.hrl"], - ), - version = "1.0.0", -) diff --git a/test/test_projects/codegen_test/BUCK b/test/test_projects/codegen_test/BUCK deleted file mode 100644 index 1df5f86eba..0000000000 --- a/test/test_projects/codegen_test/BUCK +++ /dev/null @@ -1,73 +0,0 @@ -oncall("vscode_erlang") - -# Code generation rule - generates Erlang modules from template files -genrule( - name = "example_service_types_erl", - srcs = [ - "templates/example_service_types.erl", - ], - outs = { - "example_service_types.erl": ["example_service_types.erl"], - }, - cmd = "cp $SRCDIR/templates/example_service_types.erl $OUT/example_service_types.erl", -) - -genrule( - name = "example_service_client_erl", - srcs = [ - "templates/example_service_client.erl", - ], - outs = { - "example_service_client.erl": ["example_service_client.erl"], - }, - cmd = "cp $SRCDIR/templates/example_service_client.erl $OUT/example_service_client.erl", -) - -genrule( - name = "example_service_types_hrl", - srcs = [ - "templates/example_service_types.hrl", - ], - outs = { - "example_service_types.hrl": ["example_service_types.hrl"], - }, - cmd = "cp $SRCDIR/templates/example_service_types.hrl $OUT/example_service_types.hrl", -) - -# Erlang library containing only the generated code -erlang_app( - name = "example_service_generated", - srcs = [ - # Include generated Erlang modules from genrule output - ":example_service_types_erl[example_service_types.erl]", - ":example_service_client_erl[example_service_client.erl]", - ], - includes = [ - # Include generated header files from genrule output - ":example_service_types_hrl[example_service_types.hrl]", - ], -) - -# Erlang application that uses the generated code (non-generated files only) -erlang_application( - name = "codegen_test_app", - srcs = glob(["app_a/src/*.erl"]), - app_name = "codegen_test", - app_src = "app_a/src/codegen_test.app.src", - applications = [ - "kernel", - "stdlib", - ":example_service_generated", - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -# Test to verify the generated code works -erlang_tests( - suites = [ - "app_a/test/codegen_test_SUITE.erl", - ], - deps = [":codegen_test_app"], -) diff --git a/test/test_projects/codegen_test/README.md b/test/test_projects/codegen_test/README.md deleted file mode 100644 index 1f73475d9d..0000000000 --- a/test/test_projects/codegen_test/README.md +++ /dev/null @@ -1,138 +0,0 @@ -# Code Generation Test Project - -This test project demonstrates Buck2-based code generation for Erlang -applications using `genrule`. - -## Project Structure - -``` -codegen_test/ -├── .elp.toml # ELP configuration -├── BUCK # Buck build configuration with genrule -├── README.md # This file -├── templates/ # Erlang template files (input) -│ ├── example_service_types.erl # Type definitions template -│ ├── example_service_client.erl # Client stubs template -│ └── example_service_types.hrl # Header file template -├── generated/ # Pre-generated code (for reference) -│ ├── example_service_types.erl # Generated type module -│ ├── example_service_client.erl # Generated client stubs -│ └── example_service_types.hrl # Generated header file -└── app_a/ - ├── src/ - │ ├── codegen_test.app.src # Application metadata - │ └── example_usage.erl # Example using generated code - └── test/ - └── codegen_test_SUITE.erl # Test suite -``` - -## How It Works - -### 1. Template Files - -The templates directory contains well-formed Erlang files that serve as input to -the code generation process. These are complete, valid Erlang files that are -copied to the output directory during the build. - -### 2. Code Generation - -The code is generated automatically during the build process using a -`genrule`: - -```python -genrule( - name = "example_service_types_erl", - srcs = [ - "templates/example_service_types.erl", - ], - outs = { - "example_service_types.erl": ["example_service_types.erl"], - }, - cmd = "cp $SRCDIR/templates/example_service_types.erl $OUT/example_service_types.erl", -) -``` - -The genrule: - -- Takes the template file as input (`srcs`) -- Defines named outputs using `outs` parameter (creates subtargets for each - file) -- Uses `cp` command to copy template files to `$OUT` -- Outputs files to `$OUT` directory in `buck-out/` - -### 3. Build Integration - -The `BUCK` file references the generated files using subtarget syntax: - -```python -erlang_app( - name = "example_service_generated", - srcs = [ - ":example_service_types_erl[example_service_types.erl]", - ":example_service_client_erl[example_service_client.erl]", - ], - includes = [ - ":example_service_types_hrl[example_service_types.hrl]", - ], -) -``` - -When Buck builds the application: - -1. The genrule runs first, copying the template Erlang files to the output -2. The generated files are placed in - `buck-out/v2/gen/.../example_service_types_erl/` -3. The `erlang_app` consumes these files via subtarget references (`[filename]` - syntax) -4. The files are copied to the application's build directory in `buck-out/` - -### 4. Using Generated Code - -Application code includes the generated header and uses the types: - -```erlang --module(example_usage). --include("example_service_types.hrl"). - -create_sample_user() -> - #user_info{ - user_id = <<"user_123">>, - username = <<"john_doe">>, - age = 25, - is_active = true - }. - -get_user_by_id(UserId) -> - example_service_client:get_user(UserId). -``` - -## Building and Testing - -```bash -# Build just the code generation step -buck2 build fbcode//whatsapp/elp/test/test_projects/codegen_test:example_service_types_erl - -# Build the application (automatically runs code generation) -buck2 build fbcode//whatsapp/elp/test/test_projects/codegen_test:codegen_test_app - -# Run tests -buck2 test fbcode//whatsapp/elp/test/test_projects/codegen_test:codegen_test_SUITE - -# View generated files in buck-out -find buck-out -path "*codegen_test*" -name "example_service_*.erl" -``` - -## Test Coverage - -The test suite (`app_a/test/codegen_test_SUITE.erl`) verifies: - -- Generated record types work correctly -- Generated client functions are callable -- Record fields have correct types and defaults -- Integration with application code - -All tests pass: - -``` -Tests finished: Pass 3. Fail 0. Fatal 0. Skip 0. Build failure 0 -``` diff --git a/test/test_projects/codegen_test/app_a/src/codegen_test.app.src b/test/test_projects/codegen_test/app_a/src/codegen_test.app.src deleted file mode 100644 index 7a38d49a24..0000000000 --- a/test/test_projects/codegen_test/app_a/src/codegen_test.app.src +++ /dev/null @@ -1,14 +0,0 @@ -{application, codegen_test, - [{description, "Test application demonstrating code generation"}, - {vsn, "1.0.0"}, - {registered, []}, - {applications, - [kernel, - stdlib, - example_service_generated - ]}, - {env,[]}, - {modules, []}, - {licenses, ["Apache 2.0"]}, - {links, []} - ]}. diff --git a/test/test_projects/codegen_test/app_a/src/example_usage.erl b/test/test_projects/codegen_test/app_a/src/example_usage.erl deleted file mode 100644 index a624c2089b..0000000000 --- a/test/test_projects/codegen_test/app_a/src/example_usage.erl +++ /dev/null @@ -1,51 +0,0 @@ --module(example_usage). --compile([warn_missing_spec_all]). --moduledoc """ -Example module that demonstrates using generated code. -This module uses the types and client functions generated from -the example_service.schema file. -""". - -%% Include the generated header file --include_lib("example_service_generated/include/example_service_types.hrl"). - -%% API exports --export([ - create_sample_user/0, - create_query_request/1, - get_user_by_id/1 -]). - -%%%=================================================================== -%%% API -%%%=================================================================== - --doc """ -Creates a sample user_info record using generated types -""". --spec create_sample_user() -> #user_info{}. -create_sample_user() -> - #user_info{ - user_id = <<"user_123">>, - username = <<"john_doe">>, - age = 25, - is_active = true - }. - --doc """ -Creates a query_request record -""". --spec create_query_request(binary()) -> #query_request{}. -create_query_request(QueryId) -> - #query_request{ - query_id = QueryId, - filters = [{age, greater_than, 18}] - }. - --doc """ -Uses the generated client to get user information -""". --spec get_user_by_id(binary()) -> {ok, term()} | {error, term()}. -get_user_by_id(UserId) -> - %% This calls the generated client function - example_service_client:get_user(UserId). diff --git a/test/test_projects/codegen_test/app_a/test/codegen_test_SUITE.erl b/test/test_projects/codegen_test/app_a/test/codegen_test_SUITE.erl deleted file mode 100644 index 3c0135dcee..0000000000 --- a/test/test_projects/codegen_test/app_a/test/codegen_test_SUITE.erl +++ /dev/null @@ -1,73 +0,0 @@ -%%% Test suite for code generation functionality --module(codegen_test_SUITE). - --include_lib("stdlib/include/assert.hrl"). --include("example_service_types.hrl"). - -%% CT callbacks --export([all/0, init_per_suite/1, end_per_suite/1]). - -%% Test cases --export([ - test_generated_types/1, - test_generated_client/1, - test_user_record_creation/1 -]). - -%%%=================================================================== -%%% CT Callbacks -%%%=================================================================== - -all() -> - [ - test_generated_types, - test_generated_client, - test_user_record_creation - ]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -%%%=================================================================== -%%% Test Cases -%%%=================================================================== - -test_generated_types(_Config) -> - %% Test that we can create a user_info record - User = #user_info{ - user_id = <<"test_123">>, - username = <<"testuser">>, - age = 30, - is_active = true - }, - - %% Verify the record fields - ?assertEqual(<<"test_123">>, User#user_info.user_id), - ?assertEqual(<<"testuser">>, User#user_info.username), - ?assertEqual(30, User#user_info.age), - ?assertEqual(true, User#user_info.is_active), - - ok. - -test_generated_client(_Config) -> - %% Test that the generated client module exists and can be called - Result = example_service_client:get_user(<<"user_123">>), - - %% The generated stub returns {ok, generated_response} - ?assertMatch({ok, _}, Result), - - ok. - -test_user_record_creation(_Config) -> - %% Test the example_usage module - User = example_usage:create_sample_user(), - - %% Verify it's a valid user_info record - ?assertMatch(#user_info{}, User), - ?assertEqual(<<"user_123">>, User#user_info.user_id), - ?assertEqual(25, User#user_info.age), - - ok. diff --git a/test/test_projects/codegen_test/generated/example_service_client.erl b/test/test_projects/codegen_test/generated/example_service_client.erl deleted file mode 100644 index 6b38c39425..0000000000 --- a/test/test_projects/codegen_test/generated/example_service_client.erl +++ /dev/null @@ -1,37 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated client for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_client). - --include("example_service_types.hrl"). - -%% API exports --export([get_user/1]). --export([query_users/1]). --export([update_user/2]). - -%%%=================================================================== -%%% API -%%%=================================================================== - - -%% @doc Retrieves user information by user ID --spec get_user(term()) -> {ok, term()} | {error, term()}. -get_user(_UserId) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Queries users with given filters --spec query_users(term()) -> {ok, term()} | {error, term()}. -query_users(_Request) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Updates user information --spec update_user(term(), term()) -> {ok, term()} | {error, term()}. -update_user(_UserId, _UserInfo) -> - %% Auto-generated client stub - {ok, generated_response}. diff --git a/test/test_projects/codegen_test/generated/example_service_types.erl b/test/test_projects/codegen_test/generated/example_service_types.erl deleted file mode 100644 index 3f89adcba9..0000000000 --- a/test/test_projects/codegen_test/generated/example_service_types.erl +++ /dev/null @@ -1,55 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated type definitions for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_types). - -%% API exports --export([new_user_info/0]). --export([new_query_request/0]). --export([new_query_response/0]). --export([get_version/0]). - -%% Type exports --export_type([user_info/0]). --export_type([query_request/0]). --export_type([query_response/0]). - -%% Record definitions --record(user_info, {user_id = <<>>, username = <<>>, age = 0, is_active = false}). --record(query_request, {query_id = <<>>, filters = []}). --record(query_response, {results = [], count = 0}). - -%% Type definitions --type user_info() :: #user_info{}. --type query_request() :: #query_request{}. --type query_response() :: #query_response{}. - -%%%=================================================================== -%%% API -%%%=================================================================== - -%% @doc Returns the schema version --spec get_version() -> binary(). -get_version() -> - <<"1.0.0">>. - - -%% @doc Creates a new user_info record --spec new_user_info() -> #user_info{}. -new_user_info() -> - #user_info{}. - - -%% @doc Creates a new query_request record --spec new_query_request() -> #query_request{}. -new_query_request() -> - #query_request{}. - - -%% @doc Creates a new query_response record --spec new_query_response() -> #query_response{}. -new_query_response() -> - #query_response{}. diff --git a/test/test_projects/codegen_test/generated/example_service_types.hrl b/test/test_projects/codegen_test/generated/example_service_types.hrl deleted file mode 100644 index 4c957a0906..0000000000 --- a/test/test_projects/codegen_test/generated/example_service_types.hrl +++ /dev/null @@ -1,27 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated header file for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- - - --record(user_info, { - - user_id = <<>> :: binary(), - username = <<>> :: binary(), - age = 0 :: integer(), - is_active = false :: boolean() -}). - --record(query_request, { - - query_id = <<>> :: binary(), - filters = [] :: list() -}). - --record(query_response, { - - results = [] :: list(), - count = 0 :: integer() -}). diff --git a/test/test_projects/codegen_test/templates/example_service_client.erl b/test/test_projects/codegen_test/templates/example_service_client.erl deleted file mode 100644 index ab30a89f74..0000000000 --- a/test/test_projects/codegen_test/templates/example_service_client.erl +++ /dev/null @@ -1,38 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated client for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_client). - --include("example_service_types.hrl"). - -%% API exports --export([get_user/1]). --export([query_users/1]). --export([update_user/2]). - -%%%=================================================================== -%%% API -%%%=================================================================== - - -%% @doc Retrieves user information by user ID --spec get_user(term()) -> {ok, term()} | {error, term()}. -get_user(_UserId) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Queries users with given filters --spec query_users(term()) -> {ok, term()} | {error, term()}. -query_users(_Request) -> - %% Auto-generated client stub - {ok, generated_response}. - -%% @doc Updates user information --spec update_user(term(), term()) -> {ok, term()} | {error, term()}. -update_user(_UserId, _UserInfo) -> - %% Auto-generated client stub - {ok, generated_response}. - diff --git a/test/test_projects/codegen_test/templates/example_service_types.erl b/test/test_projects/codegen_test/templates/example_service_types.erl deleted file mode 100644 index 833df167c6..0000000000 --- a/test/test_projects/codegen_test/templates/example_service_types.erl +++ /dev/null @@ -1,56 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated type definitions for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- --module(example_service_types). - -%% API exports --export([new_user_info/0]). --export([new_query_request/0]). --export([new_query_response/0]). --export([get_version/0]). - -%% Type exports --export_type([user_info/0]). --export_type([query_request/0]). --export_type([query_response/0]). - -%% Record definitions --record(user_info, {user_id = <<>>, username = <<>>, age = 0, is_active = false}). --record(query_request, {query_id = <<>>, filters = []}). --record(query_response, {results = [], count = 0}). - -%% Type definitions --type user_info() :: #user_info{}. --type query_request() :: #query_request{}. --type query_response() :: #query_response{}. - -%%%=================================================================== -%%% API -%%%=================================================================== - -%% @doc Returns the schema version --spec get_version() -> binary(). -get_version() -> - <<"1.0.0">>. - - -%% @doc Creates a new user_info record --spec new_user_info() -> #user_info{}. -new_user_info() -> - #user_info{}. - - -%% @doc Creates a new query_request record --spec new_query_request() -> #query_request{}. -new_query_request() -> - #query_request{}. - - -%% @doc Creates a new query_response record --spec new_query_response() -> #query_response{}. -new_query_response() -> - #query_response{}. - diff --git a/test/test_projects/codegen_test/templates/example_service_types.hrl b/test/test_projects/codegen_test/templates/example_service_types.hrl deleted file mode 100644 index 88a2e7aed2..0000000000 --- a/test/test_projects/codegen_test/templates/example_service_types.hrl +++ /dev/null @@ -1,28 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @doc -%%% Auto-generated header file for example_service -%%% DO NOT EDIT - Generated by generate_erlang.sh -%%% @end -%%%------------------------------------------------------------------- - - --record(user_info, { - - user_id = <<>> :: binary(), - username = <<>> :: binary(), - age = 0 :: integer(), - is_active = false :: boolean() -}). - --record(query_request, { - - query_id = <<>> :: binary(), - filters = [] :: list() -}). - --record(query_response, { - - results = [] :: list(), - count = 0 :: integer() -}). - diff --git a/test/test_projects/diagnostics/.elp.toml b/test/test_projects/diagnostics/.elp.toml deleted file mode 100644 index 504ef547af..0000000000 --- a/test/test_projects/diagnostics/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//diagnostics/..." ] -source_root = "diagnostics" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/diagnostics/BUCK b/test/test_projects/diagnostics/BUCK deleted file mode 100644 index 19c15e5acf..0000000000 --- a/test/test_projects/diagnostics/BUCK +++ /dev/null @@ -1,20 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "diagnostics_app_a_target", - srcs = glob(["app_a/src/*.erl"]), - app_name = "diagnostics_app_a", - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":diagnostics_app_a_target"], -) diff --git a/test/test_projects/end_to_end/.elp.toml b/test/test_projects/end_to_end/.elp.toml deleted file mode 100644 index acbcd6146f..0000000000 --- a/test/test_projects/end_to_end/.elp.toml +++ /dev/null @@ -1,7 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = ["root//end_to_end/..."] - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/end_to_end/assist_examples/BUCK b/test/test_projects/end_to_end/assist_examples/BUCK deleted file mode 100644 index 60d39de125..0000000000 --- a/test/test_projects/end_to_end/assist_examples/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "assist_examples", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/assist_examples.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/definitions/BUCK b/test/test_projects/end_to_end/definitions/BUCK deleted file mode 100644 index c9e6b204f4..0000000000 --- a/test/test_projects/end_to_end/definitions/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "definitions", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/definitions.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/docs/BUCK b/test/test_projects/end_to_end/docs/BUCK deleted file mode 100644 index 7429863b6e..0000000000 --- a/test/test_projects/end_to_end/docs/BUCK +++ /dev/null @@ -1,16 +0,0 @@ -load("@waserver//buck2/whatsapp:erlang.bzl", "erlang_application") - -oncall("vscode_erlang") - -erlang_application( - name = "docs", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/docs.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/hover/BUCK b/test/test_projects/end_to_end/hover/BUCK deleted file mode 100644 index 7732dc473e..0000000000 --- a/test/test_projects/end_to_end/hover/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "hover", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/hover.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/end_to_end/single_errors/BUCK b/test/test_projects/end_to_end/single_errors/BUCK deleted file mode 100644 index a8f6e478b0..0000000000 --- a/test/test_projects/end_to_end/single_errors/BUCK +++ /dev/null @@ -1,14 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "single_errors", - srcs = glob([ - "src/*.erl", - ]), - app_src = "src/single_errors.app.src", - applications = [], - includes = [], - labels = ["user_application"], - version = "1.0.0", - visibility = ["PUBLIC"], -) diff --git a/test/test_projects/eqwalizer_callers/.elp.toml b/test/test_projects/eqwalizer_callers/.elp.toml deleted file mode 100644 index 68476bcf2e..0000000000 --- a/test/test_projects/eqwalizer_callers/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//eqwalizer_callers/..." ] -source_root = "eqwalizer_callers" diff --git a/test/test_projects/eqwalizer_callers/BUCK b/test/test_projects/eqwalizer_callers/BUCK deleted file mode 100644 index 32012a0dc0..0000000000 --- a/test/test_projects/eqwalizer_callers/BUCK +++ /dev/null @@ -1,19 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) diff --git a/test/test_projects/eqwalizer_tests/.elp.toml b/test/test_projects/eqwalizer_tests/.elp.toml deleted file mode 100644 index 5dac3aa6a6..0000000000 --- a/test/test_projects/eqwalizer_tests/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//eqwalizer_tests/..." ] -source_root = "eqwalizer_tests" - -[eqwalizer] -enable_all = true diff --git a/test/test_projects/eqwalizer_tests/BUCK b/test/test_projects/eqwalizer_tests/BUCK deleted file mode 100644 index 0817873cb0..0000000000 --- a/test/test_projects/eqwalizer_tests/BUCK +++ /dev/null @@ -1,77 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "check", - srcs = glob(["check/src/**/*.erl"]), - applications = [":eqwalizer"], - includes = glob([ - "check/include/*.hrl", - "eqwalizer/include/*.hrl", - ]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "check_gradual", - srcs = glob(["check_gradual/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "check/test/check_SUITE.erl", - ], - deps = [":check"], -) - -erlang_application( - name = "debug", - srcs = glob(["debug/src/*.erl"]), - applications = [":eqwalizer"], - includes = glob(["debug/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "elm_core", - srcs = glob(["elm_core/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "eqwater", - srcs = glob(["eqwater/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "fault_tolerance", - srcs = glob(["fault_tolerance/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "options", - srcs = glob(["options/src/*.erl"]), - applications = [":eqwalizer"], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "eqwalizer", - srcs = glob(["eqwalizer/src/*.erl"]), - includes = glob(["eqwalizer/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/hierarchical_config/.elp.toml b/test/test_projects/hierarchical_config/.elp.toml deleted file mode 100644 index e4d04eb6e0..0000000000 --- a/test/test_projects/hierarchical_config/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//hierarchical_config/..." ] -source_root = "hierarchical_config" diff --git a/test/test_projects/hierarchical_config/BUCK b/test/test_projects/hierarchical_config/BUCK deleted file mode 100644 index bc78a42d57..0000000000 --- a/test/test_projects/hierarchical_config/BUCK +++ /dev/null @@ -1,23 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - applications = [ - ], - includes = glob(["app_b/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/in_place_tests/.elp.toml b/test/test_projects/in_place_tests/.elp.toml deleted file mode 100644 index 70edcc3f03..0000000000 --- a/test/test_projects/in_place_tests/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//in_place_tests/..." ] -source_root = "in_place_tests" diff --git a/test/test_projects/in_place_tests/BUCK b/test/test_projects/in_place_tests/BUCK deleted file mode 100644 index f4f354e7ee..0000000000 --- a/test/test_projects/in_place_tests/BUCK +++ /dev/null @@ -1,19 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "in_place_tests_app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":in_place_tests_app_a"], -) diff --git a/test/test_projects/include_lib_dependency_test/.elp.toml b/test/test_projects/include_lib_dependency_test/.elp.toml deleted file mode 100644 index 9d1c859339..0000000000 --- a/test/test_projects/include_lib_dependency_test/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//include_lib_dependency_test/..." ] -source_root = "include_lib_dependency_test" diff --git a/test/test_projects/include_lib_dependency_test/BUCK b/test/test_projects/include_lib_dependency_test/BUCK deleted file mode 100644 index 54b81c47b5..0000000000 --- a/test/test_projects/include_lib_dependency_test/BUCK +++ /dev/null @@ -1,43 +0,0 @@ -oncall("vscode_erlang") - -# Main application that will try to include_lib from an app it doesn't depend on -erlang_application( - name = "main_app", - srcs = glob(["main_app/src/*.erl"]), - app_src = "main_app/src/main_app.app.src", - applications = [ - # Note: deliberately NOT including :external_app as a dependency - "root//include_lib_dependency_test:normal_dep", - ], - extra_includes = ["root//include_lib_dependency_test:extra_app"], - labels = ["user_application"], - version = "1.0.0", -) - -# External application that main_app will try to include_lib from -erlang_application( - name = "external_app", - srcs = glob(["external_app/src/*.erl"]), - app_src = "external_app/src/external_app.app.src", - includes = glob(["external_app/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "extra_app", - srcs = glob(["extra_app/src/*.erl"]), - app_src = "extra_app/src/extra_app.app.src", - includes = glob(["extra_app/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "normal_dep", - srcs = glob(["normal_dep/src/*.erl"]), - app_src = "normal_dep/src/normal_dep.app.src", - includes = glob(["normal_dep/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/linter/.elp.toml b/test/test_projects/linter/.elp.toml deleted file mode 100644 index 4820625b2d..0000000000 --- a/test/test_projects/linter/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter/..." ] -source_root = "linter" diff --git a/test/test_projects/linter/BUCK b/test/test_projects/linter/BUCK deleted file mode 100644 index 2db8750582..0000000000 --- a/test/test_projects/linter/BUCK +++ /dev/null @@ -1,41 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) - -erlang_application( - name = "app_a_test_utils", - srcs = [ - "app_a/test/app_a_test_helpers.erl", - "app_a/test/app_a_test_helpers_not_opted_in.erl", - "app_a/test/app_test_helpers_no_errors.erl", - ], - applications = [":app_a"], - labels = [ - "test_application", - "test_utils", - ], -) diff --git a/test/test_projects/linter_bad_config/.elp.toml b/test/test_projects/linter_bad_config/.elp.toml deleted file mode 100644 index 4820625b2d..0000000000 --- a/test/test_projects/linter_bad_config/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter/..." ] -source_root = "linter" diff --git a/test/test_projects/linter_bad_config/BUCK b/test/test_projects/linter_bad_config/BUCK deleted file mode 100644 index a0817a6ad6..0000000000 --- a/test/test_projects/linter_bad_config/BUCK +++ /dev/null @@ -1,12 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/linter_bad_config/linter/.elp.toml b/test/test_projects/linter_bad_config/linter/.elp.toml deleted file mode 100644 index 4820625b2d..0000000000 --- a/test/test_projects/linter_bad_config/linter/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter/..." ] -source_root = "linter" diff --git a/test/test_projects/linter_bad_config/linter/BUCK b/test/test_projects/linter_bad_config/linter/BUCK deleted file mode 100644 index 2db8750582..0000000000 --- a/test/test_projects/linter_bad_config/linter/BUCK +++ /dev/null @@ -1,41 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) - -erlang_application( - name = "app_a_test_utils", - srcs = [ - "app_a/test/app_a_test_helpers.erl", - "app_a/test/app_a_test_helpers_not_opted_in.erl", - "app_a/test/app_test_helpers_no_errors.erl", - ], - applications = [":app_a"], - labels = [ - "test_application", - "test_utils", - ], -) diff --git a/test/test_projects/linter_config/.elp.toml b/test/test_projects/linter_config/.elp.toml deleted file mode 100644 index c490cc155e..0000000000 --- a/test/test_projects/linter_config/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//linter_config/..." ] -source_root = "linter_config" diff --git a/test/test_projects/linter_config/.elp_lint.toml b/test/test_projects/linter_config/.elp_lint.toml deleted file mode 100644 index 47886dd507..0000000000 --- a/test/test_projects/linter_config/.elp_lint.toml +++ /dev/null @@ -1,5 +0,0 @@ -[linters.L1260] # Unused record, produced by the Erlang Service -exclude_apps = ["app_b", "app_c"] - -[linters.unused_macro] -exclude_apps = ["app_c"] diff --git a/test/test_projects/linter_config/BUCK b/test/test_projects/linter_config/BUCK deleted file mode 100644 index c1101daea2..0000000000 --- a/test/test_projects/linter_config/BUCK +++ /dev/null @@ -1,25 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_c", - srcs = glob(["app_c/src/*.erl"]), - app_src = "app_c/src/app_c.app.src", - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/linter_config/app_a/src/app_a.erl b/test/test_projects/linter_config/app_a/src/app_a.erl deleted file mode 100644 index c374c0b518..0000000000 --- a/test/test_projects/linter_config/app_a/src/app_a.erl +++ /dev/null @@ -1,4 +0,0 @@ --module(app_a). - --define(MACRO_A, a). --record(rec_a, {a :: atom()}). diff --git a/test/test_projects/linter_config/app_b/src/app_b.erl b/test/test_projects/linter_config/app_b/src/app_b.erl deleted file mode 100644 index ca7ecf985b..0000000000 --- a/test/test_projects/linter_config/app_b/src/app_b.erl +++ /dev/null @@ -1,4 +0,0 @@ --module(app_b). - --define(MACRO_B, b). --record(rec_b, {b :: atom()}). diff --git a/test/test_projects/linter_config/app_c/src/app_c.app.src b/test/test_projects/linter_config/app_c/src/app_c.app.src deleted file mode 100644 index c278bbce23..0000000000 --- a/test/test_projects/linter_config/app_c/src/app_c.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_c, - [{description, "example app C"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/linter_config/app_c/src/app_c.erl b/test/test_projects/linter_config/app_c/src/app_c.erl deleted file mode 100644 index 57573554b6..0000000000 --- a/test/test_projects/linter_config/app_c/src/app_c.erl +++ /dev/null @@ -1,4 +0,0 @@ --module(app_c). - --define(MACRO_C, c). --record(rec_c, {c :: atom()}). diff --git a/test/test_projects/linter_config/rebar.config b/test/test_projects/linter_config/rebar.config deleted file mode 100644 index d508bd24de..0000000000 --- a/test/test_projects/linter_config/rebar.config +++ /dev/null @@ -1,9 +0,0 @@ -{checkouts_dir, ["."]}. -{project_app_dirs, [ - "app_a", - "app_b", - "app_c" -]}. - -{erl_opts, [debug_info]}. -{deps, []}. diff --git a/test/test_projects/parse_error/.elp.toml b/test/test_projects/parse_error/.elp.toml deleted file mode 100644 index 1a06a42f0d..0000000000 --- a/test/test_projects/parse_error/.elp.toml +++ /dev/null @@ -1,8 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//parse_error/..." ] -source_root = "parse_error" - -[eqwalizer] -enable_all = false diff --git a/test/test_projects/parse_error/BUCK b/test/test_projects/parse_error/BUCK deleted file mode 100644 index ed65c267d0..0000000000 --- a/test/test_projects/parse_error/BUCK +++ /dev/null @@ -1,9 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "elp_test_parse_a", - srcs = glob(["parse_error_a/src/*.erl"]), - app_src = "parse_error_a/src/parse_error_a.app.src", - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/standard/.elp.toml b/test/test_projects/standard/.elp.toml deleted file mode 100644 index f5e2ac1943..0000000000 --- a/test/test_projects/standard/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//standard/..." ] -source_root = "standard" diff --git a/test/test_projects/standard/BUCK b/test/test_projects/standard/BUCK deleted file mode 100644 index 3f1e9ee947..0000000000 --- a/test/test_projects/standard/BUCK +++ /dev/null @@ -1,49 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - app_src = "app_a/src/app_a.app.src", - applications = [ - ], - includes = glob(["app_a/include/*.hrl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "elp_test_standard_app_b", - srcs = glob(["app_b/src/*.erl"]), - app_src = "app_b/src/app_b.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "elp_test_eqwalizer", - srcs = glob(["eqwalizer/src/*.erl"]), - app_src = "eqwalizer/src/eqwalizer.app.src", - labels = ["user_application"], - version = "1.0.0", -) - -erlang_tests( - suites = [ - "app_a/test/app_a_SUITE.erl", - ], - deps = [":app_a"], -) - -erlang_application( - name = "app_a_test_utils", - srcs = [ - "app_a/test/app_a_test_helpers.erl", - "app_a/test/app_a_test_helpers_not_opted_in.erl", - "app_a/test/app_test_helpers_no_errors.erl", - ], - applications = [":app_a"], - labels = [ - "test_application", - "test_utils", - ], -) diff --git a/test/test_projects/standard/app_a/src/app_a.app.src b/test/test_projects/standard/app_a/src/app_a.app.src deleted file mode 100644 index 1381435a46..0000000000 --- a/test/test_projects/standard/app_a/src/app_a.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_a, - [{description, "example app A"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/standard/app_b/src/app_b.app.src b/test/test_projects/standard/app_b/src/app_b.app.src deleted file mode 100644 index 4112b4129f..0000000000 --- a/test/test_projects/standard/app_b/src/app_b.app.src +++ /dev/null @@ -1,3 +0,0 @@ -{application, app_b, - [{description, "example app B"}, {vsn, "inplace"}, {applications, [kernel, stdlib]}] -}. diff --git a/test/test_projects/toolchains/BUCK b/test/test_projects/toolchains/BUCK deleted file mode 100644 index 770ac61f67..0000000000 --- a/test/test_projects/toolchains/BUCK +++ /dev/null @@ -1,5 +0,0 @@ -load("@prelude//toolchains:demo.bzl", "system_demo_toolchains") - -oncall("vscode_erlang") - -system_demo_toolchains() diff --git a/test/test_projects/xref/.elp.toml b/test/test_projects/xref/.elp.toml deleted file mode 100644 index 87c2f17334..0000000000 --- a/test/test_projects/xref/.elp.toml +++ /dev/null @@ -1,5 +0,0 @@ -[buck] -enabled = true -build_deps = false -included_targets = [ "root//xref/..." ] -source_root = "xref" diff --git a/test/test_projects/xref/BUCK b/test/test_projects/xref/BUCK deleted file mode 100644 index bf44968f02..0000000000 --- a/test/test_projects/xref/BUCK +++ /dev/null @@ -1,25 +0,0 @@ -oncall("vscode_erlang") - -erlang_application( - name = "app_a", - srcs = glob(["app_a/src/*.erl"]), - applications = [ - ":app_b", - ], - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_b", - srcs = glob(["app_b/src/*.erl"]), - labels = ["user_application"], - version = "1.0.0", -) - -erlang_application( - name = "app_c", - srcs = glob(["app_c/src/*.erl"]), - labels = ["user_application"], - version = "1.0.0", -) diff --git a/test/test_projects/.gitignore b/test_projects/.gitignore similarity index 85% rename from test/test_projects/.gitignore rename to test_projects/.gitignore index 2672c17cc4..b34578734c 100644 --- a/test/test_projects/.gitignore +++ b/test_projects/.gitignore @@ -3,4 +3,3 @@ *wa.build_info *_build/ *rebar.lock -buck-out/ diff --git a/test/test_projects/README.md b/test_projects/README.md similarity index 100% rename from test/test_projects/README.md rename to test_projects/README.md diff --git a/test_projects/buck_bad_config/.elp.toml b/test_projects/buck_bad_config/.elp.toml new file mode 100644 index 0000000000..a891a3dfc5 --- /dev/null +++ b/test_projects/buck_bad_config/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/buck_bad_config/..." ] +source_root = "whatsapp/elp/test_projects/buck_bad_config" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/buck_bad_config/src/bad_app.erl b/test_projects/buck_bad_config/src/bad_app.erl similarity index 100% rename from test/test_projects/buck_bad_config/src/bad_app.erl rename to test_projects/buck_bad_config/src/bad_app.erl diff --git a/test_projects/buck_tests/.elp.toml b/test_projects/buck_tests/.elp.toml new file mode 100644 index 0000000000..acb0799975 --- /dev/null +++ b/test_projects/buck_tests/.elp.toml @@ -0,0 +1,9 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/buck_tests/..." ] +excluded_targets = [ "fbcode//whatsapp/elp/test_projects/buck_tests:test_elp_ignored" ] +source_root = "whatsapp/elp/test_projects/buck_tests" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/buck_tests/TARGETS.v2_ b/test_projects/buck_tests/TARGETS.v2_ similarity index 100% rename from test/test_projects/buck_tests/TARGETS.v2_ rename to test_projects/buck_tests/TARGETS.v2_ diff --git a/test/test_projects/buck_tests/test_elp/TARGETS.v2_ b/test_projects/buck_tests/test_elp/TARGETS.v2_ similarity index 77% rename from test/test_projects/buck_tests/test_elp/TARGETS.v2_ rename to test_projects/buck_tests/test_elp/TARGETS.v2_ index 7e5bd95db5..83089813da 100644 --- a/test/test_projects/buck_tests/test_elp/TARGETS.v2_ +++ b/test_projects/buck_tests/test_elp/TARGETS.v2_ @@ -7,11 +7,11 @@ erlang_application( ]), app_src = "src/test_elp.app.src", applications = [ - "//buck_tests/test_elp_direct_dep:test_elp_direct_dep", - "//buck_tests:test_elp_no_private_headers", - "//buck_tests:test_elp_no_public_headers", - "//buck_tests:test_elp_flat_outside_target", - "//buck_tests/test_elp_flat_inside_target:test_elp_flat_inside_target", + "//whatsapp/elp/test_projects/buck_tests/test_elp_direct_dep:test_elp_direct_dep", + "//whatsapp/elp/test_projects/buck_tests:test_elp_no_private_headers", + "//whatsapp/elp/test_projects/buck_tests:test_elp_no_public_headers", + "//whatsapp/elp/test_projects/buck_tests:test_elp_flat_outside_target", + "//whatsapp/elp/test_projects/buck_tests/test_elp_flat_inside_target:test_elp_flat_inside_target", ], includes = glob(["include/*.hrl"]), version = "1.0.0", diff --git a/test/test_projects/buck_tests/test_elp/include/test_elp.hrl b/test_projects/buck_tests/test_elp/include/test_elp.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp/include/test_elp.hrl rename to test_projects/buck_tests/test_elp/include/test_elp.hrl diff --git a/test/test_projects/buck_tests/test_elp/src/test_elp.app.src b/test_projects/buck_tests/test_elp/src/test_elp.app.src similarity index 100% rename from test/test_projects/buck_tests/test_elp/src/test_elp.app.src rename to test_projects/buck_tests/test_elp/src/test_elp.app.src diff --git a/test/test_projects/buck_tests/test_elp/src/test_elp.erl b/test_projects/buck_tests/test_elp/src/test_elp.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/src/test_elp.erl rename to test_projects/buck_tests/test_elp/src/test_elp.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl b/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test1.json diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/handle_update_test2.json diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_header.hrl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl b/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl rename to test_projects/buck_tests/test_elp/test/test_elp_SUITE_data/untracked_module.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl b/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl rename to test_projects/buck_tests/test_elp/test/test_elp_test_utils.erl diff --git a/test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl b/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl rename to test_projects/buck_tests/test_elp/test/test_elp_test_utils.hrl diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ b/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ similarity index 62% rename from test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ rename to test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ index a752b99087..d0fea8149b 100644 --- a/test/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ +++ b/test_projects/buck_tests/test_elp_direct_dep/TARGETS.v2_ @@ -5,10 +5,10 @@ erlang_application( "src/*.hrl", ]), applications = [ - "//buck_tests/test_elp_transitive_dep:test_elp_transitive_dep", + "//whatsapp/elp/test_projects/buck_tests/test_elp_transitive_dep:test_elp_transitive_dep", ], extra_includes = [ - "//buck_tests/test_elp:test_elp", + "//whatsapp/elp/test_projects/buck_tests/test_elp:test_elp", ], includes = glob(["include/*.hrl"]), version = "1.0.0", diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl b/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl rename to test_projects/buck_tests/test_elp_direct_dep/include/test_elp_direct_dep.hrl diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl b/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl rename to test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep.erl diff --git a/test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl b/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl rename to test_projects/buck_tests/test_elp_direct_dep/src/test_elp_direct_dep_private.hrl diff --git a/test/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ b/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ rename to test_projects/buck_tests/test_elp_flat_inside_target/TARGETS.v2_ diff --git a/test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl b/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl rename to test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.erl diff --git a/test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl b/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl rename to test_projects/buck_tests/test_elp_flat_inside_target/test_elp_flat_inside_target.hrl diff --git a/test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl b/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl rename to test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.erl diff --git a/test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl b/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl rename to test_projects/buck_tests/test_elp_flat_outside_target/test_elp_flat_outside_target.hrl diff --git a/test/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl b/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl rename to test_projects/buck_tests/test_elp_ignored/test_elp_ignored.erl diff --git a/test/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl b/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl rename to test_projects/buck_tests/test_elp_no_private_headers/include/test_elp_no_private_headers.hrl diff --git a/test/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl b/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl rename to test_projects/buck_tests/test_elp_no_private_headers/src/test_elp_no_private_headers.erl diff --git a/test/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl b/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl rename to test_projects/buck_tests/test_elp_no_public_headers/src/test_elp_no_headers.erl diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ b/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ rename to test_projects/buck_tests/test_elp_transitive_dep/TARGETS.v2_ diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl b/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl rename to test_projects/buck_tests/test_elp_transitive_dep/include/test_elp_transitive_dep.hrl diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl b/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl rename to test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep.erl diff --git a/test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl b/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl similarity index 100% rename from test/test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl rename to test_projects/buck_tests/test_elp_transitive_dep/src/test_elp_transitive_dep_private.hrl diff --git a/test_projects/buck_tests_2/.elp.toml b/test_projects/buck_tests_2/.elp.toml new file mode 100644 index 0000000000..35f02a72f3 --- /dev/null +++ b/test_projects/buck_tests_2/.elp.toml @@ -0,0 +1,12 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ + "fbcode//whatsapp/elp/test_projects/buck_tests_2/util/app_a/...", + "fbcode//whatsapp/elp/test_projects/buck_tests_2:check_include" + ] +excluded_targets = [ "fbcode//whatsapp/elp/test_projects/buck_tests_2:test_elp_ignored" ] +source_root = "whatsapp/elp/test_projects/buck_tests_2" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl b/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl similarity index 100% rename from test/test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl rename to test_projects/buck_tests_2/auto_gen/auto_gen_a/include/auto_gen_a.hrl diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl b/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl similarity index 100% rename from test/test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl rename to test_projects/buck_tests_2/auto_gen/auto_gen_a/out/pretend_generated.erl diff --git a/test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl b/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl similarity index 100% rename from test/test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl rename to test_projects/buck_tests_2/auto_gen/auto_gen_a/src/auto_gen_a.erl diff --git a/test/test_projects/buck_tests_2/check_include/src/top_includer.erl b/test_projects/buck_tests_2/check_include/src/top_includer.erl similarity index 100% rename from test/test_projects/buck_tests_2/check_include/src/top_includer.erl rename to test_projects/buck_tests_2/check_include/src/top_includer.erl diff --git a/test/test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl b/test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl similarity index 100% rename from test/test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl rename to test_projects/buck_tests_2/check_include_separate_1/include/include_with_bug.hrl diff --git a/test/test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl b/test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl similarity index 100% rename from test/test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl rename to test_projects/buck_tests_2/check_include_separate_1/include/top_includer.hrl diff --git a/test/test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl b/test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl similarity index 100% rename from test/test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl rename to test_projects/buck_tests_2/check_include_separate_2/include/separate_include.hrl diff --git a/test/test_projects/buck_tests_2/generated/out/generated_header.hrl b/test_projects/buck_tests_2/generated/out/generated_header.hrl similarity index 100% rename from test/test_projects/buck_tests_2/generated/out/generated_header.hrl rename to test_projects/buck_tests_2/generated/out/generated_header.hrl diff --git a/test/test_projects/buck_tests_2/util/app_a/include/junk.hrl b/test_projects/buck_tests_2/util/app_a/include/junk.hrl similarity index 100% rename from test/test_projects/buck_tests_2/util/app_a/include/junk.hrl rename to test_projects/buck_tests_2/util/app_a/include/junk.hrl diff --git a/test/test_projects/buck_tests_2/util/app_a/src/app_a.erl b/test_projects/buck_tests_2/util/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/buck_tests_2/util/app_a/src/app_a.erl rename to test_projects/buck_tests_2/util/app_a/src/app_a.erl diff --git a/test/test_projects/custom_build_tool/.elp.toml b/test_projects/custom_build_tool/.elp.toml similarity index 100% rename from test/test_projects/custom_build_tool/.elp.toml rename to test_projects/custom_build_tool/.elp.toml diff --git a/test/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl b/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/custom_build_tool/apps/app_a/include/app_a.hrl rename to test_projects/custom_build_tool/apps/app_a/include/app_a.hrl diff --git a/test/test_projects/custom_build_tool/apps/app_a/src/app_a.erl b/test_projects/custom_build_tool/apps/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/custom_build_tool/apps/app_a/src/app_a.erl rename to test_projects/custom_build_tool/apps/app_a/src/app_a.erl diff --git a/test/test_projects/custom_build_tool/apps/app_b/src/app_b.erl b/test_projects/custom_build_tool/apps/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/custom_build_tool/apps/app_b/src/app_b.erl rename to test_projects/custom_build_tool/apps/app_b/src/app_b.erl diff --git a/test_projects/diagnostics/.elp.toml b/test_projects/diagnostics/.elp.toml new file mode 100644 index 0000000000..e5ee70c992 --- /dev/null +++ b/test_projects/diagnostics/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/diagnostics/..." ] +source_root = "whatsapp/elp/test_projects/diagnostics" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/diagnostics/README.md b/test_projects/diagnostics/README.md similarity index 100% rename from test/test_projects/diagnostics/README.md rename to test_projects/diagnostics/README.md diff --git a/test/test_projects/diagnostics/app_a/extra/app_a.erl b/test_projects/diagnostics/app_a/extra/app_a.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/extra/app_a.erl rename to test_projects/diagnostics/app_a/extra/app_a.erl diff --git a/test/test_projects/diagnostics/app_a/include/app_a.hrl b/test_projects/diagnostics/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/diagnostics/app_a/include/app_a.hrl rename to test_projects/diagnostics/app_a/include/app_a.hrl diff --git a/test/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl b/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl similarity index 100% rename from test/test_projects/diagnostics/app_a/include/broken_diagnostics.hrl rename to test_projects/diagnostics/app_a/include/broken_diagnostics.hrl diff --git a/test/test_projects/diagnostics/app_a/include/diagnostics.hrl b/test_projects/diagnostics/app_a/include/diagnostics.hrl similarity index 100% rename from test/test_projects/diagnostics/app_a/include/diagnostics.hrl rename to test_projects/diagnostics/app_a/include/diagnostics.hrl diff --git a/test/test_projects/diagnostics/app_a/src/app_a.app.src b/test_projects/diagnostics/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/diagnostics/app_a/src/app_a.app.src rename to test_projects/diagnostics/app_a/src/app_a.app.src diff --git a/test/test_projects/diagnostics/app_a/src/app_a.erl b/test_projects/diagnostics/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/app_a.erl rename to test_projects/diagnostics/app_a/src/app_a.erl diff --git a/test/test_projects/diagnostics/app_a/src/broken_parse_trans.erl b/test_projects/diagnostics/app_a/src/broken_parse_trans.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/broken_parse_trans.erl rename to test_projects/diagnostics/app_a/src/broken_parse_trans.erl diff --git a/test/test_projects/diagnostics/app_a/src/cascading.erl b/test_projects/diagnostics/app_a/src/cascading.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/cascading.erl rename to test_projects/diagnostics/app_a/src/cascading.erl diff --git a/test/test_projects/diagnostics/app_a/src/crlf.erl b/test_projects/diagnostics/app_a/src/crlf.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/crlf.erl rename to test_projects/diagnostics/app_a/src/crlf.erl diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics.erl b/test_projects/diagnostics/app_a/src/diagnostics.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics.erl rename to test_projects/diagnostics/app_a/src/diagnostics.erl diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics.escript b/test_projects/diagnostics/app_a/src/diagnostics.escript similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics.escript rename to test_projects/diagnostics/app_a/src/diagnostics.escript diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics_errors.escript b/test_projects/diagnostics/app_a/src/diagnostics_errors.escript similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics_errors.escript rename to test_projects/diagnostics/app_a/src/diagnostics_errors.escript diff --git a/test/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript b/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript similarity index 100% rename from test/test_projects/diagnostics/app_a/src/diagnostics_warnings.escript rename to test_projects/diagnostics/app_a/src/diagnostics_warnings.escript diff --git a/test/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl b/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl rename to test_projects/diagnostics/app_a/src/erlang_diagnostics_errors_gen.erl diff --git a/test/test_projects/diagnostics/app_a/src/file_attribute.erl b/test_projects/diagnostics/app_a/src/file_attribute.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/file_attribute.erl rename to test_projects/diagnostics/app_a/src/file_attribute.erl diff --git a/test/test_projects/diagnostics/app_a/src/lint_recursive.erl b/test_projects/diagnostics/app_a/src/lint_recursive.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/lint_recursive.erl rename to test_projects/diagnostics/app_a/src/lint_recursive.erl diff --git a/test/test_projects/diagnostics/app_a/src/lints.erl b/test_projects/diagnostics/app_a/src/lints.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/lints.erl rename to test_projects/diagnostics/app_a/src/lints.erl diff --git a/test/test_projects/diagnostics/app_a/src/otp27_docstrings.erl b/test_projects/diagnostics/app_a/src/otp27_docstrings.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/otp27_docstrings.erl rename to test_projects/diagnostics/app_a/src/otp27_docstrings.erl diff --git a/test/test_projects/diagnostics/app_a/src/otp27_sigils.erl b/test_projects/diagnostics/app_a/src/otp27_sigils.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/otp27_sigils.erl rename to test_projects/diagnostics/app_a/src/otp27_sigils.erl diff --git a/test/test_projects/diagnostics/app_a/src/otp_7655.erl b/test_projects/diagnostics/app_a/src/otp_7655.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/otp_7655.erl rename to test_projects/diagnostics/app_a/src/otp_7655.erl diff --git a/test/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl b/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl rename to test_projects/diagnostics/app_a/src/parse_error_a_cascade.erl diff --git a/test/test_projects/diagnostics/app_a/src/suppressed.erl b/test_projects/diagnostics/app_a/src/suppressed.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/suppressed.erl rename to test_projects/diagnostics/app_a/src/suppressed.erl diff --git a/test/test_projects/diagnostics/app_a/src/syntax.erl b/test_projects/diagnostics/app_a/src/syntax.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/src/syntax.erl rename to test_projects/diagnostics/app_a/src/syntax.erl diff --git a/test/test_projects/diagnostics/app_a/test/app_a_SUITE.erl b/test_projects/diagnostics/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/diagnostics/app_a/test/app_a_SUITE.erl rename to test_projects/diagnostics/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/diagnostics/erlang_ls.config b/test_projects/diagnostics/erlang_ls.config similarity index 100% rename from test/test_projects/diagnostics/erlang_ls.config rename to test_projects/diagnostics/erlang_ls.config diff --git a/test/test_projects/diagnostics/rebar.config b/test_projects/diagnostics/rebar.config similarity index 100% rename from test/test_projects/diagnostics/rebar.config rename to test_projects/diagnostics/rebar.config diff --git a/test/test_projects/diagnostics/test_build_info.json b/test_projects/diagnostics/test_build_info.json similarity index 100% rename from test/test_projects/diagnostics/test_build_info.json rename to test_projects/diagnostics/test_build_info.json diff --git a/test/test_projects/codegen_test/.elp.toml b/test_projects/end_to_end/.elp.toml similarity index 50% rename from test/test_projects/codegen_test/.elp.toml rename to test_projects/end_to_end/.elp.toml index f21fe1bc73..f015956e45 100644 --- a/test/test_projects/codegen_test/.elp.toml +++ b/test_projects/end_to_end/.elp.toml @@ -1,7 +1,7 @@ [buck] enabled = true build_deps = false -included_targets = ["root//codegen_test/..."] +included_targets = ["fbcode//whatsapp/elp/test_projects/end_to_end/..."] [eqwalizer] enable_all = false diff --git a/test/test_projects/end_to_end/assist_examples/src/add_doc.erl b/test_projects/end_to_end/assist_examples/src/add_doc.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/add_doc.erl rename to test_projects/end_to_end/assist_examples/src/add_doc.erl diff --git a/test/test_projects/end_to_end/assist_examples/src/assist_examples.app.src b/test_projects/end_to_end/assist_examples/src/assist_examples.app.src similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/assist_examples.app.src rename to test_projects/end_to_end/assist_examples/src/assist_examples.app.src diff --git a/test/test_projects/end_to_end/assist_examples/src/code_completion.erl b/test_projects/end_to_end/assist_examples/src/code_completion.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/code_completion.erl rename to test_projects/end_to_end/assist_examples/src/code_completion.erl diff --git a/test/test_projects/end_to_end/assist_examples/src/extract_function.erl b/test_projects/end_to_end/assist_examples/src/extract_function.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/extract_function.erl rename to test_projects/end_to_end/assist_examples/src/extract_function.erl diff --git a/test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl b/test_projects/end_to_end/assist_examples/src/head_mismatch.erl similarity index 100% rename from test/test_projects/end_to_end/assist_examples/src/head_mismatch.erl rename to test_projects/end_to_end/assist_examples/src/head_mismatch.erl diff --git a/test/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl b/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl similarity index 100% rename from test/test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl rename to test_projects/end_to_end/caf/configerator/source/whatsapp/my_caf.erl diff --git a/test/test_projects/end_to_end/definitions/README.md b/test_projects/end_to_end/definitions/README.md similarity index 100% rename from test/test_projects/end_to_end/definitions/README.md rename to test_projects/end_to_end/definitions/README.md diff --git a/test/test_projects/end_to_end/definitions/src/definitions.app.src b/test_projects/end_to_end/definitions/src/definitions.app.src similarity index 100% rename from test/test_projects/end_to_end/definitions/src/definitions.app.src rename to test_projects/end_to_end/definitions/src/definitions.app.src diff --git a/test/test_projects/end_to_end/definitions/src/local_def.erl b/test_projects/end_to_end/definitions/src/local_def.erl similarity index 100% rename from test/test_projects/end_to_end/definitions/src/local_def.erl rename to test_projects/end_to_end/definitions/src/local_def.erl diff --git a/test/test_projects/end_to_end/docs/src/docs.app.src b/test_projects/end_to_end/docs/src/docs.app.src similarity index 100% rename from test/test_projects/end_to_end/docs/src/docs.app.src rename to test_projects/end_to_end/docs/src/docs.app.src diff --git a/test/test_projects/end_to_end/docs/src/docs.erl b/test_projects/end_to_end/docs/src/docs.erl similarity index 100% rename from test/test_projects/end_to_end/docs/src/docs.erl rename to test_projects/end_to_end/docs/src/docs.erl diff --git a/test/test_projects/end_to_end/erlang_ls.config b/test_projects/end_to_end/erlang_ls.config similarity index 100% rename from test/test_projects/end_to_end/erlang_ls.config rename to test_projects/end_to_end/erlang_ls.config diff --git a/test/test_projects/end_to_end/fixtures/erlang-stacktrace.txt b/test_projects/end_to_end/fixtures/erlang-stacktrace.txt similarity index 100% rename from test/test_projects/end_to_end/fixtures/erlang-stacktrace.txt rename to test_projects/end_to_end/fixtures/erlang-stacktrace.txt diff --git a/test/test_projects/end_to_end/hover/README.md b/test_projects/end_to_end/hover/README.md similarity index 100% rename from test/test_projects/end_to_end/hover/README.md rename to test_projects/end_to_end/hover/README.md diff --git a/test/test_projects/end_to_end/hover/src/doc_examples.erl b/test_projects/end_to_end/hover/src/doc_examples.erl similarity index 100% rename from test/test_projects/end_to_end/hover/src/doc_examples.erl rename to test_projects/end_to_end/hover/src/doc_examples.erl diff --git a/test/test_projects/end_to_end/hover/src/hover.app.src b/test_projects/end_to_end/hover/src/hover.app.src similarity index 100% rename from test/test_projects/end_to_end/hover/src/hover.app.src rename to test_projects/end_to_end/hover/src/hover.app.src diff --git a/test/test_projects/end_to_end/rebar.config b/test_projects/end_to_end/rebar.config similarity index 100% rename from test/test_projects/end_to_end/rebar.config rename to test_projects/end_to_end/rebar.config diff --git a/test/test_projects/end_to_end/single_errors/README.md b/test_projects/end_to_end/single_errors/README.md similarity index 100% rename from test/test_projects/end_to_end/single_errors/README.md rename to test_projects/end_to_end/single_errors/README.md diff --git a/test/test_projects/end_to_end/single_errors/src/as_you_type.erl b/test_projects/end_to_end/single_errors/src/as_you_type.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/as_you_type.erl rename to test_projects/end_to_end/single_errors/src/as_you_type.erl diff --git a/test/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl b/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl rename to test_projects/end_to_end/single_errors/src/compiler_diagnostics.erl diff --git a/test/test_projects/end_to_end/single_errors/src/single_errors.app.src b/test_projects/end_to_end/single_errors/src/single_errors.app.src similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/single_errors.app.src rename to test_projects/end_to_end/single_errors/src/single_errors.app.src diff --git a/test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl b/test_projects/end_to_end/single_errors/src/spec_mismatch.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl rename to test_projects/end_to_end/single_errors/src/spec_mismatch.erl diff --git a/test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 b/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 rename to test_projects/end_to_end/single_errors/src/spec_mismatch.erl.2 diff --git a/test/test_projects/end_to_end/single_errors/src/types_on_hover.erl b/test_projects/end_to_end/single_errors/src/types_on_hover.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/types_on_hover.erl rename to test_projects/end_to_end/single_errors/src/types_on_hover.erl diff --git a/test/test_projects/end_to_end/single_errors/src/unused_macro.erl b/test_projects/end_to_end/single_errors/src/unused_macro.erl similarity index 100% rename from test/test_projects/end_to_end/single_errors/src/unused_macro.erl rename to test_projects/end_to_end/single_errors/src/unused_macro.erl diff --git a/test/test_projects/eqwalizer/src/eqwalizer.app.src b/test_projects/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/eqwalizer/src/eqwalizer.app.src rename to test_projects/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/eqwalizer/src/eqwalizer_specs.erl b/test_projects/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/eqwalizer/src/eqwalizer_specs.erl diff --git a/test_projects/eqwalizer_callers/.elp.toml b/test_projects/eqwalizer_callers/.elp.toml new file mode 100644 index 0000000000..f4b7f6f6ac --- /dev/null +++ b/test_projects/eqwalizer_callers/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/eqwalizer_callers/..." ] +source_root = "whatsapp/elp/test_projects/eqwalizer_callers" diff --git a/test/test_projects/eqwalizer_callers/.gitignore b/test_projects/eqwalizer_callers/.gitignore similarity index 100% rename from test/test_projects/eqwalizer_callers/.gitignore rename to test_projects/eqwalizer_callers/.gitignore diff --git a/test/test_projects/eqwalizer_callers/app_a/include/app_a.hrl b/test_projects/eqwalizer_callers/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/include/app_a.hrl rename to test_projects/eqwalizer_callers/app_a/include/app_a.hrl diff --git a/test/test_projects/eqwalizer_callers/app_a/src/app_a.app.src b/test_projects/eqwalizer_callers/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/src/app_a.app.src rename to test_projects/eqwalizer_callers/app_a/src/app_a.app.src diff --git a/test/test_projects/eqwalizer_callers/app_a/src/app_a.erl b/test_projects/eqwalizer_callers/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/src/app_a.erl rename to test_projects/eqwalizer_callers/app_a/src/app_a.erl diff --git a/test/test_projects/eqwalizer_callers/app_a/src/app_b.erl b/test_projects/eqwalizer_callers/app_a/src/app_b.erl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/src/app_b.erl rename to test_projects/eqwalizer_callers/app_a/src/app_b.erl diff --git a/test/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl b/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl rename to test_projects/eqwalizer_callers/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/eqwalizer_callers/rebar.config b/test_projects/eqwalizer_callers/rebar.config similarity index 100% rename from test/test_projects/eqwalizer_callers/rebar.config rename to test_projects/eqwalizer_callers/rebar.config diff --git a/test/test_projects/eqwalizer_ignore_modules/.elp.toml b/test_projects/eqwalizer_ignore_modules/.elp.toml similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/.elp.toml rename to test_projects/eqwalizer_ignore_modules/.elp.toml diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl b/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl rename to test_projects/eqwalizer_ignore_modules/apps/app_a/include/app_a.hrl diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl b/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl rename to test_projects/eqwalizer_ignore_modules/apps/app_a/src/another_module_a.erl diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl b/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl rename to test_projects/eqwalizer_ignore_modules/apps/app_a/src/app_a.erl diff --git a/test/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl b/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl rename to test_projects/eqwalizer_ignore_modules/apps/app_b/src/app_b.erl diff --git a/test_projects/eqwalizer_tests/.elp.toml b/test_projects/eqwalizer_tests/.elp.toml new file mode 100644 index 0000000000..ed5c60502f --- /dev/null +++ b/test_projects/eqwalizer_tests/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/eqwalizer_tests/..." ] +source_root = "whatsapp/elp/test_projects/eqwalizer_tests" + +[eqwalizer] +enable_all = true diff --git a/test/test_projects/eqwalizer_tests/.gitignore b/test_projects/eqwalizer_tests/.gitignore similarity index 100% rename from test/test_projects/eqwalizer_tests/.gitignore rename to test_projects/eqwalizer_tests/.gitignore diff --git a/test/test_projects/eqwalizer_tests/.rebar.root b/test_projects/eqwalizer_tests/.rebar.root similarity index 100% rename from test/test_projects/eqwalizer_tests/.rebar.root rename to test_projects/eqwalizer_tests/.rebar.root diff --git a/test/test_projects/eqwalizer_tests/check/include/my_header.hrl b/test_projects/eqwalizer_tests/check/include/my_header.hrl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/include/my_header.hrl rename to test_projects/eqwalizer_tests/check/include/my_header.hrl diff --git a/test/test_projects/eqwalizer_tests/check/src/any_fun_type.erl b/test_projects/eqwalizer_tests/check/src/any_fun_type.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/any_fun_type.erl rename to test_projects/eqwalizer_tests/check/src/any_fun_type.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/apply_none.erl b/test_projects/eqwalizer_tests/check/src/apply_none.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/apply_none.erl rename to test_projects/eqwalizer_tests/check/src/apply_none.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/approx.erl b/test_projects/eqwalizer_tests/check/src/approx.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/approx.erl rename to test_projects/eqwalizer_tests/check/src/approx.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/as_pat.erl b/test_projects/eqwalizer_tests/check/src/as_pat.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/as_pat.erl rename to test_projects/eqwalizer_tests/check/src/as_pat.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/auto_imports.erl b/test_projects/eqwalizer_tests/check/src/auto_imports.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/auto_imports.erl rename to test_projects/eqwalizer_tests/check/src/auto_imports.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/behave.erl b/test_projects/eqwalizer_tests/check/src/behave.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/behave.erl rename to test_projects/eqwalizer_tests/check/src/behave.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/binaries.erl b/test_projects/eqwalizer_tests/check/src/binaries.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/binaries.erl rename to test_projects/eqwalizer_tests/check/src/binaries.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/booleans.erl b/test_projects/eqwalizer_tests/check/src/booleans.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/booleans.erl rename to test_projects/eqwalizer_tests/check/src/booleans.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl b/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl rename to test_projects/eqwalizer_tests/check/src/callbacks1_pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl similarity index 70% rename from test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl index 854feec923..8152487669 100644 --- a/test/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl +++ b/test_projects/eqwalizer_tests/check/src/callbacks3_neg.erl @@ -3,12 +3,11 @@ %%% This source code is licensed under the Apache 2.0 license found in %%% the LICENSE file in the root directory of this source tree. --module(callbacks3_neg). % @OTP27Only +-module(callbacks3_neg). % @OTPVersionDependent -export([ init/1, handle_call/3, - handle_cast/2, - handle_info/2 + handle_cast/2 ]). -behavior(gen_server). @@ -20,7 +19,3 @@ handle_call(_, _From, State) -> -spec handle_cast(ok, ok) -> wrong_ret. handle_cast(_, _) -> wrong_ret. - --spec handle_info(ok, ok) -> {noreply, ok, wrong_atom}. -handle_info(_, _) -> - {noreply, ok, wrong_atom}. diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks4_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks5_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl b/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl rename to test_projects/eqwalizer_tests/check/src/callbacks6_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl b/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl rename to test_projects/eqwalizer_tests/check/src/callbacks7_overload_pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/case_predicates.erl b/test_projects/eqwalizer_tests/check/src/case_predicates.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/case_predicates.erl rename to test_projects/eqwalizer_tests/check/src/case_predicates.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/check.app.src b/test_projects/eqwalizer_tests/check/src/check.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/check.app.src rename to test_projects/eqwalizer_tests/check/src/check.app.src diff --git a/test/test_projects/eqwalizer_tests/check/src/compiler_macro.erl b/test_projects/eqwalizer_tests/check/src/compiler_macro.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/compiler_macro.erl rename to test_projects/eqwalizer_tests/check/src/compiler_macro.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/complex_maps.erl b/test_projects/eqwalizer_tests/check/src/complex_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/complex_maps.erl rename to test_projects/eqwalizer_tests/check/src/complex_maps.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/comprehensions.erl b/test_projects/eqwalizer_tests/check/src/comprehensions.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/comprehensions.erl rename to test_projects/eqwalizer_tests/check/src/comprehensions.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/contravariant.erl b/test_projects/eqwalizer_tests/check/src/contravariant.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/contravariant.erl rename to test_projects/eqwalizer_tests/check/src/contravariant.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/custom.erl b/test_projects/eqwalizer_tests/check/src/custom.erl similarity index 99% rename from test/test_projects/eqwalizer_tests/check/src/custom.erl rename to test_projects/eqwalizer_tests/check/src/custom.erl index b6910b0fc7..911bfa3a0a 100644 --- a/test/test_projects/eqwalizer_tests/check/src/custom.erl +++ b/test_projects/eqwalizer_tests/check/src/custom.erl @@ -3,7 +3,7 @@ %%% This source code is licensed under the Apache 2.0 license found in %%% the LICENSE file in the root directory of this source tree. --module(custom). % @OTP27Only +-module(custom). % @OTPVersionDependent -import(maps, [get/2, get/3]). -compile([export_all, nowarn_export_all]). diff --git a/test/test_projects/eqwalizer_tests/check/src/detached_specs1.erl b/test_projects/eqwalizer_tests/check/src/detached_specs1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/detached_specs1.erl rename to test_projects/eqwalizer_tests/check/src/detached_specs1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/detached_specs2.erl b/test_projects/eqwalizer_tests/check/src/detached_specs2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/detached_specs2.erl rename to test_projects/eqwalizer_tests/check/src/detached_specs2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dyn_calls.erl b/test_projects/eqwalizer_tests/check/src/dyn_calls.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dyn_calls.erl rename to test_projects/eqwalizer_tests/check/src/dyn_calls.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl b/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl rename to test_projects/eqwalizer_tests/check/src/dyn_remote_funs.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl b/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_callbacks_1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl b/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_callbacks_2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl b/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_calls.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_calls.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl b/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_catch.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_catch.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl b/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_fun.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_fun.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl b/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_generics.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_generics.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl b/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_local_funs.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl b/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_receive.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_receive.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl b/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_refine.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_refine.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl b/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl rename to test_projects/eqwalizer_tests/check/src/dynamic_try_catch.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/elab_clause.erl b/test_projects/eqwalizer_tests/check/src/elab_clause.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/elab_clause.erl rename to test_projects/eqwalizer_tests/check/src/elab_clause.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/error_messages.erl b/test_projects/eqwalizer_tests/check/src/error_messages.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/error_messages.erl rename to test_projects/eqwalizer_tests/check/src/error_messages.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/fancy_generics.erl b/test_projects/eqwalizer_tests/check/src/fancy_generics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/fancy_generics.erl rename to test_projects/eqwalizer_tests/check/src/fancy_generics.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/format.erl b/test_projects/eqwalizer_tests/check/src/format.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/format.erl rename to test_projects/eqwalizer_tests/check/src/format.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/fun_stats.erl b/test_projects/eqwalizer_tests/check/src/fun_stats.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/fun_stats.erl rename to test_projects/eqwalizer_tests/check/src/fun_stats.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/fun_stats2.erl b/test_projects/eqwalizer_tests/check/src/fun_stats2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/fun_stats2.erl rename to test_projects/eqwalizer_tests/check/src/fun_stats2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/funs.erl b/test_projects/eqwalizer_tests/check/src/funs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/funs.erl rename to test_projects/eqwalizer_tests/check/src/funs.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/funs2.erl b/test_projects/eqwalizer_tests/check/src/funs2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/funs2.erl rename to test_projects/eqwalizer_tests/check/src/funs2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl b/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/funs_uncommon.erl rename to test_projects/eqwalizer_tests/check/src/funs_uncommon.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl b/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/generic_fun_application.erl rename to test_projects/eqwalizer_tests/check/src/generic_fun_application.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl b/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/generics_with_unions.erl rename to test_projects/eqwalizer_tests/check/src/generics_with_unions.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl b/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_bounded.erl rename to test_projects/eqwalizer_tests/check/src/gradual_bounded.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl b/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl rename to test_projects/eqwalizer_tests/check/src/gradual_complex_types.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_custom.erl b/test_projects/eqwalizer_tests/check/src/gradual_custom.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_custom.erl rename to test_projects/eqwalizer_tests/check/src/gradual_custom.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl b/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl rename to test_projects/eqwalizer_tests/check/src/gradual_lambdas.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl b/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_maybe.erl rename to test_projects/eqwalizer_tests/check/src/gradual_maybe.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_misc.erl b/test_projects/eqwalizer_tests/check/src/gradual_misc.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_misc.erl rename to test_projects/eqwalizer_tests/check/src/gradual_misc.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl b/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl rename to test_projects/eqwalizer_tests/check/src/gradual_overloaded.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl b/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl rename to test_projects/eqwalizer_tests/check/src/gradual_regression_01.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl b/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/gradual_untyped.erl rename to test_projects/eqwalizer_tests/check/src/gradual_untyped.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl b/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guard_b_connections.erl rename to test_projects/eqwalizer_tests/check/src/guard_b_connections.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guards.erl b/test_projects/eqwalizer_tests/check/src/guards.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guards.erl rename to test_projects/eqwalizer_tests/check/src/guards.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guards_logic.erl b/test_projects/eqwalizer_tests/check/src/guards_logic.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guards_logic.erl rename to test_projects/eqwalizer_tests/check/src/guards_logic.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/guards_simple.erl b/test_projects/eqwalizer_tests/check/src/guards_simple.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/guards_simple.erl rename to test_projects/eqwalizer_tests/check/src/guards_simple.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/hints.erl b/test_projects/eqwalizer_tests/check/src/hints.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/hints.erl rename to test_projects/eqwalizer_tests/check/src/hints.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/index1.erl b/test_projects/eqwalizer_tests/check/src/index1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/index1.erl rename to test_projects/eqwalizer_tests/check/src/index1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/index2.erl b/test_projects/eqwalizer_tests/check/src/index2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/index2.erl rename to test_projects/eqwalizer_tests/check/src/index2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/iolists.erl b/test_projects/eqwalizer_tests/check/src/iolists.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/iolists.erl rename to test_projects/eqwalizer_tests/check/src/iolists.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/kp_01.erl b/test_projects/eqwalizer_tests/check/src/kp_01.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/kp_01.erl rename to test_projects/eqwalizer_tests/check/src/kp_01.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/kp_02.erl b/test_projects/eqwalizer_tests/check/src/kp_02.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/kp_02.erl rename to test_projects/eqwalizer_tests/check/src/kp_02.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/lists_tests.erl b/test_projects/eqwalizer_tests/check/src/lists_tests.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/lists_tests.erl rename to test_projects/eqwalizer_tests/check/src/lists_tests.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/misc.erl b/test_projects/eqwalizer_tests/check/src/misc.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/misc.erl rename to test_projects/eqwalizer_tests/check/src/misc.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/misc_lib.erl b/test_projects/eqwalizer_tests/check/src/misc_lib.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/misc_lib.erl rename to test_projects/eqwalizer_tests/check/src/misc_lib.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/my_behaviour.erl b/test_projects/eqwalizer_tests/check/src/my_behaviour.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/my_behaviour.erl rename to test_projects/eqwalizer_tests/check/src/my_behaviour.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl b/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl rename to test_projects/eqwalizer_tests/check/src/my_gradual_behaviour.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/my_header.erl b/test_projects/eqwalizer_tests/check/src/my_header.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/my_header.erl rename to test_projects/eqwalizer_tests/check/src/my_header.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/neg.erl b/test_projects/eqwalizer_tests/check/src/neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/neg.erl rename to test_projects/eqwalizer_tests/check/src/neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl b/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl rename to test_projects/eqwalizer_tests/check/src/nested1/misc_nested1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl b/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl rename to test_projects/eqwalizer_tests/check/src/nested1/nested2/misc_nested2.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/nowarn.erl b/test_projects/eqwalizer_tests/check/src/nowarn.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/nowarn.erl rename to test_projects/eqwalizer_tests/check/src/nowarn.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/number_comparisons.erl b/test_projects/eqwalizer_tests/check/src/number_comparisons.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/number_comparisons.erl rename to test_projects/eqwalizer_tests/check/src/number_comparisons.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/numbers.erl b/test_projects/eqwalizer_tests/check/src/numbers.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/numbers.erl rename to test_projects/eqwalizer_tests/check/src/numbers.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/opaque.erl b/test_projects/eqwalizer_tests/check/src/opaque.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/opaque.erl rename to test_projects/eqwalizer_tests/check/src/opaque.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/other.erl b/test_projects/eqwalizer_tests/check/src/other.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/other.erl rename to test_projects/eqwalizer_tests/check/src/other.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/otp28.erl b/test_projects/eqwalizer_tests/check/src/otp28.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/otp28.erl rename to test_projects/eqwalizer_tests/check/src/otp28.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/otp_opaques.erl b/test_projects/eqwalizer_tests/check/src/otp_opaques.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/otp_opaques.erl rename to test_projects/eqwalizer_tests/check/src/otp_opaques.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/overloaded.erl b/test_projects/eqwalizer_tests/check/src/overloaded.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/overloaded.erl rename to test_projects/eqwalizer_tests/check/src/overloaded.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl b/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl rename to test_projects/eqwalizer_tests/check/src/overloaded_specs_union.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/parametricity.erl b/test_projects/eqwalizer_tests/check/src/parametricity.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/parametricity.erl rename to test_projects/eqwalizer_tests/check/src/parametricity.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/pats.erl b/test_projects/eqwalizer_tests/check/src/pats.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/pats.erl rename to test_projects/eqwalizer_tests/check/src/pats.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/pinned.erl b/test_projects/eqwalizer_tests/check/src/pinned.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/pinned.erl rename to test_projects/eqwalizer_tests/check/src/pinned.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/pos.erl b/test_projects/eqwalizer_tests/check/src/pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/pos.erl rename to test_projects/eqwalizer_tests/check/src/pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/records.erl b/test_projects/eqwalizer_tests/check/src/records.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/records.erl rename to test_projects/eqwalizer_tests/check/src/records.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl b/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/recursive_aliases.erl rename to test_projects/eqwalizer_tests/check/src/recursive_aliases.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/refine.erl b/test_projects/eqwalizer_tests/check/src/refine.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/refine.erl rename to test_projects/eqwalizer_tests/check/src/refine.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/scoping.erl b/test_projects/eqwalizer_tests/check/src/scoping.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/scoping.erl rename to test_projects/eqwalizer_tests/check/src/scoping.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/skip.erl b/test_projects/eqwalizer_tests/check/src/skip.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/skip.erl rename to test_projects/eqwalizer_tests/check/src/skip.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/static_maybe.erl b/test_projects/eqwalizer_tests/check/src/static_maybe.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/static_maybe.erl rename to test_projects/eqwalizer_tests/check/src/static_maybe.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl b/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/strict_complex_types.erl rename to test_projects/eqwalizer_tests/check/src/strict_complex_types.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/strict_fun.erl b/test_projects/eqwalizer_tests/check/src/strict_fun.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/strict_fun.erl rename to test_projects/eqwalizer_tests/check/src/strict_fun.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/strict_receive.erl b/test_projects/eqwalizer_tests/check/src/strict_receive.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/strict_receive.erl rename to test_projects/eqwalizer_tests/check/src/strict_receive.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/subtype_neg.erl b/test_projects/eqwalizer_tests/check/src/subtype_neg.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/subtype_neg.erl rename to test_projects/eqwalizer_tests/check/src/subtype_neg.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/subtype_pos.erl b/test_projects/eqwalizer_tests/check/src/subtype_pos.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/subtype_pos.erl rename to test_projects/eqwalizer_tests/check/src/subtype_pos.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/t_maps.erl b/test_projects/eqwalizer_tests/check/src/t_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/t_maps.erl rename to test_projects/eqwalizer_tests/check/src/t_maps.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl b/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/tagged_tuples.erl rename to test_projects/eqwalizer_tests/check/src/tagged_tuples.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/test.erl b/test_projects/eqwalizer_tests/check/src/test.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/test.erl rename to test_projects/eqwalizer_tests/check/src/test.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/tries.erl b/test_projects/eqwalizer_tests/check/src/tries.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/tries.erl rename to test_projects/eqwalizer_tests/check/src/tries.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/tuple_union.erl b/test_projects/eqwalizer_tests/check/src/tuple_union.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/tuple_union.erl rename to test_projects/eqwalizer_tests/check/src/tuple_union.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/type_aliases.erl b/test_projects/eqwalizer_tests/check/src/type_aliases.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/type_aliases.erl rename to test_projects/eqwalizer_tests/check/src/type_aliases.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/type_asserts.erl b/test_projects/eqwalizer_tests/check/src/type_asserts.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/type_asserts.erl rename to test_projects/eqwalizer_tests/check/src/type_asserts.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/type_predicates.erl b/test_projects/eqwalizer_tests/check/src/type_predicates.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/type_predicates.erl rename to test_projects/eqwalizer_tests/check/src/type_predicates.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/united_fun.erl b/test_projects/eqwalizer_tests/check/src/united_fun.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/united_fun.erl rename to test_projects/eqwalizer_tests/check/src/united_fun.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/unspecced.erl b/test_projects/eqwalizer_tests/check/src/unspecced.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/unspecced.erl rename to test_projects/eqwalizer_tests/check/src/unspecced.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl b/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl rename to test_projects/eqwalizer_tests/check/src/use_dynamic_gradual.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl b/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl rename to test_projects/eqwalizer_tests/check/src/use_dynamic_strict.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/vars1.erl b/test_projects/eqwalizer_tests/check/src/vars1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/vars1.erl rename to test_projects/eqwalizer_tests/check/src/vars1.erl diff --git a/test/test_projects/eqwalizer_tests/check/src/vars2.erl b/test_projects/eqwalizer_tests/check/src/vars2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/src/vars2.erl rename to test_projects/eqwalizer_tests/check/src/vars2.erl diff --git a/test/test_projects/eqwalizer_tests/check/test/check_SUITE.erl b/test_projects/eqwalizer_tests/check/test/check_SUITE.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/check/test/check_SUITE.erl rename to test_projects/eqwalizer_tests/check/test/check_SUITE.erl diff --git a/test/test_projects/eqwalizer_tests/debug/include/debug_header.hrl b/test_projects/eqwalizer_tests/debug/include/debug_header.hrl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/include/debug_header.hrl rename to test_projects/eqwalizer_tests/debug/include/debug_header.hrl diff --git a/test/test_projects/eqwalizer_tests/debug/src/attributes.erl b/test_projects/eqwalizer_tests/debug/src/attributes.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/attributes.erl rename to test_projects/eqwalizer_tests/debug/src/attributes.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/debug.app.src b/test_projects/eqwalizer_tests/debug/src/debug.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/debug.app.src rename to test_projects/eqwalizer_tests/debug/src/debug.app.src diff --git a/test/test_projects/eqwalizer_tests/debug/src/debug_header.erl b/test_projects/eqwalizer_tests/debug/src/debug_header.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/debug_header.erl rename to test_projects/eqwalizer_tests/debug/src/debug_header.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/expand.erl b/test_projects/eqwalizer_tests/debug/src/expand.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/expand.erl rename to test_projects/eqwalizer_tests/debug/src/expand.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/expr1.erl b/test_projects/eqwalizer_tests/debug/src/expr1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/expr1.erl rename to test_projects/eqwalizer_tests/debug/src/expr1.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/expr2.erl b/test_projects/eqwalizer_tests/debug/src/expr2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/expr2.erl rename to test_projects/eqwalizer_tests/debug/src/expr2.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/records_wip.erl b/test_projects/eqwalizer_tests/debug/src/records_wip.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/records_wip.erl rename to test_projects/eqwalizer_tests/debug/src/records_wip.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/types1.erl b/test_projects/eqwalizer_tests/debug/src/types1.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/types1.erl rename to test_projects/eqwalizer_tests/debug/src/types1.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/types2.erl b/test_projects/eqwalizer_tests/debug/src/types2.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/types2.erl rename to test_projects/eqwalizer_tests/debug/src/types2.erl diff --git a/test/test_projects/eqwalizer_tests/debug/src/wip_maps.erl b/test_projects/eqwalizer_tests/debug/src/wip_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/debug/src/wip_maps.erl rename to test_projects/eqwalizer_tests/debug/src/wip_maps.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/basics.erl b/test_projects/eqwalizer_tests/elm_core/src/basics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/basics.erl rename to test_projects/eqwalizer_tests/elm_core/src/basics.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src b/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src rename to test_projects/eqwalizer_tests/elm_core/src/elm_core.app.src diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/list.erl b/test_projects/eqwalizer_tests/elm_core/src/list.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/list.erl rename to test_projects/eqwalizer_tests/elm_core/src/list.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/map.erl b/test_projects/eqwalizer_tests/elm_core/src/map.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/map.erl rename to test_projects/eqwalizer_tests/elm_core/src/map.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl b/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl rename to test_projects/eqwalizer_tests/elm_core/src/map_ffi.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/maybe.erl b/test_projects/eqwalizer_tests/elm_core/src/maybe.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/maybe.erl rename to test_projects/eqwalizer_tests/elm_core/src/maybe.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/result.erl b/test_projects/eqwalizer_tests/elm_core/src/result.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/result.erl rename to test_projects/eqwalizer_tests/elm_core/src/result.erl diff --git a/test/test_projects/eqwalizer_tests/elm_core/src/tuple.erl b/test_projects/eqwalizer_tests/elm_core/src/tuple.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/elm_core/src/tuple.erl rename to test_projects/eqwalizer_tests/elm_core/src/tuple.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl b/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl rename to test_projects/eqwalizer_tests/eqwalizer/include/eqwalizer.hrl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src b/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src rename to test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl b/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl rename to test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl b/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/eqwalizer_tests/eqwalizer/src/eqwalizer_specs.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl b/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl rename to test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_build_info_prv.erl diff --git a/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src b/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src rename to test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.app.src diff --git a/test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl b/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl rename to test_projects/eqwalizer_tests/eqwalizer_rebar3/src/eqwalizer_rebar3.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/readme.md b/test_projects/eqwalizer_tests/eqwater/readme.md similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/readme.md rename to test_projects/eqwalizer_tests/eqwater/readme.md diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl b/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl rename to test_projects/eqwalizer_tests/eqwater/src/deep_tuples.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src b/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src rename to test_projects/eqwalizer_tests/eqwater/src/eqwater.app.src diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_aliases.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_generics.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_lists.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl similarity index 89% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl index 68d938f790..78ae852b8a 100644 --- a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl +++ b/test_projects/eqwalizer_tests/eqwater/src/eqwater_maps.erl @@ -59,13 +59,3 @@ map_occ_08_neg(_) -> err. map_occ_09(#{a := undefined}) -> 1; map_occ_09(#{a := Map}) -> Map#{2 => 2}; map_occ_09(_) -> 3. - --spec is_ok(ok) -> ok. -is_ok(ok) -> ok. - --spec map_occ_foreach_neg(#{term() => #{a => ok | err}}) -> ok. -map_occ_foreach_neg(M) -> - maps:foreach(fun - (_, #{a := err}) -> ok; - (_, #{a := V}) -> is_ok(V) - end, M). diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_records.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl b/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl rename to test_projects/eqwalizer_tests/eqwater/src/eqwater_sound.erl diff --git a/test/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl b/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl rename to test_projects/eqwalizer_tests/eqwater/src/unlimited_refinement.erl diff --git a/test/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer b/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer similarity index 100% rename from test/test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer rename to test_projects/eqwalizer_tests/fault_tolerance/.eqwalizer diff --git a/test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src b/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src rename to test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.app.src diff --git a/test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl b/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl rename to test_projects/eqwalizer_tests/fault_tolerance/src/fault_tolerance.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/bad_maps.erl b/test_projects/eqwalizer_tests/options/src/bad_maps.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/bad_maps.erl rename to test_projects/eqwalizer_tests/options/src/bad_maps.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl b/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl rename to test_projects/eqwalizer_tests/options/src/dynamic_lambdas.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/options.app.src b/test_projects/eqwalizer_tests/options/src/options.app.src similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/options.app.src rename to test_projects/eqwalizer_tests/options/src/options.app.src diff --git a/test/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl b/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl rename to test_projects/eqwalizer_tests/options/src/overloaded_specs_dynamic_result.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/redundant_guards.erl b/test_projects/eqwalizer_tests/options/src/redundant_guards.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/redundant_guards.erl rename to test_projects/eqwalizer_tests/options/src/redundant_guards.erl diff --git a/test/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl b/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl similarity index 100% rename from test/test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl rename to test_projects/eqwalizer_tests/options/src/uncovered_clauses.erl diff --git a/test/test_projects/eqwalizer_tests/rebar.config b/test_projects/eqwalizer_tests/rebar.config similarity index 100% rename from test/test_projects/eqwalizer_tests/rebar.config rename to test_projects/eqwalizer_tests/rebar.config diff --git a/test_projects/hierarchical_config/.elp.toml b/test_projects/hierarchical_config/.elp.toml new file mode 100644 index 0000000000..1033c181ee --- /dev/null +++ b/test_projects/hierarchical_config/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/hierarchical_config/..." ] +source_root = "whatsapp/elp/test_projects/hierarchical_config" diff --git a/test/test_projects/hierarchical_config/.elp_lint.toml b/test_projects/hierarchical_config/.elp_lint.toml similarity index 100% rename from test/test_projects/hierarchical_config/.elp_lint.toml rename to test_projects/hierarchical_config/.elp_lint.toml diff --git a/test/test_projects/hierarchical_config/app_a/.elp_lint.toml b/test_projects/hierarchical_config/app_a/.elp_lint.toml similarity index 100% rename from test/test_projects/hierarchical_config/app_a/.elp_lint.toml rename to test_projects/hierarchical_config/app_a/.elp_lint.toml diff --git a/test/test_projects/hierarchical_config/app_a/src/app_a.app.src b/test_projects/hierarchical_config/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/hierarchical_config/app_a/src/app_a.app.src rename to test_projects/hierarchical_config/app_a/src/app_a.app.src diff --git a/test/test_projects/hierarchical_config/app_a/src/app_a.erl b/test_projects/hierarchical_config/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/hierarchical_config/app_a/src/app_a.erl rename to test_projects/hierarchical_config/app_a/src/app_a.erl diff --git a/test/test_projects/hierarchical_config/app_b/src/app_b.app.src b/test_projects/hierarchical_config/app_b/src/app_b.app.src similarity index 100% rename from test/test_projects/hierarchical_config/app_b/src/app_b.app.src rename to test_projects/hierarchical_config/app_b/src/app_b.app.src diff --git a/test/test_projects/hierarchical_config/app_b/src/app_b.erl b/test_projects/hierarchical_config/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/hierarchical_config/app_b/src/app_b.erl rename to test_projects/hierarchical_config/app_b/src/app_b.erl diff --git a/test/test_projects/hierarchical_config/rebar.config b/test_projects/hierarchical_config/rebar.config similarity index 100% rename from test/test_projects/hierarchical_config/rebar.config rename to test_projects/hierarchical_config/rebar.config diff --git a/test_projects/in_place_tests/.elp.toml b/test_projects/in_place_tests/.elp.toml new file mode 100644 index 0000000000..b6c251f03c --- /dev/null +++ b/test_projects/in_place_tests/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/in_place_tests/..." ] +source_root = "whatsapp/elp/test_projects/in_place_tests" diff --git a/test/test_projects/in_place_tests/README.md b/test_projects/in_place_tests/README.md similarity index 100% rename from test/test_projects/in_place_tests/README.md rename to test_projects/in_place_tests/README.md diff --git a/test/test_projects/in_place_tests/app_a/extra/app_a.erl b/test_projects/in_place_tests/app_a/extra/app_a.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/extra/app_a.erl rename to test_projects/in_place_tests/app_a/extra/app_a.erl diff --git a/test/test_projects/in_place_tests/app_a/include/app_a.hrl b/test_projects/in_place_tests/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/in_place_tests/app_a/include/app_a.hrl rename to test_projects/in_place_tests/app_a/include/app_a.hrl diff --git a/test/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl b/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl similarity index 100% rename from test/test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl rename to test_projects/in_place_tests/app_a/include/broken_diagnostics.hrl diff --git a/test/test_projects/in_place_tests/app_a/include/diagnostics.hrl b/test_projects/in_place_tests/app_a/include/diagnostics.hrl similarity index 100% rename from test/test_projects/in_place_tests/app_a/include/diagnostics.hrl rename to test_projects/in_place_tests/app_a/include/diagnostics.hrl diff --git a/test/test_projects/in_place_tests/app_a/src/app_a.app.src b/test_projects/in_place_tests/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/in_place_tests/app_a/src/app_a.app.src rename to test_projects/in_place_tests/app_a/src/app_a.app.src diff --git a/test/test_projects/in_place_tests/app_a/src/app_a.erl b/test_projects/in_place_tests/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/src/app_a.erl rename to test_projects/in_place_tests/app_a/src/app_a.erl diff --git a/test/test_projects/in_place_tests/app_a/src/lints.erl b/test_projects/in_place_tests/app_a/src/lints.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/src/lints.erl rename to test_projects/in_place_tests/app_a/src/lints.erl diff --git a/test/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl b/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/in_place_tests/app_a/test/app_a_SUITE.erl rename to test_projects/in_place_tests/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/in_place_tests/erlang_ls.config b/test_projects/in_place_tests/erlang_ls.config similarity index 100% rename from test/test_projects/in_place_tests/erlang_ls.config rename to test_projects/in_place_tests/erlang_ls.config diff --git a/test/test_projects/in_place_tests/rebar.config b/test_projects/in_place_tests/rebar.config similarity index 100% rename from test/test_projects/in_place_tests/rebar.config rename to test_projects/in_place_tests/rebar.config diff --git a/test_projects/include_lib_dependency_test/.elp.toml b/test_projects/include_lib_dependency_test/.elp.toml new file mode 100644 index 0000000000..65e106a9e2 --- /dev/null +++ b/test_projects/include_lib_dependency_test/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/include_lib_dependency_test/..." ] +source_root = "whatsapp/elp/test_projects/include_lib_dependency_test" diff --git a/test/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl b/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl similarity index 100% rename from test/test_projects/include_lib_dependency_test/external_app/include/external_header.hrl rename to test_projects/include_lib_dependency_test/external_app/include/external_header.hrl diff --git a/test/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src b/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/external_app/src/external_app.app.src rename to test_projects/include_lib_dependency_test/external_app/src/external_app.app.src diff --git a/test/test_projects/include_lib_dependency_test/external_app/src/external_app.erl b/test_projects/include_lib_dependency_test/external_app/src/external_app.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/external_app/src/external_app.erl rename to test_projects/include_lib_dependency_test/external_app/src/external_app.erl diff --git a/test/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl b/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl similarity index 100% rename from test/test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl rename to test_projects/include_lib_dependency_test/extra_app/include/extra_header.hrl diff --git a/test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src b/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src rename to test_projects/include_lib_dependency_test/extra_app/src/extra_app.app.src diff --git a/test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl b/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl rename to test_projects/include_lib_dependency_test/extra_app/src/extra_app.erl diff --git a/test/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src b/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/main_app/src/main_app.app.src rename to test_projects/include_lib_dependency_test/main_app/src/main_app.app.src diff --git a/test/test_projects/include_lib_dependency_test/main_app/src/main_app.erl b/test_projects/include_lib_dependency_test/main_app/src/main_app.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/main_app/src/main_app.erl rename to test_projects/include_lib_dependency_test/main_app/src/main_app.erl diff --git a/test/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl b/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl similarity index 100% rename from test/test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl rename to test_projects/include_lib_dependency_test/normal_dep/include/assert.hrl diff --git a/test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src b/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src similarity index 100% rename from test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src rename to test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.app.src diff --git a/test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl b/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl similarity index 100% rename from test/test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl rename to test_projects/include_lib_dependency_test/normal_dep/src/normal_dep.erl diff --git a/test/test_projects/include_lib_dependency_test/rebar.config b/test_projects/include_lib_dependency_test/rebar.config similarity index 100% rename from test/test_projects/include_lib_dependency_test/rebar.config rename to test_projects/include_lib_dependency_test/rebar.config diff --git a/test_projects/linter/.elp.toml b/test_projects/linter/.elp.toml new file mode 100644 index 0000000000..a887ab835c --- /dev/null +++ b/test_projects/linter/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/linter/..." ] +source_root = "whatsapp/elp/test_projects/linter" diff --git a/test/test_projects/linter/.elp_lint.toml b/test_projects/linter/.elp_lint.toml similarity index 100% rename from test/test_projects/linter/.elp_lint.toml rename to test_projects/linter/.elp_lint.toml diff --git a/test/test_projects/linter/.gitignore b/test_projects/linter/.gitignore similarity index 100% rename from test/test_projects/linter/.gitignore rename to test_projects/linter/.gitignore diff --git a/test/test_projects/linter/app_a/include/app_a.hrl b/test_projects/linter/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/linter/app_a/include/app_a.hrl rename to test_projects/linter/app_a/include/app_a.hrl diff --git a/test/test_projects/linter/app_a/src/app_a.app.src b/test_projects/linter/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/linter/app_a/src/app_a.app.src rename to test_projects/linter/app_a/src/app_a.app.src diff --git a/test/test_projects/linter/app_a/src/app_a.erl b/test_projects/linter/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/linter/app_a/src/app_a.erl rename to test_projects/linter/app_a/src/app_a.erl diff --git a/test/test_projects/linter/app_a/src/app_a_edoc.erl b/test_projects/linter/app_a/src/app_a_edoc.erl similarity index 100% rename from test/test_projects/linter/app_a/src/app_a_edoc.erl rename to test_projects/linter/app_a/src/app_a_edoc.erl diff --git a/test/test_projects/linter/app_a/src/app_a_ssr.erl b/test_projects/linter/app_a/src/app_a_ssr.erl similarity index 100% rename from test/test_projects/linter/app_a/src/app_a_ssr.erl rename to test_projects/linter/app_a/src/app_a_ssr.erl diff --git a/test/test_projects/linter/app_a/src/app_a_unused_param.erl b/test_projects/linter/app_a/src/app_a_unused_param.erl similarity index 100% rename from test/test_projects/linter/app_a/src/app_a_unused_param.erl rename to test_projects/linter/app_a/src/app_a_unused_param.erl diff --git a/test/test_projects/linter/app_a/src/custom_function_matches.erl b/test_projects/linter/app_a/src/custom_function_matches.erl similarity index 100% rename from test/test_projects/linter/app_a/src/custom_function_matches.erl rename to test_projects/linter/app_a/src/custom_function_matches.erl diff --git a/test/test_projects/linter/app_a/src/expression_updates_literal.erl b/test_projects/linter/app_a/src/expression_updates_literal.erl similarity index 100% rename from test/test_projects/linter/app_a/src/expression_updates_literal.erl rename to test_projects/linter/app_a/src/expression_updates_literal.erl diff --git a/test/test_projects/linter/app_a/src/spelling.erl b/test_projects/linter/app_a/src/spelling.erl similarity index 100% rename from test/test_projects/linter/app_a/src/spelling.erl rename to test_projects/linter/app_a/src/spelling.erl diff --git a/test/test_projects/linter/app_a/test/app_a_SUITE.erl b/test_projects/linter/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_SUITE.erl rename to test_projects/linter/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/linter/app_a/test/app_a_test_helpers.erl b/test_projects/linter/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_test_helpers.erl rename to test_projects/linter/app_a/test/app_a_test_helpers.erl diff --git a/test/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl b/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test_projects/linter/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl b/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl rename to test_projects/linter/app_a/test/app_a_unreachable_test_SUITE.erl diff --git a/test/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl b/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test/test_projects/linter/app_a/test/app_test_helpers_no_errors.erl rename to test_projects/linter/app_a/test/app_test_helpers_no_errors.erl diff --git a/test/test_projects/linter/app_b/src/app_b.app.src b/test_projects/linter/app_b/src/app_b.app.src similarity index 100% rename from test/test_projects/linter/app_b/src/app_b.app.src rename to test_projects/linter/app_b/src/app_b.app.src diff --git a/test/test_projects/linter/app_b/src/app_b.erl b/test_projects/linter/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/linter/app_b/src/app_b.erl rename to test_projects/linter/app_b/src/app_b.erl diff --git a/test/test_projects/linter/app_b/src/app_b_unused_param.erl b/test_projects/linter/app_b/src/app_b_unused_param.erl similarity index 100% rename from test/test_projects/linter/app_b/src/app_b_unused_param.erl rename to test_projects/linter/app_b/src/app_b_unused_param.erl diff --git a/test/test_projects/linter/elp_lint_adhoc.toml b/test_projects/linter/elp_lint_adhoc.toml similarity index 100% rename from test/test_projects/linter/elp_lint_adhoc.toml rename to test_projects/linter/elp_lint_adhoc.toml diff --git a/test/test_projects/linter/elp_lint_custom_function_matches.toml b/test_projects/linter/elp_lint_custom_function_matches.toml similarity index 100% rename from test/test_projects/linter/elp_lint_custom_function_matches.toml rename to test_projects/linter/elp_lint_custom_function_matches.toml diff --git a/test/test_projects/linter/elp_lint_ssr_adhoc.toml b/test_projects/linter/elp_lint_ssr_adhoc.toml similarity index 100% rename from test/test_projects/linter/elp_lint_ssr_adhoc.toml rename to test_projects/linter/elp_lint_ssr_adhoc.toml diff --git a/test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml b/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml similarity index 100% rename from test/test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml rename to test_projects/linter/elp_lint_ssr_adhoc_parse_fail.toml diff --git a/test/test_projects/linter/elp_lint_test1.toml b/test_projects/linter/elp_lint_test1.toml similarity index 100% rename from test/test_projects/linter/elp_lint_test1.toml rename to test_projects/linter/elp_lint_test1.toml diff --git a/test/test_projects/linter/elp_lint_test2.toml b/test_projects/linter/elp_lint_test2.toml similarity index 100% rename from test/test_projects/linter/elp_lint_test2.toml rename to test_projects/linter/elp_lint_test2.toml diff --git a/test/test_projects/linter/elp_lint_test_ignore.toml b/test_projects/linter/elp_lint_test_ignore.toml similarity index 100% rename from test/test_projects/linter/elp_lint_test_ignore.toml rename to test_projects/linter/elp_lint_test_ignore.toml diff --git a/test/test_projects/linter/elp_lint_warnings_as_errors.toml b/test_projects/linter/elp_lint_warnings_as_errors.toml similarity index 100% rename from test/test_projects/linter/elp_lint_warnings_as_errors.toml rename to test_projects/linter/elp_lint_warnings_as_errors.toml diff --git a/test/test_projects/linter/rebar.config b/test_projects/linter/rebar.config similarity index 100% rename from test/test_projects/linter/rebar.config rename to test_projects/linter/rebar.config diff --git a/test_projects/linter_bad_config/.elp.toml b/test_projects/linter_bad_config/.elp.toml new file mode 100644 index 0000000000..a887ab835c --- /dev/null +++ b/test_projects/linter_bad_config/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/linter/..." ] +source_root = "whatsapp/elp/test_projects/linter" diff --git a/test/test_projects/linter_bad_config/.elp_lint.toml b/test_projects/linter_bad_config/.elp_lint.toml similarity index 100% rename from test/test_projects/linter_bad_config/.elp_lint.toml rename to test_projects/linter_bad_config/.elp_lint.toml diff --git a/test/test_projects/linter_bad_config/.gitignore b/test_projects/linter_bad_config/.gitignore similarity index 100% rename from test/test_projects/linter_bad_config/.gitignore rename to test_projects/linter_bad_config/.gitignore diff --git a/test/test_projects/linter_bad_config/app_a/include/app_a.hrl b/test_projects/linter_bad_config/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/linter_bad_config/app_a/include/app_a.hrl rename to test_projects/linter_bad_config/app_a/include/app_a.hrl diff --git a/test/test_projects/linter_bad_config/app_a/src/app_a.app.src b/test_projects/linter_bad_config/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/linter_bad_config/app_a/src/app_a.app.src rename to test_projects/linter_bad_config/app_a/src/app_a.app.src diff --git a/test/test_projects/linter_bad_config/app_a/src/app_a.erl b/test_projects/linter_bad_config/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/linter_bad_config/app_a/src/app_a.erl rename to test_projects/linter_bad_config/app_a/src/app_a.erl diff --git a/test_projects/linter_bad_config/linter/.elp.toml b/test_projects/linter_bad_config/linter/.elp.toml new file mode 100644 index 0000000000..a887ab835c --- /dev/null +++ b/test_projects/linter_bad_config/linter/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/linter/..." ] +source_root = "whatsapp/elp/test_projects/linter" diff --git a/test/test_projects/linter_bad_config/linter/.elp_lint.toml b/test_projects/linter_bad_config/linter/.elp_lint.toml similarity index 100% rename from test/test_projects/linter_bad_config/linter/.elp_lint.toml rename to test_projects/linter_bad_config/linter/.elp_lint.toml diff --git a/test/test_projects/linter_bad_config/linter/.gitignore b/test_projects/linter_bad_config/linter/.gitignore similarity index 100% rename from test/test_projects/linter_bad_config/linter/.gitignore rename to test_projects/linter_bad_config/linter/.gitignore diff --git a/test/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl b/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/include/app_a.hrl rename to test_projects/linter_bad_config/linter/app_a/include/app_a.hrl diff --git a/test/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src b/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/src/app_a.app.src rename to test_projects/linter_bad_config/linter/app_a/src/app_a.app.src diff --git a/test/test_projects/linter_bad_config/linter/app_a/src/app_a.erl b/test_projects/linter_bad_config/linter/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/src/app_a.erl rename to test_projects/linter_bad_config/linter/app_a/src/app_a.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl b/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl rename to test_projects/linter_bad_config/linter/app_a/src/app_a_unused_param.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl b/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl b/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl b/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl b/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl rename to test_projects/linter_bad_config/linter/app_a/test/app_test_helpers_no_errors.erl diff --git a/test/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src b/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_b/src/app_b.app.src rename to test_projects/linter_bad_config/linter/app_b/src/app_b.app.src diff --git a/test/test_projects/linter_bad_config/linter/app_b/src/app_b.erl b/test_projects/linter_bad_config/linter/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_b/src/app_b.erl rename to test_projects/linter_bad_config/linter/app_b/src/app_b.erl diff --git a/test/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl b/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl similarity index 100% rename from test/test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl rename to test_projects/linter_bad_config/linter/app_b/src/app_b_unused_param.erl diff --git a/test/test_projects/linter_bad_config/linter/rebar.config b/test_projects/linter_bad_config/linter/rebar.config similarity index 100% rename from test/test_projects/linter_bad_config/linter/rebar.config rename to test_projects/linter_bad_config/linter/rebar.config diff --git a/test/test_projects/linter_bad_config/rebar.config b/test_projects/linter_bad_config/rebar.config similarity index 100% rename from test/test_projects/linter_bad_config/rebar.config rename to test_projects/linter_bad_config/rebar.config diff --git a/test_projects/parse_error/.elp.toml b/test_projects/parse_error/.elp.toml new file mode 100644 index 0000000000..bf2c1ad580 --- /dev/null +++ b/test_projects/parse_error/.elp.toml @@ -0,0 +1,8 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/parse_error/..." ] +source_root = "whatsapp/elp/test_projects/parse_error" + +[eqwalizer] +enable_all = false diff --git a/test/test_projects/parse_error/.gitignore b/test_projects/parse_error/.gitignore similarity index 100% rename from test/test_projects/parse_error/.gitignore rename to test_projects/parse_error/.gitignore diff --git a/test/test_projects/parse_error/.rebar.root b/test_projects/parse_error/.rebar.root similarity index 100% rename from test/test_projects/parse_error/.rebar.root rename to test_projects/parse_error/.rebar.root diff --git a/test/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src b/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/parse_error/eqwalizer/src/eqwalizer.app.src rename to test_projects/parse_error/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/parse_error/eqwalizer/src/eqwalizer.erl b/test_projects/parse_error/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test/test_projects/parse_error/eqwalizer/src/eqwalizer.erl rename to test_projects/parse_error/eqwalizer/src/eqwalizer.erl diff --git a/test/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl b/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/parse_error/eqwalizer/src/eqwalizer_specs.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src b/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a.app.src rename to test_projects/parse_error/parse_error_a/src/parse_error_a.app.src diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_bad.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_reference_bad.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_syntax_error.erl diff --git a/test/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl b/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl similarity index 100% rename from test/test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl rename to test_projects/parse_error/parse_error_a/src/parse_error_a_worst.erl diff --git a/test/test_projects/parse_error/rebar.config b/test_projects/parse_error/rebar.config similarity index 100% rename from test/test_projects/parse_error/rebar.config rename to test_projects/parse_error/rebar.config diff --git a/test_projects/standard/.elp.toml b/test_projects/standard/.elp.toml new file mode 100644 index 0000000000..09ff5a4d5a --- /dev/null +++ b/test_projects/standard/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/standard/..." ] +source_root = "whatsapp/elp/test_projects/standard" diff --git a/test/test_projects/standard/.gitignore b/test_projects/standard/.gitignore similarity index 100% rename from test/test_projects/standard/.gitignore rename to test_projects/standard/.gitignore diff --git a/test/test_projects/standard/.rebar.root b/test_projects/standard/.rebar.root similarity index 100% rename from test/test_projects/standard/.rebar.root rename to test_projects/standard/.rebar.root diff --git a/test/test_projects/standard/app_a/.eqwalizer b/test_projects/standard/app_a/.eqwalizer similarity index 100% rename from test/test_projects/standard/app_a/.eqwalizer rename to test_projects/standard/app_a/.eqwalizer diff --git a/test/test_projects/standard/app_a/extra/app_a.erl b/test_projects/standard/app_a/extra/app_a.erl similarity index 100% rename from test/test_projects/standard/app_a/extra/app_a.erl rename to test_projects/standard/app_a/extra/app_a.erl diff --git a/test/test_projects/standard/app_a/include/app_a.hrl b/test_projects/standard/app_a/include/app_a.hrl similarity index 100% rename from test/test_projects/standard/app_a/include/app_a.hrl rename to test_projects/standard/app_a/include/app_a.hrl diff --git a/test/test_projects/linter_config/app_a/src/app_a.app.src b/test_projects/standard/app_a/src/app_a.app.src similarity index 100% rename from test/test_projects/linter_config/app_a/src/app_a.app.src rename to test_projects/standard/app_a/src/app_a.app.src diff --git a/test/test_projects/standard/app_a/src/app_a.erl b/test_projects/standard/app_a/src/app_a.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a.erl rename to test_projects/standard/app_a/src/app_a.erl diff --git a/test/test_projects/standard/app_a/src/app_a_errors_generated.erl b/test_projects/standard/app_a/src/app_a_errors_generated.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_errors_generated.erl rename to test_projects/standard/app_a/src/app_a_errors_generated.erl diff --git a/test/test_projects/standard/app_a/src/app_a_fixme.erl b/test_projects/standard/app_a/src/app_a_fixme.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_fixme.erl rename to test_projects/standard/app_a/src/app_a_fixme.erl diff --git a/test/test_projects/standard/app_a/src/app_a_ignored.erl b/test_projects/standard/app_a/src/app_a_ignored.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_ignored.erl rename to test_projects/standard/app_a/src/app_a_ignored.erl diff --git a/test/test_projects/standard/app_a/src/app_a_lists.erl b/test_projects/standard/app_a/src/app_a_lists.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_lists.erl rename to test_projects/standard/app_a/src/app_a_lists.erl diff --git a/test/test_projects/standard/app_a/src/app_a_mod2.erl b/test_projects/standard/app_a/src/app_a_mod2.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_mod2.erl rename to test_projects/standard/app_a/src/app_a_mod2.erl diff --git a/test/test_projects/standard/app_a/src/app_a_no_errors.erl b/test_projects/standard/app_a/src/app_a_no_errors.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_no_errors.erl rename to test_projects/standard/app_a/src/app_a_no_errors.erl diff --git a/test/test_projects/standard/app_a/src/app_a_no_errors_generated.erl b/test_projects/standard/app_a/src/app_a_no_errors_generated.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_no_errors_generated.erl rename to test_projects/standard/app_a/src/app_a_no_errors_generated.erl diff --git a/test/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl b/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl similarity index 100% rename from test/test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl rename to test_projects/standard/app_a/src/app_a_no_errors_opted_in.erl diff --git a/test/test_projects/standard/app_a/test/app_a_SUITE.erl b/test_projects/standard/app_a/test/app_a_SUITE.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_a_SUITE.erl rename to test_projects/standard/app_a/test/app_a_SUITE.erl diff --git a/test/test_projects/standard/app_a/test/app_a_test_helpers.erl b/test_projects/standard/app_a/test/app_a_test_helpers.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_a_test_helpers.erl rename to test_projects/standard/app_a/test/app_a_test_helpers.erl diff --git a/test/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl b/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl rename to test_projects/standard/app_a/test/app_a_test_helpers_not_opted_in.erl diff --git a/test/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl b/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl similarity index 100% rename from test/test_projects/standard/app_a/test/app_test_helpers_no_errors.erl rename to test_projects/standard/app_a/test/app_test_helpers_no_errors.erl diff --git a/test/test_projects/linter_config/app_b/src/app_b.app.src b/test_projects/standard/app_b/src/app_b.app.src similarity index 100% rename from test/test_projects/linter_config/app_b/src/app_b.app.src rename to test_projects/standard/app_b/src/app_b.app.src diff --git a/test/test_projects/standard/app_b/src/app_b.erl b/test_projects/standard/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/standard/app_b/src/app_b.erl rename to test_projects/standard/app_b/src/app_b.erl diff --git a/test/test_projects/standard/eqwalizer/src/eqwalizer.app.src b/test_projects/standard/eqwalizer/src/eqwalizer.app.src similarity index 100% rename from test/test_projects/standard/eqwalizer/src/eqwalizer.app.src rename to test_projects/standard/eqwalizer/src/eqwalizer.app.src diff --git a/test/test_projects/standard/eqwalizer/src/eqwalizer.erl b/test_projects/standard/eqwalizer/src/eqwalizer.erl similarity index 100% rename from test/test_projects/standard/eqwalizer/src/eqwalizer.erl rename to test_projects/standard/eqwalizer/src/eqwalizer.erl diff --git a/test/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl b/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl similarity index 100% rename from test/test_projects/standard/eqwalizer/src/eqwalizer_specs.erl rename to test_projects/standard/eqwalizer/src/eqwalizer_specs.erl diff --git a/test/test_projects/standard/erlang_ls.config b/test_projects/standard/erlang_ls.config similarity index 100% rename from test/test_projects/standard/erlang_ls.config rename to test_projects/standard/erlang_ls.config diff --git a/test/test_projects/standard/rebar.config b/test_projects/standard/rebar.config similarity index 100% rename from test/test_projects/standard/rebar.config rename to test_projects/standard/rebar.config diff --git a/test_projects/xref/.elp.toml b/test_projects/xref/.elp.toml new file mode 100644 index 0000000000..afda912287 --- /dev/null +++ b/test_projects/xref/.elp.toml @@ -0,0 +1,5 @@ +[buck] +enabled = true +build_deps = false +included_targets = [ "fbcode//whatsapp/elp/test_projects/xref/..." ] +source_root = "whatsapp/elp/test_projects/xref" diff --git a/test/test_projects/xref/app_a/src/unavailable_type.erl b/test_projects/xref/app_a/src/unavailable_type.erl similarity index 100% rename from test/test_projects/xref/app_a/src/unavailable_type.erl rename to test_projects/xref/app_a/src/unavailable_type.erl diff --git a/test/test_projects/xref/app_b/src/app_b.erl b/test_projects/xref/app_b/src/app_b.erl similarity index 100% rename from test/test_projects/xref/app_b/src/app_b.erl rename to test_projects/xref/app_b/src/app_b.erl diff --git a/test/test_projects/xref/app_c/src/app_c.erl b/test_projects/xref/app_c/src/app_c.erl similarity index 100% rename from test/test_projects/xref/app_c/src/app_c.erl rename to test_projects/xref/app_c/src/app_c.erl diff --git a/test/test_projects/xref/elp_lint_unavailable_type.toml b/test_projects/xref/elp_lint_unavailable_type.toml similarity index 100% rename from test/test_projects/xref/elp_lint_unavailable_type.toml rename to test_projects/xref/elp_lint_unavailable_type.toml diff --git a/website/docs/erlang-error-index/w/W0060.md b/website/docs/erlang-error-index/w/W0060.md deleted file mode 100644 index 91b972dacf..0000000000 --- a/website/docs/erlang-error-index/w/W0060.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -sidebar_position: 60 ---- - -# W0060 - Bound Variable in LHS - -## Error - -```erlang -handle_request(Message) -> - Message = next_action(). -%% ^^^^^^^ 💡 warning: W0060: Match on a bound variable -``` - -## Explanation - -This diagnostic flags cases where a variable that is already bound appears on the left-hand side (LHS) of a match expression. This can be problematic if the binding is not intentional and can lead to subtle bugs. - -Consider the following code snippet: - -```erlang showLineNumbers -foo() -> - AA = foo(), - AA = bar(). -``` - -The pattern on line `3` will only match if and only if the result of the call to `bar/0` is the same as the call to `foo/0`. This behaviour could be intentional or not. If not, it can easily lead to bugs. - -An alternative, more explicit, way to express that behaviour - when intentional - could be: - -```erlang showLineNumbers -foo() -> - AA = foo(), - BB = bar(), - AA = BB. -``` - -Or using an assertion: - -```erlang showLineNumbers -foo() -> - AA = foo(), - ?assertEqual(AA, bar()). -``` - -## Semantic highlighting - -Note that we also have semantic highlighting of the more general case, where a bound variable appears in any pattern. diff --git a/website/docs/get-started/editors/emacs.md b/website/docs/get-started/editors/emacs.md index fab357f4a4..072e6902da 100644 --- a/website/docs/get-started/editors/emacs.md +++ b/website/docs/get-started/editors/emacs.md @@ -37,8 +37,9 @@ additional configuration options. ### Semantic tokens -Semantic token support has been added to eglot, but is not yet in the released -version. But it is possible to install the updated version of eglot. +Semantic token support has been added to eglot, but is not yet in the +released version. But it is possible to install the updated version +of eglot. To do so, add @@ -51,14 +52,8 @@ to your `init.el`, then run `M-x eglot-upgrade-eglot` Once upgraded, add the following to the `(use-package` entry for `eglot` ```elisp -(setq-default eglot-workspace-configuration - ;; Run `elp config` to see that options can be used here - ;; Use `eglot-show-workspace-configuration` to see what is sent - '(:elp (:highlightDynamic (:enable t) - :typesOnHover (:enable t) )) - - eglot-semantic-token-modifiers - '("bound" "exported_function" "exported_type" "deprecated_function" "type_dynamic")) + (setq eglot-semantic-token-modifiers ' + ("bound" "exported_function" "exported_type" "deprecated_function" "type_dynamic")) ;; Each face name arises as a template from the modifiers as ;; "eglot-semantic-%s-face" @@ -97,6 +92,7 @@ Once upgraded, add the following to the `(use-package` entry for `eglot` (eglot--widening (font-lock-flush))))) ``` + ## lsp-mode Install the `lsp-mode` package, which is a generic Emacs client for LSP servers.