@@ -181,8 +181,10 @@ static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group,
181
181
}
182
182
}
183
183
184
+ // Parse the Static Analyzer configuration. If \p Diags is set to nullptr,
185
+ // it won't verify the input.
184
186
static void parseAnalyzerConfigs (AnalyzerOptions &AnOpts,
185
- DiagnosticsEngine & Diags);
187
+ DiagnosticsEngine * Diags);
186
188
187
189
static void getAllNoBuiltinFuncValues (ArgList &Args,
188
190
std::vector<std::string> &Funcs) {
@@ -284,6 +286,12 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
284
286
Opts.ShowCheckerHelp = Args.hasArg (OPT_analyzer_checker_help);
285
287
Opts.ShowConfigOptionsList = Args.hasArg (OPT_analyzer_config_help);
286
288
Opts.ShowEnabledCheckerList = Args.hasArg (OPT_analyzer_list_enabled_checkers);
289
+ Opts.ShouldEmitErrorsOnInvalidConfigValue =
290
+ /* negated */ !llvm::StringSwitch<bool >(
291
+ Args.getLastArgValue (OPT_analyzer_config_compatibility_mode))
292
+ .Case (" true" , true )
293
+ .Case (" false" , false )
294
+ .Default (false );
287
295
Opts.DisableAllChecks = Args.hasArg (OPT_analyzer_disable_all_checks);
288
296
289
297
Opts.visualizeExplodedGraphWithGraphViz =
@@ -320,7 +328,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
320
328
321
329
// Go through the analyzer configuration options.
322
330
for (const auto *A : Args.filtered (OPT_analyzer_config)) {
323
- A-> claim ();
331
+
324
332
// We can have a list of comma separated config names, e.g:
325
333
// '-analyzer-config key1=val1,key2=val2'
326
334
StringRef configList = A->getValue ();
@@ -342,11 +350,24 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
342
350
Success = false ;
343
351
break ;
344
352
}
353
+
354
+ // TODO: Check checker options too, possibly in CheckerRegistry.
355
+ // Leave unknown non-checker configs unclaimed.
356
+ if (!key.contains (" :" ) && Opts.isUnknownAnalyzerConfig (key)) {
357
+ if (Opts.ShouldEmitErrorsOnInvalidConfigValue )
358
+ Diags.Report (diag::err_analyzer_config_unknown) << key;
359
+ continue ;
360
+ }
361
+
362
+ A->claim ();
345
363
Opts.Config [key] = val;
346
364
}
347
365
}
348
366
349
- parseAnalyzerConfigs (Opts, Diags);
367
+ if (Opts.ShouldEmitErrorsOnInvalidConfigValue )
368
+ parseAnalyzerConfigs (Opts, &Diags);
369
+ else
370
+ parseAnalyzerConfigs (Opts, nullptr );
350
371
351
372
llvm::raw_string_ostream os (Opts.FullCompilerInvocation );
352
373
for (unsigned i = 0 ; i < Args.getNumInputArgStrings (); ++i) {
@@ -365,56 +386,82 @@ static StringRef getStringOption(AnalyzerOptions::ConfigTable &Config,
365
386
}
366
387
367
388
static void initOption (AnalyzerOptions::ConfigTable &Config,
389
+ DiagnosticsEngine *Diags,
368
390
StringRef &OptionField, StringRef Name,
369
391
StringRef DefaultVal) {
392
+ // String options may be known to invalid (e.g. if the expected string is a
393
+ // file name, but the file does not exist), those will have to be checked in
394
+ // parseConfigs.
370
395
OptionField = getStringOption (Config, Name, DefaultVal);
371
396
}
372
397
373
398
static void initOption (AnalyzerOptions::ConfigTable &Config,
399
+ DiagnosticsEngine *Diags,
374
400
bool &OptionField, StringRef Name, bool DefaultVal) {
375
- // FIXME: We should emit a warning here if the value is something other than
376
- // "true", "false", or the empty string (meaning the default value),
377
- // but the AnalyzerOptions doesn't have access to a diagnostic engine.
378
- OptionField = llvm::StringSwitch<bool >(getStringOption (Config, Name,
379
- (DefaultVal ? " true" : " false" )))
401
+ auto PossiblyInvalidVal = llvm::StringSwitch<Optional<bool >>(
402
+ getStringOption (Config, Name, (DefaultVal ? " true" : " false" )))
380
403
.Case (" true" , true )
381
404
.Case (" false" , false )
382
- .Default (DefaultVal);
405
+ .Default (None);
406
+
407
+ if (!PossiblyInvalidVal) {
408
+ if (Diags)
409
+ Diags->Report (diag::err_analyzer_config_invalid_input)
410
+ << Name << " a boolean" ;
411
+ else
412
+ OptionField = DefaultVal;
413
+ } else
414
+ OptionField = PossiblyInvalidVal.getValue ();
383
415
}
384
416
385
417
static void initOption (AnalyzerOptions::ConfigTable &Config,
418
+ DiagnosticsEngine *Diags,
386
419
unsigned &OptionField, StringRef Name,
387
420
unsigned DefaultVal) {
421
+
388
422
OptionField = DefaultVal;
389
423
bool HasFailed = getStringOption (Config, Name, std::to_string (DefaultVal))
390
424
.getAsInteger (10 , OptionField);
391
- assert (!HasFailed && " analyzer-config option should be numeric" );
392
- (void )HasFailed;
425
+ if (Diags && HasFailed)
426
+ Diags->Report (diag::err_analyzer_config_invalid_input)
427
+ << Name << " an unsigned" ;
393
428
}
394
429
395
430
static void parseAnalyzerConfigs (AnalyzerOptions &AnOpts,
396
- DiagnosticsEngine &Diags) {
397
- // TODO: Emit warnings for incorrect options.
431
+ DiagnosticsEngine *Diags) {
398
432
// TODO: There's no need to store the entire configtable, it'd be plenty
399
433
// enough tostore checker options.
400
434
401
435
#define ANALYZER_OPTION (TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL ) \
402
- initOption (AnOpts.Config , AnOpts.NAME , CMDFLAG, DEFAULT_VAL); \
436
+ initOption (AnOpts.Config , Diags, AnOpts.NAME , CMDFLAG, DEFAULT_VAL);
403
437
404
438
#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE (TYPE, NAME, CMDFLAG, DESC, \
405
439
SHALLOW_VAL, DEEP_VAL) \
406
440
switch (AnOpts.getUserMode ()) { \
407
441
case UMK_Shallow: \
408
- initOption (AnOpts.Config , AnOpts.NAME , CMDFLAG, SHALLOW_VAL); \
442
+ initOption (AnOpts.Config , Diags, AnOpts.NAME , CMDFLAG, SHALLOW_VAL); \
409
443
break ; \
410
444
case UMK_Deep: \
411
- initOption (AnOpts.Config , AnOpts.NAME , CMDFLAG, DEEP_VAL); \
445
+ initOption (AnOpts.Config , Diags, AnOpts.NAME , CMDFLAG, DEEP_VAL); \
412
446
break ; \
413
447
} \
414
448
415
449
#include " clang/StaticAnalyzer/Core/AnalyzerOptions.def"
416
450
#undef ANALYZER_OPTION
417
451
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
452
+
453
+ // At this point, AnalyzerOptions is configured. Let's validate some options.
454
+
455
+ if (!Diags)
456
+ return ;
457
+
458
+ if (!AnOpts.CTUDir .empty () && !llvm::sys::fs::is_directory (AnOpts.CTUDir ))
459
+ Diags->Report (diag::err_analyzer_config_invalid_input)
460
+ << " ctu-dir" << " a filename" ;
461
+
462
+ if (!AnOpts.CTUDir .empty () && !llvm::sys::fs::is_directory (AnOpts.CTUDir ))
463
+ Diags->Report (diag::err_analyzer_config_invalid_input)
464
+ << " model-path" << " a filename" ;
418
465
}
419
466
420
467
static bool ParseMigratorArgs (MigratorOptions &Opts, ArgList &Args) {
0 commit comments