[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-bugs-dist
Subject:    [Bug 242660] QHashIterator mixes up code completion for key and value
From:       Nicolás Alvarez  <nicolas.alvarez () gmail ! com>
Date:       2010-11-16 19:58:52
Message-ID: 20101116195852.C625574907 () immanuel ! kde ! org
[Download RAW message or body]

https://bugs.kde.org/show_bug.cgi?id=242660


Nicolás Alvarez <nicolas.alvarez@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |investigated




--- Comment #3 from Nicolás Alvarez <nicolas alvarez gmail com>  2010-11-16 20:58:50 ---
I think I found the complex sequence of events that makes this fail.

Note: Just to be clear on parameter vs argument: in "template<typename T> int
foo(int x)", T is a template parameter and x is a simple function parameter. In
"foo<char>(4)", char is a template argument (assigned to the T template
parameter) and 4 is a function call argument (assigned to the x parameter).

When the MyIterator template declaration is found
(ContextBuilder::visitTemplateDeclaration), a new context is created to hold
the template parameters (the template context), and the parameters are added
one by one as declarations inside that context (by calling
DeclarationBuilder::visitTemplateParameter for each).

Later, when MyIterator<QString, int> is found, TemplateDeclaration::instantiate
is called. After it's convinced there really isn't a usable instantiation
already (eg. with the same template arguments), it calls
instantiateDeclarationAndContext.

instantiateDeclarationAndContext goes into the template context and replaces
the parameters like 'T' with real types like 'int'. To do this, it clones the
template context, iterates over its localDeclarations (the template parameter
declarations), clones those too, and changes the type of the new declaration to
be a real type, taken from the templateArguments list. To match the template
parameter to its argument, it uses the position in the templateArguments list:

arg=0;
foreach (declaration in templateContext->localDeclarations()) {
    declaration.type = templateArguments[arg].type;
    arg++;
}

So far so good.

The problem is during the creation of the initial, non-instantiated template
context. I thought declarations were always added at the end of the declaration
list for the current context, but it turns out they are added according to
their ranges in the document (see DUContextDynamicData::addDeclaration).

When the template comes from an expanded macro, the ranges of the template
parameters (and all other declarations like the class) are all identical:
zero-length ranges at the last character of the macro call. addDeclaration
compares the range of the new decl to the ranges of existing decls in the
context to see where it should go. Since all ranges are identical, it doesn't
find any good place to put it. Quote from a comment in addDeclaration: "We
haven't found any child that is before this one, so prepend it". Why prepend
and not append?

When parsing template<class Key, class T> expanded from a macro, KDevelop will
create a template context, add the Key declaration to it, and then since T's
range is equal to Key's range, T will be prepended. As a result the template
context has declarations T and Key, in that order. When that's instantiated as
MyIterator<QString, int>, T and Key will be assigned QString and int,
respectively, which is backwards.

Whew.

Now we just need someone with a clue to decide how to fix it. Is there a good
reason for prepending instead of appending, for starters?

-- 
Configure bugmail: https://bugs.kde.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching all bug changes.
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic