[PATCH] 658097 Fix hovering over pointer dereference expression



Hello,

Consider the following pointer de-referencing expression:
foo->bar;

When I hover over the "foo" part of that expression, I want Nemiver to
show me the content of the foo variable.  That works OK.

But when I hover over the "bar" part of the expression, I want Nemiver
to show me the content of the foo->bar variable.  That doesn't work.
Nemiver tries to show me the content of an "hypothetical" bar
variable.  That can even lead to some buggy behaviour, e.g:

struct S
{
  int bar;
   S() : bar(0) {}
}

void
fun()
{
  int bar = 1;
  S * foo = new S;
  foo->bar = 2; //#0
}

On the line commented #0, if I hover over the "bar" part of the
foo->bar expression, the variable tooltip shows the content of the bar
variable which value is 1, instead of showing the value of the
foo->bar expression which is 2!

The patch below enhances the behaviour of the simplistic expression
parsing code that deals with recognizing things like foo->bar or
foo.bar.

Tested and applied to master and gtk2-branch

commit 7902ae8cddd7b5f1bfc758597f6943cabe86aa66
Author: Dodji Seketeli <dodji seketeli org>
Date:   Sat Sep 3 00:28:00 2011 +0200

    658097 Fix hovering over pointer dereference expression
    
    	* src/uicommon/nmv-source-editor.cc (parse_word_around_iter): New
    	function.  Factorized and enhanced from ...
    	(SourceEditor::get_word_at_position): ... here.
    	* tests/pointer-deref.cc: Enhance this test to add some
    	de-referencing expression for testing purpose.

diff --git a/src/uicommon/nmv-source-editor.cc b/src/uicommon/nmv-source-editor.cc
index 42e9b1b..d93e18a 100644
--- a/src/uicommon/nmv-source-editor.cc
+++ b/src/uicommon/nmv-source-editor.cc
@@ -1106,58 +1106,95 @@ is_word_delimiter (gunichar a_char)
     return false;
 }
 
+/// Parse the name of the variable that surrounds a_iter.  If a_iter
+/// is on the "bar" part of "foo->bar", the name returned is
+/// "foo->bar".  If it's on the "foo" part, the name returned is
+/// "foo".  Similarly for foo.bar.
+///
+/// \param a_iter the iterator from which the parsing starts
+///
+/// \param a_begin the resulting iterator pointing at the character
+/// that starts the variable name that has been parsed.
+///
+/// \param a_end the resulting iterator pointing at the character that
+/// ends the variable name that has been parsed.
+///
+/// \return true if the parsing succeeded, false otherwise.
+bool
+parse_word_around_iter (const Gtk::TextBuffer::iterator &a_iter,
+			Gtk::TextBuffer::iterator &a_begin,
+			Gtk::TextBuffer::iterator &a_end)
+{
+    if (!a_iter)
+	return false;
+
+    gunichar c = 0, prev_char = 0;
+    Gtk::TextBuffer::iterator iter = a_iter;
+
+    // First, go backward to find the first word delimiter before a_iter
+    while (iter.backward_char ()
+	   && (!is_word_delimiter (c = iter.get_char ())
+	       || c == '>' || c == '-' || c == '.')) {
+	if (c == '-') {
+	    if (prev_char == '>') {
+		// this is the '-' of the "->" operator.  Keep going.
+
+	    } else {
+		// This is the minus operator.  It's a word
+		// delimiter.  Stop here.
+		iter.forward_char ();
+		break;
+	    }
+	}
+	prev_char = c;
+    }
+    iter.forward_char ();
+    a_begin = iter;
+
+    // Then, go forward find the first word delimiter after a_iter
+    iter = a_iter;
+    while (iter.forward_char ()
+	   && !is_word_delimiter (iter.get_char ())) {}
+    a_end = iter;
+
+    return true;
+}
+
 bool
 SourceEditor::get_word_at_position (int a_x,
-                                    int a_y,
-                                    UString &a_word,
-                                    Gdk::Rectangle &a_start_rect,
-                                    Gdk::Rectangle &a_end_rect) const
+				    int a_y,
+				    UString &a_word,
+				    Gdk::Rectangle &a_start_rect,
+				    Gdk::Rectangle &a_end_rect) const
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD
 
     THROW_IF_FAIL (m_priv);
     int buffer_x=0, buffer_y=0;
     source_view ().window_to_buffer_coords (Gtk::TEXT_WINDOW_TEXT,
-                                            (int)a_x,
-                                            (int)a_y,
-                                            buffer_x, buffer_y);
+					    (int)a_x,
+					    (int)a_y,
+					    buffer_x, buffer_y);
     Gtk::TextBuffer::iterator clicked_at_iter;
     source_view ().get_iter_at_location (clicked_at_iter, buffer_x, buffer_y);
     if (!clicked_at_iter) {
-        return false;
+	return false;
     }
 
