clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
144 lines
4.8 KiB
C++
144 lines
4.8 KiB
C++
//===------------------------ MapLattice.h ----------------------*- C++ -*-===//
|
|
//
|
|
// 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 defines a parameterized lattice that maps keys to individual
|
|
// lattice elements (of the parameter lattice type). A typical usage is lifting
|
|
// a particular lattice to all variables in a lexical scope.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__MAPLATTICE_H
|
|
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__MAPLATTICE_H
|
|
|
|
#include <ostream>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "DataflowAnalysis.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
namespace clang {
|
|
namespace dataflow {
|
|
|
|
/// A lattice that maps keys to individual lattice elements. When instantiated
|
|
/// with an `ElementLattice` that is a bounded semi-lattice, `MapLattice` is
|
|
/// itself a bounded semi-lattice, so long as the user limits themselves to a
|
|
/// finite number of keys. In that case, `top` is (implicitly), the map
|
|
/// containing all valid keys mapped to `top` of `ElementLattice`.
|
|
///
|
|
/// Requirements on `ElementLattice`:
|
|
/// * Provides standard declarations of a bounded semi-lattice.
|
|
template <typename Key, typename ElementLattice> class MapLattice {
|
|
using Container = llvm::DenseMap<Key, ElementLattice>;
|
|
Container C;
|
|
|
|
public:
|
|
using key_type = Key;
|
|
using mapped_type = ElementLattice;
|
|
using value_type = typename Container::value_type;
|
|
using iterator = typename Container::iterator;
|
|
using const_iterator = typename Container::const_iterator;
|
|
|
|
MapLattice() = default;
|
|
|
|
explicit MapLattice(Container C) : C{std::move(C)} {};
|
|
|
|
// The `bottom` element is the empty map.
|
|
static MapLattice bottom() { return MapLattice(); }
|
|
|
|
std::pair<iterator, bool>
|
|
insert(const std::pair<const key_type, mapped_type> &P) {
|
|
return C.insert(P);
|
|
}
|
|
|
|
std::pair<iterator, bool> insert(std::pair<const key_type, mapped_type> &&P) {
|
|
return C.insert(std::move(P));
|
|
}
|
|
|
|
unsigned size() const { return C.size(); }
|
|
bool empty() const { return C.empty(); }
|
|
|
|
iterator begin() { return C.begin(); }
|
|
iterator end() { return C.end(); }
|
|
const_iterator begin() const { return C.begin(); }
|
|
const_iterator end() const { return C.end(); }
|
|
|
|
// Equality is direct equality of underlying map entries. One implication of
|
|
// this definition is that a map with (only) keys that map to bottom is not
|
|
// equal to the empty map.
|
|
friend bool operator==(const MapLattice &LHS, const MapLattice &RHS) {
|
|
return LHS.C == RHS.C;
|
|
}
|
|
|
|
friend bool operator!=(const MapLattice &LHS, const MapLattice &RHS) {
|
|
return !(LHS == RHS);
|
|
}
|
|
|
|
bool contains(const key_type &K) const { return C.find(K) != C.end(); }
|
|
|
|
iterator find(const key_type &K) { return C.find(K); }
|
|
const_iterator find(const key_type &K) const { return C.find(K); }
|
|
|
|
mapped_type &operator[](const key_type &K) { return C[K]; }
|
|
|
|
/// If an entry exists in one map but not the other, the missing entry is
|
|
/// treated as implicitly mapping to `bottom`. So, the joined map contains the
|
|
/// entry as it was in the source map.
|
|
LatticeJoinEffect join(const MapLattice &Other) {
|
|
LatticeJoinEffect Effect = LatticeJoinEffect::Unchanged;
|
|
for (const auto &O : Other.C) {
|
|
auto It = C.find(O.first);
|
|
if (It == C.end()) {
|
|
C.insert(O);
|
|
Effect = LatticeJoinEffect::Changed;
|
|
} else if (It->second.join(O.second) == LatticeJoinEffect::Changed)
|
|
Effect = LatticeJoinEffect::Changed;
|
|
}
|
|
return Effect;
|
|
}
|
|
};
|
|
|
|
/// Convenience alias that captures the common use of map lattices to model
|
|
/// in-scope variables.
|
|
template <typename ElementLattice>
|
|
using VarMapLattice = MapLattice<const clang::VarDecl *, ElementLattice>;
|
|
|
|
template <typename Key, typename ElementLattice>
|
|
std::ostream &
|
|
operator<<(std::ostream &Os,
|
|
const clang::dataflow::MapLattice<Key, ElementLattice> &M) {
|
|
std::string Separator;
|
|
Os << "{";
|
|
for (const auto &E : M) {
|
|
Os << std::exchange(Separator, ", ") << E.first << " => " << E.second;
|
|
}
|
|
Os << "}";
|
|
return Os;
|
|
}
|
|
|
|
template <typename ElementLattice>
|
|
std::ostream &
|
|
operator<<(std::ostream &Os,
|
|
const clang::dataflow::VarMapLattice<ElementLattice> &M) {
|
|
std::string Separator;
|
|
Os << "{";
|
|
for (const auto &E : M) {
|
|
Os << std::exchange(Separator, ", ") << E.first->getName().str() << " => "
|
|
<< E.second;
|
|
}
|
|
Os << "}";
|
|
return Os;
|
|
}
|
|
} // namespace dataflow
|
|
} // namespace clang
|
|
|
|
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__MAPLATTICE_H
|