[clang][dataflow] Add a lattice to track source locations.

This patch adds a simpe lattice used to collect source loctions. An intended application is to track errors found in code during an analysis.

Differential Revision: https://reviews.llvm.org/D120890
This commit is contained in:
Yitzhak Mandelbaum
2022-03-03 03:34:44 +00:00
parent 62f84c73d2
commit 7ee97c24ef
5 changed files with 187 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
//===-- SourceLocationsLattice.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 lattice that collects source locations of interest.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOURCELOCATIONS_LATTICE_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOURCELOCATIONS_LATTICE_H
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseSet.h"
#include <string>
#include <utility>
namespace clang {
namespace dataflow {
/// Lattice for dataflow analysis that keeps track of a set of source locations.
///
/// Bottom is the empty set, join is set union, and equality is set equality.
///
/// FIXME: Generalize into a (templated) PowerSetLattice.
class SourceLocationsLattice {
public:
SourceLocationsLattice() = default;
explicit SourceLocationsLattice(llvm::DenseSet<SourceLocation> Locs)
: Locs(std::move(Locs)) {}
bool operator==(const SourceLocationsLattice &Other) const {
return Locs == Other.Locs;
}
bool operator!=(const SourceLocationsLattice &Other) const {
return !(*this == Other);
}
LatticeJoinEffect join(const SourceLocationsLattice &Other);
llvm::DenseSet<SourceLocation> &getSourceLocations() { return Locs; }
const llvm::DenseSet<SourceLocation> &getSourceLocations() const {
return Locs;
}
private:
llvm::DenseSet<SourceLocation> Locs;
};
/// Returns a string that represents the source locations of the lattice.
std::string DebugString(const SourceLocationsLattice &Lattice,
const ASTContext &Context);
} // namespace dataflow
} // namespace clang
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOURCELOCATIONS_LATTICE_H

View File

@@ -2,6 +2,7 @@ add_clang_library(clangAnalysisFlowSensitive
ControlFlowContext.cpp
DataflowAnalysisContext.cpp
DataflowEnvironment.cpp
SourceLocationsLattice.cpp
Transfer.cpp
TypeErasedDataflowAnalysis.cpp
WatchedLiteralsSolver.cpp
@@ -9,4 +10,5 @@ add_clang_library(clangAnalysisFlowSensitive
LINK_LIBS
clangAnalysis
clangAST
clangBasic
)

View File

@@ -0,0 +1,51 @@
//===- SourceLocationsLattice.cpp -----------------------------------------===//
//
// 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 implements a lattice that collects source locations of interest.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <string>
#include <vector>
namespace clang {
namespace dataflow {
LatticeJoinEffect
SourceLocationsLattice::join(const SourceLocationsLattice &Other) {
auto SizeBefore = Locs.size();
Locs.insert(Other.Locs.begin(), Other.Locs.end());
return SizeBefore == Locs.size() ? LatticeJoinEffect::Unchanged
: LatticeJoinEffect::Changed;
}
std::string DebugString(const SourceLocationsLattice &Lattice,
const ASTContext &Context) {
if (Lattice.getSourceLocations().empty())
return "";
std::vector<std::string> Locations;
Locations.reserve(Lattice.getSourceLocations().size());
for (const clang::SourceLocation &Loc : Lattice.getSourceLocations()) {
Locations.push_back(Loc.printToString(Context.getSourceManager()));
}
std::sort(Locations.begin(), Locations.end());
std::string result;
llvm::raw_string_ostream OS(result);
llvm::interleaveComma(Locations, OS);
return result;
}
} // namespace dataflow
} // namespace clang

View File

@@ -9,6 +9,7 @@ add_clang_unittest(ClangAnalysisFlowSensitiveTests
MapLatticeTest.cpp
MultiVarConstantPropagationTest.cpp
SingleVarConstantPropagationTest.cpp
SourceLocationsLatticeTest.cpp
TestingSupport.cpp
TestingSupportTest.cpp
TransferTest.cpp

View File

@@ -0,0 +1,68 @@
//===- unittests/Analysis/FlowSensitive/SourceLocationsLatticeTest.cpp ----===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Basic/SourceLocation.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace clang {
namespace dataflow {
namespace {
TEST(SourceLocationsLatticeTest, Comparison) {
const SourceLocationsLattice Bottom;
const SourceLocationsLattice NonBottom(
{SourceLocation::getFromRawEncoding(0)});
EXPECT_TRUE(Bottom == Bottom);
EXPECT_FALSE(Bottom == NonBottom);
EXPECT_FALSE(NonBottom == Bottom);
EXPECT_TRUE(NonBottom == NonBottom);
EXPECT_FALSE(Bottom != Bottom);
EXPECT_TRUE(Bottom != NonBottom);
EXPECT_TRUE(NonBottom != Bottom);
EXPECT_FALSE(NonBottom != NonBottom);
}
TEST(SourceLocationsLatticeTest, Join) {
const SourceLocationsLattice Bottom;
const SourceLocationsLattice NonBottom(
{SourceLocation::getFromRawEncoding(0)});
{
SourceLocationsLattice LHS = Bottom;
const SourceLocationsLattice RHS = Bottom;
EXPECT_EQ(LHS.join(RHS), LatticeJoinEffect::Unchanged);
EXPECT_EQ(LHS, Bottom);
}
{
SourceLocationsLattice LHS = NonBottom;
const SourceLocationsLattice RHS = Bottom;
EXPECT_EQ(LHS.join(RHS), LatticeJoinEffect::Unchanged);
EXPECT_EQ(LHS, NonBottom);
}
{
SourceLocationsLattice LHS = Bottom;
const SourceLocationsLattice RHS = NonBottom;
EXPECT_EQ(LHS.join(RHS), LatticeJoinEffect::Changed);
EXPECT_EQ(LHS, NonBottom);
}
{
SourceLocationsLattice LHS = NonBottom;
const SourceLocationsLattice RHS = NonBottom;
EXPECT_EQ(LHS.join(RHS), LatticeJoinEffect::Unchanged);
EXPECT_EQ(LHS, NonBottom);
}
}
} // namespace
} // namespace dataflow
} // namespace clang