@@ -135,6 +135,49 @@ static std::filesystem::path normalizePath(const std::filesystem::path path)
135135 return result;
136136}
137137
138+ std::string Config::matchFilenameFromCompileCommand ()
139+ {
140+ auto path = findFile (m_cppcheck, " compile_commands.json" );
141+
142+ if (path.empty ())
143+ return " Failed to find 'compile_commands.json' in any parent directory of cppcheck" ;
144+
145+ // Read compile_commands file
146+ std::ifstream ifs (path);
147+ if (ifs.fail ())
148+ return std::strerror (errno);
149+
150+ const std::string text (std::istreambuf_iterator<char >(ifs), {});
151+
152+ // Parse JSON
153+ picojson::value compileCommands;
154+ const std::string err = picojson::parse (compileCommands, text);
155+ if (!err.empty ()) {
156+ return err;
157+ }
158+
159+ if (!compileCommands.is <picojson::array>())
160+ return " Compilation database is not a JSON array" ;
161+
162+ for (const picojson::value &fileInfo : compileCommands.get <picojson::array>()) {
163+ picojson::object obj = fileInfo.get <picojson::object>();
164+
165+ if (obj.count (" file" ) && obj[" file" ].is <std::string>()) {
166+ const std::string file = obj[" file" ].get <std::string>();
167+
168+ // TODO should we warn if the file is not found?
169+ std::error_code err;
170+ if (std::filesystem::equivalent (file, m_filename, err)) {
171+ m_filename = file;
172+ return " " ;
173+ }
174+ }
175+
176+ }
177+
178+ return " File not found" ;
179+ }
180+
138181std::string Config::parseArgs (int argc, char **argv)
139182{
140183 (void ) argc;
@@ -170,12 +213,12 @@ std::string Config::parseArgs(int argc, char **argv)
170213 return error;
171214 }
172215 if (m_configPath.empty ())
173- m_configPath = findConfig (m_filename);
216+ m_configPath = findFile (m_filename, " run-cppcheck-config.json " );
174217
175218 if (m_configPath.empty ())
176219 return " Failed to find 'run-cppcheck-config.json' in any parent directory of analyzed file" ;
177220
178- const std::string err = load (m_configPath);
221+ std::string err = load (m_configPath);
179222 if (!err.empty ())
180223 return " Failed to load '" + m_configPath.string () + " ': " + err;
181224
@@ -185,11 +228,16 @@ std::string Config::parseArgs(int argc, char **argv)
185228 if (m_filename.is_relative ())
186229 m_filename = normalizePath (std::filesystem::current_path () / m_filename);
187230
231+ err = matchFilenameFromCompileCommand ();
232+ if (!err.empty ())
233+ return
234+ " Failed to find matching file in compile_commands.json: " + err;
235+
188236 return " " ;
189237}
190238
191239// Find config file by recursively searching parent directories of input file
192- std::filesystem::path Config::findConfig (const std::filesystem::path &input_path)
240+ std::filesystem::path Config::findFile (const std::filesystem::path &input_path, const std::string &filename )
193241{
194242 auto path = input_path;
195243
@@ -198,7 +246,7 @@ std::filesystem::path Config::findConfig(const std::filesystem::path &input_path
198246
199247 do {
200248 path = path.parent_path ();
201- const auto config_path = path / " run-cppcheck-config.json " ;
249+ const auto config_path = path / filename ;
202250
203251 if (std::filesystem::exists (config_path))
204252 return config_path;
0 commit comments