
Summary: This patch introduces a new `analyzer-config` configuration: `-analyzer-config silence-checkers` which could be used to silence the given checkers. It accepts a semicolon separated list, packed into quotation marks, e.g: `-analyzer-config silence-checkers="core.DivideZero;core.NullDereference"` It could be used to "disable" core checkers, so they model the analysis as before, just if some of them are too noisy it prevents to emit reports. This patch also adds support for that new option to the scan-build. Passing the option `-disable-checker core.DivideZero` to the scan-build will be transferred to `-analyzer-config silence-checkers=core.DivideZero`. Reviewed By: NoQ, Szelethus Differential Revision: https://reviews.llvm.org/D66042 llvm-svn: 369078
195 lines
6.8 KiB
C++
195 lines
6.8 KiB
C++
//===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains special accessors for analyzer configuration options
|
|
// with string representations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
|
|
#include "clang/StaticAnalyzer/Core/Checker.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/FormattedStream.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
using namespace clang;
|
|
using namespace ento;
|
|
using namespace llvm;
|
|
|
|
void AnalyzerOptions::printFormattedEntry(
|
|
llvm::raw_ostream &Out,
|
|
std::pair<StringRef, StringRef> EntryDescPair,
|
|
size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
|
|
|
|
llvm::formatted_raw_ostream FOut(Out);
|
|
|
|
const size_t PadForDesc = InitialPad + EntryWidth;
|
|
|
|
FOut.PadToColumn(InitialPad) << EntryDescPair.first;
|
|
// If the buffer's length is greater then PadForDesc, print a newline.
|
|
if (FOut.getColumn() > PadForDesc)
|
|
FOut << '\n';
|
|
|
|
FOut.PadToColumn(PadForDesc);
|
|
|
|
if (MinLineWidth == 0) {
|
|
FOut << EntryDescPair.second;
|
|
return;
|
|
}
|
|
|
|
for (char C : EntryDescPair.second) {
|
|
if (FOut.getColumn() > MinLineWidth && C == ' ') {
|
|
FOut << '\n';
|
|
FOut.PadToColumn(PadForDesc);
|
|
continue;
|
|
}
|
|
FOut << C;
|
|
}
|
|
}
|
|
|
|
ExplorationStrategyKind
|
|
AnalyzerOptions::getExplorationStrategy() const {
|
|
auto K =
|
|
llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
|
|
ExplorationStrategy)
|
|
.Case("dfs", ExplorationStrategyKind::DFS)
|
|
.Case("bfs", ExplorationStrategyKind::BFS)
|
|
.Case("unexplored_first",
|
|
ExplorationStrategyKind::UnexploredFirst)
|
|
.Case("unexplored_first_queue",
|
|
ExplorationStrategyKind::UnexploredFirstQueue)
|
|
.Case("unexplored_first_location_queue",
|
|
ExplorationStrategyKind::UnexploredFirstLocationQueue)
|
|
.Case("bfs_block_dfs_contents",
|
|
ExplorationStrategyKind::BFSBlockDFSContents)
|
|
.Default(None);
|
|
assert(K.hasValue() && "User mode is invalid.");
|
|
return K.getValue();
|
|
}
|
|
|
|
IPAKind AnalyzerOptions::getIPAMode() const {
|
|
auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
|
|
.Case("none", IPAK_None)
|
|
.Case("basic-inlining", IPAK_BasicInlining)
|
|
.Case("inlining", IPAK_Inlining)
|
|
.Case("dynamic", IPAK_DynamicDispatch)
|
|
.Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
|
|
.Default(None);
|
|
assert(K.hasValue() && "IPA Mode is invalid.");
|
|
|
|
return K.getValue();
|
|
}
|
|
|
|
bool
|
|
AnalyzerOptions::mayInlineCXXMemberFunction(
|
|
CXXInlineableMemberKind Param) const {
|
|
if (getIPAMode() < IPAK_Inlining)
|
|
return false;
|
|
|
|
auto K =
|
|
llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
|
|
CXXMemberInliningMode)
|
|
.Case("constructors", CIMK_Constructors)
|
|
.Case("destructors", CIMK_Destructors)
|
|
.Case("methods", CIMK_MemberFunctions)
|
|
.Case("none", CIMK_None)
|
|
.Default(None);
|
|
|
|
assert(K.hasValue() && "Invalid c++ member function inlining mode.");
|
|
|
|
return *K >= Param;
|
|
}
|
|
|
|
StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName,
|
|
StringRef OptionName,
|
|
bool SearchInParents) const {
|
|
assert(!CheckerName.empty() &&
|
|
"Empty checker name! Make sure the checker object (including it's "
|
|
"bases!) if fully initialized before calling this function!");
|
|
|
|
ConfigTable::const_iterator E = Config.end();
|
|
do {
|
|
ConfigTable::const_iterator I =
|
|
Config.find((Twine(CheckerName) + ":" + OptionName).str());
|
|
if (I != E)
|
|
return StringRef(I->getValue());
|
|
size_t Pos = CheckerName.rfind('.');
|
|
if (Pos == StringRef::npos)
|
|
break;
|
|
|
|
CheckerName = CheckerName.substr(0, Pos);
|
|
} while (!CheckerName.empty() && SearchInParents);
|
|
|
|
llvm_unreachable("Unknown checker option! Did you call getChecker*Option "
|
|
"with incorrect parameters? User input must've been "
|
|
"verified by CheckerRegistry.");
|
|
|
|
return "";
|
|
}
|
|
|
|
StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
|
|
StringRef OptionName,
|
|
bool SearchInParents) const {
|
|
return getCheckerStringOption(
|
|
C->getTagDescription(), OptionName, SearchInParents);
|
|
}
|
|
|
|
bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
|
|
StringRef OptionName,
|
|
bool SearchInParents) const {
|
|
auto Ret = llvm::StringSwitch<llvm::Optional<bool>>(
|
|
getCheckerStringOption(CheckerName, OptionName,
|
|
SearchInParents))
|
|
.Case("true", true)
|
|
.Case("false", false)
|
|
.Default(None);
|
|
|
|
assert(Ret &&
|
|
"This option should be either 'true' or 'false', and should've been "
|
|
"validated by CheckerRegistry!");
|
|
|
|
return *Ret;
|
|
}
|
|
|
|
bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
|
|
StringRef OptionName,
|
|
bool SearchInParents) const {
|
|
return getCheckerBooleanOption(
|
|
C->getTagDescription(), OptionName, SearchInParents);
|
|
}
|
|
|
|
int AnalyzerOptions::getCheckerIntegerOption(StringRef CheckerName,
|
|
StringRef OptionName,
|
|
bool SearchInParents) const {
|
|
int Ret = 0;
|
|
bool HasFailed = getCheckerStringOption(CheckerName, OptionName,
|
|
SearchInParents)
|
|
.getAsInteger(0, Ret);
|
|
assert(!HasFailed &&
|
|
"This option should be numeric, and should've been validated by "
|
|
"CheckerRegistry!");
|
|
(void)HasFailed;
|
|
return Ret;
|
|
}
|
|
|
|
int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
|
|
StringRef OptionName,
|
|
bool SearchInParents) const {
|
|
return getCheckerIntegerOption(
|
|
C->getTagDescription(), OptionName, SearchInParents);
|
|
}
|