@@ -123,29 +123,42 @@ pub fn refute_with_primitive_check(
123123 if status != VerificationStatus :: Confirmed {
124124 return ( status, notes. to_string ( ) ) ;
125125 }
126- if let Some ( ( _body, found) ) = anchored_body_containing_primitive ( finding, primitives) {
127- let reason = format ! (
128- "not confirmed: {} found in the body of the function this finding names" ,
129- found
130- ) ;
131- let merged = if notes. trim ( ) . is_empty ( ) {
132- reason
133- } else {
134- format ! ( "{notes} ({reason})" )
135- } ;
136- return ( VerificationStatus :: FalsePositive , merged) ;
126+ match anchored_body_containing_primitive ( finding, primitives) {
127+ Some ( Ok ( ( _body, found) ) ) => {
128+ let reason = format ! (
129+ "not confirmed: {} found in the body of the function this finding names" ,
130+ found
131+ ) ;
132+ let merged = if notes. trim ( ) . is_empty ( ) {
133+ reason
134+ } else {
135+ format ! ( "{notes} ({reason})" )
136+ } ;
137+ ( VerificationStatus :: FalsePositive , merged)
138+ }
139+ Some ( Err ( read_error) ) => {
140+ let reason = format ! ( "{read_error}: {path}" , path = finding. file_path) ;
141+ let merged = if notes. trim ( ) . is_empty ( ) {
142+ reason
143+ } else {
144+ format ! ( "{notes} ({reason})" )
145+ } ;
146+ ( VerificationStatus :: NeedsReview , merged)
147+ }
148+ None => ( status, notes. to_string ( ) ) ,
137149 }
138- ( status, notes. to_string ( ) )
139150}
140151
141152/// The body of the function the title names, if it contains a primitive.
142153///
143- /// Returns the body and which primitive matched, so the reason names the
144- /// evidence rather than asserting that a check happened.
154+ /// Returns:
155+ /// - `Some(Ok((body, primitive)))` if the file was read and a primitive was found
156+ /// - `Some(Err(String))` if the file could not be read (missing, permissions, etc.)
157+ /// - `None` if the file was read but no primitive was found, or if language/name could not be determined
145158fn anchored_body_containing_primitive (
146159 finding : & VulnerabilityFinding ,
147160 primitives : & std:: collections:: HashMap < String , Vec < String > > ,
148- ) -> Option < ( String , String ) > {
161+ ) -> Option < Result < ( String , String ) , String > > {
149162 let language = extract_language_from_path ( & finding. file_path ) ;
150163 let for_language = primitives. get ( & language) ?;
151164 if for_language. is_empty ( ) {
@@ -154,7 +167,10 @@ fn anchored_body_containing_primitive(
154167 let name = crate :: llm_analysis:: function_names_in_title ( & finding. title )
155168 . into_iter ( )
156169 . next ( ) ?;
157- let content = std:: fs:: read_to_string ( & finding. file_path ) . ok ( ) ?;
170+ let content = match std:: fs:: read_to_string ( & finding. file_path ) {
171+ Ok ( c) => c,
172+ Err ( e) => return Some ( Err ( format ! ( "cannot read file: {}" , e) ) ) ,
173+ } ;
158174 let ranges = crate :: llm_analysis:: function_line_ranges ( & content, & language) ;
159175 let ( start, end) = * ranges. get ( & name) ?;
160176
@@ -163,7 +179,7 @@ fn anchored_body_containing_primitive(
163179 . iter ( )
164180 . find ( |p| !p. is_empty ( ) && body. contains ( p. as_str ( ) ) ) ?
165181 . clone ( ) ;
166- Some ( ( body, found) )
182+ Some ( Ok ( ( body, found) ) )
167183}
168184
169185/// The function body, by its 1-indexed line range.
0 commit comments