From a6b29094c0c013f68ac7d4005bc53c1fcf9472f4 Mon Sep 17 00:00:00 2001 From: James Strachan Date: Fri, 24 Feb 2012 15:15:34 +0000 Subject: [PATCH 01/21] fixed up little gremlin on the package page showing base methods --- .../jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt index 10c86370f36..256c2262d02 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageSummaryTemplate.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.model.KModel import org.jetbrains.kotlin.model.KPackage import org.jetbrains.kotlin.model.KClass import org.jetbrains.kotlin.model.extensionFunctions +import org.jetbrains.kotlin.model.inheritedExtensionFunctions class PackageSummaryTemplate(val model: KModel, pkg: KPackage) : PackageTemplateSupport(pkg) { override fun render() { @@ -263,7 +264,7 @@ Copyright © 2010-2012. All Rights Reserved. } protected fun printExtensionFunctions(): Unit { - val map = extensionFunctions(pkg.functions) + val map = inheritedExtensionFunctions(pkg.functions) if (! map.isEmpty()) { print(""" From 8faf1e62d3901c55e0bacefe467598370a75dceb Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Fri, 24 Feb 2012 18:01:10 +0200 Subject: [PATCH 02/21] fix for NPE --- .../src/org/jetbrains/jet/codegen/CallableMethod.java | 2 +- .../src/org/jetbrains/jet/codegen/ClosureCodegen.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index 34e6d8f4879..966b6cc1807 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -124,7 +124,7 @@ public class CallableMethod implements Callable { } public boolean isNeedsThis() { - return thisClass != null; + return thisClass != null && generateCalleeType == null; } public boolean isNeedsReceiver() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index d49fc46fc50..df5e3b9e66b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -91,6 +91,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { if (fd.getReceiverParameter().exists()) { result.setNeedsReceiver(fd); } + result.setNeedsThis(getInternalType(fd)); result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd))); return result; } @@ -337,6 +338,16 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { } } + public static ClassDescriptor getInternalType(FunctionDescriptor descriptor) { + final int paramCount = descriptor.getValueParameters().size(); + if (descriptor.getReceiverParameter().exists()) { + return JetStandardClasses.getReceiverFunction(paramCount); + } + else { + return JetStandardClasses.getFunction(paramCount); + } + } + private void appendType(SignatureWriter signatureWriter, JetType type, char variance) { signatureWriter.visitTypeArgument(variance); From 9523be50de24af87fed6cf9dd305d7de2d34b9f8 Mon Sep 17 00:00:00 2001 From: James Strachan Date: Fri, 24 Feb 2012 17:25:59 +0000 Subject: [PATCH 03/21] added not null helper methods for Set and Map --- stdlib/ktSrc/JavaUtil.kt | 8 ++++++-- stdlib/ktSrc/JavaUtilMap.kt | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/stdlib/ktSrc/JavaUtil.kt b/stdlib/ktSrc/JavaUtil.kt index 6d0c7ce2de8..4c54219cb2a 100644 --- a/stdlib/ktSrc/JavaUtil.kt +++ b/stdlib/ktSrc/JavaUtil.kt @@ -55,8 +55,12 @@ inline fun > List.sort(comparator: java.util.Co } /** Converts the nullable List into an empty List if its null */ -inline fun java.util.List?.notNull() : List - = if (this != null) this else Collections.EMPTY_LIST as List +inline fun java.util.List?.notNull() : java.util.List + = if (this != null) this else Collections.EMPTY_LIST as java.util.List + +/** Converts the nullable Set into an empty Set if its null */ +inline fun java.util.Set?.notNull() : java.util.Set + = if (this != null) this else Collections.EMPTY_SET as java.util.Set /** TODO figure out necessary variance/generics ninja stuff... :) diff --git a/stdlib/ktSrc/JavaUtilMap.kt b/stdlib/ktSrc/JavaUtilMap.kt index 7c02d1f65cc..985e89225b5 100644 --- a/stdlib/ktSrc/JavaUtilMap.kt +++ b/stdlib/ktSrc/JavaUtilMap.kt @@ -2,6 +2,7 @@ package std.util import java.util.Map as JMap import java.util.HashMap +import java.util.Collections // Temporary workaround: commenting out //import java.util.Map.Entry as JEntry @@ -19,6 +20,10 @@ val JMap<*,*>.empty : Boolean /** Provides [] access to maps */ fun JMap.set(key : K, value : V) = this.put(key, value) +/** Converts the nullable Map into an empty Map if its null */ +inline fun java.util.Map?.notNull() : java.util.Map + = if (this != null) this else Collections.EMPTY_MAP as java.util.Map + /** Returns the key of the entry */ // Temporary workaround: commenting out From 6bee965c51a805dcbe3942e0ccbc45023384cd32 Mon Sep 17 00:00:00 2001 From: James Strachan Date: Fri, 24 Feb 2012 17:26:25 +0000 Subject: [PATCH 04/21] added support for documenting extension properties too --- .../kotlin/doc/JavadocStyleHtmlDoclet.kt | 15 ++-- .../doc/templates/ClassExtensionsTemplate.kt | 5 +- .../org/jetbrains/kotlin/model/KotlinModel.kt | 78 ++++++++++++++----- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/JavadocStyleHtmlDoclet.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/JavadocStyleHtmlDoclet.kt index 3876303c175..d84e9352687 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/JavadocStyleHtmlDoclet.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/JavadocStyleHtmlDoclet.kt @@ -45,11 +45,16 @@ class JavadocStyleHtmlDoclet() : Doclet { fun generateExtensionFunctions(p: KPackage): Unit { val map = inheritedExtensionFunctions(p.functions) - for (e in map.entrySet()) { - val c = e?.getKey() - val functions = e?.getValue() - if (c != null && functions != null) { - run("${p.nameAsPath}/${c.simpleName}-extensions.html", ClassExtensionsTemplate(model, p, c, functions)) + val pmap = inheritedExtensionProperties(p.properties) + val classes = hashSet() + classes.addAll(map.keySet()) + classes.addAll(pmap.keySet()) + for (c in classes) { + if (c != null) { + val functions = map.get(c).notNull() + val properties = pmap.get(c).notNull() + run("${p.nameAsPath}/${c.simpleName}-extensions.html", + ClassExtensionsTemplate(model, p, c, functions, properties)) } } } diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassExtensionsTemplate.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassExtensionsTemplate.kt index 94a68f71d2d..33fe30a186f 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassExtensionsTemplate.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/ClassExtensionsTemplate.kt @@ -10,8 +10,10 @@ import org.jetbrains.kotlin.model.KPackage import org.jetbrains.kotlin.model.KClass import org.jetbrains.kotlin.model.KFunction import org.jetbrains.kotlin.model.KAnnotation +import org.jetbrains.kotlin.model.KProperty -class ClassExtensionsTemplate(m: KModel, p: KPackage, k: KClass, var functions: Collection) : ClassTemplate(m, p, k) { +class ClassExtensionsTemplate(m: KModel, p: KPackage, k: KClass, + val functions: Collection, val properties: Collection) : ClassTemplate(m, p, k) { override fun pageTitle(): String = "${klass.name} Extensions fom ${pkg.name} (${model.title})" @@ -31,6 +33,7 @@ from package ${link(pkg)}

""") + printPropertySummary(properties) printFunctionSummary(functions) printFunctionDetail(functions) println(""" diff --git a/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt b/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt index 2ac6814b9fb..82f75520ab0 100644 --- a/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt +++ b/kdoc/src/main/kotlin/org/jetbrains/kotlin/model/KotlinModel.kt @@ -64,15 +64,55 @@ fun inheritedExtensionFunctions(functions: Collection): Map): Map> { + val map = extensionProperties(properties) + // for each class, lets walk its base classes and add any other extension properties from base classes + val classes = map.keySet().toList() + val answer = TreeMap>() + for (c in map.keySet()) { + val allProperties = map.get(c).notNull().toSortedSet() + answer.put(c, allProperties) + val des = c.descendants() + for (b in des) { + val list = map.get(b) + if (list != null) { + if (allProperties != null) { + for (f in list) { + if (f != null) { + // add the proeprties from the base class if we don't have a matching method + if (!allProperties.any{ it.name == f.name}) { + allProperties.add(f) + } + } + } + } + } + } + } + return answer +} + + // TODO for some reason the SortedMap causes kotlin to freak out a little :) fun extensionFunctions(functions: Collection): Map> { - //fun extensionFunctions(functions: Collection): SortedMap> { val map = TreeMap>() functions.filter{ it.extensionClass != null }.groupBy(map){ it.extensionClass.sure() } return map } -trait KClassOrPackage { +// TODO for some reason the SortedMap causes kotlin to freak out a little :) +fun extensionProperties(properties: Collection): Map> { + val map = TreeMap>() + properties.filter{ it.extensionClass != null }.groupBy(map){ it.extensionClass.sure() } + return map +} + +abstract class KClassOrPackage : KAnnotated() { + + public open val functions: SortedSet = TreeSet() + + public open val properties: SortedSet = TreeSet() } class KModel(var context: BindingContext, var title: String = "Documentation", var version: String = "TODO") { @@ -131,7 +171,7 @@ class KModel(var context: BindingContext, var title: String = "Documentation", v } if (created) { pkg.description = commentsFor(descriptor) - addFunctions(pkg, pkg.functions, descriptor.getMemberScope()) + addFunctions(pkg, descriptor.getMemberScope()) if (pkg.functions.notEmpty()) { pkg.local = true } @@ -139,23 +179,26 @@ class KModel(var context: BindingContext, var title: String = "Documentation", v return pkg; } - protected fun addFunctions(owner: KClassOrPackage, list: Collection, scope: JetScope): Unit { + protected fun addFunctions(owner: KClassOrPackage, scope: JetScope): Unit { try { val descriptors = scope.getAllDescriptors() for (descriptor in descriptors) { if (descriptor is PropertyDescriptor) { - if (owner is KClass) { - val name = descriptor.getName() - val returnType = getClass(descriptor.getReturnType()) - if (returnType != null) { - val property = KProperty(owner, descriptor, name, returnType) - owner.properties.add(property) - } + val name = descriptor.getName() + val returnType = getClass(descriptor.getReturnType()) + if (returnType != null) { + val receiver = descriptor.getReceiverParameter() + val extensionClass = if (receiver is ExtensionReceiver) { + getClass(receiver.getType()) + } else null + + val property = KProperty(owner, descriptor, name, returnType, extensionClass) + owner.properties.add(property) } } else if (descriptor is CallableDescriptor) { val function = createFunction(owner, descriptor) if (function != null) { - list.add(function) + owner.functions.add(function) } } } @@ -271,8 +314,7 @@ abstract class KAnnotated { class KPackage(val model: KModel, val descriptor: NamespaceDescriptor, val name: String, var external: Boolean = false, - var functions: SortedSet = TreeSet(), - var local: Boolean = false) : KAnnotated(), Comparable, KClassOrPackage { + var local: Boolean = false) : KClassOrPackage(), Comparable { override fun compareTo(other: KPackage): Int = name.compareTo(other.name) @@ -296,7 +338,7 @@ class KPackage(val model: KModel, val descriptor: NamespaceDescriptor, klass.baseClasses.add(sc) } } - model.addFunctions(klass, klass.functions, classElement.getDefaultType().getMemberScope()) + model.addFunctions(klass, classElement.getDefaultType().getMemberScope()) } return klass } @@ -364,11 +406,9 @@ class KClass(val pkg: KPackage, val descriptor: ClassDescriptor, var annotations: List = arrayList(), var since: String = "", var authors: List = arrayList(), - var functions: SortedSet = TreeSet(), - var properties: SortedSet = TreeSet(), var baseClasses: List = arrayList(), var nestedClasses: List = arrayList(), - var sourceLine: Int = 2) : KAnnotated(), Comparable, KClassOrPackage { + var sourceLine: Int = 2) : KClassOrPackage(), Comparable { override fun compareTo(other: KClass): Int = name.compareTo(other.name) @@ -444,7 +484,7 @@ class KFunction(val owner: KClassOrPackage, val name: String, } class KProperty(val owner: KClassOrPackage, val descriptor: PropertyDescriptor, val name: String, - val returnType: KClass) : KAnnotated(), Comparable { + val returnType: KClass, val extensionClass: KClass?) : KAnnotated(), Comparable { override fun compareTo(other: KProperty): Int = name.compareTo(other.name) From 5841438134d38fb54bbe319399e6a334140b362c Mon Sep 17 00:00:00 2001 From: James Strachan Date: Fri, 24 Feb 2012 17:45:43 +0000 Subject: [PATCH 05/21] added a nicer subscript navigation of DOM kinda like jquery but without the $ :) --- stdlib/ktSrc/dom/Dom.kt | 30 ++++++++++++++++++++++-------- testlib/test/dom/DomBuilderTest.kt | 7 +++++-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/stdlib/ktSrc/dom/Dom.kt b/stdlib/ktSrc/dom/Dom.kt index 669678cf825..50751901975 100644 --- a/stdlib/ktSrc/dom/Dom.kt +++ b/stdlib/ktSrc/dom/Dom.kt @@ -74,22 +74,36 @@ set(value) { // Helper methods +/** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ +fun Document?.get(selector: String): List { + val root = this?.getDocumentElement() + return if (root != null) { + root.get(selector) + } else { + Collections.EMPTY_LIST as List + } +} + +/** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ +fun Element.get(selector: String): List { + if (selector.startsWith(".")) { + // TODO filter by CSS style class + } else if (selector.startsWith("#")) { + // TODO lookup by ID + } + // TODO assume its a vanilla element name + return this.getElementsByTagName(selector).toElementList() +} + +/** Returns the children of the element as a list */ inline fun Element?.children(): List { return this?.getChildNodes().toList() } -inline fun Element?.elementsByTagName(name: String?): List { - return this?.getElementsByTagName(name).toElementList() -} - inline fun Element?.elementsByTagNameNS(namespaceUri: String?, localName: String?): List { return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList() } -inline fun Document?.elementsByTagName(name: String?): List { - return this?.getElementsByTagName(name).toElementList() -} - inline fun Document?.elementsByTagNameNS(namespaceUri: String?, localName: String?): List { return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList() } diff --git a/testlib/test/dom/DomBuilderTest.kt b/testlib/test/dom/DomBuilderTest.kt index dea799d0dae..2548268e1d8 100644 --- a/testlib/test/dom/DomBuilderTest.kt +++ b/testlib/test/dom/DomBuilderTest.kt @@ -11,6 +11,10 @@ class DomBuilderTest() : TestSupport() { fun testBuildDocument() { var doc = createDocument() + assert { + doc["grandchild"].isEmpty() + } + doc.addElement("foo") { id = "id1" style = "bold" @@ -27,8 +31,7 @@ class DomBuilderTest() : TestSupport() { } println("builder document: ${doc.toXmlString()}") - - val grandChild = doc.elementsByTagName("grandChild").first + val grandChild = doc["grandChild"].first if (grandChild != null) { println("got element ${grandChild.toXmlString()} with text '${grandChild.text}`") assertEquals("Hello World!", grandChild.text) From 7f97f9710ee5fe04f338c3d5ea7870fb1288503b Mon Sep 17 00:00:00 2001 From: James Strachan Date: Fri, 24 Feb 2012 17:54:03 +0000 Subject: [PATCH 06/21] added attribute lookup helper method --- stdlib/ktSrc/dom/Dom.kt | 5 +++++ testlib/test/dom/DomBuilderTest.kt | 1 + 2 files changed, 6 insertions(+) diff --git a/stdlib/ktSrc/dom/Dom.kt b/stdlib/ktSrc/dom/Dom.kt index 50751901975..870da1c1b8e 100644 --- a/stdlib/ktSrc/dom/Dom.kt +++ b/stdlib/ktSrc/dom/Dom.kt @@ -95,6 +95,11 @@ fun Element.get(selector: String): List { return this.getElementsByTagName(selector).toElementList() } +/** Returns the attribute value or null if its not present */ +inline fun Element?.attribute(name: String): String? { + return this?.getAttribute(name) +} + /** Returns the children of the element as a list */ inline fun Element?.children(): List { return this?.getChildNodes().toList() diff --git a/testlib/test/dom/DomBuilderTest.kt b/testlib/test/dom/DomBuilderTest.kt index 2548268e1d8..1bce2f89534 100644 --- a/testlib/test/dom/DomBuilderTest.kt +++ b/testlib/test/dom/DomBuilderTest.kt @@ -35,6 +35,7 @@ class DomBuilderTest() : TestSupport() { if (grandChild != null) { println("got element ${grandChild.toXmlString()} with text '${grandChild.text}`") assertEquals("Hello World!", grandChild.text) + assertEquals("tiny", grandChild.attribute("class") ?: "") } else { fail("Not an Element $grandChild") } From 782ea7b1c322589bb8aca02c1b10bb67cef38b21 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Fri, 24 Feb 2012 19:29:21 +0400 Subject: [PATCH 07/21] getElement() and getRangeInElement() are expected to return non-nullable values --- .../jet/lang/parsing/JetParsing.java | 26 ++++++++---- .../jet/lang/psi/JetSimpleNameExpression.java | 18 ++++----- .../jet/lang/resolve/ImportsResolver.java | 40 ++++++++++--------- compiler/testData/psi/Imports_ERR.txt | 36 +++++++---------- .../references/JetArrayAccessReference.java | 3 +- .../references/JetPackageReference.java | 8 ++-- .../plugin/references/JetPsiReference.java | 8 +++- .../references/JetSimpleNameReference.java | 14 +++++-- 8 files changed, 87 insertions(+), 66 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java index b8aebb0e19f..a490e8e261d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -207,8 +207,12 @@ public class JetParsing extends AbstractJetParsing { advance(); // DOT reference = mark(); - expect(IDENTIFIER, "Qualified name must be a '.'-separated identifier list", TokenSet.create(AS_KEYWORD, DOT, SEMICOLON)); - reference.done(REFERENCE_EXPRESSION); + if (expect(IDENTIFIER, "Qualified name must be a '.'-separated identifier list", TokenSet.create(AS_KEYWORD, DOT, SEMICOLON))) { + reference.done(REFERENCE_EXPRESSION); + } + else { + reference.drop(); + } PsiBuilder.Marker precede = qualifiedName.precede(); qualifiedName.done(DOT_QUALIFIED_EXPRESSION); @@ -817,7 +821,7 @@ public class JetParsing extends AbstractJetParsing { errorAndAdvance("Expecting 'val' or 'var'"); } - boolean typeParametersDeclared = at(LT) ? parseTypeParameterList(TokenSet.create(IDENTIFIER, EQ, COLON, SEMICOLON)) : false; + boolean typeParametersDeclared = at(LT) && parseTypeParameterList(TokenSet.create(IDENTIFIER, EQ, COLON, SEMICOLON)); TokenSet propertyNameFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON, VAL_KEYWORD, VAR_KEYWORD, FUN_KEYWORD, CLASS_KEYWORD); @@ -1236,8 +1240,11 @@ public class JetParsing extends AbstractJetParsing { } PsiBuilder.Marker reference = mark(); - expect(IDENTIFIER, "Expecting type parameter name", TokenSet.orSet(TokenSet.create(COLON, COMMA), TYPE_REF_FIRST)); - reference.done(REFERENCE_EXPRESSION); + if (expect(IDENTIFIER, "Expecting type parameter name", TokenSet.orSet(TokenSet.create(COLON, COMMA), TYPE_REF_FIRST))) { + reference.done(REFERENCE_EXPRESSION); + } else { + reference.drop(); + } expect(COLON, "Expecting ':' before the upper bound", TYPE_REF_FIRST); @@ -1394,8 +1401,13 @@ public class JetParsing extends AbstractJetParsing { PsiBuilder.Marker reference = mark(); while (true) { - expect(IDENTIFIER, "Expecting type name", TokenSet.orSet(JetExpressionParsing.EXPRESSION_FIRST, JetExpressionParsing.EXPRESSION_FOLLOW)); - reference.done(REFERENCE_EXPRESSION); + if (expect(IDENTIFIER, "Expecting type name", TokenSet.orSet(JetExpressionParsing.EXPRESSION_FIRST, JetExpressionParsing.EXPRESSION_FOLLOW))) { + reference.done(REFERENCE_EXPRESSION); + } + else { + reference.drop(); + break; + } parseTypeArgumentList(-1); if (!at(DOT)) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java index bb45a802af5..d907762dd5e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetSimpleNameExpression.java @@ -81,27 +81,27 @@ public class JetSimpleNameExpression extends JetReferenceExpression { @Nullable @IfNotParsed public String getReferencedName() { - PsiElement referencedNameElement = getReferencedNameElement(); - if (referencedNameElement == null) { - return null; - } - String text = referencedNameElement.getNode().getText(); + String text = getReferencedNameElement().getNode().getText(); return text != null ? JetPsiUtil.unquoteIdentifierOrFieldReference(text) : null; } - @Nullable @IfNotParsed + @NotNull public PsiElement getReferencedNameElement() { PsiElement element = findChildByType(REFERENCE_TOKENS); if (element == null) { element = findChildByType(JetExpressionParsing.ALL_OPERATIONS); } - return element; + + if (element != null) { + return element; + } + + return this; } @Nullable @IfNotParsed public IElementType getReferencedNameElementType() { - PsiElement element = getReferencedNameElement(); - return element == null ? null : element.getNode().getElementType(); + return getReferencedNameElement().getNode().getElementType(); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java index 9218d720867..7d95fd82c2d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java @@ -194,27 +194,31 @@ public class ImportsResolver { } JetExpression selectorExpression = importedReference.getSelectorExpression(); - assert selectorExpression instanceof JetSimpleNameExpression; - JetSimpleNameExpression selector = (JetSimpleNameExpression) selectorExpression; - JetSimpleNameExpression lastReference = getLastReference(receiverExpression); - if (lastReference == null || !canImportMembersFrom(declarationDescriptors, lastReference)) { - return Collections.emptyList(); - } - Collection result; - for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { - if (declarationDescriptor instanceof NamespaceDescriptor) { - result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope(), true); - if (!result.isEmpty()) return result; + + if (selectorExpression instanceof JetSimpleNameExpression) { + JetSimpleNameExpression selector = (JetSimpleNameExpression) selectorExpression; + JetSimpleNameExpression lastReference = getLastReference(receiverExpression); + if (lastReference == null || !canImportMembersFrom(declarationDescriptors, lastReference)) { + return Collections.emptyList(); } - if (declarationDescriptor instanceof ClassDescriptor) { - result = lookupObjectMembers((ClassDescriptor) declarationDescriptor, selector); - if (!result.isEmpty()) return result; - } - if (declarationDescriptor instanceof VariableDescriptor) { - result = lookupVariableMembers((VariableDescriptor) declarationDescriptor, selector); - if (!result.isEmpty()) return result; + + Collection result; + for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { + if (declarationDescriptor instanceof NamespaceDescriptor) { + result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope(), true); + if (!result.isEmpty()) return result; + } + if (declarationDescriptor instanceof ClassDescriptor) { + result = lookupObjectMembers((ClassDescriptor) declarationDescriptor, selector); + if (!result.isEmpty()) return result; + } + if (declarationDescriptor instanceof VariableDescriptor) { + result = lookupVariableMembers((VariableDescriptor) declarationDescriptor, selector); + if (!result.isEmpty()) return result; + } } } + return Collections.emptyList(); } diff --git a/compiler/testData/psi/Imports_ERR.txt b/compiler/testData/psi/Imports_ERR.txt index 392807d8234..c17dba8f399 100644 --- a/compiler/testData/psi/Imports_ERR.txt +++ b/compiler/testData/psi/Imports_ERR.txt @@ -92,9 +92,8 @@ JetFile: Imports_ERR.jet PsiElement(IDENTIFIER)('foo') PsiElement(DOT)('.') PsiWhiteSpace(' ') - REFERENCE_EXPRESSION - PsiErrorElement:Expecting type name - PsiElement(as)('as') + PsiErrorElement:Expecting type name + PsiElement(as)('as') PsiWhiteSpace(' ') ANNOTATION_ENTRY CONSTRUCTOR_CALLEE @@ -122,9 +121,8 @@ JetFile: Imports_ERR.jet REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('bar') PsiElement(DOT)('.') - REFERENCE_EXPRESSION - PsiErrorElement:Expecting type name - PsiElement(MUL)('*') + PsiErrorElement:Expecting type name + PsiElement(MUL)('*') PsiWhiteSpace(' ') PsiErrorElement:Expecting namespace or top level declaration PsiElement(as)('as') @@ -156,9 +154,8 @@ JetFile: Imports_ERR.jet REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('bar') PsiElement(DOT)('.') - REFERENCE_EXPRESSION - PsiErrorElement:Expecting type name - PsiElement(MUL)('*') + PsiErrorElement:Expecting type name + PsiElement(MUL)('*') PsiWhiteSpace(' ') PsiErrorElement:Expecting namespace or top level declaration PsiElement(as)('as') @@ -182,10 +179,9 @@ JetFile: Imports_ERR.jet REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('foo') PsiElement(DOT)('.') - PsiWhiteSpace(' ') - REFERENCE_EXPRESSION - PsiErrorElement:Qualified name must be a '.'-separated identifier list - + PsiErrorElement:Qualified name must be a '.'-separated identifier list + + PsiWhiteSpace(' ') PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n') IMPORT_DIRECTIVE @@ -199,10 +195,9 @@ JetFile: Imports_ERR.jet REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('bar') PsiElement(DOT)('.') - PsiWhiteSpace(' ') - REFERENCE_EXPRESSION - PsiErrorElement:Qualified name must be a '.'-separated identifier list - + PsiErrorElement:Qualified name must be a '.'-separated identifier list + + PsiWhiteSpace(' ') PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n') IMPORT_DIRECTIVE @@ -212,10 +207,9 @@ JetFile: Imports_ERR.jet REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('foo') PsiElement(DOT)('.') - PsiWhiteSpace(' ') - REFERENCE_EXPRESSION - PsiErrorElement:Qualified name must be a '.'-separated identifier list - + PsiErrorElement:Qualified name must be a '.'-separated identifier list + + PsiWhiteSpace(' ') PsiElement(as)('as') PsiWhiteSpace(' ') PsiElement(IDENTIFIER)('bar') diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java index 419270f9913..d1e3611859c 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.plugin.references; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetArrayAccessExpression; import org.jetbrains.jet.lang.psi.JetContainerNode; @@ -44,7 +45,7 @@ class JetArrayAccessReference extends JetPsiReference implements MultiRangeRefer return indicesNode == null ? PsiReference.EMPTY_ARRAY : new PsiReference[] { new JetArrayAccessReference(expression) }; } - public JetArrayAccessReference(JetArrayAccessExpression expression) { + public JetArrayAccessReference(@NotNull JetArrayAccessExpression expression) { super(expression); this.expression = expression; } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPackageReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPackageReference.java index 87daff9efbc..530f837ba3b 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetPackageReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPackageReference.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.plugin.references; import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.compiler.TipsManager; import org.jetbrains.jet.lang.psi.JetFile; @@ -33,7 +32,7 @@ public class JetPackageReference extends JetPsiReference { private JetNamespaceHeader packageExpression; - public JetPackageReference(JetNamespaceHeader expression) { + public JetPackageReference(@NotNull JetNamespaceHeader expression) { super(expression); packageExpression = expression; } @@ -48,11 +47,10 @@ public class JetPackageReference extends JetPsiReference { bindingContext, TipsManager.getReferenceVariants(packageExpression, bindingContext)); } + @NotNull @Override public TextRange getRangeInElement() { - PsiElement element = getElement(); - if (element == null) return null; - return new TextRange(0, element.getTextLength()); + return new TextRange(0, getElement().getTextLength()); } @NotNull diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java index 0811c340481..0e3b3499088 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java @@ -22,6 +22,7 @@ import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.ResolveResult; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetReferenceExpression; @@ -36,12 +37,15 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_ import static org.jetbrains.jet.lang.resolve.BindingContext.DESCRIPTOR_TO_DECLARATION; public abstract class JetPsiReference implements PsiPolyVariantReference { + + @NotNull protected final JetReferenceExpression myExpression; - protected JetPsiReference(JetReferenceExpression expression) { + protected JetPsiReference(@NotNull JetReferenceExpression expression) { this.myExpression = expression; } + @NotNull @Override public PsiElement getElement() { return myExpression; @@ -69,6 +73,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { throw new IncorrectOperationException(); } + @NotNull @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { throw new IncorrectOperationException(); @@ -90,6 +95,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { return false; } + @Nullable protected PsiElement doResolve() { JetFile file = (JetFile) getElement().getContainingFile(); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index 96027693cf6..af542042930 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -33,23 +33,29 @@ import org.jetbrains.jet.plugin.completion.DescriptorLookupConverter; */ public class JetSimpleNameReference extends JetPsiReference { + @NotNull private final JetSimpleNameExpression myExpression; - public JetSimpleNameReference(JetSimpleNameExpression jetSimpleNameExpression) { + public JetSimpleNameReference(@NotNull JetSimpleNameExpression jetSimpleNameExpression) { super(jetSimpleNameExpression); myExpression = jetSimpleNameExpression; } + @NotNull @Override public PsiElement getElement() { return myExpression.getReferencedNameElement(); } + @NotNull + public JetSimpleNameExpression getExpression() { + return myExpression; + } + + @NotNull @Override public TextRange getRangeInElement() { - PsiElement element = getElement(); - if (element == null) return null; - return new TextRange(0, element.getTextLength()); + return new TextRange(0, getElement().getTextLength()); } @NotNull From 010090cd51ea7f8778c5b4fcfc7373ce035ad908 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Sat, 25 Feb 2012 00:04:56 +0400 Subject: [PATCH 08/21] Fixes couple exceptions --- .../handlers/JetFunctionInsertHandler.java | 2 +- .../formatter/JetFormattingModelBuilder.java | 2 ++ .../plugin/quickfix/ImportClassHelper.java | 11 +++++--- .../quickfix/ImportClassHelperTest.java | 26 +++++++++++++++++++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java index 637bbf68543..40612db4ebd 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java @@ -90,7 +90,7 @@ public class JetFunctionInsertHandler implements InsertHandler { // Insert () if it's not already exist document.insertString(endOffset, "()"); bothParentheses = true; - } else if (endOffset + 1 < documentText.length() && documentText.charAt(endOffset) == ')') { + } else if (endOffset + 1 < documentText.length() && documentText.charAt(endOffset + 1) == ')') { bothParentheses = true; } diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java index 6f45d821a4d..99a006df400 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java @@ -44,6 +44,8 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder { private static SpacingBuilder createSpacingBuilder(CodeStyleSettings settings) { return new SpacingBuilder(settings) + .after(NAMESPACE_HEADER).blankLines(1) + .before(IMPORT_DIRECTIVE).lineBreakInCode() .between(IMPORT_DIRECTIVE, CLASS).blankLines(1) .between(IMPORT_DIRECTIVE, FUN).blankLines(1) diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java index 59b552f7f8a..5c0cf8aaa05 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java @@ -89,9 +89,14 @@ public class ImportClassHelper { } else { List declarations = file.getDeclarations(); - assert !declarations.isEmpty(); - JetDeclaration firstDeclaration = declarations.iterator().next(); - firstDeclaration.getParent().addBefore(newDirective, firstDeclaration); + + if (!declarations.isEmpty()) { + JetDeclaration firstDeclaration = declarations.iterator().next(); + firstDeclaration.getParent().addBefore(newDirective, firstDeclaration); + } + else { + file.getNamespaceHeader().getParent().addAfter(newDirective, file.getNamespaceHeader()); + } } } diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java index ef2edbe353a..ed6184b6b43 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java @@ -21,6 +21,8 @@ import com.intellij.openapi.application.ApplicationManager; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.plugin.PluginTestCaseBase; +import java.io.IOException; + /** * @author Nikolay Krasko */ @@ -48,6 +50,30 @@ public class ImportClassHelperTest extends LightDaemonAnalyzerTestCase { checkResultByFile(getTestName(false) + ".kt.after"); } + public void testInsertInEmptyFile() throws IOException { + configureFromFileText("testInsertInEmptyFile.kt", ""); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + ImportClassHelper.addImportDirective("java.util.ArrayList", (JetFile) getFile()); + } + }); + + checkResultByText("import java.util.ArrayList"); + } + + public void testInsertInPackageOnlyFile() throws IOException { + configureFromFileText("testInsertInPackageOnlyFile.kt", "package some"); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + ImportClassHelper.addImportDirective("java.util.ArrayList", (JetFile) getFile()); + } + }); + + checkResultByText("package some\n\nimport java.util.ArrayList"); + } + @Override protected String getTestDataPath() { return PluginTestCaseBase.getTestDataPathBase() + "/quickfix/importHelper/"; From eb017d8a2e481cf7516a6a95f79740d47171619d Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 26 Feb 2012 09:38:07 +0200 Subject: [PATCH 09/21] fix for 1345 --- .../jet/codegen/FunctionCodegen.java | 8 + .../testData/codegen/regressions/kt1345.kt | 13 ++ .../jetbrains/jet/codegen/ClassGenTest.java | 4 + examples/src/guice-kotlin/guice-kotlin.iws | 196 +++++++++--------- 4 files changed, 126 insertions(+), 95 deletions(-) create mode 100644 compiler/testData/codegen/regressions/kt1345.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 579071d2de4..678bceaa671 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -431,6 +431,14 @@ public class FunctionCodegen { private static void checkOverride(CodegenContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) { Method method = state.getTypeMapper().mapSignature(functionDescriptor.getName(), functionDescriptor).getAsmMethod(); Method overriden = state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal()).getAsmMethod(); + + if(overriddenFunction.getModality() == Modality.ABSTRACT) { + Set overriddenFunctions = overriddenFunction.getOverriddenDescriptors(); + for (FunctionDescriptor of : overriddenFunctions) { + checkOverride(owner, state, v, jvmSignature, overriddenFunction, of.getOriginal()); + } + } + if(differentMethods(method, overriden)) { int flags = ACC_PUBLIC | ACC_BRIDGE; // TODO. diff --git a/compiler/testData/codegen/regressions/kt1345.kt b/compiler/testData/codegen/regressions/kt1345.kt new file mode 100644 index 00000000000..1888fa33dd8 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt1345.kt @@ -0,0 +1,13 @@ +trait Creator { + fun create() : T +} + +class Actor(val code: String = "OK") + +trait Factory : Creator + +class MyFactory() : Factory { + override fun create(): Actor = Actor() +} + +fun box() : String = MyFactory().create().code \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index b32ce49066d..c400b51caf5 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -303,4 +303,8 @@ public class ClassGenTest extends CodegenTestCase { blackBoxFile("regressions/kt633.kt"); } + + public void testKt1345() throws Exception { + blackBoxFile("regressions/kt1345.kt"); + } } diff --git a/examples/src/guice-kotlin/guice-kotlin.iws b/examples/src/guice-kotlin/guice-kotlin.iws index 7803ff96873..20a33e94f44 100644 --- a/examples/src/guice-kotlin/guice-kotlin.iws +++ b/examples/src/guice-kotlin/guice-kotlin.iws @@ -58,10 +58,10 @@ - + - + @@ -130,10 +130,10 @@ - + - + @@ -161,16 +161,15 @@ - @@ -203,16 +202,6 @@ - - - - - - - - @@ -235,6 +224,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -268,10 +299,10 @@ - - - + + + @@ -355,6 +386,24 @@ - + @@ -515,22 +546,23 @@ - + - - + + - + - + + @@ -597,105 +629,79 @@ - - - + - - - + - - - + - - - + - - - + - - - - - - - - - - + - - - + + + + + + - - - + - - - + - - - + - - - + - + + + + + + - - - - - - - - + From 230afd367fe6ae1f418725671e89302a6610e6bd Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Mon, 27 Feb 2012 00:59:27 +0400 Subject: [PATCH 10/21] bin/kotlin: better lookup for idea home, fix classpath --- bin/kotlin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/kotlin b/bin/kotlin index 4f03952c5b3..e456ffbe73d 100755 --- a/bin/kotlin +++ b/bin/kotlin @@ -8,7 +8,7 @@ die() { root=`cd $(dirname $0)/..; pwd` ideaRoot= -for d in /Applications/Nika-*.app; do +for d in $root/ideaSDK /Applications/Nika-*.app; do if [ -d "$d/lib" ]; then ideaRoot="$d" break @@ -18,7 +18,7 @@ done test -n "$ideaRoot" || die "Idea root not found" classpath="$root/out/production/cli" -classpath="$classpath:$root/out/production/backend:$root/out/production/frontend:$root/out/production/frontend.java:$root/out/production/jet.as.java.psi" +classpath="$classpath:$root/out/production/backend:$root/out/production/frontend:$root/out/production/frontend.java:$root/out/production/jet.as.java.psi:$root/out/production/util" classpath="$classpath:$root/out/production/stdlib" classpath="$classpath:$root/lib/*:$ideaRoot/lib/*:$ideaRoot/lib/rt/*" From 0bcdb9a95ed22299de936ea0a996c308241412ad Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 24 Feb 2012 19:05:34 +0400 Subject: [PATCH 11/21] Added smart Ctrl+W support in Kotlin plugin. #KT-1267 fixed #KT-1271 fixed --- idea/src/META-INF/plugin.xml | 3 + .../jet/plugin/JetCodeBlockSelectioner.java | 93 +++++++++++++++ .../plugin/JetStatementGroupSelectioner.java | 112 ++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 idea/src/org/jetbrains/jet/plugin/JetCodeBlockSelectioner.java create mode 100644 idea/src/org/jetbrains/jet/plugin/JetStatementGroupSelectioner.java diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 87a93df2976..a58f10797e2 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -120,6 +120,9 @@ + + + diff --git a/idea/src/org/jetbrains/jet/plugin/JetCodeBlockSelectioner.java b/idea/src/org/jetbrains/jet/plugin/JetCodeBlockSelectioner.java new file mode 100644 index 00000000000..0abdd99a22b --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/JetCodeBlockSelectioner.java @@ -0,0 +1,93 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jet.plugin; + +import com.intellij.codeInsight.editorActions.wordSelection.BasicSelectioner; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import org.jetbrains.jet.lang.psi.JetBlockExpression; +import org.jetbrains.jet.lang.psi.JetWhenExpression; +import org.jetbrains.jet.lexer.JetTokens; + +import java.util.ArrayList; +import java.util.List; + +/** + * Originally from IDEA platform: CodeBlockOrInitializerSelectioner + */ +public class JetCodeBlockSelectioner extends BasicSelectioner { + public boolean canSelect(PsiElement e) { + return e instanceof JetBlockExpression || e instanceof JetWhenExpression; + } + + public List select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) { + List result = new ArrayList(); + + ASTNode[] children = e.getNode().getChildren(null); + + int start = findOpeningBrace(children); + int end = findClosingBrace(children, start); + + result.add(e.getTextRange()); + result.addAll(expandToWholeLine(editorText, new TextRange(start, end))); + + return result; + } + + public static int findOpeningBrace(ASTNode[] children) { + int start = children[children.length - 1].getTextRange().getStartOffset(); + for (int i = 0; i < children.length; i++) { + PsiElement child = children[i].getPsi(); + + if (child instanceof LeafPsiElement) { + if (((LeafPsiElement) child).getElementType() == JetTokens.LBRACE) { + int j = i + 1; + + while (children[j] instanceof PsiWhiteSpace) { + j++; + } + + start = children[j].getTextRange().getStartOffset(); + } + } + } + return start; + } + + public static int findClosingBrace(ASTNode[] children, int startOffset) { + int end = children[children.length - 1].getTextRange().getEndOffset(); + for (int i = 0; i < children.length; i++) { + PsiElement child = children[i].getPsi(); + + if (child instanceof LeafPsiElement) { + if (((LeafPsiElement) child).getElementType() == JetTokens.RBRACE) { + int j = i - 1; + + while (children[j] instanceof PsiWhiteSpace && children[j].getTextRange().getStartOffset() > startOffset) { + j--; + } + + end = children[j].getTextRange().getEndOffset(); + } + } + } + return end; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/JetStatementGroupSelectioner.java b/idea/src/org/jetbrains/jet/plugin/JetStatementGroupSelectioner.java new file mode 100644 index 00000000000..40086378ab6 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/JetStatementGroupSelectioner.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin; + +import com.intellij.codeInsight.editorActions.wordSelection.BasicSelectioner; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.LineTokenizer; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import org.jetbrains.jet.lang.psi.JetBlockExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetWhenEntry; +import org.jetbrains.jet.lang.psi.JetWhenExpression; +import org.jetbrains.jet.lexer.JetTokens; + +import java.util.ArrayList; +import java.util.List; + +/** + * Originally from IDEA platform: StatementGroupSelectioner + */ +public class JetStatementGroupSelectioner extends BasicSelectioner { + public boolean canSelect(PsiElement e) { + return e instanceof JetExpression || e instanceof JetWhenEntry; + } + + public List select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) { + List result = new ArrayList(); + + PsiElement parent = e.getParent(); + + if (!(parent instanceof JetBlockExpression) && !(parent instanceof JetWhenExpression)) { + return result; + } + + + PsiElement startElement = e; + PsiElement endElement = e; + + + while (startElement.getPrevSibling() != null) { + PsiElement sibling = startElement.getPrevSibling(); + + if (sibling instanceof LeafPsiElement) { + if (((LeafPsiElement) sibling).getElementType() == JetTokens.LBRACE) { + break; + } + } + + if (sibling instanceof PsiWhiteSpace) { + PsiWhiteSpace whiteSpace = (PsiWhiteSpace) sibling; + + String[] strings = LineTokenizer.tokenize(whiteSpace.getText().toCharArray(), false); + if (strings.length > 2) { + break; + } + } + + startElement = sibling; + } + + while (startElement instanceof PsiWhiteSpace) { + startElement = startElement.getNextSibling(); + } + + while (endElement.getNextSibling() != null) { + PsiElement sibling = endElement.getNextSibling(); + + if (sibling instanceof LeafPsiElement) { + if (((LeafPsiElement) sibling).getElementType() == JetTokens.RBRACE) { + break; + } + } + + if (sibling instanceof PsiWhiteSpace) { + PsiWhiteSpace whiteSpace = (PsiWhiteSpace) sibling; + + String[] strings = LineTokenizer.tokenize(whiteSpace.getText().toCharArray(), false); + if (strings.length > 2) { + break; + } + } + + endElement = sibling; + } + + while (endElement instanceof PsiWhiteSpace) { + endElement = endElement.getPrevSibling(); + } + + result.addAll(expandToWholeLine(editorText, new TextRange(startElement.getTextRange().getStartOffset(), + endElement.getTextRange().getEndOffset()))); + + return result; + } +} From d6fa5b8921f340664f3c39947e48aec1de462091 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 24 Feb 2012 19:24:41 +0400 Subject: [PATCH 12/21] Added simple test for word selection. --- idea/testData/wordSelection/Statements.1.kt | 24 +++++++++ idea/testData/wordSelection/Statements.10.kt | 24 +++++++++ idea/testData/wordSelection/Statements.11.kt | 24 +++++++++ idea/testData/wordSelection/Statements.2.kt | 24 +++++++++ idea/testData/wordSelection/Statements.3.kt | 24 +++++++++ idea/testData/wordSelection/Statements.4.kt | 24 +++++++++ idea/testData/wordSelection/Statements.5.kt | 24 +++++++++ idea/testData/wordSelection/Statements.6.kt | 24 +++++++++ idea/testData/wordSelection/Statements.7.kt | 24 +++++++++ idea/testData/wordSelection/Statements.8.kt | 24 +++++++++ idea/testData/wordSelection/Statements.9.kt | 24 +++++++++ idea/testData/wordSelection/Statements.kt | 24 +++++++++ .../org/jetbrains/jet/WordSelectionTest.java | 52 +++++++++++++++++++ 13 files changed, 340 insertions(+) create mode 100644 idea/testData/wordSelection/Statements.1.kt create mode 100644 idea/testData/wordSelection/Statements.10.kt create mode 100644 idea/testData/wordSelection/Statements.11.kt create mode 100644 idea/testData/wordSelection/Statements.2.kt create mode 100644 idea/testData/wordSelection/Statements.3.kt create mode 100644 idea/testData/wordSelection/Statements.4.kt create mode 100644 idea/testData/wordSelection/Statements.5.kt create mode 100644 idea/testData/wordSelection/Statements.6.kt create mode 100644 idea/testData/wordSelection/Statements.7.kt create mode 100644 idea/testData/wordSelection/Statements.8.kt create mode 100644 idea/testData/wordSelection/Statements.9.kt create mode 100644 idea/testData/wordSelection/Statements.kt create mode 100644 idea/tests/org/jetbrains/jet/WordSelectionTest.java diff --git a/idea/testData/wordSelection/Statements.1.kt b/idea/testData/wordSelection/Statements.1.kt new file mode 100644 index 00000000000..08711ceaaab --- /dev/null +++ b/idea/testData/wordSelection/Statements.1.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.10.kt b/idea/testData/wordSelection/Statements.10.kt new file mode 100644 index 00000000000..29dab7c1e26 --- /dev/null +++ b/idea/testData/wordSelection/Statements.10.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.11.kt b/idea/testData/wordSelection/Statements.11.kt new file mode 100644 index 00000000000..bfd75290e19 --- /dev/null +++ b/idea/testData/wordSelection/Statements.11.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.2.kt b/idea/testData/wordSelection/Statements.2.kt new file mode 100644 index 00000000000..a443c992f6b --- /dev/null +++ b/idea/testData/wordSelection/Statements.2.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.3.kt b/idea/testData/wordSelection/Statements.3.kt new file mode 100644 index 00000000000..d15f26a343e --- /dev/null +++ b/idea/testData/wordSelection/Statements.3.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.4.kt b/idea/testData/wordSelection/Statements.4.kt new file mode 100644 index 00000000000..3318697e3a0 --- /dev/null +++ b/idea/testData/wordSelection/Statements.4.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.5.kt b/idea/testData/wordSelection/Statements.5.kt new file mode 100644 index 00000000000..432855942cd --- /dev/null +++ b/idea/testData/wordSelection/Statements.5.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.6.kt b/idea/testData/wordSelection/Statements.6.kt new file mode 100644 index 00000000000..d3128f07ee9 --- /dev/null +++ b/idea/testData/wordSelection/Statements.6.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.7.kt b/idea/testData/wordSelection/Statements.7.kt new file mode 100644 index 00000000000..f8d8d794f83 --- /dev/null +++ b/idea/testData/wordSelection/Statements.7.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.8.kt b/idea/testData/wordSelection/Statements.8.kt new file mode 100644 index 00000000000..24da15d38ea --- /dev/null +++ b/idea/testData/wordSelection/Statements.8.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.9.kt b/idea/testData/wordSelection/Statements.9.kt new file mode 100644 index 00000000000..0dfa15e2d0b --- /dev/null +++ b/idea/testData/wordSelection/Statements.9.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/Statements.kt b/idea/testData/wordSelection/Statements.kt new file mode 100644 index 00000000000..94031204d4e --- /dev/null +++ b/idea/testData/wordSelection/Statements.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/WordSelectionTest.java b/idea/tests/org/jetbrains/jet/WordSelectionTest.java new file mode 100644 index 00000000000..479f6a77606 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/WordSelectionTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet; + +import com.intellij.testFramework.fixtures.CodeInsightTestUtil; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import org.jetbrains.jet.plugin.PluginTestCaseBase; + +import java.io.File; + +/** + * @author Evgeny Gerashchenko + * @since 2/24/12 + */ +public class WordSelectionTest extends LightCodeInsightFixtureTestCase { + public void testStatements() { + doTest(11); + } + + private void doTest(int howMany) { + String testName = getTestName(false); + String[] afterFiles = new String[howMany]; + for (int i = 1; i <= howMany; i++) { + afterFiles[i - 1] = String.format("%s.%d.kt", testName, i); + } + + CodeInsightTestUtil.doWordSelectionTest(myFixture, testName + ".kt", afterFiles); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + final String testRelativeDir = "wordSelection"; + myFixture.setTestDataPath(new File(PluginTestCaseBase.getTestDataPathBase(), testRelativeDir).getPath() + + File.separator); + } + +} From e44754683bc90b5a7ea9f3c97de7dcb723d65314 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 27 Feb 2012 12:28:41 +0400 Subject: [PATCH 13/21] Added test for selection of when entries. --- idea/testData/wordSelection/WhenEntries.1.kt | 24 +++++++++++++++++++ idea/testData/wordSelection/WhenEntries.2.kt | 24 +++++++++++++++++++ idea/testData/wordSelection/WhenEntries.3.kt | 24 +++++++++++++++++++ idea/testData/wordSelection/WhenEntries.4.kt | 24 +++++++++++++++++++ idea/testData/wordSelection/WhenEntries.5.kt | 24 +++++++++++++++++++ idea/testData/wordSelection/WhenEntries.6.kt | 24 +++++++++++++++++++ idea/testData/wordSelection/WhenEntries.kt | 24 +++++++++++++++++++ .../org/jetbrains/jet/WordSelectionTest.java | 4 ++++ 8 files changed, 172 insertions(+) create mode 100644 idea/testData/wordSelection/WhenEntries.1.kt create mode 100644 idea/testData/wordSelection/WhenEntries.2.kt create mode 100644 idea/testData/wordSelection/WhenEntries.3.kt create mode 100644 idea/testData/wordSelection/WhenEntries.4.kt create mode 100644 idea/testData/wordSelection/WhenEntries.5.kt create mode 100644 idea/testData/wordSelection/WhenEntries.6.kt create mode 100644 idea/testData/wordSelection/WhenEntries.kt diff --git a/idea/testData/wordSelection/WhenEntries.1.kt b/idea/testData/wordSelection/WhenEntries.1.kt new file mode 100644 index 00000000000..60d8505c781 --- /dev/null +++ b/idea/testData/wordSelection/WhenEntries.1.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/WhenEntries.2.kt b/idea/testData/wordSelection/WhenEntries.2.kt new file mode 100644 index 00000000000..e99d62b920a --- /dev/null +++ b/idea/testData/wordSelection/WhenEntries.2.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/WhenEntries.3.kt b/idea/testData/wordSelection/WhenEntries.3.kt new file mode 100644 index 00000000000..058e866e65a --- /dev/null +++ b/idea/testData/wordSelection/WhenEntries.3.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/WhenEntries.4.kt b/idea/testData/wordSelection/WhenEntries.4.kt new file mode 100644 index 00000000000..919ce6e14e3 --- /dev/null +++ b/idea/testData/wordSelection/WhenEntries.4.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/WhenEntries.5.kt b/idea/testData/wordSelection/WhenEntries.5.kt new file mode 100644 index 00000000000..2b6d0e3f527 --- /dev/null +++ b/idea/testData/wordSelection/WhenEntries.5.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/WhenEntries.6.kt b/idea/testData/wordSelection/WhenEntries.6.kt new file mode 100644 index 00000000000..2e12b5424d1 --- /dev/null +++ b/idea/testData/wordSelection/WhenEntries.6.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/testData/wordSelection/WhenEntries.kt b/idea/testData/wordSelection/WhenEntries.kt new file mode 100644 index 00000000000..7c98f072bf2 --- /dev/null +++ b/idea/testData/wordSelection/WhenEntries.kt @@ -0,0 +1,24 @@ +fun main(args : Array) { + for (i in 1..100) { + when { + i%3 == 0 -> {print("Fizz"); continue;} + i%5 == 0 -> {print("Buzz"); continue;} + + (i%3 != 0 && i%5 != 0) -> {print(i); continue;} + else -> println() + } + } +} + +fun foo() : Unit { + println() { + println() + + + println() + println() + } + + println(array(1, 2, 3)) + println() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/WordSelectionTest.java b/idea/tests/org/jetbrains/jet/WordSelectionTest.java index 479f6a77606..7ffd03b477d 100644 --- a/idea/tests/org/jetbrains/jet/WordSelectionTest.java +++ b/idea/tests/org/jetbrains/jet/WordSelectionTest.java @@ -31,6 +31,10 @@ public class WordSelectionTest extends LightCodeInsightFixtureTestCase { doTest(11); } + public void testWhenEntries() { + doTest(6); + } + private void doTest(int howMany) { String testName = getTestName(false); String[] afterFiles = new String[howMany]; From f84d22f0407f7f13e6953db1922726f6a8b66a36 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 27 Feb 2012 12:36:30 +0400 Subject: [PATCH 14/21] Got rid of LinkedMultiMap, since it is added to IDEA platform. --- .../jet/lang/resolve/OverrideResolver.java | 2 +- .../jetbrains/jet/util/LinkedMultiMap.java | 39 ------------------- 2 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/jet/util/LinkedMultiMap.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index 21e63ace72a..41c3cbf53e6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.util.CommonSuppliers; -import org.jetbrains.jet.util.LinkedMultiMap; +import com.intellij.util.containers.LinkedMultiMap; import java.util.*; diff --git a/compiler/frontend/src/org/jetbrains/jet/util/LinkedMultiMap.java b/compiler/frontend/src/org/jetbrains/jet/util/LinkedMultiMap.java deleted file mode 100644 index aa74d5a5c90..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/util/LinkedMultiMap.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.util; - -import com.intellij.util.containers.MultiMap; - -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * @author Evgeny Gerashchenko - * TODO reuse LinkedMultiMap from IDEA platform when it will be available there - */ -public class LinkedMultiMap extends MultiMap { - @Override - protected Map> createMap() { - return new LinkedHashMap>(); - } - - @Override - protected Map> createMap(int i, float v) { - return new LinkedHashMap>(i, v); - } -} From 9e6a9e2dc7ff78808f1d5a78094a2609c3d58512 Mon Sep 17 00:00:00 2001 From: James Strachan Date: Mon, 27 Feb 2012 08:45:42 +0000 Subject: [PATCH 15/21] made testlib failures fail the build :) --- build.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml index a73d158bbee..ce282e77443 100644 --- a/build.xml +++ b/build.xml @@ -130,7 +130,7 @@ - + @@ -148,7 +148,7 @@ --> - + From dd36efd24d52f655e19b82162e1452dc602019dd Mon Sep 17 00:00:00 2001 From: James Strachan Date: Mon, 27 Feb 2012 08:49:47 +0000 Subject: [PATCH 16/21] support jquery style element / css style / id lookups of elements on a document/element - along with test cases --- stdlib/ktSrc/String.kt | 2 ++ stdlib/ktSrc/dom/Dom.kt | 49 ++++++++++++++++++++++++++---- testlib/test/dom/DomBuilderTest.kt | 47 ++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/stdlib/ktSrc/String.kt b/stdlib/ktSrc/String.kt index f0101efe61b..4398507a648 100644 --- a/stdlib/ktSrc/String.kt +++ b/stdlib/ktSrc/String.kt @@ -10,6 +10,8 @@ inline fun String.equalsIgnoreCase(anotherString: String) = (this as java.lang.S inline fun String.indexOf(str : String) = (this as java.lang.String).indexOf(str) +inline fun String.matches(regex : String): Boolean = (this as java.lang.String).matches(regex) + inline fun String.indexOf(str : String, fromIndex : Int) = (this as java.lang.String).indexOf(str, fromIndex) inline fun String.replace(oldChar: Char, newChar : Char) = (this as java.lang.String).replace(oldChar, newChar).sure() diff --git a/stdlib/ktSrc/dom/Dom.kt b/stdlib/ktSrc/dom/Dom.kt index 870da1c1b8e..92a03763049 100644 --- a/stdlib/ktSrc/dom/Dom.kt +++ b/stdlib/ktSrc/dom/Dom.kt @@ -56,6 +56,7 @@ var Element.id : String get() = this.getAttribute("id")?: "" set(value) { this.setAttribute("id", value) + this.setIdAttribute("id", true) } var Element.style : String @@ -73,12 +74,32 @@ set(value) { // Helper methods +fun Element.hasClass(cssClass: String): Boolean { + val c = this.cssClass + return if (c != null) + c.matches("""(^|\s+)$cssClass($|\s+)""") + else false +} /** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ fun Document?.get(selector: String): List { val root = this?.getDocumentElement() return if (root != null) { - root.get(selector) + if (selector == "*") { + elements + } else if (selector.startsWith(".")) { + elements.filter{ it.hasClass(selector.substring(1)) }.toList() + } else if (selector.startsWith("#")) { + val id = selector.substring(1) + val element = this?.getElementById(id) + return if (element != null) + Collections.singletonList(element).sure() as List + else + Collections.EMPTY_LIST.sure() as List + } else { + // assume its a vanilla element name + this?.getElementsByTagName(selector).toElementList() + } } else { Collections.EMPTY_LIST as List } @@ -86,13 +107,20 @@ fun Document?.get(selector: String): List { /** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ fun Element.get(selector: String): List { - if (selector.startsWith(".")) { - // TODO filter by CSS style class + return if (selector == "*") { + elements + } else if (selector.startsWith(".")) { + elements.filter{ it.hasClass(selector.substring(1)) }.toList() } else if (selector.startsWith("#")) { - // TODO lookup by ID + val element = this.getOwnerDocument()?.getElementById(selector.substring(1)) + return if (element != null) + Collections.singletonList(element).sure() as List + else + Collections.EMPTY_LIST.sure() as List + } else { + // assume its a vanilla element name + this.getElementsByTagName(selector).toElementList() } - // TODO assume its a vanilla element name - return this.getElementsByTagName(selector).toElementList() } /** Returns the attribute value or null if its not present */ @@ -105,6 +133,13 @@ inline fun Element?.children(): List { return this?.getChildNodes().toList() } +val Document?.elements : List +get() = this?.getElementsByTagName("*").toElementList() + +val Element?.elements : List +get() = this?.getElementsByTagName("*").toElementList() + + inline fun Element?.elementsByTagNameNS(namespaceUri: String?, localName: String?): List { return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList() } @@ -188,6 +223,8 @@ class ElementListAsList(val nodeList: NodeList): AbstractList() { override fun size(): Int = nodeList.getLength() } + + // Syntax sugar inline fun Node.plus(child: Node?): Node { diff --git a/testlib/test/dom/DomBuilderTest.kt b/testlib/test/dom/DomBuilderTest.kt index 1bce2f89534..d1045df18f6 100644 --- a/testlib/test/dom/DomBuilderTest.kt +++ b/testlib/test/dom/DomBuilderTest.kt @@ -20,8 +20,10 @@ class DomBuilderTest() : TestSupport() { style = "bold" cssClass = "bar" addElement("child") { + id = "id2" cssClass = "another" addElement("grandChild") { + id = "id3" cssClass = "tiny" addText("Hello World!") // TODO support neater syntax sugar for adding text? @@ -31,6 +33,51 @@ class DomBuilderTest() : TestSupport() { } println("builder document: ${doc.toXmlString()}") + + // test css selections on document + assertEquals(0, doc[".doesNotExist"].size()) + assertEquals(1, doc[".another"].size()) + assertEquals(1, doc[".tiny"].size()) + assertEquals(1, doc[".bar"].size()) + + // element tag selections + assertEquals(0, doc["doesNotExist"].size()) + assertEquals(1, doc["foo"].size()) + assertEquals(1, doc["child"].size()) + assertEquals(1, doc["grandChild"].size()) + + // id selections + assertEquals(1, doc["#id1"].size()) + assertEquals(1, doc["#id2"].size()) + assertEquals(1, doc["#id3"].size()) + + val root = doc.rootElement + if (root != null) { + assert { + root.hasClass("bar") + } + + // test css selections on element + assertEquals(0, root[".doesNotExist"].size()) + assertEquals(1, root[".another"].size()) + assertEquals(1, root[".tiny"].size()) + assertEquals(0, root[".bar"].size()) + + // element tag selections + assertEquals(0, root["doesNotExist"].size()) + assertEquals(0, root["foo"].size()) + assertEquals(1, root["child"].size()) + assertEquals(1, root["grandChild"].size()) + + // id selections + assertEquals(1, root["#id1"].size()) + assertEquals(1, root["#id2"].size()) + assertEquals(1, root["#id3"].size()) + } else { + fail("No root!") + } + + val grandChild = doc["grandChild"].first if (grandChild != null) { println("got element ${grandChild.toXmlString()} with text '${grandChild.text}`") From cefd9d5ca21666800f1a885e15ad80496f212e19 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 27 Feb 2012 12:57:55 +0400 Subject: [PATCH 17/21] KT-627 Drop Predicate expression --- .../src/org/jetbrains/jet/JetNodeTypes.java | 2 +- .../lang/parsing/JetExpressionParsing.java | 14 +++++----- .../tests/QualifiedExpressions.jet | 2 +- compiler/testData/psi/PredicateExpression.jet | 3 --- compiler/testData/psi/PredicateExpression.txt | 26 ------------------- .../org/jetbrains/jet/codegen/StdlibTest.java | 26 +++++++++---------- .../jet/types/JetTypeCheckerTest.java | 6 ++--- .../testData/checker/QualifiedExpressions.jet | 2 +- 8 files changed, 26 insertions(+), 55 deletions(-) delete mode 100644 compiler/testData/psi/PredicateExpression.jet delete mode 100644 compiler/testData/psi/PredicateExpression.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java index 8da5c9790c4..241072f3482 100644 --- a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java +++ b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java @@ -138,7 +138,7 @@ public interface JetNodeTypes { JetNodeType DOT_QUALIFIED_EXPRESSION = new JetNodeType("DOT_QUALIFIED_EXPRESSION", JetDotQualifiedExpression.class); JetNodeType HASH_QUALIFIED_EXPRESSION = new JetNodeType("HASH_QUALIFIED_EXPRESSION", JetHashQualifiedExpression.class); JetNodeType SAFE_ACCESS_EXPRESSION = new JetNodeType("SAFE_ACCESS_EXPRESSION", JetSafeQualifiedExpression.class); - JetNodeType PREDICATE_EXPRESSION = new JetNodeType("PREDICATE_EXPRESSION", JetPredicateExpression.class); +// JetNodeType PREDICATE_EXPRESSION = new JetNodeType("PREDICATE_EXPRESSION", JetPredicateExpression.class); JetNodeType OBJECT_LITERAL = new JetNodeType("OBJECT_LITERAL", JetObjectLiteralExpression.class); JetNodeType ROOT_NAMESPACE = new JetNodeType("ROOT_NAMESPACE", JetRootNamespaceExpression.class); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 55b62543698..bf5c7daa96f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -385,13 +385,13 @@ public class JetExpressionParsing extends AbstractJetParsing { expression.done(SAFE_ACCESS_EXPRESSION); } - else if (at(QUEST)) { - advance(); // QUEST - - parseCallExpression(); - - expression.done(PREDICATE_EXPRESSION); - } +// else if (at(QUEST)) { +// advance(); // QUEST +// +// parseCallExpression(); +// +// expression.done(PREDICATE_EXPRESSION); +// } // else if (at(HASH)) { // advance(); // HASH // diff --git a/compiler/testData/diagnostics/tests/QualifiedExpressions.jet b/compiler/testData/diagnostics/tests/QualifiedExpressions.jet index 3ce867b2def..3b8b899e892 100644 --- a/compiler/testData/diagnostics/tests/QualifiedExpressions.jet +++ b/compiler/testData/diagnostics/tests/QualifiedExpressions.jet @@ -7,7 +7,7 @@ fun test(s: String?) { val d: Int = s?.length ?: "empty" val e: String = s?.length ?: "empty" val f: Int = s?.length ?: b ?: 1 - val g: Int? = e? startsWith("s")?.length + val g: Boolean? = e.startsWith("s")//?.length } fun String.startsWith(s: String): Boolean = true \ No newline at end of file diff --git a/compiler/testData/psi/PredicateExpression.jet b/compiler/testData/psi/PredicateExpression.jet deleted file mode 100644 index 385f1838582..00000000000 --- a/compiler/testData/psi/PredicateExpression.jet +++ /dev/null @@ -1,3 +0,0 @@ -fun foo() { - a?f.foo -} \ No newline at end of file diff --git a/compiler/testData/psi/PredicateExpression.txt b/compiler/testData/psi/PredicateExpression.txt deleted file mode 100644 index c1cb9259feb..00000000000 --- a/compiler/testData/psi/PredicateExpression.txt +++ /dev/null @@ -1,26 +0,0 @@ -JetFile: PredicateExpression.jet - NAMESPACE_HEADER - - FUN - PsiElement(fun)('fun') - PsiWhiteSpace(' ') - PsiElement(IDENTIFIER)('foo') - VALUE_PARAMETER_LIST - PsiElement(LPAR)('(') - PsiElement(RPAR)(')') - PsiWhiteSpace(' ') - BLOCK - PsiElement(LBRACE)('{') - PsiWhiteSpace('\n ') - DOT_QUALIFIED_EXPRESSION - PREDICATE_EXPRESSION - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('a') - PsiElement(QUEST)('?') - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('f') - PsiElement(DOT)('.') - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('foo') - PsiWhiteSpace('\n') - PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java index b1386f62dd5..841c9fb52e4 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java @@ -88,19 +88,19 @@ public class StdlibTest extends CodegenTestCase { } //from NamespaceGenTest - public void testPredicateOperator() throws Exception { - loadText("fun foo(s: String) = s?startsWith(\"J\")"); - final Method main = generateFunction(); - try { - assertEquals("JetBrains", main.invoke(null, "JetBrains")); - assertNull(main.invoke(null, "IntelliJ")); - } catch (Throwable t) { -// System.out.println(generateToText()); - t.printStackTrace(); - throw t instanceof Exception ? (Exception)t : new RuntimeException(t); - } - } - +// public void testPredicateOperator() throws Exception { +// loadText("fun foo(s: String) = s?startsWith(\"J\")"); +// final Method main = generateFunction(); +// try { +// assertEquals("JetBrains", main.invoke(null, "JetBrains")); +// assertNull(main.invoke(null, "IntelliJ")); +// } catch (Throwable t) { +//// System.out.println(generateToText()); +// t.printStackTrace(); +// throw t instanceof Exception ? (Exception)t : new RuntimeException(t); +// } +// } +// public void testForInString() throws Exception { loadText("fun foo() : Int { var sum = 0\n" + " for(c in \"239\")\n" + diff --git a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 94fbe77f39c..89c41a74ca9 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -460,9 +460,9 @@ public class JetTypeCheckerTest extends JetLiteFixture { assertType("true && false", "Boolean"); assertType("true || false", "Boolean"); assertType("null ?: false", "Boolean"); - assertType("WithPredicate()?isValid()", "WithPredicate?"); - assertType("WithPredicate()?isValid(1)", "WithPredicate?"); - assertType("WithPredicate()?p", "WithPredicate?"); +// assertType("WithPredicate()?isValid()", "WithPredicate?"); +// assertType("WithPredicate()?isValid(1)", "WithPredicate?"); +// assertType("WithPredicate()?p", "WithPredicate?"); } public void testSupertypes() throws Exception { diff --git a/idea/testData/checker/QualifiedExpressions.jet b/idea/testData/checker/QualifiedExpressions.jet index 0527d08943d..d35193fc0ac 100644 --- a/idea/testData/checker/QualifiedExpressions.jet +++ b/idea/testData/checker/QualifiedExpressions.jet @@ -7,7 +7,7 @@ fun test(s: String?) { val d: Int = s?.length ?: "empty" val e: String = s?.length ?: "empty" val f: Int = s?.length ?: b ?: 1 - val g: Int? = e? startsWith("s")?.length + val g: Boolean? = e.startsWith("s")//?.length } fun String.startsWith(s: String): Boolean = true \ No newline at end of file From 2e0d00c45bc597a2059fab40fc1a0f6c66c3e70c Mon Sep 17 00:00:00 2001 From: James Strachan Date: Mon, 27 Feb 2012 09:11:51 +0000 Subject: [PATCH 18/21] fixed CI build :) --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index ce282e77443..68287f6f74f 100644 --- a/build.xml +++ b/build.xml @@ -130,7 +130,7 @@ - + From 963557f3c8ee131b58ea936e58c4d722fcbeaad4 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 27 Feb 2012 15:34:57 +0400 Subject: [PATCH 19/21] KT-1457 Subtyping doesn't work when type parameter is used indirectly in supertype declaration --- .../types/checker/TypeCheckingProcedure.java | 58 ++++++++++++++++++- .../diagnostics/tests/subtyping/kt-1457.jet | 8 +++ .../jet/types/JetTypeCheckerTest.java | 15 +++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/subtyping/kt-1457.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java index 765ac15aee2..c62d901ed96 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java @@ -87,9 +87,11 @@ public class TypeCheckingProcedure { } for (int i = 0; i < type1Arguments.size(); i++) { + TypeParameterDescriptor typeParameter1 = constructor1.getParameters().get(i); TypeProjection typeProjection1 = type1Arguments.get(i); + TypeParameterDescriptor typeParameter2 = constructor2.getParameters().get(i); TypeProjection typeProjection2 = type2Arguments.get(i); - if (typeProjection1.getProjectionKind() != typeProjection2.getProjectionKind()) { + if (getEffectiveProjectionKind(typeParameter1, typeProjection1) != getEffectiveProjectionKind(typeParameter2, typeProjection2)) { return false; } @@ -100,6 +102,58 @@ public class TypeCheckingProcedure { return true; } + private enum EnrichedProjectionKind { + IN, OUT, INV, STAR; + + @NotNull + public static EnrichedProjectionKind fromVariance(@NotNull Variance variance) { + switch (variance) { + case INVARIANT: + return INV; + case IN_VARIANCE: + return IN; + case OUT_VARIANCE: + return OUT; + } + throw new IllegalStateException("Unknown variance"); + } + } + + // If class C then C and C mean the same + // out * out = out + // out * in = * + // out * inv = out + // + // in * out = * + // in * in = in + // in * inv = in + // + // inv * out = out + // inv * in = out + // inv * inv = inv + private EnrichedProjectionKind getEffectiveProjectionKind(@NotNull TypeParameterDescriptor typeParameter, @NotNull TypeProjection typeArgument) { + Variance a = typeParameter.getVariance(); + Variance b = typeArgument.getProjectionKind(); + + // If they are not both invariant, let's make b not invariant for sure + if (b == INVARIANT) { + Variance t = a; + a = b; + b = t; + } + + // Opposites yield STAR + if (a == IN_VARIANCE && b == OUT_VARIANCE) { + return EnrichedProjectionKind.STAR; + } + if (a == OUT_VARIANCE && b == IN_VARIANCE) { + return EnrichedProjectionKind.STAR; + } + + // If they are not opposite, return b, because b is either equal to a or b is in/out and a is inv + return EnrichedProjectionKind.fromVariance(b); + } + public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) { return true; @@ -127,7 +181,7 @@ public class TypeCheckingProcedure { List subArguments = subtype.getArguments(); List superArguments = supertype.getArguments(); List parameters = constructor.getParameters(); - for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { + for (int i = 0; i < parameters.size(); i++) { TypeParameterDescriptor parameter = parameters.get(i); diff --git a/compiler/testData/diagnostics/tests/subtyping/kt-1457.jet b/compiler/testData/diagnostics/tests/subtyping/kt-1457.jet new file mode 100644 index 00000000000..bcbf5ce0407 --- /dev/null +++ b/compiler/testData/diagnostics/tests/subtyping/kt-1457.jet @@ -0,0 +1,8 @@ +// +JDK +import java.util.ArrayList + +class MyListOfPairs : ArrayList<#(T, T)>() { } + +fun test() { + MyListOfPairs : ArrayList<#(Int, Int)> +} diff --git a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 89c41a74ca9..68acc9f10f6 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -471,6 +471,21 @@ public class JetTypeCheckerTest extends JetLiteFixture { assertSupertypes("Derived1_inT", "Derived_T", "Base_T", "Any", "Base_inT"); } + public void testEffectiveProjectionKinds() throws Exception { + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Tuple1", "Tuple1"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void assertSupertypes(String typeStr, String... supertypeStrs) { From 12f7d463ad7f0c6c5dac2f1fdb8339f1cb753a57 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 27 Feb 2012 16:53:58 +0400 Subject: [PATCH 20/21] Fixed compilation of example-vfs project. --- examples/example-vfs/src/Main.kt | 3 ++- examples/example-vfs/src/RefreshQueue.kt | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/example-vfs/src/Main.kt b/examples/example-vfs/src/Main.kt index 71c74c3b81f..374e4986c69 100644 --- a/examples/example-vfs/src/Main.kt +++ b/examples/example-vfs/src/Main.kt @@ -26,7 +26,8 @@ fun main(args : Array) { FileSystem.addVirtualFileListener{ event -> println(event) if (event is VirtualFileChangedEvent) { - println("new file size is ${event.file.size()}") + // FIXME explicit type casting to avoid overload ambiguity (KT-1461) + println("new file size is ${(event as VirtualFileChangedEvent).file.size()}") } } diff --git a/examples/example-vfs/src/RefreshQueue.kt b/examples/example-vfs/src/RefreshQueue.kt index 1ba33a0cad5..a92e60139fe 100644 --- a/examples/example-vfs/src/RefreshQueue.kt +++ b/examples/example-vfs/src/RefreshQueue.kt @@ -50,9 +50,12 @@ internal object RefreshQueue { /* Checks for changes in virtual file recursively, notifying listeners. */ private fun refreshFile(file : VirtualFile) { FileSystem.assertCanWrite() + val fileInfo = FileSystem.fileToInfo[file.path] + assert(fileInfo != null) + if (fileInfo == null) { + return + } if (file.isDirectory()) { - val fileToInfo = FileSystem.fileToInfo - val fileInfo = fileToInfo[file.path] val oldChildren = fileInfo.children val newChildren = file.children() @@ -69,9 +72,6 @@ internal object RefreshQueue { commonChildren.foreach{ refreshFile(it) } } else { - val fileInfo = FileSystem.fileToInfo[file.path] - assert(fileInfo != null) - val newModificationTime = file.modificationTime() if (fileInfo.lastModified != newModificationTime) { fileInfo.lastModified = newModificationTime From 4c70d341b1d70a3e85501d1037630d6262b36dff Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 27 Feb 2012 17:43:04 +0400 Subject: [PATCH 21/21] Added stdlib function withIndices() converting sequence (Iterable) to sequence of index-value pairs. #KT-1195 fixed --- stdlib/ktSrc/JavaIterablesSpecial.kt | 38 +++++++++++++++++++++++++++- testlib/test/ListTest.kt | 11 ++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/stdlib/ktSrc/JavaIterablesSpecial.kt b/stdlib/ktSrc/JavaIterablesSpecial.kt index 3a564fabeb8..e0b301f7e3a 100644 --- a/stdlib/ktSrc/JavaIterablesSpecial.kt +++ b/stdlib/ktSrc/JavaIterablesSpecial.kt @@ -1,9 +1,10 @@ package std.util -// Number of extension function for ava.lang.Iterable that shouldn't participate in auto generation +// Number of extension function for java.lang.Iterable that shouldn't participate in auto generation import java.util.Collection import java.util.List import java.util.AbstractList +import java.util.Iterator /** * Count the number of elements in collection. @@ -83,3 +84,38 @@ fun java.lang.Iterable.contains(item : T) : Boolean { return false } + +/** + * Convert collection of arbitrary elements to collection of + */ +fun java.lang.Iterable.withIndices() : java.lang.Iterable<#(Int, T)> { + return object : java.lang.Iterable<#(Int, T)> { + override fun iterator(): java.util.Iterator<#(Int, T)> { + // TODO explicit typecast as a workaround for KT-1457, should be removed when it is fixed + return NumberedIterator(this@withIndices.iterator().sure()) as java.util.Iterator<#(Int, T)> + } + } +} + +private class NumberedIterator(private val sourceIterator : java.util.Iterator) : java.util.Iterator<#(Int, TT)> { + private var nextIndex = 0 + + override fun remove() { + try { + sourceIterator.remove() + nextIndex--; + } catch (e : UnsupportedOperationException) { + throw e + } + } + + override fun hasNext(): Boolean { + return sourceIterator.hasNext(); + } + + override fun next(): #(Int, TT) { + val result = #(nextIndex, sourceIterator.next()) + nextIndex++ + return result + } +} \ No newline at end of file diff --git a/testlib/test/ListTest.kt b/testlib/test/ListTest.kt index e45177d4d91..8fb628735db 100644 --- a/testlib/test/ListTest.kt +++ b/testlib/test/ListTest.kt @@ -27,4 +27,15 @@ class ListTest() : TestSupport() { val t = data.last assertEquals("bar", t) } + + fun testWithIndices() { + val withIndices = data.withIndices() + var index = 0 + for (withIndex in withIndices) { + assertEquals(withIndex._1, index) + assertEquals(withIndex._2, data[index]) + index++ + } + assertEquals(data.size(), index) + } }