Weihua Sheng

195 papers A* 35A 34B 1C 6Misc 2Journal 67Unranked 44
YearRankTypeTitle / Venue / Authors
2026 J jnl
Robotics Auton. Syst.
Zhidong Su, Weihua Sheng
2026 J jnl
Adv. Eng. Informatics
Ifeoluwa Awotunde, Dharmendra Reddy Chitte, Yongwei Shan, Weihua Sheng, Hossein Khaleghian
2026 J jnl
ACM Trans. Design Autom. Electr. Syst.
Tianji Liu, Nutdranai Jaruthikorn, Shiju Lin, Bentian Jiang, Guannan Guo, Weihua Sheng, Evangeline F. Y. Young
2026 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Shanyi Li, Zhen Zhuang, Mingyu Liu, Weihua Sheng, Bei Yu, Tsung-Yi Ho
2025 conf
MLCAD
Yuntao Lu, Dehua Liang, Siting Liu, Yuhao Ji, Yu Zhang, Xuanqi Chen, Xia Lin, Jinlei Lu, Weihua Sheng, Bei Yu
2025 J jnl
IEEE Trans. Veh. Technol.
Sanzida Hossain, Jiaxing Lu, He Bai, Weihua Sheng
2025 conf
CASE
Dharmendra Reddy Chitte, Fei Liang, Weihua Sheng, Yongwei Shan, Hossein Khaleghian
2025 conf
ISPD
Fangzhou Liu, Guannan Guo, Yuyang Ye, Ziyi Wang, Wenjie Fu, Weihua Sheng, Bei Yu
2025 conf
CASE
Zhanjie Chen, Zhidong Su, Conlan Chesser, Craig Bourlon, Weihua Sheng
2025 conf
CASE
Claudia Pauyac Estrada, Weihua Sheng
2025 J jnl
IEEE Trans. Comput. Aided Des. Integr. Circuits Syst.
Ziyi Wang, Wenqian Zhao, Yuan Pu, Lei Chen, Wilson W. K. Thong, Weihua Sheng, Tsung-Yi Ho, Bei Yu
2025 J jnl
Inf. Fusion
Jialin Zhang, Xianfeng Yuan, Chaoqun Wang, Yong Song, Wenfeng Nie, Fengyu Zhou, Weihua Sheng
2025 J jnl
IEEE Trans. Instrum. Meas.
Xiaoxuan Xing, Xianfeng Yuan, Chaoqun Wang, Wenfeng Nie, Qingyang Xu, Yong Song, Weihua Sheng
2024 J jnl
IEEE Trans. Intell. Transp. Syst.
Jiaxing Lu, Sanzida Hossain, Wakun Lam, Weihua Sheng, He Bai
2024 J jnl
Comput. Aided Civ. Infrastructure Eng.
Guijie Zhu, Jiacheng Liu, Zhun Fan, Duan Yuan, Peili Ma, Meihua Wang, Weihua Sheng, Kelvin C. P. Wang
2024 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Zhongmou Ying, Xianfeng Yuan, Boyi Song, Yong Song, Fengyu Zhou, Weihua Sheng
2024 A conf
IROS
Jiaxing Lu, Sanzida Hossain, Weihua Sheng, He Bai
2024 A* conf
ICRA
Zhidong Su, Weihua Sheng
2024 A conf
IROS
Zhidong Su, Weihua Sheng
2024 J jnl
IEEE Trans. Intell. Transp. Syst.
Chong Li, Zhun Fan, Ying Chen, Huibiao Lin, Laura Moretti, Giuseppe Loprencipe, Weihua Sheng, Kelvin C. P. Wang
2024 A* conf
DAC
Shiju Lin, Guannan Guo, Tsung-Wei Huang, Weihua Sheng, Evangeline F. Y. Young, Martin D. F. Wong
2024 J jnl
Adv. Eng. Informatics
Baojiang Yang, Xianfeng Yuan, Zhongmou Ying, Jialin Zhang, Boyi Song, Yong Song, Fengyu Zhou, Weihua Sheng
2024 J jnl
IEEE Robotics Autom. Lett.
Zhongmou Ying, Xianfeng Yuan, Baojiang Yang, Yong Song, Qingyang Xu, Fengyu Zhou, Weihua Sheng
2024 A* conf
DAC
Shiju Lin, Bentian Jiang, Weihua Sheng, Evangeline F. Y. Young
2023 A* conf
DAC
Xuliang Zhu, Ruofei Tang, Lei Chen, Xing Li, Xin Huang, Mingxuan Yuan, Weihua Sheng, Jianliang Xu
2023 conf
ACM Great Lakes Symposium on VLSI
Xinshi Zang, Lei Chen, Xing Li, Wilson W. K. Thong, Weihua Sheng, Evangeline F. Y. Young, Martin D. F. Wong
2023 conf
ECC
Sanzida Hossain, Jiaxing Lu, He Bai, Weihua Sheng
2023 A* conf
ICRA
Jiaxing Lu, Sanzida Hossain, Weihua Sheng, He Bai
2023 J jnl
CoRR
Chong Li, Zhun Fan, Ying Chen, Huibiao Lin, Laura Moretti, Giuseppe Loprencipe, Weihua Sheng, Kelvin C. P. Wang
2023 A conf
ICCAD
Xing Li, Lei Chen, Jiantang Zhang, Shuang Wen, Weihua Sheng, Yu Huang, Mingxuan Yuan
2023 J jnl
IEEE Robotics Autom. Mag.
Weihua Sheng, Hesheng Wang, Yingzi Lin, Yasuhisa Hirata, Stefano Mazzoleni
2023 A conf
IROS
Sanzida Hossain, Jiaxing Lu, He Bai, Weihua Sheng
2022 J jnl
Frontiers Inf. Technol. Electron. Eng.
Qi Wang, Zhen Fan, Weihua Sheng, Senlin Zhang, Meiqin Liu
2022 A conf
IROS
Jiaxing Lu, Ryan Stracener, Weihua Sheng, He Bai, Sanzida Hossain
2022 J jnl
IEEE Trans. Vis. Comput. Graph.
Mahdi Yazdanpour, Guoliang Fan, Weihua Sheng
2022 J jnl
CoRR
Guijie Zhu, Zhun Fan, Jiacheng Liu, Duan Yuan, Peili Ma, Meihua Wang, Weihua Sheng, Kelvin C. P. Wang
2022 J jnl
IEEE Trans Autom. Sci. Eng.
Ha Manh Do, Karla Conn Welch, Weihua Sheng
2021 J jnl
IEEE Trans Autom. Sci. Eng.
Ha Manh Do, Weihua Sheng, Erin E. Harrington, Alex J. Bishop
2021 A* conf
ICRA
Fei Liang, Ricardo Hernandez, Jiaxing Lu, Brandon Ong, Matthew Jackson Moore, Weihua Sheng, Senlin Zhang
2021 J jnl
IEEE Robotics Autom. Lett.
Zhidong Su, Fei Liang, Ha Manh Do, Alex J. Bishop, Barbara Carlson, Weihua Sheng
2021 J jnl
Int. J. Soc. Robotics
Jianhao Du, Ha Manh Do, Weihua Sheng
2021 J jnl
Pattern Recognit. Lett.
Qi Wang, Senlin Zhang, Weihua Sheng, Badong Chen, Meiqin Liu
2021 J jnl
IEEE Robotics Autom. Lett.
Minh Pham, Ha Manh Do, Zhidong Su, Alex J. Bishop, Weihua Sheng
2021 J jnl
Auton. Robots
Ye Gu, Meiqin Liu, Weihua Sheng, Yongsheng Ou, Yongqiang Li
2020 J jnl
Image Vis. Comput.
Ye Gu, Xiaofeng Ye, Weihua Sheng, Yongsheng Ou, Yongqiang Li
2020 A conf
IROS
Duy Tran, Ha Manh Do, Jiaxing Lu, Weihua Sheng
2019 J jnl
IEEE Trans. Intell. Transp. Syst.
Duy Tran, Jianhao Du, Weihua Sheng, Denis Osipychev, Yuge Sun, He Bai
2019 J jnl
IEEE Trans Autom. Sci. Eng.
Minh Pham, Dan Yang, Weihua Sheng
2019
Weihua Sheng
2019 B conf
ICIP
Lin Guo, Guoliang Fan, Weihua Sheng
2019 conf
CVPR Workshops
Lin Guo, Guoliang Fan, Weihua Sheng
2019 J jnl
Frontiers Inf. Technol. Electron. Eng.
Qi Wang, Zhen Fan, Weihua Sheng, Senlin Zhang, Meiqin Liu
2019 C conf
VCIP
Mahdi Yazdanpour, Guoliang Fan, Weihua Sheng
2019 conf
CVPR Workshops
Mahdi Yazdanpour, Guoliang Fan, Weihua Sheng
2018 J jnl
CoRR
Trung Nguyen, Barth Lakshmanan, Weihua Sheng
2018 J jnl
Robotics Auton. Syst.
Ye Gu, Weihua Sheng, Christopher Crick, Yongsheng Ou
2018 J jnl
Sensors
Guanci Yang, Jing Yang, Weihua Sheng, Francisco Erivaldo Fernandes Junior, Shaobo Li
2018 J jnl
Future Gener. Comput. Syst.
Minh Pham, Yehenew Mengistu, Ha Manh Do, Weihua Sheng
2018 conf
AIMS
Tianyu Liu, Ye Gu, Weihua Sheng, Yongqiang Li, Yongsheng Ou
2018 J jnl
Sensors
Dan Yang, Bin Xu, Kaiyou Rao, Weihua Sheng
2018 conf
ISR
Fei Wang, Hu Chen, Li Kong, Weihua Sheng
2018 J jnl
Robotics Auton. Syst.
Ha Manh Do, Minh Pham, Weihua Sheng, Dan Yang, Meiqin Liu
2017 A* conf
ICRA
Duy Tran, Eyosiyas Tadesse, Denis Osipychev, Jianhao Du, Weihua Sheng, Yuge Sun, Heping Chen
2017 conf
ROBIO
Francisco Erivaldo Fernandes Junior, Ha Manh Do, Kiran Muniraju, Weihua Sheng, Alex J. Bishop
2017 conf
ROBIO
Xiaofeng Ye, Ye Gu, Weihua Sheng, Fei Wang, Hu Chen, Heping Chen
2017 J jnl
Appl. Artif. Intell.
Guanci Yang, Weihua Sheng, Shaobo Li, Yang Wang, Fei Xu
2017 C conf
ACC
Denis Osipychev, Duy Tran, Weihua Sheng, Girish Chowdhary
2017 ch.
Handbook of Hardware/Software Codesign
Rainer Leupers, Miguel Angel Aguilar, Juan Fernando Eusse, Jerónimo Castrillón, Weihua Sheng
2017 C conf
VCIP
Mahdi Yazdanpour, Guoliang Fan, Weihua Sheng
2017 C conf
VCIP
Lin Guo, Guoliang Fan, Weihua Sheng
2017 J jnl
Int. J. Parallel Program.
Miguel Angel Aguilar, Juan Fernando Eusse, Projjol Ray, Rainer Leupers, Gerd Ascheid, Weihua Sheng, Prashant Sharma
2016 A conf
IROS
Yehenew Mengistu, Minh Pham, Ha Manh Do, Weihua Sheng
2016 conf
CASE
Minh Pham, Yehenew Mengistu, Ha Manh Do, Weihua Sheng
2016 conf
CASE
Ha Manh Do, Weihua Sheng, Meiqin Liu, Senlin Zhang
2016 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Jianhao Du, Craig Mouser, Weihua Sheng
2016 conf
CASE
Francisco Erivaldo Fernandes Junior, Guanci Yang, Ha Manh Do, Weihua Sheng
2016 A conf
IROS
Jianhao Du, Weihua Sheng, Meiqin Liu
2016 conf
ICCSIP
Xinyue Sun, Meiqin Liu, Weihua Sheng, Senlin Zhang, Zhen Fan
2016 conf
ICCSIP
Ye Tang, Meiqin Liu, Weihua Sheng, Senlin Zhang
2015 conf
ROBIO
Duy Tran, Eyosiyas Tadesse, Praveen Batapati, Weihua Sheng, Li Liu
2015 J jnl
IEEE Trans. Cybern.
Weihua Sheng, Anand Thobbi, Ye Gu
2015 A conf
IROS
Ha Manh Do, Weihua Sheng, Meiqin Liu
2015 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Hung Manh La, Weihua Sheng, Jiming Chen
2015 A conf
IROS
Ye Gu, Weihua Sheng, Meiqin Liu, Yongsheng Ou
2015 J jnl
IEEE Trans Autom. Sci. Eng.
Weihua Sheng, Yoky Matsuoka, Yongsheng Ou, Meiqin Liu, Fulvio Mastrogiovanni
2015 conf
ROBIO
Minh Pham, Dan Yang, Weihua Sheng, Meiqin Liu
2015 A conf
DATE
Jerónimo Castrillón, Lothar Thiele, Lars Schor, Weihua Sheng, Ben H. H. Juurlink, Mauricio Alvarez-Mesa, Angela Pohl, Ralph Jessenberger, Victor Reyes, Rainer Leupers
2015 J jnl
IEEE Trans. Control. Syst. Technol.
Hung Manh La, Ronny Salim Lim, Weihua Sheng
2015 J jnl
Neurocomputing
Yujie Zhang, Yongsheng Ou, Yimin Zhou, Xinyu Wu, Weihua Sheng
2015 J jnl
Int. J. Distributed Sens. Networks
Dan Yang, Kaiyou Rao, Bin Xu, Weihua Sheng
2015 conf
SAMOS
Miguel Angel Aguilar, Juan Fernando Eusse, Projjol Ray, Rainer Leupers, Gerd Ascheid, Weihua Sheng, Prashant Sharma
2015 J jnl
Robotics Auton. Syst.
Weihua Sheng, Jianhao Du, Qi Cheng, Gang Li, Chun Zhu, Meiqin Liu, Guoqing Xu
2015 J jnl
IEEE Trans Autom. Sci. Eng.
Chun Zhu, Weihua Sheng, Meiqin Liu
2014 J jnl
IEEE Trans Autom. Sci. Eng.
Ronny Salim Lim, Hung Manh La, Weihua Sheng
2014 J jnl
Parallel Comput.
Weihua Sheng, Stefan Schürmans, Maximilian Odendahl, Mark Bertsch, Vitaliy Volevach, Rainer Leupers, Gerd Ascheid
2014 A* conf
ICRA
Ye Gu, Weihua Sheng, Yongsheng Ou
2014 A* conf
ICRA
Eyosiyas Tadesse, Weihua Sheng, Meiqin Liu
2014 C conf
ACC
Tong-yang Jiang, Meiqin Liu, Senlin Zhang, Weihua Sheng
2014 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Meiqin Liu, Senlin Zhang, Haiyang Chen, Weihua Sheng
2014 A* conf
ICRA
Rakshit Allamaraju, Hassan A. Kingravi, Allan Axelrod, Girish Chowdhary, Robert C. Grande, Jonathan P. How, Christopher Crick, Weihua Sheng
2014 A* conf
ICRA
Ha Manh Do, Craig Mouser, Meiqin Liu, Weihua Sheng
2014 conf
ISVC (1)
Jianhao Du, Weihua Sheng, Qi Cheng, Meiqin Liu
2013 conf
PMAM
Weihua Sheng, Stefan Schürmans, Maximilian Odendahl, Mark Bertsch, Vitaliy Volevach, Rainer Leupers, Gerd Ascheid
2013 A conf
IROS
Weihua Sheng, Yongsheng Ou, Duy Tran, Eyosiyas Tadesse, Meiqin Liu, Gangfeng Yan
2013 J jnl
IEEE Des. Test
Weihua Sheng, Stefan Schürmans, Maximilian Odendahl, Rainer Leupers, Gerd Ascheid
2013 conf
CASE
Hung Manh La, Weihua Sheng, Jiming Chen
2013 J jnl
IEEE Trans. Cybern.
Hung Manh La, Weihua Sheng
2013 conf
HPCC/EUC
Weihua Sheng, Vitaliy Volevach, Rainer Leupers, Gerd Ascheid
2013 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Meiqin Liu, Senlin Zhang, Zhen Fan, Shiyou Zheng, Weihua Sheng
2013 conf
ROBIO
Ye Gu, Weihua Sheng, Yongsheng Ou, Meiqin Liu, Senlin Zhang
2013 ch.
Human Behavior Recognition Technologies
Chun Zhu, Weihua Sheng
2013 J jnl
J. Commun.
Hung Manh La, Weihua Sheng
2013 ch.
Handbook of Signal Processing Systems
Rainer Leupers, Weihua Sheng, Jerónimo Castrillón
2012 J jnl
IEEE Trans. Intell. Transp. Syst.
Hung Manh La, Ronny Salim Lim, Jianhao Du, Sijian Zhang, Gangfeng Yan, Weihua Sheng
2012 J jnl
Robotics Auton. Syst.
Hung Manh La, Weihua Sheng
2012 conf
MCSoC
Weihua Sheng, Artur Wiebe, Anastasia Stulova, Rainer Leupers, Bart Kienhuis, Johan Walters, Gerd Ascheid
2012 conf
ROBIO
Ye Gu, Ha Manh Do, Yongsheng Ou, Weihua Sheng
2012 conf
ROBIO
Jianhao Du, Yongsheng Ou, Weihua Sheng
2012 J jnl
Int. J. Ad Hoc Ubiquitous Comput.
Weihua Sheng, Ravi K. Garimella
2012 J jnl
IEEE Trans. Biomed. Eng.
Chun Zhu, Weihua Sheng
2012 A* conf
ICRA
Gang Li, Chun Zhu, Jianhao Du, Qi Cheng, Weihua Sheng, Heping Chen
2011 conf
ROBIO
Hung Manh La, Ronny Salim Lim, Jianhao Du, Weihua Sheng, Gang Li, Sijian Zhang, Heping Chen
2011 conf
SoC
Weihua Sheng, Stefan Schürmans, Maximilian Odendahl, Rainer Leupers, Gerd Ascheid
2011 A* conf
ICRA
Ronny Salim Lim, Hung Manh La, Zeyong Shan, Weihua Sheng
2011 J jnl
IEEE Trans. Autom. Control.
Changhua Wu, Girma S. Tewolde, Weihua Sheng, Bin Xu, Yu Wang
2011 ch.
Bio-Inspired Self-Organizing Robotic Systems
Hung Manh La, Weihua Sheng
2011 J jnl
Pervasive Mob. Comput.
Chun Zhu, Weihua Sheng
2011 A conf
IROS
Chun Zhu, Weihua Sheng
2011 A* conf
ICRA
Heping Chen, Weihua Sheng
2011 conf
ICSAMOS
Jerónimo Castrillón, Weihua Sheng, Rainer Leupers
2011 A conf
IROS
Anand Thobbi, Ye Gu, Weihua Sheng
2011 J jnl
IEEE Trans. Syst. Man Cybern. Part A
Chun Zhu, Weihua Sheng
2010 A* conf
ICRA
Hung Manh La, Weihua Sheng
2010 conf
Humanoids
Anand Thobbi, Weihua Sheng
2010 A conf
IROS
Rohit Shrikant Kadam, Sijian Zhang, Qizhi Wang, Weihua Sheng
2010 J jnl
Int. J. Ad Hoc Ubiquitous Comput.
Changhua Wu, Ying Zhang, Weihua Sheng, Saroja Kanchi
2010 ch.
Handbook of Signal Processing Systems
Rainer Leupers, Weihua Sheng, Jerónimo Castrillón
2010 A conf
DATE
Jerónimo Castrillón, Ricardo Velasquez, Anastasia Stulova, Weihua Sheng, Jianjiang Ceng, Rainer Leupers, Gerd Ascheid, Heinrich Meyr
2009 Misc conf
CODES+ISSS
Jianjiang Ceng, Weihua Sheng, Jerónimo Castrillón, Anastasia Stulova, Rainer Leupers, Gerd Ascheid, Heinrich Meyr
2009 A conf
IROS
Hung Manh La, Weihua Sheng
2009 A conf
IROS
Vimal Mehta, Weihua Sheng, Tianzhou Chen, Quan Shi
2009 A* conf
ICRA
Hung Manh La, Weihua Sheng
2009 A* conf
ICRA
Chun Zhu, Weihua Sheng
2009 C conf
ACC
Hung M. La, Weihua Sheng
2009 A* conf
HRI
Chun Zhu, Weihua Sheng
2009 A conf
IROS
Chun Zhu, Weihua Sheng
2009 A conf
IROS
Sijian Zhang, Gangfeng Yan, Weihua Sheng
2008 conf
ROBIO
Vimal Mehta, Weihua Sheng
2008 conf
CASE
Girma S. Tewolde, Changhua Wu, Yu Wang, Weihua Sheng
2008 conf
CASE
Chun Zhu, Qi Cheng, Weihua Sheng
2008 A* conf
DAC
Jianjiang Ceng, Jerónimo Castrillón, Weihua Sheng, Hanno Scharwächter, Rainer Leupers, Gerd Ascheid, Heinrich Meyr, Tsuyoshi Isshiki, Hiroaki Kunieda
2008 J jnl
IEEE Trans Autom. Sci. Eng.
Weihua Sheng, Hongjun Chen, Ning Xi
2008 J jnl
IEEE Trans. Syst. Man Cybern. Part A
Girma S. Tewolde, Weihua Sheng
2008 conf
ROBIO
Hung Manh La, Weihua Sheng
2007 conf
CIRA
Rong Huang, Shurong Tong, Weihua Sheng, Zhun Fan
2007 A conf
IROS
Ravi K. Garimella, Weihua Sheng
2007 A* conf
ICRA
Yi Guo, Yi Long, Weihua Sheng
2007 A* conf
ICRA
Changhua Wu, Weihua Sheng, Ying Zhang
2007 A* conf
ICRA
Quan Shi, Ning Xi, Weihua Sheng
2007 conf
CIRA
Weihua Sheng, Girma S. Tewolde
2007 conf
APPT
Lingxiang Xiang, Jiangwei Huang, Weihua Sheng, Tianzhou Chen
2006 conf
ROBIO
Changhua Wu, Weihua Sheng, Wen-Zhan Song
2006 A conf
IROS
Girma S. Tewolde, Weihua Sheng
2006 A conf
IROS
Weihua Sheng, Qingyan Yang, Yi Guo
2006 Misc conf
FLAIRS
Weihua Sheng, Girma S. Tewolde
2006 A* conf
ICRA
Quan Shi, Ning Xi, Weihua Sheng, Yifan Chen
2006 J jnl
Robotics Auton. Syst.
Weihua Sheng, Qingyan Yang, Jindong Tan, Ning Xi
2006 conf
ITSC
Weihua Sheng, Qingyan Yang, Yi Guo
2006 A conf
IROS
Weihua Sheng, Girma S. Tewolde, Song Ci
2006 A conf
IROS
Weihua Sheng, Yantao Shen, Ning Xi
2006 J jnl
J. VLSI Signal Process.
Jianjiang Ceng, Weihua Sheng, Manuel Hohenauer, Rainer Leupers, Gerd Ascheid, Heinrich Meyr, Gunnar Braun
2006 A conf
IROS
Quan Shi, Ning Xi, Yifan Chen, Weihua Sheng
2005 A conf
IROS
Heping Chen, Ning Xi, Weihua Sheng, Jeffrey Dahl, Hongjun Chen
2005 A conf
IROS
Weihua Sheng, Qingyan Yang, Shenghuo Zhu, Qizhi Wang
2005 A* conf
ICRA
Hongjun Chen, Weihua Sheng, Ning Xi, Jindong Tan
2005 A* conf
ICRA
Weihua Sheng, Hongjun Chen, Heping Chen, Ning Xi
2005 J jnl
IEEE Trans Autom. Sci. Eng.
Weihua Sheng, Heping Chen, Ning Xi, Yifan Chen
2004 A* conf
DAC
Gunnar Braun, Achim Nohl, Weihua Sheng, Jianjiang Ceng, Manuel Hohenauer, Hanno Scharwächter, Rainer Leupers, Heinrich Meyr
2004 A* conf
ICRA
Jun Xiao, Jizhong Xiao, Ning Xi, Weihua Sheng
2004 A conf
IROS
Qi Zhu, Weihua Sheng, Ning Xi
2004 conf
SAMOS
Jianjiang Ceng, Weihua Sheng, Manuel Hohenauer, Rainer Leupers, Gerd Ascheid, Heinrich Meyr, Gunnar Braun
2004 A* conf
ICRA
Jindong Tan, Ning Xi, Weihua Sheng, Jizhong Xiao
2004 A conf
IROS
Weihua Sheng, Qingyan Yang, Song Ci, Ning Xi
2004 A* conf
ICRA
Heping Chen, Ning Xi, Weihua Sheng, Yifan Chen, Jeffrey Dahl
2004 A* conf
ICRA
Weihua Sheng, Heping Chen, Ning Xi, Jindong Tan, Yifan Chen
2003 A* conf
ICRA
Heping Chen, Ning Xi, Weihua Sheng, Yifan Chen, Allen Roche, Jeffrey Dahl
2003 A* conf
ICRA
Jindong Tan, Ning Xi, Amit Goradia, Weihua Sheng
2003 conf
CIRA
Weihua Sheng, Ning Xi, Heping Chen, Yifan Chen, Mumin Song
2003 A conf
IROS
Weihua Sheng, Ning Xi, Heping Chen, Yifan Chen, Mumin Song
2002 A* conf
ICRA
Heping Chen, Weihua Sheng, Ning Xi, Mumin Song, Yifan Chen
2002 A conf
IROS
Weihua Sheng, Ning Xi, Mumin Song, Yifan Chen
2001 A* conf
ICRA
Weihua Sheng, Ning Xi, Mumin Song, Yifan Chen
2001 A conf
IROS
Weihua Sheng, Ning Xi, Mumin Song, Yifan Chen
2000 A* conf
ICRA
Weihua Sheng, Ning Xi, Mumin Song, Yifan Chen, James S. Rankin III
2000 A conf
IROS
Weihua Sheng, Ning Xi, Mumin Song, Yifan Chen, Perry MacNeille
tests/unit/test_decompile_analysis.py
← Index tests/unit/test_decompile_analysis.py python
"""Unit tests (mocked Binary Ninja) for analysis modules:
- bninja/analysis/cfg.py — CFGAnalysis
- bninja/analysis/disassembly.py — DisassemblyAnalysis
- bninja/analysis/low_level.py — LowLevelAnalysis
"""
import sys
import pytest
from unittest.mock import MagicMock

