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

List:       kde-commits
Subject:    [kdev-python] /: Refactor import declaration creation code for dotted names
From:       Sven Brauch <svenbrauch () googlemail ! com>
Date:       2012-02-29 21:30:11
Message-ID: 20120229213011.ED230A60A9 () git ! kde ! org
[Download RAW message or body]

Git commit e6af0a0e39480eb4697edfeae0b6f65f7f5e02ff by Sven Brauch.
Committed on 29/02/2012 at 22:29.
Pushed by brauch into branch 'master'.

Refactor import declaration creation code for dotted names

please test! should fix various issues

M  +3    -0    codecompletion/pythoncodecompletioncontext.cpp
M  +131  -93   duchain/declarationbuilder.cpp
M  +31   -2    duchain/declarationbuilder.h
M  +6    -2    duchain/helpers.cpp

http://commits.kde.org/kdev-python/e6af0a0e39480eb4697edfeae0b6f65f7f5e02ff

diff --git a/codecompletion/pythoncodecompletioncontext.cpp \
b/codecompletion/pythoncodecompletioncontext.cpp index 965c090..746a044 100644
--- a/codecompletion/pythoncodecompletioncontext.cpp
+++ b/codecompletion/pythoncodecompletioncontext.cpp
@@ -435,7 +435,10 @@ QList<CompletionTreeItemPointer> \
                PythonCodeCompletionContext::getCompletionItems
         QList<DUContext*> searchContexts = Helper::internalContextsForClass(cls, \
m_context->topContext());  QList<DeclarationDepthPair> keepDeclarations;
         foreach ( const DUContext* currentlySearchedContext, searchContexts ) {
+            kDebug() << "searching context " << \
                currentlySearchedContext->scopeIdentifier() << "for autocompletion \
                items";
             QList<DeclarationDepthPair> declarations = \
currentlySearchedContext->allDeclarations(CursorInRevision::invalid(), \
m_context->topContext(), false); +            kDebug() << "found" << \
declarations.length() << "declarations"; +            
             // filter out those which are builtin functions, and those which were \
                imported; we don't want those here
             // TODO rework this, it's maybe not the most elegant solution possible
             KUrl url = KUrl(KStandardDirs::locate("data", \
                "kdevpythonsupport/documentation_files/builtindocumentation.py"));
diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp
index 40594a8..30ced5d 100644
--- a/duchain/declarationbuilder.cpp
+++ b/duchain/declarationbuilder.cpp
@@ -399,6 +399,7 @@ void DeclarationBuilder::visitImportFrom(ImportFromAst* node)
 {
     Python::AstDefaultVisitor::visitImportFrom(node);
     QString moduleName;
+    QString declarationName;
     foreach ( AliasAst* name, node->names ) {
         if ( node->module ) {
             moduleName = node->module->value + "." + name->name->value;
@@ -407,16 +408,19 @@ void DeclarationBuilder::visitImportFrom(ImportFromAst* node)
             moduleName = "." + name->name->value;
         }
         Identifier* declarationIdentifier = 0;
+        declarationName = "";
         if ( name->asName ) {
             declarationIdentifier = name->asName;
+            declarationName = name->asName->value;
         }
         else {
             declarationIdentifier = name->name;
+            declarationName = name->name->value;
         }
-        Declaration* success = createModuleImportDeclaration(moduleName, \
declarationIdentifier, 0, DontCreateProblems); +        Declaration* success = \
createModuleImportDeclaration(moduleName, declarationName, declarationIdentifier, 0, \
DontCreateProblems);  if ( not success and node->module ) {
-            moduleName = node->module->value + ".__init__." + name->name->value;
-            createModuleImportDeclaration(moduleName, declarationIdentifier);
+            QString modifiedModuleName = node->module->value + ".__init__." + \
name->name->value; +            createModuleImportDeclaration(modifiedModuleName, \
declarationName, declarationIdentifier);  }
     }
 }
@@ -477,14 +481,129 @@ void DeclarationBuilder::visitImport(ImportAst* node)
         QString moduleName = name->name->value;
         // use alias if available, name otherwise
         Identifier* declarationIdentifier = name->asName ? name->asName : \
                name->name;
-        createModuleImportDeclaration(moduleName, declarationIdentifier);
+        createModuleImportDeclaration(moduleName, declarationIdentifier->value, \
declarationIdentifier);  }
 }
 
