Support clang tidy (#2486)
This commit is contained in:
parent
dcee189146
commit
d82da987e5
|
@ -925,6 +925,8 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
|
||||||
++c;
|
++c;
|
||||||
if (!settings.quiet)
|
if (!settings.quiet)
|
||||||
reportStatus(c, settings.project.fileSettings.size(), c, settings.project.fileSettings.size());
|
reportStatus(c, settings.project.fileSettings.size(), c, settings.project.fileSettings.size());
|
||||||
|
if(settings.clangTidy)
|
||||||
|
cppcheck.analyseClangTidy(fs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1352,6 +1352,83 @@ void CppCheck::getErrorMessages()
|
||||||
Preprocessor::getErrorMessages(this, &s);
|
Preprocessor::getErrorMessages(this, &s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppCheck::analyseClangTidy(const ImportProject::FileSettings &fileSettings )
|
||||||
|
{
|
||||||
|
std::string allIncludes = "";
|
||||||
|
std::string allDefines = "-D"+fileSettings.defines;
|
||||||
|
for (const std::string &inc : fileSettings.includePaths) {
|
||||||
|
allIncludes = allIncludes + "-I\"" + inc + "\" ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::size_type pos = 0u;
|
||||||
|
while ((pos = allDefines.find(";", pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
allDefines.replace(pos, 1, " -D");
|
||||||
|
pos += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string cmd = "clang-tidy -quiet -checks=*,-clang-analyzer-*,-llvm* \"" + fileSettings.filename + "\" -- " + allIncludes + allDefines;
|
||||||
|
std::pair<bool, std::string> result = executeCommand(cmd);
|
||||||
|
if (!result.first) {
|
||||||
|
std::cerr << "Failed to execute '" + cmd + "'" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse output and create error messages
|
||||||
|
std::istringstream istr(result.second);
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
if (!mSettings.buildDir.empty())
|
||||||
|
{
|
||||||
|
const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, fileSettings.filename, "");
|
||||||
|
std::ofstream fcmd(analyzerInfoFile + ".clang-tidy-cmd");
|
||||||
|
fcmd << istr.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (std::getline(istr, line)) {
|
||||||
|
if (line.find("error") == std::string::npos && line.find("warning") == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::size_t endColumnPos = line.find(": error:");
|
||||||
|
if (endColumnPos == std::string::npos) {
|
||||||
|
endColumnPos = line.find(": warning:");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t endLinePos = line.rfind(":", endColumnPos-1);
|
||||||
|
const std::size_t endNamePos = line.rfind(":", endLinePos - 1);
|
||||||
|
const std::size_t endMsgTypePos = line.find(':', endColumnPos + 2);
|
||||||
|
const std::size_t endErrorPos = line.rfind('[', std::string::npos);
|
||||||
|
|
||||||
|
const std::string lineNumString = line.substr(endNamePos + 1, endLinePos - endNamePos - 1);
|
||||||
|
const std::string columnNumString = line.substr(endLinePos + 1, endColumnPos - endLinePos - 1);
|
||||||
|
const std::string errorTypeString = line.substr(endColumnPos + 1, endMsgTypePos - endColumnPos - 1);
|
||||||
|
const std::string messageString = line.substr(endMsgTypePos + 1, endErrorPos - endMsgTypePos - 1);
|
||||||
|
const std::string errorString = line.substr(endErrorPos, line.length());
|
||||||
|
|
||||||
|
std::string fixedpath = Path::simplifyPath(line.substr(0, endNamePos));
|
||||||
|
const int64_t lineNumber = std::atol(lineNumString.c_str());
|
||||||
|
const int64_t column = std::atol(columnNumString.c_str());
|
||||||
|
fixedpath = Path::toNativeSeparators(fixedpath);
|
||||||
|
|
||||||
|
ErrorLogger::ErrorMessage errmsg;
|
||||||
|
errmsg.callStack.emplace_back(ErrorLogger::ErrorMessage::FileLocation(fixedpath, lineNumber, column));
|
||||||
|
|
||||||
|
errmsg.id = "clang-tidy-" + errorString.substr(1, errorString.length() - 2);
|
||||||
|
if (errmsg.id.find("performance") != std::string::npos)
|
||||||
|
errmsg.severity = Severity::SeverityType::performance;
|
||||||
|
else if (errmsg.id.find("portability") != std::string::npos)
|
||||||
|
errmsg.severity = Severity::SeverityType::portability;
|
||||||
|
else if (errmsg.id.find("cert") != std::string::npos || errmsg.id.find("misc") != std::string::npos || errmsg.id.find("unused") != std::string::npos)
|
||||||
|
errmsg.severity = Severity::SeverityType::warning;
|
||||||
|
else
|
||||||
|
errmsg.severity = Severity::SeverityType::style;
|
||||||
|
|
||||||
|
errmsg.file0 = fixedpath;
|
||||||
|
errmsg.setmsg(messageString);
|
||||||
|
reportErr(errmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CppCheck::analyseWholeProgram()
|
bool CppCheck::analyseWholeProgram()
|
||||||
{
|
{
|
||||||
bool errors = false;
|
bool errors = false;
|
||||||
|
|
|
@ -136,6 +136,9 @@ public:
|
||||||
*/
|
*/
|
||||||
bool analyseWholeProgram();
|
bool analyseWholeProgram();
|
||||||
|
|
||||||
|
/** Analyze all files using clang-tidy */
|
||||||
|
void analyseClangTidy(const ImportProject::FileSettings &fileSettings);
|
||||||
|
|
||||||
/** analyse whole program use .analyzeinfo files */
|
/** analyse whole program use .analyzeinfo files */
|
||||||
void analyseWholeProgram(const std::string &buildDir, const std::map<std::string, std::size_t> &files);
|
void analyseWholeProgram(const std::string &buildDir, const std::map<std::string, std::size_t> &files);
|
||||||
|
|
||||||
|
|
|
@ -1026,9 +1026,13 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
temp.addons = readXmlStringList(node, "", CppcheckXml::AddonElementName, nullptr);
|
temp.addons = readXmlStringList(node, "", CppcheckXml::AddonElementName, nullptr);
|
||||||
else if (strcmp(node->Name(), CppcheckXml::TagsElementName) == 0)
|
else if (strcmp(node->Name(), CppcheckXml::TagsElementName) == 0)
|
||||||
node->Attribute(CppcheckXml::TagElementName); // FIXME: Write some warning
|
node->Attribute(CppcheckXml::TagElementName); // FIXME: Write some warning
|
||||||
else if (strcmp(node->Name(), CppcheckXml::ToolsElementName) == 0)
|
else if (strcmp(node->Name(), CppcheckXml::ToolsElementName) == 0) {
|
||||||
node->Attribute(CppcheckXml::ToolElementName); // FIXME: Write some warning
|
const std::list<std::string> toolList = readXmlStringList(node, "", CppcheckXml::ToolElementName, nullptr);
|
||||||
else if (strcmp(node->Name(), CppcheckXml::CheckHeadersElementName) == 0)
|
for (const std::string &toolName : toolList) {
|
||||||
|
if (toolName == std::string(CppcheckXml::ClangTidy))
|
||||||
|
temp.clangTidy = true;
|
||||||
|
}
|
||||||
|
} else if (strcmp(node->Name(), CppcheckXml::CheckHeadersElementName) == 0)
|
||||||
temp.checkHeaders = (strcmp(node->GetText(), "true") == 0);
|
temp.checkHeaders = (strcmp(node->GetText(), "true") == 0);
|
||||||
else if (strcmp(node->Name(), CppcheckXml::CheckUnusedTemplatesElementName) == 0)
|
else if (strcmp(node->Name(), CppcheckXml::CheckUnusedTemplatesElementName) == 0)
|
||||||
temp.checkUnusedTemplates = (strcmp(node->GetText(), "true") == 0);
|
temp.checkUnusedTemplates = (strcmp(node->GetText(), "true") == 0);
|
||||||
|
@ -1059,6 +1063,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
settings->userDefines = temp.userDefines;
|
settings->userDefines = temp.userDefines;
|
||||||
settings->userUndefs = temp.userUndefs;
|
settings->userUndefs = temp.userUndefs;
|
||||||
settings->addons = temp.addons;
|
settings->addons = temp.addons;
|
||||||
|
settings->clangTidy = temp.clangTidy;
|
||||||
for (const std::string &p : paths)
|
for (const std::string &p : paths)
|
||||||
guiProject.pathNames.push_back(p);
|
guiProject.pathNames.push_back(p);
|
||||||
for (const std::string &supp : suppressions)
|
for (const std::string &supp : suppressions)
|
||||||
|
|
|
@ -152,6 +152,7 @@ namespace CppcheckXml {
|
||||||
const char CheckUnusedTemplatesElementName[] = "check-unused-templates";
|
const char CheckUnusedTemplatesElementName[] = "check-unused-templates";
|
||||||
const char MaxCtuDepthElementName[] = "max-ctu-depth";
|
const char MaxCtuDepthElementName[] = "max-ctu-depth";
|
||||||
const char CheckUnknownFunctionReturn[] = "check-unknown-function-return-values";
|
const char CheckUnknownFunctionReturn[] = "check-unknown-function-return-values";
|
||||||
|
const char ClangTidy[] = "clang-tidy";
|
||||||
const char Name[] = "name";
|
const char Name[] = "name";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ Settings::Settings()
|
||||||
checkHeaders(true),
|
checkHeaders(true),
|
||||||
checkUnusedTemplates(false),
|
checkUnusedTemplates(false),
|
||||||
clang(false),
|
clang(false),
|
||||||
|
clangTidy(false),
|
||||||
debugSimplified(false),
|
debugSimplified(false),
|
||||||
debugnormal(false),
|
debugnormal(false),
|
||||||
debugwarnings(false),
|
debugwarnings(false),
|
||||||
|
|
|
@ -99,6 +99,9 @@ public:
|
||||||
/** Use Clang */
|
/** Use Clang */
|
||||||
bool clang;
|
bool clang;
|
||||||
|
|
||||||
|
/** Use clang-tidy */
|
||||||
|
bool clangTidy;
|
||||||
|
|
||||||
/** @brief include paths excluded from checking the configuration */
|
/** @brief include paths excluded from checking the configuration */
|
||||||
std::set<std::string> configExcludePaths;
|
std::set<std::string> configExcludePaths;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue