@ -12,6 +12,7 @@
# include "documentation.hpp"
# include "documentation.hpp"
# include "filesystem.hpp"
# include "filesystem.hpp"
# include "info.hpp"
# include "info.hpp"
# include "sarif.hpp"
# include "selection_dialog.hpp"
# include "selection_dialog.hpp"
# include "usages_clang.hpp"
# include "usages_clang.hpp"
# include "utility.hpp"
# include "utility.hpp"
@ -171,6 +172,16 @@ void Source::ClangViewParse::parse(size_t count) {
for ( auto & token : * clang_tokens )
for ( auto & token : * clang_tokens )
clang_tokens_offsets . emplace_back ( token . get_source_range ( ) . get_offsets ( ) ) ;
clang_tokens_offsets . emplace_back ( token . get_source_range ( ) . get_offsets ( ) ) ;
clang_diagnostics = clang_tu - > get_diagnostics ( ) ;
clang_diagnostics = clang_tu - > get_diagnostics ( ) ;
try {
auto analyze_results_file = Project : : Build : : create ( this - > file_path ) - > get_default_path ( ) / " clang-analyze.sarif.json " ;
analyze_diagnostics = SARIF : : results_for_file ( analyze_results_file , file_path ) ;
}
catch ( const std : : exception & err ) {
analyze_diagnostics . clear ( ) ;
Terminal : : get ( ) . async_print ( " \ e[31mError \ e[m: Parsing clang-analyze results failed: " + std : : string { err . what ( ) } + " . \n " , true ) ;
}
parse_mutex . unlock ( ) ;
parse_mutex . unlock ( ) ;
dispatcher . post ( [ this , count ] {
dispatcher . post ( [ this , count ] {
if ( count ! = parse_count | | parse_state ! = ParseState : : processing )
if ( count ! = parse_count | | parse_state ! = ParseState : : processing )
@ -525,6 +536,86 @@ void Source::ClangViewParse::update_diagnostics() {
}
}
}
}
std : : map < std : : pair < Gtk : : TextIter , Gtk : : TextIter > , std : : set < std : : string > > added_messages ;
const auto add_tooltip_for_location = [ this , & added_messages ] ( const SARIF : : Location & location , const SARIF : : Result & result ) {
auto text = result . get_message ( location , true /* markdown */ ) ;
int line = location . region . start_line - 1 ;
if ( line < 0 | | line > = get_buffer ( ) - > get_line_count ( ) )
line = get_buffer ( ) - > get_line_count ( ) - 1 ;
auto start = get_iter_at_line_end ( line ) ;
int offset = location . region . start_column - 1 ;
if ( offset > = 0 & & offset < start . get_line_index ( ) )
start = get_buffer ( ) - > get_iter_at_line_offset ( line , offset ) ;
if ( start . ends_line ( ) ) {
while ( ! start . is_start ( ) & & start . ends_line ( ) )
start . backward_char ( ) ;
}
line = location . region . end_line - 1 ;
if ( line < 0 | | line > = get_buffer ( ) - > get_line_count ( ) )
line = get_buffer ( ) - > get_line_count ( ) - 1 ;
auto end = get_iter_at_line_end ( line ) ;
offset = location . region . end_column - 1 ;
if ( offset > = 0 & & offset < end . get_line_index ( ) )
end = get_buffer ( ) - > get_iter_at_line_offset ( line , offset ) ;
// Check whether the source actually still matches the scan result
auto match = get_buffer ( ) - > get_text ( start , end ) ;
if ( ! location . region . snippet . empty ( ) & & match ! = location . region . snippet ) {
bool context_found = false ;
if ( location . context_region & & ! location . context_region - > snippet . empty ( ) ) {
// Try to find the context in case the matching source was only moved
Gtk : : TextIter match_start , match_end ;
if ( start . forward_search ( location . context_region - > snippet , static_cast < Gtk : : TextSearchFlags > ( 0 ) , match_start , match_end ) )
context_found = true ;
else if ( end . backward_search ( location . context_region - > snippet , static_cast < Gtk : : TextSearchFlags > ( 0 ) , match_start , match_end ) )
context_found = true ;
else if ( get_buffer ( ) - > begin ( ) . forward_search ( location . context_region - > snippet , static_cast < Gtk : : TextSearchFlags > ( 0 ) , match_start , match_end ) )
context_found = true ;
if ( context_found ) {
match_start . forward_search ( location . region . snippet , static_cast < Gtk : : TextSearchFlags > ( 0 ) , start , end , match_end ) ;
}
}
text . append ( " (Source modified since scan, match " ) . append ( context_found ? " may be " : " is " ) . append ( " inaccurate) " ) ;
}
auto added_it = added_messages . find ( std : : make_pair ( start , end ) ) ;
if ( added_it ! = added_messages . end ( ) & & added_it - > second . find ( text ) ! = added_it - > second . end ( ) )
return false ;
diagnostic_offsets . emplace ( start . get_offset ( ) ) ;
added_messages [ std : : make_pair ( start , end ) ] . emplace ( text ) ;
add_diagnostic_tooltip ( start , end , result . level = = SARIF : : Result : : Level : : error , [ text ] ( Tooltip & tooltip ) {
tooltip . insert_markdown ( text ) ;
} ) ;
return true ;
} ;
for ( const auto & diagnostic : analyze_diagnostics ) {
for ( const auto & location : diagnostic . locations ) {
if ( location . artifact_location = = file_path ) {
if ( add_tooltip_for_location ( location , diagnostic ) ) {
num_warnings + = diagnostic . level = = SARIF : : Result : : Level : : warning ;
num_errors + = diagnostic . level = = SARIF : : Result : : Level : : error ;
}
}
}
for ( const auto & code_flow : diagnostic . code_flows ) {
for ( const auto & thread_flow : code_flow . thread_flows ) {
for ( const auto & entry : thread_flow . locations ) {
if ( entry . location . artifact_location = = file_path & & entry . importance ! = SARIF : : ThreadFlowLocation : : Importance : : unimportant ) {
if ( add_tooltip_for_location ( entry . location , diagnostic ) ) {
num_warnings + = diagnostic . level = = SARIF : : Result : : Level : : warning ;
num_errors + = diagnostic . level = = SARIF : : Result : : Level : : error ;
}
}
}
}
}
}
status_diagnostics = std : : make_tuple ( num_warnings , num_errors , num_fix_its ) ;
status_diagnostics = std : : make_tuple ( num_warnings , num_errors , num_fix_its ) ;
if ( update_status_diagnostics )
if ( update_status_diagnostics )
update_status_diagnostics ( this ) ;
update_status_diagnostics ( this ) ;