from tests.unit.conftest_binja_stubs import (
    install_binja_stubs,
    BranchType,
    InstructionTextTokenType,
    MockBasicBlock,
    MockEdge,
    MockFunction,
    MockToken,
    MockDisassemblyLine,
    MockBinaryView,
    MockSymbol,
    SymbolType,
    LowLevelILOperation,
)

install_binja_stubs()

from redb.extractors.decompiler.bninja.analysis.cfg import CFGAnalysis
from redb.extractors.decompiler.bninja.analysis.disassembly import DisassemblyAnalysis
from redb.extractors.decompiler.bninja.arch.x86 import Arch_x86


# ============================================================================
# 9a. CFGAnalysis
# ============================================================================


class TestCFGCyclomaticComplexity:
    def test_cyclomatic_complexity_linear(self):
        """Single block, no edges: E - N + 2 = 0 - 1 + 2 = 1."""
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])
        func = MockFunction(start=0x1000, basic_blocks=[block])
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert result["cyclomatic_complexity"] == 1

    def test_cyclomatic_complexity_branch(self):
        """Diamond: 4 blocks, 4 edges -> 4 - 4 + 2 = 2."""
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        true_b = MockBasicBlock(start=0x1010, end=0x1020)
        false_b = MockBasicBlock(start=0x1020, end=0x1030)
        merge = MockBasicBlock(start=0x1030, end=0x1040)

        entry.outgoing_edges = [MockEdge(target=true_b), MockEdge(target=false_b)]
        true_b.outgoing_edges = [MockEdge(target=merge)]
        false_b.outgoing_edges = [MockEdge(target=merge)]
        merge.outgoing_edges = []

        func = MockFunction(start=0x1000, basic_blocks=[entry, true_b, false_b, merge])
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert result["cyclomatic_complexity"] == 2

    def test_cyclomatic_complexity_loop(self):
        """Loop: 3 blocks, 3 edges -> 3 - 3 + 2 = 2."""
        header = MockBasicBlock(start=0x1000, end=0x1010)
        body = MockBasicBlock(start=0x1010, end=0x1020)
        exit_b = MockBasicBlock(start=0x1020, end=0x1030)

        header.outgoing_edges = [MockEdge(target=body), MockEdge(target=exit_b)]
        body.outgoing_edges = [MockEdge(target=header)]
        exit_b.outgoing_edges = []

        func = MockFunction(start=0x1000, basic_blocks=[header, body, exit_b])
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert result["cyclomatic_complexity"] == 2


