Review Request 119208: Use DUContext::Class instead of DUContext::Namespace when declaring namespace contexts

Denis Steckelmacher steckdenis at yahoo.fr
Thu Jul 10 12:06:55 UTC 2014



> On July 10, 2014, 10:18 a.m., Milian Wolff wrote:
> > This will mean you'll have to special-case these imports in the navigation windows though, no? There, you do want to say that it is a namespace (and not a class/type), or?
> > 
> > Furthermore, unrelated to this review request, could you explain me again why you create alias declarations instead of importing the context of the imported file into the namespace/class context?
> 
> Denis Steckelmacher wrote:
>     Even if the type of the context is set to Class, the kind of the declaration remains Namespace. The code-completion items and the navigation widget therefore still show the proper icon and "namespace ...". Is there a place that may use the type of the context and that I should check?
>     
>     Regarding aliased declarations, I first tried to import the context of the file in the namespace, but then I discovered that I needed some sort of filtering. For instance, when importing a file, the namespace alias declarations of this file should not be imported (typing "MyFile." should offer completion items for every local declaration of MyFile, but not for "MyFile.QtQuick", "MyFile.MyOtherFile", etc).
> 
> Milian Wolff wrote:
>     Regarding navigation: ok, cool. if it works that sounds OK.
>     
>     Regarding alias declarations: we should rethink that and probably filter it in the code completion then, instead of spamming the duchain with alias declarations.
> 
> Sven Brauch wrote:
>     Does "MyFile.QtQuick.Foo" work in theory? If yes, then I certainly agree with Milian that the filtering should take place in the completion list.

I remember having played with addImportedParentContext, namespaces and automatic imports, and I remember that using alias declarations was a last resort solution. Until just now, I did not remember what was the problem, though :-).

Now I have remembered what it was: http://steckdenis.be/post-2014-06-17-qml-module-versions-and-automatic-imports.html (first title, fourth paragraph) :

> There is a small technical difficulty here, though: if every file imports all the others, we get circular dependencies (A imports B and C, but B imports A and C, thus A can see itself by the way of B). The solution that I used is to “copy” the declarations of every file into the others instead of importing them. This way, A doesn’t import anything but contains the declarations of B, C, etc. B does the same, but uses the version of A without the declarations of B, C, etc copied. This way, A cannot see itself by the way of B, and B cannot see itself by the way of A.

Using clearer and more technical words, I have a problem when unnamed imports are used (the automatic import of the files in the same directory, and imports without an "as" clause). Let's take three files: A, B and C. Let's say that B and C are in the same directory, and that A contains an "import B as B" statement.

If addImportedParentContext is used, then the top-context of B will import the top-context of C (because they are in the same directory). The top-context of C will import the top-context of B, which will create a cyclic import (very difficult to solve, because both B and C should be able to see the declarations of the other file, but that could be worked around using namespaces and {...import...} namespace aliases). This is the first problem.

Now, A imports B, because A is interested in the declarations of B. If A creates a namespace named B (because there was an "as B" clause in the import), and imports the top-context of B in this namespace, then every declaration visible from the top-context of B will be available in the namespace B. The problem is that B sees the declaration of C, so the declarations of C become visible in the namespace "B", that should only contain the declarations of B. This is the second problem.

Using alias declarations, I can copy only the local declarations of the context I import. This avoids circular imports (A imports the declarations of B, no matter which declarations B can have imported, because aliased declarations are filtered out), and ensures that importing a file only imports the file and not everything else it may have imported itself.

Maybe a better solution exists for these two problems. I'll think about it, but the solution used depends on the importance you give to concise code (alias declarations require less than 10 lines of code and work well) and clean DUChain (alias declarations fill the DUChain, and using nested contexts or namespace aliases could simplify the DUChain at the expense of code complexity).


- Denis


-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://git.reviewboard.kde.org/r/119208/#review62058
-----------------------------------------------------------


On July 10, 2014, 10:04 a.m., Denis Steckelmacher wrote:
> 
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://git.reviewboard.kde.org/r/119208/
> -----------------------------------------------------------
> 
> (Updated July 10, 2014, 10:04 a.m.)
> 
> 
> Review request for KDevelop.
> 
> 
> Repository: kdev-qmljs
> 
> 
> Description
> -------
> 
> KDevPlatform sometimes special-cases contexts having the Namespace type. This was not a problem until I discovered that this QML snippet does not work:
> 
>     :::javascript
>     import "myfile.js" as MyFile
> 
>     Item {
>         onTest: console.log(MyFile.myVariable)
>     }
> 
> In order to better see which contexts are used, here is the same snippet in a C++-like language:
> 
>     :::cpp
>     namespace MyFile {
>         alias myVariable = "myVariable in myfile.js";
>     }
>     
>     class __ : public Item {
>         void onTest() {
>             console.log(MyFile::myVariable);
>         }
>     };
> 
> The line starting with "onTest" calls findDeclarations(myVariable) on MyFile, that is a namespace (and has a namespace context). myVariable is a local declaration of MyFile, but is not returned by findDeclarations because an if statement skips findLocalDeclarations for Namespace contexts. A comment in language/duchain/ducontext.cpp says that declarations in namespace contexts are resolved in the top-context, but this cannot happen in my case because I set the DontSearchInParent flag when looking for object members.
> 
> This patch work-arounds this issue by giving a Class type to the internal contexts of namespace declarations. This way, KDevPlatform does not special-case the contexts and works as expected.
> 
> 
> Diffs
> -----
> 
>   duchain/declarationbuilder.cpp 8927633 
> 
> Diff: https://git.reviewboard.kde.org/r/119208/diff/
> 
> 
> Testing
> -------
> 
> The whole testsuite passes. The feature shown above (importing Javascript files) is not added by this patch, but is made to work with this patch applied.
> 
> 
> Thanks,
> 
> Denis Steckelmacher
> 
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/kdevelop-devel/attachments/20140710/5488c78e/attachment.html>


More information about the KDevelop-devel mailing list