diff --git a/clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h b/clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/SourceLocationsLattice.h @@ -0,0 +1,63 @@ +//===-- 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 +#include + +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. +class SourceLocationsLattice { +public: + SourceLocationsLattice() = default; + + explicit SourceLocationsLattice(llvm::DenseSet 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 &getSourceLocations() { return Locs; } + + const llvm::DenseSet &getSourceLocations() const { + return Locs; + } + +private: + llvm::DenseSet 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 diff --git a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt --- a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt +++ b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt @@ -2,6 +2,7 @@ ControlFlowContext.cpp DataflowAnalysisContext.cpp DataflowEnvironment.cpp + SourceLocationsLattice.cpp Transfer.cpp TypeErasedDataflowAnalysis.cpp WatchedLiteralsSolver.cpp @@ -9,4 +10,5 @@ LINK_LIBS clangAnalysis clangAST + clangBasic ) diff --git a/clang/lib/Analysis/FlowSensitive/SourceLocationsLattice.cpp b/clang/lib/Analysis/FlowSensitive/SourceLocationsLattice.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/SourceLocationsLattice.cpp @@ -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 +#include +#include + +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 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 diff --git a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt --- a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt +++ b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt @@ -9,6 +9,7 @@ MapLatticeTest.cpp MultiVarConstantPropagationTest.cpp SingleVarConstantPropagationTest.cpp + SourceLocationsLatticeTest.cpp TestingSupport.cpp TestingSupportTest.cpp TransferTest.cpp diff --git a/clang/unittests/Analysis/FlowSensitive/SourceLocationsLatticeTest.cpp b/clang/unittests/Analysis/FlowSensitive/SourceLocationsLatticeTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/Analysis/FlowSensitive/SourceLocationsLatticeTest.cpp @@ -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