Fix function shortening for complex cases, like:
std::basic_ostream<A, B>& operator<< <A, B >(std::basic_ostream<A, B>&, T const&)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
package CrashTest::Plugin::CrashSignatureExtractor::C_Cpp;
use Mojo::Base -base;
use Mojo::Util qw/dumper/;
use Text::Balanced qw/extract_bracketed/;
use CrashTest::Model::Thread;
has [ qw/app config/ ];
sub extract_signature {
my ($self, $thread) = @_;
my $frames = $thread->frames;
$frames = _strip_top_frames($frames, $self->config->{TopIrrelevant}, $self->config->{TopFrame});
#my @rev_frames = reverse @$frames;
# $frames = _strip_top_frames(\@rev_frames, $self->config->{BottomIrrelevant}, $self->config->{BottomFrame});
#my @new_frames = reverse @$frames;
my @new_frames = @$frames;
my @short_frames;
foreach my $frame(@new_frames) {
my $short = _extract_function_name($frame->function);
$short =~ s/^$_// foreach (@{$self->config->{RemoveNamespace}});
push @short_frames, $short;
# . "@" . $frame->function_offset;
}
return \@short_frames;
}
sub extract_signature_title {
my ($self, $thread) = @_;
return $self->extract_signature($thread)->[0];
}
sub _extract_function_name {
my $signature = shift;
return "" if(!defined($signature) || $signature eq "");
my $short_signature = "";
my $text = $signature;
do {
# the complex prefix is here to match normal function names (the last '[^<\(]*' part)
# but also the complex case of unbalanced <> like in:
# std::basic_ostream<A, B>& operator<< <A, B >(std::basic_ostream<A, B>&, T const&)
my ($str, $next, $prefix) = extract_bracketed($text, '<(', qr/([^<\(]*operator[<>]{1,2})?[^<\(]*/);
if($str) {
$short_signature .= $prefix;
$text = $next;
} else {
$short_signature .= $next;
$text = undef;
}
} while($text);
return $short_signature;
}
sub _smartmatch {
my ($text, $pat) = @_;
return $text =~ $pat if(ref($pat) eq "Regexp");
return $text eq $pat;
}
sub _strip_top_frames {
my ($frames, $skip, $stop) = @_;
my $first_frame = 0;
my $i = -1;
TOPFRAME: foreach my $frame(@$frames) {
my $f = _extract_function_name($frame->function);
$i += 1;
# if matching, mark first frame, and stop
foreach my $m(@{$stop}) {
if(_smartmatch($f, $m)) {
$first_frame = $i;
last TOPFRAME;
}
}
# if matching, mark next frame as first, and continue
my $skip_matched = 0;
foreach my $m(@{$skip}) {
if(_smartmatch($f, $m)) {
$first_frame = $i + 1;
$skip_matched = 1;
}
}
# else, stop
unless($skip_matched) {
last TOPFRAME;
}
}
my $last = scalar(@$frames) - 1;
my @new_frames = @$frames[$first_frame .. $last];
return \@new_frames;
}
1;