cmcmd: Restore support for running multiple lint tools

Refactoring in commit v3.10.0-rc1~115^2 (Clean up iwyu code to not be
one big if statement, 2017-08-28) incorrectly changed the logic to run
only one lint tool at a time.  Restore support for running all tools
specified on the command-line.
This commit is contained in:
Brad King
2017-10-27 08:31:34 -04:00
parent a5197eeac7
commit 992962c76d
15 changed files with 165 additions and 60 deletions
+65 -55
View File
@@ -33,15 +33,13 @@
#include "cmsys/Process.h" #include "cmsys/Process.h"
#include "cmsys/Terminal.h" #include "cmsys/Terminal.h"
#include <algorithm> #include <algorithm>
#include <functional>
#include <iostream> #include <iostream>
#include <map>
#include <memory> // IWYU pragma: keep #include <memory> // IWYU pragma: keep
#include <sstream> #include <sstream>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <time.h> #include <time.h>
#include <utility>
class cmConnection; class cmConnection;
@@ -328,35 +326,41 @@ static int HandleCppCheck(const std::string& runCmd,
return 0; return 0;
} }
typedef int (*CoCompileHandler)(const std::string&, const std::string&,
const std::vector<std::string>&);
struct CoCompiler
{
const char* Option;
CoCompileHandler Handler;
bool NoOriginalCommand;
};
static CoCompiler CoCompilers[] = { // Table of options and handlers.
{ "--cppcheck=", HandleCppCheck, false },
{ "--cpplint=", HandleCppLint, false },
{ "--iwyu=", HandleIWYU, false },
{ "--lwyu=", HandleLWYU, true },
{ "--tidy=", HandleTidy, false }
};
struct CoCompileJob
{
std::string Command;
CoCompileHandler Handler;
};
// called when args[0] == "__run_co_compile" // called when args[0] == "__run_co_compile"
int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args) int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
{ {
// initialize a map from command option to handler function std::vector<CoCompileJob> jobs;
std::map<std::string, std::string sourceFile; // store --source=
std::function<int(const std::string&, const std::string&,
const std::vector<std::string>&)>> // Default is to run the original command found after -- if the option
coCompileTypes; // does not need to do that, it should be specified here, currently only
auto a1 = std::placeholders::_1; // lwyu does that.
auto a2 = std::placeholders::_2; bool runOriginalCmd = true;
auto a3 = std::placeholders::_3;
// create a map from option to handler function for option
// if the option does not call the original command then it will need
// to set runOriginalCmd to false later in this function
coCompileTypes["--iwyu="] = std::bind(&HandleIWYU, a1, a2, a3);
coCompileTypes["--tidy="] = std::bind(&HandleTidy, a1, a2, a3);
coCompileTypes["--lwyu="] = std::bind(&HandleLWYU, a1, a2, a3);
coCompileTypes["--cpplint="] = std::bind(&HandleCppLint, a1, a2, a3);
coCompileTypes["--cppcheck="] = std::bind(&HandleCppCheck, a1, a2, a3);
// copy the command options to a vector of strings
std::vector<std::string> commandOptions;
commandOptions.reserve(coCompileTypes.size());
for (const auto& i : coCompileTypes) {
commandOptions.push_back(i.first);
}
std::string runCmd; // command to be run from --thing=command
std::string sourceFile; // store --source=
std::string commandFound; // the command that was in the args list
std::vector<std::string> orig_cmd; std::vector<std::string> orig_cmd;
bool doing_options = true; bool doing_options = true;
for (std::string::size_type i = 2; i < args.size(); ++i) { for (std::string::size_type i = 2; i < args.size(); ++i) {
@@ -367,20 +371,25 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
doing_options = false; doing_options = false;
} else if (doing_options) { } else if (doing_options) {
bool optionFound = false; bool optionFound = false;
// check arg against all the commandOptions for (CoCompiler const* cc = cmArrayBegin(CoCompilers);
for (auto const& command : commandOptions) { cc != cmArrayEnd(CoCompilers); ++cc) {
if (arg.compare(0, command.size(), command) == 0) { size_t optionLen = strlen(cc->Option);
if (arg.compare(0, optionLen, cc->Option) == 0) {
optionFound = true; optionFound = true;
runCmd = arg.substr(command.size()); CoCompileJob job;
commandFound = command; job.Command = arg.substr(optionLen);
job.Handler = cc->Handler;
jobs.push_back(std::move(job));
if (cc->NoOriginalCommand) {
runOriginalCmd = false;
}
} }
} }
// check arg with --source=
if (cmHasLiteralPrefix(arg, "--source=")) { if (cmHasLiteralPrefix(arg, "--source=")) {
sourceFile = arg.substr(9); sourceFile = arg.substr(9);
optionFound = true; optionFound = true;
} }
// if it was not a commandOptions or --source then error // if it was not a co-compiler or --source then error
if (!optionFound) { if (!optionFound) {
std::cerr << "__run_co_compile given unknown argument: " << arg std::cerr << "__run_co_compile given unknown argument: " << arg
<< "\n"; << "\n";
@@ -390,39 +399,40 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string>& args)
orig_cmd.push_back(arg); orig_cmd.push_back(arg);
} }
} }
if (commandFound.empty()) { if (jobs.empty()) {
std::cerr << "__run_co_compile missing command to run. Looking for one of " std::cerr << "__run_co_compile missing command to run. "
"the following:\n"; "Looking for one or more of the following:\n";
for (const auto& i : commandOptions) { for (CoCompiler const* cc = cmArrayBegin(CoCompilers);
std::cerr << i << "\n"; cc != cmArrayEnd(CoCompilers); ++cc) {
std::cerr << cc->Option << "\n";
} }
return 1; return 1;
} }
// Default is to run the original command found after -- if the option
// does not need to do that, it should be specified here, currently only
// lwyu does that.
bool runOriginalCmd = true;
if (commandFound == "--lwyu=") {
runOriginalCmd = false;
}
if (runOriginalCmd && orig_cmd.empty()) { if (runOriginalCmd && orig_cmd.empty()) {
std::cerr << "__run_co_compile missing compile command after --\n"; std::cerr << "__run_co_compile missing compile command after --\n";
return 1; return 1;
} }
// call the command handler here for (CoCompileJob const& job : jobs) {
int ret = coCompileTypes[commandFound](runCmd, sourceFile, orig_cmd); // call the command handler here
// if the command returns non-zero then return and fail. int ret = job.Handler(job.Command, sourceFile, orig_cmd);
// for commands that do not want to break the build, they should return
// 0 no matter what. // if the command returns non-zero then return and fail.
if (ret != 0) { // for commands that do not want to break the build, they should return
return ret; // 0 no matter what.
if (ret != 0) {
return ret;
}
} }
// if there is no original command to run return now // if there is no original command to run return now
if (!runOriginalCmd) { if (!runOriginalCmd) {
return ret; return 0;
} }
// Now run the real compiler command and return its result value // Now run the real compiler command and return its result value
int ret;
if (!cmSystemTools::RunSingleCommand(orig_cmd, nullptr, nullptr, &ret, if (!cmSystemTools::RunSingleCommand(orig_cmd, nullptr, nullptr, &ret,
nullptr, nullptr,
cmSystemTools::OUTPUT_PASSTHROUGH)) { cmSystemTools::OUTPUT_PASSTHROUGH)) {
+6
View File
@@ -370,6 +370,12 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>) add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>)
add_RunCMake_test(Cpplint -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>) add_RunCMake_test(Cpplint -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>)
add_RunCMake_test(Cppcheck -DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>) add_RunCMake_test(Cppcheck -DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>)
add_RunCMake_test(MultiLint
-DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>
-DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>
-DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>
-DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>
)
if(DEFINED CMake_TEST_CUDA) if(DEFINED CMake_TEST_CUDA)
list(APPEND CompilerLauncher_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA}) list(APPEND CompilerLauncher_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
endif() endif()
@@ -1,5 +1,6 @@
^__run_co_compile missing command to run. Looking for one of the following: ^__run_co_compile missing command to run. Looking for one or more of the following:
.*--cppcheck= --cppcheck=
.*--cpplint= --cpplint=
.*--iwyu= --iwyu=
.*--tidy= --lwyu=
--tidy=
@@ -0,0 +1,8 @@
Warning: include-what-you-use reported diagnostics:
should add these lines:
*
#include <\.\.\.>
+
.*Tests[/\]RunCMake[/\]MultiLint[/\]main\.c:0:0: warning: message \[checker\].*
Total errors found: 0
.*Warning: cppcheck reported diagnostics.*error.*warning.*style.*performance.*information.*
@@ -0,0 +1,8 @@
Warning: include-what-you-use reported diagnostics:
should add these lines:
*
#include <\.\.\.>
+
.*Tests[/\]RunCMake[/\]MultiLint[/\]main\.c:0:0: warning: message \[checker\].*
Total errors found: 0
.*Warning: cppcheck reported diagnostics.*error.*warning.*style.*performance.*information.*
+3
View File
@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(C.cmake)
+6
View File
@@ -0,0 +1,6 @@
enable_language(C)
set(CMAKE_C_INCLUDE_WHAT_YOU_USE "${PSEUDO_IWYU}" -some -args)
set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
set(CMAKE_C_CPPLINT "${PSEUDO_CPPLINT}" --verbose=0 --linelength=80)
set(CMAKE_C_CPPCHECK "${PSEUDO_CPPCHECK}")
add_executable(main main.c)
+3
View File
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.10)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
@@ -0,0 +1,8 @@
Warning: include-what-you-use reported diagnostics:
should add these lines:
*
#include <\.\.\.>
+
.*Tests[/\]RunCMake[/\]MultiLint[/\]main\.cxx:0:0: warning: message \[checker\].*
Total errors found: 0
.*Warning: cppcheck reported diagnostics.*error.*warning.*style.*performance.*information.*
@@ -0,0 +1,8 @@
Warning: include-what-you-use reported diagnostics:
should add these lines:
*
#include <\.\.\.>
+
.*Tests[/\]RunCMake[/\]MultiLint[/\]main\.cxx:0:0: warning: message \[checker\].*
Total errors found: 0
.*Warning: cppcheck reported diagnostics.*error.*warning.*style.*performance.*information.*
@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(CXX.cmake)
+6
View File
@@ -0,0 +1,6 @@
enable_language(CXX)
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${PSEUDO_IWYU}" -some -args)
set(CMAKE_CXX_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
set(CMAKE_CXX_CPPLINT "${PSEUDO_CPPLINT}" --verbose=0 --linelength=80)
set(CMAKE_CXX_CPPCHECK "${PSEUDO_CPPCHECK}")
add_executable(main main.cxx)
@@ -0,0 +1,27 @@
include(RunCMake)
set(RunCMake_TEST_OPTIONS
"-DPSEUDO_CPPCHECK=${PSEUDO_CPPCHECK}"
"-DPSEUDO_CPPLINT=${PSEUDO_CPPLINT}"
"-DPSEUDO_IWYU=${PSEUDO_IWYU}"
"-DPSEUDO_TIDY=${PSEUDO_TIDY}"
)
function(run_multilint lang)
# Use a single build tree for tests without cleaning.
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${lang}-build")
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(${lang})
set(RunCMake_TEST_OUTPUT_MERGE 1)
run_cmake_command(${lang}-Build ${CMAKE_COMMAND} --build .)
endfunction()
run_multilint(C)
run_multilint(CXX)
if(NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
run_multilint(C-launch)
run_multilint(CXX-launch)
endif()
+4
View File
@@ -0,0 +1,4 @@
int main(void)
{
return 0;
}
+4
View File
@@ -0,0 +1,4 @@
int main()
{
return 0;
}