-Declaration* DeclarationBuilder::createModuleImportDeclaration(QString dottedName, \
Identifier* declarationIdentifier, Ast* rangeNode, ProblemPolicy createProblem) \
+Declaration* DeclarationBuilder::createDeclarationTree(const QStringList& \
nameComponents, Identifier* declarationIdentifier, +                                  \
const ReferencedTopDUContext& innerCtx, Declaration* aliasDeclaration, +              \
const RangeInRevision& range)  {
-    QPair<KUrl, QStringList> moduleInfo = findModulePath(dottedName);
-    kDebug() << dottedName;
+    Q_ASSERT( ( innerCtx.data() or aliasDeclaration ) && "exactly one of innerCtx or \
aliasDeclaration must be provided"); +    Q_ASSERT( ( not innerCtx.data() or not \
aliasDeclaration ) && "exactly one of innerCtx or aliasDeclaration must be \
provided"); +    
+    kDebug() << "creating declaration tree for" << nameComponents;
+    
+    Declaration* lastDeclaration = 0;
+    int depth = 0;
+    
+    // check for already existing trees to update
+    for ( int i = nameComponents.length() - 1; i >= 0; i-- ) {
+        QStringList currentName;
+        for ( int j = 0; j < i; j++ ) {
+            currentName.append(nameComponents.at(j));
+        }
+        lastDeclaration = findDeclarationInContext(currentName, topContext());
+        if ( lastDeclaration and lastDeclaration->range() < range ) {
+            depth = i;
+            break;
+        }
+    }
+    
+    DUContext* extendingPreviousImportCtx = 0;
+    QStringList remainingNameComponents;
+    bool injectingContext = false;
+    if ( lastDeclaration and lastDeclaration->internalContext() ) {
+        kDebug() << "Found existing import statement while creating declaration for \
" << declarationIdentifier->value; +        for ( int i = depth; i < \
nameComponents.length(); i++ ) { +            \
remainingNameComponents.append(nameComponents.at(i)); +        }
+        extendingPreviousImportCtx = lastDeclaration->internalContext();
+        injectContext(extendingPreviousImportCtx);
+        injectingContext = true;
+    }
+    else {
+        remainingNameComponents = nameComponents;
+        extendingPreviousImportCtx = topContext();
+    }
+    
+    // now, proceed normally
+    QList<Declaration*> openedDeclarations;
+    QList<StructureType::Ptr> openedTypes;
+    QList<DUContext*> openedContexts;
+    
+    DUChainWriteLocker lock(DUChain::lock());
+    for ( int i = 0; i < remainingNameComponents.length(); i++ ) {
+        const QString& component = remainingNameComponents.at(i);
+        kDebug() << "creating context for " << component;
+        Identifier* temporaryIdentifier = new Identifier(component);
+        Declaration* d = 0;
+        StructureType::Ptr moduleType = StructureType::Ptr(new StructureType());
+        temporaryIdentifier->copyRange(declarationIdentifier);
+        temporaryIdentifier->endCol = temporaryIdentifier->startCol - 1;
+        openType(moduleType);
+        if ( i != remainingNameComponents.length() - 1 or not aliasDeclaration ) {
+            d = visitVariableDeclaration<Declaration>(temporaryIdentifier);
+            if ( d ) {
+                if ( topContext() != extendingPreviousImportCtx ) {
+                    \
d->setRange(RangeInRevision(extendingPreviousImportCtx->range().start, \
extendingPreviousImportCtx->range().start)); +                }
+                d->setAutoDeclaration(true);
+                currentContext()->createUse(d->ownIndex(), \
editorFindRange(declarationIdentifier, declarationIdentifier)); +            }
+        }
+        else {
+            AliasDeclaration* adecl = \
visitVariableDeclaration<AliasDeclaration>(temporaryIdentifier, range); +            \
if ( adecl ) { +                adecl->setAliasedDeclaration(aliasDeclaration);
+            }
+            d = adecl;
+        }
+        
+        openedContexts.append(openContext(declarationIdentifier, \
KDevelop::DUContext::Other)); +        openedDeclarations.append(d);
+        openedTypes.append(moduleType);
+        if ( i == remainingNameComponents.length() - 1 ) {
+            if ( innerCtx ) {
+                kDebug() << "adding imported context to inner declaration";
+                currentContext()->addImportedParentContext(innerCtx);
+            }
+            else if ( aliasDeclaration ) {
+                kDebug() << "setting alias declaration on inner declaration";
+            }
+        }
+        // TODO this sucks
+        currentContext()->setLocalScopeIdentifier(QualifiedIdentifier("__kdevpythonlanguagesupport_import_helper"));
 +        delete temporaryIdentifier;
+    }
+    for ( int i = remainingNameComponents.length() - 1; i >= 0; i-- ) {
+        kDebug() << "closing context";
+        closeType();
+        closeContext();
+        Declaration* d = openedDeclarations.at(i);
+        if ( d and ( i != 0 or not aliasDeclaration ) ) {
+            openedTypes[i]->setDeclaration(d);
+            d->setType(openedTypes.at(i));
+            d->setInternalContext(openedContexts.at(i));
+        }
+    }
+    
+    if ( injectingContext ) {
+        closeInjectedContext();
+    }
+    
+    if ( ! openedDeclarations.isEmpty() ) {
+        return openedDeclarations.last();
+    }
+    else return 0;
+}
+
+Declaration* DeclarationBuilder::createModuleImportDeclaration(QString moduleName, \
QString declarationName, +                                                            \
Identifier* declarationIdentifier, +                                                  \
Ast* rangeNode, ProblemPolicy createProblem) +{
+    QPair<KUrl, QStringList> moduleInfo = findModulePath(moduleName);
+    kDebug() << moduleName;
     RangeInRevision range(RangeInRevision::invalid());
     if ( rangeNode ) {
         range = rangeForNode(rangeNode, false);
@@ -507,7 +626,7 @@ Declaration* \
                DeclarationBuilder::createModuleImportDeclaration(QString dottedNam
             p->setFinalLocation(DocumentRange(currentlyParsedDocument(), \
range.castToSimpleRange())); // TODO ok?  \
p->setSource(KDevelop::ProblemData::SemanticAnalysis);  \
                p->setSeverity(KDevelop::ProblemData::Warning);
-            p->setDescription(i18n("Module \"%1\" not found", dottedName));
+            p->setDescription(i18n("Module \"%1\" not found", moduleName));
             {
                 DUChainWriteLocker wlock(DUChain::lock());
                 ProblemPointer ptr(p);
@@ -533,89 +652,7 @@ Declaration* \
DeclarationBuilder::createModuleImportDeclaration(QString dottedNam  if ( \
moduleInfo.second.isEmpty() ) {  // import the whole module
         kDebug() << "Got module, importing it" << declarationIdentifier->value;
-        Declaration* lastDeclaration = 0;
-        QStringList nameComponents = declarationIdentifier->value.split('.');
-        int depth = 0;
-        
-        for ( int i = nameComponents.length() - 1; i >= 0; i-- ) {
-            QStringList currentName;
-            for ( int j = 0; j < i; j++ ) {
-                currentName.append(nameComponents.at(j));
-            }
-            lastDeclaration = findDeclarationInContext(currentName, topContext());
-            if ( lastDeclaration and lastDeclaration->range() < range ) {
-                depth = i;
-                break;
-            }
-        }
-        
-        DUContext* extendingPreviousImportCtx = 0;
-        QStringList remainingNameComponents;
-        bool injectingContext = false;
-        if ( lastDeclaration and lastDeclaration->internalContext() ) {
-            kDebug() << "Found existing import statement while creating declaration \
                for " << declarationIdentifier->value;
-            for ( int i = depth; i < nameComponents.length(); i++ ) {
-                remainingNameComponents.append(nameComponents.at(i));
-            }
-            extendingPreviousImportCtx = lastDeclaration->internalContext();
-            injectContext(extendingPreviousImportCtx);
-            injectingContext = true;
-        }
-        else {
-            remainingNameComponents = nameComponents;
-            extendingPreviousImportCtx = topContext();
-        }
-        
-        // now, proceed normally
-        QList<Declaration*> openedDeclarations;
-        QList<StructureType::Ptr> openedTypes;
-        QList<DUContext*> openedContexts;
-//         bool extendingPreviousImports = true;
-        
-        DUChainWriteLocker lock(DUChain::lock());
-        for ( int i = 0; i < remainingNameComponents.length(); i++ ) {
-            const QString& component = remainingNameComponents.at(i);
-            kDebug() << "creating context for " << component;
-            Identifier* temporaryIdentifier = new Identifier(component);
-            Declaration* d = 0;
-            StructureType::Ptr moduleType;
-            moduleType = StructureType::Ptr(new StructureType());
-            temporaryIdentifier->copyRange(declarationIdentifier);
-            temporaryIdentifier->endCol = temporaryIdentifier->startCol - 1;
-            openType(moduleType);
-            d = visitVariableDeclaration<Declaration>(temporaryIdentifier);
-            delete temporaryIdentifier;
-            if ( d ) {
-                if ( topContext() != extendingPreviousImportCtx ) {
-                    \
d->setRange(RangeInRevision(extendingPreviousImportCtx->range().start, \
                extendingPreviousImportCtx->range().start));
-                }
-                d->setAutoDeclaration(true);
-                currentContext()->createUse(d->ownIndex(), \
                editorFindRange(declarationIdentifier, declarationIdentifier));
-            }
-            openedContexts.append(openContext(declarationIdentifier, \
                KDevelop::DUContext::Other));
-            if ( i == remainingNameComponents.length() - 1 ) {
-                currentContext()->addImportedParentContext(moduleContext);
-            }
-            // TODO this sucks
-            currentContext()->setLocalScopeIdentifier(QualifiedIdentifier("__kdevpythonlanguagesupport_import_helper"));
                
-            openedDeclarations.append(d);
-            openedTypes.append(moduleType);
-        }
-        for ( int i = remainingNameComponents.length() - 1; i >= 0; i-- ) {
-            kDebug() << "closing context";
-            closeType();
-            closeContext();
-            Declaration* d = openedDeclarations.at(i);
-            if ( d ) {
-                openedTypes[i]->setDeclaration(d);
-                d->setType(openedTypes.at(i));
-                d->setInternalContext(openedContexts.at(i));
-            }
-        }
-        
-        if ( injectingContext ) {
-            closeInjectedContext();
-        }
+        resultingDeclaration = createDeclarationTree(declarationName.split("."), \
declarationIdentifier, moduleContext, 0, range);  }
     else {
         // import a specific declaration from the given file
@@ -630,13 +667,14 @@ Declaration* \
DeclarationBuilder::createModuleImportDeclaration(QString dottedNam  kDebug() << \
"Result: " << originalDeclaration;  if ( originalDeclaration ) {
                 DUChainWriteLocker lock(DUChain::lock());
-                resultingDeclaration = \
visitVariableDeclaration<AliasDeclaration>(declarationIdentifier, range); +           \
resultingDeclaration = createDeclarationTree(declarationName.split("."), \
declarationIdentifier, ReferencedTopDUContext(0), originalDeclaration); +             \
                /** DEBUG **/
                 if ( dynamic_cast<AliasDeclaration*>(resultingDeclaration) ) {
-                    \
static_cast<AliasDeclaration*>(resultingDeclaration)->setAliasedDeclaration(originalDeclaration);
                
                     kDebug() << "Resulting alias: " << \
resultingDeclaration->toString();  }
                 else
                     kWarning() << "import declaration is being overwritten!";
+                /** END DEBUG **/
             }
             else if ( createProblem != DontCreateProblems ) {
                 KDevelop::Problem *p = new KDevelop::Problem();
diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h
index fee837c..39aba2d 100644
--- a/duchain/declarationbuilder.h
+++ b/duchain/declarationbuilder.h
@@ -96,15 +96,44 @@ protected:
         DontCreateProblems
     };
     
-    Declaration* createModuleImportDeclaration(QString dottedName, \
Python::Identifier* declarationIdentifier, +    /**
+     * @brief Create a declaration for an import statement.
+     *
+     * @param dottedName The dotted name of the module, like "random.randint".
+     * @param declarationIdentifier provides the name and range
+     * @param rangeNode can be used to override the declarationIdentifier's range, \
if required. Defaults to 0. +     * @param createProblem whether or not to create \
DUChain problems Defaults to CreateProblems. +     * @return :Declaration* the \
declaration created, or 0 if none was found. +     **/
+    Declaration* createModuleImportDeclaration(QString dottedName, QString \
                declarationName, Python::Identifier* declarationIdentifier,
                                                Python::Ast* rangeNode = 0, \
ProblemPolicy createProblem = CreateProblems); +    /**
+     * @brief Create a tree of declarations for the specified list.
+     * Give the list ["foo","bar","baz"], and you'll get a declaration "foo" \
containing "bar" in its internal context, +     * "bar" containing "baz" etc.
+     * This is used in import handling.
+     * This function automatically updates existing declaration trees to the maximum \
level possible! Thus, +     * if you call this with ["foo", "bar"], then ["foo", \
"baz"], "baz" will be added to "foo". +     * 
+     * @warning The DUChain must not be locked when this is called.
+     * 
+     * @param nameComponents the list of names to create declarations for
+     * @param declarationIdentifier provides the name and range
+     * @param innerCtx the internalContext() to set on the last created declaration. \
Either this or aliasDeclaration must be provided! +     * @param aliasDeclaration the \
declaration to alias with the last created declaration +     * @param rangeNode can \
be used to override the declarationIdentifier's range, if required. Defaults to 0. +  \
* @return :Declaration* the top level declaration created +     **/
+    Declaration* createDeclarationTree(const QStringList& nameComponents, \
Identifier* declarationIdentifier, +                                       const \
ReferencedTopDUContext& innerCtx, Declaration* aliasDeclaration = 0, +                \
const RangeInRevision& range = RangeInRevision::invalid());  
     /**
      * @brief Find a declaration specified by "foo.bar.baz" in the given top \
                context.
      *
      * @param dottedNameIdentifier string list of module names, starting with the \
                most general one.
      * @param ctx top context to search
-     * @return :Declaration* declaration if found, 0x0 otherwise.
+     * @return :Declaration* declaration if found, 0 otherwise.
      * 
      * @note The DUChain must not be locked.
      **/
diff --git a/duchain/helpers.cpp b/duchain/helpers.cpp
index ed3b20f..88d5885 100644
--- a/duchain/helpers.cpp
+++ b/duchain/helpers.cpp
@@ -181,9 +181,13 @@ QList< DUContext* > \
Helper::internalContextsForClass(StructureType::Ptr klassTyp  return searchContexts;
     }
     searchContexts << klassType->internalContext(context);
-    Declaration* decl = klassType->declaration(context);
+    Declaration* decl = \
Helper::resolveAliasDeclaration(klassType->declaration(context));  ClassDeclaration* \
                klass = dynamic_cast<ClassDeclaration*>(decl);
-    kDebug() << "Got class Declaration:" << klass;
+    kDebug() << "Got class Declaration:" << klass << decl;
+    if ( decl ) {
+        kDebug() << decl->toString();
+    }
+    kDebug() << klassType->internalContext(context)->allDeclarations(CursorInRevision::invalid(), \
context).length();  if ( klass ) {
         kDebug() << "Base classes: " << klass->baseClassesSize();
         FOREACH_FUNCTION ( const BaseClassInstance& base, klass->baseClasses ) {


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

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