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

List:       kde-commits
Subject:    [kdev-ruby/gsoc] duchain: This commit fixes a few things regarding class subclassing:
From:       Miquel_Sabaté <mikisabate () gmail ! com>
Date:       2012-05-31 19:29:56
Message-ID: 20120531192956.5C8DBA60A9 () git ! kde ! org
[Download RAW message or body]

Git commit 95c6675fef5d9ae7ec0770f64fb6d30ca4ab2570 by Miquel Sabaté.
Committed on 30/05/2012 at 12:54.
Pushed by mssola into branch 'gsoc'.

This commit fixes a few things regarding class subclassing:

  - Fixed visitors of methods/classes/modules from modifying the original AST.
  - Properly importing the context of the base class.
  - Implemented tests (both duchain and uses) regarding subclassing.

M  +9    -2    duchain/builders/contextbuilder.cpp
M  +9    -13   duchain/builders/declarationbuilder.cpp
M  +49   -14   duchain/tests/duchain.cpp
M  +3    -0    duchain/tests/duchain.h
M  +5    -0    duchain/tests/duchaintestbase.h
M  +14   -0    duchain/tests/uses.cpp
M  +1    -0    duchain/tests/uses.h

http://commits.kde.org/kdev-ruby/95c6675fef5d9ae7ec0770f64fb6d30ca4ab2570

diff --git a/duchain/builders/contextbuilder.cpp \
b/duchain/builders/contextbuilder.cpp index 184a214..c541ac6 100644
--- a/duchain/builders/contextbuilder.cpp
+++ b/duchain/builders/contextbuilder.cpp
@@ -148,14 +148,20 @@ KDevelop::QualifiedIdentifier \
ContextBuilder::identifierForNode(NameAst *name)  
 void ContextBuilder::visitModuleStatement(RubyAst *node)
 {
-    node->tree = node->tree->l;
+    Node *aux = node->tree;
+    node->tree = aux->l;
     visitBody(node);
+    node->tree = aux;
 }
 
 void ContextBuilder::visitClassStatement(RubyAst *node)
 {
-    node->tree = node->tree->l;
+    Node *aux = node->tree;
+    node->tree = aux->cond;
+    visitNode(node);
+    node->tree = aux->l;
     visitBody(node);
+    node->tree = aux;
 }
 
 void ContextBuilder::visitMethodStatement(RubyAst *node)
@@ -183,6 +189,7 @@ void ContextBuilder::visitMethodStatement(RubyAst *node)
         RubyAstVisitor::visitBody(node);
         closeContext();
     }
+    node->tree = aux;
 }
 
 void ContextBuilder::visitRequire(RubyAst *node)
diff --git a/duchain/builders/declarationbuilder.cpp \
b/duchain/builders/declarationbuilder.cpp index 774ddb1..2134f1f 100644
--- a/duchain/builders/declarationbuilder.cpp
+++ b/duchain/builders/declarationbuilder.cpp
@@ -88,6 +88,7 @@ void DeclarationBuilder::visitClassStatement(RubyAst *node)
     m_accessPolicyStack.push(Declaration::Public);
     lastClassModule = decl;
     insideClassModule = true;
+    openContextForClassDefinition(node);
 
     /*
      * Now let's check for the base class. Ruby does not support multiple
@@ -98,17 +99,18 @@ void DeclarationBuilder::visitClassStatement(RubyAst *node)
     if (node->tree) {
         QualifiedIdentifier baseId = getIdentifier(node);
         KDevelop::Declaration *baseDecl = declarationForNode(baseId, range, \
                DUContextPointer(currentContext()));
-        if (!baseDecl) {
+        if (!baseDecl)
             appendProblem(node->tree, i18n("NameError: undefined local variable or \
                method `%1'", baseId.toString()));
-        } else {
+        else {
             ClassDeclaration *realClass = dynamic_cast<ClassDeclaration \
                *>(baseDecl);
-            if (!realClass || realClass->classType() == \
ClassDeclarationData::Interface) { +            if (!realClass || \
                realClass->classType() == ClassDeclarationData::Interface)
                 appendProblem(node->tree, i18n("TypeError: wrong argument type \
                (expected Class)"));
-            } else {
+            else {
+                currentContext()->addImportedParentContext(realClass->internalContext());
  BaseClassInstance base;
-                StructureType::Ptr baseType = baseDecl->type<StructureType>();
-                base.baseClass = baseType->indexed();
+                base.baseClass = realClass->indexedType();
                 base.access = KDevelop::Declaration::Public;
+                base.virtualInheritance = false;
                 decl->addBaseClass(base);
             }
         }
@@ -116,16 +118,13 @@ void DeclarationBuilder::visitClassStatement(RubyAst *node)
     node->tree = aux;
 
     /*  Setup types and go for the class body */
