File indexing completed on 2024-04-21 05:41:55

0001 #!/usr/bin/perl
0002 
0003 # Kevin Funk <kfunk@kde.org> (2015)
0004 #
0005 # Attempts to remove lines such as '#include "<basename>.moc"' from cpp files
0006 #
0007 # Automoc conventions:
0008 # - include moc_<basename>.cpp <=> Q_OBJECT/Q_GADGET inside header
0009 # - include <basename>.moc     <=> Q_OBJECT/Q_GADGET inside source file
0010 #
0011 # Additionally, if K_PLUGIN_FACTORY is used, we'll *have* to use '<basename>.moc'
0012 #
0013 # Now, if <basename>.moc is included, and the source file does *not* need a moc run,
0014 # CMake's automoc still performs a moc run and moc will give warnings, such as:
0015 # "foo.cpp:0: Note: No relevant classes found. No output generated."
0016 # => Remove the include in this case
0017 #
0018 # More info: https://cmake.org/cmake/help/v3.0/manual/cmake-qt.7.html#automoc
0019 #
0020 # Usual invocation:
0021 #   find -iname "*.cpp" | xargs kde-dev-scripts/kf5/convert-to-cmake-automoc.pl
0022 
0023 use strict;
0024 use warnings;
0025 
0026 use File::Basename;
0027 use lib dirname($0);
0028 use functionUtilkde;
0029 
0030 foreach my $file (@ARGV) {
0031     open(my $FILE, "<", $file) or die "We can't open file $file:$!\n";
0032     my $content = do { local $/; <$FILE> };
0033 
0034     my $regexRequiresMoc = qr/(Q_OBJECT|Q_GADGET|K_PLUGIN_FACTORY|EXPORT_KONTACT_PLUGIN|_WITH_JSON|K_EXPORT_PLASMA_)/;
0035 
0036     my ($filenameWithoutExtension, $dirs,) = fileparse($file, qr/\.[^.]*/);
0037 
0038     # In some cases, we cannot just get rid off the '#include <basename>.moc',
0039     # and need to include '#include moc_<basename>.cpp'
0040     # E.g. in case when the moc-generated file needs information about a class declared inside the .cpp file
0041     # Try to detect these cases and include '#include moc_<basename>.cpp' instead
0042     my $headerFile = $dirs . "$filenameWithoutExtension.h";
0043     my $requiresHeaderMocInclude = (-e $headerFile) ?
0044         `grep Q_PRIVATE_SLOT -q $headerFile` :
0045         0;
0046 
0047     my $sourceMocFilename = "$filenameWithoutExtension.moc";
0048     my $requiresSourceMocInclude = ($content =~ /$regexRequiresMoc/);
0049     my $includesSourceMocInclude = ($content =~ /#include \"$sourceMocFilename\"/);
0050 
0051     # rewrite file and fix moc includes
0052     if (!$requiresSourceMocInclude && $includesSourceMocInclude) {
0053         open (my $OUT, ">", $file);
0054         # TODO: Refactor, then use functionUtilkde::removeIncludeInFile?
0055         # Cannot use, because it a) only accepts <>-style includes and b) creates redundant newlines
0056         for (split /^/, $content) {
0057             # strip or replace unwanted includes
0058             if (/#include \"$sourceMocFilename\"/) {
0059                 if ($requiresHeaderMocInclude) {
0060                     print $OUT "#include \"moc_$filenameWithoutExtension.cpp\"\n";
0061                 }
0062                 next; # remove line
0063             }
0064 
0065             print $OUT $_;
0066         }
0067         close ($OUT);
0068     }
0069 }
0070 
0071 functionUtilkde::diffFile( "@ARGV" );