| 1724 | } |
| 1725 | |
| 1726 | void CppCheck::analyseClangTidy(const FileSettings &fileSettings) |
| 1727 | { |
| 1728 | std::string allIncludes; |
| 1729 | for (const std::string &inc : fileSettings.includePaths) { |
| 1730 | allIncludes = allIncludes + "-I\"" + inc + "\" "; |
| 1731 | } |
| 1732 | |
| 1733 | const std::string allDefines = getDefinesFlags(fileSettings.defines); |
| 1734 | |
| 1735 | std::string exe = mSettings.clangTidyExecutable; |
| 1736 | #ifdef _WIN32 |
| 1737 | // TODO: is this even necessary? |
| 1738 | // append .exe if it is not a path |
| 1739 | if (Path::fromNativeSeparators(mSettings.clangTidyExecutable).find('/') == std::string::npos) { |
| 1740 | exe += ".exe"; |
| 1741 | } |
| 1742 | #endif |
| 1743 | |
| 1744 | if (!mExecuteCommand) { |
| 1745 | std::cerr << "Failed to execute '" << exe << "' (no command callback provided)" << std::endl; |
| 1746 | return; |
| 1747 | } |
| 1748 | |
| 1749 | // TODO: log this call |
| 1750 | // TODO: get rid of hard-coded checks |
| 1751 | const std::string args = "-quiet -checks=*,-clang-analyzer-*,-llvm* \"" + fileSettings.filename() + "\" -- " + allIncludes + allDefines; |
| 1752 | std::string output; |
| 1753 | if (const int exitcode = mExecuteCommand(exe, split(args), "2>&1", output)) { |
| 1754 | // TODO: needs to be a proper error |
| 1755 | std::cerr << "Failed to execute '" << exe << "' (exitcode: " << std::to_string(exitcode) << ")" << std::endl; |
| 1756 | return; |
| 1757 | } |
| 1758 | |
| 1759 | // parse output and create error messages |
| 1760 | std::istringstream istr(output); |
| 1761 | std::string line; |
| 1762 | |
| 1763 | if (!mSettings.buildDir.empty()) { |
| 1764 | const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, fileSettings.sfilename(), "", fileSettings.file.fsFileId()); |
| 1765 | std::ofstream fcmd(analyzerInfoFile + ".clang-tidy-cmd"); |
| 1766 | fcmd << istr.str(); |
| 1767 | } |
| 1768 | |
| 1769 | // TODO: log |
| 1770 | while (std::getline(istr, line)) { |
| 1771 | if (line.find("error") == std::string::npos && line.find("warning") == std::string::npos) |
| 1772 | continue; |
| 1773 | |
| 1774 | std::size_t endColumnPos = line.find(": error:"); |
| 1775 | if (endColumnPos == std::string::npos) { |
| 1776 | endColumnPos = line.find(": warning:"); |
| 1777 | } |
| 1778 | |
| 1779 | const std::size_t endLinePos = line.rfind(':', endColumnPos-1); |
| 1780 | const std::size_t endNamePos = line.rfind(':', endLinePos - 1); |
| 1781 | const std::size_t endMsgTypePos = line.find(':', endColumnPos + 2); |
| 1782 | const std::size_t endErrorPos = line.rfind('[', std::string::npos); |
| 1783 | if (endLinePos==std::string::npos || endNamePos==std::string::npos || endMsgTypePos==std::string::npos || endErrorPos==std::string::npos) |
nothing calls this directly
no test coverage detected