class TestCFGExtractFunctionCFG:
    def _make_simple_cfg(self):
        """Create a simple two-block CFG for testing structure."""
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)

        entry.outgoing_edges = [MockEdge(source=entry, target=exit_b, edge_type=BranchType.UnconditionalBranch)]
        exit_b.incoming_edges = [MockEdge(source=entry, target=exit_b)]
        exit_b.outgoing_edges = []
        entry.incoming_edges = []

        func = MockFunction(start=0x1000, basic_blocks=[entry, exit_b])
        return func

    def test_extract_function_cfg_structure(self):
        func = self._make_simple_cfg()
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert "function_address" not in result
        # New schema: no "blocks" or "measures" nesting
        assert "blocks" not in result
        assert "measures" not in result

    def test_function_cfg_new_keys(self):
        """Assert all expected keys are present in the new output dict."""
        func = self._make_simple_cfg()
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        expected_keys = [
            "cfg_topology_hash",
            "block_count",
            "edge_count",
            "llil_total_operations",
            "call_count",
            "cyclomatic_complexity",
            "loop_count",
            "max_depth",
            "max_fan_out",
            "md_index_topdown",
            "md_index_bottomup",
            "prime_product_llil",
            "cfg_feature_tlsh",
            "wl_minhash",
            "bb_features",
            "cfg_adjacency",
        ]
        for key in expected_keys:
            assert key in result, f"Missing key: {key}"

    def test_returns_none_for_empty_blocks(self):
        func = MockFunction(start=0x1000, basic_blocks=[])
        cfg = CFGAnalysis(func)
        assert cfg.extract_function_cfg() is None


class TestCFGTopologyHash:
    def _make_two_block_cfg(self):
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)
        entry.outgoing_edges = [MockEdge(target=exit_b)]
        exit_b.outgoing_edges = []
        return MockFunction(start=0x1000, basic_blocks=[entry, exit_b])

    def test_topology_hash_is_16_bytes(self):
        func = self._make_two_block_cfg()
        cfg = CFGAnalysis(func)
        result = cfg.extract_function_cfg()
        assert isinstance(result["cfg_topology_hash"], bytes)
        assert len(result["cfg_topology_hash"]) == 16

    def test_topology_hash_deterministic(self):
        func = self._make_two_block_cfg()
        r1 = CFGAnalysis(func).extract_function_cfg()
        r2 = CFGAnalysis(func).extract_function_cfg()
        assert r1["cfg_topology_hash"] == r2["cfg_topology_hash"]


class TestCFGLoopCount:
    def test_no_loops(self):
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)
        entry.outgoing_edges = [MockEdge(target=exit_b)]
        exit_b.outgoing_edges = []
        func = MockFunction(start=0x1000, basic_blocks=[entry, exit_b])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["loop_count"] == 0

    def test_single_loop(self):
        header = MockBasicBlock(start=0x1000, end=0x1010)
        body = MockBasicBlock(start=0x1010, end=0x1020)
        exit_b = MockBasicBlock(start=0x1020, end=0x1030)
        header.outgoing_edges = [MockEdge(target=body), MockEdge(target=exit_b)]
        body.outgoing_edges = [MockEdge(target=header)]
        exit_b.outgoing_edges = []
        func = MockFunction(start=0x1000, basic_blocks=[header, body, exit_b])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["loop_count"] == 1