-    StructureType::Ptr type = StructureType::Ptr(new ClassType());
+    ClassType::Ptr type = ClassType::Ptr(new ClassType());
     type->setDeclaration(decl);
     decl->setType(type);
     openType(type);
 
-    openContextForClassDefinition(node);
     decl->setInternalContext(currentContext());
-    lock.unlock();
     DeclarationBuilderBase::visitClassStatement(node);
-    lock.lock();
     closeContext();
 
     closeType();
@@ -141,7 +140,6 @@ void DeclarationBuilder::visitModuleStatement(RubyAst* node)
     QualifiedIdentifier id = getIdentifier(node);
 
     setComment(getComment(node));
-    /* TODO: should this get a ModuleDeclaration or so? */
     ClassDeclaration *decl = openDeclaration<ClassDeclaration>(id, range);
     decl->setKind(KDevelop::Declaration::Type);
     decl->clearBaseClasses();
@@ -157,9 +155,7 @@ void DeclarationBuilder::visitModuleStatement(RubyAst* node)
 
     openContextForClassDefinition(node);
     decl->setInternalContext(currentContext());
-    lock.unlock();
     DeclarationBuilderBase::visitModuleStatement(node);
-    lock.lock();
     closeContext();
 
     closeType();
diff --git a/duchain/tests/duchain.cpp b/duchain/tests/duchain.cpp
index ab02572..6c4329f 100644
--- a/duchain/tests/duchain.cpp
+++ b/duchain/tests/duchain.cpp
@@ -33,6 +33,7 @@
 #include <duchain/tests/duchain.h>
 #include <duchain/types/classtype.h>
 #include <duchain/declarations/methoddeclaration.h>
+#include <duchain/declarations/classdeclaration.h>
 
 
 QTEST_MAIN(Ruby::TestDUChain)
@@ -312,8 +313,7 @@ void TestDUChain::multipleAssignment2()
 {
     QByteArray code("a, b = 1, [1, 2, 3]");
 
-    /* TODO: pending */
-    QVERIFY(true);
+    PENDING("Waiting for the ClassType to be supported");
 }
 
 void TestDUChain::multipleAssignmentLeft()
@@ -546,32 +546,28 @@ void TestDUChain::assignFromArrayItem1()
 {
     QByteArray code("a = [1, 2, 3]; b = a[0]");
 
-    /* TODO: pending */
-    QVERIFY(true);
+    PENDING("Waiting for the ClassType to be supported");
 }
 
 void TestDUChain::assignFromArrayItem2()
 {
     QByteArray code("a = [1, '2']; b = a[0]");
 
-    /* TODO: pending */
-    QVERIFY(true);
+    PENDING("Waiting for the ClassType to be supported");
 }
 
 void TestDUChain::assignFromHashItem()
 {
     QByteArray code("a = { :a => 'a', b: 1 }; b = a[:a]");
 
-    /* TODO: pending */
-    QVERIFY(true);
+    PENDING("Waiting for the ClassType to be supported");
 }
 
 void TestDUChain::assignToArrayItem()
 {
     QByteArray code("a = [1, nil]; a[1] = 2");
 
-    /* TODO: pending */
-    QVERIFY(true);
+    PENDING("Waiting for the ClassType to be supported");
 }
 
 //END: Variable Length Container
@@ -646,6 +642,47 @@ void TestDUChain::accessPolicyMethodInModule()
     QVERIFY(d4->accessPolicy() == Declaration::Public);
 }
 
