Skip to content

Commit e626789

Browse files
alanzmeta-codesync[bot]
authored andcommitted
16/n ifdef: Add is_form_active_with_env for cross-file context
Summary: - Add `is_form_active_with_env` method to `FormList` that accepts a caller-provided `MacroEnvironment` instead of building one from `project_macro_environment` - This is needed for included files where the caller has accumulated macro state (e.g., include guards defined by a previous inclusion) - Add test `include_guard_with_env` verifying that an include guard header is active on first inclusion (no guard defined) and inactive on second inclusion (guard predefined in env) Reviewed By: TD5 Differential Revision: D94370681 fbshipit-source-id: 9ea57a973cccbfb5cd2d09d76e79392e577bdb77
1 parent fe01aee commit e626789

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

crates/hir/src/form_list.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ use la_arena::Idx;
6565
use la_arena::IdxRange;
6666

6767
use crate::Diagnostic;
68+
use crate::MacroEnvironment;
6869
use crate::MacroName;
6970
use crate::Name;
7071
use crate::NameArity;
@@ -276,6 +277,30 @@ impl FormList {
276277
}
277278
}
278279
}
280+
281+
/// Evaluates whether a form is active using a caller-provided macro environment.
282+
///
283+
/// Unlike `is_form_active`, this does not use `project_macro_environment` to build
284+
/// the environment. This is needed for included files where the caller has accumulated
285+
/// macro state (e.g., include guards defined by a previous inclusion).
286+
pub fn is_form_active_with_env(
287+
&self,
288+
db: &dyn DefDatabase,
289+
file_id: FileId,
290+
pp_ctx: &FormPPContext,
291+
env: Arc<MacroEnvironment>,
292+
) -> PPConditionResult {
293+
match pp_ctx.condition {
294+
None => PPConditionResult::Active,
295+
Some(cond_id) => {
296+
if !env.new_ifdef {
297+
return PPConditionResult::Active;
298+
}
299+
let analysis = db.file_preprocessor_analysis(file_id, env);
300+
analysis.is_condition_active(cond_id)
301+
}
302+
}
303+
}
279304
}
280305

281306
#[derive(Debug, Default, Eq, PartialEq)]

crates/hir/src/form_list/tests.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88
* above-listed licenses.
99
*/
1010

11+
use std::sync::Arc;
12+
1113
use elp_base_db::fixture::WithFixture;
1214
use expect_test::Expect;
1315
use expect_test::expect;
1416

17+
use crate::MacroEnvironment;
18+
use crate::MacroName;
19+
use crate::Name;
1520
use crate::PPDirective;
1621
use crate::db::DefDatabase;
1722
use crate::form_list::PPConditionResult;
@@ -892,6 +897,45 @@ in_inner_else() -> ok.
892897
}
893898
}
894899

900+
#[test]
901+
fn include_guard_with_env() {
902+
// Header with an include guard pattern.
903+
// is_form_active (no GUARD in project env) → Active (first inclusion)
904+
// is_form_active_with_env (GUARD predefined) → Inactive (second inclusion)
905+
let (db, files, _) = TestDB::with_many_files(
906+
r#"
907+
//- /src/main.erl
908+
-module(main).
909+
//- /src/guard.hrl
910+
-ifndef(GUARD).
911+
-define(GUARD, 1).
912+
foo() -> ok.
913+
-endif.
914+
"#,
915+
);
916+
917+
let header_file_id = files[1];
918+
let form_list = db.file_form_list(header_file_id);
919+
920+
// First inclusion: GUARD not defined, ifndef is active
921+
for (_idx, clause) in form_list.function_clauses() {
922+
let result = form_list.is_form_active(&db, header_file_id, &clause.pp_ctx, None);
923+
assert_eq!(result, PPConditionResult::Active);
924+
}
925+
926+
// Second inclusion: GUARD predefined in env, ifndef is inactive
927+
let mut env = MacroEnvironment::new();
928+
env.set_new_ifdef(true);
929+
env.define(MacroName::new(Name::from_erlang_service("GUARD"), None));
930+
let env = Arc::new(env);
931+
932+
for (_idx, clause) in form_list.function_clauses() {
933+
let result =
934+
form_list.is_form_active_with_env(&db, header_file_id, &clause.pp_ctx, env.clone());
935+
assert_eq!(result, PPConditionResult::Inactive);
936+
}
937+
}
938+
895939
#[test]
896940
fn resolved_include_populated() {
897941
// Test that ConditionEnv.resolved_include is populated for include directives

0 commit comments

Comments
 (0)