[Lldb-commits] [lldb] adfffeb - [lldb/Core] Add SourceLocationSpec class (NFC)
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Tue May 4 09:35:01 PDT 2021
Author: Med Ismail Bennani
Date: 2021-05-04T16:34:45Z
New Revision: adfffebec6d6910304e4b1ccdbef78e226a8fd32
URL: https://github.com/llvm/llvm-project/commit/adfffebec6d6910304e4b1ccdbef78e226a8fd32
DIFF: https://github.com/llvm/llvm-project/commit/adfffebec6d6910304e4b1ccdbef78e226a8fd32.diff
LOG: [lldb/Core] Add SourceLocationSpec class (NFC)
A source location specifier class that holds a Declaration object containing
a FileSpec with line and column information. The column line is optional.
It also holds search flags that can be fetched by resolvers to look inlined
declarations and/or exact matches.
It describes a specific location in a source file and allows the user
to perform checks and comparaisons between multiple instances of that class.
Differential Revision: https://reviews.llvm.org/D100962
Signed-off-by: Med Ismail Bennani <medismail.bennani at gmail.com>
Added:
lldb/include/lldb/Core/SourceLocationSpec.h
lldb/source/Core/SourceLocationSpec.cpp
lldb/unittests/Core/SourceLocationSpecTest.cpp
Modified:
lldb/source/Core/CMakeLists.txt
lldb/unittests/Core/CMakeLists.txt
Removed:
################################################################################
diff --git a/lldb/include/lldb/Core/SourceLocationSpec.h b/lldb/include/lldb/Core/SourceLocationSpec.h
new file mode 100644
index 0000000000000..808931186dba5
--- /dev/null
+++ b/lldb/include/lldb/Core/SourceLocationSpec.h
@@ -0,0 +1,188 @@
+//===-- SourceLocationSpec.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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_SOURCELOCATIONSPEC_H
+#define LLDB_UTILITY_SOURCELOCATIONSPEC_H
+
+#include "lldb/Core/Declaration.h"
+#include "lldb/lldb-defines.h"
+#include "llvm/ADT/Optional.h"
+
+#include <string>
+
+namespace lldb_private {
+
+/// \class SourceLocationSpec SourceLocationSpec.h
+/// "lldb/Core/SourceLocationSpec.h" A source location specifier class.
+///
+/// A source location specifier class that holds a Declaration object containing
+/// a FileSpec with line and column information. The column line is optional.
+/// It also holds search flags that can be fetched by resolvers to look inlined
+/// declarations and/or exact matches.
+class SourceLocationSpec {
+public:
+ /// Constructor.
+ ///
+ /// Takes a \a file_spec with a \a line number and a \a column number. If
+ /// \a column is null or not provided, it is set to llvm::None.
+ ///
+ /// \param[in] file_spec
+ /// The full or partial path to a file.
+ ///
+ /// \param[in] line
+ /// The line number in the source file.
+ ///
+ /// \param[in] column
+ /// The column number in the line of the source file.
+ ///
+ /// \param[in] check_inlines
+ /// Whether to look for a match in inlined declaration.
+ ///
+ /// \param[in] exact_match
+ /// Whether to look for an exact match.
+ ///
+ explicit SourceLocationSpec(FileSpec file_spec, uint32_t line,
+ llvm::Optional<uint16_t> column = llvm::None,
+ bool check_inlines = false,
+ bool exact_match = false);
+
+ SourceLocationSpec() = delete;
+
+ /// Convert to boolean operator.
+ ///
+ /// This allows code to check a SourceLocationSpec object to see if it
+ /// contains anything valid using code such as:
+ ///
+ /// \code
+ /// SourceLocationSpec location_spec(...);
+ /// if (location_spec)
+ /// { ...
+ /// \endcode
+ ///
+ /// \return
+ /// A pointer to this object if both the file_spec and the line are valid,
+ /// nullptr otherwise.
+ explicit operator bool() const;
+
+ /// Logical NOT operator.
+ ///
+ /// This allows code to check a SourceLocationSpec object to see if it is
+ /// invalid using code such as:
+ ///
+ /// \code
+ /// SourceLocationSpec location_spec(...);
+ /// if (!location_spec)
+ /// { ...
+ /// \endcode
+ ///
+ /// \return
+ /// Returns \b true if the object has an invalid file_spec or line number,
+ /// \b false otherwise.
+ bool operator!() const;
+
+ /// Equal to operator
+ ///
+ /// Tests if this object is equal to \a rhs.
+ ///
+ /// \param[in] rhs
+ /// A const SourceLocationSpec object reference to compare this object
+ /// to.
+ ///
+ /// \return
+ /// \b true if this object is equal to \a rhs, \b false
+ /// otherwise.
+ bool operator==(const SourceLocationSpec &rhs) const;
+
+ /// Not equal to operator
+ ///
+ /// Tests if this object is not equal to \a rhs.
+ ///
+ /// \param[in] rhs
+ /// A const SourceLocationSpec object reference to compare this object
+ /// to.
+ ///
+ /// \return
+ /// \b true if this object is equal to \a rhs, \b false
+ /// otherwise.
+ bool operator!=(const SourceLocationSpec &rhs) const;
+
+ /// Less than to operator
+ ///
+ /// Tests if this object is less than \a rhs.
+ ///
+ /// \param[in] rhs
+ /// A const SourceLocationSpec object reference to compare this object
+ /// to.
+ ///
+ /// \return
+ /// \b true if this object is less than \a rhs, \b false
+ /// otherwise.
+ bool operator<(const SourceLocationSpec &rhs) const;
+
+ /// Compare two SourceLocationSpec objects.
+ ///
+ /// If \a full is true, then the file_spec, the line and column must match.
+ /// If \a full is false, then only the file_spec and line number for \a lhs
+ /// and \a rhs are compared. This allows a SourceLocationSpec object that have
+ /// no column information to match a SourceLocationSpec objects that have
+ /// column information with matching file_spec and line component.
+ ///
+ /// \param[in] lhs
+ /// A const reference to the Left Hand Side object to compare.
+ ///
+ /// \param[in] rhs
+ /// A const reference to the Right Hand Side object to compare.
+ ///
+ /// \param[in] full
+ /// If true, then the file_spec, the line and column must match for a
+ /// compare to return zero (equal to). If false, then only the file_spec
+ /// and line number for \a lhs and \a rhs are compared, else a full
+ /// comparison is done.
+ ///
+ /// \return -1 if \a lhs is less than \a rhs, 0 if \a lhs is equal to \a rhs,
+ /// 1 if \a lhs is greater than \a rhs
+ static int Compare(const SourceLocationSpec &lhs,
+ const SourceLocationSpec &rhs);
+
+ static bool Equal(const SourceLocationSpec &lhs,
+ const SourceLocationSpec &rhs, bool full);
+
+ /// Dump this object to a Stream.
+ ///
+ /// Dump the object to the supplied stream \a s, starting with the file name,
+ /// then the line number and if available the column number.
+ ///
+ /// \param[in] s
+ /// The stream to which to dump the object description.
+ void Dump(Stream &s) const;
+
+ std::string GetString() const;
+
+ FileSpec GetFileSpec() const { return m_declaration.GetFile(); }
+
+ llvm::Optional<uint32_t> GetLine() const;
+
+ llvm::Optional<uint16_t> GetColumn() const;
+
+ bool GetCheckInlines() const { return m_check_inlines; }
+
+ bool GetExactMatch() const { return m_exact_match; }
+
+protected:
+ Declaration m_declaration;
+ /// Tells if the resolver should look in inlined declaration.
+ bool m_check_inlines;
+ /// Tells if the resolver should look for an exact match.
+ bool m_exact_match;
+};
+
+/// Dump a SourceLocationSpec object to a stream
+Stream &operator<<(Stream &s, const SourceLocationSpec &loc);
+} // namespace lldb_private
+
+#endif // LLDB_UTILITY_SOURCELOCATIONSPEC_H
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index 338fd4aaa921f..65be803addf5f 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -48,6 +48,7 @@ add_lldb_library(lldbCore
RichManglingContext.cpp
SearchFilter.cpp
Section.cpp
+ SourceLocationSpec.cpp
SourceManager.cpp
StreamAsynchronousIO.cpp
StreamFile.cpp
diff --git a/lldb/source/Core/SourceLocationSpec.cpp b/lldb/source/Core/SourceLocationSpec.cpp
new file mode 100644
index 0000000000000..610754bb187c8
--- /dev/null
+++ b/lldb/source/Core/SourceLocationSpec.cpp
@@ -0,0 +1,81 @@
+//===-- SourceLocationSpec.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 "lldb/Core/SourceLocationSpec.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SourceLocationSpec::SourceLocationSpec(FileSpec file_spec, uint32_t line,
+ llvm::Optional<uint16_t> column,
+ bool check_inlines, bool exact_match)
+ : m_declaration(file_spec, line,
+ column.getValueOr(LLDB_INVALID_COLUMN_NUMBER)),
+ m_check_inlines(check_inlines), m_exact_match(exact_match) {}
+
+SourceLocationSpec::operator bool() const { return m_declaration.IsValid(); }
+
+bool SourceLocationSpec::operator!() const { return !operator bool(); }
+
+bool SourceLocationSpec::operator==(const SourceLocationSpec &rhs) const {
+ return m_declaration == rhs.m_declaration &&
+ m_check_inlines == rhs.GetCheckInlines() &&
+ m_exact_match == rhs.GetExactMatch();
+}
+
+bool SourceLocationSpec::operator!=(const SourceLocationSpec &rhs) const {
+ return !(*this == rhs);
+}
+
+bool SourceLocationSpec::operator<(const SourceLocationSpec &rhs) const {
+ return SourceLocationSpec::Compare(*this, rhs) < 0;
+}
+
+Stream &lldb_private::operator<<(Stream &s, const SourceLocationSpec &loc) {
+ loc.Dump(s);
+ return s;
+}
+
+int SourceLocationSpec::Compare(const SourceLocationSpec &lhs,
+ const SourceLocationSpec &rhs) {
+ return Declaration::Compare(lhs.m_declaration, rhs.m_declaration);
+}
+
+bool SourceLocationSpec::Equal(const SourceLocationSpec &lhs,
+ const SourceLocationSpec &rhs, bool full) {
+ return full ? lhs == rhs
+ : (lhs.GetFileSpec() == rhs.GetFileSpec() &&
+ lhs.GetLine() == rhs.GetLine());
+}
+
+void SourceLocationSpec::Dump(Stream &s) const {
+ s << "check inlines = " << llvm::toStringRef(m_check_inlines);
+ s << ", exact match = " << llvm::toStringRef(m_exact_match);
+ m_declaration.Dump(&s, true);
+}
+
+std::string SourceLocationSpec::GetString() const {
+ StreamString ss;
+ Dump(ss);
+ return ss.GetString().str();
+}
+
+llvm::Optional<uint32_t> SourceLocationSpec::GetLine() const {
+ uint32_t line = m_declaration.GetLine();
+ if (line == 0 || line == LLDB_INVALID_LINE_NUMBER)
+ return llvm::None;
+ return line;
+}
+
+llvm::Optional<uint16_t> SourceLocationSpec::GetColumn() const {
+ uint16_t column = m_declaration.GetColumn();
+ if (column == LLDB_INVALID_COLUMN_NUMBER)
+ return llvm::None;
+ return column;
+}
diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt
index 56ae282ae6590..dfe017b3c9c6e 100644
--- a/lldb/unittests/Core/CMakeLists.txt
+++ b/lldb/unittests/Core/CMakeLists.txt
@@ -5,6 +5,7 @@ add_lldb_unittest(LLDBCoreTests
MangledTest.cpp
ModuleSpecTest.cpp
RichManglingContextTest.cpp
+ SourceLocationSpecTest.cpp
SourceManagerTest.cpp
StreamCallbackTest.cpp
UniqueCStringMapTest.cpp
diff --git a/lldb/unittests/Core/SourceLocationSpecTest.cpp b/lldb/unittests/Core/SourceLocationSpecTest.cpp
new file mode 100644
index 0000000000000..b79662f865f6b
--- /dev/null
+++ b/lldb/unittests/Core/SourceLocationSpecTest.cpp
@@ -0,0 +1,183 @@
+//===-- SourceLocationSpecTest.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 "gtest/gtest.h"
+
+#include "lldb/Core/SourceLocationSpec.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+#include "llvm/Testing/Support/Error.h"
+
+using namespace lldb_private;
+
+TEST(SourceLocationSpecTest, OperatorBool) {
+ SourceLocationSpec invalid(FileSpec(), 0);
+ EXPECT_FALSE(invalid);
+
+ SourceLocationSpec invalid_filespec(FileSpec(), 4);
+ EXPECT_FALSE(invalid_filespec);
+
+ SourceLocationSpec invalid_line(FileSpec("/foo/bar"), 0);
+ EXPECT_FALSE(invalid_line);
+
+ SourceLocationSpec valid_fs_line_no_column(FileSpec("/foo/bar"), 4);
+ EXPECT_TRUE(valid_fs_line_no_column);
+
+ SourceLocationSpec invalid_fs_column(FileSpec(), 4, 0);
+ EXPECT_FALSE(invalid_fs_column);
+
+ SourceLocationSpec invalid_line_column(FileSpec("/foo/bar"), 0, 19);
+ EXPECT_FALSE(invalid_line_column);
+
+ SourceLocationSpec valid_fs_line_zero_column(FileSpec("/foo/bar"), 4, 0);
+ EXPECT_TRUE(valid_fs_line_zero_column);
+
+ SourceLocationSpec valid_fs_line_column(FileSpec("/foo/bar"), 4, 19);
+ EXPECT_TRUE(valid_fs_line_column);
+}
+
+TEST(SourceLocationSpecTest, FileLineColumnComponents) {
+ FileSpec fs("/foo/bar", FileSpec::Style::posix);
+ const uint32_t line = 19;
+ const uint16_t column = 4;
+
+ SourceLocationSpec without_column(fs, line, LLDB_INVALID_COLUMN_NUMBER, false,
+ true);
+ EXPECT_TRUE(without_column);
+ EXPECT_EQ(fs, without_column.GetFileSpec());
+ EXPECT_EQ(line, without_column.GetLine().getValueOr(0));
+ EXPECT_EQ(llvm::None, without_column.GetColumn());
+ EXPECT_FALSE(without_column.GetCheckInlines());
+ EXPECT_TRUE(without_column.GetExactMatch());
+ EXPECT_STREQ("check inlines = false, exact match = true, decl = /foo/bar:19",
+ without_column.GetString().c_str());
+
+ SourceLocationSpec with_column(fs, line, column, true, false);
+ EXPECT_TRUE(with_column);
+ EXPECT_EQ(column, *with_column.GetColumn());
+ EXPECT_TRUE(with_column.GetCheckInlines());
+ EXPECT_FALSE(with_column.GetExactMatch());
+ EXPECT_STREQ(
+ "check inlines = true, exact match = false, decl = /foo/bar:19:4",
+ with_column.GetString().c_str());
+}
+
+static SourceLocationSpec Create(bool check_inlines, bool exact_match,
+ FileSpec fs, uint32_t line,
+ uint16_t column = LLDB_INVALID_COLUMN_NUMBER) {
+ return SourceLocationSpec(fs, line, column, check_inlines, exact_match);
+}
+
+TEST(SourceLocationSpecTest, Equal) {
+ auto Equal = [](SourceLocationSpec lhs, SourceLocationSpec rhs, bool full) {
+ return SourceLocationSpec::Equal(lhs, rhs, full);
+ };
+
+ const FileSpec fs("/foo/bar", FileSpec::Style::posix);
+ const FileSpec other_fs("/foo/baz", FileSpec::Style::posix);
+
+ // mutating FileSpec + const Inlined, ExactMatch, Line
+ EXPECT_TRUE(
+ Equal(Create(false, false, fs, 4), Create(false, false, fs, 4), true));
+ EXPECT_TRUE(
+ Equal(Create(true, true, fs, 4), Create(true, true, fs, 4), false));
+ EXPECT_FALSE(Equal(Create(false, false, fs, 4),
+ Create(false, false, other_fs, 4), true));
+ EXPECT_FALSE(
+ Equal(Create(true, true, fs, 4), Create(true, true, other_fs, 4), false));
+
+ // Mutating FileSpec + const Inlined, ExactMatch, Line, Column
+ EXPECT_TRUE(Equal(Create(false, false, fs, 4, 19),
+ Create(false, false, fs, 4, 19), true));
+ EXPECT_TRUE(Equal(Create(true, true, fs, 4, 19),
+ Create(true, true, fs, 4, 19), false));
+ EXPECT_FALSE(Equal(Create(false, false, fs, 4, 19),
+ Create(false, false, other_fs, 4, 19), true));
+ EXPECT_FALSE(Equal(Create(true, true, fs, 4, 19),
+ Create(true, true, other_fs, 4, 19), false));
+
+ // Asymetric match
+ EXPECT_FALSE(
+ Equal(Create(true, true, fs, 4), Create(true, true, fs, 4, 19), true));
+ EXPECT_TRUE(Equal(Create(false, false, fs, 4),
+ Create(false, false, fs, 4, 19), false));
+
+ // Mutating Inlined, ExactMatch
+ EXPECT_FALSE(
+ Equal(Create(true, false, fs, 4), Create(false, true, fs, 4), true));
+ EXPECT_TRUE(
+ Equal(Create(false, true, fs, 4), Create(true, false, fs, 4), false));
+
+ // Mutating Column
+ EXPECT_FALSE(Equal(Create(true, true, fs, 4, 96),
+ Create(true, true, fs, 4, 19), true));
+ EXPECT_TRUE(Equal(Create(false, false, fs, 4, 96),
+ Create(false, false, fs, 4, 19), false));
+}
+
+TEST(SourceLocationSpecTest, Compare) {
+ auto Cmp = [](SourceLocationSpec a, SourceLocationSpec b) {
+ return SourceLocationSpec::Compare(a, b);
+ };
+
+ FileSpec fs("/foo/bar", FileSpec::Style::posix);
+ FileSpec other_fs("/foo/baz", FileSpec::Style::posix);
+
+ // Asymetric comparaison
+ EXPECT_EQ(-1, Cmp(Create(true, true, fs, 4), Create(true, true, fs, 4, 19)));
+ EXPECT_EQ(-1,
+ Cmp(Create(false, false, fs, 4), Create(false, false, fs, 4, 19)));
+ EXPECT_EQ(1, Cmp(Create(true, true, fs, 4, 19), Create(true, true, fs, 4)));
+
+ // Mutating FS, const Line
+ EXPECT_EQ(
+ -1, Cmp(Create(false, false, fs, 4), Create(false, false, other_fs, 4)));
+ EXPECT_EQ(-1,
+ Cmp(Create(true, true, fs, 4), Create(true, true, other_fs, 4)));
+ EXPECT_EQ(1,
+ Cmp(Create(false, true, other_fs, 4), Create(false, true, fs, 4)));
+ EXPECT_EQ(1,
+ Cmp(Create(true, false, other_fs, 4), Create(true, false, fs, 4)));
+
+ // Const FS, mutating Line
+ EXPECT_EQ(-1, Cmp(Create(false, false, fs, 1), Create(false, false, fs, 4)));
+ EXPECT_EQ(-1, Cmp(Create(true, true, fs, 1), Create(true, true, fs, 4)));
+ EXPECT_EQ(0, Cmp(Create(false, true, fs, 4), Create(false, true, fs, 4)));
+ EXPECT_EQ(0, Cmp(Create(true, false, fs, 4), Create(true, false, fs, 4)));
+ EXPECT_EQ(1, Cmp(Create(false, false, fs, 4), Create(false, false, fs, 1)));
+ EXPECT_EQ(1, Cmp(Create(true, true, fs, 4), Create(true, true, fs, 1)));
+
+ // Const FS, mutating Line, const Column
+ EXPECT_EQ(-1,
+ Cmp(Create(false, true, fs, 1), Create(false, true, fs, 4, 19)));
+ EXPECT_EQ(-1, Cmp(Create(true, true, fs, 1), Create(true, true, fs, 4, 19)));
+ EXPECT_EQ(1, Cmp(Create(true, false, fs, 4, 19), Create(true, false, fs, 1)));
+ EXPECT_EQ(1, Cmp(Create(true, false, fs, 4, 19), Create(true, false, fs, 1)));
+
+ // Mutating FS, const Line, const Column
+ EXPECT_EQ(-1, Cmp(Create(false, false, fs, 4, 19),
+ Create(false, false, other_fs, 4, 19)));
+ EXPECT_EQ(-1, Cmp(Create(true, true, fs, 4, 19),
+ Create(true, true, other_fs, 4, 19)));
+ EXPECT_EQ(
+ 0, Cmp(Create(false, false, fs, 4, 19), Create(false, false, fs, 4, 19)));
+ EXPECT_EQ(0,
+ Cmp(Create(true, true, fs, 4, 19), Create(true, true, fs, 4, 19)));
+ EXPECT_EQ(1, Cmp(Create(false, true, other_fs, 4, 19),
+ Create(false, true, fs, 4, 19)));
+ EXPECT_EQ(1, Cmp(Create(true, false, other_fs, 4, 19),
+ Create(true, false, fs, 4, 19)));
+
+ // Const FS, const Line, mutating Column
+ EXPECT_EQ(-1, Cmp(Create(false, false, fs, 4, 19),
+ Create(false, false, fs, 4, 96)));
+ EXPECT_EQ(1,
+ Cmp(Create(true, true, fs, 4, 96), Create(true, true, fs, 4, 19)));
+ EXPECT_EQ(
+ 1, Cmp(Create(false, true, fs, 4, 96), Create(false, true, fs, 4, 19)));
+}
More information about the lldb-commits
mailing list