提交 75b23344 编写于 作者: P pTalanov

Merge remote-tracking branch 'origin/master'

......@@ -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/*"
......
......@@ -130,7 +130,7 @@
<target name="testlib" depends="compileTestlib">
<mkdir dir="${output}/test-reports"/>
<junit printsummary="yes" haltonfailure="no">
<junit printsummary="yes" haltonfailure="true">
<classpath>
<pathelement location="${kotlin-home}/lib/kotlin-runtime.jar"/>
<pathelement location="${basedir}/testlib/lib/junit-4.9.jar"/>
......@@ -148,7 +148,7 @@
</test>
-->
<batchtest fork="yes" todir="${output}/test-reports">
<batchtest fork="yes" todir="${output}/test-reports" haltonerror="true">
<fileset dir="${output}/classes/testlib">
<include name="**/*Test.*"/>
</fileset>
......
......@@ -124,7 +124,7 @@ public class CallableMethod implements Callable {
}
public boolean isNeedsThis() {
return thisClass != null;
return thisClass != null && generateCalleeType == null;
}
public boolean isNeedsReceiver() {
......
......@@ -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);
......
......@@ -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<? extends FunctionDescriptor> 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.
......
......@@ -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);
......
......@@ -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
//
......
......@@ -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)) {
......
......@@ -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
......
......@@ -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<? extends DeclarationDescriptor> 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 (selectorExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression selector = (JetSimpleNameExpression) selectorExpression;
JetSimpleNameExpression lastReference = getLastReference(receiverExpression);
if (lastReference == null || !canImportMembersFrom(declarationDescriptors, lastReference)) {
return Collections.emptyList();
}
if (declarationDescriptor instanceof VariableDescriptor) {
result = lookupVariableMembers((VariableDescriptor) declarationDescriptor, selector);
if (!result.isEmpty()) return result;
Collection<? extends DeclarationDescriptor> 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();
}
......
......@@ -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.*;
......
......@@ -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<out T> then C<T> and C<out T> 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<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments();
List<TypeParameterDescriptor> 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);
......
trait Creator<T> {
fun create() : T
}
class Actor(val code: String = "OK")
trait Factory : Creator<Actor>
class MyFactory() : Factory {
override fun create(): Actor = Actor()
}
fun box() : String = MyFactory().create().code
\ No newline at end of file
......@@ -7,7 +7,7 @@ fun test(s: String?) {
val <!UNUSED_VARIABLE!>d<!>: Int = s?.length ?: <!TYPE_MISMATCH!>"empty"<!>
val e: String = <!TYPE_MISMATCH!>s?.length<!> ?: "empty"
val <!UNUSED_VARIABLE!>f<!>: Int = s?.length ?: b ?: 1
val <!UNUSED_VARIABLE!>g<!>: Int? = e? startsWith("s")?.length
val <!UNUSED_VARIABLE!>g<!>: Boolean? = e.startsWith("s")//?.length
}
fun String.startsWith(<!UNUSED_PARAMETER!>s<!>: String): Boolean = true
\ No newline at end of file
// +JDK
import java.util.ArrayList
class MyListOfPairs<T> : ArrayList<#(T, T)>() { }
fun test() {
MyListOfPairs<Int> : ArrayList<#(Int, Int)>
}
......@@ -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
<empty list>
PsiErrorElement:Qualified name must be a '.'-separated identifier list
<empty 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
<empty list>
PsiErrorElement:Qualified name must be a '.'-separated identifier list
<empty 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
<empty list>
PsiErrorElement:Qualified name must be a '.'-separated identifier list
<empty list>
PsiWhiteSpace(' ')
PsiElement(as)('as')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('bar')
......
fun foo() {
a?f.foo
}
\ No newline at end of file
JetFile: PredicateExpression.jet
NAMESPACE_HEADER
<empty list>
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
......@@ -303,4 +303,8 @@ public class ClassGenTest extends CodegenTestCase {
blackBoxFile("regressions/kt633.kt");
}
public void testKt1345() throws Exception {
blackBoxFile("regressions/kt1345.kt");
}
}
......@@ -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" +
......
......@@ -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 {
......@@ -471,6 +471,21 @@ public class JetTypeCheckerTest extends JetLiteFixture {
assertSupertypes("Derived1_inT<Int>", "Derived_T<Int>", "Base_T<Int>", "Any", "Base_inT<Int>");
}
public void testEffectiveProjectionKinds() throws Exception {
assertSubtype("Tuple1<Int>", "Tuple1<Int>");
assertSubtype("Tuple1<out Int>", "Tuple1<out Int>");
assertSubtype("Tuple1<out Int>", "Tuple1<Int>");
assertSubtype("Tuple1<Int>", "Tuple1<out Int>");
assertSubtype("Tuple1<in Int>", "Tuple1<out Any?>");
assertSubtype("Tuple1<out Any?>", "Tuple1<in String>");
assertSubtype("Base_inT<Int>", "Base_inT<Int>");
assertSubtype("Base_inT<in Int>", "Base_inT<in Int>");
assertSubtype("Base_inT<in Int>", "Base_inT<Int>");
assertSubtype("Base_inT<Int>", "Base_inT<in Int>");
assertSubtype("Base_inT<out Int>", "Base_inT<out Any?>");
assertSubtype("Base_inT<out Any?>", "Base_inT<out Int>");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void assertSupertypes(String typeStr, String... supertypeStrs) {
......
......@@ -26,7 +26,8 @@ fun main(args : Array<String>) {
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()}")
}
}
......
......@@ -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
......
......@@ -128,6 +128,9 @@
<annotator language="jet" implementationClass="org.jetbrains.jet.plugin.annotations.JetPsiChecker"/>
<annotator language="jet" implementationClass="org.jetbrains.jet.plugin.annotations.DebugInfoAnnotator"/>
<extendWordSelectionHandler implementation="org.jetbrains.jet.plugin.JetStatementGroupSelectioner"/>
<extendWordSelectionHandler implementation="org.jetbrains.jet.plugin.JetCodeBlockSelectioner"/>
<documentationProvider implementation="org.jetbrains.jet.plugin.JetQuickDocumentationProvider"/>
<configurationType implementation="org.jetbrains.jet.plugin.run.JetRunConfigurationType"/>
<configurationProducer implementation="org.jetbrains.jet.plugin.run.JetRunConfigurationProducer"/>
......
/*
* 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<TextRange> select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) {
List<TextRange> result = new ArrayList<TextRange>();
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;
}
}
/*
* 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<TextRange> select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) {
List<TextRange> result = new ArrayList<TextRange>();
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;
}
}
......@@ -90,7 +90,7 @@ public class JetFunctionInsertHandler implements InsertHandler<LookupElement> {
// 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;
}
......
......@@ -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)
......
......@@ -89,9 +89,14 @@ public class ImportClassHelper {
}
else {
List<JetDeclaration> 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());
}
}
}
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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);
......
......@@ -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
......
......@@ -7,7 +7,7 @@ fun test(s: String?) {
val <warning>d</warning>: Int = s?.length ?: <error>"empty"</error>
val e: String = <error>s?.length</error> ?: "empty"
val <warning>f</warning>: Int = s?.length ?: b ?: 1
val <warning>g</warning>: Int? = e? startsWith("s")?.length
val <warning>g</warning>: Boolean? = e.startsWith("s")//?.length
}
fun String.startsWith(<warning>s</warning>: String): Boolean = true
\ No newline at end of file
fun main(args : Array<String>) {
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()
<selection>pr<caret>intln</selection>()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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()
}
}
}
<selection>fun foo() : Unit {
println() {
println()
pr<caret>intln()
println()
}
println(array(1, 2, 3))
println()
}</selection>
\ No newline at end of file
<selection>fun main(args : Array<String>) {
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()
pr<caret>intln()
println()
}
println(array(1, 2, 3))
println()
}</selection>
\ No newline at end of file
fun main(args : Array<String>) {
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()
<selection>pr<caret>intln()</selection>
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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()
<selection> pr<caret>intln()
</selection> println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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()
<selection> pr<caret>intln()
println()
</selection> }
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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() {
<selection> println()
pr<caret>intln()
println()
</selection> }
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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() <selection>{
println()
pr<caret>intln()
println()
}
</selection>
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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 {
<selection> println() {
println()
pr<caret>intln()
println()
}
</selection>
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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 {
<selection> println() {
println()
pr<caret>intln()
println()
}
println(array(1, 2, 3))
println()
</selection>}
\ No newline at end of file
fun main(args : Array<String>) {
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 <selection>{
println() {
println()
pr<caret>intln()
println()
}
println(array(1, 2, 3))
println()
}</selection>
\ No newline at end of file
fun main(args : Array<String>) {
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()
pr<caret>intln()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
for (i in 1..100) {
when {
i%3 == 0 -> {print("Fizz"); continue;}
i%5 == 0 -> {print("Buzz"); continue;}
(i%3 != 0 && i%5 != 0) -> <selection>{print(i); continue;}<caret></selection>
else -> println()
}
}
}
fun foo() : Unit {
println() {
println()
println()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
for (i in 1..100) {
when {
i%3 == 0 -> {print("Fizz"); continue;}
i%5 == 0 -> {print("Buzz"); continue;}
<selection>(i%3 != 0 && i%5 != 0) -> {print(i); continue;}<caret></selection>
else -> println()
}
}
}
fun foo() : Unit {
println() {
println()
println()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
for (i in 1..100) {
when {
i%3 == 0 -> {print("Fizz"); continue;}
i%5 == 0 -> {print("Buzz"); continue;}
<selection> (i%3 != 0 && i%5 != 0) -> {print(i); continue;}<caret>
</selection> else -> println()
}
}
}
fun foo() : Unit {
println() {
println()
println()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
for (i in 1..100) {
when {
i%3 == 0 -> {print("Fizz"); continue;}
i%5 == 0 -> {print("Buzz"); continue;}
<selection> (i%3 != 0 && i%5 != 0) -> {print(i); continue;}<caret>
else -> println()
</selection> }
}
}
fun foo() : Unit {
println() {
println()
println()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
for (i in 1..100) {
when {
<selection> i%3 == 0 -> {print("Fizz"); continue;}
i%5 == 0 -> {print("Buzz"); continue;}
(i%3 != 0 && i%5 != 0) -> {print(i); continue;}<caret>
else -> println()
</selection> }
}
}
fun foo() : Unit {
println() {
println()
println()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
for (i in 1..100) {
<selection>when {
i%3 == 0 -> {print("Fizz"); continue;}
i%5 == 0 -> {print("Buzz"); continue;}
(i%3 != 0 && i%5 != 0) -> {print(i); continue;}<caret>
else -> println()
}</selection>
}
}
fun foo() : Unit {
println() {
println()
println()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
fun main(args : Array<String>) {
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); <selection>continue;}<caret></selection>
else -> println()
}
}
}
fun foo() : Unit {
println() {
println()
println()
println()
}
println(array(1, 2, 3))
println()
}
\ No newline at end of file
......@@ -14,26 +14,43 @@
* limitations under the License.
*/
package org.jetbrains.jet.util;
package org.jetbrains.jet;
import com.intellij.util.containers.MultiMap;
import com.intellij.testFramework.fixtures.CodeInsightTestUtil;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.io.File;
/**
* @author Evgeny Gerashchenko
* TODO reuse LinkedMultiMap from IDEA platform when it will be available there
* @since 2/24/12
*/
public class LinkedMultiMap<K, V> extends MultiMap<K, V> {
@Override
protected Map<K, Collection<V>> createMap() {
return new LinkedHashMap<K, Collection<V>>();
public class WordSelectionTest extends LightCodeInsightFixtureTestCase {
public void testStatements() {
doTest(11);
}
public void testWhenEntries() {
doTest(6);
}
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
protected Map<K, Collection<V>> createMap(int i, float v) {
return new LinkedHashMap<K, Collection<V>>(i, v);
public void setUp() throws Exception {
super.setUp();
final String testRelativeDir = "wordSelection";
myFixture.setTestDataPath(new File(PluginTestCaseBase.getTestDataPathBase(), testRelativeDir).getPath() +
File.separator);
}
}
......@@ -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/";
......
......@@ -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<KClass>()
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))
}
}
}
......
......@@ -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<KFunction>) : ClassTemplate(m, p, k) {
class ClassExtensionsTemplate(m: KModel, p: KPackage, k: KClass,
val functions: Collection<KFunction>, val properties: Collection<KProperty>) : ClassTemplate(m, p, k) {
override fun pageTitle(): String = "${klass.name} Extensions fom ${pkg.name} (${model.title})"
......@@ -31,6 +33,7 @@ from package ${link(pkg)}
</PRE>
<P>""")
printPropertySummary(properties)
printFunctionSummary(functions)
printFunctionDetail(functions)
println("""<!-- ========= END OF CLASS EXTENSIONS DATA ========= -->
......
......@@ -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 &#169; 2010-2012. All Rights Reserved.
}
protected fun printExtensionFunctions(): Unit {
val map = extensionFunctions(pkg.functions)
val map = inheritedExtensionFunctions(pkg.functions)
if (! map.isEmpty()) {
print("""<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
......
......@@ -64,15 +64,55 @@ fun inheritedExtensionFunctions(functions: Collection<KFunction>): Map<KClass, S
return answer
}
// TODO for some reason the SortedMap causes kotlin to freak out a little :)
fun inheritedExtensionProperties(properties: Collection<KProperty>): Map<KClass, SortedSet<KProperty>> {
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<KClass, SortedSet<KProperty>>()
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<KFunction>): Map<KClass, List<KFunction>> {
//fun extensionFunctions(functions: Collection<KFunction>): SortedMap<KClass, List<KFunction>> {
val map = TreeMap<KClass, List<KFunction>>()
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<KProperty>): Map<KClass, List<KProperty>> {
val map = TreeMap<KClass, List<KProperty>>()
properties.filter{ it.extensionClass != null }.groupBy(map){ it.extensionClass.sure() }
return map
}
abstract class KClassOrPackage : KAnnotated() {
public open val functions: SortedSet<KFunction> = TreeSet<KFunction>()
public open val properties: SortedSet<KProperty> = TreeSet<KProperty>()
}
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<KFunction>, 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<KFunction> = TreeSet<KFunction>(),
var local: Boolean = false) : KAnnotated(), Comparable<KPackage>, KClassOrPackage {
var local: Boolean = false) : KClassOrPackage(), Comparable<KPackage> {
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<KAnnotation> = arrayList<KAnnotation>(),
var since: String = "",
var authors: List<String> = arrayList<String>(),
var functions: SortedSet<KFunction> = TreeSet<KFunction>(),
var properties: SortedSet<KProperty> = TreeSet<KProperty>(),
var baseClasses: List<KClass> = arrayList<KClass>(),
var nestedClasses: List<KClass> = arrayList<KClass>(),
var sourceLine: Int = 2) : KAnnotated(), Comparable<KClass>, KClassOrPackage {
var sourceLine: Int = 2) : KClassOrPackage(), Comparable<KClass> {
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<KProperty> {
val returnType: KClass, val extensionClass: KClass?) : KAnnotated(), Comparable<KProperty> {
override fun compareTo(other: KProperty): Int = name.compareTo(other.name)
......
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 <T> java.lang.Iterable<T>.contains(item : T) : Boolean {
return false
}
/**
* Convert collection of arbitrary elements to collection of
*/
fun <T> java.lang.Iterable<T>.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<T>(this@withIndices.iterator().sure()) as java.util.Iterator<#(Int, T)>
}
}
}
private class NumberedIterator<TT>(private val sourceIterator : java.util.Iterator<TT>) : 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
......@@ -55,8 +55,12 @@ inline fun <in T: java.lang.Comparable<T>> List<T>.sort(comparator: java.util.Co
}
/** Converts the nullable List into an empty List if its null */
inline fun <T> java.util.List<T>?.notNull() : List<T>
= if (this != null) this else Collections.EMPTY_LIST as List<T>
inline fun <T> java.util.List<T>?.notNull() : java.util.List<T>
= if (this != null) this else Collections.EMPTY_LIST as java.util.List<T>
/** Converts the nullable Set into an empty Set if its null */
inline fun <T> java.util.Set<T>?.notNull() : java.util.Set<T>
= if (this != null) this else Collections.EMPTY_SET as java.util.Set<T>
/**
TODO figure out necessary variance/generics ninja stuff... :)
......
......@@ -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 <K, V> JMap<K, V>.set(key : K, value : V) = this.put(key, value)
/** Converts the nullable Map into an empty Map if its null */
inline fun <K,V> java.util.Map<K,V>?.notNull() : java.util.Map<K,V>
= if (this != null) this else Collections.EMPTY_MAP as java.util.Map<K,V>
/** Returns the key of the entry */
// Temporary workaround: commenting out
......
......@@ -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()
......
......@@ -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,23 +74,76 @@ 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<Element> {
val root = this?.getDocumentElement()
return if (root != null) {
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<Element>
else
Collections.EMPTY_LIST.sure() as List<Element>
} else {
// assume its a vanilla element name
this?.getElementsByTagName(selector).toElementList()
}
} else {
Collections.EMPTY_LIST as List<Element>
}
}
/** 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<Element> {
return if (selector == "*") {
elements
} else if (selector.startsWith(".")) {
elements.filter{ it.hasClass(selector.substring(1)) }.toList()
} else if (selector.startsWith("#")) {
val element = this.getOwnerDocument()?.getElementById(selector.substring(1))
return if (element != null)
Collections.singletonList(element).sure() as List<Element>
else
Collections.EMPTY_LIST.sure() as List<Element>
} else {
// assume its a vanilla element name
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<Node> {
return this?.getChildNodes().toList()
}
inline fun Element?.elementsByTagName(name: String?): List<Element> {
return this?.getElementsByTagName(name).toElementList()
}
val Document?.elements : List<Element>
get() = this?.getElementsByTagName("*").toElementList()
val Element?.elements : List<Element>
get() = this?.getElementsByTagName("*").toElementList()
inline fun Element?.elementsByTagNameNS(namespaceUri: String?, localName: String?): List<Element> {
return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList()
}
inline fun Document?.elementsByTagName(name: String?): List<Element> {
return this?.getElementsByTagName(name).toElementList()
}
inline fun Document?.elementsByTagNameNS(namespaceUri: String?, localName: String?): List<Element> {
return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList()
}
......@@ -169,6 +223,8 @@ class ElementListAsList(val nodeList: NodeList): AbstractList<Element>() {
override fun size(): Int = nodeList.getLength()
}
// Syntax sugar
inline fun Node.plus(child: Node?): Node {
......
......@@ -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)
}
}
......@@ -11,13 +11,19 @@ class DomBuilderTest() : TestSupport() {
fun testBuildDocument() {
var doc = createDocument()
assert {
doc["grandchild"].isEmpty()
}
doc.addElement("foo") {
id = "id1"
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?
......@@ -28,10 +34,55 @@ class DomBuilderTest() : TestSupport() {
println("builder document: ${doc.toXmlString()}")
val grandChild = doc.elementsByTagName("grandChild").first
// 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}`")
assertEquals("Hello World!", grandChild.text)
assertEquals("tiny", grandChild.attribute("class") ?: "")
} else {
fail("Not an Element $grandChild")
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册