[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