find_class_typos.pl 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 24 June 2017
  5. # https://github.com/trizen
  6. use 5.014;
  7. use strict;
  8. use autodie;
  9. use warnings;
  10. use File::Find qw(find);
  11. use File::Basename qw(basename);
  12. use Text::Levenshtein::XS qw(distance);
  13. my $dir = shift() // die "usage: $0 [lib dir]\n";
  14. if (basename($dir) ne 'lib') {
  15. die "error: '$dir' is not a lib directory!";
  16. }
  17. my $typo_dist = 1; # maximum typo distance
  18. my %invokants;
  19. my %declarations;
  20. find {
  21. no_chdir => 1,
  22. wanted => sub {
  23. /\.pm\z/ || return;
  24. my $content = do {
  25. local $/;
  26. open my $fh, '<:utf8', $_;
  27. <$fh>;
  28. };
  29. if ($content =~ /\bpackage\h+(Sidef(::\w+)*)/) {
  30. undef $declarations{$1};
  31. }
  32. else {
  33. warn "Unable to extract the package name from: $_\n";
  34. }
  35. while ($content =~ /\b(Sidef(::\w+)+)/g) {
  36. my $name = $1;
  37. push @{$invokants{$name}}, $_;
  38. if ($name =~ /^(.+)::/) { # handle function calls
  39. push @{$invokants{$1}}, $_;
  40. }
  41. }
  42. },
  43. } => $dir;
  44. my @invokants = keys(%invokants);
  45. my @declarations = keys(%declarations);
  46. foreach my $invo (@invokants) {
  47. next if exists($declarations{$invo});
  48. foreach my $decl (@declarations) {
  49. if (abs(length($invo) - length($decl)) <= $typo_dist
  50. and distance($invo, $decl) <= $typo_dist) {
  51. say "Possible typo: <<$invo>> instead of <<$decl>> in:";
  52. say "\t", join(
  53. "\n\t",
  54. do {
  55. my %seen;
  56. grep { !$seen{$_}++ } @{$invokants{$invo}};
  57. }
  58. ),
  59. "\n";
  60. }
  61. }
  62. }