diff --git a/build.xml b/build.xml index da3a17c9402..7ea61a95155 100644 --- a/build.xml +++ b/build.xml @@ -151,6 +151,20 @@ + + + + + + + + + + + + + + diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index f5063500f7f..465692b5139 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -282,14 +282,16 @@ public class JavaDescriptorResolver { ResolverBinaryClassData classData = new ResolverBinaryClassData(); classDescriptorCache.put(psiClass.getQualifiedName(), classData); ClassKind kind = psiClass.isInterface() ? (psiClass.isAnnotationType() ? ClassKind.ANNOTATION_CLASS : ClassKind.TRAIT) : ClassKind.CLASS; - DeclarationDescriptor containingDeclaration = resolveParentDescriptor(psiClass); + ClassOrNamespaceDescriptor containingDeclaration = resolveParentDescriptor(psiClass); classData.classDescriptor = new MutableClassDescriptorLite(containingDeclaration, kind); classData.classDescriptor.setName(name); classData.classDescriptor.setAnnotations(resolveAnnotations(psiClass)); List supertypes = new ArrayList(); - TypeVariableResolverFromOuters outerTypeVariableByNameResolver = new TypeVariableResolverFromOuters(containingDeclaration); + TypeVariableResolver outerTypeVariableByNameResolver = TypeVariableResolvers.classTypeVariableResolver( + (ClassOrNamespaceDescriptor) classData.classDescriptor.getContainingDeclaration(), + "class " + psiClass.getQualifiedName()); classData.typeParameters = createUninitializedClassTypeParameters(psiClass, classData, outerTypeVariableByNameResolver); @@ -314,9 +316,11 @@ public class JavaDescriptorResolver { classData.classDescriptor.createTypeConstructor(); classData.classDescriptor.setScopeForMemberLookup(new JavaClassMembersScope(classData.classDescriptor, psiClass, semanticServices, false)); - initializeTypeParameters(classData.typeParameters, new TypeVariableResolverFromTypeDescriptors(new ArrayList(), outerTypeVariableByNameResolver)); + initializeTypeParameters(classData.typeParameters, classData.classDescriptor, "class " + psiClass.getQualifiedName()); - TypeVariableResolverFromTypeDescriptors resolverForTypeParameters = new TypeVariableResolverFromTypeDescriptors(classData.getTypeParameters(), null); + TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver( + classData.classDescriptor, + "class " + psiClass.getQualifiedName()); // TODO: ugly hack: tests crash if initializeTypeParameters called with class containing proper supertypes supertypes.addAll(getSupertypes(new PsiClassWrapper(psiClass), classData.classDescriptor, classData.getTypeParameters())); @@ -392,10 +396,10 @@ public class JavaDescriptorResolver { classData.classDescriptor, Collections.emptyList(), // TODO false); + String context = "constructor of class " + psiClass.getQualifiedName(); ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors(constructorDescriptor, constructor.getParameters(), - new TypeVariableResolverFromTypeDescriptors(classData.getTypeParameters(), null) // TODO: outer too - ); + TypeVariableResolvers.classTypeVariableResolver(classData.classDescriptor, context)); if (valueParameterDescriptors.receiverType != null) { throw new IllegalStateException(); } @@ -474,7 +478,7 @@ public class JavaDescriptorResolver { if (jetClassAnnotation.signature().length() > 0) { return resolveClassTypeParametersFromJetSignature( - jetClassAnnotation.signature(), psiClass, classData.classDescriptor, typeVariableResolver); + jetClassAnnotation.signature(), psiClass, classData.classDescriptor); } return makeUninitializedTypeParameters(classData.classDescriptor, psiClass.getTypeParameters()); @@ -578,11 +582,14 @@ public class JavaDescriptorResolver { private final TypeVariableResolver typeVariableResolver; - private JetSignatureTypeParametersVisitor(@NotNull TypeVariableResolver containerTypeVariableResolver, @NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameterListOwner psiOwner) { + private JetSignatureTypeParametersVisitor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameterListOwner psiOwner, @NotNull String context) { this.containingDeclaration = containingDeclaration; this.psiOwner = psiOwner; - this.typeVariableResolver = new TypeVariableResolverFromTypeDescriptors(previousTypeParameters, containerTypeVariableResolver); + this.typeVariableResolver = TypeVariableResolvers.typeVariableResolverFromTypeParameters( + previousTypeParameters, + containingDeclaration, + context); } private int formalTypeParameterIndex = 0; @@ -613,11 +620,12 @@ public class JavaDescriptorResolver { } /** - * @see #resolveMethodTypeParametersFromJetSignature(String, com.intellij.psi.PsiMethod, org.jetbrains.jet.lang.descriptors.DeclarationDescriptor, TypeVariableResolver) + * @see #resolveMethodTypeParametersFromJetSignature(String, com.intellij.psi.PsiMethod, org.jetbrains.jet.lang.descriptors.DeclarationDescriptor) */ - private List resolveClassTypeParametersFromJetSignature(String jetSignature, final PsiClass clazz, - final ClassDescriptor classDescriptor, final TypeVariableResolver outerClassTypeVariableResolver) { - JetSignatureTypeParametersVisitor jetSignatureTypeParametersVisitor = new JetSignatureTypeParametersVisitor(outerClassTypeVariableResolver, classDescriptor, clazz) { + private List resolveClassTypeParametersFromJetSignature(String jetSignature, + final PsiClass clazz, final ClassDescriptor classDescriptor) { + String context = "class " + clazz.getQualifiedName(); + JetSignatureTypeParametersVisitor jetSignatureTypeParametersVisitor = new JetSignatureTypeParametersVisitor(classDescriptor, clazz, context) { @Override public JetSignatureVisitor visitSuperclass() { // TODO @@ -634,7 +642,7 @@ public class JavaDescriptorResolver { return jetSignatureTypeParametersVisitor.r; } - private DeclarationDescriptor resolveParentDescriptor(PsiClass psiClass) { + private ClassOrNamespaceDescriptor resolveParentDescriptor(PsiClass psiClass) { PsiClass containingClass = psiClass.getContainingClass(); if (containingClass != null) { return resolveClass(containingClass); @@ -704,19 +712,21 @@ public class JavaDescriptorResolver { typeParameterDescriptor.setInitialized(); } - private void initializeTypeParameters(List typeParametersInitialization, TypeVariableResolver typeVariableByPsiResolver) { + private void initializeTypeParameters(List typeParametersInitialization, @NotNull DeclarationDescriptor typeParametersOwner, @NotNull String context) { List prevTypeParameters = new ArrayList(); for (TypeParameterDescriptorInitialization psiTypeParameter : typeParametersInitialization) { prevTypeParameters.add(psiTypeParameter.descriptor); - initializeTypeParameter(psiTypeParameter, new TypeVariableResolverFromTypeDescriptors(prevTypeParameters, typeVariableByPsiResolver)); + initializeTypeParameter(psiTypeParameter, TypeVariableResolvers.typeVariableResolverFromTypeParameters(prevTypeParameters, typeParametersOwner, context)); } } private Collection getSupertypes(PsiClassWrapper psiClass, ClassDescriptor classDescriptor, List typeParameters) { final List result = new ArrayList(); + String context = "class " + psiClass.getQualifiedName(); + if (psiClass.getJetClass().signature().length() > 0) { - final TypeVariableResolver typeVariableResolver = new TypeVariableResolverFromTypeDescriptors(typeParameters, null); + final TypeVariableResolver typeVariableResolver = TypeVariableResolvers.typeVariableResolverFromTypeParameters(typeParameters, classDescriptor, context); new JetSignatureReader(psiClass.getJetClass().signature()).accept(new JetSignatureExceptionsAdapter() { @Override @@ -743,8 +753,9 @@ public class JavaDescriptorResolver { } }); } else { - transformSupertypeList(result, psiClass.getPsiClass().getExtendsListTypes(), new TypeVariableResolverFromTypeDescriptors(typeParameters, null), classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS); - transformSupertypeList(result, psiClass.getPsiClass().getImplementsListTypes(), new TypeVariableResolverFromTypeDescriptors(typeParameters, null), classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS); + TypeVariableResolver typeVariableResolverForSupertypes = TypeVariableResolvers.typeVariableResolverFromTypeParameters(typeParameters, classDescriptor, context); + transformSupertypeList(result, psiClass.getPsiClass().getExtendsListTypes(), typeVariableResolverForSupertypes, classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS); + transformSupertypeList(result, psiClass.getPsiClass().getImplementsListTypes(), typeVariableResolverForSupertypes, classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS); } for (JetType supertype : result) { @@ -792,17 +803,27 @@ public class JavaDescriptorResolver { return resolveNamespace(psiPackage); } - public PsiClass findClass(String qualifiedName) { + @Nullable + public PsiClass findClass(@NotNull String qualifiedName) { PsiClass original = javaFacade.findClass(qualifiedName, javaSearchScope); PsiClass altClass = altClassFinder.findClass(qualifiedName); + PsiClass result = original; if (altClass != null) { if (altClass instanceof ClsClassImpl) { altClass.putUserData(ClsClassImpl.DELEGATE_KEY, original); } - return altClass; + result = altClass; } - return original; + + if (result != null) { + String actualQualifiedName = result.getQualifiedName(); + if (!actualQualifiedName.equals(qualifiedName)) { + throw new IllegalStateException("requested " + qualifiedName + ", got " + actualQualifiedName); + } + } + + return result; } /*package*/ PsiPackage findPackage(String qualifiedName) { @@ -978,7 +999,7 @@ public class JavaDescriptorResolver { } } - public Set resolveFieldGroupByName(@NotNull ClassOrNamespaceDescriptor owner, PsiClass psiClass, String fieldName, boolean staticMembers) { + public Set resolveFieldGroupByName(@NotNull ClassOrNamespaceDescriptor owner, @NotNull PsiClass psiClass, String fieldName, boolean staticMembers) { ResolverScopeData scopeData = getResolverScopeData(owner, new PsiClassWrapper(psiClass)); NamedMembers namedMembers = scopeData.namedMembersMap.get(fieldName); @@ -987,7 +1008,7 @@ public class JavaDescriptorResolver { } Set r = new HashSet(); - resolveNamedGroupProperties(owner, scopeData, staticMembers, namedMembers, fieldName); + resolveNamedGroupProperties(owner, scopeData, staticMembers, namedMembers, fieldName, "class or namespace " + psiClass.getQualifiedName()); r.addAll(namedMembers.propertyDescriptors); @@ -999,7 +1020,7 @@ public class JavaDescriptorResolver { } @NotNull - public Set resolveFieldGroup(@NotNull ClassOrNamespaceDescriptor owner, PsiClass psiClass, boolean staticMembers) { + public Set resolveFieldGroup(@NotNull ClassOrNamespaceDescriptor owner, @NotNull PsiClass psiClass, boolean staticMembers) { ResolverScopeData scopeData = getResolverScopeData(owner, new PsiClassWrapper(psiClass)); @@ -1013,7 +1034,7 @@ public class JavaDescriptorResolver { String propertyName = entry.getKey(); - resolveNamedGroupProperties(owner, scopeData, staticMembers, namedMembers, propertyName); + resolveNamedGroupProperties(owner, scopeData, staticMembers, namedMembers, propertyName, "class or namespace " + psiClass.getQualifiedName()); descriptors.addAll(namedMembers.propertyDescriptors); } @@ -1060,7 +1081,9 @@ public class JavaDescriptorResolver { private void resolveNamedGroupProperties( @NotNull ClassOrNamespaceDescriptor owner, @NotNull ResolverScopeData scopeData, - boolean staticMembers, NamedMembers namedMembers, String propertyName) { + boolean staticMembers, @NotNull NamedMembers namedMembers, @NotNull String propertyName, + @NotNull String context + ) { if (namedMembers.propertyDescriptors != null) { return; } @@ -1070,9 +1093,7 @@ public class JavaDescriptorResolver { return; } - final List classTypeParameterDescriptorInitialization = scopeData.getTypeParameters(); - - TypeVariableResolver typeVariableResolver = new TypeVariableResolverFromTypeDescriptors(scopeData.getTypeParameters(), null); + TypeVariableResolver typeVariableResolver = TypeVariableResolvers.classTypeVariableResolver(owner, context); class GroupingValue { PropertyAccessorData getter; @@ -1186,32 +1207,24 @@ public class JavaDescriptorResolver { propertyDescriptor.initialize(getterDescriptor, setterDescriptor); - List typeParametersInitialization = new ArrayList(0); + List typeParameters = new ArrayList(0); if (members.setter != null) { PsiMethodWrapper method = (PsiMethodWrapper) members.setter.getMember(); if (anyMember == members.setter) { - typeParametersInitialization = resolveMethodTypeParameters(method, setterDescriptor, typeVariableResolver); + typeParameters = resolveMethodTypeParameters(method, propertyDescriptor, typeVariableResolver); } } if (members.getter != null) { PsiMethodWrapper method = (PsiMethodWrapper) members.getter.getMember(); if (anyMember == members.getter) { - typeParametersInitialization = resolveMethodTypeParameters(method, getterDescriptor, typeVariableResolver); + typeParameters = resolveMethodTypeParameters(method, propertyDescriptor, typeVariableResolver); } } - List typeParameters = new ArrayList(); - for (TypeParameterDescriptor typeParameter : typeParametersInitialization) { - typeParameters.add(typeParameter); - } - - List typeParametersForReceiver = new ArrayList(); - typeParametersForReceiver.addAll(classTypeParameterDescriptorInitialization); - typeParametersForReceiver.addAll(typeParametersInitialization); - TypeVariableResolver typeVariableResolverForPropertyInternals = new TypeVariableResolverFromTypeDescriptors(typeParametersForReceiver, null); + TypeVariableResolver typeVariableResolverForPropertyInternals = TypeVariableResolvers.typeVariableResolverFromTypeParameters(typeParameters, propertyDescriptor, "property " + propertyName + " in " + context); JetType propertyType; if (anyMember.getType().getTypeString().length() > 0) { @@ -1438,11 +1451,13 @@ public class JavaDescriptorResolver { CallableMemberDescriptor.Kind.DECLARATION ); - final TypeVariableResolver typeVariableResolverForParameters = TypeVariableResolvers.classTypeVariableResolver(classDescriptor); + String context = "method " + method.getName() + " in class " + psiClass.getQualifiedName(); + + final TypeVariableResolver typeVariableResolverForParameters = TypeVariableResolvers.classTypeVariableResolver(classDescriptor, context); final List methodTypeParameters = resolveMethodTypeParameters(method, functionDescriptorImpl, typeVariableResolverForParameters); - TypeVariableResolver methodTypeVariableResolver = new TypeVariableResolverFromTypeDescriptors(methodTypeParameters, typeVariableResolverForParameters); + TypeVariableResolver methodTypeVariableResolver = TypeVariableResolvers.typeVariableResolverFromTypeParameters(methodTypeParameters, functionDescriptorImpl, context); ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors(functionDescriptorImpl, method.getParameters(), methodTypeVariableResolver); @@ -1544,12 +1559,13 @@ public class JavaDescriptorResolver { List typeParametersIntialization; if (method.getJetMethod().typeParameters().length() > 0) { typeParametersIntialization = resolveMethodTypeParametersFromJetSignature( - method.getJetMethod().typeParameters(), method.getPsiMethod(), functionDescriptor, classTypeVariableResolver); + method.getJetMethod().typeParameters(), method.getPsiMethod(), functionDescriptor); } else { typeParametersIntialization = makeUninitializedTypeParameters(functionDescriptor, method.getPsiMethod().getTypeParameters()); } - initializeTypeParameters(typeParametersIntialization, classTypeVariableResolver); + String context = "method " + method.getName() + " in class " + method.getPsiMethod().getContainingClass().getQualifiedName(); + initializeTypeParameters(typeParametersIntialization, functionDescriptor, context); List typeParameters = Lists.newArrayListWithCapacity(typeParametersIntialization.size()); @@ -1561,12 +1577,13 @@ public class JavaDescriptorResolver { } /** - * @see #resolveClassTypeParametersFromJetSignature(String, com.intellij.psi.PsiClass, org.jetbrains.jet.lang.descriptors.ClassDescriptor, TypeVariableResolver) + * @see #resolveClassTypeParametersFromJetSignature(String, com.intellij.psi.PsiClass, org.jetbrains.jet.lang.descriptors.ClassDescriptor) */ - private List resolveMethodTypeParametersFromJetSignature(String jetSignature, final PsiMethod method, - final DeclarationDescriptor functionDescriptor, final TypeVariableResolver classTypeVariableResolver) + private List resolveMethodTypeParametersFromJetSignature(String jetSignature, + final PsiMethod method, final DeclarationDescriptor functionDescriptor) { - JetSignatureTypeParametersVisitor jetSignatureTypeParametersVisitor = new JetSignatureTypeParametersVisitor(classTypeVariableResolver, functionDescriptor, method); + String context = "method " + method.getName() + " in class " + method.getContainingClass().getQualifiedName(); + JetSignatureTypeParametersVisitor jetSignatureTypeParametersVisitor = new JetSignatureTypeParametersVisitor(functionDescriptor, method, context); new JetSignatureReader(jetSignature).acceptFormalTypeParametersOnly(jetSignatureTypeParametersVisitor); return jetSignatureTypeParametersVisitor.r; } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java index 08623eb8827..6b2b982c666 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java @@ -83,7 +83,10 @@ public abstract class JetTypeJetSignatureReader extends JetSignatureExceptionsAd @Override public void visitClassType(String name, boolean nullable, boolean forceReal) { - String ourName = name.replace('/', '.'); + String ourName = name + .replace('/', '.') + .replace('$', '.') // TODO: not sure + ; this.classDescriptor = null; if (this.classDescriptor == null && !forceReal) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromOuters.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromOuters.java deleted file mode 100644 index c3d8a87a4a6..00000000000 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromOuters.java +++ /dev/null @@ -1,56 +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.lang.resolve.java; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; - -/** - * @author Stepan Koltsov - */ -public class TypeVariableResolverFromOuters implements TypeVariableResolver { - - @NotNull - private final DeclarationDescriptor outer; - - public TypeVariableResolverFromOuters(@NotNull DeclarationDescriptor outer) { - this.outer = outer; - } - - @NotNull - @Override - public TypeParameterDescriptor getTypeVariable(@NotNull String name) { - DeclarationDescriptor outer = this.outer; - for (;;) { - if (outer instanceof NamespaceDescriptor) { - throw new IllegalStateException("unresolve type parameter: " + name); - } else if (outer instanceof ClassDescriptor) { - for (TypeParameterDescriptor typeParameter : ((ClassDescriptor) outer).getTypeConstructor().getParameters()) { - if (typeParameter.getName().equals(name)) { - return typeParameter; - } - } - outer = outer.getContainingDeclaration(); - } else { - throw new IllegalStateException("unknown outer: " + outer.getClass().getName()); - } - } - } -} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java index 8c2713267d1..848a2e643bf 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolverFromTypeDescriptors.java @@ -18,6 +18,8 @@ package org.jetbrains.jet.lang.resolve.java; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import java.util.List; @@ -29,25 +31,52 @@ public class TypeVariableResolverFromTypeDescriptors implements TypeVariableReso @NotNull private final List typeParameters; - @Nullable - private final TypeVariableResolver parent; + @NotNull + private final DeclarationDescriptor typeParametersOwner; + @NotNull + private final String context; - public TypeVariableResolverFromTypeDescriptors(@NotNull List typeParameters, @Nullable TypeVariableResolver parent) { + public TypeVariableResolverFromTypeDescriptors( + @NotNull List typeParameters, + @NotNull DeclarationDescriptor owner, + @NotNull String context) { this.typeParameters = typeParameters; - this.parent = parent; + this.typeParametersOwner = owner; + this.context = context; + + for (TypeParameterDescriptor typeParameter : typeParameters) { + if (typeParameter.getContainingDeclaration() != owner) { + throw new IllegalStateException(); + } + } } @NotNull @Override public TypeParameterDescriptor getTypeVariable(@NotNull String name) { + return getTypeVariable(name, typeParameters, typeParametersOwner, context); + } + + @NotNull + private static TypeParameterDescriptor getTypeVariable( + @NotNull String name, + @NotNull List typeParameters, + @NotNull DeclarationDescriptor owner, + @NotNull String context) { for (TypeParameterDescriptor typeParameter : typeParameters) { if (typeParameter.getName().equals(name)) { return typeParameter; } } - if (parent != null) { - return parent.getTypeVariable(name); + + DeclarationDescriptor containingDeclaration = owner.getContainingDeclaration(); + if (containingDeclaration != null) { + return getTypeVariable( + name, + TypeVariableResolvers.getTypeParameterDescriptors((ClassOrNamespaceDescriptor) containingDeclaration), + containingDeclaration, + context); } - throw new RuntimeException("type parameter not found by name " + name); // TODO report properly + throw new RuntimeException("type parameter not found by name '" + name + "' in " + context); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java index 9c4c1232120..6efcac5a4fa 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/TypeVariableResolvers.java @@ -16,23 +16,41 @@ package org.jetbrains.jet.lang.resolve.java; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import java.util.ArrayList; +import java.util.List; /** * @author Stepan Koltsov */ public class TypeVariableResolvers { - public static TypeVariableResolver classTypeVariableResolver(ClassOrNamespaceDescriptor clazz) { + @NotNull + public static List getTypeParameterDescriptors(@NotNull ClassOrNamespaceDescriptor clazz) { if (clazz instanceof ClassDescriptor) { - return new TypeVariableResolverFromTypeDescriptors(((ClassDescriptor) clazz).getTypeConstructor().getParameters(), new TypeVariableResolverFromOuters(clazz.getContainingDeclaration())); + return ((ClassDescriptor) clazz).getTypeConstructor().getParameters(); } else { - return new TypeVariableResolverFromTypeDescriptors(new ArrayList(0), null); + return new ArrayList(0); } } + + @NotNull + public static TypeVariableResolver classTypeVariableResolver(@NotNull ClassOrNamespaceDescriptor clazz, @NotNull String context) { + return typeVariableResolverFromTypeParameters(getTypeParameterDescriptors(clazz), clazz, context); + } + + @NotNull + public static TypeVariableResolver typeVariableResolverFromTypeParameters( + @NotNull List typeParameters, @NotNull DeclarationDescriptor owner, @NotNull String context) { + + return new TypeVariableResolverFromTypeDescriptors(typeParameters, owner, context); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ModuleDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ModuleDescriptor.java index bcced8441e1..772367c602e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ModuleDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ModuleDescriptor.java @@ -25,7 +25,7 @@ import java.util.Collections; /** * @author abreslav */ -public class ModuleDescriptor extends DeclarationDescriptorImpl { +public class ModuleDescriptor extends DeclarationDescriptorImpl implements ClassOrNamespaceDescriptor { public ModuleDescriptor(String name) { super(null, Collections.emptyList(), name); } diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java index 99a006df400..ea0813686ec 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java @@ -50,6 +50,7 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder { .between(IMPORT_DIRECTIVE, CLASS).blankLines(1) .between(IMPORT_DIRECTIVE, FUN).blankLines(1) .between(IMPORT_DIRECTIVE, PROPERTY).blankLines(1) + .between(IMPORT_DIRECTIVE, OBJECT_DECLARATION).blankLines(1) .before(FUN).lineBreakInCode() .before(PROPERTY).lineBreakInCode() diff --git a/idea/testData/quickfix/importHelper/ImportBeforeObject.kt b/idea/testData/quickfix/importHelper/ImportBeforeObject.kt new file mode 100644 index 00000000000..9b9b1ae471c --- /dev/null +++ b/idea/testData/quickfix/importHelper/ImportBeforeObject.kt @@ -0,0 +1,2 @@ +object some { +} \ No newline at end of file diff --git a/idea/testData/quickfix/importHelper/ImportBeforeObject.kt.after b/idea/testData/quickfix/importHelper/ImportBeforeObject.kt.after new file mode 100644 index 00000000000..01206050f05 --- /dev/null +++ b/idea/testData/quickfix/importHelper/ImportBeforeObject.kt.after @@ -0,0 +1,4 @@ +import java.util.HashSet + +object some { +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java index ed6184b6b43..d381821129b 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java @@ -28,26 +28,19 @@ import java.io.IOException; */ public class ImportClassHelperTest extends LightDaemonAnalyzerTestCase { public void testDoNotImportIfGeneralExist() { - configureByFile(getTestName(false) + ".kt"); - ImportClassHelper.addImportDirective("jettesting.data.testFunction", (JetFile) getFile()); - checkResultByFile(getTestName(false) + ".kt.after"); + testImportInFile("jettesting.data.testFunction"); } public void testDoNotImportIfGeneralSpaceExist() { - configureByFile(getTestName(false) + ".kt"); - ImportClassHelper.addImportDirective("jettesting.data.testFunction", (JetFile) getFile()); - checkResultByFile(getTestName(false) + ".kt.after"); + testImportInFile("jettesting.data.testFunction"); } public void testNoDefaultImport() { - configureByFile(getTestName(false) + ".kt"); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - ImportClassHelper.addImportDirective("std.io.println", (JetFile) getFile()); - } - }); - checkResultByFile(getTestName(false) + ".kt.after"); + testImportInFile("std.io.println"); + } + + public void testImportBeforeObject() { + testImportInFile("java.util.HashSet"); } public void testInsertInEmptyFile() throws IOException { @@ -74,6 +67,17 @@ public class ImportClassHelperTest extends LightDaemonAnalyzerTestCase { checkResultByText("package some\n\nimport java.util.ArrayList"); } + public void testImportInFile(final String importString) { + configureByFile(getTestName(false) + ".kt"); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + ImportClassHelper.addImportDirective(importString, (JetFile) getFile()); + } + }); + checkResultByFile(getTestName(false) + ".kt.after"); + } + @Override protected String getTestDataPath() { return PluginTestCaseBase.getTestDataPathBase() + "/quickfix/importHelper/"; diff --git a/kunit/src/main/kotlin/Test.kt b/kunit/src/main/kotlin/Test.kt index 30fbd211eca..3789573874e 100644 --- a/kunit/src/main/kotlin/Test.kt +++ b/kunit/src/main/kotlin/Test.kt @@ -65,7 +65,7 @@ inline fun expect(expected: T, message: String, block: ()-> T) { } /** Asserts that given function block fails by throwing an exception */ -fun fails(block: ()-> Any): Exception? { +fun fails(block: ()-> Unit): Exception? { try { block() Assert.fail("Expected an exception to be thrown") @@ -77,7 +77,7 @@ fun fails(block: ()-> Any): Exception? { } /** Asserts that a block fails with a specific exception being thrown */ -fun failsWith(block: ()-> Any) { +fun failsWith(block: ()-> Unit) { try { block() Assert.fail("Expected an exception to be thrown") diff --git a/runtests/test/stdlib/testall/CollectionTestAllTest.java b/runtests/test/stdlib/testall/CollectionTestAllTest.java new file mode 100644 index 00000000000..367f346064e --- /dev/null +++ b/runtests/test/stdlib/testall/CollectionTestAllTest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2010-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 stdlib.testall; + +import junit.framework.TestSuite; +import test.collections.*; + +/** + */ +public class CollectionTestAllTest { + public static TestSuite suite() { + return new TestSuite(CollectionTest.class, MapTest.class); + } +} diff --git a/stdlib/ktSrc/Arrays.kt b/stdlib/ktSrc/Arrays.kt index d7213ad4a53..cf8889b2821 100644 --- a/stdlib/ktSrc/Arrays.kt +++ b/stdlib/ktSrc/Arrays.kt @@ -104,3 +104,5 @@ inline fun ByteArray.inputStream(offset: Int, length: Int) = ByteArrayInputStrea /** Returns true if the array is not empty */ inline fun Array.notEmpty() : Boolean = this.size > 0 +/** Returns true if the array is empty */ +inline fun Array.isEmpty() : Boolean = this.size == 0 diff --git a/stdlib/ktSrc/Filter.kt b/stdlib/ktSrc/Filter.kt index bf458ae0fb8..8c31626d436 100644 --- a/stdlib/ktSrc/Filter.kt +++ b/stdlib/ktSrc/Filter.kt @@ -8,17 +8,6 @@ Filters given iterator */ inline fun java.util.Iterator.filter(f: (T)-> Boolean) : java.util.Iterator = FilterIterator(this, f) -/* -Adds filtered elements in to given container -*/ -inline fun > java.lang.Iterable.filterTo(var container: U, filter: (T)->Boolean) : U { - for(element in this) { - if(filter(element)) - container.add(element) - } - return container -} - /* Create iterator filtering given java.lang.Iterable */ diff --git a/stdlib/ktSrc/JavaCollections.kt b/stdlib/ktSrc/JavaCollections.kt index bcd9f001b4a..673edbeec3f 100644 --- a/stdlib/ktSrc/JavaCollections.kt +++ b/stdlib/ktSrc/JavaCollections.kt @@ -2,16 +2,14 @@ package std.util import java.util.* -/** Returns a new collection containing the results of applying the given function to each element in this collection */ -inline fun java.util.Collection.map(result: Collection = ArrayList(this.size), transform : (T) -> R) : Collection { +/** Returns a new List containing the results of applying the given function to each element in this collection */ +inline fun java.util.Collection.map(transform : (T) -> R) : java.util.List { + return mapTo(java.util.ArrayList(this.size), transform) +} + +/** Transforms each element of this collection with the given function then adds the results to the given collection */ +inline fun > java.util.Collection.mapTo(result: C, transform : (T) -> R) : C { for (item in this) result.add(transform(item)) return result } - -/** Returns true if the collection is not empty */ -inline fun java.util.Collection.notEmpty() : Boolean = !this.isEmpty() - -/** Converts the nullable collection into an empty collection if its null */ -inline fun java.util.Collection?.notNull() : Collection - = if (this != null) this else Collections.EMPTY_LIST as Collection diff --git a/stdlib/ktSrc/JavaIterables.kt b/stdlib/ktSrc/JavaIterables.kt index 9a63529c57c..c8ac5b970ab 100644 --- a/stdlib/ktSrc/JavaIterables.kt +++ b/stdlib/ktSrc/JavaIterables.kt @@ -41,8 +41,11 @@ inline fun java.lang.Iterable.find(predicate: (T)-> Boolean) : T? { return null } -/** Returns a new collection containing all elements in this collection which match the given predicate */ -inline fun java.lang.Iterable.filter(result: Collection = ArrayList(), predicate: (T)-> Boolean) : Collection { +/** Returns a new List containing all elements in this collection which match the given predicate */ +inline fun java.lang.Iterable.filter(predicate: (T)-> Boolean) : Collection = filterTo(java.util.ArrayList(), predicate) + +/** Filters all elements in this collection which match the given predicate into the given result collection */ +inline fun > java.lang.Iterable.filterTo(result: C, predicate: (T)-> Boolean) : C { for (elem in this) { if (predicate(elem)) result.add(elem) @@ -51,7 +54,10 @@ inline fun java.lang.Iterable.filter(result: Collection = ArrayList } /** Returns a new collection containing all elements in this collection which do not match the given predicate */ -inline fun java.lang.Iterable.filterNot(result: Collection = ArrayList(), predicate: (T)-> Boolean) : Collection { +inline fun java.lang.Iterable.filterNot(predicate: (T)-> Boolean) : Collection = filterNotTo(ArrayList(), predicate) + +/** Returns a new collection containing all elements in this collection which do not match the given predicate */ +inline fun > java.lang.Iterable.filterNotTo(result: C, predicate: (T)-> Boolean) : C { for (elem in this) { if (!predicate(elem)) result.add(elem) diff --git a/stdlib/ktSrc/JavaUtil.kt b/stdlib/ktSrc/JavaUtil.kt index 4c54219cb2a..50006784026 100644 --- a/stdlib/ktSrc/JavaUtil.kt +++ b/stdlib/ktSrc/JavaUtil.kt @@ -96,4 +96,10 @@ val List.last : T? get() = this.tail +/** Returns true if the collection is not empty */ +inline fun java.util.Collection.notEmpty() : Boolean = !this.isEmpty() + +/** Converts the nullable collection into an empty collection if its null */ +inline fun java.util.Collection?.notNull() : Collection + = if (this != null) this else Collections.EMPTY_LIST as Collection diff --git a/stdlib/ktSrc/dom/Dom.kt b/stdlib/ktSrc/dom/Dom.kt index 92a03763049..29ac4efb210 100644 --- a/stdlib/ktSrc/dom/Dom.kt +++ b/stdlib/ktSrc/dom/Dom.kt @@ -65,22 +65,89 @@ set(value) { this.setAttribute("style", value) } -// TODO can we come up with a better name; 'class' is a reserved word? -var Element.cssClass : String +var Element.classes : String get() = this.getAttribute("class")?: "" set(value) { this.setAttribute("class", value) } +var Element.classSet : Set +get() { + val answer = LinkedHashSet() + val array = this.classes.split("""\s""") + for (s in array) { + if (s != null && s.size > 0) { + answer.add(s) + } + } + return answer +} +set(value) { + this.classes = value.join(" ") +} + // Helper methods + +/** Returns true if the element has the given CSS class style in its 'class' attribute */ fun Element.hasClass(cssClass: String): Boolean { - val c = this.cssClass + val c = this.classes return if (c != null) - c.matches("""(^|\s+)$cssClass($|\s+)""") + c.matches("""(^|.*\s+)$cssClass($|\s+.*)""") else false } +/** Adds the given CSS class to this element's 'class' attribute */ +fun Element.addClass(cssClass: String): Boolean { + val classSet = this.classSet + val answer = classSet.add(cssClass) + if (answer) { + this.classSet = classSet + } + return answer +} + +/** Removes the given CSS class to this element's 'class' attribute */ +fun Element.removeClass(cssClass: String): Boolean { + val classSet = this.classSet + val answer = classSet.remove(cssClass) + if (answer) { + this.classSet = classSet + } + return answer +} + +/** TODO this approach generates compiler errors... + +fun Element.addClass(varargs cssClasses: Array): Boolean { + val set = this.classSet + var answer = false + for (cs in cssClasses) { + if (set.add(cs)) { + answer = true + } + } + if (answer) { + this.classSet = classSet + } + return answer +} + +fun Element.removeClass(varargs cssClasses: Array): Boolean { + val set = this.classSet + var answer = false + for (cs in cssClasses) { + if (set.remove(cs)) { + answer = true + } + } + if (answer) { + this.classSet = classSet + } + return answer +} +*/ + /** 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() @@ -123,9 +190,9 @@ fun Element.get(selector: String): List { } } -/** Returns the attribute value or null if its not present */ -inline fun Element?.attribute(name: String): String? { - return this?.getAttribute(name) +/** Returns the attribute value or empty string if its not present */ +inline fun Element.attribute(name: String): String { + return this.getAttribute(name) ?: "" } /** Returns the children of the element as a list */ diff --git a/stdlib/ktSrc/generated/ArraysFromJavaCollections.kt b/stdlib/ktSrc/generated/ArraysFromJavaCollections.kt index 12db122013e..3b1f0c23224 100644 --- a/stdlib/ktSrc/generated/ArraysFromJavaCollections.kt +++ b/stdlib/ktSrc/generated/ArraysFromJavaCollections.kt @@ -3,8 +3,13 @@ package std import java.util.* -/** Returns a new collection containing the results of applying the given function to each element in this collection */ -inline fun Array.map(result: Collection = ArrayList(this.size), transform : (T) -> R) : Collection { +/** Returns a new List containing the results of applying the given function to each element in this collection */ +inline fun Array.map(transform : (T) -> R) : java.util.List { + return mapTo(java.util.ArrayList(this.size), transform) +} + +/** Transforms each element of this collection with the given function then adds the results to the given collection */ +inline fun > Array.mapTo(result: C, transform : (T) -> R) : C { for (item in this) result.add(transform(item)) return result diff --git a/stdlib/ktSrc/generated/ArraysFromJavaIterables.kt b/stdlib/ktSrc/generated/ArraysFromJavaIterables.kt index 9794644f7d7..05597f4094a 100644 --- a/stdlib/ktSrc/generated/ArraysFromJavaIterables.kt +++ b/stdlib/ktSrc/generated/ArraysFromJavaIterables.kt @@ -1,6 +1,8 @@ // NOTE this file is auto-generated from stdlib/ktSrc/JavaIterables.kt package std +import std.util.* + import java.util.* /** Returns true if any elements in the collection match the given predicate */ @@ -23,6 +25,16 @@ inline fun Array.all(predicate: (T)-> Boolean) : Boolean { return true } +/** Returns the number of items which match the given predicate */ +inline fun Array.count(predicate: (T)-> Boolean) : Int { + var answer = 0 + for (elem in this) { + if (predicate(elem)) + answer += 1 + } + return answer +} + /** Returns the first item in the collection which matches the given predicate or null if none matched */ inline fun Array.find(predicate: (T)-> Boolean) : T? { for (elem in this) { @@ -32,8 +44,11 @@ inline fun Array.find(predicate: (T)-> Boolean) : T? { return null } -/** Returns a new collection containing all elements in this collection which match the given predicate */ -inline fun Array.filter(result: Collection = ArrayList(), predicate: (T)-> Boolean) : Collection { +/** Returns a new List containing all elements in this collection which match the given predicate */ +inline fun Array.filter(predicate: (T)-> Boolean) : Collection = filterTo(java.util.ArrayList(), predicate) + +/** Filters all elements in this collection which match the given predicate into the given result collection */ +inline fun > Array.filterTo(result: C, predicate: (T)-> Boolean) : C { for (elem in this) { if (predicate(elem)) result.add(elem) @@ -42,7 +57,10 @@ inline fun Array.filter(result: Collection = ArrayList(), predicate } /** Returns a new collection containing all elements in this collection which do not match the given predicate */ -inline fun Array.filterNot(result: Collection = ArrayList(), predicate: (T)-> Boolean) : Collection { +inline fun Array.filterNot(predicate: (T)-> Boolean) : Collection = filterNotTo(ArrayList(), predicate) + +/** Returns a new collection containing all elements in this collection which do not match the given predicate */ +inline fun > Array.filterNotTo(result: C, predicate: (T)-> Boolean) : C { for (elem in this) { if (!predicate(elem)) result.add(elem) @@ -72,6 +90,42 @@ inline fun Array.foreach(operation: (element: T) -> Unit) { operation(elem) } +/** + * Folds all the values from from left to right with the initial value to perform the operation on sequential pairs of values + * + * For example to sum together all numeric values in a collection of numbers it would be + * {code}val total = numbers.fold(0){(a, b) -> a + b}{code} + */ +inline fun Array.fold(initial: T, operation: (it: T, it2: T) -> T): T { + var answer = initial + for (elem in this) { + answer = operation(answer, elem) + } + return answer +} + +/** + * Folds all the values from right to left with the initial value to perform the operation on sequential pairs of values + */ +inline fun Array.foldRight(initial: T, operation: (it: T, it2: T) -> T): T { + val reversed = this.reverse() + return reversed.fold(initial, operation) +} + +/** + * Iterates through the collection performing the transformation on each element and using the result + * as the key in a map to group elements by the result + */ +inline fun Array.groupBy(result: Map> = HashMap>(), toKey: (T)-> K) : Map> { + for (elem in this) { + val key = toKey(elem) + val list = result.getOrPut(key){ ArrayList() } + list.add(elem) + } + return result +} + + /** Creates a String from all the elements in the collection, using the seperator between them and using the given prefix and postfix if supplied */ inline fun Array.join(separator: String, prefix: String = "", postfix: String = "") : String { val buffer = StringBuilder(prefix) @@ -87,18 +141,33 @@ inline fun Array.join(separator: String, prefix: String = "", postfix: St return buffer.toString().sure() } +/** Returns a reversed List of this collection */ +inline fun Array.reverse() : List { + val answer = LinkedList() + for (elem in this) { + answer.addFirst(elem) + } + return answer +} + +/* Copies the collection into the given collection */ inline fun > Array.to(result: C) : C { for (elem in this) result.add(elem) return result } +/* Converts the collection into a LinkedList */ inline fun Array.toLinkedList() : LinkedList = this.to(LinkedList()) +/* Converts the collection into a List */ inline fun Array.toList() : List = this.to(ArrayList()) +/* Converts the collection into a Set */ inline fun Array.toSet() : Set = this.to(HashSet()) +/* Converts the collection into a SortedSet */ +inline fun Array.toSortedSet() : SortedSet = this.to(TreeSet()) /** TODO figure out necessary variance/generics ninja stuff... :) inline fun Array.toSortedList(transform: fun(T) : java.lang.Comparable<*>) : List { diff --git a/stdlib/ktSrc/generated/JavaUtilIterablesFromJavaCollections.kt b/stdlib/ktSrc/generated/JavaUtilIterablesFromJavaCollections.kt index e4592189fca..0900ca1de80 100644 --- a/stdlib/ktSrc/generated/JavaUtilIterablesFromJavaCollections.kt +++ b/stdlib/ktSrc/generated/JavaUtilIterablesFromJavaCollections.kt @@ -3,8 +3,13 @@ package std.util import java.util.* -/** Returns a new collection containing the results of applying the given function to each element in this collection */ -inline fun java.lang.Iterable.map(result: Collection = ArrayList(), transform : (T) -> R) : Collection { +/** Returns a new List containing the results of applying the given function to each element in this collection */ +inline fun java.lang.Iterable.map(transform : (T) -> R) : java.util.List { + return mapTo(java.util.ArrayList(), transform) +} + +/** Transforms each element of this collection with the given function then adds the results to the given collection */ +inline fun > java.lang.Iterable.mapTo(result: C, transform : (T) -> R) : C { for (item in this) result.add(transform(item)) return result diff --git a/stdlib/ktSrc/generated/StandardFromJavaCollections.kt b/stdlib/ktSrc/generated/StandardFromJavaCollections.kt index e94ec1d52d3..e79bfb9f5e1 100644 --- a/stdlib/ktSrc/generated/StandardFromJavaCollections.kt +++ b/stdlib/ktSrc/generated/StandardFromJavaCollections.kt @@ -3,8 +3,13 @@ package std import java.util.* -/** Returns a new collection containing the results of applying the given function to each element in this collection */ -inline fun Iterable.map(result: Collection = ArrayList(), transform : (T) -> R) : Collection { +/** Returns a new List containing the results of applying the given function to each element in this collection */ +inline fun Iterable.map(transform : (T) -> R) : java.util.List { + return mapTo(java.util.ArrayList(), transform) +} + +/** Transforms each element of this collection with the given function then adds the results to the given collection */ +inline fun > Iterable.mapTo(result: C, transform : (T) -> R) : C { for (item in this) result.add(transform(item)) return result diff --git a/stdlib/ktSrc/generated/StandardFromJavaIterables.kt b/stdlib/ktSrc/generated/StandardFromJavaIterables.kt index 00a566350ec..e2992f217cb 100644 --- a/stdlib/ktSrc/generated/StandardFromJavaIterables.kt +++ b/stdlib/ktSrc/generated/StandardFromJavaIterables.kt @@ -1,6 +1,8 @@ // NOTE this file is auto-generated from stdlib/ktSrc/JavaIterables.kt package std +import std.util.* + import java.util.* /** Returns true if any elements in the collection match the given predicate */ @@ -23,6 +25,16 @@ inline fun Iterable.all(predicate: (T)-> Boolean) : Boolean { return true } +/** Returns the number of items which match the given predicate */ +inline fun Iterable.count(predicate: (T)-> Boolean) : Int { + var answer = 0 + for (elem in this) { + if (predicate(elem)) + answer += 1 + } + return answer +} + /** Returns the first item in the collection which matches the given predicate or null if none matched */ inline fun Iterable.find(predicate: (T)-> Boolean) : T? { for (elem in this) { @@ -32,8 +44,11 @@ inline fun Iterable.find(predicate: (T)-> Boolean) : T? { return null } -/** Returns a new collection containing all elements in this collection which match the given predicate */ -inline fun Iterable.filter(result: Collection = ArrayList(), predicate: (T)-> Boolean) : Collection { +/** Returns a new List containing all elements in this collection which match the given predicate */ +inline fun Iterable.filter(predicate: (T)-> Boolean) : Collection = filterTo(java.util.ArrayList(), predicate) + +/** Filters all elements in this collection which match the given predicate into the given result collection */ +inline fun > Iterable.filterTo(result: C, predicate: (T)-> Boolean) : C { for (elem in this) { if (predicate(elem)) result.add(elem) @@ -42,7 +57,10 @@ inline fun Iterable.filter(result: Collection = ArrayList(), predic } /** Returns a new collection containing all elements in this collection which do not match the given predicate */ -inline fun Iterable.filterNot(result: Collection = ArrayList(), predicate: (T)-> Boolean) : Collection { +inline fun Iterable.filterNot(predicate: (T)-> Boolean) : Collection = filterNotTo(ArrayList(), predicate) + +/** Returns a new collection containing all elements in this collection which do not match the given predicate */ +inline fun > Iterable.filterNotTo(result: C, predicate: (T)-> Boolean) : C { for (elem in this) { if (!predicate(elem)) result.add(elem) @@ -72,6 +90,42 @@ inline fun Iterable.foreach(operation: (element: T) -> Unit) { operation(elem) } +/** + * Folds all the values from from left to right with the initial value to perform the operation on sequential pairs of values + * + * For example to sum together all numeric values in a collection of numbers it would be + * {code}val total = numbers.fold(0){(a, b) -> a + b}{code} + */ +inline fun Iterable.fold(initial: T, operation: (it: T, it2: T) -> T): T { + var answer = initial + for (elem in this) { + answer = operation(answer, elem) + } + return answer +} + +/** + * Folds all the values from right to left with the initial value to perform the operation on sequential pairs of values + */ +inline fun Iterable.foldRight(initial: T, operation: (it: T, it2: T) -> T): T { + val reversed = this.reverse() + return reversed.fold(initial, operation) +} + +/** + * Iterates through the collection performing the transformation on each element and using the result + * as the key in a map to group elements by the result + */ +inline fun Iterable.groupBy(result: Map> = HashMap>(), toKey: (T)-> K) : Map> { + for (elem in this) { + val key = toKey(elem) + val list = result.getOrPut(key){ ArrayList() } + list.add(elem) + } + return result +} + + /** Creates a String from all the elements in the collection, using the seperator between them and using the given prefix and postfix if supplied */ inline fun Iterable.join(separator: String, prefix: String = "", postfix: String = "") : String { val buffer = StringBuilder(prefix) @@ -87,18 +141,33 @@ inline fun Iterable.join(separator: String, prefix: String = "", postfix: return buffer.toString().sure() } +/** Returns a reversed List of this collection */ +inline fun Iterable.reverse() : List { + val answer = LinkedList() + for (elem in this) { + answer.addFirst(elem) + } + return answer +} + +/* Copies the collection into the given collection */ inline fun > Iterable.to(result: C) : C { for (elem in this) result.add(elem) return result } +/* Converts the collection into a LinkedList */ inline fun Iterable.toLinkedList() : LinkedList = this.to(LinkedList()) +/* Converts the collection into a List */ inline fun Iterable.toList() : List = this.to(ArrayList()) +/* Converts the collection into a Set */ inline fun Iterable.toSet() : Set = this.to(HashSet()) +/* Converts the collection into a SortedSet */ +inline fun Iterable.toSortedSet() : SortedSet = this.to(TreeSet()) /** TODO figure out necessary variance/generics ninja stuff... :) inline fun Iterable.toSortedList(transform: fun(T) : java.lang.Comparable<*>) : List { diff --git a/testlib/test/CollectionTest.kt b/testlib/test/CollectionTest.kt index 5db34d064b1..d6427678b56 100644 --- a/testlib/test/CollectionTest.kt +++ b/testlib/test/CollectionTest.kt @@ -67,7 +67,7 @@ class CollectionTest() : TestSupport() { fun testFilterIntoLinkedList() { // TODO would be nice to avoid the - val foo = data.filter(linkedList()){it.startsWith("f")} + val foo = data.filterTo(linkedList()){it.startsWith("f")} assertTrue { foo.all{it.startsWith("f")} @@ -82,7 +82,7 @@ class CollectionTest() : TestSupport() { fun testFilterIntoSortedSet() { // TODO would be nice to avoid the - val foo = data.filter(hashSet()){it.startsWith("f")} + val foo = data.filterTo(hashSet()){it.startsWith("f")} assertTrue { foo.all{it.startsWith("f")} @@ -246,6 +246,29 @@ class CollectionTest() : TestSupport() { fails { hashSet().last() } } + fun testSubscript() { + val list = arrayList("foo", "bar") + assertEquals("foo", list[0]) + assertEquals("bar", list[1]) + + // lists throw an exception if out of range + fails { + assertEquals(null, list[2]) + } + + // lets try update the list + list[0] = "new" + list[1] = "thing" + + // lists don't allow you to set past the end of the list + fails { + list[2] = "works" + } + + list.add("works") + assertEquals(arrayList("new", "thing", "works"), list) + } + fun testIndices() { val indices = data.indices assertEquals(0, indices.start) diff --git a/testlib/test/GenerateStandardLib.kt b/testlib/test/GenerateStandardLib.kt index 0907fd1bd77..347f99bc0e9 100644 --- a/testlib/test/GenerateStandardLib.kt +++ b/testlib/test/GenerateStandardLib.kt @@ -58,11 +58,11 @@ fun main(args: Array) { // JavaIterables - Generic iterable stuff - generateFile(File(outDir, "ArraysFromJavaIterables.kt"), "package std", File(srcDir, "JavaIterables.kt")) { + generateFile(File(outDir, "ArraysFromJavaIterables.kt"), "package std\n\nimport std.util.*", File(srcDir, "JavaIterables.kt")) { it.replaceAll("java.lang.Iterable", "Array") } - generateFile(File(outDir, "StandardFromJavaIterables.kt"), "package std", File(srcDir, "JavaIterables.kt")) { + generateFile(File(outDir, "StandardFromJavaIterables.kt"), "package std\n\nimport std.util.*", File(srcDir, "JavaIterables.kt")) { it.replaceAll("java.lang.Iterable", "Iterable") } diff --git a/testlib/test/MapTest.kt b/testlib/test/MapTest.kt index aa5894a8970..0bcb78af912 100644 --- a/testlib/test/MapTest.kt +++ b/testlib/test/MapTest.kt @@ -39,14 +39,12 @@ class MapTest() : TestSupport() { fun testSetViaIndexOperators() { val map = java.util.HashMap() assertTrue{ map.empty } - // TODO cannot use map.size due to compiler bug - assertEquals(map.size(), 0) + assertEquals(map.size, 0) map["name"] = "James" assertTrue{ !map.empty } - // TODO cannot use map.size due to compiler bug - assertEquals(map.size(), 1) + assertEquals(map.size, 1) assertEquals("James", map["name"]) } } diff --git a/testlib/test/dom/DomBuilderTest.kt b/testlib/test/dom/DomBuilderTest.kt index 5729a0f49d1..f61341672bd 100644 --- a/testlib/test/dom/DomBuilderTest.kt +++ b/testlib/test/dom/DomBuilderTest.kt @@ -8,6 +8,7 @@ import org.w3c.dom.* class DomBuilderTest() : TestSupport() { + fun testBuildDocument() { var doc = createDocument() @@ -18,13 +19,20 @@ class DomBuilderTest() : TestSupport() { doc.addElement("foo") { id = "id1" style = "bold" - cssClass = "bar" + classes = "bar" addElement("child") { id = "id2" - cssClass = "another" + classes = "another" addElement("grandChild") { id = "id3" - cssClass = "tiny" + classes = " bar tiny" + addText("Hello World!") + // TODO support neater syntax sugar for adding text? + // += "Hello World!" + } + addElement("grandChild2") { + id = "id3" + classes = "tiny thing bar " addText("Hello World!") // TODO support neater syntax sugar for adding text? // += "Hello World!" @@ -37,8 +45,8 @@ class DomBuilderTest() : TestSupport() { // 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()) + assertEquals(3, doc[".bar"].size()) + assertEquals(2, doc[".tiny"].size()) // element tag selections assertEquals(0, doc["doesNotExist"].size()) @@ -60,8 +68,8 @@ class DomBuilderTest() : TestSupport() { // 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()) + assertEquals(2, root[".bar"].size()) + assertEquals(2, root[".tiny"].size()) // element tag selections assertEquals(0, root["doesNotExist"].size()) @@ -77,12 +85,32 @@ class DomBuilderTest() : TestSupport() { fail("No root!") } - val grandChild = doc["grandChild"].first if (grandChild != null) { println("got element ${grandChild.toXmlString()} with text '${grandChild.text}`") assertEquals("Hello World!", grandChild.text) - assertEquals("tiny", grandChild.attribute("class") ?: "") + assertEquals(" bar tiny", grandChild.attribute("class")) + + // test the classSet + val classSet = grandChild.classSet + + assertTrue(classSet.contains("bar")) + assertTrue(classSet.contains("tiny")) + assertTrue(classSet.size == 2 ) + assertFalse(classSet.contains("doesNotExist")) + + // lets add a new class and some existing classes + grandChild.addClass("bar") + grandChild.addClass("newThingy") + assertEquals("bar tiny newThingy", grandChild.classes) + + // remove + grandChild.removeClass("bar") + assertEquals("tiny newThingy", grandChild.classes) + + grandChild.removeClass("tiny") + assertEquals("newThingy", grandChild.classes) + } else { fail("Not an Element $grandChild") } diff --git a/testlib/test/dom/DomTest.kt b/testlib/test/dom/DomTest.kt index 1cf469464bc..558d0f99f94 100644 --- a/testlib/test/dom/DomTest.kt +++ b/testlib/test/dom/DomTest.kt @@ -15,7 +15,7 @@ class DomTest() : TestSupport() { assertCssClass(e, "") // now lets update the cssClass property - e.cssClass = "foo" + e.classes = "foo" assertCssClass(e, "foo") // now using the attribute directly @@ -28,7 +28,7 @@ class DomTest() : TestSupport() { fun assertCssClass(e: Element, value: String?): Unit { - val cl = e.cssClass + val cl = e.classes val cl2 = e.getAttribute("class") println("element ${e.toXmlString()} has cssClass `${cl}` class attr `${cl2}`") diff --git a/testlib/test/regressions/kt1172.kt b/testlib/test/regressions/kt1172.kt index e17d3f26d97..9f60d47b4a0 100644 --- a/testlib/test/regressions/kt1172.kt +++ b/testlib/test/regressions/kt1172.kt @@ -5,7 +5,8 @@ import junit.framework.* import java.util.* public fun scheduleRefresh(vararg files : Object) { - java.util.ArrayList(files.map{ it }) + // TODO + // java.util.ArrayList(files.map{ it }) } fun main(args : Array?) {