class TestCFGMaxDepth:
    def test_max_depth_linear(self):
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        b1 = MockBasicBlock(start=0x1010, end=0x1020)
        b2 = MockBasicBlock(start=0x1020, end=0x1030)
        entry.outgoing_edges = [MockEdge(target=b1)]
        b1.outgoing_edges = [MockEdge(target=b2)]
        b2.outgoing_edges = []
        func = MockFunction(start=0x1000, basic_blocks=[entry, b1, b2])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["max_depth"] == 2

    def test_max_depth_single_block(self):
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])
        func = MockFunction(start=0x1000, basic_blocks=[block])
        result = CFGAnalysis(func).extract_function_cfg()
        assert result["max_depth"] == 0


class TestCFGCollectBlockLlilOps:
    """Test that _collect_block_llil_ops correctly maps LLIL data to native blocks."""

    def test_llil_fields_nonzero_with_mock_llil(self):
        """When LLIL is available, llil_total_operations and call_count should be non-zero."""
        # Two native blocks
        entry = MockBasicBlock(start=0x1000, end=0x1010)
        exit_b = MockBasicBlock(start=0x1010, end=0x1020)
        entry.outgoing_edges = [MockEdge(target=exit_b)]
        exit_b.outgoing_edges = []

        # LLIL instructions: SET_REG, CALL in first block; STORE, RET in second
        llil_instrs_1 = [
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG),
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
        ]
        llil_instrs_2 = [
            MockLLILInstruction(LowLevelILOperation.LLIL_STORE),
            MockLLILInstruction(LowLevelILOperation.LLIL_RET),
        ]

        # LLIL basic blocks map back to native blocks via source_block
        llil_bb1 = MockLLILBasicBlock(llil_instrs_1, source_block=entry)
        llil_bb2 = MockLLILBasicBlock(llil_instrs_2, source_block=exit_b)
        llil_func = MockLLILFunction([llil_bb1, llil_bb2])

        func = MockFunction(start=0x1000, basic_blocks=[entry, exit_b], llil=llil_func)
        result = CFGAnalysis(func, llil_function=llil_func).extract_function_cfg()

        assert result["llil_total_operations"] == 4
        assert result["call_count"] == 1
        assert result["prime_product_llil"] != 0

    def test_llil_none_gives_zero_fields(self):
        """Without LLIL, LLIL-dependent fields should be zero."""
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])
        func = MockFunction(start=0x1000, basic_blocks=[block])
        result = CFGAnalysis(func).extract_function_cfg()

        assert result["llil_total_operations"] == 0
        assert result["call_count"] == 0
        assert result["prime_product_llil"] == 0

    def test_bb_features_with_llil(self):
        """bb_features should reflect LLIL instruction categories when LLIL is available."""
        block = MockBasicBlock(start=0x1000, end=0x1010, outgoing_edges=[])

        llil_instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_ADD),
            MockLLILInstruction(LowLevelILOperation.LLIL_LOAD),
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
        ]
        llil_bb = MockLLILBasicBlock(llil_instrs, source_block=block)
        llil_func = MockLLILFunction([llil_bb])

        func = MockFunction(start=0x1000, basic_blocks=[block])
        result = CFGAnalysis(func, llil_function=llil_func).extract_function_cfg()

        feats = result["bb_features"]
        assert len(feats) == 1
        assert feats[0][0] == 3  # instruction count = 3
        # At least one non-zero category count (not all OTHER)
        category_counts = feats[0][1:7]
        assert sum(category_counts) > 0


# ============================================================================
# 9b. DisassemblyAnalysis
# ============================================================================


class TestDisassemblyAnalysisGetJson:
    def _make_analysis(self, instructions=None, basic_blocks=None):
        arch = Arch_x86()
        if instructions is None:
            instructions = [
                (
                    [
                        MockToken("push", InstructionTextTokenType.InstructionToken),
                        MockToken(" ", InstructionTextTokenType.TextToken),
                        MockToken("rbp", InstructionTextTokenType.RegisterToken),
                    ],
                    0x1000,
                ),
                (
                    [
                        MockToken("mov", InstructionTextTokenType.InstructionToken),
                        MockToken(" ", InstructionTextTokenType.TextToken),
                        MockToken("rsp", InstructionTextTokenType.RegisterToken),
                    ],
                    0x1003,
                ),
            ]
        if basic_blocks is None:
            basic_blocks = [MockBasicBlock(
                start=0x1000, end=0x1010,
                disassembly_text=[MockDisassemblyLine([MockToken("push rbp")])]
            )]

        func = MockFunction(
            name="test_func",
            start=0x1000,
            basic_blocks=basic_blocks,
            instructions=instructions,
            symbol=MockSymbol(symbol_type=SymbolType.FunctionSymbol, name="test_func"),
            stack_adjustment=MagicMock(value=-8),
            mlil=None,
        )
        bv = MockBinaryView()
        logger = MagicMock()
        return DisassemblyAnalysis(arch, func, bv, logger)

    def test_get_json_basic_structure(self):
        da = self._make_analysis()
        result, errors = da.get_json()
        expected_keys = [
            "disassembled_function_hash",
            "disassembled_function",
            "disassembled_function_no_addresses",
            "disassembled_function_name",
            "disassembled_function_address",
            "instructions_count",
            "function_type",
            "instructions_types",
            "control_flow_count",
            "memory_access_pattern",
            "register_usage",
            "data_references_count",
        ]
        for key in expected_keys:
            assert key in result, f"Missing key: {key}"

    def test_get_json_hash_deterministic(self):
        da = self._make_analysis()
        r1, _ = da.get_json()
        da2 = self._make_analysis()
        r2, _ = da2.get_json()
        assert r1["disassembled_function_hash"] == r2["disassembled_function_hash"]


class TestDisassemblyCollectInstructionTypes:
    def test_collect_instruction_types(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("MOV", InstructionTextTokenType.InstructionToken)], 0x1000),
            ([MockToken("ADD", InstructionTextTokenType.InstructionToken)], 0x1001),
            ([MockToken("MOV", InstructionTextTokenType.InstructionToken)], 0x1002),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        types = da.collect_instruction_types()
        assert "DATA_MOVEMENT" in types
        assert "ARITHMETIC" in types

    def test_collect_instruction_types_empty(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        types = da.collect_instruction_types()
        assert types == {}


class TestDisassemblyMemoryPatterns:
    def _make_memory_instruction(self, tokens):
        return ([t for t in tokens], 0x1000)

    def test_collect_memory_patterns_stack(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("RSP", InstructionTextTokenType.RegisterToken),
            MockToken("+0x8", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_STACK" in patterns

    def test_collect_memory_patterns_direct(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("0x402000", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_DIRECT" in patterns

    def test_collect_memory_patterns_scaled(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("RAX+RCX*4", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_SCALED_INDEX" in patterns

    def test_collect_memory_patterns_base_offset(self):
        arch = Arch_x86()
        tokens = [
            MockToken("[", InstructionTextTokenType.BeginMemoryOperandToken),
            MockToken("RAX+0x10", InstructionTextTokenType.TextToken),
            MockToken("]", InstructionTextTokenType.EndMemoryOperandToken),
        ]
        instructions = [self._make_memory_instruction(tokens)]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        patterns = da.collect_memory_patterns()
        assert "MEM_BASE_OFFSET" in patterns


class TestDisassemblyRegisterUsage:
    def test_collect_register_usage_gpr(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("RAX", InstructionTextTokenType.RegisterToken)], 0x1000),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        regs = da.collect_register_usage()
        assert "GPR" in regs

    def test_collect_register_usage_simd(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("XMM0", InstructionTextTokenType.RegisterToken)], 0x1000),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        regs = da.collect_register_usage()
        assert "SIMD" in regs

    def test_collect_register_usage_fpu(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("ST0", InstructionTextTokenType.RegisterToken)], 0x1000),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        regs = da.collect_register_usage()
        assert "FPU" in regs


class TestDisassemblyMisc:
    def test_count_data_references(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol(), mlil=None)
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.count_data_references() == 0

    def test_compute_max_block_size(self):
        arch = Arch_x86()
        blocks = [
            MockBasicBlock(disassembly_text=[MockDisassemblyLine([]) for _ in range(3)]),
            MockBasicBlock(disassembly_text=[MockDisassemblyLine([]) for _ in range(5)]),
        ]
        func = MockFunction(start=0x1000, basic_blocks=blocks, instructions=[], symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.compute_max_block_size() == 5

    def test_compute_num_calls(self):
        arch = Arch_x86()
        instructions = [
            ([MockToken("CALL", InstructionTextTokenType.InstructionToken)], 0x1000),
            ([MockToken("MOV", InstructionTextTokenType.InstructionToken)], 0x1005),
            ([MockToken("CALL", InstructionTextTokenType.InstructionToken)], 0x1010),
        ]
        func = MockFunction(start=0x1000, instructions=instructions, symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.compute_num_calls() == 2

    def test_estimate_stack_size_value(self):
        arch = Arch_x86()
        stack = MagicMock()
        stack.value = -16
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol(), stack_adjustment=stack)
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.estimate_stack_size() == -16

    def test_estimate_stack_size_int(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol(), stack_adjustment=-8)
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.estimate_stack_size() == -8

    def test_normalize_opcode(self):
        arch = Arch_x86()
        func = MockFunction(start=0x1000, instructions=[], symbol=MockSymbol())
        da = DisassemblyAnalysis(arch, func, MockBinaryView(), MagicMock())
        assert da.normalize_opcode("mov") == "MOV"
        assert da.normalize_opcode("PUSH") == "PUSH"


# ============================================================================
# 9c. LowLevelAnalysis (basic tests with mocked LLIL)
# ============================================================================


class MockLLILInstruction:
    """Mock LLIL instruction for low_level.py tests."""
    def __init__(self, operation, operands=None, address=0):
        self.operation = operation
        self.operands = operands or []
        self.address = address

    def __str__(self):
        return f"LLIL_{self.operation}"


class MockLLILBasicBlock:
    def __init__(self, instructions, source_block=None):
        self._instructions = instructions
        self.source_block = source_block

    def __iter__(self):
        return iter(self._instructions)


class MockLLILFunction:
    def __init__(self, basic_blocks):
        self.basic_blocks = basic_blocks
        self._instructions = []
        for bb in basic_blocks:
            self._instructions.extend(bb._instructions)

    @property
    def instructions(self):
        return iter(self._instructions)

    @property
    def source_function(self):
        mock = MagicMock()
        mock.start = 0x1000
        return mock


class TestLowLevelAnalysisCountControlFlow:
    def test_count_control_flow_instructions(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_IF),
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG),
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
            MockLLILInstruction(LowLevelILOperation.LLIL_GOTO),
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        bv.arch = MagicMock()
        bv.arch.stack_pointer = "sp"
        la = LowLevelAnalysis(func, bv, MagicMock())
        assert la.count_control_flow_instructions() == 3  # IF, CALL, GOTO


class TestLowLevelAnalysisNumCalls:
    def test_compute_num_calls_llil(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_CALL),
            MockLLILInstruction(LowLevelILOperation.LLIL_TAILCALL),
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG),
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        la = LowLevelAnalysis(func, bv, MagicMock())
        assert la.compute_num_calls() == 2


class TestLowLevelAnalysisCollectNormalization:
    def test_collect_low_level(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG, address=0x1000),
            MockLLILInstruction(LowLevelILOperation.LLIL_STORE, address=0x1004),
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        la = LowLevelAnalysis(func, bv, MagicMock())
        result, _ = la._collect_low_level_and_with_addr()
        assert len(result) == 2
        # Each item is a list of operation ints
        assert isinstance(result[0], list)

    def test_collect_low_level_with_addr_offset_clamping(self):
        from redb.extractors.decompiler.bninja.analysis.low_level import LowLevelAnalysis
        instrs = [
            MockLLILInstruction(LowLevelILOperation.LLIL_SET_REG, address=0x0FFF),  # Before function start
        ]
        bb = MockLLILBasicBlock(instrs)
        llil_func = MockLLILFunction([bb])

        func = MockFunction(start=0x1000, llil=llil_func, symbol=MockSymbol())
        func.low_level_il = None
        bv = MockBinaryView()
        la = LowLevelAnalysis(func, bv, MagicMock())
        _, result = la._collect_low_level_and_with_addr()
        assert len(result) == 1
        offset, _ = result[0]
        assert offset == 0  # Clamped to 0