diff --git a/src/parser.rs b/src/parser.rs index d8adb37..069bd2d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,4 @@ -use std::collections::{btree_map, hash_map, BTreeMap}; +use std::collections::{btree_map, hash_map, BTreeMap, HashSet}; use std::fmt; use std::fs::File; use std::io::{self, BufRead, BufReader, Read}; @@ -6,6 +6,8 @@ use std::num::ParseIntError; use std::path::Path; use std::str; +use log::error; + use xml::events::{BytesStart, Event}; use xml::Reader; @@ -125,6 +127,8 @@ pub fn parse_lcov( let mut cur_lines = BTreeMap::new(); let mut cur_branches = BTreeMap::new(); let mut cur_functions = FxHashMap::default(); + // Only needed for the workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1597997. + let mut cur_fndas = HashSet::new(); let mut results = Vec::new(); @@ -182,9 +186,24 @@ pub fn parse_lcov( "FN" => { let mut f_splits = value.splitn(2, ','); let start = try_parse_next!(f_splits, l); - let f_name = try_next!(f_splits, l); + let mut f_name = try_next!(f_splits, l).to_owned(); + + // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1597997. + if f_name == "top-level" { + let mut i = 1; + + while cur_functions.contains_key(&f_name) { + if i == 1 { + error!("{} FN duplicated in a lcov file", f_name); + } + + f_name = format!("top-level{}", i); + i += 1; + } + } + cur_functions.insert( - f_name.to_owned(), + f_name, Function { start, executed: false, @@ -194,8 +213,28 @@ pub fn parse_lcov( "FNDA" => { let mut f_splits = value.splitn(2, ','); let executed = try_next!(f_splits, l) != "0"; - let f_name = try_next!(f_splits, l); - if let Some(f) = cur_functions.get_mut(f_name) { + let mut f_name = try_next!(f_splits, l).to_owned(); + + // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1597997. + let mut is_top_level = false; + if f_name == "top-level" { + is_top_level = true; + + let mut i = 1; + + while cur_fndas.contains(&f_name) { + let new_f_name = format!("top-level{}", i); + i += 1; + + if cur_functions.contains_key(&new_f_name) { + f_name = new_f_name; + } else { + break; + } + } + } + + if let Some(f) = cur_functions.get_mut(&f_name) { f.executed |= executed; } else { return Err(ParserError::Parse(format!( @@ -203,6 +242,10 @@ pub fn parse_lcov( f_name ))); } + + if is_top_level { + cur_fndas.insert(f_name); + } } "BRDA" => { if branch_enabled { @@ -964,6 +1007,288 @@ mod tests { assert!(result.is_err()); } + // Test for the workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1597997. + #[test] + fn test_lcov_parser_duplicate_fn_fnda() { + let f = File::open("./test/duplicate_fn_fnda.info").expect("Failed to open lcov file"); + let file = BufReader::new(&f); + let results = parse_lcov(file, true).unwrap(); + + assert_eq!(results.len(), 1); + + let (ref source_name, ref result) = results[0]; + assert_eq!( + source_name, + "devtools/client/webconsole/components/Output/ConsoleTable.js" + ); + assert_eq!( + result.lines, + [ + (9, 1), + (10, 1), + (11, 1), + (16, 1), + (17, 1), + (18, 1), + (21, 2), + (22, 1), + (25, 2), + (26, 1), + (27, 1), + (28, 1), + (31, 1), + (33, 1), + (35, 1), + (36, 1), + (37, 0), + (38, 0), + (39, 0), + (40, 0), + (41, 0), + (43, 0), + (48, 2), + (49, 2), + (50, 2), + (54, 3), + (55, 2), + (57, 2), + (58, 2), + (59, 0), + (63, 2), + (64, 2), + (65, 2), + (66, 0), + (68, 2), + (69, 2), + (73, 0), + (74, 0), + (75, 0), + (76, 0), + (77, 0), + (80, 2), + (82, 3), + (83, 2), + (84, 2), + (85, 12), + (86, 12), + (87, 6), + (88, 6), + (89, 6), + (90, 6), + (91, 6), + (93, 6), + (97, 2), + (98, 2), + (100, 3), + (101, 2), + (103, 6), + (104, 4), + (105, 4), + (107, 16), + (108, 12), + (110, 12), + (111, 4), + (112, 16), + (113, 8), + (114, 8), + (115, 8), + (116, 8), + (117, 8), + (120, 24), + (121, 24), + (122, 12), + (123, 12), + (124, 12), + (125, 12), + (127, 12), + (131, 4), + (132, 4), + (133, 2), + (135, 3), + (136, 2), + (137, 2), + (140, 2), + (143, 2), + (144, 2), + (145, 0), + (148, 2), + (149, 0), + (152, 2), + (156, 2), + (157, 2), + (158, 0), + (160, 4), + (161, 2), + (162, 2), + (163, 2), + (164, 2), + (165, 2), + (166, 2), + (167, 2), + (170, 2), + (171, 2), + (173, 2), + (176, 2), + (177, 2), + (180, 2), + (181, 0), + (182, 2), + (185, 2), + (187, 2), + (188, 2), + (190, 2), + (191, 2), + (192, 0), + (194, 2), + (195, 2), + (196, 0), + (198, 2), + (199, 2), + (200, 2), + (202, 1), + (203, 1), + (206, 2), + (207, 2), + (208, 2), + (209, 2), + (210, 2), + (211, 0), + (212, 2), + (213, 2), + (219, 2), + (220, 0), + (221, 0), + (226, 2), + (227, 2), + (229, 2), + (230, 2), + (232, 2), + (233, 4), + (234, 12), + (237, 2), + (239, 10), + (240, 8), + (241, 8), + (244, 8), + (245, 6), + (246, 6), + (247, 0), + (248, 0), + (250, 6), + (254, 2), + (255, 4), + (256, 4), + (259, 4), + (260, 4), + (263, 4), + (265, 4), + (266, 2), + (267, 2), + (269, 4), + (270, 2), + (271, 2), + (272, 2), + (275, 2), + (276, 2), + (277, 0), + (279, 0), + (280, 0), + (282, 2), + (285, 4), + (287, 4), + (288, 0), + (294, 2), + (295, 0), + (299, 2), + (300, 2), + (301, 2), + (302, 2), + (306, 2), + (307, 2), + (308, 2), + (309, 2), + (312, 2), + (313, 2), + (314, 2), + (316, 2), + (322, 0), + (323, 0), + (325, 0), + (326, 0), + (328, 0), + (329, 0), + (330, 0), + (333, 0), + (335, 0), + (336, 0), + (337, 0), + (340, 0), + (341, 0), + (342, 0), + (343, 0), + (344, 0), + (346, 0), + (350, 0), + (351, 0), + (352, 0), + (355, 0), + (356, 0), + (359, 0), + (361, 0), + (363, 0), + (364, 0), + (365, 0), + (366, 0), + (367, 0), + (368, 0), + (369, 0), + (370, 0), + (371, 0), + (374, 0), + (375, 0), + (378, 0), + (379, 0), + (380, 0), + (382, 0), + (383, 0), + (386, 0), + (389, 0), + (391, 0), + (392, 0), + (398, 0), + (399, 0), + (403, 0), + (404, 0), + (405, 0), + (406, 0), + (410, 0), + (411, 0), + (412, 0), + (413, 0), + (416, 0), + (417, 0), + (418, 0), + (420, 0), + (422, 1), + ] + .iter() + .cloned() + .collect() + ); + assert!(result.functions.contains_key("top-level")); + let func = result.functions.get("top-level").unwrap(); + assert_eq!(func.start, 1); + assert_eq!(func.executed, true); + assert!(result.functions.contains_key("top-level1")); + let func = result.functions.get("top-level1").unwrap(); + assert_eq!(func.start, 17); + assert_eq!(func.executed, true); + assert!(result.functions.contains_key("top-level2")); + let func = result.functions.get("top-level2").unwrap(); + assert_eq!(func.start, 176); + assert_eq!(func.executed, true); + } + #[test] fn test_parser() { let results = parse_gcov(Path::new("./test/prova.gcov")).unwrap(); diff --git a/src/producer.rs b/src/producer.rs index 259efba..a8fc2aa 100644 --- a/src/producer.rs +++ b/src/producer.rs @@ -655,6 +655,7 @@ mod tests { (ItemFormat::INFO, false, "prova_fn_with_commas.info", false), (ItemFormat::INFO, false, "empty_line.info", false), (ItemFormat::INFO, false, "invalid_DA_record.info", false), + (ItemFormat::INFO, false, "duplicate_fn_fnda.info", false), ( ItemFormat::INFO, false, diff --git a/test/duplicate_fn_fnda.info b/test/duplicate_fn_fnda.info new file mode 100644 index 0000000..5d7d161 --- /dev/null +++ b/test/duplicate_fn_fnda.info @@ -0,0 +1,298 @@ +SF:devtools/client/webconsole/components/Output/ConsoleTable.js +FN:1,top-level +FN:17,top-level +FN:176,top-level +FN:190,top-level +FN:205,top-level +FN:217,top-level +FN:221,top-level +FN:226,top-level +FN:232,top-level +FN:234,top-level +FN:239,top-level +FN:295,top-level +FN:322,top-level +FN:328,top-level +FN:330,top-level +FN:335,top-level +FN:399,top-level +FN:47,top-level +FN:36,top-level +FN:54,top-level +FN:82,top-level +FN:84,top-level +FN:100,top-level +FN:103,top-level +FN:107,top-level +FN:135,top-level +FNDA:1,top-level +FNDA:1,top-level +FNDA:2,top-level +FNDA:2,top-level +FNDA:2,top-level +FNDA:2,top-level +FNDA:2,top-level +FNDA:4,top-level +FNDA:8,top-level +FNDA:8,top-level +FNDA:2,top-level +FNDA:2,top-level +FNDA:2,top-level +FNDA:6,top-level +FNDA:2,top-level +FNDA:4,top-level +FNDA:12,top-level +FNDA:2,top-level +FNF:26 +FNH:18 +BRF:248 +BRH:79 +DA:9,1 +DA:10,1 +DA:11,1 +DA:16,1 +DA:17,1 +DA:18,1 +DA:21,2 +DA:22,1 +DA:25,2 +DA:26,1 +DA:27,1 +DA:28,1 +DA:31,1 +DA:33,1 +DA:35,1 +DA:36,1 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:48,2 +DA:49,2 +DA:50,2 +DA:54,3 +DA:55,2 +DA:57,2 +DA:58,2 +DA:59,0 +DA:63,2 +DA:64,2 +DA:65,2 +DA:66,0 +DA:68,2 +DA:69,2 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:80,2 +DA:82,3 +DA:83,2 +DA:84,2 +DA:85,12 +DA:86,12 +DA:87,6 +DA:88,6 +DA:89,6 +DA:90,6 +DA:91,6 +DA:93,6 +DA:97,2 +DA:98,2 +DA:100,3 +DA:101,2 +DA:103,6 +DA:104,4 +DA:105,4 +DA:107,16 +DA:108,12 +DA:110,12 +DA:111,4 +DA:112,16 +DA:113,8 +DA:114,8 +DA:115,8 +DA:116,8 +DA:117,8 +DA:120,24 +DA:121,24 +DA:122,12 +DA:123,12 +DA:124,12 +DA:125,12 +DA:127,12 +DA:131,4 +DA:132,4 +DA:133,2 +DA:135,3 +DA:136,2 +DA:137,2 +DA:140,2 +DA:143,2 +DA:144,2 +DA:145,0 +DA:148,2 +DA:149,0 +DA:152,2 +DA:156,2 +DA:157,2 +DA:158,0 +DA:160,4 +DA:161,2 +DA:162,2 +DA:163,2 +DA:164,2 +DA:165,2 +DA:166,2 +DA:167,2 +DA:170,2 +DA:171,2 +DA:173,2 +DA:176,2 +DA:177,2 +DA:180,2 +DA:181,0 +DA:182,2 +DA:185,2 +DA:187,2 +DA:188,2 +DA:190,2 +DA:191,2 +DA:192,0 +DA:194,2 +DA:195,2 +DA:196,0 +DA:198,2 +DA:199,2 +DA:200,2 +DA:202,1 +DA:203,1 +DA:206,2 +DA:207,2 +DA:208,2 +DA:209,2 +DA:210,2 +DA:211,0 +DA:212,2 +DA:213,2 +DA:219,2 +DA:220,0 +DA:221,0 +DA:226,2 +DA:227,2 +DA:229,2 +DA:230,2 +DA:232,2 +DA:233,4 +DA:234,12 +DA:237,2 +DA:239,10 +DA:240,8 +DA:241,8 +DA:244,8 +DA:245,6 +DA:246,6 +DA:247,0 +DA:248,0 +DA:250,6 +DA:254,2 +DA:255,4 +DA:256,4 +DA:259,4 +DA:260,4 +DA:263,4 +DA:265,4 +DA:266,2 +DA:267,2 +DA:269,4 +DA:270,2 +DA:271,2 +DA:272,2 +DA:275,2 +DA:276,2 +DA:277,0 +DA:279,0 +DA:280,0 +DA:282,2 +DA:285,4 +DA:287,4 +DA:288,0 +DA:294,2 +DA:295,0 +DA:299,2 +DA:300,2 +DA:301,2 +DA:302,2 +DA:306,2 +DA:307,2 +DA:308,2 +DA:309,2 +DA:312,2 +DA:313,2 +DA:314,2 +DA:316,2 +DA:322,0 +DA:323,0 +DA:325,0 +DA:326,0 +DA:328,0 +DA:329,0 +DA:330,0 +DA:333,0 +DA:335,0 +DA:336,0 +DA:337,0 +DA:340,0 +DA:341,0 +DA:342,0 +DA:343,0 +DA:344,0 +DA:346,0 +DA:350,0 +DA:351,0 +DA:352,0 +DA:355,0 +DA:356,0 +DA:359,0 +DA:361,0 +DA:363,0 +DA:364,0 +DA:365,0 +DA:366,0 +DA:367,0 +DA:368,0 +DA:369,0 +DA:370,0 +DA:371,0 +DA:374,0 +DA:375,0 +DA:378,0 +DA:379,0 +DA:380,0 +DA:382,0 +DA:383,0 +DA:386,0 +DA:389,0 +DA:391,0 +DA:392,0 +DA:398,0 +DA:399,0 +DA:403,0 +DA:404,0 +DA:405,0 +DA:406,0 +DA:410,0 +DA:411,0 +DA:412,0 +DA:413,0 +DA:416,0 +DA:417,0 +DA:418,0 +DA:420,0 +DA:422,1 +LF:246 +LH:159 +end_of_record