|  | @@ -901,6 +901,214 @@ bool cmQtAutoGenerators::StrictParseCppFile(
 | 
	
		
			
				|  |  |    return true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * @return True on success
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +bool cmQtAutoGenerators::ParseSourceFile(
 | 
	
		
			
				|  |  | +  const std::string& absFilename,
 | 
	
		
			
				|  |  | +  const std::vector<std::string>& headerExtensions,
 | 
	
		
			
				|  |  | +  std::map<std::string, std::string>& includedMocs,
 | 
	
		
			
				|  |  | +  std::map<std::string, std::vector<std::string> >& includedUis, bool relaxed)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  cmsys::RegularExpression mocIncludeRegExp(
 | 
	
		
			
				|  |  | +    "[\n][ \t]*#[ \t]*include[ \t]+"
 | 
	
		
			
				|  |  | +    "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const std::string contentsString = ReadAll(absFilename);
 | 
	
		
			
				|  |  | +  if (contentsString.empty()) {
 | 
	
		
			
				|  |  | +    std::ostringstream err;
 | 
	
		
			
				|  |  | +    err << "AUTOGEN: warning: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +        << "The file is empty\n";
 | 
	
		
			
				|  |  | +    this->LogWarning(err.str());
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Parse source contents for UIC
 | 
	
		
			
				|  |  | +  this->ParseForUic(absFilename, contentsString, includedUis);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Continue with moc parsing on demand
 | 
	
		
			
				|  |  | +  if (this->MocExecutable.empty()) {
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const std::string scannedFileAbsPath =
 | 
	
		
			
				|  |  | +    cmsys::SystemTools::GetFilenamePath(
 | 
	
		
			
				|  |  | +      cmsys::SystemTools::GetRealPath(absFilename)) +
 | 
	
		
			
				|  |  | +    '/';
 | 
	
		
			
				|  |  | +  const std::string scannedFileBasename =
 | 
	
		
			
				|  |  | +    cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  std::string macroName;
 | 
	
		
			
				|  |  | +  const bool requiresMoc = requiresMocing(contentsString, macroName);
 | 
	
		
			
				|  |  | +  bool ownDotMocIncluded = false;
 | 
	
		
			
				|  |  | +  bool ownMocUnderscoreIncluded = false;
 | 
	
		
			
				|  |  | +  std::string ownMocUnderscoreFile;
 | 
	
		
			
				|  |  | +  std::string ownMocHeaderFile;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  std::string::size_type matchOffset = 0;
 | 
	
		
			
				|  |  | +  // first a simple string check for "moc" is *much* faster than the regexp,
 | 
	
		
			
				|  |  | +  // and if the string search already fails, we don't have to try the
 | 
	
		
			
				|  |  | +  // expensive regexp
 | 
	
		
			
				|  |  | +  if (strstr(contentsString.c_str(), "moc") != CM_NULLPTR) {
 | 
	
		
			
				|  |  | +    // Iterate over all included moc files
 | 
	
		
			
				|  |  | +    const char* contentChars = contentsString.c_str();
 | 
	
		
			
				|  |  | +    while (mocIncludeRegExp.find(contentChars)) {
 | 
	
		
			
				|  |  | +      const std::string currentMoc = mocIncludeRegExp.match(1);
 | 
	
		
			
				|  |  | +      // Basename of the current moc include
 | 
	
		
			
				|  |  | +      std::string basename =
 | 
	
		
			
				|  |  | +        cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // If the moc include is of the moc_foo.cpp style we expect
 | 
	
		
			
				|  |  | +      // the Q_OBJECT class declaration in a header file.
 | 
	
		
			
				|  |  | +      // If the moc include is of the foo.moc style we need to look for
 | 
	
		
			
				|  |  | +      // a Q_OBJECT macro in the current source file, if it contains the
 | 
	
		
			
				|  |  | +      // macro we generate the moc file from the source file.
 | 
	
		
			
				|  |  | +      if (cmHasLiteralPrefix(basename, "moc_")) {
 | 
	
		
			
				|  |  | +        // Include: moc_FOO.cxx
 | 
	
		
			
				|  |  | +        // basename should be the part of the moc filename used for
 | 
	
		
			
				|  |  | +        // finding the correct header, so we need to remove the moc_ part
 | 
	
		
			
				|  |  | +        basename = basename.substr(4);
 | 
	
		
			
				|  |  | +        const std::string mocSubDir =
 | 
	
		
			
				|  |  | +          extractSubDir(scannedFileAbsPath, currentMoc);
 | 
	
		
			
				|  |  | +        const std::string headerToMoc = findMatchingHeader(
 | 
	
		
			
				|  |  | +          scannedFileAbsPath, mocSubDir, basename, headerExtensions);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (!headerToMoc.empty()) {
 | 
	
		
			
				|  |  | +          includedMocs[headerToMoc] = currentMoc;
 | 
	
		
			
				|  |  | +          if (relaxed && (basename == scannedFileBasename)) {
 | 
	
		
			
				|  |  | +            ownMocUnderscoreIncluded = true;
 | 
	
		
			
				|  |  | +            ownMocUnderscoreFile = currentMoc;
 | 
	
		
			
				|  |  | +            ownMocHeaderFile = headerToMoc;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          std::ostringstream err;
 | 
	
		
			
				|  |  | +          err << "AUTOGEN: error: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +              << "The file includes the moc file \"" << currentMoc
 | 
	
		
			
				|  |  | +              << "\", but could not find header \"" << basename << '{'
 | 
	
		
			
				|  |  | +              << this->JoinExts(headerExtensions) << "}\" ";
 | 
	
		
			
				|  |  | +          if (mocSubDir.empty()) {
 | 
	
		
			
				|  |  | +            err << "in " << scannedFileAbsPath << "\n";
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            err << "neither in " << scannedFileAbsPath << " nor in "
 | 
	
		
			
				|  |  | +                << mocSubDir << "\n";
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          this->LogError(err.str());
 | 
	
		
			
				|  |  | +          return false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        // Include: FOO.moc
 | 
	
		
			
				|  |  | +        std::string fileToMoc;
 | 
	
		
			
				|  |  | +        if (relaxed) {
 | 
	
		
			
				|  |  | +          // Mode: Relaxed
 | 
	
		
			
				|  |  | +          if (!requiresMoc || basename != scannedFileBasename) {
 | 
	
		
			
				|  |  | +            const std::string mocSubDir =
 | 
	
		
			
				|  |  | +              extractSubDir(scannedFileAbsPath, currentMoc);
 | 
	
		
			
				|  |  | +            const std::string headerToMoc = findMatchingHeader(
 | 
	
		
			
				|  |  | +              scannedFileAbsPath, mocSubDir, basename, headerExtensions);
 | 
	
		
			
				|  |  | +            if (!headerToMoc.empty()) {
 | 
	
		
			
				|  |  | +              // This is for KDE4 compatibility:
 | 
	
		
			
				|  |  | +              fileToMoc = headerToMoc;
 | 
	
		
			
				|  |  | +              if (!requiresMoc && basename == scannedFileBasename) {
 | 
	
		
			
				|  |  | +                std::ostringstream err;
 | 
	
		
			
				|  |  | +                err << "AUTOMOC: warning: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +                    << "The file includes the moc file \"" << currentMoc
 | 
	
		
			
				|  |  | +                    << "\", but does not contain a " << macroName
 | 
	
		
			
				|  |  | +                    << " macro. Running moc on "
 | 
	
		
			
				|  |  | +                    << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
 | 
	
		
			
				|  |  | +                    << ".cpp\" for a compatibility with "
 | 
	
		
			
				|  |  | +                       "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
 | 
	
		
			
				|  |  | +                this->LogWarning(err.str());
 | 
	
		
			
				|  |  | +              } else {
 | 
	
		
			
				|  |  | +                std::ostringstream err;
 | 
	
		
			
				|  |  | +                err << "AUTOMOC: warning: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +                    << "The file includes the moc file \"" << currentMoc
 | 
	
		
			
				|  |  | +                    << "\" instead of \"moc_" << basename
 | 
	
		
			
				|  |  | +                    << ".cpp\". Running moc on "
 | 
	
		
			
				|  |  | +                    << "\"" << headerToMoc << "\" ! Include \"moc_" << basename
 | 
	
		
			
				|  |  | +                    << ".cpp\" for compatibility with "
 | 
	
		
			
				|  |  | +                       "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
 | 
	
		
			
				|  |  | +                this->LogWarning(err.str());
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +              std::ostringstream err;
 | 
	
		
			
				|  |  | +              err << "AUTOMOC: error: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +                  << "The file includes the moc file \"" << currentMoc
 | 
	
		
			
				|  |  | +                  << "\", which seems to be the moc file from a different "
 | 
	
		
			
				|  |  | +                     "source file. CMake also could not find a matching "
 | 
	
		
			
				|  |  | +                     "header.\n";
 | 
	
		
			
				|  |  | +              this->LogError(err.str());
 | 
	
		
			
				|  |  | +              return false;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            // Include self
 | 
	
		
			
				|  |  | +            fileToMoc = absFilename;
 | 
	
		
			
				|  |  | +            ownDotMocIncluded = true;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          // Mode: Strict
 | 
	
		
			
				|  |  | +          if (basename != scannedFileBasename) {
 | 
	
		
			
				|  |  | +            // Don't allow FOO.moc include other than self in strict mode
 | 
	
		
			
				|  |  | +            std::ostringstream err;
 | 
	
		
			
				|  |  | +            err << "AUTOMOC: error: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +                << "The file includes the moc file \"" << currentMoc
 | 
	
		
			
				|  |  | +                << "\", which seems to be the moc file from a different "
 | 
	
		
			
				|  |  | +                   "source file. This is not supported. Include \""
 | 
	
		
			
				|  |  | +                << scannedFileBasename
 | 
	
		
			
				|  |  | +                << ".moc\" to run moc on this source file.\n";
 | 
	
		
			
				|  |  | +            this->LogError(err.str());
 | 
	
		
			
				|  |  | +            return false;
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            // Include self
 | 
	
		
			
				|  |  | +            fileToMoc = absFilename;
 | 
	
		
			
				|  |  | +            ownDotMocIncluded = true;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (!fileToMoc.empty()) {
 | 
	
		
			
				|  |  | +          includedMocs[fileToMoc] = currentMoc;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      // Forward content pointer
 | 
	
		
			
				|  |  | +      contentChars += mocIncludeRegExp.end();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // In this case, check whether the scanned file itself contains a Q_OBJECT.
 | 
	
		
			
				|  |  | +  // If this is the case, the moc_foo.cpp should probably be generated from
 | 
	
		
			
				|  |  | +  // foo.cpp instead of foo.h, because otherwise it won't build.
 | 
	
		
			
				|  |  | +  // But warn, since this is not how it is supposed to be used.
 | 
	
		
			
				|  |  | +  if (requiresMoc && !ownDotMocIncluded) {
 | 
	
		
			
				|  |  | +    if (relaxed && ownMocUnderscoreIncluded) {
 | 
	
		
			
				|  |  | +      // This is for KDE4 compatibility:
 | 
	
		
			
				|  |  | +      std::ostringstream err;
 | 
	
		
			
				|  |  | +      err << "AUTOMOC: warning: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +          << "The file contains a " << macroName
 | 
	
		
			
				|  |  | +          << " macro, but does not include "
 | 
	
		
			
				|  |  | +          << "\"" << scannedFileBasename << ".moc\", but instead includes "
 | 
	
		
			
				|  |  | +          << "\"" << ownMocUnderscoreFile << "\". Running moc on "
 | 
	
		
			
				|  |  | +          << "\"" << absFilename << "\" ! Better include \""
 | 
	
		
			
				|  |  | +          << scannedFileBasename
 | 
	
		
			
				|  |  | +          << ".moc\" for compatibility with "
 | 
	
		
			
				|  |  | +             "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n";
 | 
	
		
			
				|  |  | +      this->LogWarning(err.str());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // Use scanned source file instead of scanned header file as moc source
 | 
	
		
			
				|  |  | +      includedMocs[absFilename] = ownMocUnderscoreFile;
 | 
	
		
			
				|  |  | +      includedMocs.erase(ownMocHeaderFile);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      // Otherwise always error out since it will not compile:
 | 
	
		
			
				|  |  | +      std::ostringstream err;
 | 
	
		
			
				|  |  | +      err << "AUTOMOC: error: " << absFilename << "\n"
 | 
	
		
			
				|  |  | +          << "The file contains a " << macroName
 | 
	
		
			
				|  |  | +          << " macro, but does not include "
 | 
	
		
			
				|  |  | +          << "\"" << scannedFileBasename << ".moc\" !\n";
 | 
	
		
			
				|  |  | +      this->LogError(err.str());
 | 
	
		
			
				|  |  | +      return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void cmQtAutoGenerators::ParseForUic(
 | 
	
		
			
				|  |  |    const std::string& absFilename,
 | 
	
		
			
				|  |  |    std::map<std::string, std::vector<std::string> >& includedUis)
 |