+void TestDUChain::checkSubClassing()
+{
+    QByteArray code("class Base; end; class Final < Base; end");
+    TopDUContext *top = parse(code, "checkSubClassing");
+    DUChainReleaser releaser(top);
+    DUChainWriteLocker lock(DUChain::lock());
+
+    // Base
+    ClassDeclaration *base = dynamic_cast<ClassDeclaration \
*>(top->localDeclarations().first()); +    QVERIFY(base);
+    QCOMPARE(base->internalContext()->childContexts().count(), 0);
+    QCOMPARE(base->internalContext()->importedParentContexts().count(), 0);
+    QCOMPARE(base->internalContext()->localScopeIdentifier(), \
QualifiedIdentifier("Base")); +
+    // Final
+    ClassDeclaration *final = dynamic_cast<ClassDeclaration \
*>(top->localDeclarations().last()); +    QVERIFY(final);
+    QCOMPARE(final->internalContext()->childContexts().count(), 0);
+    QCOMPARE(final->internalContext()->importedParentContexts().count(), 1);
+    QCOMPARE(final->internalContext()->localScopeIdentifier(), \
QualifiedIdentifier("Final")); +    QCOMPARE(final->baseClassesSize(), 1u);
+    QCOMPARE(final->baseClasses()[0].baseClass, base->indexedType());
+}
+
+void TestDUChain::checkDeclarationsOnSubClass()
+{
+    /*
+     * The class Base defines a public instance method and a public class
+     * method. Then it defines a protected instance method and a private one.
+     * Finally, the class Final gets defined, and it subclasses the Base class.
+     */
+    QByteArray code("class Base; def foo; end; def self.selfish; end; ");
+    code += "protected; def protected_foo; end; private; def private_foo;";
+    code += "end; end; class Final < Base; end";
+    TopDUContext *top = parse(code, "checkDeclarationsOnSubClass");
+    DUChainReleaser releaser(top);
+    DUChainWriteLocker lock(DUChain::lock());
+
+    PENDING("Still hacking on the subclassing code");
+}
+
 //END: Declarations
 
 //BEGIN: Returning Values
@@ -788,8 +825,7 @@ void TestDUChain::include2()
     DUChainReleaser releaser(top);
     DUChainWriteLocker lock(DUChain::lock());
 
-    /* TODO: pending */
-    QVERIFY(true);
+    PENDING("Left as pending for some reason.");
 }
 
 void TestDUChain::extend1()
@@ -801,8 +837,7 @@ void TestDUChain::extend1()
     DUChainReleaser releaser(top);
     DUChainWriteLocker lock(DUChain::lock());
 
-    /* TODO: pending */
-    QVERIFY(true);
+    PENDING("Left as pending for some reason.");
 }
 
 //END: Include & Extend
diff --git a/duchain/tests/duchain.h b/duchain/tests/duchain.h
index fba1bb2..a0207d9 100644
--- a/duchain/tests/duchain.h
+++ b/duchain/tests/duchain.h
@@ -89,6 +89,7 @@ private slots:
     void hashAssignment();
 
     // Variable Length Container
+    // TODO: rename the VariableLengthContainer thingy.
     void assignFromArrayItem1();
     void assignFromArrayItem2();
     void assignFromHashItem();
@@ -98,6 +99,8 @@ private slots:
     void instanceClassMethodDeclaration();
     void accessPolicyMethodInClass();
     void accessPolicyMethodInModule();
+    void checkSubClassing();
+    void checkDeclarationsOnSubClass();
 
     // Returning values
     void multipleReturns();
diff --git a/duchain/tests/duchaintestbase.h b/duchain/tests/duchaintestbase.h
index c1d4e07..52f7f48 100644
--- a/duchain/tests/duchaintestbase.h
+++ b/duchain/tests/duchaintestbase.h
@@ -32,6 +32,11 @@
 #include <duchain/duchainexport.h>
 
 
+// Defined so tests can be marked as pending.
+#define DO_PRAGMA(x) _Pragma (#x)
+#define PENDING(x) DO_PRAGMA(message ("PENDING: " #x))
+
+
 namespace Ruby
 {
 
diff --git a/duchain/tests/uses.cpp b/duchain/tests/uses.cpp
index bceda75..56dfd2f 100644
--- a/duchain/tests/uses.cpp
+++ b/duchain/tests/uses.cpp
@@ -104,6 +104,20 @@ void TestUseBuilder::assignment()
     compareUses(dec, RangeInRevision(0, 17, 0, 18));
 }
 
+void TestUseBuilder::checkSubClassing()
+{
+    //               0          1        2         3
+    //               0123456789012345678901234567890123456789
+    QByteArray code("class Base; end; class Final < Base; end");
+    TopDUContext *top = parse(code, "checkSubClassing");
+    DUChainReleaser releaser(top);
+    DUChainWriteLocker lock(DUChain::lock());
+
+    Declaration *d = top->localDeclarations().first();
+    QCOMPARE(d->uses().count(), 1);
+    compareUses(d, RangeInRevision(0, 31, 0, 35));
+}
+
 } // End of namespace Ruby
 
 
diff --git a/duchain/tests/uses.h b/duchain/tests/uses.h
index 36f14e3..1521e31 100644
--- a/duchain/tests/uses.h
+++ b/duchain/tests/uses.h
@@ -56,6 +56,7 @@ private slots:
     void stringInterpolation();
     void alias();
     void assignment();
+    void checkSubClassing();
 };
 
 }


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

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