Zwabel’s Weblog

March 6, 2009

Typedefs in Templates, and Code-Completion

Filed under: KDE,KDevelop — zwabel @ 2:28 pm

Sometimes you have to decide between being “correct”, and being user-friendly.

Also, sometimes you have to do one painful change with many regressions, to reach an ultimately better state.

I hope I had to do the last such step before the stable KDevelop release(Though you never know). I have changed the internal representation of the C++ DUChain, so typedefs spawn custom types, instead of being just pointers to the targets. This is not exactly what the C++ standard says, but this means that KDevelop will no more replace std::string with “std::basic_string<blah bla>” if you implement a function or do other simple refactoring stuff.

There is some problems with generally doing this though, because for example in a template container like “std::list”, you want the types in the completion-list not to show “std::list::reference_type”, which also is a typedef, but instead the type you gave to the container. So how should this be done to be most userfriendly, while still staying correct enough?

I’ve implemented this simple logic for the completion-list: If the typedefs target type recursively contains less template parameters, show that one, else show the typedef type. I’m quite sure you can construct a case where this does not work as expected, but for 99% of all cases, it should show the nicest thing that could be shown.

But there is other problems with representing typedef types as real types. The C++ standard explicitly states that typedef types given as template parameters, spawn exactly the same template instantiation as the typedefs real type. For that reason, a typedef has to be resolved before doing any template stuff. If this would be done, you as well be back to “std::basic_string<bla bla>” as return-types in “std::list<std::string>”, so a decision had to be done here.

I have decided to spawn different templates for typedef types, so that the user will see the nices possible representations.

And here the glorious results:
typedef_1

typedef_2

Unbelievable that such a simple-looking thing can be so painful.πŸ™‚
The good thing is: After some time of finding all the regressions, KDevelop is better than ever!

14 Comments »

  1. How does this take care of the typedefs in stdint.h?
    Does kdevelop group them as their actual type, or just as uint8_t etc.?
    And do functions defined with these typedefs as arguments show the actual types in the completion?

    Comment by Matthijs — March 6, 2009 @ 3:18 pm

  2. @Matthijs: Those types will be shown as their typedef types, eg. uint8_t

    Comment by zwabel — March 6, 2009 @ 3:22 pm

  3. Maybe this is exactly what you were talking about and I’m just too mortal to comprehend it, but if you explicitly define something using the lengthier name (when it has a shorter typedef available), will it use that?

    Comment by illissius — March 6, 2009 @ 4:12 pm

  4. I’ve noticed this minor bug in 3.9.91. I don’t know if you’re aware of it, maybe you’ve already fixed it:

    It’s valid to use the same name for a struct as in the typedef for the struct. This is very commonly used in a C project that I’m involved with. Here’s an example:

    typedef struct foo_t;

    struct foo_t {
    int bar;
    };

    int main()
    {
    foo_t foo; // Not recognized as struct foo_t, only typedef foo_t

    foo.| // No completion offered
    }

    Comment by Robin Pedersen — March 6, 2009 @ 4:29 pm

  5. Sorry, there’s a mistake above. The first line should be:
    typedef struct foo_t foo_t;

    Comment by Robin Pedersen — March 6, 2009 @ 4:31 pm

  6. @Illius: It does not care about the length. See the MyOwnIntegerType example.

    @Robin Pedersen: There is no official C support yet, so it’s not a real bug, but if you file a bug-report, I would probably make that thing work at some point.

    Comment by zwabel — March 6, 2009 @ 4:34 pm

  7. Is it too difficult at this point to modify DUChain to internally have an alias system. Unidirectional (ie “size_t” is an alias for “unsigned int” but not the reverse). Perhaps that is what you mean by “custom type”.

    This would not immediately solve the problem of which typename to show a user in a given context but would make it much easier to do the right things in the right places later on. Particularly if you (or someone else) goes on to implement more tools, such as a code refactoring it could be important to have the correct representation.

    You talked about “semantic highlighting” before, this is exactly about semantics, i.e. you want your object representing std::string to know

    (1) that it “is a” std::basic_string

    …but that…

    (2) in this context its **meaning in the code** is std::string.

    Comment by maninalift — March 6, 2009 @ 4:48 pm

  8. @maninalift: That alias system is there. The system knows that std::string is std::basic_string, it can do correct type-conversion operations, and everything.

    The only point where I had to do a compromise was the “identity” of template-instantiations, because by C++ standard, those should not care about typedefs, but now they do.

    Comment by zwabel — March 6, 2009 @ 4:51 pm

  9. Done, bug 186361

    Comment by Robin Pedersen — March 6, 2009 @ 4:54 pm

  10. Having such a full representation of typedefs would allow you to provide contextual information about the type semantics , e.g. this is a my_string which is a std::string which is a…

    While you might not want to show this all by default (then again you might) having it a click-away in the contextual information would do a lot to solve any frustrations relating to giving the user the “wrong” type information.

    Comment by maninalift — March 6, 2009 @ 4:56 pm

  11. @maninalift: That’s how it works. When you click a typedef name in the navigation-widget, you get to navigate the type behind the typedef, but normally you only see the typedef name.

    Comment by zwabel — March 6, 2009 @ 5:25 pm

  12. What I meant was, if in the example given, you had written, say, “unsigned int function2()”, it wouldn’t get too clever and use MyOwnIntegerType there, right?

    Comment by illissius — March 6, 2009 @ 6:41 pm

  13. @illisius: Impossible. That wouldn’t bee “too clever”, that would be stupid.πŸ˜‰

    Comment by zwabel — March 6, 2009 @ 7:19 pm

  14. @zwabel excellent

    Comment by maninalift — March 8, 2009 @ 5:06 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: