Skip to content

Commit 36be913

Browse files
committed
Auto merge of #15709 - Veykril:runnables-custom-main, r=Veykril
fix: Recognize custom main function as binary entrypoint for runnables
2 parents 7b8330f + fe39816 commit 36be913

File tree

3 files changed

+72
-23
lines changed

3 files changed

+72
-23
lines changed

crates/hir-def/src/attr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ impl Attrs {
215215
self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec())
216216
}
217217

218+
pub fn export_name(&self) -> Option<&SmolStr> {
219+
self.by_key("export_name").string_value()
220+
}
221+
218222
pub fn is_proc_macro(&self) -> bool {
219223
self.by_key("proc_macro").exists()
220224
}

crates/hir/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,17 @@ impl Function {
19711971
db.function_data(self.id).attrs.is_test()
19721972
}
19731973

1974+
/// is this a `fn main` or a function with an `export_name` of `main`?
1975+
pub fn is_main(self, db: &dyn HirDatabase) -> bool {
1976+
if !self.module(db).is_crate_root() {
1977+
return false;
1978+
}
1979+
let data = db.function_data(self.id);
1980+
1981+
data.name.to_smol_str() == "main"
1982+
|| data.attrs.export_name().map(core::ops::Deref::deref) == Some("main")
1983+
}
1984+
19741985
/// Does this function have the ignore attribute?
19751986
pub fn is_ignore(self, db: &dyn HirDatabase) -> bool {
19761987
db.function_data(self.id).attrs.is_ignore()

crates/ide/src/runnables.rs

+57-23
Original file line numberDiff line numberDiff line change
@@ -308,19 +308,17 @@ pub(crate) fn runnable_fn(
308308
sema: &Semantics<'_, RootDatabase>,
309309
def: hir::Function,
310310
) -> Option<Runnable> {
311-
let name = def.name(sema.db).to_smol_str();
312-
313-
let root = def.module(sema.db).krate().root_module();
314-
315-
let kind = if name == "main" && def.module(sema.db) == root {
311+
let kind = if def.is_main(sema.db) {
316312
RunnableKind::Bin
317313
} else {
318314
let test_id = || {
319315
let canonical_path = {
320316
let def: hir::ModuleDef = def.into();
321317
def.canonical_path(sema.db)
322318
};
323-
canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name))
319+
canonical_path
320+
.map(TestId::Path)
321+
.unwrap_or(TestId::Name(def.name(sema.db).to_smol_str()))
324322
};
325323

326324
if def.is_test(sema.db) {
@@ -587,6 +585,9 @@ mod tests {
587585
$0
588586
fn main() {}
589587
588+
#[export_name = "main"]
589+
fn __cortex_m_rt_main_trampoline() {}
590+
590591
#[test]
591592
fn test_foo() {}
592593
@@ -604,7 +605,7 @@ mod not_a_root {
604605
fn main() {}
605606
}
606607
"#,
607-
&[TestMod, Bin, Test, Test, Test, Bench],
608+
&[TestMod, Bin, Bin, Test, Test, Test, Bench],
608609
expect![[r#"
609610
[
610611
Runnable {
@@ -613,7 +614,7 @@ mod not_a_root {
613614
file_id: FileId(
614615
0,
615616
),
616-
full_range: 0..190,
617+
full_range: 0..253,
617618
name: "",
618619
kind: Module,
619620
},
@@ -642,8 +643,22 @@ mod not_a_root {
642643
file_id: FileId(
643644
0,
644645
),
645-
full_range: 15..39,
646-
focus_range: 26..34,
646+
full_range: 15..76,
647+
focus_range: 42..71,
648+
name: "__cortex_m_rt_main_trampoline",
649+
kind: Function,
650+
},
651+
kind: Bin,
652+
cfg: None,
653+
},
654+
Runnable {
655+
use_name_in_title: false,
656+
nav: NavigationTarget {
657+
file_id: FileId(
658+
0,
659+
),
660+
full_range: 78..102,
661+
focus_range: 89..97,
647662
name: "test_foo",
648663
kind: Function,
649664
},
@@ -663,8 +678,8 @@ mod not_a_root {
663678
file_id: FileId(
664679
0,
665680
),
666-
full_range: 41..92,
667-
focus_range: 73..87,
681+
full_range: 104..155,
682+
focus_range: 136..150,
668683
name: "test_full_path",
669684
kind: Function,
670685
},
@@ -684,8 +699,8 @@ mod not_a_root {
684699
file_id: FileId(
685700
0,
686701
),
687-
full_range: 94..128,
688-
focus_range: 115..123,
702+
full_range: 157..191,
703+
focus_range: 178..186,
689704
name: "test_foo",
690705
kind: Function,
691706
},
@@ -705,8 +720,8 @@ mod not_a_root {
705720
file_id: FileId(
706721
0,
707722
),
708-
full_range: 130..152,
709-
focus_range: 142..147,
723+
full_range: 193..215,
724+
focus_range: 205..210,
710725
name: "bench",
711726
kind: Function,
712727
},
@@ -1655,12 +1670,18 @@ macro_rules! gen2 {
16551670
}
16561671
}
16571672
}
1673+
macro_rules! gen_main {
1674+
() => {
1675+
fn main() {}
1676+
}
1677+
}
16581678
mod tests {
16591679
gen!();
16601680
}
16611681
gen2!();
1682+
gen_main!();
16621683
"#,
1663-
&[TestMod, TestMod, Test, Test, TestMod],
1684+
&[TestMod, TestMod, Test, Test, TestMod, Bin],
16641685
expect![[r#"
16651686
[
16661687
Runnable {
@@ -1669,7 +1690,7 @@ gen2!();
16691690
file_id: FileId(
16701691
0,
16711692
),
1672-
full_range: 0..237,
1693+
full_range: 0..315,
16731694
name: "",
16741695
kind: Module,
16751696
},
@@ -1684,8 +1705,8 @@ gen2!();
16841705
file_id: FileId(
16851706
0,
16861707
),
1687-
full_range: 202..227,
1688-
focus_range: 206..211,
1708+
full_range: 267..292,
1709+
focus_range: 271..276,
16891710
name: "tests",
16901711
kind: Module,
16911712
description: "mod tests",
@@ -1701,7 +1722,7 @@ gen2!();
17011722
file_id: FileId(
17021723
0,
17031724
),
1704-
full_range: 218..225,
1725+
full_range: 283..290,
17051726
name: "foo_test",
17061727
kind: Function,
17071728
},
@@ -1721,7 +1742,7 @@ gen2!();
17211742
file_id: FileId(
17221743
0,
17231744
),
1724-
full_range: 228..236,
1745+
full_range: 293..301,
17251746
name: "foo_test2",
17261747
kind: Function,
17271748
},
@@ -1741,7 +1762,7 @@ gen2!();
17411762
file_id: FileId(
17421763
0,
17431764
),
1744-
full_range: 228..236,
1765+
full_range: 293..301,
17451766
name: "tests2",
17461767
kind: Module,
17471768
description: "mod tests2",
@@ -1751,6 +1772,19 @@ gen2!();
17511772
},
17521773
cfg: None,
17531774
},
1775+
Runnable {
1776+
use_name_in_title: false,
1777+
nav: NavigationTarget {
1778+
file_id: FileId(
1779+
0,
1780+
),
1781+
full_range: 302..314,
1782+
name: "main",
1783+
kind: Function,
1784+
},
1785+
kind: Bin,
1786+
cfg: None,
1787+
},
17541788
]
17551789
"#]],
17561790
);

0 commit comments

Comments
 (0)