-    //go find the first white word delimiter before clicked_at_iter
-    Gtk::TextBuffer::iterator cur_iter = clicked_at_iter;
-    if (!cur_iter) {return false;}
-
-    while (cur_iter.backward_char ()
-           && !is_word_delimiter (cur_iter.get_char ())) {}
-    THROW_IF_FAIL (cur_iter.forward_char ());
-    Gtk::TextBuffer::iterator start_word_iter = cur_iter;
-
-    //go find the first word delimiter after clicked_at_iter
-    cur_iter = clicked_at_iter;
-    while (cur_iter.forward_char ()
-           && !is_word_delimiter (cur_iter.get_char ())) {}
-    Gtk::TextBuffer::iterator end_word_iter = cur_iter;
+    Gtk::TextBuffer::iterator start_word_iter, end_word_iter;
+    if (!parse_word_around_iter (clicked_at_iter,
+				 start_word_iter,
+				 end_word_iter))
+	return false;
 
     UString var_name = start_word_iter.get_slice (end_word_iter);
-    while (var_name != "" && !isalpha (var_name[0]) && var_name[0] != '_') {
-        var_name.erase (0, 1);
-    }
-    while (var_name != ""
-           && !isalnum (var_name[var_name.size () - 1])
-           && var_name[var_name.size () - 1] != '_') {
-        var_name.erase (var_name.size () - 1, 1);
-    }
 
     Gdk::Rectangle start_rect, end_rect;
     source_view ().get_iter_location (start_word_iter, start_rect);
     source_view ().get_iter_location (end_word_iter, end_rect);
     if (!(start_rect.get_x () <= buffer_x) || !(buffer_x <= end_rect.get_x ())) {
-        LOG_DD ("mouse not really on word: '" << var_name << "'");
-        return false;
+	LOG_DD ("mouse not really on word: '" << var_name << "'");
+	return false;
     }
     LOG_DD ("got variable candidate name: '" << var_name << "'");
     a_word = var_name;
diff --git a/tests/pointer-deref.cc b/tests/pointer-deref.cc
index 876c641..76cfeb1 100644
--- a/tests/pointer-deref.cc
+++ b/tests/pointer-deref.cc
@@ -1,6 +1,6 @@
 #include <iostream>
 
-class baz {
+struct baz {
     int m_a;
     int m_b;
 
@@ -23,7 +23,7 @@ public:
 };//end foo
 
 
-class bar {
+struct bar {
     baz *m_baz;
 
 public:
@@ -65,7 +65,7 @@ public:
     }
 };//end bar
 
-class foo {
+struct foo {
     bar * m_bar;
 public:
 
@@ -145,6 +145,23 @@ main ()
     change_baz (baz_ptr);
     change_baz_ptr (&baz_ptr);
 
+    if (foo_ptr->m_bar) {
+        ;
+    }
+
+    if (foo_ptr->m_bar->m_baz) {
+        ;
+    }
+    
+    if (foo_ptr->m_bar->m_baz->m_a) {
+        ;
+    }
+
+    baz b;
+    if (b.m_b) {
+        ;
+    }
+
     delete foo_ptr;
 
     return 0;


-- 
		Dodji


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]