@@ -14,6 +14,7 @@ use std::{
1414use anyhow:: { anyhow, Context , Result } ;
1515use git2:: { DiffOptions , Patch } ;
1616use regex:: Regex ;
17+ use semver:: Version ;
1718use tokio:: task:: JoinSet ;
1819use which:: { which, which_in} ;
1920
@@ -68,9 +69,32 @@ impl ClangTool {
6869 which ( name) . map_err ( |_| anyhow ! ( "Could not find clang tool by name" ) )
6970 }
7071 RequestedVersion :: Requirement ( req) => {
71- // `version` specified has at least a major version number.
72- for req_ver in & req. comparators {
73- let major = req_ver. major ;
72+ // `req.comparators` has at least a major version number for each comparator.
73+ // We need to start with the highest major version number first, then
74+ // decrement to the lowest that satisfies the requirement.
75+
76+ // find the highest major version from requirement's boundaries.
77+ let mut it = req. comparators . iter ( ) ;
78+ let mut highest_major = it. next ( ) . map ( |v| v. major ) . unwrap_or_default ( ) + 1 ;
79+ for n in it {
80+ if n. major < highest_major {
81+ // +1 because we aren't checking the comparator's operator here.
82+ highest_major = n. major + 1 ;
83+ }
84+ }
85+
86+ // aggregate by decrementing through major versions that satisfy the requirement.
87+ let mut majors = vec ! [ ] ;
88+ while highest_major > 0 {
89+ // check if the current major version satisfies the requirement.
90+ if req. matches ( & Version :: new ( highest_major, 0 , 0 ) ) {
91+ majors. push ( highest_major) ;
92+ }
93+ highest_major -= 1 ;
94+ }
95+
96+ // now we're ready to search for the binary exe with the major version suffixed.
97+ for major in majors {
7498 if let Ok ( cmd) = which ( format ! ( "{name}-{major}" ) ) {
7599 return Ok ( cmd) ;
76100 }
@@ -464,7 +488,7 @@ pub trait MakeSuggestions {
464488
465489#[ cfg( test) ]
466490mod tests {
467- use std:: { env , path:: PathBuf , str:: FromStr } ;
491+ use std:: { path:: PathBuf , str:: FromStr } ;
468492
469493 use which:: which;
470494
@@ -475,8 +499,8 @@ mod tests {
475499
476500 #[ test]
477501 fn get_exe_by_version ( ) {
478- let clang_version = env :: var ( "CLANG_VERSION" ) . unwrap_or ( "16" . to_string ( ) ) ;
479- let req_version = RequestedVersion :: from_str ( & clang_version ) . unwrap ( ) ;
502+ let requirement = ">=9, <22" ;
503+ let req_version = RequestedVersion :: from_str ( requirement ) . unwrap ( ) ;
480504 let tool_exe = CLANG_FORMAT . get_exe_path ( & req_version) ;
481505 println ! ( "tool_exe: {:?}" , tool_exe) ;
482506 assert ! ( tool_exe. is_ok_and( |val| val
0 commit comments