@@ -135,6 +135,49 @@ static std::filesystem::path normalizePath(const std::filesystem::path path)
135
135
return result;
136
136
}
137
137
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
+
138
181
std::string Config::parseArgs (int argc, char **argv)
139
182
{
140
183
(void ) argc;
@@ -170,12 +213,12 @@ std::string Config::parseArgs(int argc, char **argv)
170
213
return error;
171
214
}
172
215
if (m_configPath.empty ())
173
- m_configPath = findConfig (m_filename);
216
+ m_configPath = findFile (m_filename, " run-cppcheck-config.json " );
174
217
175
218
if (m_configPath.empty ())
176
219
return " Failed to find 'run-cppcheck-config.json' in any parent directory of analyzed file" ;
177
220
178
- const std::string err = load (m_configPath);
221
+ std::string err = load (m_configPath);
179
222
if (!err.empty ())
180
223
return " Failed to load '" + m_configPath.string () + " ': " + err;
181
224
@@ -185,11 +228,16 @@ std::string Config::parseArgs(int argc, char **argv)
185
228
if (m_filename.is_relative ())
186
229
m_filename = normalizePath (std::filesystem::current_path () / m_filename);
187
230
231
+ err = matchFilenameFromCompileCommand ();
232
+ if (!err.empty ())
233
+ return
234
+ " Failed to find matching file in compile_commands.json: " + err;
235
+
188
236
return " " ;
189
237
}
190
238
191
239
// 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 )
193
241
{
194
242
auto path = input_path;
195
243
@@ -198,7 +246,7 @@ std::filesystem::path Config::findConfig(const std::filesystem::path &input_path
198
246
199
247
do {
200
248
path = path.parent_path ();
201
- const auto config_path = path / " run-cppcheck-config.json " ;
249
+ const auto config_path = path / filename ;
202
250
203
251
if (std::filesystem::exists (config_path))
204
252
return config_path;
0 commit comments