@@ -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