llvm-project/llvm/lib/Support/SpecialCaseList.cpp
serge-sans-paille 75e164f61d [llvm] Cleanup header dependencies in ADT and Support
The cleanup was manual, but assisted by "include-what-you-use". It consists in

1. Removing unused forward declaration. No impact expected.
2. Removing unused headers in .cpp files. No impact expected.
3. Removing unused headers in .h files. This removes implicit dependencies and
   is generally considered a good thing, but this may break downstream builds.
   I've updated llvm, clang, lld, lldb and mlir deps, and included a list of the
   modification in the second part of the commit.
4. Replacing header inclusion by forward declaration. This has the same impact
   as 3.

Notable changes:

- llvm/Support/TargetParser.h no longer includes llvm/Support/AArch64TargetParser.h nor llvm/Support/ARMTargetParser.h
- llvm/Support/TypeSize.h no longer includes llvm/Support/WithColor.h
- llvm/Support/YAMLTraits.h no longer includes llvm/Support/Regex.h
- llvm/ADT/SmallVector.h no longer includes llvm/Support/MemAlloc.h nor llvm/Support/ErrorHandling.h

You may need to add some of these headers in your compilation units, if needs be.

As an hint to the impact of the cleanup, running

clang++ -E  -Iinclude -I../llvm/include ../llvm/lib/Support/*.cpp -std=c++14 -fno-rtti -fno-exceptions | wc -l

before: 8000919 lines
after:  7917500 lines

Reduced dependencies also helps incremental rebuilds and is more ccache
friendly, something not shown by the above metric :-)

Discourse thread on the topic: https://llvm.discourse.group/t/include-what-you-use-include-cleanup/5831
2022-01-21 13:54:49 +01:00

233 lines
7.5 KiB
C++

//===-- SpecialCaseList.cpp - special case list for sanitizers ------------===//
//
// 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 is a utility class for instrumentation passes (like AddressSanitizer
// or ThreadSanitizer) to avoid instrumenting some functions or global
// variables, or to instrument some functions or global variables in a specific
// way, based on a user-supplied list.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/SpecialCaseList.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <string>
#include <system_error>
#include <utility>
#include <stdio.h>
namespace llvm {
bool SpecialCaseList::Matcher::insert(std::string Regexp,
unsigned LineNumber,
std::string &REError) {
if (Regexp.empty()) {
REError = "Supplied regexp was blank";
return false;
}
if (Regex::isLiteralERE(Regexp)) {
Strings[Regexp] = LineNumber;
return true;
}
Trigrams.insert(Regexp);
// Replace * with .*
for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
pos += strlen(".*")) {
Regexp.replace(pos, strlen("*"), ".*");
}
Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
// Check that the regexp is valid.
Regex CheckRE(Regexp);
if (!CheckRE.isValid(REError))
return false;
RegExes.emplace_back(
std::make_pair(std::make_unique<Regex>(std::move(CheckRE)), LineNumber));
return true;
}
unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
auto It = Strings.find(Query);
if (It != Strings.end())
return It->second;
if (Trigrams.isDefinitelyOut(Query))
return false;
for (const auto &RegExKV : RegExes)
if (RegExKV.first->match(Query))
return RegExKV.second;
return 0;
}
std::unique_ptr<SpecialCaseList>
SpecialCaseList::create(const std::vector<std::string> &Paths,
llvm::vfs::FileSystem &FS, std::string &Error) {
std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
if (SCL->createInternal(Paths, FS, Error))
return SCL;
return nullptr;
}
std::unique_ptr<SpecialCaseList> SpecialCaseList::create(const MemoryBuffer *MB,
std::string &Error) {
std::unique_ptr<SpecialCaseList> SCL(new SpecialCaseList());
if (SCL->createInternal(MB, Error))
return SCL;
return nullptr;
}
std::unique_ptr<SpecialCaseList>
SpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
llvm::vfs::FileSystem &FS) {
std::string Error;
if (auto SCL = create(Paths, FS, Error))
return SCL;
report_fatal_error(Twine(Error));
}
bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
vfs::FileSystem &VFS, std::string &Error) {
StringMap<size_t> Sections;
for (const auto &Path : Paths) {
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
VFS.getBufferForFile(Path);
if (std::error_code EC = FileOrErr.getError()) {
Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();
return false;
}
std::string ParseError;
if (!parse(FileOrErr.get().get(), Sections, ParseError)) {
Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
return false;
}
}
return true;
}
bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
std::string &Error) {
StringMap<size_t> Sections;
if (!parse(MB, Sections, Error))
return false;
return true;
}
bool SpecialCaseList::parse(const MemoryBuffer *MB,
StringMap<size_t> &SectionsMap,
std::string &Error) {
// Iterate through each line in the exclusion list file.
SmallVector<StringRef, 16> Lines;
MB->getBuffer().split(Lines, '\n');
unsigned LineNo = 1;
StringRef Section = "*";
for (auto I = Lines.begin(), E = Lines.end(); I != E; ++I, ++LineNo) {
*I = I->trim();
// Ignore empty lines and lines starting with "#"
if (I->empty() || I->startswith("#"))
continue;
// Save section names
if (I->startswith("[")) {
if (!I->endswith("]")) {
Error = (Twine("malformed section header on line ") + Twine(LineNo) +
": " + *I).str();
return false;
}
Section = I->slice(1, I->size() - 1);
std::string REError;
Regex CheckRE(Section);
if (!CheckRE.isValid(REError)) {
Error =
(Twine("malformed regex for section ") + Section + ": '" + REError)
.str();
return false;
}
continue;
}
// Get our prefix and unparsed regexp.
std::pair<StringRef, StringRef> SplitLine = I->split(":");
StringRef Prefix = SplitLine.first;
if (SplitLine.second.empty()) {
// Missing ':' in the line.
Error = (Twine("malformed line ") + Twine(LineNo) + ": '" +
SplitLine.first + "'").str();
return false;
}
std::pair<StringRef, StringRef> SplitRegexp = SplitLine.second.split("=");
std::string Regexp = std::string(SplitRegexp.first);
StringRef Category = SplitRegexp.second;
// Create this section if it has not been seen before.
if (SectionsMap.find(Section) == SectionsMap.end()) {
std::unique_ptr<Matcher> M = std::make_unique<Matcher>();
std::string REError;
if (!M->insert(std::string(Section), LineNo, REError)) {
Error = (Twine("malformed section ") + Section + ": '" + REError).str();
return false;
}
SectionsMap[Section] = Sections.size();
Sections.emplace_back(std::move(M));
}
auto &Entry = Sections[SectionsMap[Section]].Entries[Prefix][Category];
std::string REError;
if (!Entry.insert(std::move(Regexp), LineNo, REError)) {
Error = (Twine("malformed regex in line ") + Twine(LineNo) + ": '" +
SplitLine.second + "': " + REError).str();
return false;
}
}
return true;
}
SpecialCaseList::~SpecialCaseList() {}
bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix,
StringRef Query, StringRef Category) const {
return inSectionBlame(Section, Prefix, Query, Category);
}
unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
StringRef Query,
StringRef Category) const {
for (const auto &SectionIter : Sections)
if (SectionIter.SectionMatcher->match(Section)) {
unsigned Blame =
inSectionBlame(SectionIter.Entries, Prefix, Query, Category);
if (Blame)
return Blame;
}
return 0;
}
unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries,
StringRef Prefix, StringRef Query,
StringRef Category) const {
SectionEntries::const_iterator I = Entries.find(Prefix);
if (I == Entries.end()) return 0;
StringMap<Matcher>::const_iterator II = I->second.find(Category);
if (II == I->second.end()) return 0;
return II->getValue().match(Query);
}
} // namespace llvm