Thread: [CEDET-devel] Problem with 'using' and nested namespaces
Brought to you by:
zappo
From: David E. <de...@ra...> - 2009-07-10 16:37:10
|
Consider the following c++ code: --8<---------------cut here---------------start------------->8--- #include <iostream> namespace outer { namespace inner { struct foo { int bar; }; } } namespace outer { using outer::inner::foo; } int main(void) { outer::inner::foo a; outer::foo b; a.bar=5; b.bar=6; std::cout << a.bar << std::endl << b.bar << std::endl; return 0; } --8<---------------cut here---------------end--------------->8--- Semantic is not able to provide completions for 'b'. Currently, I have this problem with the vmime library, which is using nested namespaces with additional 'using' statements like above for some types. -David |
From: David E. <de...@ra...> - 2009-07-12 11:34:02
|
David Engster <de...@ra...> writes: > Semantic is not able to provide completions for 'b'. Currently, I have > this problem with the vmime library, which is using nested namespaces > with additional 'using' statements like above for some types. There seems to be a more general problem with 'using' statements not done in the global scope. For example: namespace test { struct foo { int bar; }; } int main(void) { using namespace test; foo var; var. // Completion fails } If the 'using namespace test' is put in the global scope (i.e. before the 'main' function), completions works. Is this a problem with the grammar, or is there maybe something missing in the code? -David |
From: Eric M. L. <er...@si...> - 2009-07-12 12:41:03
|
On Sun, 2009-07-12 at 13:33 +0200, David Engster wrote: > David Engster <de...@ra...> writes: > > Semantic is not able to provide completions for 'b'. Currently, I have > > this problem with the vmime library, which is using nested namespaces > > with additional 'using' statements like above for some types. > > There seems to be a more general problem with 'using' statements not > done in the global scope. For example: > > namespace test { > struct foo { > int bar; > }; > } > > int main(void) { > using namespace test; > foo var; > var. // Completion fails > } > > If the 'using namespace test' is put in the global scope (i.e. before > the 'main' function), completions works. > > Is this a problem with the grammar, or is there maybe something missing > in the code? Hi, I think the parser is working fine. The piece of code that calculates completions, however, runs backward from what a typical parser/compiler does. In a compiler, it starts at the beginning, maintains a current "state", then it knows what's going on. For the Semamtic, it just builds up a big set of tables, mostly during idle time, and maintains them as current as possible. When an analysis is requested, it parses the context around the cursor, then starts working backwards though the tables of data. The pieces that deals with 'using' statements is an overload function of semantic-ctxt-scoped-types written for C++ in semantic-c.el. I'll take a guess that this function is missing for you case. I usually debug stuff like this by just calling the function directly, ie: M-: (semantic-ctxt-scoped-types) RET to see what it says. In your original example, which has "inner" squeezed out when you refer to it as outer::foo, instead of outer::inner::foo, this is because I did not know this was valid syntax, so it needs to be added. Somewhere. I don't know if it is in semantic-ctxt-scoped-types, or not. Does the scoped types fcn need to derive all possible squeezed out names? Eric |
From: David E. <de...@ra...> - 2009-07-12 16:51:01
|
Eric M. Ludlam <er...@si...> writes: > On Sun, 2009-07-12 at 13:33 +0200, David Engster wrote: >> If the 'using namespace test' is put in the global scope (i.e. before >> the 'main' function), completions works. >> >> Is this a problem with the grammar, or is there maybe something missing >> in the code? > I think the parser is working fine. I have the feeling it doesn't parse 'using' statements in inner scopes correctly. Try evaluating the following in a c++ buffer: (semantic-bovinate-stream '((USING 45 . 50) (symbol 51 . 54) (punctuation 54 . 55)) 'bovine-inner-scope) It returns '(((symbol 51 . 54) (punctuation 54 . 55)) nil)'. If you use 'bovine-toplevel instead of 'bovine-inner-scope, it correctly returns (nil ("std" using (:type ("std" type (:type "class") nil nil)) nil nil 45 55)) [...] > The pieces that deals with 'using' statements is an overload function > of semantic-ctxt-scoped-types written for C++ in semantic-c.el. I'll > take a guess that this function is missing for you case. I usually > debug stuff like this by just calling the function directly, ie: > > M-: (semantic-ctxt-scoped-types) RET > > to see what it says. I've stepped through that function, and it just doesn't seem to get any 'using' types in the inner scope. But I must admit I have a hard time understanding that function. For example, what does this construction do? ;; In C++, we want to find all the namespaces declared ;; locally and add them to the list. (setq tmp (semantic-find-tags-by-class 'type (current-buffer))) (setq tmp (semantic-find-tags-by-type "namespace" tmp)) (setq tmp (semantic-find-tags-by-name "unnamed" tmp)) (setq tagreturn tmp) > In your original example, which has "inner" squeezed out when you > refer to it as outer::foo, instead of outer::inner::foo, this is > because I did not know this was valid syntax, so it needs to be added. > Somewhere. I don't know if it is in semantic-ctxt-scoped-types, or > not. Does the scoped types fcn need to derive all possible squeezed > out names? I don't know. At the moment I'm only struggling with the 'using' statements in the local scope. As soon as those get parsed correctly, I'd try to deal with the more complicated case of nested namespaces. -David |
From: Eric M. L. <er...@si...> - 2009-07-12 18:51:32
|
On Sun, 2009-07-12 at 18:50 +0200, David Engster wrote: > Eric M. Ludlam <er...@si...> writes: > > On Sun, 2009-07-12 at 13:33 +0200, David Engster wrote: > >> If the 'using namespace test' is put in the global scope (i.e. before > >> the 'main' function), completions works. > >> > >> Is this a problem with the grammar, or is there maybe something missing > >> in the code? > > > I think the parser is working fine. > > I have the feeling it doesn't parse 'using' statements in inner scopes > correctly. Try evaluating the following in a c++ buffer: > > (semantic-bovinate-stream > '((USING 45 . 50) > (symbol 51 . 54) > (punctuation 54 . 55)) > 'bovine-inner-scope) > > It returns '(((symbol 51 . 54) (punctuation 54 . 55)) nil)'. If you use > 'bovine-toplevel instead of 'bovine-inner-scope, it correctly returns > > (nil > ("std" using > (:type > ("std" type > (:type "class") > nil nil)) > nil nil 45 55)) > > [...] Hi, When I parsed your example from a couple emails ago, the construct: namespace outer { using outer::inner::foo; } Resulted in: ("outer" type (:members (("outer::inner::foo" using (:type ("outer::inner::foo" type (:type "class") nil nil)) (reparse-symbol namespacesubparts) #<overlay from 158 to 182 in deng.cpp>)) :type "namespace") which is the "outer" namespace with a using statement of outer::inner::foo. If there is a particular using statement that is not being parsed, I'd like to know what that syntax is. > > The pieces that deals with 'using' statements is an overload function > > of semantic-ctxt-scoped-types written for C++ in semantic-c.el. I'll > > take a guess that this function is missing for you case. I usually > > debug stuff like this by just calling the function directly, ie: > > > > M-: (semantic-ctxt-scoped-types) RET > > > > to see what it says. > > I've stepped through that function, and it just doesn't seem to get any > 'using' types in the inner scope. But I must admit I have a hard time > understanding that function. For example, what does this construction do? > > ;; In C++, we want to find all the namespaces declared > ;; locally and add them to the list. > (setq tmp (semantic-find-tags-by-class 'type (current-buffer))) > (setq tmp (semantic-find-tags-by-type "namespace" tmp)) > (setq tmp (semantic-find-tags-by-name "unnamed" tmp)) > (setq tagreturn tmp) When looking for stuff w/ Semantic against multiple constraints, you have to do it in multiple lines. The above construct searches first for all types in the current buffer. Then it filters against the output of the first search for all namespaces. Of those namespaces, it pulls out all the unnamed namespaces. Thus, if your original c++ construct was: namespace { using outer::inner::foo; } it would be found by this. Thanks Eric |
From: David E. <de...@ra...> - 2009-07-12 19:17:32
|
Eric M. Ludlam <er...@si...> writes: > On Sun, 2009-07-12 at 18:50 +0200, David Engster wrote: >> I have the feeling it doesn't parse 'using' statements in inner scopes >> correctly. Try evaluating the following in a c++ buffer: >> >> (semantic-bovinate-stream >> '((USING 45 . 50) >> (symbol 51 . 54) >> (punctuation 54 . 55)) >> 'bovine-inner-scope) >> >> It returns '(((symbol 51 . 54) (punctuation 54 . 55)) nil)'. If you use >> 'bovine-toplevel instead of 'bovine-inner-scope, it correctly returns [...] > When I parsed your example from a couple emails ago, the construct: > > namespace outer { > using outer::inner::foo; > } > > Resulted in: > > ("outer" type > (:members > (("outer::inner::foo" using > (:type > ("outer::inner::foo" type > (:type "class") > nil nil)) > (reparse-symbol namespacesubparts) > #<overlay from 158 to 182 in deng.cpp>)) > :type "namespace") > > which is the "outer" namespace with a using statement of > outer::inner::foo. > If there is a particular using statement that is not being parsed, I'd > like to know what that syntax is. Simply consider int main(void) { using namespace std; cout << "test"; } How do I obtain that 'using' type in semantic-ctxt-scoped-types? As I described above, the parses doesn't seem to return a proper tag. >> ;; In C++, we want to find all the namespaces declared >> ;; locally and add them to the list. >> (setq tmp (semantic-find-tags-by-class 'type (current-buffer))) >> (setq tmp (semantic-find-tags-by-type "namespace" tmp)) >> (setq tmp (semantic-find-tags-by-name "unnamed" tmp)) >> (setq tagreturn tmp) > > When looking for stuff w/ Semantic against multiple constraints, you > have to do it in multiple lines. The above construct searches first for > all types in the current buffer. Then it filters against the output of > the first search for all namespaces. Of those namespaces, it pulls out > all the unnamed namespaces. Ah, OK. Thank you for the explanation. -David |
From: Eric M. L. <er...@si...> - 2009-07-12 21:42:23
|
On Sun, 2009-07-12 at 21:17 +0200, David Engster wrote: > Eric M. Ludlam <er...@si...> writes: > > If there is a particular using statement that is not being parsed, I'd > > like to know what that syntax is. > > Simply consider > > int main(void) { > using namespace std; > cout << "test"; > } > > How do I obtain that 'using' type in semantic-ctxt-scoped-types? As I > described above, the parses doesn't seem to return a proper tag. > Oh. I get it. Ok then, every parser that skips large blocks of code, such as the C one, has at least two parser entry points. One for the file, and one for parsing local context via `semantic-get-local-variables'. Some languages opt to implement getting local variables a different way. Anyway, for c.by, if you look for the %start you will see there is a 'codeblock' rule that doesn't have 'using' as one of the things it can parse. I added one and now your example returns std as something being used. The c smart completer may need some more help before it uses it though. Eric |
From: David E. <de...@ra...> - 2009-07-13 16:09:13
Attachments:
semantic-c-patch.diff
|
Eric M. Ludlam <er...@si...> writes: > Anyway, for c.by, if you look for the %start you will see there is a > 'codeblock' rule that doesn't have 'using' as one of the things it can > parse. > > I added one and now your example returns std as something being used. > The c smart completer may need some more help before it uses it though. Hi Eric, The parsing of the 'using' statement in local scopes now works. I had to add some code to the semantic-ctxt-scoped-types override. I have attached the patch to this mail. It uses semantic-get-local-variables to get the local 'using' statements though - maybe there's a more efficient way. Since this is working now, I looked a bit into the original problem with 'using' statements in (maybe even nested) namespaces. Consider the following: namespace foo { struct test { int a; }; } namespace bar { using foo::test; } What I would like to do is the following: When semantic encounters a 'using' statement in a namespace, it should create an "alias" in that namespace of every tag covered by that using statement. In the above example, we would then have "bar::test" as an alias of of "foo::test". I'm not sure if semantic has the notion of an alias - if not, the tag could simply be copied, i.e. we would simply have two tags. I'm not sure how keep those in sync, though. Even more general, consider namespace foo { using namespace std; } This makes all members of 'std' accessible via the prefix 'foo', but usually you would create such an alias by simply using namespace foo = std; This construct is currently not parsed at all; I guess this would have to be added to the grammar? In these cases, one would have to make all tags from 'std' accessible from 'foo'. I'd appreciate any ideas you could give on these issues. I'm not sure where to start with this. -David |
From: Eric M. L. <er...@si...> - 2009-07-16 01:04:11
|
On Mon, 2009-07-13 at 18:08 +0200, David Engster wrote: > Eric M. Ludlam <er...@si...> writes: > > Anyway, for c.by, if you look for the %start you will see there is a > > 'codeblock' rule that doesn't have 'using' as one of the things it can > > parse. > > > > I added one and now your example returns std as something being used. > > The c smart completer may need some more help before it uses it though. > > Hi Eric, > > The parsing of the 'using' statement in local scopes now works. I had to > add some code to the semantic-ctxt-scoped-types override. I have > attached the patch to this mail. It uses semantic-get-local-variables to > get the local 'using' statements though - maybe there's a more efficient > way. That function caches its value against the raw text, so if you call it multiple times in a row, in only parses the context once, so it should be safe to do. I've also checked in your patch with small changes after verifying against your old example. Would you be interested in adding a unit test in semantic/tests/testusing.cpp for this? Thanks! > Since this is working now, I looked a bit into the original problem with > 'using' statements in (maybe even nested) namespaces. Consider the > following: > > namespace foo { > struct test { > int a; > }; > } > > namespace bar { > using foo::test; > } > > What I would like to do is the following: When semantic encounters a > 'using' statement in a namespace, it should create an "alias" in that > namespace of every tag covered by that using statement. In the above > example, we would then have "bar::test" as an alias of of > "foo::test". I'm not sure if semantic has the notion of an alias - if > not, the tag could simply be copied, i.e. we would simply have two > tags. I'm not sure how keep those in sync, though. The existing magic in semantic-c relating to typedefs might help here. I call it magic in that it was contributed, and I've never quite fully understood some of the new paths here. Anyway, you can probably mimic the typedef dereferencer to do what you want for these types of using statements once you have determined what kind of using statement it is. See semantic-c-dereference-typedef for more details on this. There may be a new entry in the list of dereferencers in semantic-analyze-dereference-metatype to solve this problem. > Even more general, consider > > namespace foo { > using namespace std; > } > > This makes all members of 'std' accessible via the prefix 'foo', but > usually you would create such an alias by simply using > > namespace foo = std; > > This construct is currently not parsed at all; I guess this would have > to be added to the grammar? > > In these cases, one would have to make all tags from 'std' accessible > from 'foo'. This also looks like a typedef in some ways. I can look into what it will take to modify c.by to capture this syntax. Eric |
From: David E. <de...@ra...> - 2009-07-16 10:41:52
Attachments:
testusing-patch.diff
|
Hi Eric, Eric M. Ludlam <er...@si...> writes: > Would you be interested in adding a unit test in > semantic/tests/testusing.cpp for this? Thanks! Sure. I added a patch to this mail. > The existing magic in semantic-c relating to typedefs might help here. > I call it magic in that it was contributed, and I've never quite fully > understood some of the new paths here. > > Anyway, you can probably mimic the typedef dereferencer to do what you > want for these types of using statements once you have determined what > kind of using statement it is. > > See semantic-c-dereference-typedef for more details on this. There may > be a new entry in the list of dereferencers in > semantic-analyze-dereference-metatype to solve this problem. Thanks for the pointer. "meta type" pretty much seems to be what I was looking for. I'll look into how it can be used for namespaces. -David |
From: Eric M. L. <er...@si...> - 2009-07-17 02:28:03
|
On Thu, 2009-07-16 at 12:41 +0200, David Engster wrote: > Hi Eric, > > Eric M. Ludlam <er...@si...> writes: > > Would you be interested in adding a unit test in > > semantic/tests/testusing.cpp for this? Thanks! > > Sure. I added a patch to this mail. Thanks! I checked in the new tests. Eric |
From: David E. <de...@ra...> - 2009-07-17 13:53:58
|
Eric M. Ludlam <er...@si...> writes: > On Mon, 2009-07-13 at 18:08 +0200, David Engster wrote: >> This makes all members of 'std' accessible via the prefix 'foo', but >> usually you would create such an alias by simply using >> >> namespace foo = std; >> >> This construct is currently not parsed at all; I guess this would have >> to be added to the grammar? >> >> In these cases, one would have to make all tags from 'std' accessible >> from 'foo'. > > This also looks like a typedef in some ways. I can look into what it > will take to modify c.by to capture this syntax. There's another thing the grammar does not capture: it treats using declarations and directives (i.e. "using" and "using namespace") the same way. For example: namespace one { namespace two { struct test { int a; }; struct anotherTest { int b; }; } } namespace foo { // directive using namespace one::two; } namespace bar { // declaration using one::two::test; } While 'foo' contains the whole namespace 'one::two', the namespace 'bar' only contains the struct 'one::two::test'. However, both get parsed like this: ("foo" type (:members (("one::two" using (:type ("one::two" type (:type "class") nil nil)) (reparse-symbol namespacesubparts) #<overlay from 130 to 155 in testneu.cpp>)) :type "namespace") ("bar" type (:members (("one::two::test" using (:type ("one::two::test" type (:type "class") nil nil)) (reparse-symbol namespacesubparts) #<overlay from 180 to 201 in testneu.cpp>)) :type "namespace") That means, I cannot see if "one::two" and "one::two::test" refer to a type or another namespace - it could be both. I currently have to resolve this by searching the typecache for other namespaces and see if "one::two" and "one::two::test" exist there, which makes the code more complicated than it has to be. -David |
From: Eric M. L. <er...@si...> - 2009-07-18 01:53:10
|
Hi David, I'll be honest, in that I really don't know what all the namespace/using nuances are. If you do, it would be helpful to me to enumerate all the variants and specify what the expected output should be. That would give me a good target in the parser code. If you want to take a crack at changing c.by instead, there is a rule just called "using" that creates a type-tag that is, in turn converted to a 'using tag upstream. Variants could go in this rule. Thanks Eric On Fri, 2009-07-17 at 15:53 +0200, David Engster wrote: > Eric M. Ludlam <er...@si...> writes: > > On Mon, 2009-07-13 at 18:08 +0200, David Engster wrote: > >> This makes all members of 'std' accessible via the prefix 'foo', but > >> usually you would create such an alias by simply using > >> > >> namespace foo = std; > >> > >> This construct is currently not parsed at all; I guess this would have > >> to be added to the grammar? > >> > >> In these cases, one would have to make all tags from 'std' accessible > >> from 'foo'. > > > > This also looks like a typedef in some ways. I can look into what it > > will take to modify c.by to capture this syntax. > > There's another thing the grammar does not capture: it treats using > declarations and directives (i.e. "using" and "using namespace") the > same way. For example: > > namespace one { > namespace two { > struct test { int a; }; > struct anotherTest { int b; }; > } > } > > namespace foo { > // directive > using namespace one::two; > } > > namespace bar { > // declaration > using one::two::test; > } > > > While 'foo' contains the whole namespace 'one::two', the namespace 'bar' > only contains the struct 'one::two::test'. However, both get parsed > like this: > > ("foo" type > (:members > (("one::two" using > (:type > ("one::two" type > (:type "class") > nil nil)) > (reparse-symbol namespacesubparts) > #<overlay from 130 to 155 in testneu.cpp>)) > :type "namespace") > > ("bar" type > (:members > (("one::two::test" using > (:type > ("one::two::test" type > (:type "class") > nil nil)) > (reparse-symbol namespacesubparts) > #<overlay from 180 to 201 in testneu.cpp>)) > :type "namespace") > > That means, I cannot see if "one::two" and "one::two::test" refer to a > type or another namespace - it could be both. I currently have to > resolve this by searching the typecache for other namespaces and see if > "one::two" and "one::two::test" exist there, which makes the code more > complicated than it has to be. > > -David |
From: David E. <de...@ra...> - 2009-07-19 23:30:50
|
Eric M. Ludlam <er...@si...> writes: > I'll be honest, in that I really don't know what all the > namespace/using nuances are. If you do, it would be helpful to me to > enumerate all the variants and specify what the expected output should > be. That would give me a good target in the parser code. > > If you want to take a crack at changing c.by instead, there is a rule > just called "using" that creates a type-tag that is, in turn converted > to a 'using tag upstream. Variants could go in this rule. I saw that Jan Moringen already posted a patch in January which does just what I need (see http://thread.gmane.org/gmane.emacs.cedet/3038). I applied the patch (with changing :value to :type), and it seems to do the right thing without breaking the unit tests. Parsing the using statements correctly still required quite some code, but I think I have most of it running now; it just needs some further testing. -David |