Skip to content

[lldb][nfc] Factor out code checking if Variable is in scope #143572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

felipepiovezan
Copy link
Contributor

This is useful for checking whether a variable is in scope inside a specific block.

This is useful for checking whether a variable is in scope inside a
specific block.
@llvmbot
Copy link
Member

llvmbot commented Jun 10, 2025

@llvm/pr-subscribers-lldb

Author: Felipe de Azevedo Piovezan (felipepiovezan)

Changes

This is useful for checking whether a variable is in scope inside a specific block.


Full diff: https://github.com/llvm/llvm-project/pull/143572.diff

2 Files Affected:

  • (modified) lldb/include/lldb/Symbol/Variable.h (+3)
  • (modified) lldb/source/Symbol/Variable.cpp (+24-22)
diff --git a/lldb/include/lldb/Symbol/Variable.h b/lldb/include/lldb/Symbol/Variable.h
index c437624d1ea6d..b867369576a41 100644
--- a/lldb/include/lldb/Symbol/Variable.h
+++ b/lldb/include/lldb/Symbol/Variable.h
@@ -89,6 +89,9 @@ class Variable : public UserID, public std::enable_shared_from_this<Variable> {
 
   bool IsInScope(StackFrame *frame);
 
+  /// Returns true if this variable is in scope at `addr` inside `block`.
+  bool IsInScope(Block &block, Address addr);
+
   bool LocationIsValidForFrame(StackFrame *frame);
 
   bool LocationIsValidForAddress(const Address &address);
diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
index 8244725aba545..0415758dd268a 100644
--- a/lldb/source/Symbol/Variable.cpp
+++ b/lldb/source/Symbol/Variable.cpp
@@ -290,28 +290,9 @@ bool Variable::IsInScope(StackFrame *frame) {
       // this variable was defined in is currently
       Block *deepest_frame_block =
           frame->GetSymbolContext(eSymbolContextBlock).block;
-      if (deepest_frame_block) {
-        SymbolContext variable_sc;
-        CalculateSymbolContext(&variable_sc);
-
-        // Check for static or global variable defined at the compile unit
-        // level that wasn't defined in a block
-        if (variable_sc.block == nullptr)
-          return true;
-
-        // Check if the variable is valid in the current block
-        if (variable_sc.block != deepest_frame_block &&
-            !variable_sc.block->Contains(deepest_frame_block))
-          return false;
-
-        // If no scope range is specified then it means that the scope is the
-        // same as the scope of the enclosing lexical block.
-        if (m_scope_range.IsEmpty())
-          return true;
-
-        addr_t file_address = frame->GetFrameCodeAddress().GetFileAddress();
-        return m_scope_range.FindEntryThatContains(file_address) != nullptr;
-      }
+      Address frame_addr = frame->GetFrameCodeAddress();
+      if (deepest_frame_block)
+        return IsInScope(*deepest_frame_block, frame_addr);
     }
     break;
 
@@ -321,6 +302,27 @@ bool Variable::IsInScope(StackFrame *frame) {
   return false;
 }
 
+bool Variable::IsInScope(Block &block, Address addr) {
+  SymbolContext variable_sc;
+  CalculateSymbolContext(&variable_sc);
+
+  // Check for static or global variable defined at the compile unit
+  // level that wasn't defined in a block
+  if (variable_sc.block == nullptr)
+    return true;
+
+  // Check if the variable is valid in the current block
+  if (variable_sc.block != &block && !variable_sc.block->Contains(&block))
+    return false;
+
+  // If no scope range is specified then it means that the scope is the
+  // same as the scope of the enclosing lexical block.
+  if (m_scope_range.IsEmpty())
+    return true;
+
+  return m_scope_range.FindEntryThatContains(addr.GetFileAddress()) != nullptr;
+}
+
 Status Variable::GetValuesForVariableExpressionPath(
     llvm::StringRef variable_expr_path, ExecutionContextScope *scope,
     GetVariableCallback callback, void *baton, VariableList &variable_list,

@@ -321,6 +302,27 @@ bool Variable::IsInScope(StackFrame *frame) {
return false;
}

bool Variable::IsInScope(Block &block, Address addr) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not pass this by const ref?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an oopsie on my part!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Address? :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That one is just a pointer + integer, my understanding is that it is supposed to be passed by value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmmm it is a weak pointer + integer. How cheap is it to copy a weak pointer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like std::shared_ptr, a typical implementation of weak_ptr stores two pointers:
a pointer to the control block; and
the stored pointer of the shared_ptr it was constructed from.

Seems like it is cheap?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A quick grep shows 223 instances of it being passed by const ref and the class itself seems to be taking other Addresses by const-ref too. There are definitely a bunch of instances of it being passed by value, but I would say "it's only slightly more expensive" isn't a strong argument unless there's a benefit to weigh that against such as needing a copy to modify or something. My final argument would be that if we ever do address spaces, the class will grow, which makes the case for the reference more compelling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an interesting, given the current usage it makes sense to switch this to const reference.

Future changes aside, it's still worth pointing out that "by value" by default is usually the correct choice. An API that prescribes passing something by reference is also saying "it's a bad idea to copy this object", a warning to users of the API. Here, there is no such warning, so it is an API that makes a developer pause for nothing -- the warnings are usually "it's expensive", "you can't copy because of ownership semantics".

@felipepiovezan felipepiovezan merged commit 145b1b0 into llvm:main Jun 11, 2025
7 checks passed
@felipepiovezan felipepiovezan deleted the felipe/upstream_var_in_scope_nfc branch June 11, 2025 16:57
felipepiovezan added a commit to felipepiovezan/llvm-project that referenced this pull request Jun 11, 2025
…3572)

This is useful for checking whether a variable is in scope inside a
specific block.
tomtor pushed a commit to tomtor/llvm-project that referenced this pull request Jun 14, 2025
…3572)

This is useful for checking whether a variable is in scope inside a
specific block.
akuhlens pushed a commit to akuhlens/llvm-project that referenced this pull request Jun 24, 2025
…3572)

This is useful for checking whether a variable is in scope inside a
specific block.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants