From 868e0d9306e8d02bbac77e03ef52cf609947778e Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 20 Jun 2014 19:55:50 +0400 Subject: [PATCH 001/143] LOG.error() instead of exception for "Rewrite at slice" errors --- .../frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java b/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java index bf3276e13e5..693e816088a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java +++ b/compiler/frontend/src/org/jetbrains/jet/util/slicedmap/Slices.java @@ -16,12 +16,14 @@ package org.jetbrains.jet.util.slicedmap; +import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.List; public class Slices { + private static final Logger LOG = Logger.getInstance(Slices.class); public static final RewritePolicy ONLY_REWRITE_TO_EQUAL = new RewritePolicy() { @Override @@ -33,7 +35,7 @@ public class Slices { public boolean processRewrite(WritableSlice slice, K key, V oldValue, V newValue) { if (!((oldValue == null && newValue == null) || (oldValue != null && oldValue.equals(newValue)))) { // NOTE: Use BindingTraceContext.TRACK_REWRITES to debug this exception - throw new IllegalStateException("Rewrite at slice " + slice + + LOG.error("Rewrite at slice " + slice + " key: " + key + " old value: " + oldValue + '@' + System.identityHashCode(oldValue) + " new value: " + newValue + '@' + System.identityHashCode(newValue)); From fc19f1db440a69eb290ef40c6d9df8d9d99aff26 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Fri, 20 Jun 2014 22:23:24 +0400 Subject: [PATCH 002/143] Minor: improve assertion message in SpecifyTypeExplicitlyFix --- .../jet/plugin/quickfix/SpecifyTypeExplicitlyFix.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/SpecifyTypeExplicitlyFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/SpecifyTypeExplicitlyFix.java index 50f220f038b..350506570c2 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/SpecifyTypeExplicitlyFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/SpecifyTypeExplicitlyFix.java @@ -22,9 +22,11 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetNamedDeclaration; import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetBundle; @@ -40,7 +42,7 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction { } @Override - public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element) { //noinspection unchecked JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetProperty.class, JetNamedFunction.class); JetType type = getTypeForDeclaration(declaration); @@ -51,12 +53,12 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction { addTypeAnnotation(project, editor, (JetNamedFunction) declaration, type); } else { - assert false : "Couldn't find property or function"; + assert false : "Couldn't find property or function " + JetPsiUtil.getElementTextWithContext((JetElement) element); } } @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + public boolean isAvailable(@NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element) { //noinspection unchecked JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetProperty.class, JetNamedFunction.class); if (declaration instanceof JetProperty) { @@ -66,7 +68,7 @@ public class SpecifyTypeExplicitlyFix extends PsiElementBaseIntentionAction { setText(JetBundle.message("specify.type.explicitly.add.return.type.action.name")); } else { - assert false : "Couldn't find property or function"; + assert false : "Couldn't find property or function " + JetPsiUtil.getElementTextWithContext((JetElement) element); } return !getTypeForDeclaration(declaration).isError(); From 4efeb2eae2c302273de155d6f257e8308ac83606 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 10 Jun 2014 14:56:21 +0400 Subject: [PATCH 003/143] Refactoring: extracted 'reportUnreachableCode' --- .../lang/cfg/JetFlowInformationProvider.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 26944142c2c..d0da240b44d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -124,8 +124,9 @@ public class JetFlowInformationProvider { } public void checkFunction(@Nullable JetType expectedReturnType) { - - checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE); + Set unreachableElements = collectUnreachableCode(); + checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, unreachableElements); + reportUnreachableCode(unreachableElements); markTailCalls(); } @@ -208,7 +209,7 @@ public class JetFlowInformationProvider { } } - public void checkDefiniteReturn(final @NotNull JetType expectedReturnType) { + public void checkDefiniteReturn(final @NotNull JetType expectedReturnType, @NotNull final Set unreachableElements) { assert subroutine instanceof JetDeclarationWithBody; JetDeclarationWithBody function = (JetDeclarationWithBody) subroutine; @@ -219,11 +220,6 @@ public class JetFlowInformationProvider { final boolean blockBody = function.hasBlockBody(); - final Set rootUnreachableElements = collectUnreachableCode(); - for (JetElement element : rootUnreachableElements) { - trace.report(UNREACHABLE_CODE.on(element)); - } - final boolean[] noReturnError = new boolean[] { false }; for (JetElement returnedExpression : returnedExpressions) { returnedExpression.accept(new JetVisitorVoid() { @@ -240,7 +236,7 @@ public class JetFlowInformationProvider { if (blockBody && !noExpectedType(expectedReturnType) && !KotlinBuiltIns.getInstance().isUnit(expectedReturnType) - && !rootUnreachableElements.contains(element)) { + && !unreachableElements.contains(element)) { noReturnError[0] = true; } } @@ -251,8 +247,17 @@ public class JetFlowInformationProvider { } } + private void reportUnreachableCode(@NotNull Set unreachableElements) { + // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well + Set rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements); + + for (JetElement element : rootUnreachableElements) { + trace.report(UNREACHABLE_CODE.on(element)); + } + } + private Set collectUnreachableCode() { - Collection unreachableElements = Lists.newArrayList(); + Set unreachableElements = Sets.newHashSet(); for (Instruction deadInstruction : pseudocode.getDeadInstructions()) { if (!(deadInstruction instanceof JetElementInstruction) || deadInstruction instanceof LoadUnitValueInstruction @@ -271,8 +276,7 @@ public class JetFlowInformationProvider { unreachableElements.add(element); } - // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well - return JetPsiUtil.findRootExpressions(unreachableElements); + return unreachableElements; } //////////////////////////////////////////////////////////////////////////////// From 67fd858432815f2f652788e487b9a72269ad84e7 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 11 Jun 2014 12:53:03 +0400 Subject: [PATCH 004/143] Rename: getAllInstructions -> getInstructionsIncludingDeadCode Added this method to 'Pseudocode' interface instead of 'getDeadInstructions', added 'isDead' to 'Instruction' interface --- .../lang/cfg/JetFlowInformationProvider.java | 15 ++++++------ .../jet/lang/cfg/pseudocode/Pseudocode.java | 2 +- .../lang/cfg/pseudocode/PseudocodeImpl.java | 24 ++----------------- .../lang/cfg/pseudocode/PseudocodeUtil.java | 8 +++++++ .../pseudocode/instructions/Instruction.kt | 2 ++ .../instructions/InstructionImpl.kt | 2 +- .../jet/cfg/AbstractControlFlowTest.java | 9 ++++--- .../jet/cfg/AbstractDataFlowTest.java | 2 +- .../jet/cfg/AbstractPseudocodeTest.java | 2 +- .../jet/cfg/CFGraphToDotFilePrinter.java | 6 ++--- 10 files changed, 31 insertions(+), 41 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index d0da240b44d..5375b8e65c2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -258,15 +258,16 @@ public class JetFlowInformationProvider { private Set collectUnreachableCode() { Set unreachableElements = Sets.newHashSet(); - for (Instruction deadInstruction : pseudocode.getDeadInstructions()) { - if (!(deadInstruction instanceof JetElementInstruction) - || deadInstruction instanceof LoadUnitValueInstruction - || deadInstruction instanceof MergeInstruction - || (deadInstruction instanceof MagicInstruction && ((MagicInstruction) deadInstruction).getSynthetic())) continue; + for (Instruction instruction : pseudocode.getDeadInstructions()) { + if (!PseudocodeUtil.isDeadInAllCopies(instruction)) continue; + if (!(instruction instanceof JetElementInstruction) + || instruction instanceof LoadUnitValueInstruction + || instruction instanceof MergeInstruction + || (instruction instanceof MagicInstruction && ((MagicInstruction) instruction).getSynthetic())) continue; - JetElement element = ((JetElementInstruction) deadInstruction).getElement(); + JetElement element = ((JetElementInstruction) instruction).getElement(); - if (deadInstruction instanceof JumpInstruction) { + if (instruction instanceof JumpInstruction) { boolean isJumpElement = element instanceof JetBreakExpression || element instanceof JetContinueExpression || element instanceof JetReturnExpression diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java index e86b008fd7d..91044d06959 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java @@ -45,7 +45,7 @@ public interface Pseudocode { List getReversedInstructions(); @NotNull - List getDeadInstructions(); + List getInstructionsIncludingDeadCode(); @NotNull SubroutineExitInstruction getExitInstruction(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java index 650d9123af3..9613b7a0f40 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java @@ -183,30 +183,10 @@ public class PseudocodeImpl implements Pseudocode { return Lists.newArrayList(traversedInstructions); } - //for tests only - @NotNull - public List getAllInstructions() { - return mutableInstructionList; - } - @Override @NotNull - public List getDeadInstructions() { - List deadInstructions = Lists.newArrayList(); - for (Instruction instruction : mutableInstructionList) { - if (isDead(instruction)) { - deadInstructions.add(instruction); - } - } - return deadInstructions; - } - - private static boolean isDead(@NotNull Instruction instruction) { - if (!((InstructionImpl)instruction).getDead()) return false; - for (Instruction copy : instruction.getCopies()) { - if (!((InstructionImpl)copy).getDead()) return false; - } - return true; + public List getInstructionsIncludingDeadCode() { + return mutableInstructionList; } //for tests only diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java index 8ad89af03b5..b6e5bdc5db8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java @@ -85,4 +85,12 @@ public class PseudocodeUtil { } return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference); } + + public static boolean isDeadInAllCopies(@NotNull Instruction instruction) { + boolean allCopiesAreDead = instruction.getDead(); + for (Instruction copy : instruction.getCopies()) { + allCopiesAreDead = allCopiesAreDead && copy.getDead(); + } + return allCopiesAreDead; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt index 17fbcaaeffe..e98ff49cdb0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt @@ -26,6 +26,8 @@ public trait Instruction { public val previousInstructions: MutableCollection public val nextInstructions: Collection + public val dead: Boolean + public val lexicalScope: LexicalScope public val inputValues: List diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt index bb367a57f1b..a57b75dd7c2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt @@ -53,7 +53,7 @@ public abstract class InstructionImpl(public override val lexicalScope: LexicalS _dead = true } - public val dead: Boolean get() = _dead + override val dead: Boolean get() = _dead public fun copy(): Instruction { return updateCopyInfo(createCopy()) diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java b/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java index 64a552fb074..cea52dc1fa4 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java @@ -19,9 +19,8 @@ package org.jetbrains.jet.cfg; import kotlin.Function3; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction; -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionImpl; import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; +import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction; import org.jetbrains.jet.lang.resolve.BindingContext; import java.util.*; @@ -34,7 +33,7 @@ public abstract class AbstractControlFlowTest extends AbstractPseudocodeTest { @NotNull StringBuilder out, @NotNull BindingContext bindingContext ) { - final int nextInstructionsColumnWidth = countNextInstructionsColumnWidth(pseudocode.getAllInstructions()); + final int nextInstructionsColumnWidth = countNextInstructionsColumnWidth(pseudocode.getInstructionsIncludingDeadCode()); dumpInstructions(pseudocode, out, new Function3() { @Override @@ -107,9 +106,9 @@ public abstract class AbstractControlFlowTest extends AbstractPseudocodeTest { @Override protected void checkPseudocode(PseudocodeImpl pseudocode) { //check edges directions - Collection instructions = pseudocode.getAllInstructions(); + Collection instructions = pseudocode.getInstructionsIncludingDeadCode(); for (Instruction instruction : instructions) { - if (!((InstructionImpl)instruction).getDead()) { + if (!instruction.getDead()) { for (Instruction nextInstruction : instruction.getNextInstructions()) { assertTrue("instruction '" + instruction + "' has '" + nextInstruction + "' among next instructions list, but not vice versa", nextInstruction.getPreviousInstructions().contains(instruction)); diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractDataFlowTest.java b/compiler/tests/org/jetbrains/jet/cfg/AbstractDataFlowTest.java index 64b095a31ed..27b37d7a209 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractDataFlowTest.java +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractDataFlowTest.java @@ -49,7 +49,7 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest { pseudocodeVariablesData.getVariableUseStatusData(); final String initPrefix = " INIT:"; final String usePrefix = " USE:"; - final int initializersColumnWidth = countDataColumnWidth(initPrefix, pseudocode.getAllInstructions(), variableInitializers); + final int initializersColumnWidth = countDataColumnWidth(initPrefix, pseudocode.getInstructionsIncludingDeadCode(), variableInitializers); dumpInstructions(pseudocode, out, new Function3() { @Override diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java index 1d8315db966..1dc9d51d6d1 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java @@ -179,7 +179,7 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironment { @NotNull StringBuilder out, @NotNull Function3 getInstructionData ) { - List instructions = pseudocode.getAllInstructions(); + List instructions = pseudocode.getInstructionsIncludingDeadCode(); Set remainedAfterPostProcessInstructions = Sets.newHashSet(pseudocode.getInstructions()); List labels = pseudocode.getLabels(); int instructionColumnWidth = countInstructionColumnWidth(instructions); diff --git a/compiler/tests/org/jetbrains/jet/cfg/CFGraphToDotFilePrinter.java b/compiler/tests/org/jetbrains/jet/cfg/CFGraphToDotFilePrinter.java index 4dc51c2b970..878996e3845 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/CFGraphToDotFilePrinter.java +++ b/compiler/tests/org/jetbrains/jet/cfg/CFGraphToDotFilePrinter.java @@ -44,7 +44,7 @@ public class CFGraphToDotFilePrinter { int[] count = new int[1]; Map nodeToName = new HashMap(); for (Pseudocode pseudocode : pseudocodes) { - dumpNodes(((PseudocodeImpl)pseudocode).getAllInstructions(), out, count, nodeToName, Sets + dumpNodes(pseudocode.getInstructionsIncludingDeadCode(), out, count, nodeToName, Sets .newHashSet(pseudocode.getInstructions())); } int i = 0; @@ -61,7 +61,7 @@ public class CFGraphToDotFilePrinter { out.println("subgraph cluster_" + i + " {\n" + "label=\"" + label + "\";\n" + "color=blue;\n"); - dumpEdges(((PseudocodeImpl)pseudocode).getAllInstructions(), out, count, nodeToName); + dumpEdges(pseudocode.getInstructionsIncludingDeadCode(), out, count, nodeToName); out.println("}"); i++; } @@ -76,7 +76,7 @@ public class CFGraphToDotFilePrinter { public void visitLocalFunctionDeclarationInstruction(LocalFunctionDeclarationInstruction instruction) { int index = count[0]; // instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName); - printEdge(out, nodeToName.get(instruction), nodeToName.get(((PseudocodeImpl)instruction.getBody()).getAllInstructions().get(0)), null); + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getBody().getInstructionsIncludingDeadCode().get(0)), null); visitInstructionWithNext(instruction); } From 6e622f2301402eebba20c4be26548d9c71e8c10a Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 11 Jun 2014 19:17:49 +0400 Subject: [PATCH 005/143] Highlight all text ranges for diagnostics in tests --- .../jet/checkers/CheckerTestUtil.java | 50 +++++++++---------- .../diagnostics/tests/LValueAssignment.kt | 2 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java b/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java index 79db9004292..957f86ec3c7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/checkers/CheckerTestUtil.java @@ -44,8 +44,8 @@ public class CheckerTestUtil { public int compare(@NotNull Diagnostic o1, @NotNull Diagnostic o2) { List ranges1 = o1.getTextRanges(); List ranges2 = o2.getTextRanges(); - if (ranges1.size() != ranges2.size()) return ranges1.size() - ranges2.size(); - for (int i = 0; i < ranges1.size(); i++) { + int minNumberOfRanges = ranges1.size() < ranges2.size() ? ranges1.size() : ranges2.size(); + for (int i = 0; i < minNumberOfRanges; i++) { TextRange range1 = ranges1.get(i); TextRange range2 = ranges2.get(i); int startOffset1 = range1.getStartOffset(); @@ -61,7 +61,7 @@ public class CheckerTestUtil { return endOffset2 - endOffset1; } } - return 0; + return ranges1.size() - ranges2.size(); } }; private static final Pattern RANGE_START_OR_END_PATTERN = Pattern.compile("()|()"); @@ -439,41 +439,39 @@ public class CheckerTestUtil { } } - private static List getSortedDiagnosticDescriptors(Collection diagnostics) { - List list = Lists.newArrayList(diagnostics); - Collections.sort(list, DIAGNOSTIC_COMPARATOR); - - List diagnosticDescriptors = Lists.newArrayList(); - DiagnosticDescriptor currentDiagnosticDescriptor = null; - for (Diagnostic diagnostic : list) { - List textRanges = diagnostic.getTextRanges(); + @NotNull + private static List getSortedDiagnosticDescriptors(@NotNull Collection diagnostics) { + LinkedListMultimap diagnosticsGroupedByRanges = LinkedListMultimap.create(); + for (Diagnostic diagnostic : diagnostics) { if (!diagnostic.isValid()) continue; - - TextRange textRange = textRanges.get(0); - if (currentDiagnosticDescriptor != null && currentDiagnosticDescriptor.equalRange(textRange)) { - currentDiagnosticDescriptor.diagnostics.add(diagnostic); - } - else { - currentDiagnosticDescriptor = new DiagnosticDescriptor(textRange.getStartOffset(), textRange.getEndOffset(), diagnostic); - diagnosticDescriptors.add(currentDiagnosticDescriptor); + for (TextRange textRange : diagnostic.getTextRanges()) { + diagnosticsGroupedByRanges.put(textRange, diagnostic); } } + List diagnosticDescriptors = Lists.newArrayList(); + for (TextRange range : diagnosticsGroupedByRanges.keySet()) { + diagnosticDescriptors.add( + new DiagnosticDescriptor(range.getStartOffset(), range.getEndOffset(), diagnosticsGroupedByRanges.get(range))); + } + Collections.sort(diagnosticDescriptors, new Comparator() { + @Override + public int compare(DiagnosticDescriptor d1, DiagnosticDescriptor d2) { + // Start early -- go first; start at the same offset, the one who end later is the outer, i.e. goes first + return (d1.start != d2.start) ? d1.start - d2.start : d2.end - d1.end; + } + }); return diagnosticDescriptors; } private static class DiagnosticDescriptor { private final int start; private final int end; - private final List diagnostics = Lists.newArrayList(); + private final List diagnostics; - DiagnosticDescriptor(int start, int end, Diagnostic diagnostic) { + DiagnosticDescriptor(int start, int end, List diagnostics) { this.start = start; this.end = end; - this.diagnostics.add(diagnostic); - } - - public boolean equalRange(TextRange textRange) { - return start == textRange.getStartOffset() && end == textRange.getEndOffset(); + this.diagnostics = diagnostics; } public Multiset getDiagnosticTypeStrings() { diff --git a/compiler/testData/diagnostics/tests/LValueAssignment.kt b/compiler/testData/diagnostics/tests/LValueAssignment.kt index b048163c50c..dd41b22982e 100644 --- a/compiler/testData/diagnostics/tests/LValueAssignment.kt +++ b/compiler/testData/diagnostics/tests/LValueAssignment.kt @@ -134,7 +134,7 @@ class Test() { (a : Array)[4]++ (ab.getArray() : Array)[54] += 43 - this[54] = 34 + this[54] = 34 } } From 94809075148351caf10cf2238a068fda358c54ad Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Thu, 12 Jun 2014 12:58:57 +0400 Subject: [PATCH 006/143] Mark some expressions after processing their components when it's semantically correct Expressions: calls, 'for' loops, elvis operators It's significant for reporting 'unreachable code' correctly --- .../jet/lang/cfg/JetControlFlowProcessor.java | 22 +++-- .../BasicExpressionTypingVisitor.java | 2 +- .../basic/IfWithUninitialized.instructions | 6 +- .../basic/UsageInFunctionLiteral.instructions | 12 +-- .../basic/VariablesUsage.instructions | 8 +- ...eferenceToPropertyInitializer.instructions | 10 +-- .../bugs/varInitializationInIf.instructions | 6 +- .../varInitializationInIfInCycle.instructions | 16 ++-- .../lexicalScopes/doWhileScope.instructions | 2 +- .../lexicalScopes/forScope.instructions | 8 +- .../functionLiteralScope.instructions | 6 +- .../localFunctionScope.instructions | 6 +- ...localFunctionScopeWithoutBody.instructions | 6 +- .../lexicalScopes/whileScope.instructions | 2 +- .../cfg/arrays/ArrayAccess.instructions | 4 +- .../cfg/arrays/ArrayOfFunctions.instructions | 3 +- .../arrays/arrayAccessExpression.instructions | 3 +- .../testData/cfg/arrays/arrayInc.instructions | 3 +- .../arrays/arraySetPlusAssign.instructions | 3 +- .../testData/cfg/basic/Basic.instructions | 12 +-- .../cfg/bugs/jumpToOuterScope.instructions | 4 +- .../controlStructures/Finally.instructions | 80 +++++++++---------- .../FinallyTestCopy.instructions | 16 ++-- .../cfg/controlStructures/For.instructions | 8 +- .../cfg/controlStructures/If.instructions | 16 ++-- .../OnlyWhileInFunctionBody.instructions | 10 +-- .../cfg/conventions/equals.instructions | 2 +- .../incrementAtTheEnd.instructions | 2 +- .../cfg/conventions/invoke.instructions | 2 +- .../cfg/conventions/notEqual.instructions | 2 +- .../cfg/deadCode/returnInElvis.instructions | 1 + .../local/ObjectExpression.instructions | 2 +- ...backingFieldQualifiedWithThis.instructions | 2 +- .../cfg/expressions/Assignments.instructions | 4 +- .../chainedQualifiedExpression.instructions | 48 +++++------ .../expressionAsFunction.instructions | 2 +- .../cfg/expressions/nothingExpr.instructions | 4 +- .../expressions/unresolvedCall.instructions | 2 +- .../testData/cfg/tailCalls/sum.instructions | 12 +-- 39 files changed, 181 insertions(+), 178 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 7379e15f149..1cc0a9090fb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.lang.cfg; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; @@ -333,9 +332,6 @@ public class JetControlFlowProcessor { public void visitBinaryExpressionVoid(@NotNull JetBinaryExpression expression, CFPContext context) { JetSimpleNameExpression operationReference = expression.getOperationReference(); IElementType operationType = operationReference.getReferencedNameElementType(); - if (!ImmutableSet.of(ANDAND, OROR, EQ, ELVIS).contains(operationType)) { - mark(expression); - } JetExpression left = expression.getLeft(); JetExpression right = expression.getRight(); @@ -385,11 +381,12 @@ public class JetControlFlowProcessor { } } else { - generateBothArguments(expression); + generateBothArgumentsAndMark(expression); } } else if (operationType == ELVIS) { generateInstructions(left, NOT_IN_CONDITION); + mark(expression); Label afterElvis = builder.createUnboundLabel(); builder.jumpOnTrue(afterElvis, expression, builder.getBoundValue(left)); if (right != null) { @@ -400,7 +397,7 @@ public class JetControlFlowProcessor { } else { if (!generateCall(expression, operationReference)) { - generateBothArguments(expression); + generateBothArgumentsAndMark(expression); } } } @@ -430,7 +427,7 @@ public class JetControlFlowProcessor { ); } - private void generateBothArguments(JetBinaryExpression expression) { + private void generateBothArgumentsAndMark(JetBinaryExpression expression) { JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); if (left != null) { generateInstructions(left, NOT_IN_CONDITION); @@ -439,8 +436,8 @@ public class JetControlFlowProcessor { if (right != null) { generateInstructions(right, NOT_IN_CONDITION); } - createNonSyntheticValue(expression, left, right); + mark(expression); } private void visitAssignment(JetExpression lhs, @NotNull Function0 rhsDeferredValue, JetExpression parentExpression) { @@ -592,7 +589,6 @@ public class JetControlFlowProcessor { @Override public void visitUnaryExpressionVoid(@NotNull JetUnaryExpression expression, CFPContext context) { - mark(expression); JetSimpleNameExpression operationSign = expression.getOperationReference(); IElementType operationType = operationSign.getReferencedNameElementType(); JetExpression baseExpression = expression.getBaseExpression(); @@ -795,7 +791,6 @@ public class JetControlFlowProcessor { @Override public void visitWhileExpressionVoid(@NotNull JetWhileExpression expression, CFPContext context) { - mark(expression); LoopInfo loopInfo = builder.enterLoop(expression, null, null); builder.bindLabel(loopInfo.getConditionEntryPoint()); @@ -803,6 +798,7 @@ public class JetControlFlowProcessor { if (condition != null) { generateInstructions(condition, IN_CONDITION); } + mark(expression); boolean conditionIsTrueConstant = CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace, true); if (!conditionIsTrueConstant) { builder.jumpOnFalse(loopInfo.getExitPoint(), expression, builder.getBoundValue(condition)); @@ -843,7 +839,6 @@ public class JetControlFlowProcessor { @Override public void visitForExpressionVoid(@NotNull JetForExpression expression, CFPContext context) { builder.enterLexicalScope(expression); - mark(expression); JetExpression loopRange = expression.getLoopRange(); if (loopRange != null) { @@ -863,6 +858,7 @@ public class JetControlFlowProcessor { builder.bindLabel(loopInfo.getBodyEntryPoint()); writeLoopParameterAssignment(expression); + mark(expression); JetExpression body = expression.getBody(); if (body != null) { generateInstructions(body, NOT_IN_CONDITION); @@ -1070,8 +1066,6 @@ public class JetControlFlowProcessor { @Override public void visitCallExpressionVoid(@NotNull JetCallExpression expression, CFPContext context) { - mark(expression); - JetExpression calleeExpression = expression.getCalleeExpression(); if (!generateCall(expression, calleeExpression)) { List inputExpressions = new ArrayList(); @@ -1090,6 +1084,7 @@ public class JetControlFlowProcessor { inputExpressions.add(calleeExpression); inputExpressions.add(generateAndGetReceiverIfAny(expression)); + mark(expression); createNonSyntheticValue(expression, inputExpressions); } } @@ -1416,6 +1411,7 @@ public class JetControlFlowProcessor { : "Variable-based call with non-empty argument list: " + resolvedCall.getCall().getCallElement().getText(); return builder.readVariable(calleeExpression, callExpression, resolvedCall, receivers); } + mark(resolvedCall.getCall().getCallElement()); return builder.call(calleeExpression, callExpression, resolvedCall, receivers, parameterValues); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 9b836f765d3..b15e9a82b6a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -882,7 +882,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace, "trace to resolve 'equals(Any?)' interpreting as of type Any? an expression:", right); traceInterpretingRightAsNullableAny.record(EXPRESSION_TYPE, right, KotlinBuiltIns.getInstance().getNullableAnyType()); - Call call = CallMaker.makeCallWithExpressions(operationSign, receiver, null, operationSign, Collections.singletonList(right)); + Call call = CallMaker.makeCallWithExpressions(expression, receiver, null, operationSign, Collections.singletonList(right)); ExpressionTypingContext newContext = context.replaceBindingTrace(traceInterpretingRightAsNullableAny); OverloadResolutionResults resolutionResults = components.callResolver.resolveCallWithGivenName(newContext, call, operationSign, OperatorConventions.EQUALS); diff --git a/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions b/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions index 2afa0f4bfc8..bc3499991b5 100644 --- a/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions +++ b/compiler/testData/cfg-variables/basic/IfWithUninitialized.instructions @@ -14,14 +14,14 @@ L0: 2 mark({ val b: Boolean if (1 < 2) { use(b) } else { b = true } }) v(val b: Boolean) INIT: in: {} out: {b=D} mark(if (1 < 2) { use(b) } else { b = true }) INIT: in: {b=D} out: {b=D} - mark(1 < 2) r(1) -> r(2) -> + mark(1 < 2) call(<, compareTo|, ) -> jf(L2|) - 3 mark({ use(b) }) - mark(use(b)) USE: in: {b=READ} out: {b=READ} + 3 mark({ use(b) }) USE: in: {b=READ} out: {b=READ} r(b) -> USE: in: {} out: {b=READ} + mark(use(b)) call(use, use|) -> 2 jmp(L3) USE: in: {} out: {} L2: diff --git a/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions b/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions index da8b9a71781..c1df1eb55e0 100644 --- a/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions +++ b/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions @@ -39,14 +39,14 @@ L3: magic(x: Int) -> INIT: in: {x=D} out: {x=D} w(x|) INIT: in: {x=D} out: {x=ID} 4 mark(val y = x + a use(a)) INIT: in: {x=ID} out: {x=ID} - v(val y = x + a) INIT: in: {x=ID} out: {x=ID, y=D} - mark(x + a) INIT: in: {x=ID, y=D} out: {x=ID, y=D} USE: in: {a=READ, x=READ} out: {a=READ, x=READ} - r(x) -> USE: in: {a=READ} out: {a=READ, x=READ} + v(val y = x + a) INIT: in: {x=ID} out: {x=ID, y=D} USE: in: {a=READ, x=READ} out: {a=READ, x=READ} + r(x) -> INIT: in: {x=ID, y=D} out: {x=ID, y=D} USE: in: {a=READ} out: {a=READ, x=READ} r(a) -> + mark(x + a) call(+, plus|, ) -> - w(y|) INIT: in: {x=ID, y=D} out: {x=ID, y=ID} - mark(use(a)) INIT: in: {x=ID, y=ID} out: {x=ID, y=ID} USE: in: {a=READ} out: {a=READ} - r(a) -> USE: in: {} out: {a=READ} + w(y|) INIT: in: {x=ID, y=D} out: {x=ID, y=ID} USE: in: {a=READ} out: {a=READ} + r(a) -> INIT: in: {x=ID, y=ID} out: {x=ID, y=ID} USE: in: {} out: {a=READ} + mark(use(a)) call(use, use|) -> L4: 3 INIT: in: {x=ID} out: {x=ID} diff --git a/compiler/testData/cfg-variables/basic/VariablesUsage.instructions b/compiler/testData/cfg-variables/basic/VariablesUsage.instructions index c4b90e6cd19..e7ef96d159d 100644 --- a/compiler/testData/cfg-variables/basic/VariablesUsage.instructions +++ b/compiler/testData/cfg-variables/basic/VariablesUsage.instructions @@ -11,14 +11,14 @@ L0: 2 mark({ var a = 1 use(a) a = 2 use(a) }) v(var a = 1) INIT: in: {} out: {a=D} r(1) -> INIT: in: {a=D} out: {a=D} - w(a|) INIT: in: {a=D} out: {a=ID} - mark(use(a)) INIT: in: {a=ID} out: {a=ID} USE: in: {a=READ} out: {a=READ} - r(a) -> USE: in: {a=WRITTEN_AFTER_READ} out: {a=READ} + w(a|) INIT: in: {a=D} out: {a=ID} USE: in: {a=READ} out: {a=READ} + r(a) -> INIT: in: {a=ID} out: {a=ID} USE: in: {a=WRITTEN_AFTER_READ} out: {a=READ} + mark(use(a)) call(use, use|) -> r(2) -> USE: in: {a=WRITTEN_AFTER_READ} out: {a=WRITTEN_AFTER_READ} w(a|) USE: in: {a=READ} out: {a=WRITTEN_AFTER_READ} - mark(use(a)) USE: in: {a=READ} out: {a=READ} r(a) -> USE: in: {} out: {a=READ} + mark(use(a)) call(use, use|) -> L1: 1 INIT: in: {} out: {} diff --git a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions index fe4512be268..ff2efa51a56 100644 --- a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions +++ b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions @@ -32,16 +32,16 @@ L3: magic(x: Int) -> INIT: in: {x=D} out: {x=D} w(x|) INIT: in: {x=D} out: {x=ID} 3 mark(sum(x - 1) + x) INIT: in: {x=ID} out: {x=ID} - mark(sum(x - 1) + x) - mark(sum(x - 1)) magic(sum) -> USE: in: {sum=READ, x=READ} out: {sum=READ, x=READ} r(sum|) -> USE: in: {x=READ} out: {sum=READ, x=READ} - mark(x - 1) r(x) -> r(1) -> + mark(x - 1) call(-, minus|, ) -> + mark(sum(x - 1)) call(sum, invoke|, ) -> USE: in: {x=READ} out: {x=READ} r(x) -> USE: in: {} out: {x=READ} + mark(sum(x - 1) + x) call(+, plus|, ) -> L4: 2 @@ -127,10 +127,10 @@ class TestOther { L0: 1 INIT: in: {} out: {} v(val x: Int = x + 1) INIT: in: {} out: {x=D} - mark(x + 1) INIT: in: {x=D} out: {x=D} - magic(x) -> USE: in: {x=READ} out: {x=READ} + magic(x) -> INIT: in: {x=D} out: {x=D} USE: in: {x=READ} out: {x=READ} r(x|) -> USE: in: {} out: {x=READ} r(1) -> + mark(x + 1) call(+, plus|, ) -> w(x|) INIT: in: {x=D} out: {x=ID} L1: diff --git a/compiler/testData/cfg-variables/bugs/varInitializationInIf.instructions b/compiler/testData/cfg-variables/bugs/varInitializationInIf.instructions index 96d9c9a1284..c21437571e3 100644 --- a/compiler/testData/cfg-variables/bugs/varInitializationInIf.instructions +++ b/compiler/testData/cfg-variables/bugs/varInitializationInIf.instructions @@ -15,9 +15,9 @@ L0: 2 mark({ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) }) v(val b: Boolean) INIT: in: {} out: {b=D} mark(if (1 < 2) { b = false } else { b = true }) INIT: in: {b=D} out: {b=D} - mark(1 < 2) r(1) -> r(2) -> + mark(1 < 2) call(<, compareTo|, ) -> jf(L2|) 3 mark({ b = false }) @@ -29,10 +29,10 @@ L2: r(true) -> USE: in: {b=WRITTEN_AFTER_READ} out: {b=WRITTEN_AFTER_READ} w(b|) INIT: in: {b=D} out: {b=ID} USE: in: {b=READ} out: {b=WRITTEN_AFTER_READ} L3: - 2 mark(use(b)) INIT: in: {b=ID} out: {b=ID} - error(use, No resolved call) USE: in: {b=READ} out: {b=READ} + 2 error(use, No resolved call) INIT: in: {b=ID} out: {b=ID} USE: in: {b=READ} out: {b=READ} r(b) -> USE: in: {} out: {b=READ} error(use, No resolved call) + mark(use(b)) magic(use(b)|) -> L1: 1 INIT: in: {} out: {} diff --git a/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions index aaa804160de..6c56fdbdd94 100644 --- a/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions +++ b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions @@ -18,22 +18,22 @@ L0: v(numbers: Collection) INIT: in: {} out: {numbers=D} magic(numbers: Collection) -> INIT: in: {numbers=D} out: {numbers=D} w(numbers|) INIT: in: {numbers=D} out: {numbers=ID} - 2 mark({ for (i in numbers) { val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue } }) INIT: in: {numbers=ID} out: {numbers=ID} - 3 mark(for (i in numbers) { val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) USE: in: {numbers=READ} out: {numbers=READ} - r(numbers) -> USE: in: {} out: {numbers=READ} + 2 mark({ for (i in numbers) { val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue } }) INIT: in: {numbers=ID} out: {numbers=ID} USE: in: {numbers=READ} out: {numbers=READ} + 3 r(numbers) -> USE: in: {} out: {numbers=READ} v(i) INIT: in: {numbers=ID} out: {i=D, numbers=ID} L3: jmp?(L2) INIT: in: {i=D, numbers=ID} out: {i=D, numbers=ID} L4 [loop entry point]: L5 [body entry point]: magic(numbers|) -> - w(i|) INIT: in: {i=D, numbers=ID} out: {i=ID, numbers=ID} USE: in: {} out: {} - 4 mark({ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) INIT: in: {i=ID, numbers=ID} out: {i=ID, numbers=ID} + w(i|) INIT: in: {i=D, numbers=ID} out: {i=ID, numbers=ID} + mark(for (i in numbers) { val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) INIT: in: {i=ID, numbers=ID} out: {i=ID, numbers=ID} USE: in: {} out: {} + 4 mark({ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) continue }) v(val b: Boolean) INIT: in: {i=ID, numbers=ID} out: {b=D, i=ID, numbers=ID} mark(if (1 < 2) { b = false } else { b = true }) INIT: in: {b=D, i=ID, numbers=ID} out: {b=D, i=ID, numbers=ID} - mark(1 < 2) r(1) -> r(2) -> + mark(1 < 2) call(<, compareTo|, ) -> jf(L6|) 5 mark({ b = false }) @@ -45,8 +45,8 @@ L6: r(true) -> USE: in: {b=WRITTEN_AFTER_READ} out: {b=WRITTEN_AFTER_READ} w(b|) INIT: in: {b=D, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} USE: in: {b=READ} out: {b=WRITTEN_AFTER_READ} L7: - 4 mark(use(b)) INIT: in: {b=ID, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} USE: in: {b=READ} out: {b=READ} - r(b) -> USE: in: {} out: {b=READ} + 4 r(b) -> INIT: in: {b=ID, i=ID, numbers=ID} out: {b=ID, i=ID, numbers=ID} USE: in: {} out: {b=READ} + mark(use(b)) call(use, use|) -> jmp(L4 [loop entry point]) USE: in: {} out: {} - 3 jmp?(L4 [loop entry point]) diff --git a/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.instructions index 7708be03b46..4825042e39c 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.instructions @@ -20,9 +20,9 @@ L4 [body entry point]: r(2) -> w(a|) L5 [condition entry point]: - mark(a > 0) r(a) -> r(0) -> + mark(a > 0) call(>, compareTo|, ) -> jt(L2 [loop entry point]|) USE: in: {a=READ} out: {a=READ} L3 [loop exit point]: diff --git a/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions index c9152b6723d..a061ddc9d89 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/forScope.instructions @@ -12,10 +12,9 @@ L0: 2 mark({ "before" for (i in 1..10) { val a = i } "after" }) mark("before") r("before") -> USE: in: {} out: {} - 3 mark(for (i in 1..10) { val a = i }) - mark(1..10) - r(1) -> + 3 r(1) -> r(10) -> + mark(1..10) call(.., rangeTo|, ) -> v(i) INIT: in: {} out: {i=D} L3: @@ -24,7 +23,8 @@ L4 [loop entry point]: L5 [body entry point]: magic(1..10|) -> w(i|) INIT: in: {i=D} out: {i=ID} - 4 mark({ val a = i }) INIT: in: {i=ID} out: {i=ID} + mark(for (i in 1..10) { val a = i }) INIT: in: {i=ID} out: {i=ID} + 4 mark({ val a = i }) v(val a = i) INIT: in: {i=ID} out: {a=D, i=ID} r(i) -> INIT: in: {a=D, i=ID} out: {a=D, i=ID} w(a|) INIT: in: {a=D, i=ID} out: {a=ID, i=ID} diff --git a/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions index a9f72bf6857..ad9463aaccc 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions @@ -43,10 +43,10 @@ L3: magic(x: Int) -> INIT: in: {x=D} out: {x=D} w(x|) INIT: in: {x=D} out: {x=ID} 4 mark(val a = x + b) INIT: in: {x=ID} out: {x=ID} - v(val a = x + b) INIT: in: {x=ID} out: {a=D, x=ID} - mark(x + b) INIT: in: {a=D, x=ID} out: {a=D, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ} - r(x) -> USE: in: {b=READ} out: {b=READ, x=READ} + v(val a = x + b) INIT: in: {x=ID} out: {a=D, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ} + r(x) -> INIT: in: {a=D, x=ID} out: {a=D, x=ID} USE: in: {b=READ} out: {b=READ, x=READ} r(b) -> USE: in: {} out: {b=READ} + mark(x + b) call(+, plus|, ) -> w(a|) INIT: in: {a=D, x=ID} out: {a=ID, x=ID} L4: diff --git a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions index fec9e2c51c1..e92d11ab224 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions @@ -39,10 +39,10 @@ L3: magic(x: Int) -> INIT: in: {x=D} out: {x=D} w(x|) INIT: in: {x=D} out: {x=ID} 4 mark({ val a = x + b }) INIT: in: {x=ID} out: {x=ID} - v(val a = x + b) INIT: in: {x=ID} out: {a=D, x=ID} - mark(x + b) INIT: in: {a=D, x=ID} out: {a=D, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ} - r(x) -> USE: in: {b=READ} out: {b=READ, x=READ} + v(val a = x + b) INIT: in: {x=ID} out: {a=D, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ} + r(x) -> INIT: in: {a=D, x=ID} out: {a=D, x=ID} USE: in: {b=READ} out: {b=READ, x=READ} r(b) -> USE: in: {} out: {b=READ} + mark(x + b) call(+, plus|, ) -> w(a|) INIT: in: {a=D, x=ID} out: {a=ID, x=ID} L4: diff --git a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.instructions b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.instructions index 38ee650f5a1..6053403f52c 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.instructions @@ -33,10 +33,10 @@ L3: 3 INIT: in: {} out: {} v(x: Int) INIT: in: {} out: {x=D} magic(x: Int) -> INIT: in: {x=D} out: {x=D} - w(x|) INIT: in: {x=D} out: {x=ID} - mark(x + b) INIT: in: {x=ID} out: {x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ} - r(x) -> USE: in: {b=READ} out: {b=READ, x=READ} + w(x|) INIT: in: {x=D} out: {x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ} + r(x) -> INIT: in: {x=ID} out: {x=ID} USE: in: {b=READ} out: {b=READ, x=READ} r(b) -> USE: in: {} out: {b=READ} + mark(x + b) call(+, plus|, ) -> L4: diff --git a/compiler/testData/cfg-variables/lexicalScopes/whileScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/whileScope.instructions index 50d2a76ed4b..2dec72a8ad3 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/whileScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/whileScope.instructions @@ -12,10 +12,10 @@ L0: 2 mark({ "before" while (true) { val a: Int } "after" }) mark("before") r("before") -> - mark(while (true) { val a: Int }) L2 [loop entry point]: L5 [condition entry point]: r(true) -> + mark(while (true) { val a: Int }) L4 [body entry point]: 3 mark({ val a: Int }) v(val a: Int) INIT: in: {} out: {a=D} diff --git a/compiler/testData/cfg/arrays/ArrayAccess.instructions b/compiler/testData/cfg/arrays/ArrayAccess.instructions index 67a47d4ca48..0e7994e6ff5 100644 --- a/compiler/testData/cfg/arrays/ArrayAccess.instructions +++ b/compiler/testData/cfg/arrays/ArrayAccess.instructions @@ -26,14 +26,16 @@ L0: mark(a[10]) r(a) -> r(10) -> + mark(a[10]) call(a[10], get|, ) -> r(100) -> - mark(a[10] += 1) mark(a[10]) r(a) -> r(10) -> + mark(a[10]) call(a[10], get|, ) -> r(1) -> + mark(a[10] += 1) call(+=, plus|, ) -> r(a) -> r(10) -> diff --git a/compiler/testData/cfg/arrays/ArrayOfFunctions.instructions b/compiler/testData/cfg/arrays/ArrayOfFunctions.instructions index 4b5c97d2f60..94932e91ba4 100644 --- a/compiler/testData/cfg/arrays/ArrayOfFunctions.instructions +++ b/compiler/testData/cfg/arrays/ArrayOfFunctions.instructions @@ -9,12 +9,13 @@ L0: magic(array: Array<(Int)->Unit>) -> w(array|) 2 mark({ array[11](3) }) - mark(array[11](3)) mark(array[11]) r(array) -> r(11) -> + mark(array[11]) call(array[11], get|, ) -> r(3) -> + mark(array[11](3)) call(array[11], invoke|, ) -> L1: 1 NEXT:[] diff --git a/compiler/testData/cfg/arrays/arrayAccessExpression.instructions b/compiler/testData/cfg/arrays/arrayAccessExpression.instructions index 6ac16f85361..31b610d5143 100644 --- a/compiler/testData/cfg/arrays/arrayAccessExpression.instructions +++ b/compiler/testData/cfg/arrays/arrayAccessExpression.instructions @@ -37,10 +37,11 @@ L0: 2 mark({ ab.getArray()[1] }) mark(ab.getArray()[1]) mark(ab.getArray()) - mark(getArray()) r(ab) -> + mark(getArray()) call(getArray, getArray|) -> r(1) -> + mark(ab.getArray()[1]) call(ab.getArray()[1], get|, ) -> L1: 1 NEXT:[] diff --git a/compiler/testData/cfg/arrays/arrayInc.instructions b/compiler/testData/cfg/arrays/arrayInc.instructions index 05096066b52..5916a920d52 100644 --- a/compiler/testData/cfg/arrays/arrayInc.instructions +++ b/compiler/testData/cfg/arrays/arrayInc.instructions @@ -9,11 +9,12 @@ L0: magic(a: Array) -> w(a|) 2 mark({ a[0]++ }) - mark(a[0]++) mark(a[0]) r(a) -> r(0) -> + mark(a[0]) call(a[0], get|, ) -> + mark(a[0]++) call(++, inc|) -> r(a) -> r(0) -> diff --git a/compiler/testData/cfg/arrays/arraySetPlusAssign.instructions b/compiler/testData/cfg/arrays/arraySetPlusAssign.instructions index e5629e1ca6a..4c01b6ae3ed 100644 --- a/compiler/testData/cfg/arrays/arraySetPlusAssign.instructions +++ b/compiler/testData/cfg/arrays/arraySetPlusAssign.instructions @@ -9,12 +9,13 @@ L0: magic(a: Array) -> w(a|) 2 mark({ a[0] += 1 }) - mark(a[0] += 1) mark(a[0]) r(a) -> r(0) -> + mark(a[0]) call(a[0], get|, ) -> r(1) -> + mark(a[0] += 1) call(+=, plus|, ) -> r(a) -> r(0) -> diff --git a/compiler/testData/cfg/basic/Basic.instructions b/compiler/testData/cfg/basic/Basic.instructions index 1283ba8fa66..6962e4a033a 100644 --- a/compiler/testData/cfg/basic/Basic.instructions +++ b/compiler/testData/cfg/basic/Basic.instructions @@ -26,34 +26,34 @@ L0: r(1) -> r(a) -> mark(2.toLong()) - mark(toLong()) r(2) -> + mark(toLong()) call(toLong, toLong|) -> - mark(foo(a, 3)) r(a) -> r(3) -> + mark(foo(a, 3)) call(foo, foo|, ) -> mark(genfun()) call(genfun, genfun) -> - mark(flfun {1}) mark({1}) jmp?(L2) NEXT:[r({1}) -> , d({1})] d({1}) NEXT:[] L2: r({1}) -> PREV:[jmp?(L2)] + mark(flfun {1}) call(flfun, flfun|) -> mark(3.equals(4)) - mark(equals(4)) r(3) -> r(4) -> + mark(equals(4)) call(equals, equals|, ) -> - mark(3 equals 4) r(3) -> r(4) -> + mark(3 equals 4) call(equals, equals|, ) -> - mark(1 + 2) r(1) -> r(2) -> + mark(1 + 2) call(+, plus|, ) -> r(a) -> jf(L5|) NEXT:[magic(a && true|, ) -> , r(true) -> ] diff --git a/compiler/testData/cfg/bugs/jumpToOuterScope.instructions b/compiler/testData/cfg/bugs/jumpToOuterScope.instructions index b8644228f64..018c604f721 100644 --- a/compiler/testData/cfg/bugs/jumpToOuterScope.instructions +++ b/compiler/testData/cfg/bugs/jumpToOuterScope.instructions @@ -13,8 +13,7 @@ L0: magic(c: Collection) -> w(c|) 2 mark({ for (e in c) { { break } } }) - 3 mark(for (e in c) { { break } }) - r(c) -> + 3 r(c) -> v(e) L3: jmp?(L2) NEXT:[read (Unit), magic(c|) -> ] @@ -22,6 +21,7 @@ L4 [loop entry point]: L5 [body entry point]: magic(c|) -> PREV:[jmp?(L2), jmp?(L4 [loop entry point])] w(e|) + mark(for (e in c) { { break } }) 4 mark({ { break } }) mark({ break }) jmp?(L6) NEXT:[r({ break }) -> , d({ break })] diff --git a/compiler/testData/cfg/controlStructures/Finally.instructions b/compiler/testData/cfg/controlStructures/Finally.instructions index 05e80d05c0e..07f32055e00 100644 --- a/compiler/testData/cfg/controlStructures/Finally.instructions +++ b/compiler/testData/cfg/controlStructures/Finally.instructions @@ -51,9 +51,9 @@ L0: 3 mark({ 1 if (2 > 3) { return } }) r(1) -> mark(if (2 > 3) { return }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L3|) NEXT:[read (Unit), mark({ return })] 4 mark({ return }) @@ -136,9 +136,9 @@ L4: 4 5 mark(if (2 > 3) { return@l }) mark(if (2 > 3) { return@l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L6|) NEXT:[read (Unit), mark({ return@l })] 6 mark({ return@l }) @@ -204,9 +204,9 @@ L3: 5 mark({ 1 if (2 > 3) { return@l } }) r(1) -> mark(if (2 > 3) { return@l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L6|) NEXT:[read (Unit), mark({ return@l })] 6 mark({ return@l }) @@ -252,10 +252,10 @@ L0: 1 2 mark({ @l while(true) { try { 1 if (2 > 3) { break @l } } finally { 2 } } }) mark(@l while(true) { try { 1 if (2 > 3) { break @l } } finally { 2 } }) - mark(while(true) { try { 1 if (2 > 3) { break @l } } finally { 2 } }) L2 [loop entry point]: L5 [condition entry point]: - r(true) -> PREV:[mark(while(true) { try { 1 if (2 > 3) { break @l } } finally { 2 } }), jmp(L2 [loop entry point])] + r(true) -> PREV:[mark(@l while(true) { try { 1 if (2 > 3) { break @l } } finally { 2 } }), jmp(L2 [loop entry point])] + mark(while(true) { try { 1 if (2 > 3) { break @l } } finally { 2 } }) L4 [body entry point]: 3 mark({ try { 1 if (2 > 3) { break @l } } finally { 2 } }) mark(try { 1 if (2 > 3) { break @l } } finally { 2 }) @@ -263,9 +263,9 @@ L4 [body entry point]: 4 mark({ 1 if (2 > 3) { break @l } }) r(1) -> mark(if (2 > 3) { break @l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L7|) NEXT:[read (Unit), mark({ break @l })] 5 mark({ break @l }) @@ -318,17 +318,17 @@ L0: jmp?(L2 [onExceptionToFinallyBlock]) NEXT:[mark({ 2 }), mark({ @l while(true) { 1 if (2 > 3) { break @l } } 5 })] 3 mark({ @l while(true) { 1 if (2 > 3) { break @l } } 5 }) mark(@l while(true) { 1 if (2 > 3) { break @l } }) - mark(while(true) { 1 if (2 > 3) { break @l } }) L3 [loop entry point]: L6 [condition entry point]: - r(true) -> PREV:[mark(while(true) { 1 if (2 > 3) { break @l } }), jmp(L3 [loop entry point])] + r(true) -> PREV:[mark(@l while(true) { 1 if (2 > 3) { break @l } }), jmp(L3 [loop entry point])] + mark(while(true) { 1 if (2 > 3) { break @l } }) L5 [body entry point]: 4 mark({ 1 if (2 > 3) { break @l } }) r(1) -> mark(if (2 > 3) { break @l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L7|) NEXT:[read (Unit), mark({ break @l })] 5 mark({ break @l }) @@ -379,17 +379,17 @@ L0: jmp?(L2 [onExceptionToFinallyBlock]) NEXT:[mark({ 2 }), mark({ @l while(true) { 1 if (2 > 3) { break @l } } })] 3 mark({ @l while(true) { 1 if (2 > 3) { break @l } } }) mark(@l while(true) { 1 if (2 > 3) { break @l } }) - mark(while(true) { 1 if (2 > 3) { break @l } }) L3 [loop entry point]: L6 [condition entry point]: - r(true) -> PREV:[mark(while(true) { 1 if (2 > 3) { break @l } }), jmp(L3 [loop entry point])] + r(true) -> PREV:[mark(@l while(true) { 1 if (2 > 3) { break @l } }), jmp(L3 [loop entry point])] + mark(while(true) { 1 if (2 > 3) { break @l } }) L5 [body entry point]: 4 mark({ 1 if (2 > 3) { break @l } }) r(1) -> mark(if (2 > 3) { break @l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L7|) NEXT:[read (Unit), mark({ break @l })] 5 mark({ break @l }) @@ -439,10 +439,9 @@ L0: w(a|) 2 mark({ @l for (i in 1..a) { try { 1 if (2 > 3) { continue @l } } finally { 2 } } }) mark(@l for (i in 1..a) { try { 1 if (2 > 3) { continue @l } } finally { 2 } }) - 3 mark(for (i in 1..a) { try { 1 if (2 > 3) { continue @l } } finally { 2 } }) - mark(1..a) - r(1) -> + 3 r(1) -> r(a) -> + mark(1..a) call(.., rangeTo|, ) -> v(i) L3: @@ -451,15 +450,16 @@ L4 [loop entry point]: L5 [body entry point]: magic(1..a|) -> PREV:[jmp?(L2), jmp(L4 [loop entry point]), jmp?(L4 [loop entry point])] w(i|) + mark(for (i in 1..a) { try { 1 if (2 > 3) { continue @l } } finally { 2 } }) 4 mark({ try { 1 if (2 > 3) { continue @l } } finally { 2 } }) mark(try { 1 if (2 > 3) { continue @l } } finally { 2 }) jmp?(L6 [onExceptionToFinallyBlock]) NEXT:[mark({ 2 }), mark({ 1 if (2 > 3) { continue @l } })] 5 mark({ 1 if (2 > 3) { continue @l } }) r(1) -> mark(if (2 > 3) { continue @l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L7|) NEXT:[read (Unit), mark({ continue @l })] 6 mark({ continue @l }) @@ -515,10 +515,9 @@ L0: jmp?(L2 [onExceptionToFinallyBlock]) NEXT:[mark({ 2 }), mark({ @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 })] 3 mark({ @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 }) mark(@l for (i in 1..a) { 1 if (2 > 3) { continue @l } }) - 4 mark(for (i in 1..a) { 1 if (2 > 3) { continue @l } }) - mark(1..a) - r(1) -> + 4 r(1) -> r(a) -> + mark(1..a) call(.., rangeTo|, ) -> v(i) L4: @@ -527,12 +526,13 @@ L5 [loop entry point]: L6 [body entry point]: magic(1..a|) -> PREV:[jmp?(L3), jmp(L5 [loop entry point]), jmp?(L5 [loop entry point])] w(i|) + mark(for (i in 1..a) { 1 if (2 > 3) { continue @l } }) 5 mark({ 1 if (2 > 3) { continue @l } }) r(1) -> mark(if (2 > 3) { continue @l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L7|) NEXT:[read (Unit), mark({ continue @l })] 6 mark({ continue @l }) @@ -586,10 +586,9 @@ L0: jmp?(L2 [onExceptionToFinallyBlock]) NEXT:[mark({ 2 }), mark({ @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } })] 3 mark({ @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } }) mark(@l for (i in 1..a) { 1 if (2 > 3) { continue @l } }) - 4 mark(for (i in 1..a) { 1 if (2 > 3) { continue @l } }) - mark(1..a) - r(1) -> + 4 r(1) -> r(a) -> + mark(1..a) call(.., rangeTo|, ) -> v(i) L4: @@ -598,12 +597,13 @@ L5 [loop entry point]: L6 [body entry point]: magic(1..a|) -> PREV:[jmp?(L3), jmp(L5 [loop entry point]), jmp?(L5 [loop entry point])] w(i|) + mark(for (i in 1..a) { 1 if (2 > 3) { continue @l } }) 5 mark({ 1 if (2 > 3) { continue @l } }) r(1) -> mark(if (2 > 3) { continue @l }) - mark(2 > 3) r(2) -> r(3) -> + mark(2 > 3) call(>, compareTo|, ) -> jf(L7|) NEXT:[read (Unit), mark({ continue @l })] 6 mark({ continue @l }) @@ -691,22 +691,22 @@ L0: r(1) -> L3 [start finally]: 4 mark({ doSmth(3) }) - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> L4 [finish finally]: 3 ret(*|) L1 NEXT:[] - 2 jmp(L5 [skipFinallyToErrorBlock]) NEXT:[mark({ doSmth(3) })] PREV:[] L2 [onExceptionToFinallyBlock]: 4 mark({ doSmth(3) }) PREV:[jmp?(L2 [onExceptionToFinallyBlock])] - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> 2 jmp(error) NEXT:[] L5 [skipFinallyToErrorBlock]: - 4 mark({ doSmth(3) }) PREV:[] -- mark(doSmth(3)) PREV:[] - r(3) -> PREV:[] +- mark(doSmth(3)) PREV:[] - call(doSmth, doSmth|) -> PREV:[] L1: 1 NEXT:[] PREV:[ret(*|) L1] @@ -738,8 +738,8 @@ L0: r(1) -> L4 [start finally]: 4 mark({ doSmth(3) }) - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> L5 [finish finally]: 3 ret(*|) L1 NEXT:[] @@ -749,22 +749,22 @@ L2 [onException]: magic(e: UnsupportedOperationException) -> w(e|) 4 mark({ doSmth(2) }) - mark(doSmth(2)) r(2) -> + mark(doSmth(2)) call(doSmth, doSmth|) -> 3 jmp(L6 [afterCatches]) L6 [afterCatches]: 2 jmp(L7 [skipFinallyToErrorBlock]) NEXT:[mark({ doSmth(3) })] L3 [onExceptionToFinallyBlock]: 4 mark({ doSmth(3) }) PREV:[jmp?(L3 [onExceptionToFinallyBlock])] - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> 2 jmp(error) NEXT:[] L7 [skipFinallyToErrorBlock]: 4 mark({ doSmth(3) }) PREV:[jmp(L7 [skipFinallyToErrorBlock])] - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> L1: 1 NEXT:[] PREV:[ret(*|) L1, call(doSmth, doSmth|) -> ] @@ -797,8 +797,8 @@ L2 [onException]: magic(e: UnsupportedOperationException) -> w(e|) 4 mark({ doSmth(2) }) - mark(doSmth(2)) r(2) -> + mark(doSmth(2)) call(doSmth, doSmth|) -> 3 jmp(L3 [afterCatches]) L1: @@ -832,8 +832,8 @@ L0: r(1) -> L4 [start finally]: 4 mark({ doSmth(3) }) - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> L5 [finish finally]: 3 ret(*|) L1 NEXT:[] @@ -845,8 +845,8 @@ L2 [onException]: 4 mark({ return 2 }) r(2) -> mark({ doSmth(3) }) - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> ret(*|) L1 NEXT:[] - 3 jmp(L6 [afterCatches]) PREV:[] @@ -854,14 +854,14 @@ L6 [afterCatches]: - 2 jmp(L7 [skipFinallyToErrorBlock]) NEXT:[mark({ doSmth(3) })] PREV:[] L3 [onExceptionToFinallyBlock]: 4 mark({ doSmth(3) }) PREV:[jmp?(L3 [onExceptionToFinallyBlock])] - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> 2 jmp(error) NEXT:[] L7 [skipFinallyToErrorBlock]: - 4 mark({ doSmth(3) }) PREV:[] -- mark(doSmth(3)) PREV:[] - r(3) -> PREV:[] +- mark(doSmth(3)) PREV:[] - call(doSmth, doSmth|) -> PREV:[] L1: 1 NEXT:[] PREV:[ret(*|) L1, ret(*|) L1] @@ -890,8 +890,8 @@ L0: jmp?(L2 [onException]) NEXT:[v(e: UnsupportedOperationException), jmp?(L3 [onExceptionToFinallyBlock])] jmp?(L3 [onExceptionToFinallyBlock]) NEXT:[mark({ doSmth(3) }), mark({ doSmth(1) })] 3 mark({ doSmth(1) }) - mark(doSmth(1)) r(1) -> + mark(doSmth(1)) call(doSmth, doSmth|) -> 2 jmp(L4 [afterCatches]) NEXT:[jmp(L7 [skipFinallyToErrorBlock])] L2 [onException]: @@ -902,8 +902,8 @@ L2 [onException]: r(2) -> L5 [start finally]: 5 mark({ doSmth(3) }) - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> L6 [finish finally]: 4 ret(*|) L1 NEXT:[] @@ -912,14 +912,14 @@ L4 [afterCatches]: 2 jmp(L7 [skipFinallyToErrorBlock]) NEXT:[mark({ doSmth(3) })] PREV:[jmp(L4 [afterCatches])] L3 [onExceptionToFinallyBlock]: 5 mark({ doSmth(3) }) PREV:[jmp?(L3 [onExceptionToFinallyBlock])] - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> 2 jmp(error) NEXT:[] L7 [skipFinallyToErrorBlock]: 5 mark({ doSmth(3) }) PREV:[jmp(L7 [skipFinallyToErrorBlock])] - mark(doSmth(3)) r(3) -> + mark(doSmth(3)) call(doSmth, doSmth|) -> L1: 1 NEXT:[] PREV:[ret(*|) L1, call(doSmth, doSmth|) -> ] diff --git a/compiler/testData/cfg/controlStructures/FinallyTestCopy.instructions b/compiler/testData/cfg/controlStructures/FinallyTestCopy.instructions index 10fc552489d..1fab4a10d8b 100644 --- a/compiler/testData/cfg/controlStructures/FinallyTestCopy.instructions +++ b/compiler/testData/cfg/controlStructures/FinallyTestCopy.instructions @@ -140,11 +140,11 @@ fun testCopy2() { L0: 1 2 mark({ while (cond()) { try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } } }) - mark(while (cond()) { try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } }) L2 [loop entry point]: L5 [condition entry point]: - mark(cond()) PREV:[mark(while (cond()) { try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } }), jmp(L2 [loop entry point]), jmp(L2 [loop entry point])] + mark(cond()) PREV:[mark({ while (cond()) { try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } } }), jmp(L2 [loop entry point]), jmp(L2 [loop entry point])] call(cond, cond) -> + mark(while (cond()) { try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } }) jf(L3 [loop exit point]|) NEXT:[read (Unit), mark({ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } })] L4 [body entry point]: 3 mark({ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } }) @@ -256,11 +256,11 @@ L4 [afterCatches]: L3 [onExceptionToFinallyBlock]: L7 [start finally]: 3 mark({ while (cond()); }) PREV:[jmp?(L3 [onExceptionToFinallyBlock])] - mark(while (cond())) L8 [loop entry point]: L11 [condition entry point]: - mark(cond()) PREV:[mark(while (cond())), jmp(L8 [loop entry point])] + mark(cond()) PREV:[mark({ while (cond()); }), jmp(L8 [loop entry point])] call(cond, cond) -> + mark(while (cond())) jf(L9 [loop exit point]|) NEXT:[read (Unit), jmp(L8 [loop entry point])] L10 [body entry point]: jmp(L8 [loop entry point]) NEXT:[mark(cond())] @@ -270,9 +270,9 @@ L12 [finish finally]: 2 jmp(error) NEXT:[] L6 [skipFinallyToErrorBlock]: 3 mark({ while (cond()); }) PREV:[jmp(L6 [skipFinallyToErrorBlock])] - mark(while (cond())) - mark(cond()) PREV:[mark(while (cond())), jmp(copy L8 [loop entry point])] + mark(cond()) PREV:[mark({ while (cond()); }), jmp(copy L8 [loop entry point])] call(cond, cond) -> + mark(while (cond())) jf(copy L9 [loop exit point]|) NEXT:[read (Unit), jmp(copy L8 [loop entry point])] jmp(copy L8 [loop entry point]) NEXT:[mark(cond())] read (Unit) PREV:[jf(copy L9 [loop exit point]|)] @@ -311,9 +311,9 @@ L2 [onExceptionToFinallyBlock]: L4 [start finally]: 3 mark({ if(list != null) { } }) PREV:[jmp?(L2 [onExceptionToFinallyBlock])] mark(if(list != null) { }) - mark(list != null) r(list) -> r(null) -> + mark(list != null) call(!=, equals|, ) -> jf(L5|) NEXT:[read (Unit), mark({ })] 4 mark({ }) @@ -327,9 +327,9 @@ L7 [finish finally]: L3 [skipFinallyToErrorBlock]: 3 mark({ if(list != null) { } }) PREV:[jmp(L3 [skipFinallyToErrorBlock])] mark(if(list != null) { }) - mark(list != null) r(list) -> r(null) -> + mark(list != null) call(!=, equals|, ) -> jf(copy L5|) NEXT:[read (Unit), mark({ })] 4 mark({ }) diff --git a/compiler/testData/cfg/controlStructures/For.instructions b/compiler/testData/cfg/controlStructures/For.instructions index 4ef25287833..399d662f15f 100644 --- a/compiler/testData/cfg/controlStructures/For.instructions +++ b/compiler/testData/cfg/controlStructures/For.instructions @@ -8,10 +8,9 @@ fun t1() { L0: 1 2 mark({ for (i in 1..2) { doSmth(i) } }) - 3 mark(for (i in 1..2) { doSmth(i) }) - mark(1..2) - r(1) -> + 3 r(1) -> r(2) -> + mark(1..2) call(.., rangeTo|, ) -> v(i) L3: @@ -20,9 +19,10 @@ L4 [loop entry point]: L5 [body entry point]: magic(1..2|) -> PREV:[jmp?(L2), jmp?(L4 [loop entry point])] w(i|) + mark(for (i in 1..2) { doSmth(i) }) 4 mark({ doSmth(i) }) - mark(doSmth(i)) r(i) -> + mark(doSmth(i)) call(doSmth, doSmth|) -> 3 jmp?(L4 [loop entry point]) NEXT:[magic(1..2|) -> , read (Unit)] L2: diff --git a/compiler/testData/cfg/controlStructures/If.instructions b/compiler/testData/cfg/controlStructures/If.instructions index c99cbe8b258..3393470ce8a 100644 --- a/compiler/testData/cfg/controlStructures/If.instructions +++ b/compiler/testData/cfg/controlStructures/If.instructions @@ -30,12 +30,12 @@ L0: mark("s") r("s") -> w(u|) - 2 jmp(L3) NEXT:[mark(doSmth(u))] + 2 jmp(L3) NEXT:[r(u) -> ] L2: read (Unit) PREV:[jf(L2|)] L3: - mark(doSmth(u)) PREV:[jmp(L3), read (Unit)] - r(u) -> + r(u) -> PREV:[jmp(L3), read (Unit)] + mark(doSmth(u)) call(doSmth, doSmth|) -> v(var r: String) mark(if (b) { r = "s" } else { r = "t" }) @@ -45,15 +45,15 @@ L3: mark("s") r("s") -> w(r|) - 2 jmp(L5) NEXT:[mark(doSmth(r))] + 2 jmp(L5) NEXT:[r(r) -> ] L4: 3 mark({ r = "t" }) PREV:[jf(L4|)] mark("t") r("t") -> w(r|) L5: - 2 mark(doSmth(r)) PREV:[jmp(L5), w(r|)] - r(r) -> + 2 r(r) -> PREV:[jmp(L5), w(r|)] + mark(doSmth(r)) call(doSmth, doSmth|) -> L1: 1 NEXT:[] @@ -88,12 +88,12 @@ L0: jf(L2|) NEXT:[read (Unit), mark({ return; })] 3 mark({ return; }) ret L1 NEXT:[] -- 2 jmp(L3) NEXT:[mark(doSmth(i))] PREV:[] +- 2 jmp(L3) NEXT:[r(i) -> ] PREV:[] L2: read (Unit) PREV:[jf(L2|)] L3: - mark(doSmth(i)) r(i) -> + mark(doSmth(i)) call(doSmth, doSmth|) -> mark(if (i is Int) { return; }) mark(i is Int) diff --git a/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.instructions b/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.instructions index 9d727a8c2f8..452cda3860e 100644 --- a/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.instructions +++ b/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.instructions @@ -8,18 +8,18 @@ fun main() { L0: 1 2 mark({ while(0 > 1) { 2 } }) - mark(while(0 > 1) { 2 }) L2 [loop entry point]: L5 [condition entry point]: - mark(0 > 1) PREV:[mark(while(0 > 1) { 2 }), jmp(L2 [loop entry point])] - r(0) -> + r(0) -> PREV:[mark({ while(0 > 1) { 2 } }), jmp(L2 [loop entry point])] r(1) -> + mark(0 > 1) call(>, compareTo|, ) -> + mark(while(0 > 1) { 2 }) jf(L3 [loop exit point]|) NEXT:[read (Unit), mark({ 2 })] L4 [body entry point]: 3 mark({ 2 }) r(2) -> - 2 jmp(L2 [loop entry point]) NEXT:[mark(0 > 1)] + 2 jmp(L2 [loop entry point]) NEXT:[r(0) -> ] L3 [loop exit point]: read (Unit) PREV:[jf(L3 [loop exit point]|)] L1: @@ -44,9 +44,9 @@ L4 [body entry point]: mark({return}) ret L1 NEXT:[] L5 [condition entry point]: -- mark(0 > 1) PREV:[] - r(0) -> PREV:[] - r(1) -> PREV:[] +- mark(0 > 1) PREV:[] - call(>, compareTo|, ) -> PREV:[] - jt(L2 [loop entry point]|) NEXT:[read (Unit), mark({return})] PREV:[] L3 [loop exit point]: diff --git a/compiler/testData/cfg/conventions/equals.instructions b/compiler/testData/cfg/conventions/equals.instructions index 5151be2fd13..d8431a598c6 100644 --- a/compiler/testData/cfg/conventions/equals.instructions +++ b/compiler/testData/cfg/conventions/equals.instructions @@ -14,9 +14,9 @@ L0: w(b|) 2 mark({ if (a == b) { } }) mark(if (a == b) { }) - mark(a == b) r(a) -> r(b) -> + mark(a == b) call(==, equals|, ) -> jf(L2|) NEXT:[read (Unit), mark({ })] 3 mark({ }) diff --git a/compiler/testData/cfg/conventions/incrementAtTheEnd.instructions b/compiler/testData/cfg/conventions/incrementAtTheEnd.instructions index 7ea1808d900..030decbcc89 100644 --- a/compiler/testData/cfg/conventions/incrementAtTheEnd.instructions +++ b/compiler/testData/cfg/conventions/incrementAtTheEnd.instructions @@ -10,8 +10,8 @@ L0: v(var i = 1) r(1) -> w(i|) - mark(i++) r(i) -> + mark(i++) call(++, inc|) -> w(i|) L1: diff --git a/compiler/testData/cfg/conventions/invoke.instructions b/compiler/testData/cfg/conventions/invoke.instructions index cababa1643f..9c282e0116d 100644 --- a/compiler/testData/cfg/conventions/invoke.instructions +++ b/compiler/testData/cfg/conventions/invoke.instructions @@ -9,8 +9,8 @@ L0: magic(f: () -> Unit) -> w(f|) 2 mark({ f() }) - mark(f()) r(f) -> + mark(f()) call(f, invoke|) -> L1: 1 NEXT:[] diff --git a/compiler/testData/cfg/conventions/notEqual.instructions b/compiler/testData/cfg/conventions/notEqual.instructions index 83685976b4b..98d8a17ae84 100644 --- a/compiler/testData/cfg/conventions/notEqual.instructions +++ b/compiler/testData/cfg/conventions/notEqual.instructions @@ -13,9 +13,9 @@ L0: w(b|) 2 mark({ if (a != b) {} }) mark(if (a != b) {}) - mark(a != b) r(a) -> r(b) -> + mark(a != b) call(!=, equals|, ) -> jf(L2|) NEXT:[read (Unit), mark({})] 3 mark({}) diff --git a/compiler/testData/cfg/deadCode/returnInElvis.instructions b/compiler/testData/cfg/deadCode/returnInElvis.instructions index dc75bf6ae3f..a8837e2cd21 100644 --- a/compiler/testData/cfg/deadCode/returnInElvis.instructions +++ b/compiler/testData/cfg/deadCode/returnInElvis.instructions @@ -7,6 +7,7 @@ L0: 1 2 mark({ return ?: null }) ret L1 NEXT:[] +- mark(return ?: null) PREV:[] - jt(L2) NEXT:[r(null) -> , ] PREV:[] - r(null) -> PREV:[] L1: diff --git a/compiler/testData/cfg/declarations/local/ObjectExpression.instructions b/compiler/testData/cfg/declarations/local/ObjectExpression.instructions index 806b47a8c84..11cf0c848e9 100644 --- a/compiler/testData/cfg/declarations/local/ObjectExpression.instructions +++ b/compiler/testData/cfg/declarations/local/ObjectExpression.instructions @@ -70,8 +70,8 @@ L0: r(object : A by b {}) -> w(o|) mark(o.foo()) - mark(foo()) r(o) -> + mark(foo()) call(foo, foo|) -> ret(*|) L1 L1: diff --git a/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.instructions b/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.instructions index 7f0b2a4f09d..2f8dbad732c 100644 --- a/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.instructions +++ b/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.instructions @@ -19,12 +19,12 @@ fun foo() = "foo" + this.$bar --------------------- L0: 1 - mark("foo" + this.$bar) mark("foo") r("foo") -> mark(this.$bar) r(this) -> r($bar|) -> + mark("foo" + this.$bar) call(+, plus|, ) -> L1: NEXT:[] diff --git a/compiler/testData/cfg/expressions/Assignments.instructions b/compiler/testData/cfg/expressions/Assignments.instructions index f2c24747477..a9368b3d1f3 100644 --- a/compiler/testData/cfg/expressions/Assignments.instructions +++ b/compiler/testData/cfg/expressions/Assignments.instructions @@ -37,9 +37,9 @@ L0: w(x|) r(2) -> w(x|) - mark(x += 2) r(x) -> r(2) -> + mark(x += 2) call(+=, plus|, ) -> w(x|) mark(if (true) 1 else 2) @@ -73,11 +73,11 @@ L5: r(t) -> r(1) -> w(t.x|, ) - mark(t.x += 1) mark(t.x) r(t) -> r(x|) -> r(1) -> + mark(t.x += 1) call(+=, plus|, ) -> r(t) -> w(t.x|, ) diff --git a/compiler/testData/cfg/expressions/chainedQualifiedExpression.instructions b/compiler/testData/cfg/expressions/chainedQualifiedExpression.instructions index dd79aa7acbc..427a9c29ff2 100644 --- a/compiler/testData/cfg/expressions/chainedQualifiedExpression.instructions +++ b/compiler/testData/cfg/expressions/chainedQualifiedExpression.instructions @@ -65,158 +65,158 @@ L0: r(1.0) -> w(inTopLevel|) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode) .registerAll()) - mark(registerAll()) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode)) - mark(add(OBJECT_KEYWORD, unresolvedCode)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel)) - mark(add(OUT_KEYWORD, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel)) - mark(add(IN_KEYWORD, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel)) - mark(add(OVERRIDE_KEYWORD, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel)) - mark(add(PACKAGE_KEYWORD, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel)) - mark(add(IMPORT_KEYWORD, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) - mark(add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) - mark(add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) - mark(add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) - mark(add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) mark(BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) - mark(BunchKeywordRegister()) magic(BunchKeywordRegister()) -> + mark(BunchKeywordRegister()) call(BunchKeywordRegister, |) -> r(ABSTRACT_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(FINAL_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(OPEN_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(INTERNAL_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , , ) -> r(PRIVATE_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , , ) -> r(PROTECTED_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , , ) -> r(PUBLIC_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , , ) -> r(CLASS_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(ENUM_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(FUN_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(GET_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(SET_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(TRAIT_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(VAL_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(VAR_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(TYPE_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel)) call(add, add|, , , , ) -> r(IMPORT_KEYWORD) -> r(inTopLevel) -> + mark(add(IMPORT_KEYWORD, inTopLevel)) call(add, add|, , ) -> r(PACKAGE_KEYWORD) -> r(inTopLevel) -> + mark(add(PACKAGE_KEYWORD, inTopLevel)) call(add, add|, , ) -> r(OVERRIDE_KEYWORD) -> r(inTopLevel) -> + mark(add(OVERRIDE_KEYWORD, inTopLevel)) call(add, add|, , ) -> r(IN_KEYWORD) -> r(inTopLevel) -> r(inTopLevel) -> + mark(add(IN_KEYWORD, inTopLevel, inTopLevel)) call(add, add|, , , ) -> r(OUT_KEYWORD) -> r(inTopLevel) -> + mark(add(OUT_KEYWORD, inTopLevel)) call(add, add|, , ) -> r(OBJECT_KEYWORD) -> error(unresolvedCode, No resolved call) magic(unresolvedCode) -> + mark(add(OBJECT_KEYWORD, unresolvedCode)) call(add, add|, , ) -> + mark(registerAll()) call(registerAll, registerAll|) -> L1: 1 NEXT:[] diff --git a/compiler/testData/cfg/expressions/expressionAsFunction.instructions b/compiler/testData/cfg/expressions/expressionAsFunction.instructions index 44b62d7531e..b83a5ff8b36 100644 --- a/compiler/testData/cfg/expressions/expressionAsFunction.instructions +++ b/compiler/testData/cfg/expressions/expressionAsFunction.instructions @@ -9,9 +9,9 @@ L0: magic(f: () -> Unit) -> w(f|) 2 mark({ (f)() }) - mark((f)()) mark((f)) r(f) -> + mark((f)()) call((f), invoke|) -> L1: 1 NEXT:[] diff --git a/compiler/testData/cfg/expressions/nothingExpr.instructions b/compiler/testData/cfg/expressions/nothingExpr.instructions index ad4f0bf0576..21a743f846e 100644 --- a/compiler/testData/cfg/expressions/nothingExpr.instructions +++ b/compiler/testData/cfg/expressions/nothingExpr.instructions @@ -38,16 +38,16 @@ L0: 1 2 mark({ null!!.doSomething() bar().doSomething }) mark(null!!.doSomething()) - mark(doSomething()) - mark(null!!) r(null) -> magic(null!!|) -> jmp(error) NEXT:[] +- mark(doSomething()) PREV:[] - call(doSomething, doSomething|) -> PREV:[] - mark(bar().doSomething) PREV:[] - mark(bar()) PREV:[] - call(bar, bar) PREV:[] - jmp(error) NEXT:[] PREV:[] +- mark(doSomething) PREV:[] - call(doSomething, doSomething) -> PREV:[] L1: 1 NEXT:[] PREV:[] diff --git a/compiler/testData/cfg/expressions/unresolvedCall.instructions b/compiler/testData/cfg/expressions/unresolvedCall.instructions index 9bf196dff93..3bfc2044c02 100644 --- a/compiler/testData/cfg/expressions/unresolvedCall.instructions +++ b/compiler/testData/cfg/expressions/unresolvedCall.instructions @@ -10,10 +10,10 @@ L0: w(a|) 2 mark({ a.foo() }) mark(a.foo()) - mark(foo()) error(foo, No resolved call) error(foo, No resolved call) r(a) -> + mark(foo()) magic(foo()|) -> L1: 1 NEXT:[] diff --git a/compiler/testData/cfg/tailCalls/sum.instructions b/compiler/testData/cfg/tailCalls/sum.instructions index 80567d12824..ce457b14d51 100644 --- a/compiler/testData/cfg/tailCalls/sum.instructions +++ b/compiler/testData/cfg/tailCalls/sum.instructions @@ -14,29 +14,29 @@ L0: w(sum|) 2 mark({ if (x == 0.toLong()) return sum return sum(x - 1, sum + x) }) mark(if (x == 0.toLong()) return sum) - mark(x == 0.toLong()) r(x) -> mark(0.toLong()) - mark(toLong()) r(0) -> + mark(toLong()) call(toLong, toLong|) -> + mark(x == 0.toLong()) call(==, equals|, ) -> jf(L2|) NEXT:[read (Unit), r(sum) -> ] r(sum) -> ret(*|) L1 NEXT:[] -- jmp(L3) NEXT:[mark(sum(x - 1, sum + x))] PREV:[] +- jmp(L3) NEXT:[r(x) -> ] PREV:[] L2: read (Unit) PREV:[jf(L2|)] L3: - mark(sum(x - 1, sum + x)) - mark(x - 1) r(x) -> r(1) -> + mark(x - 1) call(-, minus|, ) -> - mark(sum + x) r(sum) -> r(x) -> + mark(sum + x) call(+, plus|, ) -> + mark(sum(x - 1, sum + x)) call(sum, sum|, ) -> ret(*|) L1 L1: From 88ecc5cc59511d9a973da59cc988b2b98e960a5b Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Thu, 12 Jun 2014 13:03:59 +0400 Subject: [PATCH 007/143] Evaluate default value for argument non-deterministically in pseudocode --- .../jet/lang/cfg/JetControlFlowProcessor.java | 3 +++ .../DefaultValuesForArguments.instructions | 22 +++++++++++++++++++ .../functions/DefaultValuesForArguments.kt | 1 + .../DefaultValuesForArguments.values | 8 +++++++ .../jet/cfg/ControlFlowTestGenerated.java | 16 +++++++++++++- .../jet/cfg/PseudoValueTestGenerated.java | 16 +++++++++++++- 6 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/cfg/functions/DefaultValuesForArguments.instructions create mode 100644 compiler/testData/cfg/functions/DefaultValuesForArguments.kt create mode 100644 compiler/testData/cfg/functions/DefaultValuesForArguments.values diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 1cc0a9090fb..aa28746f47a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -1001,7 +1001,10 @@ public class JetControlFlowProcessor { builder.declareParameter(parameter); JetExpression defaultValue = parameter.getDefaultValue(); if (defaultValue != null) { + Label skipDefaultValue = builder.createUnboundLabel("after default value for parameter " + parameter.getName()); + builder.nondeterministicJump(skipDefaultValue, defaultValue, null); generateInstructions(defaultValue, context); + builder.bindLabel(skipDefaultValue); } generateInitializer(parameter, createSyntheticValue(parameter)); } diff --git a/compiler/testData/cfg/functions/DefaultValuesForArguments.instructions b/compiler/testData/cfg/functions/DefaultValuesForArguments.instructions new file mode 100644 index 00000000000..a42371f93ab --- /dev/null +++ b/compiler/testData/cfg/functions/DefaultValuesForArguments.instructions @@ -0,0 +1,22 @@ +== foo == +fun foo(i: Int = 1) = i + 2 +--------------------- +L0: + 1 + v(i: Int = 1) + jmp?(L2 [after default value for parameter i]) NEXT:[magic(i: Int = 1) -> , r(1) -> ] + r(1) -> +L2 [after default value for parameter i]: + magic(i: Int = 1) -> PREV:[jmp?(L2 [after default value for parameter i]), r(1) -> ] + w(i|) + r(i) -> + r(2) -> + mark(i + 2) + call(+, plus|, ) -> +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/functions/DefaultValuesForArguments.kt b/compiler/testData/cfg/functions/DefaultValuesForArguments.kt new file mode 100644 index 00000000000..3b6a8f9835c --- /dev/null +++ b/compiler/testData/cfg/functions/DefaultValuesForArguments.kt @@ -0,0 +1 @@ +fun foo(i: Int = 1) = i + 2 \ No newline at end of file diff --git a/compiler/testData/cfg/functions/DefaultValuesForArguments.values b/compiler/testData/cfg/functions/DefaultValuesForArguments.values new file mode 100644 index 00000000000..4c5426bd1d6 --- /dev/null +++ b/compiler/testData/cfg/functions/DefaultValuesForArguments.values @@ -0,0 +1,8 @@ +== foo == +fun foo(i: Int = 1) = i + 2 +--------------------- +1 NEW() +i NEW() +2 NEW() +i + 2 NEW(, ) +===================== diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index 5d9e7198df8..597bde87fe3 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.cfg.AbstractControlFlowTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/cfg") -@InnerTestClasses({ControlFlowTestGenerated.Arrays.class, ControlFlowTestGenerated.Basic.class, ControlFlowTestGenerated.Bugs.class, ControlFlowTestGenerated.ControlStructures.class, ControlFlowTestGenerated.Conventions.class, ControlFlowTestGenerated.DeadCode.class, ControlFlowTestGenerated.Declarations.class, ControlFlowTestGenerated.Expressions.class, ControlFlowTestGenerated.TailCalls.class}) +@InnerTestClasses({ControlFlowTestGenerated.Arrays.class, ControlFlowTestGenerated.Basic.class, ControlFlowTestGenerated.Bugs.class, ControlFlowTestGenerated.ControlStructures.class, ControlFlowTestGenerated.Conventions.class, ControlFlowTestGenerated.DeadCode.class, ControlFlowTestGenerated.Declarations.class, ControlFlowTestGenerated.Expressions.class, ControlFlowTestGenerated.Functions.class, ControlFlowTestGenerated.TailCalls.class}) public class ControlFlowTestGenerated extends AbstractControlFlowTest { public void testAllFilesPresentInCfg() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg"), Pattern.compile("^(.+)\\.kt$"), true); @@ -406,6 +406,19 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { } + @TestMetadata("compiler/testData/cfg/functions") + public static class Functions extends AbstractControlFlowTest { + public void testAllFilesPresentInFunctions() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg/functions"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("DefaultValuesForArguments.kt") + public void testDefaultValuesForArguments() throws Exception { + doTest("compiler/testData/cfg/functions/DefaultValuesForArguments.kt"); + } + + } + @TestMetadata("compiler/testData/cfg/tailCalls") public static class TailCalls extends AbstractControlFlowTest { public void testAllFilesPresentInTailCalls() throws Exception { @@ -450,6 +463,7 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { suite.addTestSuite(DeadCode.class); suite.addTest(Declarations.innerSuite()); suite.addTestSuite(Expressions.class); + suite.addTestSuite(Functions.class); suite.addTestSuite(TailCalls.class); return suite; } diff --git a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java index cbe2296d004..4a9f13962dc 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java @@ -33,7 +33,7 @@ import org.jetbrains.jet.cfg.AbstractPseudoValueTest; @InnerTestClasses({PseudoValueTestGenerated.Cfg.class, PseudoValueTestGenerated.Cfg_variables.class}) public class PseudoValueTestGenerated extends AbstractPseudoValueTest { @TestMetadata("compiler/testData/cfg") - @InnerTestClasses({Cfg.Arrays.class, Cfg.Basic.class, Cfg.Bugs.class, Cfg.ControlStructures.class, Cfg.Conventions.class, Cfg.DeadCode.class, Cfg.Declarations.class, Cfg.Expressions.class, Cfg.TailCalls.class}) + @InnerTestClasses({Cfg.Arrays.class, Cfg.Basic.class, Cfg.Bugs.class, Cfg.ControlStructures.class, Cfg.Conventions.class, Cfg.DeadCode.class, Cfg.Declarations.class, Cfg.Expressions.class, Cfg.Functions.class, Cfg.TailCalls.class}) public static class Cfg extends AbstractPseudoValueTest { public void testAllFilesPresentInCfg() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg"), Pattern.compile("^(.+)\\.kt$"), true); @@ -408,6 +408,19 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { } + @TestMetadata("compiler/testData/cfg/functions") + public static class Functions extends AbstractPseudoValueTest { + public void testAllFilesPresentInFunctions() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg/functions"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("DefaultValuesForArguments.kt") + public void testDefaultValuesForArguments() throws Exception { + doTest("compiler/testData/cfg/functions/DefaultValuesForArguments.kt"); + } + + } + @TestMetadata("compiler/testData/cfg/tailCalls") public static class TailCalls extends AbstractPseudoValueTest { public void testAllFilesPresentInTailCalls() throws Exception { @@ -452,6 +465,7 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { suite.addTestSuite(DeadCode.class); suite.addTest(Declarations.innerSuite()); suite.addTestSuite(Expressions.class); + suite.addTestSuite(Functions.class); suite.addTestSuite(TailCalls.class); return suite; } From 79cec6411ddec53f1445319edcb97c2be964de46 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 11 Jun 2014 19:35:00 +0400 Subject: [PATCH 008/143] Mark only unreachable parts of element if it has reachable parts like for 'return todo()' mark only 'return' --- .../lang/cfg/JetFlowInformationProvider.java | 35 +++-- .../jetbrains/jet/lang/cfg/UnreachableCode.kt | 119 +++++++++++++++ .../lang/diagnostics/AbstractDiagnostic.java | 10 ++ .../DiagnosticFactoryWithPsiElement.java | 2 +- .../jet/lang/diagnostics/Errors.java | 10 +- .../diagnostics/PositioningStrategies.java | 13 ++ .../lang/diagnostics/PositioningStrategy.java | 7 +- .../rendering/DefaultErrorMessages.java | 2 +- .../BasicExpressionTypingVisitor.java | 2 +- .../diagnostics/tests/FunctionReturnTypes.kt | 6 +- .../deadCode/commasAndWhitespaces.kt | 12 ++ .../deadCode/deadCallInInvokeCall.kt | 11 ++ .../deadCode/deadCallInReceiver.kt | 11 ++ .../deadCode/deadCodeDifferentExamples.kt} | 19 +-- .../deadCodeFromDifferentSources.kt} | 2 +- .../deadCode/deadCodeInArrayAccess.kt | 40 +++++ .../deadCode/deadCodeInAssignment.kt | 18 +++ .../deadCode/deadCodeInBinaryExpressions.kt | 39 +++++ .../deadCode/deadCodeInCalls.kt | 13 ++ .../deadCode/deadCodeInDeadCode.kt | 24 +++ .../deadCode/deadCodeInIf.kt | 12 ++ .../deadCode/deadCodeInInnerExpressions.kt | 13 ++ .../deadCode/deadCodeInLocalDeclarations.kt | 36 +++++ .../deadCode/deadCodeInLoops.kt | 21 +++ .../deadCode/deadCodeInReturn.kt | 5 + .../deadCode/deadCodeInUnaryExpr.kt | 15 ++ .../deadCodeInWhileFromBreak.kt} | 12 +- .../{ => deadCode}/kt2585_1.kt | 2 +- .../{ => deadCode}/kt2585_2.kt | 2 +- .../{ => deadCode}/kt2585_3.kt | 2 +- .../kt770.kt351.kt735_StatementType.kt | 5 +- .../tests/controlStructures/tryReturnType.kt | 2 +- .../tests/inference/regressions/kt2445.kt | 3 +- .../tests/inference/regressions/kt2838.kt | 5 +- .../diagnostics/tests/regressions/kt58.kt | 2 +- .../checkers/JetDiagnosticsTestGenerated.java | 141 ++++++++++++++---- idea/testData/checker/FunctionReturnTypes.kt | 4 +- idea/testData/checker/UnreachableCode.kt | 4 +- 38 files changed, 597 insertions(+), 84 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commasAndWhitespaces.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInInvokeCall.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInReceiver.kt rename compiler/testData/diagnostics/tests/{UnreachableCode.kt => controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt} (84%) rename compiler/testData/diagnostics/tests/controlFlowAnalysis/{DeadCode.kt => deadCode/deadCodeFromDifferentSources.kt} (78%) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInArrayAccess.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInAssignment.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInBinaryExpressions.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInCalls.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInDeadCode.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInIf.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInInnerExpressions.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLocalDeclarations.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLoops.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInReturn.kt create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInUnaryExpr.kt rename compiler/testData/diagnostics/tests/controlFlowAnalysis/{unreachableCode.kt => deadCode/deadCodeInWhileFromBreak.kt} (68%) rename compiler/testData/diagnostics/tests/controlFlowAnalysis/{ => deadCode}/kt2585_1.kt (80%) rename compiler/testData/diagnostics/tests/controlFlowAnalysis/{ => deadCode}/kt2585_2.kt (88%) rename compiler/testData/diagnostics/tests/controlFlowAnalysis/{ => deadCode}/kt2585_3.kt (78%) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 5375b8e65c2..101d9fec9bc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -124,9 +124,9 @@ public class JetFlowInformationProvider { } public void checkFunction(@Nullable JetType expectedReturnType) { - Set unreachableElements = collectUnreachableCode(); - checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, unreachableElements); - reportUnreachableCode(unreachableElements); + UnreachableCode unreachableCode = collectUnreachableCode(); + checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, unreachableCode); + reportUnreachableCode(unreachableCode); markTailCalls(); } @@ -209,7 +209,7 @@ public class JetFlowInformationProvider { } } - public void checkDefiniteReturn(final @NotNull JetType expectedReturnType, @NotNull final Set unreachableElements) { + public void checkDefiniteReturn(final @NotNull JetType expectedReturnType, @NotNull final UnreachableCode unreachableCode) { assert subroutine instanceof JetDeclarationWithBody; JetDeclarationWithBody function = (JetDeclarationWithBody) subroutine; @@ -236,7 +236,7 @@ public class JetFlowInformationProvider { if (blockBody && !noExpectedType(expectedReturnType) && !KotlinBuiltIns.getInstance().isUnit(expectedReturnType) - && !unreachableElements.contains(element)) { + && !unreachableCode.getElements().contains(element)) { noReturnError[0] = true; } } @@ -247,19 +247,17 @@ public class JetFlowInformationProvider { } } - private void reportUnreachableCode(@NotNull Set unreachableElements) { - // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well - Set rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements); - - for (JetElement element : rootUnreachableElements) { - trace.report(UNREACHABLE_CODE.on(element)); + private void reportUnreachableCode(@NotNull UnreachableCode unreachableCode) { + for (JetElement element : unreachableCode.getElements()) { + trace.report(UNREACHABLE_CODE.on(element, unreachableCode.getUnreachableTextRanges(element))); } } - private Set collectUnreachableCode() { + @NotNull + private UnreachableCode collectUnreachableCode() { + Set reachableElements = Sets.newHashSet(); Set unreachableElements = Sets.newHashSet(); - for (Instruction instruction : pseudocode.getDeadInstructions()) { - if (!PseudocodeUtil.isDeadInAllCopies(instruction)) continue; + for (Instruction instruction : pseudocode.getInstructionsIncludingDeadCode()) { if (!(instruction instanceof JetElementInstruction) || instruction instanceof LoadUnitValueInstruction || instruction instanceof MergeInstruction @@ -275,9 +273,14 @@ public class JetFlowInformationProvider { if (!isJumpElement) continue; } - unreachableElements.add(element); + if (PseudocodeUtil.isDeadInAllCopies(instruction)) { + unreachableElements.add(element); + } + else { + reachableElements.add(element); + } } - return unreachableElements; + return new UnreachableCodeImpl(reachableElements, unreachableElements); } //////////////////////////////////////////////////////////////////////////////// diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt new file mode 100644 index 00000000000..b748efdf36a --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2010-2014 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.cfg + +import org.jetbrains.jet.lang.psi.JetElement +import com.intellij.openapi.util.TextRange +import java.util.HashSet +import org.jetbrains.jet.lang.psi.JetPsiUtil +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiWhiteSpace +import java.util.ArrayList +import org.jetbrains.jet.lexer.JetTokens +import com.intellij.psi.util.PsiTreeUtil + +trait UnreachableCode { + val elements: Set + fun getUnreachableTextRanges(element: JetElement): List +} + +class UnreachableCodeImpl( + private val reachableElements: Set, + private val unreachableElements: Set +) : UnreachableCode { + + // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well + override val elements = JetPsiUtil.findRootExpressions(unreachableElements) + + override fun getUnreachableTextRanges(element: JetElement): List { + return if (element.hasChildrenInSet(reachableElements)) { + element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges() + } + else { + listOf(element.getTextRange()!!) + } + } + + private fun JetElement.hasChildrenInSet(set: Set): Boolean { + return PsiTreeUtil.collectElements(this) { it != this }.any { it in set } + } + + private fun JetElement.getLeavesOrReachableChildren(): List { + val children = ArrayList() + acceptChildren(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + val isReachable = element is JetElement && reachableElements.contains(element) && !element.hasChildrenInSet(unreachableElements) + if (isReachable || element.getChildren().size == 0) { + children.add(element) + } + else { + element.acceptChildren(this) + } + } + }) + return children + } + + fun List.removeReachableElementsWithMeaninglessSiblings(): List { + fun PsiElement.isMeaningless() = this is PsiWhiteSpace || this.getNode()?.getElementType() == JetTokens.COMMA + + val childrenToRemove = HashSet() + fun collectSiblingsIfMeaningless(elementIndex: Int, direction: Int) { + val index = elementIndex + direction + if (index !in 0..(size() - 1)) return + + val element = this[index] + if (element.isMeaningless()) { + childrenToRemove.add(element) + collectSiblingsIfMeaningless(index, direction) + } + } + for ((index, element) in this.withIndices()) { + if (reachableElements.contains(element)) { + childrenToRemove.add(element) + collectSiblingsIfMeaningless(index, -1) + collectSiblingsIfMeaningless(index, 1) + } + } + return this.filter { it !in childrenToRemove } + } + + + private fun List.mergeAdjacentTextRanges(): List { + val result = ArrayList() + val lastRange = fold(null: TextRange?) { + currentTextRange, element -> + + val elementRange = element.getTextRange()!! + if (currentTextRange == null) { + elementRange + } + else if (currentTextRange.getEndOffset() == elementRange.getStartOffset()) { + currentTextRange.union(elementRange) + } + else { + result.add(currentTextRange) + elementRange + } + } + if (lastRange != null) { + result.add(lastRange) + } + return result + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnostic.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnostic.java index 598049b6c5a..8616757045f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnostic.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/AbstractDiagnostic.java @@ -27,6 +27,7 @@ public abstract class AbstractDiagnostic implements Parame private final E psiElement; private final DiagnosticFactoryWithPsiElement factory; private final Severity severity; + private List textRanges; public AbstractDiagnostic(@NotNull E psiElement, @NotNull DiagnosticFactoryWithPsiElement factory, @@ -63,6 +64,9 @@ public abstract class AbstractDiagnostic implements Parame @Override @NotNull public List getTextRanges() { + if (textRanges != null) { + return textRanges; + } return getFactory().getTextRanges(this); } @@ -71,4 +75,10 @@ public abstract class AbstractDiagnostic implements Parame if (!getFactory().isValid(this)) return false; return true; } + + @NotNull + public Diagnostic setTextRanges(@NotNull List textRanges) { + this.textRanges = textRanges; + return this; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement.java index 5a01175740d..a015899f523 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticFactoryWithPsiElement.java @@ -30,7 +30,7 @@ public abstract class DiagnosticFactoryWithPsiElement getTextRanges(ParametrizedDiagnostic diagnostic) { - return positioningStrategy.mark(diagnostic.getPsiElement()); + return positioningStrategy.markDiagnostic(diagnostic); } protected boolean isValid(ParametrizedDiagnostic diagnostic) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 3d0df53cdf9..1620da3f528 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -17,9 +17,11 @@ package org.jetbrains.jet.lang.diagnostics; import com.google.common.collect.ImmutableSet; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.impl.source.tree.LeafPsiElement; +import kotlin.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; @@ -446,7 +448,13 @@ public interface Errors { // Control flow / Data flow - DiagnosticFactory0 UNREACHABLE_CODE = DiagnosticFactory0.create(WARNING); + DiagnosticFactory1> UNREACHABLE_CODE = DiagnosticFactory1.create( + WARNING, PositioningStrategies.markTextRangesFromDiagnostic(new Function1>() { + @Override + public List invoke(Diagnostic diagnostic) { + return UNREACHABLE_CODE.cast(diagnostic).getA(); + } + })); DiagnosticFactory0 VARIABLE_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, NAME_IDENTIFIER); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategies.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategies.java index b472dd4169c..a0e5d07199c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategies.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategies.java @@ -23,6 +23,7 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNameIdentifierOwner; +import kotlin.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lang.psi.*; @@ -527,6 +528,18 @@ public class PositioningStrategies { } }; + public static PositioningStrategy markTextRangesFromDiagnostic( + @NotNull final Function1> getTextRanges + ) { + return new PositioningStrategy() { + @NotNull + @Override + public List markDiagnostic(@NotNull ParametrizedDiagnostic diagnostic) { + return getTextRanges.invoke(diagnostic); + } + }; + } + private PositioningStrategies() { } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategy.java index a149ef32b69..16486f78e7a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/PositioningStrategy.java @@ -27,7 +27,12 @@ import java.util.List; public class PositioningStrategy { @NotNull - public List mark(@NotNull E element) { + public List markDiagnostic(@NotNull ParametrizedDiagnostic diagnostic) { + return mark(diagnostic.getPsiElement()); + } + + @NotNull + protected List mark(@NotNull E element) { return markElement(element); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index deace52941b..bb804680559 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -212,7 +212,7 @@ public class DefaultErrorMessages { MAP.put(INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER, "Setter of this property can be overridden, so initialization using backing field required", NAME); - MAP.put(UNREACHABLE_CODE, "Unreachable code"); + MAP.put(UNREACHABLE_CODE, "Unreachable code", TO_STRING); MAP.put(MANY_CLASS_OBJECTS, "Only one class object is allowed per class"); MAP.put(CLASS_OBJECT_NOT_ALLOWED, "A class object is not allowed here"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index b15e9a82b6a..71b008af17d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -661,7 +661,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetType result; if (operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) { assert returnType != null : "returnType is null for " + resolutionResults.getResultingDescriptor(); - if (JetTypeChecker.INSTANCE.isSubtypeOf(returnType, KotlinBuiltIns.getInstance().getUnitType())) { + if (KotlinBuiltIns.getInstance().isUnit(returnType)) { result = ErrorUtils.createErrorType(KotlinBuiltIns.getInstance().getUnit().getName().asString()); context.trace.report(INC_DEC_SHOULD_NOT_RETURN_UNIT.on(operationSign)); } diff --git a/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt b/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt index a73b71e57f2..d4e0fbdcfcc 100644 --- a/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt +++ b/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt @@ -1,3 +1,5 @@ +// !DIAGNOSTICS: -UNREACHABLE_CODE + fun none() {} fun unitEmptyInfer() {} @@ -51,7 +53,7 @@ fun blockAndAndMismatch1() : Int { return true && false } fun blockAndAndMismatch2() : Int { - (return true) && (return false) + (return true) && (return false) } fun blockAndAndMismatch3() : Int { @@ -61,7 +63,7 @@ fun blockAndAndMismatch4() : Int { return true || false } fun blockAndAndMismatch5() : Int { - (return true) || (return false) + (return true) || (return false) } fun blockReturnValueTypeMatch1() : Int { return if (1 > 2) 1.0 else 2.0 diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commasAndWhitespaces.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commasAndWhitespaces.kt new file mode 100644 index 00000000000..a32de3a361c --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commasAndWhitespaces.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun testCommasAndWhitespaces() { + fun bar(i: Int, s: String, x: Any) {} + + bar( 1 , todo() , "" ) +} + +fun todo() = throw Exception() + + + diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInInvokeCall.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInInvokeCall.kt new file mode 100644 index 00000000000..9285b7122f1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInInvokeCall.kt @@ -0,0 +1,11 @@ +fun testInvoke() { + fun Nothing.invoke() = this + todo()() +} + +fun testInvokeWithLambda() { + fun Nothing.invoke(i: Int, f: () -> Int) = f + todo()(1){ 42 } +} + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInReceiver.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInReceiver.kt new file mode 100644 index 00000000000..bce9404313e --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInReceiver.kt @@ -0,0 +1,11 @@ +fun test11() { + fun Any.bar(i: Int) {} + todo().bar(1) +} + +fun test12() { + fun Any.bar(i: Int) {} + todo()?.bar(1) +} + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/UnreachableCode.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt similarity index 84% rename from compiler/testData/diagnostics/tests/UnreachableCode.kt rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt index e79c920e843..627bbd0fd81 100644 --- a/compiler/testData/diagnostics/tests/UnreachableCode.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt @@ -1,3 +1,4 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION fun t1() : Int{ return 0 @@ -46,7 +47,7 @@ fun t3() : Any { 1 } -fun t4(a : Boolean) : Int { +fun t4(a : Boolean) : Int { do { return 1 } @@ -54,7 +55,7 @@ fun t4(a : Boolean) : Int { 1 } -fun t4break(a : Boolean) : Int { +fun t4break(a : Boolean) : Int { do { break } @@ -109,7 +110,7 @@ fun t7() : Int { 2 } catch (e : Any) { - 2 + 2 } return 1 // this is OK, like in Java } @@ -127,16 +128,16 @@ fun t8() : Int { } fun blockAndAndMismatch() : Boolean { - (return true) || (return false) + (return true) || (return false) return true } fun tf() : Int { - try {return 1} finally{return 1} + try {return 1} finally{return 1} return 1 } -fun failtest(a : Int) : Int { +fun failtest(a : Int) : Int { if (fail() || true) { } @@ -144,8 +145,8 @@ fun failtest(a : Int) : Int { } fun foo(a : Nothing) : Unit { - 1 - a + 1 + a 2 } @@ -161,7 +162,7 @@ fun nullIsNotNothing() : Unit { fail() } -fun returnInWhile(a: Int) { +fun returnInWhile(a: Int) { do {return} while (1 > a) } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/DeadCode.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeFromDifferentSources.kt similarity index 78% rename from compiler/testData/diagnostics/tests/controlFlowAnalysis/DeadCode.kt rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeFromDifferentSources.kt index 0cd3fb77b75..63c2571b0ca 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/DeadCode.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeFromDifferentSources.kt @@ -1,7 +1,7 @@ package c fun test1() { - val r: Nothing = null!! + val r: Nothing = null!! } fun test2(a: A) { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInArrayAccess.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInArrayAccess.kt new file mode 100644 index 00000000000..b9109c096c9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInArrayAccess.kt @@ -0,0 +1,40 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun testArrayAccess1(array: Array) { + array[todo()] +} + +fun testArrayAccess2() { + fun Nothing.get(i: Int, s: String) {} + todo()[1, ""] +} + +fun testAraryAccess3() { + fun Nothing.get(n: Nothing) {} + todo()[todo()] +} + +fun testArrayAssignment1(array: Array) { + array[todo()] = 11 +} + +fun testArrayAssignment2(array: Array) { + array[1] = todo() +} + +fun testArrayAssignment3(n: Nothing) { + fun Nothing.set(i: Int, j: Int) {} + n[1] = 2 +} + +fun testArrayAssignment4(n: Nothing) { + fun Nothing.set(i: Int, a: Any) {} + n[1] = todo() +} + +fun testArrayPlusAssign(array: Array) { + fun Any.plusAssign(a: Any) {} + array[1] += todo() +} + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInAssignment.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInAssignment.kt new file mode 100644 index 00000000000..85e9e23aaf0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInAssignment.kt @@ -0,0 +1,18 @@ +fun testAssignment() { + var a = 1 + a = todo() +} + +fun testVariableDeclaration() { + val a = todo() +} + +fun testPlusAssign() { + fun Int.plusAssign(i: Int) {} + + var a = 1 + a += todo() +} + + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInBinaryExpressions.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInBinaryExpressions.kt new file mode 100644 index 00000000000..42b4727af76 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInBinaryExpressions.kt @@ -0,0 +1,39 @@ +fun testBinary1() { + fun Int.times(s: String) {} + + todo() * "" +} +fun testBinary2() { + "1" + todo() +} + +fun testElvis1() { + todo() ?: "" +} + +fun testElvis2(s: String?) { + s ?: todo() + + bar() +} + +fun testAnd1(b: Boolean) { + b && todo() + + bar() +} + +fun testAnd2(b: Boolean) { + todo() && b +} + +fun returnInBinary1(): Boolean { + (return true) && (return false) +} + +fun returnInBinary2(): Boolean { + (return true) || (return false) +} + +fun todo() = throw Exception() +fun bar() {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInCalls.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInCalls.kt new file mode 100644 index 00000000000..6bc59d6867a --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInCalls.kt @@ -0,0 +1,13 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun testArgumentInCall() { + fun bar(i: Int, s: String, x: Any) {} + + bar(1, todo(), "") +} + +fun testArgumentInVariableAsFunctionCall(f: (Any) -> Unit) { + f(todo()) +} + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInDeadCode.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInDeadCode.kt new file mode 100644 index 00000000000..53001d49508 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInDeadCode.kt @@ -0,0 +1,24 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun unreachable0() { + return + return todo() +} + +fun unreachable2() { + return + val a = todo() +} + +fun unreachable3() { + return + bar(todo()) +} + +fun unreachable4(array: Array) { + return + array[todo()] +} + +fun bar(a: Any) {} +fun todo() = throw Exception() diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInIf.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInIf.kt new file mode 100644 index 00000000000..283281aecc3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInIf.kt @@ -0,0 +1,12 @@ +fun testIf() { + if (todo()) 1 else 2 +} + +fun testIf1(b: Boolean) { + if (b) todo() else 1 + + bar() +} + +fun todo() = throw Exception() +fun bar() {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInInnerExpressions.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInInnerExpressions.kt new file mode 100644 index 00000000000..16f1395f857 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInInnerExpressions.kt @@ -0,0 +1,13 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun testCompound() { + fun Nothing.get(i: Int) {} + todo()!![12] +} + +fun testCompound1() { + fun Int.times(s: String): Array = throw Exception() + (todo() * "")[1] +} + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLocalDeclarations.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLocalDeclarations.kt new file mode 100644 index 00000000000..db437307072 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLocalDeclarations.kt @@ -0,0 +1,36 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun testObject() { + object : Foo(todo()) { + fun foo() = 1 + } +} + +fun testObjectExpression() { + val a = object : Foo(todo()) { + fun foo() = 1 + } +} + +fun testObjectExpression1() { + fun bar(i: Int, x: Any) {} + + bar(1, object : Foo(todo()) { + fun foo() = 1 + }) +} + +fun testClassDeclaration() { + class C : Foo(todo()) {} + + bar() +} + +fun testFunctionDefaultArgument() { + fun foo(x: Int = todo()) { bar() } +} + +open class Foo(i: Int) {} + +fun todo() = throw Exception() +fun bar() {} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLoops.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLoops.kt new file mode 100644 index 00000000000..f5f85117c8c --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLoops.kt @@ -0,0 +1,21 @@ +fun testFor() { + fun Nothing.iterator() = (0..1).iterator() + + for (i in todo()) {} +} + +fun testWhile() { + while (todo()) { + } +} + +fun testDoWhile() { + do { + + } while(todo()) + + bar() +} + +fun todo() = throw Exception() +fun bar() {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInReturn.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInReturn.kt new file mode 100644 index 00000000000..d8574db97a2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInReturn.kt @@ -0,0 +1,5 @@ +fun testReturn() { + return todo() +} + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInUnaryExpr.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInUnaryExpr.kt new file mode 100644 index 00000000000..1d158e012d2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInUnaryExpr.kt @@ -0,0 +1,15 @@ +fun testPrefix() { + fun Any.not() {} + !todo() +} + +fun testPostfixWithCall(n: Nothing) { + fun Nothing.inc(): Nothing = this + n++ +} + +fun testPostfixSpecial() { + todo()!! +} + +fun todo() = throw Exception() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInWhileFromBreak.kt similarity index 68% rename from compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInWhileFromBreak.kt index 431865396f2..978ee032ac0 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInWhileFromBreak.kt @@ -3,20 +3,20 @@ fun bar(a: Any, b: Any) {} fun test(arr: Array) { while (true) { - foo(break) + foo(break) } while (true) { - bar(arr, break) + bar(arr, break) } while (true) { - arr[break] + arr[break] } while (true) { - arr[1] = break + arr[1] = break } while (true) { @@ -32,7 +32,7 @@ fun test(arr: Array) { while (true) { var x = 1 - x = break + x = break } // TODO: bug, should be fixed in CFA @@ -50,6 +50,6 @@ fun test(arr: Array) { } while (true) { - break ?: null + break ?: null } } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_1.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_1.kt similarity index 80% rename from compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_1.kt rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_1.kt index 185066d307b..2bd2e6bd6c6 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_1.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_1.kt @@ -2,7 +2,7 @@ fun foo(x: String): String { try { - throw RuntimeException() + throw RuntimeException() } finally { try { } catch (e: Exception) { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_2.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_2.kt similarity index 88% rename from compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_2.kt rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_2.kt index 8b6d9f6ed9a..638e2fe6759 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_2.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_2.kt @@ -2,7 +2,7 @@ fun foo() { try { - throw RuntimeException() + throw RuntimeException() } catch (e: Exception) { return // <- Wrong UNREACHABLE_CODE } finally { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_3.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_3.kt similarity index 78% rename from compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_3.kt rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_3.kt index f2f917ceda4..b2b68a84a96 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_3.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_3.kt @@ -2,7 +2,7 @@ fun foo(x: String): String { try { - throw RuntimeException() //should be marked as unreachable, but is not + throw RuntimeException() //should be marked as unreachable, but is not } finally { throw NullPointerException() } diff --git a/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.kt b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.kt index 7f5528485b6..0b4e3efab96 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.kt @@ -1,3 +1,4 @@ +// !DIAGNOSTICS: -UNREACHABLE_CODE package kt770_351_735 @@ -120,9 +121,9 @@ fun testStatementInExpressionContext() { val a1: Unit = z = 334 val f = for (i in 1..10) {} if (true) return z = 34 - return while (true) {} + return while (true) {} } fun testStatementInExpressionContext2() { - val a2: Unit = while(true) {} + val a2: Unit = while(true) {} } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/tryReturnType.kt b/compiler/testData/diagnostics/tests/controlStructures/tryReturnType.kt index a61bf21605b..58f53253516 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/tryReturnType.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/tryReturnType.kt @@ -5,7 +5,7 @@ fun foo() : Int { doSmth() } catch (e: Exception) { - return "" + return "" } finally { return "" diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt2445.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt2445.kt index 34eb3099f80..2f9e0da3fab 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt2445.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt2445.kt @@ -1,3 +1,4 @@ +// !DIAGNOSTICS: -UNREACHABLE_CODE //KT-2445 Calling method with function with generic parameter causes compile-time exception package a @@ -7,4 +8,4 @@ fun main(args: Array) { } } -fun test(callback: (R) -> Unit):Unit = callback(null!!) \ No newline at end of file +fun test(callback: (R) -> Unit):Unit = callback(null!!) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt index 33518f5f228..23ff0757a4b 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt2838.kt @@ -1,3 +1,4 @@ +// !DIAGNOSTICS: -UNREACHABLE_CODE //KT-2838 Type inference failed on passing null as a nullable argument package a @@ -9,9 +10,9 @@ fun test(a: Int) { bar(a, null) } fun test1(a: Int) { - foo(a, throw Exception()) + foo(a, throw Exception()) } fun test2(a: Int) { - bar(a, throw Exception()) + bar(a, throw Exception()) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt58.kt b/compiler/testData/diagnostics/tests/regressions/kt58.kt index 665fa7ad48e..9ed3897e281 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt58.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt58.kt @@ -17,7 +17,7 @@ fun lock(lock : Lock, body : () -> T) : T { //more tests fun t1() : Int { try { - return 1 + return 1 } finally { return 2 diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 8d9b77441ed..789dbd81b1e 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -469,11 +469,6 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/UnitValue.kt"); } - @TestMetadata("UnreachableCode.kt") - public void testUnreachableCode() throws Exception { - doTest("compiler/testData/diagnostics/tests/UnreachableCode.kt"); - } - @TestMetadata("Unresolved.kt") public void testUnresolved() throws Exception { doTest("compiler/testData/diagnostics/tests/Unresolved.kt"); @@ -1239,7 +1234,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { } @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis") - @InnerTestClasses({ControlFlowAnalysis.DefiniteReturn.class}) + @InnerTestClasses({ControlFlowAnalysis.DeadCode.class, ControlFlowAnalysis.DefiniteReturn.class}) public static class ControlFlowAnalysis extends AbstractJetDiagnosticsTest { public void testAllFilesPresentInControlFlowAnalysis() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/controlFlowAnalysis"), Pattern.compile("^(.+)\\.kt$"), true); @@ -1260,11 +1255,6 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/checkPropertyAccessor.kt"); } - @TestMetadata("DeadCode.kt") - public void testDeadCode() throws Exception { - doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/DeadCode.kt"); - } - @TestMetadata("definiteReturnInWhen.kt") public void testDefiniteReturnInWhen() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt"); @@ -1340,21 +1330,6 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2369.kt"); } - @TestMetadata("kt2585_1.kt") - public void testKt2585_1() throws Exception { - doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_1.kt"); - } - - @TestMetadata("kt2585_2.kt") - public void testKt2585_2() throws Exception { - doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_2.kt"); - } - - @TestMetadata("kt2585_3.kt") - public void testKt2585_3() throws Exception { - doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2585_3.kt"); - } - @TestMetadata("kt2845.kt") public void testKt2845() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2845.kt"); @@ -1455,16 +1430,119 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/UninitializedOrReassignedVariables.kt"); } - @TestMetadata("unreachableCode.kt") - public void testUnreachableCode() throws Exception { - doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/unreachableCode.kt"); - } - @TestMetadata("varInitializationInIfInCycle.kt") public void testVarInitializationInIfInCycle() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/varInitializationInIfInCycle.kt"); } + @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode") + public static class DeadCode extends AbstractJetDiagnosticsTest { + public void testAllFilesPresentInDeadCode() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("commasAndWhitespaces.kt") + public void testCommasAndWhitespaces() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commasAndWhitespaces.kt"); + } + + @TestMetadata("deadCallInInvokeCall.kt") + public void testDeadCallInInvokeCall() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInInvokeCall.kt"); + } + + @TestMetadata("deadCallInReceiver.kt") + public void testDeadCallInReceiver() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInReceiver.kt"); + } + + @TestMetadata("deadCodeDifferentExamples.kt") + public void testDeadCodeDifferentExamples() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt"); + } + + @TestMetadata("deadCodeFromDifferentSources.kt") + public void testDeadCodeFromDifferentSources() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeFromDifferentSources.kt"); + } + + @TestMetadata("deadCodeInArrayAccess.kt") + public void testDeadCodeInArrayAccess() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInArrayAccess.kt"); + } + + @TestMetadata("deadCodeInAssignment.kt") + public void testDeadCodeInAssignment() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInAssignment.kt"); + } + + @TestMetadata("deadCodeInBinaryExpressions.kt") + public void testDeadCodeInBinaryExpressions() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInBinaryExpressions.kt"); + } + + @TestMetadata("deadCodeInCalls.kt") + public void testDeadCodeInCalls() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInCalls.kt"); + } + + @TestMetadata("deadCodeInDeadCode.kt") + public void testDeadCodeInDeadCode() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInDeadCode.kt"); + } + + @TestMetadata("deadCodeInIf.kt") + public void testDeadCodeInIf() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInIf.kt"); + } + + @TestMetadata("deadCodeInInnerExpressions.kt") + public void testDeadCodeInInnerExpressions() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInInnerExpressions.kt"); + } + + @TestMetadata("deadCodeInLocalDeclarations.kt") + public void testDeadCodeInLocalDeclarations() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLocalDeclarations.kt"); + } + + @TestMetadata("deadCodeInLoops.kt") + public void testDeadCodeInLoops() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInLoops.kt"); + } + + @TestMetadata("deadCodeInReturn.kt") + public void testDeadCodeInReturn() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInReturn.kt"); + } + + @TestMetadata("deadCodeInUnaryExpr.kt") + public void testDeadCodeInUnaryExpr() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInUnaryExpr.kt"); + } + + @TestMetadata("deadCodeInWhileFromBreak.kt") + public void testDeadCodeInWhileFromBreak() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInWhileFromBreak.kt"); + } + + @TestMetadata("kt2585_1.kt") + public void testKt2585_1() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_1.kt"); + } + + @TestMetadata("kt2585_2.kt") + public void testKt2585_2() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_2.kt"); + } + + @TestMetadata("kt2585_3.kt") + public void testKt2585_3() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_3.kt"); + } + + } + @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn") public static class DefiniteReturn extends AbstractJetDiagnosticsTest { public void testAllFilesPresentInDefiniteReturn() throws Exception { @@ -1491,6 +1569,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { public static Test innerSuite() { TestSuite suite = new TestSuite("ControlFlowAnalysis"); suite.addTestSuite(ControlFlowAnalysis.class); + suite.addTestSuite(DeadCode.class); suite.addTestSuite(DefiniteReturn.class); return suite; } diff --git a/idea/testData/checker/FunctionReturnTypes.kt b/idea/testData/checker/FunctionReturnTypes.kt index f10d48a1d5d..6ec18678986 100644 --- a/idea/testData/checker/FunctionReturnTypes.kt +++ b/idea/testData/checker/FunctionReturnTypes.kt @@ -48,7 +48,7 @@ fun blockAndAndMismatch1() : Int { return true && false } fun blockAndAndMismatch2() : Int { - (return true) && (return false) + (return true) && (return false) } fun blockAndAndMismatch3() : Int { @@ -58,7 +58,7 @@ fun blockAndAndMismatch4() : Int { return true || false } fun blockAndAndMismatch5() : Int { - (return true) || (return false) + (return true) || (return false) } fun blockReturnValueTypeMatch1() : Int { return if (1 > 2) 1.0 else 2.0 diff --git a/idea/testData/checker/UnreachableCode.kt b/idea/testData/checker/UnreachableCode.kt index a98db2ae881..70599cadac0 100644 --- a/idea/testData/checker/UnreachableCode.kt +++ b/idea/testData/checker/UnreachableCode.kt @@ -126,12 +126,12 @@ fun t8() : Int { } fun blockAndAndMismatch() : Boolean { - (return true) || (return false) + (return true) || (return false) return true } fun tf() : Int { - try {return 1} finally{return 1} + try {return 1} finally{return 1} return 1 } From 17c4930404f1f4ac13ccf02bb2c9fdfcb9678047 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 17 Jun 2014 09:59:12 +0400 Subject: [PATCH 009/143] KT-2334 An error 'local function without body' is not reported #KT-2334 Fixed --- .../expressions/ExpressionTypingVisitorForStatements.java | 3 +++ .../testData/diagnostics/tests/controlFlowAnalysis/kt2334.kt | 5 +++++ .../jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java | 5 +++++ 3 files changed, 13 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2334.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index 87d10554c36..28e9841d690 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -175,6 +175,9 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito scope, context.dataFlowInfo, context.trace, /* needCompleteAnalysis = */ true); ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor); + if (!function.hasBody()) { + context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)); + } return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo); } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2334.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2334.kt new file mode 100644 index 00000000000..4801d17d73f --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2334.kt @@ -0,0 +1,5 @@ +//KT-2334 An error 'local function without body' is not reported + +fun foo() { + fun bar() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 789dbd81b1e..e45860f977b 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1325,6 +1325,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2330.kt"); } + @TestMetadata("kt2334.kt") + public void testKt2334() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2334.kt"); + } + @TestMetadata("kt2369.kt") public void testKt2369() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt2369.kt"); From abfc8ed7e8a380fca70c6d7dcf05c2dbd312cb3f Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 17 Jun 2014 15:14:03 +0400 Subject: [PATCH 010/143] KT-5155 Auto-casts do not work with when #KT-5155 Fixed --- .../PatternMatchingTypingVisitor.java | 26 ++++++++----------- .../kt5155WhenBranches.kt | 14 ++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 ++++ 3 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/dataFlowInfoTraversal/kt5155WhenBranches.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index 89dc437e390..a3692734077 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -100,21 +100,14 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { DataFlowInfo elseDataFlowInfo = context.dataFlowInfo; for (JetWhenEntry whenEntry : expression.getEntries()) { DataFlowInfos infosForCondition = getDataFlowInfosForEntryCondition( - whenEntry, context, subjectExpression, subjectType, subjectDataFlowValue); - DataFlowInfo dataFlowInfoForEntryBody; - if (infosForCondition == null) { - dataFlowInfoForEntryBody = elseDataFlowInfo; - } - else { - dataFlowInfoForEntryBody = infosForCondition.thenInfo.and(elseDataFlowInfo); - elseDataFlowInfo = elseDataFlowInfo.and(infosForCondition.elseInfo); - } + whenEntry, context.replaceDataFlowInfo(elseDataFlowInfo), subjectExpression, subjectType, subjectDataFlowValue); + elseDataFlowInfo = elseDataFlowInfo.and(infosForCondition.elseInfo); JetExpression bodyExpression = whenEntry.getExpression(); if (bodyExpression != null) { WritableScope scopeToExtend = newWritableScopeImpl(context, "Scope extended in when entry"); ExpressionTypingContext newContext = contextWithExpectedType - .replaceScope(scopeToExtend).replaceDataFlowInfo(dataFlowInfoForEntryBody).replaceContextDependency(INDEPENDENT); + .replaceScope(scopeToExtend).replaceDataFlowInfo(infosForCondition.thenInfo).replaceContextDependency(INDEPENDENT); CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION; JetTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( scopeToExtend, Collections.singletonList(bodyExpression), coercionStrategy, newContext, context.trace); @@ -141,7 +134,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { return JetTypeInfo.create(null, commonDataFlowInfo); } - @Nullable + @NotNull private DataFlowInfos getDataFlowInfosForEntryCondition( @NotNull JetWhenEntry whenEntry, @NotNull ExpressionTypingContext context, @@ -149,13 +142,12 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { @NotNull JetType subjectType, @NotNull DataFlowValue subjectDataFlowValue ) { - JetWhenCondition[] conditions = whenEntry.getConditions(); if (whenEntry.isElse()) { - return null; + return new DataFlowInfos(context.dataFlowInfo); } DataFlowInfos infos = null; - for (JetWhenCondition condition : conditions) { + for (JetWhenCondition condition : whenEntry.getConditions()) { DataFlowInfos conditionInfos = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition, context, subjectDataFlowValue); if (infos != null) { @@ -165,7 +157,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { infos = conditionInfos; } } - return infos; + return infos != null ? infos : new DataFlowInfos(context.dataFlowInfo); } private DataFlowInfos checkWhenCondition( @@ -238,6 +230,10 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { this.thenInfo = thenInfo; this.elseInfo = elseInfo; } + + private DataFlowInfos(DataFlowInfo info) { + this(info, info); + } } private DataFlowInfos checkTypeForExpressionCondition( diff --git a/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/kt5155WhenBranches.kt b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/kt5155WhenBranches.kt new file mode 100644 index 00000000000..0f4799b9755 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dataFlowInfoTraversal/kt5155WhenBranches.kt @@ -0,0 +1,14 @@ +//KT-5155 Auto-casts do not work with when + +fun foo(s: String?) { + when { + s == null -> 1 + s.foo() -> 2 + else -> 3 + } +} + +fun String.foo() = true + + + diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index e45860f977b..6f347d12173 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2103,6 +2103,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/dataFlowInfoTraversal/kt4332WhenBranches.kt"); } + @TestMetadata("kt5155WhenBranches.kt") + public void testKt5155WhenBranches() throws Exception { + doTest("compiler/testData/diagnostics/tests/dataFlowInfoTraversal/kt5155WhenBranches.kt"); + } + @TestMetadata("kt5182WhenBranches.kt") public void testKt5182WhenBranches() throws Exception { doTest("compiler/testData/diagnostics/tests/dataFlowInfoTraversal/kt5182WhenBranches.kt"); From 4279da12f5fc746d04ba8fc1f44482710bc968fb Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 17 Jun 2014 15:50:07 +0400 Subject: [PATCH 011/143] KT-5200 Mark unreachable code in lambdas #KT-5200 Fixed --- .../lang/cfg/JetFlowInformationProvider.java | 7 +++-- .../deadCode/kt5200DeadCodeInLambdas.kt | 27 +++++++++++++++++++ .../diagnostics/tests/regressions/kt411.kt | 2 +- .../checkers/JetDiagnosticsTestGenerated.java | 5 ++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 101d9fec9bc..36f3c3ac1f8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -125,9 +125,12 @@ public class JetFlowInformationProvider { public void checkFunction(@Nullable JetType expectedReturnType) { UnreachableCode unreachableCode = collectUnreachableCode(); - checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, unreachableCode); reportUnreachableCode(unreachableCode); + if (subroutine instanceof JetFunctionLiteral) return; + + checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, unreachableCode); + markTailCalls(); } @@ -196,7 +199,7 @@ public class JetFlowInformationProvider { JetElement element = localDeclarationInstruction.getElement(); if (element instanceof JetDeclarationWithBody) { JetDeclarationWithBody localDeclaration = (JetDeclarationWithBody) element; - if (localDeclaration instanceof JetFunctionLiteral) continue; + CallableDescriptor functionDescriptor = (CallableDescriptor) trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, localDeclaration); JetType expectedType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt new file mode 100644 index 00000000000..0d53ea4e81a --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt @@ -0,0 +1,27 @@ +//KT-5200 Mark unreachable code in lambdas + +fun test1(): String { + doCall @local { + () : String -> + throw NullPointerException() + "b3" //unmarked + } + + return "OK" +} + +fun test2(nonLocal: String, b: Boolean): String { + doCall @local { + () : String -> + if (b) { + return@local "b1" + } else { + return@local "b2" + } + "b3" //unmarked + } + + return nonLocal +} + +inline fun doCall(block: ()-> String) = block() diff --git a/compiler/testData/diagnostics/tests/regressions/kt411.kt b/compiler/testData/diagnostics/tests/regressions/kt411.kt index 3c6ee7ef2a5..2f5c43386f5 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt411.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt411.kt @@ -37,7 +37,7 @@ fun t3() : String { else { return 2 } - return@l 0 + return@l 0 } ) invoker( diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 6f347d12173..80b66aba665 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1546,6 +1546,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_3.kt"); } + @TestMetadata("kt5200DeadCodeInLambdas.kt") + public void testKt5200DeadCodeInLambdas() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt"); + } + } @TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn") From 9d4aad3bbc77c994303bb617e51ee28a88d8c7ec Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 20 Jun 2014 18:44:53 +0400 Subject: [PATCH 012/143] Extracted 'generateBooleanOperation' Generate magic instruction for '&&, ||' in condition as well --- .../jet/lang/cfg/JetControlFlowProcessor.java | 52 ++++++++--------- .../cfg/expressions/LazyBooleans.instructions | 56 ++++++++++--------- .../cfg/expressions/LazyBooleans.values | 42 +++++++------- .../deadCode/deadCodeDifferentExamples.kt | 2 +- idea/testData/checker/UnreachableCode.kt | 2 +- 5 files changed, 76 insertions(+), 78 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index aa28746f47a..6ca902eed6c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -335,29 +335,8 @@ public class JetControlFlowProcessor { JetExpression left = expression.getLeft(); JetExpression right = expression.getRight(); - if (operationType == ANDAND) { - generateInstructions(left, IN_CONDITION); - Label resultLabel = builder.createUnboundLabel(); - builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left)); - if (right != null) { - generateInstructions(right, IN_CONDITION); - } - builder.bindLabel(resultLabel); - if (!context.inCondition()) { - predefinedOperation(expression, AND); - } - } - else if (operationType == OROR) { - generateInstructions(left, IN_CONDITION); - Label resultLabel = builder.createUnboundLabel(); - builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left)); - if (right != null) { - generateInstructions(right, IN_CONDITION); - } - builder.bindLabel(resultLabel); - if (!context.inCondition()) { - predefinedOperation(expression, OR); - } + if (operationType == ANDAND || operationType == OROR) { + generateBooleanOperation(expression); } else if (operationType == EQ) { visitAssignment(left, getDeferredValue(right), expression); @@ -402,6 +381,27 @@ public class JetControlFlowProcessor { } } + private void generateBooleanOperation(JetBinaryExpression expression) { + IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); + JetExpression left = expression.getLeft(); + JetExpression right = expression.getRight(); + + Label resultLabel = builder.createUnboundLabel(); + generateInstructions(left, IN_CONDITION); + if (operationType == ANDAND) { + builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left)); + } + else { + builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left)); + } + if (right != null) { + generateInstructions(right, IN_CONDITION); + } + builder.bindLabel(resultLabel); + JetControlFlowBuilder.PredefinedOperation operation = operationType == ANDAND ? AND : OR; + builder.predefinedOperation(expression, operation, elementsToValues(Arrays.asList(left, right))); + } + private Function0 getValueAsFunction(final PseudoValue value) { return new Function0() { @Override @@ -421,12 +421,6 @@ public class JetControlFlowProcessor { }; } - private void predefinedOperation(JetBinaryExpression expression, JetControlFlowBuilder.PredefinedOperation operation) { - builder.predefinedOperation( - expression, operation, elementsToValues(Arrays.asList(expression.getLeft(), expression.getRight())) - ); - } - private void generateBothArgumentsAndMark(JetBinaryExpression expression) { JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); if (left != null) { diff --git a/compiler/testData/cfg/expressions/LazyBooleans.instructions b/compiler/testData/cfg/expressions/LazyBooleans.instructions index 3d5bb8a9941..f7e99fd1981 100644 --- a/compiler/testData/cfg/expressions/LazyBooleans.instructions +++ b/compiler/testData/cfg/expressions/LazyBooleans.instructions @@ -40,48 +40,50 @@ L3: r(3) -> mark(if (a && b) 5 else 6) r(a) -> - jf(L4|) NEXT:[jf(L5), r(b) -> ] + jf(L4|) NEXT:[magic(a && b|, ) -> , r(b) -> ] r(b) -> L4: - jf(L5) NEXT:[r(6) -> , r(5) -> ] PREV:[jf(L4|), r(b) -> ] - r(5) -> - jmp(L6) NEXT:[merge(if (a && b) 5 else 6|, ) -> ] + magic(a && b|, ) -> PREV:[jf(L4|), r(b) -> ] + jf(L5|) NEXT:[r(6) -> , r(5) -> ] + r(5) -> + jmp(L6) NEXT:[merge(if (a && b) 5 else 6|, ) -> ] L5: - r(6) -> PREV:[jf(L5)] + r(6) -> PREV:[jf(L5|)] L6: - merge(if (a && b) 5 else 6|, ) -> PREV:[jmp(L6), r(6) -> ] - r(7) -> + merge(if (a && b) 5 else 6|, ) -> PREV:[jmp(L6), r(6) -> ] + r(7) -> mark(if (a || b) 8 else 9) - r(a) -> - jt(L7|) NEXT:[r(b) -> , jf(L8)] - r(b) -> + r(a) -> + jt(L7|) NEXT:[r(b) -> , magic(a || b|, ) -> ] + r(b) -> L7: - jf(L8) NEXT:[r(9) -> , r(8) -> ] PREV:[jt(L7|), r(b) -> ] - r(8) -> - jmp(L9) NEXT:[merge(if (a || b) 8 else 9|, ) -> ] + magic(a || b|, ) -> PREV:[jt(L7|), r(b) -> ] + jf(L8|) NEXT:[r(9) -> , r(8) -> ] + r(8) -> + jmp(L9) NEXT:[merge(if (a || b) 8 else 9|, ) -> ] L8: - r(9) -> PREV:[jf(L8)] + r(9) -> PREV:[jf(L8|)] L9: - merge(if (a || b) 8 else 9|, ) -> PREV:[jmp(L9), r(9) -> ] - r(10) -> + merge(if (a || b) 8 else 9|, ) -> PREV:[jmp(L9), r(9) -> ] + r(10) -> mark(if (a) 11) - r(a) -> - jf(L10|) NEXT:[read (Unit), r(11) -> ] - r(11) -> - jmp(L11) NEXT:[r(12) -> ] + r(a) -> + jf(L10|) NEXT:[read (Unit), r(11) -> ] + r(11) -> + jmp(L11) NEXT:[r(12) -> ] L10: - read (Unit) PREV:[jf(L10|)] + read (Unit) PREV:[jf(L10|)] L11: - r(12) -> PREV:[jmp(L11), read (Unit)] + r(12) -> PREV:[jmp(L11), read (Unit)] mark(if (a) else 13) - r(a) -> - jf(L12|) NEXT:[r(13) -> , read (Unit)] + r(a) -> + jf(L12|) NEXT:[r(13) -> , read (Unit)] read (Unit) - jmp(L13) NEXT:[r(14) -> ] + jmp(L13) NEXT:[r(14) -> ] L12: - r(13) -> PREV:[jf(L12|)] + r(13) -> PREV:[jf(L12|)] L13: - r(14) -> PREV:[jmp(L13), r(13) -> ] + r(14) -> PREV:[jmp(L13), r(13) -> ] L1: 1 NEXT:[] error: diff --git a/compiler/testData/cfg/expressions/LazyBooleans.values b/compiler/testData/cfg/expressions/LazyBooleans.values index 875bf5a3649..fcd696e1030 100644 --- a/compiler/testData/cfg/expressions/LazyBooleans.values +++ b/compiler/testData/cfg/expressions/LazyBooleans.values @@ -17,7 +17,7 @@ fun lazyBooleans(a : Boolean, b : Boolean) : Unit { 14 } --------------------- -a NEW() +a NEW() 1 NEW() { 1 } COPY 2 NEW() @@ -26,23 +26,25 @@ if (a) { 1 } else { 2 } 3 NEW() a NEW() b NEW() -5 NEW() -6 NEW() -if (a && b) 5 else 6 NEW(, ) -7 NEW() -a NEW() -b NEW() -8 NEW() -9 NEW() -if (a || b) 8 else 9 NEW(, ) -10 NEW() -a NEW() -11 NEW() -if (a) 11 COPY -12 NEW() -a NEW() -13 NEW() -if (a) else 13 COPY -14 NEW() -{ if (a) { 1 } else { 2 } 3 if (a && b) 5 else 6 7 if (a || b) 8 else 9 10 if (a) 11 12 if (a) else 13 14 } COPY +a && b NEW(, ) +5 NEW() +6 NEW() +if (a && b) 5 else 6 NEW(, ) +7 NEW() +a NEW() +b NEW() +a || b NEW(, ) +8 NEW() +9 NEW() +if (a || b) 8 else 9 NEW(, ) +10 NEW() +a NEW() +11 NEW() +if (a) 11 COPY +12 NEW() +a NEW() +13 NEW() +if (a) else 13 COPY +14 NEW() +{ if (a) { 1 } else { 2 } 3 if (a && b) 5 else 6 7 if (a || b) 8 else 9 10 if (a) 11 12 if (a) else 13 14 } COPY ===================== diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt index 627bbd0fd81..d3019a67a22 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.kt @@ -138,7 +138,7 @@ fun tf() : Int { } fun failtest(a : Int) : Int { - if (fail() || true) { + if (fail() || true) { } return 1 diff --git a/idea/testData/checker/UnreachableCode.kt b/idea/testData/checker/UnreachableCode.kt index 70599cadac0..1f1c1c5245b 100644 --- a/idea/testData/checker/UnreachableCode.kt +++ b/idea/testData/checker/UnreachableCode.kt @@ -136,7 +136,7 @@ fun tf() : Int { } fun failtest(a : Int) : Int { - if (fail() || true) { + if (fail() || true) { } return 1 From d150bfbce0e2e47d687f39e2fd233ea55b2ccd26 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 20 Jun 2014 18:52:30 +0400 Subject: [PATCH 013/143] Removed CFPContext flag 'inCondition' became unused --- .../jet/lang/cfg/JetControlFlowProcessor.java | 257 ++++++++---------- 1 file changed, 119 insertions(+), 138 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 6ca902eed6c..608ace76096 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -52,8 +52,6 @@ import org.jetbrains.jet.lexer.JetTokens; import java.util.*; import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*; -import static org.jetbrains.jet.lang.cfg.JetControlFlowProcessor.CFPContext.IN_CONDITION; -import static org.jetbrains.jet.lang.cfg.JetControlFlowProcessor.CFPContext.NOT_IN_CONDITION; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lexer.JetTokens.*; @@ -82,14 +80,14 @@ public class JetControlFlowProcessor { JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) subroutine; List valueParameters = declarationWithBody.getValueParameters(); for (JetParameter valueParameter : valueParameters) { - cfpVisitor.generateInstructions(valueParameter, NOT_IN_CONDITION); + cfpVisitor.generateInstructions(valueParameter); } JetExpression bodyExpression = declarationWithBody.getBodyExpression(); if (bodyExpression != null) { - cfpVisitor.generateInstructions(bodyExpression, NOT_IN_CONDITION); + cfpVisitor.generateInstructions(bodyExpression); } } else { - cfpVisitor.generateInstructions(subroutine, NOT_IN_CONDITION); + cfpVisitor.generateInstructions(subroutine); } return builder.exitSubroutine(subroutine); } @@ -105,48 +103,33 @@ public class JetControlFlowProcessor { builder.bindLabel(afterDeclaration); } - /*package*/ enum CFPContext { - IN_CONDITION(true), - NOT_IN_CONDITION(false); - - private final boolean inCondition; - - private CFPContext(boolean inCondition) { - this.inCondition = inCondition; - } - - public boolean inCondition() { - return inCondition; - } - } - - private class CFPVisitor extends JetVisitorVoidWithParameter { + private class CFPVisitor extends JetVisitorVoid { private final JetControlFlowBuilder builder; - private final JetVisitorVoidWithParameter conditionVisitor = new JetVisitorVoidWithParameter() { + private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() { @Override - public void visitWhenConditionInRangeVoid(@NotNull JetWhenConditionInRange condition, CFPContext context) { - generateInstructions(condition.getRangeExpression(), context); - generateInstructions(condition.getOperationReference(), context); + public void visitWhenConditionInRange(@NotNull JetWhenConditionInRange condition) { + generateInstructions(condition.getRangeExpression()); + generateInstructions(condition.getOperationReference()); // TODO : read the call to contains()... createNonSyntheticValue(condition, condition.getRangeExpression(), condition.getOperationReference()); } @Override - public void visitWhenConditionIsPatternVoid(@NotNull JetWhenConditionIsPattern condition, CFPContext context) { + public void visitWhenConditionIsPattern(@NotNull JetWhenConditionIsPattern condition) { // TODO: types in CF? } @Override - public void visitWhenConditionWithExpressionVoid(@NotNull JetWhenConditionWithExpression condition, CFPContext context) { - generateInstructions(condition.getExpression(), context); + public void visitWhenConditionWithExpression(@NotNull JetWhenConditionWithExpression condition) { + generateInstructions(condition.getExpression()); copyValue(condition.getExpression(), condition); } @Override - public void visitJetElementVoid(@NotNull JetElement element, CFPContext context) { + public void visitJetElement(@NotNull JetElement element) { throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString()); } }; @@ -159,9 +142,9 @@ public class JetControlFlowProcessor { builder.mark(element); } - public void generateInstructions(@Nullable JetElement element, CFPContext context) { + public void generateInstructions(@Nullable JetElement element) { if (element == null) return; - element.accept(this, context); + element.accept(this); checkNothingType(element); } @@ -265,26 +248,26 @@ public class JetControlFlowProcessor { } @Override - public void visitParenthesizedExpressionVoid(@NotNull JetParenthesizedExpression expression, CFPContext context) { + public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) { mark(expression); JetExpression innerExpression = expression.getExpression(); if (innerExpression != null) { - generateInstructions(innerExpression, context); + generateInstructions(innerExpression); copyValue(innerExpression, expression); } } @Override - public void visitAnnotatedExpressionVoid(@NotNull JetAnnotatedExpression expression, CFPContext context) { + public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) { JetExpression baseExpression = expression.getBaseExpression(); if (baseExpression != null) { - generateInstructions(baseExpression, context); + generateInstructions(baseExpression); copyValue(baseExpression, expression); } } @Override - public void visitThisExpressionVoid(@NotNull JetThisExpression expression, CFPContext context) { + public void visitThisExpression(@NotNull JetThisExpression expression) { ResolvedCall resolvedCall = getResolvedCall(expression); if (resolvedCall == null) { createNonSyntheticValue(expression); @@ -300,13 +283,13 @@ public class JetControlFlowProcessor { } @Override - public void visitConstantExpressionVoid(@NotNull JetConstantExpression expression, CFPContext context) { + public void visitConstantExpression(@NotNull JetConstantExpression expression) { CompileTimeConstant constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression); builder.loadConstant(expression, constant); } @Override - public void visitSimpleNameExpressionVoid(@NotNull JetSimpleNameExpression expression, CFPContext context) { + public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) { ResolvedCall resolvedCall = getResolvedCall(expression); if (resolvedCall instanceof VariableAsFunctionResolvedCall) { VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; @@ -318,18 +301,18 @@ public class JetControlFlowProcessor { } @Override - public void visitLabeledExpressionVoid(@NotNull JetLabeledExpression expression, CFPContext context) { + public void visitLabeledExpression(@NotNull JetLabeledExpression expression) { mark(expression); JetExpression baseExpression = expression.getBaseExpression(); if (baseExpression != null) { - generateInstructions(baseExpression, context); + generateInstructions(baseExpression); copyValue(baseExpression, expression); } } @SuppressWarnings("SuspiciousMethodCalls") @Override - public void visitBinaryExpressionVoid(@NotNull JetBinaryExpression expression, CFPContext context) { + public void visitBinaryExpression(@NotNull JetBinaryExpression expression) { JetSimpleNameExpression operationReference = expression.getOperationReference(); IElementType operationType = operationReference.getReferencedNameElementType(); @@ -364,12 +347,12 @@ public class JetControlFlowProcessor { } } else if (operationType == ELVIS) { - generateInstructions(left, NOT_IN_CONDITION); + generateInstructions(left); mark(expression); Label afterElvis = builder.createUnboundLabel(); builder.jumpOnTrue(afterElvis, expression, builder.getBoundValue(left)); if (right != null) { - generateInstructions(right, NOT_IN_CONDITION); + generateInstructions(right); } builder.bindLabel(afterElvis); mergeValues(Arrays.asList(left, right), expression); @@ -387,7 +370,7 @@ public class JetControlFlowProcessor { JetExpression right = expression.getRight(); Label resultLabel = builder.createUnboundLabel(); - generateInstructions(left, IN_CONDITION); + generateInstructions(left); if (operationType == ANDAND) { builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left)); } @@ -395,7 +378,7 @@ public class JetControlFlowProcessor { builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left)); } if (right != null) { - generateInstructions(right, IN_CONDITION); + generateInstructions(right); } builder.bindLabel(resultLabel); JetControlFlowBuilder.PredefinedOperation operation = operationType == ANDAND ? AND : OR; @@ -415,7 +398,7 @@ public class JetControlFlowProcessor { return new Function0() { @Override public PseudoValue invoke() { - generateInstructions(expression, NOT_IN_CONDITION); + generateInstructions(expression); return builder.getBoundValue(expression); } }; @@ -424,11 +407,11 @@ public class JetControlFlowProcessor { private void generateBothArgumentsAndMark(JetBinaryExpression expression) { JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft()); if (left != null) { - generateInstructions(left, NOT_IN_CONDITION); + generateInstructions(left); } JetExpression right = expression.getRight(); if (right != null) { - generateInstructions(right, NOT_IN_CONDITION); + generateInstructions(right); } createNonSyntheticValue(expression, left, right); mark(expression); @@ -488,7 +471,7 @@ public class JetControlFlowProcessor { mark(lhs); } - generateInstructions(lhs.getArrayExpression(), NOT_IN_CONDITION); + generateInstructions(lhs.getArrayExpression()); Map receiverValues = getReceiverValues(lhs, setResolvedCall, false); SmartFMap argumentValues = @@ -571,10 +554,10 @@ public class JetControlFlowProcessor { JetExpression arrayExpression = arrayAccessExpression.getArrayExpression(); inputExpressions.add(arrayExpression); - generateInstructions(arrayExpression, NOT_IN_CONDITION); + generateInstructions(arrayExpression); for (JetExpression index : arrayAccessExpression.getIndexExpressions()) { - generateInstructions(index, NOT_IN_CONDITION); + generateInstructions(index); inputExpressions.add(index); } @@ -582,13 +565,13 @@ public class JetControlFlowProcessor { } @Override - public void visitUnaryExpressionVoid(@NotNull JetUnaryExpression expression, CFPContext context) { + public void visitUnaryExpression(@NotNull JetUnaryExpression expression) { JetSimpleNameExpression operationSign = expression.getOperationReference(); IElementType operationType = operationSign.getReferencedNameElementType(); JetExpression baseExpression = expression.getBaseExpression(); if (baseExpression == null) return; if (JetTokens.EXCLEXCL == operationType) { - generateInstructions(baseExpression, NOT_IN_CONDITION); + generateInstructions(baseExpression); builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(Collections.singletonList(baseExpression))); return; } @@ -601,7 +584,7 @@ public class JetControlFlowProcessor { rhsValue = generateCall(incrementOrDecrement ? null : expression, operationSign, resolvedCall).getOutputValue(); } else { - generateInstructions(baseExpression, NOT_IN_CONDITION); + generateInstructions(baseExpression); rhsValue = createNonSyntheticValue(expression, baseExpression); } @@ -615,19 +598,19 @@ public class JetControlFlowProcessor { } @Override - public void visitIfExpressionVoid(@NotNull JetIfExpression expression, CFPContext context) { + public void visitIfExpression(@NotNull JetIfExpression expression) { mark(expression); List branches = new ArrayList(2); JetExpression condition = expression.getCondition(); if (condition != null) { - generateInstructions(condition, IN_CONDITION); + generateInstructions(condition); } Label elseLabel = builder.createUnboundLabel(); builder.jumpOnFalse(elseLabel, expression, builder.getBoundValue(condition)); JetExpression thenBranch = expression.getThen(); if (thenBranch != null) { branches.add(thenBranch); - generateInstructions(thenBranch, context); + generateInstructions(thenBranch); } else { builder.loadUnit(expression); @@ -638,7 +621,7 @@ public class JetControlFlowProcessor { JetExpression elseBranch = expression.getElse(); if (elseBranch != null) { branches.add(elseBranch); - generateInstructions(elseBranch, context); + generateInstructions(elseBranch); } else { builder.loadUnit(expression); @@ -649,13 +632,11 @@ public class JetControlFlowProcessor { private class FinallyBlockGenerator { private final JetFinallySection finallyBlock; - private final CFPContext context; private Label startFinally = null; private Label finishFinally = null; - private FinallyBlockGenerator(JetFinallySection block, CFPContext context) { + private FinallyBlockGenerator(JetFinallySection block) { finallyBlock = block; - this.context = context; } public void generate() { @@ -668,18 +649,18 @@ public class JetControlFlowProcessor { } startFinally = builder.createUnboundLabel("start finally"); builder.bindLabel(startFinally); - generateInstructions(finalExpression, context); + generateInstructions(finalExpression); finishFinally = builder.createUnboundLabel("finish finally"); builder.bindLabel(finishFinally); } } @Override - public void visitTryExpressionVoid(@NotNull JetTryExpression expression, CFPContext context) { + public void visitTryExpression(@NotNull JetTryExpression expression) { mark(expression); JetFinallySection finallyBlock = expression.getFinallyBlock(); - final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock, context); + final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock); boolean hasFinally = finallyBlock != null; if (hasFinally) { builder.enterTryFinally(new GenerationTrigger() { @@ -696,7 +677,7 @@ public class JetControlFlowProcessor { }); } - Label onExceptionToFinallyBlock = generateTryAndCatches(expression, context); + Label onExceptionToFinallyBlock = generateTryAndCatches(expression); if (hasFinally) { assert onExceptionToFinallyBlock != null : "No finally lable generated: " + expression.getText(); @@ -723,7 +704,7 @@ public class JetControlFlowProcessor { // Returns label for 'finally' block @Nullable - private Label generateTryAndCatches(@NotNull JetTryExpression expression, CFPContext context) { + private Label generateTryAndCatches(@NotNull JetTryExpression expression) { List catchClauses = expression.getCatchClauses(); boolean hasCatches = !catchClauses.isEmpty(); @@ -740,7 +721,7 @@ public class JetControlFlowProcessor { } JetBlockExpression tryBlock = expression.getTryBlock(); - generateInstructions(tryBlock, context); + generateInstructions(tryBlock); if (hasCatches) { Label afterCatches = builder.createUnboundLabel("afterCatches"); @@ -771,7 +752,7 @@ public class JetControlFlowProcessor { } JetExpression catchBody = catchClause.getCatchBody(); if (catchBody != null) { - generateInstructions(catchBody, NOT_IN_CONDITION); + generateInstructions(catchBody); } builder.jump(afterCatches, expression); builder.exitLexicalScope(catchClause); @@ -784,13 +765,13 @@ public class JetControlFlowProcessor { } @Override - public void visitWhileExpressionVoid(@NotNull JetWhileExpression expression, CFPContext context) { + public void visitWhileExpression(@NotNull JetWhileExpression expression) { LoopInfo loopInfo = builder.enterLoop(expression, null, null); builder.bindLabel(loopInfo.getConditionEntryPoint()); JetExpression condition = expression.getCondition(); if (condition != null) { - generateInstructions(condition, IN_CONDITION); + generateInstructions(condition); } mark(expression); boolean conditionIsTrueConstant = CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace, true); @@ -801,7 +782,7 @@ public class JetControlFlowProcessor { builder.bindLabel(loopInfo.getBodyEntryPoint()); JetExpression body = expression.getBody(); if (body != null) { - generateInstructions(body, NOT_IN_CONDITION); + generateInstructions(body); } builder.jump(loopInfo.getEntryPoint(), expression); builder.exitLoop(expression); @@ -809,7 +790,7 @@ public class JetControlFlowProcessor { } @Override - public void visitDoWhileExpressionVoid(@NotNull JetDoWhileExpression expression, CFPContext context) { + public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) { builder.enterLexicalScope(expression); mark(expression); LoopInfo loopInfo = builder.enterLoop(expression, null, null); @@ -817,12 +798,12 @@ public class JetControlFlowProcessor { builder.bindLabel(loopInfo.getBodyEntryPoint()); JetExpression body = expression.getBody(); if (body != null) { - generateInstructions(body, NOT_IN_CONDITION); + generateInstructions(body); } builder.bindLabel(loopInfo.getConditionEntryPoint()); JetExpression condition = expression.getCondition(); if (condition != null) { - generateInstructions(condition, IN_CONDITION); + generateInstructions(condition); } builder.jumpOnTrue(loopInfo.getEntryPoint(), expression, builder.getBoundValue(condition)); builder.exitLoop(expression); @@ -831,12 +812,12 @@ public class JetControlFlowProcessor { } @Override - public void visitForExpressionVoid(@NotNull JetForExpression expression, CFPContext context) { + public void visitForExpression(@NotNull JetForExpression expression) { builder.enterLexicalScope(expression); JetExpression loopRange = expression.getLoopRange(); if (loopRange != null) { - generateInstructions(loopRange, NOT_IN_CONDITION); + generateInstructions(loopRange); } declareLoopParameter(expression); @@ -855,7 +836,7 @@ public class JetControlFlowProcessor { mark(expression); JetExpression body = expression.getBody(); if (body != null) { - generateInstructions(body, NOT_IN_CONDITION); + generateInstructions(body); } builder.nondeterministicJump(loopInfo.getEntryPoint(), expression, null); @@ -904,7 +885,7 @@ public class JetControlFlowProcessor { } @Override - public void visitBreakExpressionVoid(@NotNull JetBreakExpression expression, CFPContext context) { + public void visitBreakExpression(@NotNull JetBreakExpression expression) { JetElement loop = getCorrespondingLoop(expression); if (loop != null) { checkJumpDoesNotCrossFunctionBoundary(expression, loop); @@ -913,7 +894,7 @@ public class JetControlFlowProcessor { } @Override - public void visitContinueExpressionVoid(@NotNull JetContinueExpression expression, CFPContext context) { + public void visitContinueExpression(@NotNull JetContinueExpression expression) { JetElement loop = getCorrespondingLoop(expression); if (loop != null) { checkJumpDoesNotCrossFunctionBoundary(expression, loop); @@ -956,10 +937,10 @@ public class JetControlFlowProcessor { } @Override - public void visitReturnExpressionVoid(@NotNull JetReturnExpression expression, CFPContext context) { + public void visitReturnExpression(@NotNull JetReturnExpression expression) { JetExpression returnedExpression = expression.getReturnedExpression(); if (returnedExpression != null) { - generateInstructions(returnedExpression, NOT_IN_CONDITION); + generateInstructions(returnedExpression); } JetSimpleNameExpression labelElement = expression.getTargetLabel(); JetElement subroutine; @@ -991,20 +972,20 @@ public class JetControlFlowProcessor { } @Override - public void visitParameterVoid(@NotNull JetParameter parameter, CFPContext context) { + public void visitParameter(@NotNull JetParameter parameter) { builder.declareParameter(parameter); JetExpression defaultValue = parameter.getDefaultValue(); if (defaultValue != null) { Label skipDefaultValue = builder.createUnboundLabel("after default value for parameter " + parameter.getName()); builder.nondeterministicJump(skipDefaultValue, defaultValue, null); - generateInstructions(defaultValue, context); + generateInstructions(defaultValue); builder.bindLabel(skipDefaultValue); } generateInitializer(parameter, createSyntheticValue(parameter)); } @Override - public void visitBlockExpressionVoid(@NotNull JetBlockExpression expression, CFPContext context) { + public void visitBlockExpression(@NotNull JetBlockExpression expression) { boolean declareLexicalScope = !isBlockInDoWhile(expression); if (declareLexicalScope) { builder.enterLexicalScope(expression); @@ -1012,7 +993,7 @@ public class JetControlFlowProcessor { mark(expression); List statements = expression.getStatements(); for (JetElement statement : statements) { - generateInstructions(statement, NOT_IN_CONDITION); + generateInstructions(statement); } if (statements.isEmpty()) { builder.loadUnit(expression); @@ -1032,12 +1013,12 @@ public class JetControlFlowProcessor { } @Override - public void visitNamedFunctionVoid(@NotNull JetNamedFunction function, CFPContext context) { + public void visitNamedFunction(@NotNull JetNamedFunction function) { processLocalDeclaration(function); } @Override - public void visitFunctionLiteralExpressionVoid(@NotNull JetFunctionLiteralExpression expression, CFPContext context) { + public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) { mark(expression); JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); processLocalDeclaration(functionLiteral); @@ -1045,39 +1026,39 @@ public class JetControlFlowProcessor { } @Override - public void visitQualifiedExpressionVoid(@NotNull JetQualifiedExpression expression, CFPContext context) { + public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) { mark(expression); JetExpression selectorExpression = expression.getSelectorExpression(); JetExpression receiverExpression = expression.getReceiverExpression(); // todo: replace with selectorExpresion != null after parser is fixed if (selectorExpression instanceof JetCallExpression || selectorExpression instanceof JetSimpleNameExpression) { - generateInstructions(selectorExpression, NOT_IN_CONDITION); + generateInstructions(selectorExpression); copyValue(selectorExpression, expression); } else { - generateInstructions(receiverExpression, NOT_IN_CONDITION); + generateInstructions(receiverExpression); createNonSyntheticValue(expression, receiverExpression); } } @Override - public void visitCallExpressionVoid(@NotNull JetCallExpression expression, CFPContext context) { + public void visitCallExpression(@NotNull JetCallExpression expression) { JetExpression calleeExpression = expression.getCalleeExpression(); if (!generateCall(expression, calleeExpression)) { List inputExpressions = new ArrayList(); for (ValueArgument argument : expression.getValueArguments()) { JetExpression argumentExpression = argument.getArgumentExpression(); if (argumentExpression != null) { - generateInstructions(argumentExpression, NOT_IN_CONDITION); + generateInstructions(argumentExpression); inputExpressions.add(argumentExpression); } } for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) { - generateInstructions(functionLiteral, NOT_IN_CONDITION); + generateInstructions(functionLiteral); inputExpressions.add(functionLiteral); } - generateInstructions(calleeExpression, NOT_IN_CONDITION); + generateInstructions(calleeExpression); inputExpressions.add(calleeExpression); inputExpressions.add(generateAndGetReceiverIfAny(expression)); @@ -1095,13 +1076,13 @@ public class JetControlFlowProcessor { if (qualifiedExpression.getSelectorExpression() != expression) return null; JetExpression receiverExpression = qualifiedExpression.getReceiverExpression(); - generateInstructions(receiverExpression, NOT_IN_CONDITION); + generateInstructions(receiverExpression); return receiverExpression; } @Override - public void visitPropertyVoid(@NotNull JetProperty property, CFPContext context) { + public void visitProperty(@NotNull JetProperty property) { builder.declareVariable(property); JetExpression initializer = property.getInitializer(); if (initializer != null) { @@ -1109,23 +1090,23 @@ public class JetControlFlowProcessor { } JetExpression delegate = property.getDelegateExpression(); if (delegate != null) { - generateInstructions(delegate, NOT_IN_CONDITION); + generateInstructions(delegate); } if (JetPsiUtil.isLocal(property)) { for (JetPropertyAccessor accessor : property.getAccessors()) { - generateInstructions(accessor, NOT_IN_CONDITION); + generateInstructions(accessor); } } } @Override - public void visitMultiDeclarationVoid(@NotNull JetMultiDeclaration declaration, CFPContext context) { + public void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration) { visitMultiDeclaration(declaration, true); } private void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration, boolean generateWriteForEntries) { JetExpression initializer = declaration.getInitializer(); - generateInstructions(initializer, NOT_IN_CONDITION); + generateInstructions(initializer); for (JetMultiDeclarationEntry entry : declaration.getEntries()) { builder.declareVariable(entry); @@ -1152,34 +1133,34 @@ public class JetControlFlowProcessor { } @Override - public void visitPropertyAccessorVoid(@NotNull JetPropertyAccessor accessor, CFPContext context) { + public void visitPropertyAccessor(@NotNull JetPropertyAccessor accessor) { processLocalDeclaration(accessor); } @Override - public void visitBinaryWithTypeRHSExpressionVoid(@NotNull JetBinaryExpressionWithTypeRHS expression, CFPContext context) { + public void visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression) { mark(expression); IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); JetExpression left = expression.getLeft(); if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) { - generateInstructions(left, NOT_IN_CONDITION); + generateInstructions(left); copyValue(left, expression); } else { - visitJetElementVoid(expression, context); + visitJetElement(expression); createNonSyntheticValue(expression, left); } } @Override - public void visitThrowExpressionVoid(@NotNull JetThrowExpression expression, CFPContext context) { + public void visitThrowExpression(@NotNull JetThrowExpression expression) { mark(expression); JetExpression thrownExpression = expression.getThrownExpression(); if (thrownExpression == null) return; - generateInstructions(thrownExpression, NOT_IN_CONDITION); + generateInstructions(thrownExpression); PseudoValue thrownValue = builder.getBoundValue(thrownExpression); if (thrownValue == null) return; @@ -1188,7 +1169,7 @@ public class JetControlFlowProcessor { } @Override - public void visitArrayAccessExpressionVoid(@NotNull JetArrayAccessExpression expression, CFPContext context) { + public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) { mark(expression); ResolvedCall getMethodResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_GET, expression); if (!checkAndGenerateCall(expression, expression, getMethodResolvedCall)) { @@ -1197,20 +1178,20 @@ public class JetControlFlowProcessor { } @Override - public void visitIsExpressionVoid(@NotNull JetIsExpression expression, CFPContext context) { + public void visitIsExpression(@NotNull JetIsExpression expression) { mark(expression); JetExpression left = expression.getLeftHandSide(); - generateInstructions(left, context); + generateInstructions(left); createNonSyntheticValue(expression, left); } @Override - public void visitWhenExpressionVoid(@NotNull JetWhenExpression expression, CFPContext context) { + public void visitWhenExpression(@NotNull JetWhenExpression expression) { mark(expression); JetExpression subjectExpression = expression.getSubjectExpression(); if (subjectExpression != null) { - generateInstructions(subjectExpression, context); + generateInstructions(subjectExpression); } boolean hasElse = false; @@ -1236,7 +1217,7 @@ public class JetControlFlowProcessor { JetWhenCondition[] conditions = whenEntry.getConditions(); for (int i = 0; i < conditions.length; i++) { JetWhenCondition condition = conditions[i]; - condition.accept(conditionVisitor, context); + condition.accept(conditionVisitor); if (i + 1 < conditions.length) { PseudoValue conditionValue = createSyntheticValue(condition, subjectExpression, condition); builder.nondeterministicJump(bodyLabel, expression, conditionValue); @@ -1256,7 +1237,7 @@ public class JetControlFlowProcessor { builder.bindLabel(bodyLabel); JetExpression whenEntryExpression = whenEntry.getExpression(); if (whenEntryExpression != null) { - generateInstructions(whenEntryExpression, context); + generateInstructions(whenEntryExpression); branches.add(whenEntryExpression); } builder.jump(doneLabel, expression); @@ -1274,28 +1255,28 @@ public class JetControlFlowProcessor { } @Override - public void visitObjectLiteralExpressionVoid(@NotNull JetObjectLiteralExpression expression, CFPContext context) { + public void visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression) { mark(expression); JetObjectDeclaration declaration = expression.getObjectDeclaration(); - generateInstructions(declaration, context); + generateInstructions(declaration); builder.createAnonymousObject(expression); } @Override - public void visitObjectDeclarationVoid(@NotNull JetObjectDeclaration objectDeclaration, CFPContext context) { - visitClassOrObject(objectDeclaration, context); + public void visitObjectDeclaration(@NotNull JetObjectDeclaration objectDeclaration) { + visitClassOrObject(objectDeclaration); } @Override - public void visitStringTemplateExpressionVoid(@NotNull JetStringTemplateExpression expression, CFPContext context) { + public void visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression) { mark(expression); List inputExpressions = new ArrayList(); for (JetStringTemplateEntry entry : expression.getEntries()) { if (entry instanceof JetStringTemplateEntryWithExpression) { JetExpression entryExpression = entry.getExpression(); - generateInstructions(entryExpression, NOT_IN_CONDITION); + generateInstructions(entryExpression); inputExpressions.add(entryExpression); } } @@ -1303,67 +1284,67 @@ public class JetControlFlowProcessor { } @Override - public void visitTypeProjectionVoid(@NotNull JetTypeProjection typeProjection, CFPContext context) { + public void visitTypeProjection(@NotNull JetTypeProjection typeProjection) { // TODO : Support Type Arguments. Class object may be initialized at this point"); } @Override - public void visitAnonymousInitializerVoid(@NotNull JetClassInitializer classInitializer, CFPContext context) { - generateInstructions(classInitializer.getBody(), context); + public void visitAnonymousInitializer(@NotNull JetClassInitializer classInitializer) { + generateInstructions(classInitializer.getBody()); } - private void visitClassOrObject(JetClassOrObject classOrObject, CFPContext context) { + private void visitClassOrObject(JetClassOrObject classOrObject) { for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) { - generateInstructions(specifier, context); + generateInstructions(specifier); } List declarations = classOrObject.getDeclarations(); if (classOrObject.isLocal()) { for (JetDeclaration declaration : declarations) { - generateInstructions(declaration, context); + generateInstructions(declaration); } return; } //For top-level and inner classes and objects functions are collected and checked separately. for (JetDeclaration declaration : declarations) { if (declaration instanceof JetProperty || declaration instanceof JetClassInitializer) { - generateInstructions(declaration, context); + generateInstructions(declaration); } } } @Override - public void visitClassVoid(@NotNull JetClass klass, CFPContext context) { + public void visitClass(@NotNull JetClass klass) { List parameters = klass.getPrimaryConstructorParameters(); for (JetParameter parameter : parameters) { - generateInstructions(parameter, context); + generateInstructions(parameter); } - visitClassOrObject(klass, context); + visitClassOrObject(klass); } @Override - public void visitDelegationToSuperCallSpecifierVoid(@NotNull JetDelegatorToSuperCall call, CFPContext context) { + public void visitDelegationToSuperCallSpecifier(@NotNull JetDelegatorToSuperCall call) { List valueArguments = call.getValueArguments(); for (ValueArgument valueArgument : valueArguments) { - generateInstructions(valueArgument.getArgumentExpression(), context); + generateInstructions(valueArgument.getArgumentExpression()); } } @Override - public void visitDelegationByExpressionSpecifierVoid(@NotNull JetDelegatorByExpressionSpecifier specifier, CFPContext context) { - generateInstructions(specifier.getDelegateExpression(), context); + public void visitDelegationByExpressionSpecifier(@NotNull JetDelegatorByExpressionSpecifier specifier) { + generateInstructions(specifier.getDelegateExpression()); } @Override - public void visitJetFileVoid(@NotNull JetFile file, CFPContext context) { + public void visitJetFile(@NotNull JetFile file) { for (JetDeclaration declaration : file.getDeclarations()) { if (declaration instanceof JetProperty) { - generateInstructions(declaration, context); + generateInstructions(declaration); } } } @Override - public void visitJetElementVoid(@NotNull JetElement element, CFPContext context) { + public void visitJetElement(@NotNull JetElement element) { builder.unsupported(element); } @@ -1440,7 +1421,7 @@ public class JetControlFlowProcessor { else if (receiver instanceof ExpressionReceiver) { JetExpression expression = ((ExpressionReceiver) receiver).getExpression(); if (generateInstructions) { - generateInstructions(expression, NOT_IN_CONDITION); + generateInstructions(expression); } PseudoValue receiverPseudoValue = builder.getBoundValue(expression); @@ -1478,7 +1459,7 @@ public class JetControlFlowProcessor { SmartFMap parameterValues) { JetExpression expression = valueArgument.getArgumentExpression(); if (expression != null) { - generateInstructions(expression, NOT_IN_CONDITION); + generateInstructions(expression); PseudoValue argValue = builder.getBoundValue(expression); if (argValue != null) { From 2077604d6d39fe2845f794cba9b2c0b6ce72941d Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 20 Jun 2014 19:37:28 +0400 Subject: [PATCH 014/143] Compute pseudo value for parameter correctly: do not throw away pseudo value for default value --- .../jet/lang/cfg/JetControlFlowProcessor.java | 12 +++++++++++- .../DefaultValuesForArguments.instructions | 16 ++++++++++------ .../cfg/functions/DefaultValuesForArguments.kt | 2 +- .../functions/DefaultValuesForArguments.values | 11 ++++++----- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 608ace76096..276c7c395f2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -981,7 +981,17 @@ public class JetControlFlowProcessor { generateInstructions(defaultValue); builder.bindLabel(skipDefaultValue); } - generateInitializer(parameter, createSyntheticValue(parameter)); + generateInitializer(parameter, computePseudoValueForParameter(parameter)); + } + + @NotNull + private PseudoValue computePseudoValueForParameter(@NotNull JetParameter parameter) { + PseudoValue syntheticValue = createSyntheticValue(parameter); + PseudoValue defaultValue = builder.getBoundValue(parameter.getDefaultValue()); + if (defaultValue == null) { + return syntheticValue; + } + return builder.merge(parameter, Lists.newArrayList(defaultValue, syntheticValue)).getOutputValue(); } @Override diff --git a/compiler/testData/cfg/functions/DefaultValuesForArguments.instructions b/compiler/testData/cfg/functions/DefaultValuesForArguments.instructions index a42371f93ab..c7177b5ce53 100644 --- a/compiler/testData/cfg/functions/DefaultValuesForArguments.instructions +++ b/compiler/testData/cfg/functions/DefaultValuesForArguments.instructions @@ -1,5 +1,5 @@ == foo == -fun foo(i: Int = 1) = i + 2 +fun foo(i: Int = 1, j: Int) = i + j --------------------- L0: 1 @@ -8,11 +8,15 @@ L0: r(1) -> L2 [after default value for parameter i]: magic(i: Int = 1) -> PREV:[jmp?(L2 [after default value for parameter i]), r(1) -> ] - w(i|) - r(i) -> - r(2) -> - mark(i + 2) - call(+, plus|, ) -> + merge(i: Int = 1|, ) -> + w(i|) + v(j: Int) + magic(j: Int) -> + w(j|) + r(i) -> + r(j) -> + mark(i + j) + call(+, plus|, ) -> L1: NEXT:[] error: diff --git a/compiler/testData/cfg/functions/DefaultValuesForArguments.kt b/compiler/testData/cfg/functions/DefaultValuesForArguments.kt index 3b6a8f9835c..29b4d4e0d46 100644 --- a/compiler/testData/cfg/functions/DefaultValuesForArguments.kt +++ b/compiler/testData/cfg/functions/DefaultValuesForArguments.kt @@ -1 +1 @@ -fun foo(i: Int = 1) = i + 2 \ No newline at end of file +fun foo(i: Int = 1, j: Int) = i + j \ No newline at end of file diff --git a/compiler/testData/cfg/functions/DefaultValuesForArguments.values b/compiler/testData/cfg/functions/DefaultValuesForArguments.values index 4c5426bd1d6..ce90d8c6d3c 100644 --- a/compiler/testData/cfg/functions/DefaultValuesForArguments.values +++ b/compiler/testData/cfg/functions/DefaultValuesForArguments.values @@ -1,8 +1,9 @@ == foo == -fun foo(i: Int = 1) = i + 2 +fun foo(i: Int = 1, j: Int) = i + j --------------------- -1 NEW() -i NEW() -2 NEW() -i + 2 NEW(, ) +1 NEW() +i: Int = 1 NEW(, ) +i NEW() +j NEW() +i + j NEW(, ) ===================== From 250b9b500b5c27830d3c5f781e9d1a2960ac2f81 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 30 May 2014 12:00:08 +0400 Subject: [PATCH 015/143] Eval4j: initialize frame with local variables values using type size #KT-5133 Fixed --- eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt b/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt index 1c10c518841..c155c691bac 100644 --- a/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt +++ b/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt @@ -33,14 +33,18 @@ fun makeInitialFrame(methodNode: MethodNode, arguments: List): Frame(methodNode.maxLocals, methodNode.maxStack) frame.setReturn(makeNotInitializedValue(Type.getReturnType(methodNode.desc))) + var index = 0 for ((i, arg) in arguments.withIndices()) { - frame.setLocal(i, arg) + frame.setLocal(index++, arg) + if (arg.getSize() == 2) { + frame.setLocal(index++, NOT_A_VALUE) + } } - for (i in arguments.size..methodNode.maxLocals - 1) { - frame.setLocal(i, NOT_A_VALUE) + while (index < methodNode.maxLocals) { + frame.setLocal(index++, NOT_A_VALUE) } - + return frame } From 906a3ea9051b7a96ac4a2e79a315ea8b9e5b4b35 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 30 May 2014 12:19:40 +0400 Subject: [PATCH 016/143] Evaluate expression: test with doubles --- idea/testData/debugger/tinyApp/outs/doubles.out | 7 +++++++ .../testData/debugger/tinyApp/src/evaluate/doubles.kt | 11 +++++++++++ .../KotlinEvaluateExpressionTestGenerated.java | 5 +++++ 3 files changed, 23 insertions(+) create mode 100644 idea/testData/debugger/tinyApp/outs/doubles.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/doubles.kt diff --git a/idea/testData/debugger/tinyApp/outs/doubles.out b/idea/testData/debugger/tinyApp/outs/doubles.out new file mode 100644 index 00000000000..7fc4417f6d8 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/doubles.out @@ -0,0 +1,7 @@ +LineBreakpoint created at doubles.kt:7 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! doubles.DoublesPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +doubles.kt:6 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/doubles.kt b/idea/testData/debugger/tinyApp/src/evaluate/doubles.kt new file mode 100644 index 00000000000..1ba2c60ef79 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/doubles.kt @@ -0,0 +1,11 @@ +package doubles + +fun main(args: Array) { + val d1 = 1.0 + val d2 = 3.0 + //Breakpoint! + args.size +} + +// EXPRESSION: d1 + d2 +// RESULT: 4.0: D \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index 73973e98407..d2831a31d1c 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -66,6 +66,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doTest("idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt"); } + @TestMetadata("doubles.kt") + public void testDoubles() throws Exception { + doTest("idea/testData/debugger/tinyApp/src/evaluate/doubles.kt"); + } + @TestMetadata("enums.kt") public void testEnums() throws Exception { doTest("idea/testData/debugger/tinyApp/src/evaluate/enums.kt"); From 03d2e89c6baef53a7368bd330b5648a6371c8336 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Thu, 5 Jun 2014 13:15:15 +0400 Subject: [PATCH 017/143] Fix typo --- .../plugin/refactoring/extractFunction/ExtractionDescriptor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt index c949d5451d6..c0684afe901 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt @@ -165,7 +165,7 @@ class AnalysisResult ( fun renderMessage(): String { val message = JetRefactoringBundle.message(when(this) { - NO_EXPRESSION -> "cannot.refactor.no.expresson" + NO_EXPRESSION -> "cannot.refactor.no.expression" NO_CONTAINER -> "cannot.refactor.no.container" SUPER_CALL -> "cannot.extract.super.call" DENOTABLE_TYPES -> "parameter.types.are.not.denotable" From 7671962284ac47c2dc7b4a23e104f0ae85ecace0 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 28 May 2014 15:09:55 +0400 Subject: [PATCH 018/143] Evaluate expression: move helper methods for extract function to separate file --- .../evaluate/KotlinEvaluationBuilder.kt | 110 -------------- .../extractFunctionForDebuggerUtil.kt | 139 ++++++++++++++++++ 2 files changed, 139 insertions(+), 110 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index b039b139d48..189f27bd444 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -43,17 +43,9 @@ import org.jetbrains.eval4j.jdi.asJdiValue import org.jetbrains.eval4j.jdi.makeInitialFrame import org.jetbrains.jet.lang.resolve.java.PackageClassUtils import org.jetbrains.jet.lang.resolve.name.FqName -import org.jetbrains.jet.lang.psi.JetPsiFactory import org.jetbrains.eval4j.jdi.asValue -import org.jetbrains.jet.plugin.refactoring.createTempCopy -import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData -import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis -import org.jetbrains.jet.plugin.refactoring.extractFunction.validate -import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction import org.jetbrains.jet.lang.psi.JetNamedFunction -import com.intellij.psi.PsiFile import org.jetbrains.jet.codegen.ClassFileFactory -import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils import org.jetbrains.jet.OutputFileCollection import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults import org.jetbrains.jet.lang.psi.JetCodeFragment @@ -63,15 +55,11 @@ import org.jetbrains.jet.lang.psi.JetExpression import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status import com.intellij.openapi.diagnostic.Logger import org.jetbrains.jet.codegen.CompilationErrorHandler -import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult -import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage import org.jetbrains.jet.lang.diagnostics.Severity import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages import com.sun.jdi.request.EventRequest import com.sun.jdi.ObjectReference import com.intellij.debugger.engine.SuspendContext -import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions -import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder object KotlinEvaluationBuilder: EvaluatorBuilder { override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator { @@ -271,38 +259,6 @@ private fun createFileForDebugger(codeFragment: JetCodeFragment, return jetFile } -fun addImportsToFile(newImportList: JetImportList?, tmpFile: JetFile) { - if (newImportList != null) { - val tmpFileImportList = tmpFile.getImportList() - val packageDirective = tmpFile.getPackageDirective() - if (tmpFileImportList == null) { - tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective) - tmpFile.addAfter(newImportList, tmpFile.getPackageDirective()) - } - else { - tmpFileImportList.replace(newImportList) - } - tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective) - } -} - -fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment, contextElement: PsiElement): JetExpression? { - val parent = contextElement.getParent() - if (parent == null) return null - - parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement) - - val debugExpression = codeFragment.getContentElement() - if (debugExpression == null) return null - - val newDebugExpression = parent.addBefore(debugExpression, contextElement) - if (newDebugExpression == null) return null - - parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement) - - return newDebugExpression as JetExpression -} - fun checkForSyntacticErrors(file: JetFile) { try { AnalyzingUtils.checkForSyntacticErrors(file) @@ -312,69 +268,3 @@ fun checkForSyntacticErrors(file: JetFile) { } } -private fun getFunctionForExtractedFragment( - codeFragment: JetCodeFragment, - breakpointFile: PsiFile, - breakpointLine: Int -): JetNamedFunction? { - - fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String { - return analysisResult.messages.map { - errorMessage -> - val message = when(errorMessage) { - ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression" - ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}" - ErrorMessage.SUPER_CALL -> "Cannot perform an action for expression with super call" - ErrorMessage.DENOTABLE_TYPES -> "Cannot perform an action because following types are unavailable from debugger scope" - ErrorMessage.MULTIPLE_OUTPUT -> "Cannot perform an action because this code fragment changes more than one variable" - ErrorMessage.DECLARATIONS_OUT_OF_SCOPE, - ErrorMessage.OUTPUT_AND_EXIT_POINT, - ErrorMessage.MULTIPLE_EXIT_POINTS, - ErrorMessage.VARIABLES_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression" - } - if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}" - }.makeString(", ") - } - - return ApplicationManager.getApplication()?.runReadAction(object: Computable { - override fun compute(): JetNamedFunction? { - checkForSyntacticErrors(codeFragment) - - val originalFile = breakpointFile as JetFile - - val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine) - if (lineStart == null) return null - - val tmpFile = originalFile.createTempCopy { it } - tmpFile.skipVisibilityCheck = true - - val elementAtOffset = tmpFile.findElementAt(lineStart) - if (elementAtOffset == null) return null - - val contextElement: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset - - addImportsToFile(codeFragment.importsAsImportList(), tmpFile) - - val newDebugExpression = addDebugExpressionBeforeContextElement(codeFragment, contextElement) - if (newDebugExpression == null) return null - - val targetSibling = tmpFile.getDeclarations().firstOrNull() - if (targetSibling == null) return null - - val analysisResult = ExtractionData( - tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false) - ).performAnalysis() - if (analysisResult.status != Status.SUCCESS) { - throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult)) - } - - val validationResult = analysisResult.descriptor!!.validate() - if (!validationResult.conflicts.isEmpty()) { - throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet()?.map { it.getText() }?.makeString(",")}") - } - - return validationResult.descriptor.generateFunction(true) - } - }) -} - diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt new file mode 100644 index 00000000000..a932c5024db --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2010-2014 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.debugger.evaluate + +import org.jetbrains.jet.lang.psi.JetCodeFragment +import com.intellij.psi.PsiFile +import org.jetbrains.jet.lang.psi.JetNamedFunction +import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult +import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.util.Computable +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils +import org.jetbrains.jet.plugin.refactoring.createTempCopy +import org.jetbrains.jet.lang.psi.codeFragmentUtil.skipVisibilityCheck +import com.intellij.psi.PsiElement +import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData +import java.util.Collections +import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis +import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status +import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil +import org.jetbrains.jet.plugin.refactoring.extractFunction.validate +import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction +import org.jetbrains.jet.lang.psi.JetImportList +import org.jetbrains.jet.lang.psi.JetPsiFactory +import org.jetbrains.jet.lang.psi.JetExpression +import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions + +fun getFunctionForExtractedFragment( + codeFragment: JetCodeFragment, + breakpointFile: PsiFile, + breakpointLine: Int +): JetNamedFunction? { + + fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String { + return analysisResult.messages.map { + errorMessage -> + val message = when(errorMessage) { + ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression" + ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.getName()}:${breakpointLine}" + ErrorMessage.SUPER_CALL -> "Cannot perform an action for expression with super call" + ErrorMessage.DENOTABLE_TYPES -> "Cannot perform an action because following types are unavailable from debugger scope" + ErrorMessage.MULTIPLE_OUTPUT -> "Cannot perform an action because this code fragment changes more than one variable" + ErrorMessage.DECLARATIONS_OUT_OF_SCOPE, + ErrorMessage.OUTPUT_AND_EXIT_POINT, + ErrorMessage.MULTIPLE_EXIT_POINTS, + ErrorMessage.VARIABLES_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression" + } + if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}" + }.makeString(", ") + } + + return ApplicationManager.getApplication()?.runReadAction(object: Computable { + override fun compute(): JetNamedFunction? { + checkForSyntacticErrors(codeFragment) + + val originalFile = breakpointFile as JetFile + + val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine) + if (lineStart == null) return null + + val tmpFile = originalFile.createTempCopy { it } + tmpFile.skipVisibilityCheck = true + + val elementAtOffset = tmpFile.findElementAt(lineStart) + if (elementAtOffset == null) return null + + val contextElement: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset + + addImportsToFile(codeFragment.importsAsImportList(), tmpFile) + + val newDebugExpression = addDebugExpressionBeforeContextElement(codeFragment, contextElement) + if (newDebugExpression == null) return null + + val targetSibling = tmpFile.getDeclarations().firstOrNull() + if (targetSibling == null) return null + + val analysisResult = ExtractionData( + tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false) + ).performAnalysis() + if (analysisResult.status != Status.SUCCESS) { + throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult)) + } + + val validationResult = analysisResult.descriptor!!.validate() + if (!validationResult.conflicts.isEmpty()) { + throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet()?.map { it.getText() }?.makeString(",")}") + } + + return validationResult.descriptor.generateFunction(true) + } + }) +} + +private fun addImportsToFile(newImportList: JetImportList?, tmpFile: JetFile) { + if (newImportList != null) { + val tmpFileImportList = tmpFile.getImportList() + val packageDirective = tmpFile.getPackageDirective() + if (tmpFileImportList == null) { + tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective) + tmpFile.addAfter(newImportList, tmpFile.getPackageDirective()) + } + else { + tmpFileImportList.replace(newImportList) + } + tmpFile.addAfter(JetPsiFactory.createNewLine(tmpFile.getProject()), packageDirective) + } +} + +private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment, contextElement: PsiElement): JetExpression? { + val parent = contextElement.getParent() + if (parent == null) return null + + parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement) + + val debugExpression = codeFragment.getContentElement() + if (debugExpression == null) return null + + val newDebugExpression = parent.addBefore(debugExpression, contextElement) + if (newDebugExpression == null) return null + + parent.addBefore(JetPsiFactory.createNewLine(contextElement.getProject()), contextElement) + + return newDebugExpression as JetExpression +} From a593738ca61d7cee031cdd31bc385df6d7e998b1 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Mon, 2 Jun 2014 19:08:57 +0400 Subject: [PATCH 019/143] Refactoring: extract method --- .../evaluate/KotlinEvaluationBuilder.kt | 192 ++++++++++-------- 1 file changed, 105 insertions(+), 87 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index 189f27bd444..a85b7b84c38 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -87,28 +87,55 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment, ) : Evaluator { override fun evaluate(context: EvaluationContextImpl): Any? { try { + val compiledData = extractAndCompile(codeFragment, sourcePosition) + return runEval4j(context, compiledData) + } + catch(e: EvaluateException) { + throw e + } + catch (e: Exception) { + logger.error("Couldn't evaluate expression:\nfileText = ${sourcePosition.getFile().getText()}\nline = ${sourcePosition.getLine()}\ncodeFragment = ${codeFragment.getText()}", e) + val cause = if (e.getMessage() != null) ": ${e.getMessage()}" else "" + exception("An exception occurs during Evaluate Expression Action $cause") + } + } + + override fun getModifier(): Modifier? { + return null + } + + class object { + private fun extractAndCompile(codeFragment: JetCodeFragment, sourcePosition: SourcePosition): CompiledDataDescriptor { val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine()) if (extractedFunction == null) { throw IllegalStateException("Code fragment cannot be extracted to function: ${sourcePosition.getFile().getText()}:${sourcePosition.getLine()},\ncodeFragment = ${codeFragment.getText()}") } - val classFileFactory = createClassFileFactory(extractedFunction) + val classFileFactory = createClassFileFactory(codeFragment, extractedFunction) // KT-4509 val outputFiles = (classFileFactory : OutputFileCollection).asList().filter { it.relativePath != "$packageInternalName.class" } if (outputFiles.size() != 1) exception("Expression compiles to more than one class file. Note that lambdas, classes and objects are unsupported yet. List of files: ${outputFiles.makeString(",")}") + val funName = extractedFunction.getName() + if (funName == null) { + throw IllegalStateException("Extracted function should have a name: ${extractedFunction.getText()}") + } + return CompiledDataDescriptor(outputFiles.first().asByteArray(), funName, extractedFunction.getParameterNamesForDebugger()) + } + + private fun runEval4j(context: EvaluationContextImpl, compiledData: CompiledDataDescriptor): Any? { val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine() var resultValue: Value? = null - ClassReader(outputFiles.first().asByteArray()).accept(object : ClassVisitor(ASM5) { + ClassReader(compiledData.bytecodes).accept(object : ClassVisitor(ASM5) { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { - if (name == extractedFunction.getName()) { + if (name == compiledData.funName) { return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { override fun visitEnd() { val value = interpreterLoop( this, - makeInitialFrame(this, context.getArgumentsByNames(extractedFunction.getParameterNamesForDebugger())), + makeInitialFrame(this, context.getArgumentsByNames(compiledData.parameterNames)), JDIEval(virtualMachine, context.getClassLoader()!!, context.getSuspendContext().getThread()?.getThreadReference()!!, context.getSuspendContext().getInvokePolicy()) @@ -128,104 +155,92 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment, }, 0) if (resultValue == null) { - throw IllegalStateException("resultValue is null: cannot find method ${extractedFunction.getName()} in ${outputFiles.first().relativePath}") + throw IllegalStateException("resultValue is null: cannot find method ${compiledData.funName}") } return resultValue!!.asJdiValue(virtualMachine, resultValue!!.asmType) } - catch(e: EvaluateException) { - throw e - } - catch (e: Exception) { - logger.error("Couldn't evaluate expression:\nfileText = ${sourcePosition.getFile().getText()}\nline = ${sourcePosition.getLine()}\ncodeFragment = ${codeFragment.getText()}", e) - val cause = if (e.getMessage() != null) ": ${e.getMessage()}" else "" - exception("An exception occurs during Evaluate Expression Action $cause") - } - } - override fun getModifier(): Modifier? { - return null - } - - private fun SuspendContext.getInvokePolicy(): Int { - return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0 - } - - private fun JetNamedFunction.getParameterNamesForDebugger(): List { - val result = arrayListOf() - if (getReceiverTypeRef() != null) { - result.add("this") + private fun SuspendContext.getInvokePolicy(): Int { + return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0 } - for (param in getValueParameters()) { - result.add(param.getName()!!) - } - return result - } - private fun EvaluationContextImpl.getArgumentsByNames(parameterNames: List): List { - val frames = getFrameProxy()?.getStackFrame() - if (frames != null) { - fun getValue(name: String): Value { - return try { - when (name) { - "this" -> frames.thisObject().asValue() - else -> frames.getValue(frames.visibleVariableByName(name)).asValue() - } - } - catch(e: Exception) { - exception("Cannot get parameter value from local variables table: parameterName = ${name}. Note that captured parameters are unsupported yet.") - } + private fun JetNamedFunction.getParameterNamesForDebugger(): List { + val result = arrayListOf() + if (getReceiverTypeRef() != null) { + result.add("this") } - - return parameterNames.map { getValue(it) } + for (param in getValueParameters()) { + result.add(param.getName()!!) + } + return result } - return Collections.emptyList() - } - private fun createClassFileFactory(extractedFunction: JetNamedFunction): ClassFileFactory { - return ApplicationManager.getApplication()?.runReadAction(object: Computable { - override fun compute(): ClassFileFactory? { - val file = createFileForDebugger(codeFragment, extractedFunction) - - checkForSyntacticErrors(file) - - val analyzeExhaust = file.getAnalysisResults() - if (analyzeExhaust.isError()) { - exception(analyzeExhaust.getError()) - } - - val bindingContext = analyzeExhaust.getBindingContext() - bindingContext.getDiagnostics().forEach { - diagnostic -> - if (diagnostic.getSeverity() == Severity.ERROR) { - exception(DefaultErrorMessages.RENDERER.render(diagnostic)) + private fun EvaluationContextImpl.getArgumentsByNames(parameterNames: List): List { + val frames = getFrameProxy()?.getStackFrame() + if (frames != null) { + fun getValue(name: String): Value { + return try { + when (name) { + "this" -> frames.thisObject().asValue() + else -> frames.getValue(frames.visibleVariableByName(name)).asValue() + } + } + catch(e: Exception) { + exception("Cannot get parameter value from local variables table: parameterName = ${name}. Note that captured parameters are unsupported yet.") } } - val state = GenerationState( - file.getProject(), - ClassBuilderFactories.BINARIES, - analyzeExhaust.getModuleDescriptor(), - bindingContext, - listOf(file) - ) - - KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION) - - return state.getFactory() + return parameterNames.map { getValue(it) } } - })!! - - } - - private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg) - - private fun exception(e: Throwable) { - val message = e.getMessage() - if (message != null) { - exception(message) + return Collections.emptyList() + } + + private fun createClassFileFactory(codeFragment: JetCodeFragment, extractedFunction: JetNamedFunction): ClassFileFactory { + return ApplicationManager.getApplication()?.runReadAction(object : Computable { + override fun compute(): ClassFileFactory? { + val file = createFileForDebugger(codeFragment, extractedFunction) + + checkForSyntacticErrors(file) + + val analyzeExhaust = file.getAnalysisResults() + if (analyzeExhaust.isError()) { + exception(analyzeExhaust.getError()) + } + + val bindingContext = analyzeExhaust.getBindingContext() + bindingContext.getDiagnostics().forEach { + diagnostic -> + if (diagnostic.getSeverity() == Severity.ERROR) { + exception(DefaultErrorMessages.RENDERER.render(diagnostic)) + } + } + + val state = GenerationState( + file.getProject(), + ClassBuilderFactories.BINARIES, + analyzeExhaust.getModuleDescriptor(), + bindingContext, + listOf(file) + ) + + KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION) + + return state.getFactory() + } + })!! + + } + + private fun exception(msg: String) = throw EvaluateExceptionUtil.createEvaluateException(msg) + + private fun exception(e: Throwable) { + val message = e.getMessage() + if (message != null) { + exception(message) + } + throw EvaluateExceptionUtil.createEvaluateException(e) } - throw EvaluateExceptionUtil.createEvaluateException(e) } } @@ -268,3 +283,6 @@ fun checkForSyntacticErrors(file: JetFile) { } } +data class CompiledDataDescriptor(val bytecodes: ByteArray, val funName: String, val parameterNames: List) + + From f4b01b5f4751a36ae18b01cf270e20c6d369975e Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 4 Jun 2014 18:07:27 +0400 Subject: [PATCH 020/143] Correct context element for watches --- .../plugin/debugger/evaluate/KotlinCodeFragmentFactory.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinCodeFragmentFactory.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinCodeFragmentFactory.kt index 904fd0125a0..850b9375f44 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinCodeFragmentFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinCodeFragmentFactory.kt @@ -50,7 +50,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() { override fun isContextAccepted(contextElement: PsiElement?): Boolean { if (contextElement is PsiCodeBlock) { - return contextElement.getContext()?.getContext()?.getLanguage() == JetFileType.INSTANCE.getLanguage() + return isContextAccepted(contextElement.getContext()) } return contextElement?.getLanguage() == JetFileType.INSTANCE.getLanguage() } @@ -63,6 +63,10 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() { fun getContextElement(elementAt: PsiElement?): PsiElement? { if (elementAt == null) return null + if (elementAt is PsiCodeBlock) { + return getContextElement(elementAt.getContext()) + } + val expressionAtOffset = PsiTreeUtil.findElementOfClassAtOffset(elementAt.getContainingFile()!!, elementAt.getTextOffset(), javaClass(), false) if (expressionAtOffset != null) { return expressionAtOffset From 0c17bbe1c4dad4d87b122a795b57ec83cadd15e5 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Thu, 12 Jun 2014 01:38:26 +0400 Subject: [PATCH 021/143] Minor: fix warnings --- eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt index af6d60070b2..6ca3861c850 100644 --- a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt +++ b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt @@ -66,7 +66,7 @@ class JDIEval( ) } - override fun loadString(str: String): Value = vm.mirrorOf(str)!!.asValue() + override fun loadString(str: String): Value = vm.mirrorOf(str).asValue() override fun newInstance(classType: Type): Value { return NewObjectValue(classType) @@ -253,12 +253,7 @@ class JDIEval( val dimensions = name.count { it == '[' } val baseTypeName = if (dimensions > 0) name.substring(0, name.indexOf('[')) else name - val primitiveType = primitiveTypes[baseTypeName] - val baseType = if (primitiveType != null) - primitiveType - else { - Type.getType("L$baseTypeName;").asReferenceType() - } + val baseType = primitiveTypes[baseTypeName] ?: Type.getType("L$baseTypeName;").asReferenceType() if (dimensions == 0) baseType From 53a1abf2e6a195b792cfd37c96ed454a7951dcd8 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Mon, 16 Jun 2014 13:10:16 +0400 Subject: [PATCH 022/143] DescriptorUtils.isSubclass: check type constructors for equality instead of checking descriptors --- .../jetbrains/jet/lang/resolve/DescriptorUtils.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 304d417863b..6a51a1e1a1b 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; +import javax.rmi.CORBA.ClassDesc; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -232,9 +233,15 @@ public class DescriptorUtils { private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) { DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); - if (descriptor != null && superClass == descriptor.getOriginal()) { - return true; + if (descriptor != null) { + DeclarationDescriptor originalDescriptor = descriptor.getOriginal(); + if (originalDescriptor instanceof ClassifierDescriptor + && superClass instanceof ClassifierDescriptor + && ((ClassifierDescriptor) superClass).getTypeConstructor().equals(((ClassifierDescriptor) originalDescriptor).getTypeConstructor())) { + return true; + } } + for (JetType superType : type.getConstructor().getSupertypes()) { if (isSubtypeOfClass(superType, superClass)) { return true; From b5f6df3144fa88e2eb47ab546349bf2bde89e89d Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Tue, 3 Jun 2014 12:44:31 +0400 Subject: [PATCH 023/143] Cache bytecodes for JetCodeFragment in Evaluate Expression --- .../jet/generators/tests/GenerateTests.kt | 3 +- idea/src/META-INF/plugin.xml | 3 + .../evaluate/KotlinEvaluateExpressionCache.kt | 119 ++++++++++ .../evaluate/KotlinEvaluationBuilder.kt | 124 ++++++---- ... allFilesPresentInMultipleBreakpoints.out} | 0 .../allFilesPresentInSingleBreakpoint.out | 0 .../debugger/tinyApp/outs/clearCache.out | 45 ++++ .../multipleBreakpoints/clearCache.kt | 206 ++++++++++++++++ .../{ => singleBreakpoint}/abstractFunCall.kt | 0 .../evaluate/{ => singleBreakpoint}/arrays.kt | 0 .../classFromAnotherPackage.kt | 0 .../{ => singleBreakpoint}/classObjectVal.kt | 0 .../{ => singleBreakpoint}/collections.kt | 0 .../collections.kt.fragment | 0 .../{ => singleBreakpoint}/dependentOnFile.kt | 0 .../{ => singleBreakpoint}/doubles.kt | 0 .../evaluate/{ => singleBreakpoint}/enums.kt | 0 .../evaluate/{ => singleBreakpoint}/errors.kt | 0 .../{ => singleBreakpoint}/errors.kt.fragment | 0 .../errors.kt.fragment2 | 0 .../extractLocalVariables.kt | 0 .../{ => singleBreakpoint}/extractThis.kt | 0 .../extractVariablesFromCall.kt | 0 .../{ => singleBreakpoint}/imports.kt | 0 .../{ => singleBreakpoint}/insertInBlock.kt | 0 .../multilineExpressionAtBreakpoint.kt | 0 .../{ => singleBreakpoint}/privateMember.kt | 0 .../{ => singleBreakpoint}/protectedMember.kt | 0 .../evaluate/{ => singleBreakpoint}/simple.kt | 0 .../{ => singleBreakpoint}/simple.kt.fragment | 0 .../evaluate/{ => singleBreakpoint}/stdlib.kt | 0 .../evaluate/{ => singleBreakpoint}/vars.kt | 0 .../AbstractKotlinEvaluateExpressionTest.kt | 73 ++++-- ...KotlinEvaluateExpressionTestGenerated.java | 223 ++++++++++-------- 34 files changed, 629 insertions(+), 167 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt rename idea/testData/debugger/tinyApp/outs/{allFilesPresentInEvaluate.out => allFilesPresentInMultipleBreakpoints.out} (100%) create mode 100644 idea/testData/debugger/tinyApp/outs/allFilesPresentInSingleBreakpoint.out create mode 100644 idea/testData/debugger/tinyApp/outs/clearCache.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/abstractFunCall.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/arrays.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/classFromAnotherPackage.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/classObjectVal.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/collections.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/collections.kt.fragment (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/dependentOnFile.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/doubles.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/enums.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/errors.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/errors.kt.fragment (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/errors.kt.fragment2 (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/extractLocalVariables.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/extractThis.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/extractVariablesFromCall.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/imports.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/insertInBlock.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/multilineExpressionAtBreakpoint.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/privateMember.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/protectedMember.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/simple.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/simple.kt.fragment (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/stdlib.kt (100%) rename idea/testData/debugger/tinyApp/src/evaluate/{ => singleBreakpoint}/vars.kt (100%) diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt index 6ae85ebc612..20f8e5867ca 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt @@ -612,7 +612,8 @@ fun main(args: Array) { } testClass(javaClass()) { - model("debugger/tinyApp/src/evaluate") + model("debugger/tinyApp/src/evaluate/singleBreakpoint", testMethod = "doSingleBreakpointTest") + model("debugger/tinyApp/src/evaluate/multipleBreakpoints", testMethod = "doMultipleBreakpointsTest") } testClass(javaClass()) { diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 808fb2a6898..e89c4c8ba1d 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -155,6 +155,9 @@ + + diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt new file mode 100644 index 00000000000..441e6776300 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2010-2014 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.debugger.evaluate + +import com.intellij.openapi.project.Project +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.PsiModificationTracker +import org.jetbrains.jet.lang.psi.JetCodeFragment +import com.intellij.debugger.SourcePosition +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl +import java.util.ArrayList +import com.intellij.openapi.components.ServiceManager +import org.jetbrains.org.objectweb.asm.Type +import com.intellij.util.containers.MultiMap +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.openapi.application.ApplicationManager +import org.jetbrains.jet.lang.psi.JetFile +import com.intellij.psi.JavaPsiFacade +import org.jetbrains.jet.lang.resolve.DescriptorUtils +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.plugin.caches.resolve.JavaResolveExtension +import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl +import org.jetbrains.jet.lang.resolve.java.JvmClassName +import org.jetbrains.jet.codegen.AsmUtil + +class KotlinEvaluateExpressionCache(val project: Project) { + + private val cachedCompiledData = CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result>( + MultiMap.create(), PsiModificationTracker.MODIFICATION_COUNT) + }, false) + + class object { + fun getInstance(project: Project) = ServiceManager.getService(project, javaClass())!! + + fun getOrCreateCompiledData( + codeFragment: JetCodeFragment, + sourcePosition: SourcePosition, + evaluationContext: EvaluationContextImpl, + create: (JetCodeFragment, SourcePosition) -> CompiledDataDescriptor + ): CompiledDataDescriptor { + val evaluateExpressionCache = getInstance(codeFragment.getProject()) + + return synchronized(evaluateExpressionCache.cachedCompiledData) { + (): CompiledDataDescriptor -> + val cache = evaluateExpressionCache.cachedCompiledData.getValue()!! + val text = "${codeFragment.importsToString()}\n${codeFragment.getText()}" + + val answer = cache[text].firstOrNull { + it.sourcePosition == sourcePosition || evaluateExpressionCache.canBeEvaluatedInThisContext(it, evaluationContext) + } + if (answer != null) return@synchronized answer + + val newCompiledData = create(codeFragment, sourcePosition) + cache.putValue(text, newCompiledData) + + return@synchronized newCompiledData + } + } + } + + private fun canBeEvaluatedInThisContext(compiledData: CompiledDataDescriptor, context: EvaluationContextImpl): Boolean { + return compiledData.parameters.all { (p): Boolean -> + val (name, jetType) = p + val value = context.getFrameProxy()?.getStackFrame()?.findLocalVariable(name, failIfNotFound = false) + if (value == null) return@all false + + val thisDescriptor = value.asmType.getClassDescriptor() + val superClassDescriptor = jetType.getConstructor().getDeclarationDescriptor() as? ClassDescriptor + return@all thisDescriptor != null && superClassDescriptor != null && DescriptorUtils.isSubclass(thisDescriptor, superClassDescriptor) + } + } + + private fun Type.getClassDescriptor(): ClassDescriptor? { + if (AsmUtil.isPrimitive(this)) return null + + val jvmName = JvmClassName.byInternalName(getInternalName()).getFqNameForClassNameWithoutDollars() + + val platformClasses = JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmName) + if (platformClasses.notEmpty) return platformClasses.first() + + return ApplicationManager.getApplication()?.runReadAction { + val classes = JavaPsiFacade.getInstance(project).findClasses(jvmName.asString(), GlobalSearchScope.allScope(project)) + if (classes.isEmpty()) null else JavaResolveExtension[project].resolveClass(JavaClassImpl(classes.first())) + } + } + + data class CompiledDataDescriptor(val bytecodes: ByteArray, val sourcePosition: SourcePosition, val funName: String, val parameters: ParametersDescriptor) + + class ParametersDescriptor : Iterable> { + private val list = ArrayList>() + + fun add(name: String, jetType: JetType) { + list.add(name to jetType) + } + + fun getParameterNames() = list.map { it.first } + + override fun iterator() = list.iterator() + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index a85b7b84c38..22942f81958 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -49,10 +49,7 @@ import org.jetbrains.jet.codegen.ClassFileFactory import org.jetbrains.jet.OutputFileCollection import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults import org.jetbrains.jet.lang.psi.JetCodeFragment -import org.jetbrains.jet.lang.psi.JetImportList import org.jetbrains.jet.lang.psi.codeFragmentUtil.skipVisibilityCheck -import org.jetbrains.jet.lang.psi.JetExpression -import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status import com.intellij.openapi.diagnostic.Logger import org.jetbrains.jet.codegen.CompilationErrorHandler import org.jetbrains.jet.lang.diagnostics.Severity @@ -60,6 +57,10 @@ import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages import com.sun.jdi.request.EventRequest import com.sun.jdi.ObjectReference import com.intellij.debugger.engine.SuspendContext +import org.jetbrains.jet.plugin.debugger.evaluate.KotlinEvaluateExpressionCache.* +import org.jetbrains.jet.lang.resolve.BindingContext +import com.sun.jdi.StackFrame +import com.sun.jdi.VirtualMachine object KotlinEvaluationBuilder: EvaluatorBuilder { override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator { @@ -86,9 +87,24 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment, val sourcePosition: SourcePosition ) : Evaluator { override fun evaluate(context: EvaluationContextImpl): Any? { + var isCompiledDataFromCache = true try { - val compiledData = extractAndCompile(codeFragment, sourcePosition) - return runEval4j(context, compiledData) + val compiledData = KotlinEvaluateExpressionCache.getOrCreateCompiledData(codeFragment, sourcePosition, context) { + fragment, position -> + isCompiledDataFromCache = false + extractAndCompile(fragment, position) + } + val args = context.getArgumentsByNames(compiledData.parameters.getParameterNames()) + val result = runEval4j(context, compiledData, args) + + val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine() + + // If bytecode was taken from cache and exception was thrown - recompile bytecode and run eval4j again + if (result is ExceptionThrown && isCompiledDataFromCache) { + return runEval4j(context, extractAndCompile(codeFragment, sourcePosition), args).toJdiValue(virtualMachine) + } + + return result.toJdiValue(virtualMachine) } catch(e: EvaluateException) { throw e @@ -121,77 +137,79 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment, if (funName == null) { throw IllegalStateException("Extracted function should have a name: ${extractedFunction.getText()}") } - return CompiledDataDescriptor(outputFiles.first().asByteArray(), funName, extractedFunction.getParameterNamesForDebugger()) + return CompiledDataDescriptor(outputFiles.first().asByteArray(), sourcePosition, funName, extractedFunction.getParametersForDebugger()) } - private fun runEval4j(context: EvaluationContextImpl, compiledData: CompiledDataDescriptor): Any? { + private fun runEval4j( + context: EvaluationContextImpl, + compiledData: CompiledDataDescriptor, + args: List + ): InterpreterResult { val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine() - var resultValue: Value? = null + var resultValue: InterpreterResult? = null ClassReader(compiledData.bytecodes).accept(object : ClassVisitor(ASM5) { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { if (name == compiledData.funName) { return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { override fun visitEnd() { - val value = interpreterLoop( + resultValue = interpreterLoop( this, - makeInitialFrame(this, context.getArgumentsByNames(compiledData.parameterNames)), + makeInitialFrame(this, args), JDIEval(virtualMachine, context.getClassLoader()!!, - context.getSuspendContext().getThread()?.getThreadReference()!!, context.getSuspendContext().getInvokePolicy()) + context.getSuspendContext().getThread()?.getThreadReference()!!, + context.getSuspendContext().getInvokePolicy()) ) - - resultValue = when (value) { - is ValueReturned -> value.result - is ExceptionThrown -> exception(value.exception.toString()) - is AbnormalTermination -> exception(value.message) - else -> throw IllegalStateException("Unknown result value produced by eval4j") - } } } } + return super.visitMethod(access, name, desc, signature, exceptions) } }, 0) - if (resultValue == null) { - throw IllegalStateException("resultValue is null: cannot find method ${compiledData.funName}") - } + return resultValue ?: throw IllegalStateException("resultValue is null: cannot find method ${compiledData.funName}") + } - return resultValue!!.asJdiValue(virtualMachine, resultValue!!.asmType) + private fun InterpreterResult.toJdiValue(vm: VirtualMachine): com.sun.jdi.Value? { + val jdiValue = when (this) { + is ValueReturned -> result + is ExceptionThrown -> exception(exception.toString()) + is AbnormalTermination -> exception(message) + else -> throw IllegalStateException("Unknown result value produced by eval4j") + } + return jdiValue.asJdiValue(vm, jdiValue.asmType) } private fun SuspendContext.getInvokePolicy(): Int { return if (getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) ObjectReference.INVOKE_SINGLE_THREADED else 0 } - private fun JetNamedFunction.getParameterNamesForDebugger(): List { - val result = arrayListOf() - if (getReceiverTypeRef() != null) { - result.add("this") - } - for (param in getValueParameters()) { - result.add(param.getName()!!) - } - return result + private fun JetNamedFunction.getParametersForDebugger(): ParametersDescriptor { + return ApplicationManager.getApplication()?.runReadAction(Computable { + val parameters = ParametersDescriptor() + val bindingContext = getAnalysisResults().getBindingContext() + val descriptor = bindingContext[BindingContext.FUNCTION, this] + if (descriptor != null) { + val receiver = descriptor.getReceiverParameter() + if (receiver != null) { + parameters.add("this", receiver.getType()) + } + + descriptor.getValueParameters().forEach { + param -> + parameters.add(param.getName().asString(), param.getType()) + } + } + parameters + })!! } private fun EvaluationContextImpl.getArgumentsByNames(parameterNames: List): List { val frames = getFrameProxy()?.getStackFrame() if (frames != null) { - fun getValue(name: String): Value { - return try { - when (name) { - "this" -> frames.thisObject().asValue() - else -> frames.getValue(frames.visibleVariableByName(name)).asValue() - } - } - catch(e: Exception) { - exception("Cannot get parameter value from local variables table: parameterName = ${name}. Note that captured parameters are unsupported yet.") - } - } - - return parameterNames.map { getValue(it) } + return parameterNames.map { frames.findLocalVariable(it)!! } } return Collections.emptyList() } @@ -283,6 +301,22 @@ fun checkForSyntacticErrors(file: JetFile) { } } -data class CompiledDataDescriptor(val bytecodes: ByteArray, val funName: String, val parameterNames: List) +fun StackFrame.findLocalVariable(name: String, failIfNotFound: Boolean = true): Value? { + return try { + when (name) { + "this" -> thisObject().asValue() + else -> getValue(visibleVariableByName(name)).asValue() + } + } + catch(e: Exception) { + if (failIfNotFound) { + throw EvaluateExceptionUtil.createEvaluateException( + "Cannot find local variable: name = ${name}. Note that captured variables are unsupported yet.") + } + else { + return null + } + } +} diff --git a/idea/testData/debugger/tinyApp/outs/allFilesPresentInEvaluate.out b/idea/testData/debugger/tinyApp/outs/allFilesPresentInMultipleBreakpoints.out similarity index 100% rename from idea/testData/debugger/tinyApp/outs/allFilesPresentInEvaluate.out rename to idea/testData/debugger/tinyApp/outs/allFilesPresentInMultipleBreakpoints.out diff --git a/idea/testData/debugger/tinyApp/outs/allFilesPresentInSingleBreakpoint.out b/idea/testData/debugger/tinyApp/outs/allFilesPresentInSingleBreakpoint.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/debugger/tinyApp/outs/clearCache.out b/idea/testData/debugger/tinyApp/outs/clearCache.out new file mode 100644 index 00000000000..4596499adcd --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/clearCache.out @@ -0,0 +1,45 @@ +LineBreakpoint created at clearCache.kt:12 +LineBreakpoint created at clearCache.kt:20 +LineBreakpoint created at clearCache.kt:31 +LineBreakpoint created at clearCache.kt:42 +LineBreakpoint created at clearCache.kt:52 +LineBreakpoint created at clearCache.kt:60 +LineBreakpoint created at clearCache.kt:78 +LineBreakpoint created at clearCache.kt:86 +LineBreakpoint created at clearCache.kt:95 +LineBreakpoint created at clearCache.kt:105 +LineBreakpoint created at clearCache.kt:113 +LineBreakpoint created at clearCache.kt:124 +LineBreakpoint created at clearCache.kt:133 +LineBreakpoint created at clearCache.kt:143 +LineBreakpoint created at clearCache.kt:151 +LineBreakpoint created at clearCache.kt:169 +LineBreakpoint created at clearCache.kt:174 +LineBreakpoint created at clearCache.kt:181 +LineBreakpoint created at clearCache.kt:189 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! clearCache.ClearCachePackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +clearCache.kt:11 +clearCache.kt:19 +clearCache.kt:30 +clearCache.kt:30 +clearCache.kt:41 +clearCache.kt:41 +clearCache.kt:51 +clearCache.kt:59 +clearCache.kt:77 +clearCache.kt:85 +clearCache.kt:94 +clearCache.kt:104 +clearCache.kt:112 +clearCache.kt:123 +clearCache.kt:132 +clearCache.kt:142 +clearCache.kt:150 +clearCache.kt:168 +clearCache.kt:173 +clearCache.kt:180 +clearCache.kt:188 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt new file mode 100644 index 00000000000..290a9a81261 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt @@ -0,0 +1,206 @@ +package clearCache + +import java.util.ArrayList +import java.util.HashSet + +fun primitiveTypes() { + if (true) { + val a: Any = 0 + // EXPRESSION: a + // RESULT: instance of java.lang.Integer(id=ID): Ljava/lang/Integer; + //Breakpoint! + val b = 1 + } + + if (true) { + val a = 1 + // EXPRESSION: a + // RESULT: 1: I + //Breakpoint! + val b = 1 + } + + for (i in 1..2) { + // EXPRESSION: i + // RESULT: 1: I + + // EXPRESSION: i + // RESULT: 2: I + + //Breakpoint! + val b = 1 + } + + for (i in 5.0..6.0) { + // EXPRESSION: i + // RESULT: 5.0: D + + // EXPRESSION: i + // RESULT: 6.0: D + + //Breakpoint! + val b = 1 + } +} + +fun subType() { + if (true) { + val o = Base() + // EXPRESSION: o.test() + // RESULT: 100: I + //Breakpoint! + val b = 1 + } + + if (true) { + val o = Derived() + // EXPRESSION: o.test() + // RESULT: 200: I + //Breakpoint! + val b = 1 + } +} + +open class Base { + open fun test() = 100 +} + +class Derived: Base() { + override fun test() = 200 +} + +fun subTypePlatform() { + if (true) { + val c: MutableList = ArrayList() + // EXPRESSION: c.size() + // RESULT: 0: I + //Breakpoint! + val b = 1 + } + + if (true) { + val c: List = ArrayList() + // EXPRESSION: c.size() + // RESULT: 0: I + //Breakpoint! + val b = 1 + } + + if (true) { + val c = ArrayList() + c.add("a") + // EXPRESSION: c.size() + // RESULT: 1: I + //Breakpoint! + val b = 1 + } + + if (true) { + val c = ArrayList() + c.add(1) + c.add(2) + // EXPRESSION: c.size() + // RESULT: 2: I + //Breakpoint! + val b = 1 + } + + if (true) { + val c = HashSet() + // EXPRESSION: c.size() + // RESULT: 0: I + //Breakpoint! + val b = 1 + } +} + +fun genericRerun() { + if (true) { + val c = ArrayList() + c.add(1) + // EXPRESSION: c.get(0) + // RESULT: 1: I + //Breakpoint! + val b = 1 + } + + if (true) { + val c = ArrayList() + c.add("a") + // EXPRESSION: c.get(0) + // RESULT: "a": Ljava/lang/String; + //Breakpoint! + val b = 1 + } +} + +fun innerClass() { + if (true) { + val o = TestInnerClasses.Base() + // EXPRESSION: o.test() + // RESULT: 100: I + //Breakpoint! + val b = 1 + } + + if (true) { + val o = TestInnerClasses.Derived() + // EXPRESSION: o.test() + // RESULT: 200: I + //Breakpoint! + val b = 1 + } +} + +class TestInnerClasses { + open class Base { + open fun test() = 100 + } + + class Derived: Base() { + override fun test() = 200 + } +} + +fun objects() { + // EXPRESSION: obj.test() + // RESULT: 1: I + //Breakpoint! + val a1 = 1 + + // EXPRESSION: obj.test() + // RESULT: 1: I + //Breakpoint! + val a2 = 1 + + if (true) { + val o: BaseObject = obj + // EXPRESSION: o.test() + // RESULT: 1: I + //Breakpoint! + val b = 1 + } + + if (true) { + val o = obj + // EXPRESSION: o.test() + // RESULT: 1: I + //Breakpoint! + val b = 1 + } +} + +val obj = object: BaseObject() { } + +open class BaseObject { + fun test() = 1 +} + +fun main(args: Array) { + primitiveTypes() + subType() + subTypePlatform() + genericRerun() + innerClass() + objects() +} diff --git a/idea/testData/debugger/tinyApp/src/evaluate/abstractFunCall.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/abstractFunCall.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/abstractFunCall.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/abstractFunCall.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/arrays.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/arrays.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/arrays.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/arrays.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/classFromAnotherPackage.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/classFromAnotherPackage.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/classFromAnotherPackage.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/classFromAnotherPackage.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/classObjectVal.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/classObjectVal.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/collections.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/collections.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/collections.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/collections.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/collections.kt.fragment b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/collections.kt.fragment similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/collections.kt.fragment rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/collections.kt.fragment diff --git a/idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/dependentOnFile.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/dependentOnFile.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/doubles.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/doubles.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/doubles.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/doubles.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/enums.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/enums.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/enums.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/enums.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/errors.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/errors.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/errors.kt.fragment b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/errors.kt.fragment rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment diff --git a/idea/testData/debugger/tinyApp/src/evaluate/errors.kt.fragment2 b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/errors.kt.fragment2 rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt.fragment2 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractLocalVariables.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractLocalVariables.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractThis.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractThis.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractVariablesFromCall.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractVariablesFromCall.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/imports.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/imports.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/imports.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/imports.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/insertInBlock.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/insertInBlock.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/insertInBlock.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/insertInBlock.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/multilineExpressionAtBreakpoint.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/multilineExpressionAtBreakpoint.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/privateMember.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/privateMember.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/protectedMember.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/protectedMember.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/protectedMember.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/protectedMember.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/simple.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/simple.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/simple.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/simple.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/simple.kt.fragment b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/simple.kt.fragment similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/simple.kt.fragment rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/simple.kt.fragment diff --git a/idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/stdlib.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/stdlib.kt diff --git a/idea/testData/debugger/tinyApp/src/evaluate/vars.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/vars.kt similarity index 100% rename from idea/testData/debugger/tinyApp/src/evaluate/vars.kt rename to idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/vars.kt diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt index ab25a5b2e2c..18a53380877 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt @@ -37,12 +37,9 @@ import java.util.Collections import com.intellij.debugger.engine.evaluation.EvaluateException public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestCase() { - fun doTest(path: String) { + fun doSingleBreakpointTest(path: String) { val file = File(path) - val fileContent = FileUtil.loadFile(file, true) - val expressions = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileContent, "// EXPRESSION: ") - val expectedExpressionResults = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileContent, "// RESULT: ") - assert(expressions.size == expectedExpressionResults.size, "Sizes of test directives are different") + val expressions = loadTestDirectivesPairs(file, "// EXPRESSION: ", "// RESULT: ") val blocks = findFilesWithBlocks(file).map { FileUtil.loadFile(it, true) } val expectedBlockResults = blocks.map { InTextDirectivesUtils.findLinesWithPrefixesRemoved(it, "// RESULT: ").makeString("\n") } @@ -51,34 +48,68 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC onBreakpoint { val exceptions = linkedMapOf() - for ((i, expression) in expressions.withIndices()) { - try { - evaluate(expression, CodeFragmentKind.EXPRESSION, expectedExpressionResults[i]) - } - catch (e: Throwable) { - exceptions.put(expression, e) + for ((expression, expected) in expressions) { + mayThrow(exceptions, expression) { + evaluate(expression, CodeFragmentKind.EXPRESSION, expected) } } for ((i, block) in blocks.withIndices()) { - try { + mayThrow(exceptions, block) { evaluate(block, CodeFragmentKind.CODE_BLOCK, expectedBlockResults[i]) } - catch (e: Throwable) { - exceptions.put(block, e) - } } - if (!exceptions.empty) { - for (exc in exceptions.values()) { - exc.printStackTrace() - } - throw AssertionError("Test failed:\n" + exceptions.map { "expression: ${it.key}, exception: ${it.value.getMessage()}" }.makeString("\n")) - } + checkExceptions(exceptions) } finish() } + fun doMultipleBreakpointsTest(path: String) { + val expressions = loadTestDirectivesPairs(File(path), "// EXPRESSION: ", "// RESULT: ") + + createDebugProcess(path) + + val exceptions = linkedMapOf() + for ((expression, expected) in expressions) { + mayThrow(exceptions, expression) { + onBreakpoint { + evaluate(expression, CodeFragmentKind.EXPRESSION, expected) + } + } + } + + checkExceptions(exceptions) + + finish() + } + + private fun checkExceptions(exceptions: MutableMap) { + if (!exceptions.empty) { + for (exc in exceptions.values()) { + exc.printStackTrace() + } + throw AssertionError("Test failed:\n" + exceptions.map { "expression: ${it.key}, exception: ${it.value.getMessage()}" }.makeString("\n")) + } + } + + private fun mayThrow(map: MutableMap, expression: String, f: () -> Unit) { + try { + f() + } + catch (e: Throwable) { + map.put(expression, e) + } + } + + private fun loadTestDirectivesPairs(file: File, directivePrefix: String, expectedPrefix: String): List> { + val fileContent = FileUtil.loadFile(file, true) + val directives = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileContent, directivePrefix) + val expected = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileContent, expectedPrefix) + assert(directives.size == expected.size, "Sizes of test directives are different") + return directives.zip(expected) + } + private fun findFilesWithBlocks(mainFile: File): List { val mainFileName = mainFile.getName() return mainFile.getParentFile()?.listFiles()?.filter { it.name.startsWith(mainFileName) && it.name != mainFileName } ?: Collections.emptyList() diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index d2831a31d1c..a9fe9459d19 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -30,110 +30,133 @@ import org.jetbrains.jet.plugin.debugger.evaluate.AbstractKotlinEvaluateExpressi /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") -@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate") +@InnerTestClasses({KotlinEvaluateExpressionTestGenerated.SingleBreakpoint.class, KotlinEvaluateExpressionTestGenerated.MultipleBreakpoints.class}) public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluateExpressionTest { - @TestMetadata("abstractFunCall.kt") - public void testAbstractFunCall() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/abstractFunCall.kt"); + @TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint") + public static class SingleBreakpoint extends AbstractKotlinEvaluateExpressionTest { + @TestMetadata("abstractFunCall.kt") + public void testAbstractFunCall() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/abstractFunCall.kt"); + } + + public void testAllFilesPresentInSingleBreakpoint() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("arrays.kt") + public void testArrays() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/arrays.kt"); + } + + @TestMetadata("classFromAnotherPackage.kt") + public void testClassFromAnotherPackage() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/classFromAnotherPackage.kt"); + } + + @TestMetadata("classObjectVal.kt") + public void testClassObjectVal() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/classObjectVal.kt"); + } + + @TestMetadata("collections.kt") + public void testCollections() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/collections.kt"); + } + + @TestMetadata("dependentOnFile.kt") + public void testDependentOnFile() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/dependentOnFile.kt"); + } + + @TestMetadata("doubles.kt") + public void testDoubles() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/doubles.kt"); + } + + @TestMetadata("enums.kt") + public void testEnums() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/enums.kt"); + } + + @TestMetadata("errors.kt") + public void testErrors() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/errors.kt"); + } + + @TestMetadata("extractLocalVariables.kt") + public void testExtractLocalVariables() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractLocalVariables.kt"); + } + + @TestMetadata("extractThis.kt") + public void testExtractThis() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractThis.kt"); + } + + @TestMetadata("extractVariablesFromCall.kt") + public void testExtractVariablesFromCall() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/extractVariablesFromCall.kt"); + } + + @TestMetadata("imports.kt") + public void testImports() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/imports.kt"); + } + + @TestMetadata("insertInBlock.kt") + public void testInsertInBlock() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/insertInBlock.kt"); + } + + @TestMetadata("multilineExpressionAtBreakpoint.kt") + public void testMultilineExpressionAtBreakpoint() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/multilineExpressionAtBreakpoint.kt"); + } + + @TestMetadata("privateMember.kt") + public void testPrivateMember() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt"); + } + + @TestMetadata("protectedMember.kt") + public void testProtectedMember() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/protectedMember.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/simple.kt"); + } + + @TestMetadata("stdlib.kt") + public void testStdlib() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/stdlib.kt"); + } + + @TestMetadata("vars.kt") + public void testVars() throws Exception { + doSingleBreakpointTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/vars.kt"); + } + } - public void testAllFilesPresentInEvaluate() throws Exception { - JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/debugger/tinyApp/src/evaluate"), Pattern.compile("^(.+)\\.kt$"), true); + @TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints") + public static class MultipleBreakpoints extends AbstractKotlinEvaluateExpressionTest { + public void testAllFilesPresentInMultipleBreakpoints() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("clearCache.kt") + public void testClearCache() throws Exception { + doMultipleBreakpointsTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt"); + } + } - @TestMetadata("arrays.kt") - public void testArrays() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/arrays.kt"); + public static Test suite() { + TestSuite suite = new TestSuite("KotlinEvaluateExpressionTestGenerated"); + suite.addTestSuite(SingleBreakpoint.class); + suite.addTestSuite(MultipleBreakpoints.class); + return suite; } - - @TestMetadata("classFromAnotherPackage.kt") - public void testClassFromAnotherPackage() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/classFromAnotherPackage.kt"); - } - - @TestMetadata("classObjectVal.kt") - public void testClassObjectVal() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/classObjectVal.kt"); - } - - @TestMetadata("collections.kt") - public void testCollections() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/collections.kt"); - } - - @TestMetadata("dependentOnFile.kt") - public void testDependentOnFile() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/dependentOnFile.kt"); - } - - @TestMetadata("doubles.kt") - public void testDoubles() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/doubles.kt"); - } - - @TestMetadata("enums.kt") - public void testEnums() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/enums.kt"); - } - - @TestMetadata("errors.kt") - public void testErrors() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/errors.kt"); - } - - @TestMetadata("extractLocalVariables.kt") - public void testExtractLocalVariables() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/extractLocalVariables.kt"); - } - - @TestMetadata("extractThis.kt") - public void testExtractThis() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/extractThis.kt"); - } - - @TestMetadata("extractVariablesFromCall.kt") - public void testExtractVariablesFromCall() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/extractVariablesFromCall.kt"); - } - - @TestMetadata("imports.kt") - public void testImports() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/imports.kt"); - } - - @TestMetadata("insertInBlock.kt") - public void testInsertInBlock() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/insertInBlock.kt"); - } - - @TestMetadata("multilineExpressionAtBreakpoint.kt") - public void testMultilineExpressionAtBreakpoint() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/multilineExpressionAtBreakpoint.kt"); - } - - @TestMetadata("privateMember.kt") - public void testPrivateMember() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/privateMember.kt"); - } - - @TestMetadata("protectedMember.kt") - public void testProtectedMember() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/protectedMember.kt"); - } - - @TestMetadata("simple.kt") - public void testSimple() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/simple.kt"); - } - - @TestMetadata("stdlib.kt") - public void testStdlib() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/stdlib.kt"); - } - - @TestMetadata("vars.kt") - public void testVars() throws Exception { - doTest("idea/testData/debugger/tinyApp/src/evaluate/vars.kt"); - } - } From 3edd6b52cf5afee33acdbc4f3d41165ccc48949a Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 18 Jun 2014 11:11:56 +0400 Subject: [PATCH 024/143] Evaluate expression: test cache using logger --- .../evaluate/KotlinEvaluateExpressionCache.kt | 6 ++- .../debugger/tinyApp/outs/abstractFunCall.out | 1 + .../testData/debugger/tinyApp/outs/arrays.out | 9 ++++ .../tinyApp/outs/classFromAnotherPackage.out | 2 + .../debugger/tinyApp/outs/classObjectVal.out | 2 + .../debugger/tinyApp/outs/clearCache.out | 12 +++++ .../debugger/tinyApp/outs/collections.out | 11 +++++ .../debugger/tinyApp/outs/dependentOnFile.out | 8 ++++ .../debugger/tinyApp/outs/doubles.out | 1 + idea/testData/debugger/tinyApp/outs/enums.out | 1 + .../tinyApp/outs/extractLocalVariables.out | 4 ++ .../debugger/tinyApp/outs/extractThis.out | 3 ++ .../tinyApp/outs/extractVariablesFromCall.out | 4 ++ .../debugger/tinyApp/outs/imports.out | 4 ++ .../debugger/tinyApp/outs/insertInBlock.out | 1 + .../outs/multilineExpressionAtBreakpoint.out | 1 + .../debugger/tinyApp/outs/privateMember.out | 3 ++ .../debugger/tinyApp/outs/protectedMember.out | 3 ++ .../testData/debugger/tinyApp/outs/simple.out | 7 +++ .../testData/debugger/tinyApp/outs/stdlib.out | 7 +++ idea/testData/debugger/tinyApp/outs/vars.out | 2 + .../AbstractKotlinEvaluateExpressionTest.kt | 44 ++++++++++++++++--- 22 files changed, 130 insertions(+), 6 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt index 441e6776300..5af28367661 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt @@ -39,6 +39,7 @@ import org.jetbrains.jet.plugin.caches.resolve.JavaResolveExtension import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl import org.jetbrains.jet.lang.resolve.java.JvmClassName import org.jetbrains.jet.codegen.AsmUtil +import org.apache.log4j.Logger class KotlinEvaluateExpressionCache(val project: Project) { @@ -49,6 +50,8 @@ class KotlinEvaluateExpressionCache(val project: Project) { }, false) class object { + private val LOG = Logger.getLogger(javaClass())!! + fun getInstance(project: Project) = ServiceManager.getService(project, javaClass())!! fun getOrCreateCompiledData( @@ -70,8 +73,9 @@ class KotlinEvaluateExpressionCache(val project: Project) { if (answer != null) return@synchronized answer val newCompiledData = create(codeFragment, sourcePosition) - cache.putValue(text, newCompiledData) + LOG.debug("Compile bytecode for ${codeFragment.getText()}") + cache.putValue(text, newCompiledData) return@synchronized newCompiledData } } diff --git a/idea/testData/debugger/tinyApp/outs/abstractFunCall.out b/idea/testData/debugger/tinyApp/outs/abstractFunCall.out index 4ec5a230c95..eef77767d00 100644 --- a/idea/testData/debugger/tinyApp/outs/abstractFunCall.out +++ b/idea/testData/debugger/tinyApp/outs/abstractFunCall.out @@ -2,6 +2,7 @@ LineBreakpoint created at abstractFunCall.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! abstractFunCall.AbstractFunCallPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' abstractFunCall.kt:4 +Compile bytecode for (1 as java.lang.Number).intValue() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/arrays.out b/idea/testData/debugger/tinyApp/outs/arrays.out index f523f93f485..3f35b7c44b9 100644 --- a/idea/testData/debugger/tinyApp/outs/arrays.out +++ b/idea/testData/debugger/tinyApp/outs/arrays.out @@ -2,6 +2,15 @@ LineBreakpoint created at arrays.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! arrays.ArraysPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' arrays.kt:4 +Compile bytecode for array(1, 2).map { it.toString() } +Compile bytecode for array(1, 2, 101, 102).filter { it > 100 } +Compile bytecode for array(1, 2).none() +Compile bytecode for array(1, 2).count() +Compile bytecode for array(1, 2).size +Compile bytecode for array(1, 2).first() +Compile bytecode for array(1, 2).last() +Compile bytecode for intArray(1, 2).max() +Compile bytecode for array(1, 2).max() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/classFromAnotherPackage.out b/idea/testData/debugger/tinyApp/outs/classFromAnotherPackage.out index e1153240cae..6dbcb1bcad4 100644 --- a/idea/testData/debugger/tinyApp/outs/classFromAnotherPackage.out +++ b/idea/testData/debugger/tinyApp/outs/classFromAnotherPackage.out @@ -2,6 +2,8 @@ LineBreakpoint created at classFromAnotherPackage.kt:7 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! classFromAnotherPackage.ClassFromAnotherPackagePackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' classFromAnotherPackage.kt:6 +Compile bytecode for MyJavaClass() +Compile bytecode for stepInto.MyJavaClass() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/classObjectVal.out b/idea/testData/debugger/tinyApp/outs/classObjectVal.out index 67eb6a81afc..a347b06cd23 100644 --- a/idea/testData/debugger/tinyApp/outs/classObjectVal.out +++ b/idea/testData/debugger/tinyApp/outs/classObjectVal.out @@ -2,6 +2,8 @@ LineBreakpoint created at classObjectVal.kt:10 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! classObjectVal.ClassObjectValPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' classObjectVal.kt:9 +Compile bytecode for coProp +Compile bytecode for MyClass.coProp Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/clearCache.out b/idea/testData/debugger/tinyApp/outs/clearCache.out index 4596499adcd..f5f1235bf62 100644 --- a/idea/testData/debugger/tinyApp/outs/clearCache.out +++ b/idea/testData/debugger/tinyApp/outs/clearCache.out @@ -20,26 +20,38 @@ LineBreakpoint created at clearCache.kt:189 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! clearCache.ClearCachePackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' clearCache.kt:11 +Compile bytecode for a clearCache.kt:19 +Compile bytecode for a clearCache.kt:30 +Compile bytecode for i clearCache.kt:30 clearCache.kt:41 +Compile bytecode for i clearCache.kt:41 clearCache.kt:51 +Compile bytecode for o.test() clearCache.kt:59 clearCache.kt:77 +Compile bytecode for c.size() clearCache.kt:85 clearCache.kt:94 clearCache.kt:104 clearCache.kt:112 +Compile bytecode for c.size() clearCache.kt:123 +Compile bytecode for c.get(0) clearCache.kt:132 clearCache.kt:142 +Compile bytecode for o.test() clearCache.kt:150 clearCache.kt:168 +Compile bytecode for obj.test() clearCache.kt:173 clearCache.kt:180 +Compile bytecode for o.test() clearCache.kt:188 +Compile bytecode for o.test() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/collections.out b/idea/testData/debugger/tinyApp/outs/collections.out index 618a4970607..8215589597b 100644 --- a/idea/testData/debugger/tinyApp/outs/collections.out +++ b/idea/testData/debugger/tinyApp/outs/collections.out @@ -2,6 +2,17 @@ LineBreakpoint created at collections.kt:6 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! collections.CollectionsPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' collections.kt:5 +Compile bytecode for arrayListOf(1, 2).map { it.toString() } +Compile bytecode for arrayListOf(1, 2, 101, 102).filter { it > 100 } +Compile bytecode for arrayListOf(1, 2).max() +Compile bytecode for arrayListOf(1, 2).count() +Compile bytecode for arrayListOf(1, 2).size +Compile bytecode for arrayListOf(1, 2).drop(1) +Compile bytecode for ar.map { if (it > 50) "big" else "small" } + .filter { it == "small" } + .size + +// RESULT: 2: I Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/dependentOnFile.out b/idea/testData/debugger/tinyApp/outs/dependentOnFile.out index 32f5a09bbfc..33361887a66 100644 --- a/idea/testData/debugger/tinyApp/outs/dependentOnFile.out +++ b/idea/testData/debugger/tinyApp/outs/dependentOnFile.out @@ -2,6 +2,14 @@ LineBreakpoint created at dependentOnFile.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! dependentOnFile.DependentOnFilePackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' dependentOnFile.kt:4 +Compile bytecode for TestClass().testFun() +Compile bytecode for testFun() +Compile bytecode for TestObject.p +Compile bytecode for TestClass.p +Compile bytecode for 1.testExtFun() +Compile bytecode for testVal +Compile bytecode for 1.testExtVal +Compile bytecode for testDelVal Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/doubles.out b/idea/testData/debugger/tinyApp/outs/doubles.out index 7fc4417f6d8..9028781bd0b 100644 --- a/idea/testData/debugger/tinyApp/outs/doubles.out +++ b/idea/testData/debugger/tinyApp/outs/doubles.out @@ -2,6 +2,7 @@ LineBreakpoint created at doubles.kt:7 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! doubles.DoublesPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' doubles.kt:6 +Compile bytecode for d1 + d2 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/enums.out b/idea/testData/debugger/tinyApp/outs/enums.out index 1c98f3af07a..9c475e903b1 100644 --- a/idea/testData/debugger/tinyApp/outs/enums.out +++ b/idea/testData/debugger/tinyApp/outs/enums.out @@ -2,6 +2,7 @@ LineBreakpoint created at enums.kt:7 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! enums.EnumsPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' enums.kt:6 +Compile bytecode for A == MyEnum.A Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/extractLocalVariables.out b/idea/testData/debugger/tinyApp/outs/extractLocalVariables.out index fca8952e6a5..e8c4407ba13 100644 --- a/idea/testData/debugger/tinyApp/outs/extractLocalVariables.out +++ b/idea/testData/debugger/tinyApp/outs/extractLocalVariables.out @@ -2,6 +2,10 @@ LineBreakpoint created at extractLocalVariables.kt:7 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! extractLocalVariables.ExtractLocalVariablesPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' extractLocalVariables.kt:6 +Compile bytecode for a +Compile bytecode for klass.f1(1) +Compile bytecode for args.size +Compile bytecode for klass.b Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/extractThis.out b/idea/testData/debugger/tinyApp/outs/extractThis.out index f308e1f8a66..fdbf81651b5 100644 --- a/idea/testData/debugger/tinyApp/outs/extractThis.out +++ b/idea/testData/debugger/tinyApp/outs/extractThis.out @@ -2,6 +2,9 @@ LineBreakpoint created at extractThis.kt:13 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! extractThis.ExtractThisPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' extractThis.kt:12 +Compile bytecode for prop +Compile bytecode for this.prop +Compile bytecode for prop + a Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out b/idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out index ac9998a6ba8..77392f6796a 100644 --- a/idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out +++ b/idea/testData/debugger/tinyApp/outs/extractVariablesFromCall.out @@ -2,6 +2,10 @@ LineBreakpoint created at extractVariablesFromCall.kt:8 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! extractVariablesFromCall.ExtractVariablesFromCallPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' extractVariablesFromCall.kt:7 +Compile bytecode for f1(a, s) +Compile bytecode for a.f2(s) +Compile bytecode for a f2 s +Compile bytecode for klass.f1(a, s) Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/imports.out b/idea/testData/debugger/tinyApp/outs/imports.out index 41c860627fb..f5d2f0980ef 100644 --- a/idea/testData/debugger/tinyApp/outs/imports.out +++ b/idea/testData/debugger/tinyApp/outs/imports.out @@ -2,6 +2,10 @@ LineBreakpoint created at imports.kt:10 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! imports.ImportsPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' imports.kt:9 +Compile bytecode for Collections.emptyList() +Compile bytecode for ArrayList() +Compile bytecode for HashSet() +Compile bytecode for JHashMap() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/insertInBlock.out b/idea/testData/debugger/tinyApp/outs/insertInBlock.out index 6936cb0ff92..88697b9114e 100644 --- a/idea/testData/debugger/tinyApp/outs/insertInBlock.out +++ b/idea/testData/debugger/tinyApp/outs/insertInBlock.out @@ -2,6 +2,7 @@ LineBreakpoint created at insertInBlock.kt:6 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! insertInBlock.InsertInBlockPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' insertInBlock.kt:5 +Compile bytecode for 1 + 1 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out b/idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out index 03b028c046d..0393ae05b63 100644 --- a/idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out +++ b/idea/testData/debugger/tinyApp/outs/multilineExpressionAtBreakpoint.out @@ -2,6 +2,7 @@ LineBreakpoint created at multilineExpressionAtBreakpoint.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! multilineExpressionAtBreakpoint.MultilineExpressionAtBreakpointPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' multilineExpressionAtBreakpoint.kt:4 +Compile bytecode for 1 + 1 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/privateMember.out b/idea/testData/debugger/tinyApp/outs/privateMember.out index beb563cb681..64268d1cda5 100644 --- a/idea/testData/debugger/tinyApp/outs/privateMember.out +++ b/idea/testData/debugger/tinyApp/outs/privateMember.out @@ -2,6 +2,9 @@ LineBreakpoint created at privateMember.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! privateMember.PrivateMemberPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' privateMember.kt:4 +Compile bytecode for MyClass().privateFun() +Compile bytecode for MyClass().privateVal +Compile bytecode for MyClass.PrivateClass().a Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/protectedMember.out b/idea/testData/debugger/tinyApp/outs/protectedMember.out index 9d9b6c38da6..35f56ba3f9f 100644 --- a/idea/testData/debugger/tinyApp/outs/protectedMember.out +++ b/idea/testData/debugger/tinyApp/outs/protectedMember.out @@ -2,6 +2,9 @@ LineBreakpoint created at protectedMember.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! protectedMember.ProtectedMemberPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' protectedMember.kt:4 +Compile bytecode for MyClass().protectedFun() +Compile bytecode for MyClass().protectedVal +Compile bytecode for MyClass.ProtectedClass().a Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/simple.out b/idea/testData/debugger/tinyApp/outs/simple.out index caf68a7723d..a50f76d0ce6 100644 --- a/idea/testData/debugger/tinyApp/outs/simple.out +++ b/idea/testData/debugger/tinyApp/outs/simple.out @@ -2,6 +2,13 @@ LineBreakpoint created at simple.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! simple.SimplePackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' simple.kt:4 +Compile bytecode for 1 +Compile bytecode for 1 + 1 +Compile bytecode for val a = 1 +a + args.size + +// RESULT: 1: I + Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/stdlib.out b/idea/testData/debugger/tinyApp/outs/stdlib.out index 08dcedff6bc..dd798d2101e 100644 --- a/idea/testData/debugger/tinyApp/outs/stdlib.out +++ b/idea/testData/debugger/tinyApp/outs/stdlib.out @@ -2,6 +2,13 @@ LineBreakpoint created at stdlib.kt:5 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! stdlib.StdlibPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' stdlib.kt:4 +Compile bytecode for array(100, 101) +Compile bytecode for array("a", "b", "c") +Compile bytecode for intArray(1, 2) +Compile bytecode for javaClass() +Compile bytecode for javaClass() +Compile bytecode for 100.toInt() +Compile bytecode for 100.toLong() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/outs/vars.out b/idea/testData/debugger/tinyApp/outs/vars.out index 764afeee9d0..0a19db7c231 100644 --- a/idea/testData/debugger/tinyApp/outs/vars.out +++ b/idea/testData/debugger/tinyApp/outs/vars.out @@ -2,6 +2,8 @@ LineBreakpoint created at vars.kt:7 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! vars.VarsPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' vars.kt:6 +Compile bytecode for a +Compile bytecode for a += 1 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt index 18a53380877..d05f7197025 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/AbstractKotlinEvaluateExpressionTest.kt @@ -35,8 +35,40 @@ import com.sun.jdi.ObjectReference import org.jetbrains.jet.lang.psi.JetCodeFragment import java.util.Collections import com.intellij.debugger.engine.evaluation.EvaluateException +import com.intellij.execution.process.ProcessOutputTypes +import org.apache.log4j.AppenderSkeleton +import org.apache.log4j.spi.LoggingEvent +import org.apache.log4j.Level +import org.apache.log4j.Logger public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestCase() { + private val logger = Logger.getLogger(javaClass())!! + + private val appender = object : AppenderSkeleton() { + override fun append(event: LoggingEvent?) { + println(event?.getRenderedMessage(), ProcessOutputTypes.SYSTEM) + } + override fun close() {} + override fun requiresLayout() = false + } + + private var oldLogLevel: Level? = null + + override fun setUp() { + super.setUp() + + oldLogLevel = logger.getLevel() + logger.setLevel(Level.DEBUG) + logger.addAppender(appender) + } + + override fun tearDown() { + logger.setLevel(oldLogLevel) + logger.removeAppender(appender) + + super.tearDown() + } + fun doSingleBreakpointTest(path: String) { val file = File(path) val expressions = loadTestDirectivesPairs(file, "// EXPRESSION: ", "// RESULT: ") @@ -84,6 +116,8 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC finish() } + + private fun checkExceptions(exceptions: MutableMap) { if (!exceptions.empty) { for (exc in exceptions.values()) { @@ -137,10 +171,10 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC val evaluator = DebuggerInvocationUtil.commitAndRunReadAction(getProject()) { EvaluatorBuilderImpl.build(TextWithImportsImpl( - codeFragmentKind, - text, - JetCodeFragment.getImportsForElement(contextElement), - JetFileType.INSTANCE), + codeFragmentKind, + text, + JetCodeFragment.getImportsForElement(contextElement), + JetFileType.INSTANCE), contextElement, sourcePosition) } @@ -151,7 +185,7 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC Assert.assertTrue("Evaluate expression returns wrong result for $text:\nexpected = $expectedResult\nactual = $actualResult\n", expectedResult == actualResult) } catch (e: EvaluateException) { - Assert.assertTrue("Evaluate expression throws wrong exception for $text:\nexpected = $expectedResult\nactual = ${e.getMessage()}\n", expectedResult == e.getMessage()) + Assert.assertTrue("Evaluate expression throws wrong exception for $text:\nexpected = $expectedResult\nactual = ${e.getMessage()}\n", expectedResult == e.getMessage()?.replaceFirst("id=[0-9]*", "id=ID")) } finally { resume(this) From fab770a3465919347868e1efd7a4c97be5e2d804 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 18 Jun 2014 16:45:47 +0400 Subject: [PATCH 025/143] Eval4j: support invokespecial instruction --- .../src/org/jetbrains/eval4j/jdi/jdiEval.kt | 42 +++++++++++-------- .../src/org/jetbrains/eval4j/jdi/jdiValues.kt | 3 +- .../org/jetbrains/eval4j/jdi/test/jdiTest.kt | 26 ++++++++---- .../jetbrains/eval4j/test/BaseTestData.java | 25 +++++++++++ .../org/jetbrains/eval4j/test/TestData.java | 25 ++++++++++- eval4j/test/org/jetbrains/eval4j/test/main.kt | 8 ++-- .../org/jetbrains/eval4j/test/suiteBuilder.kt | 11 ++--- eval4j/test/org/jetbrains/eval4j/test/util.kt | 19 +++++++++ 8 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 eval4j/test/org/jetbrains/eval4j/test/BaseTestData.java create mode 100644 eval4j/test/org/jetbrains/eval4j/test/util.kt diff --git a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt index 6ca3861c850..4f5a1df4e0b 100644 --- a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt +++ b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt @@ -21,6 +21,8 @@ import org.jetbrains.org.objectweb.asm.Type import com.sun.jdi import com.sun.jdi.ClassNotLoadedException import com.sun.tools.jdi.ReferenceTypeImpl +import com.sun.jdi.ObjectReference +import com.sun.jdi.Method val CLASS = Type.getType(javaClass>()) val BOOTSTRAP_CLASS_DESCRIPTORS = setOf("Ljava/lang/String;", "Ljava/lang/ClassLoader;", "Ljava/lang/Class;") @@ -213,27 +215,31 @@ class JDIEval( } override fun invokeMethod(instance: Value, methodDesc: MethodDescription, arguments: List, invokespecial: Boolean): Value { - if (invokespecial) { - if (methodDesc.name == "") { - // Constructor call - val ctor = findMethod(methodDesc) - val _class = (instance as NewObjectValue).asmType.asReferenceType() as jdi.ClassType - val args = mapArguments(arguments, ctor.safeArgumentTypes()) - val result = mayThrow { _class.newInstance(thread, ctor, args, invokePolicy) } - instance.value = result - return result.asValue() - } - else { - // TODO - throw UnsupportedOperationException("invokespecial is not suported yet") - } + if (invokespecial && methodDesc.name == "") { + // Constructor call + val ctor = findMethod(methodDesc) + val _class = (instance as NewObjectValue).asmType.asReferenceType() as jdi.ClassType + val args = mapArguments(arguments, ctor.safeArgumentTypes()) + val result = mayThrow { _class.newInstance(thread, ctor, args, invokePolicy) } + instance.value = result + return result.asValue() + } + + fun doInvokeMethod(obj: ObjectReference, method: Method, policy: Int): Value { + val args = mapArguments(arguments, method.safeArgumentTypes()) + val result = mayThrow { obj.invokeMethod(thread, method, args, policy) } + return result.asValue() } val obj = instance.jdiObj.checkNull() - val method = findMethod(methodDesc, instance.jdiObj!!.referenceType() ?: methodDesc.ownerType.asReferenceType()) - val args = mapArguments(arguments, method.safeArgumentTypes()) - val result = mayThrow { obj.invokeMethod(thread, method, args, invokePolicy) } - return result.asValue() + if (invokespecial) { + val method = findMethod(methodDesc) + return doInvokeMethod(obj, method, invokePolicy or ObjectReference.INVOKE_NONVIRTUAL) + } + else { + val method = findMethod(methodDesc, obj.referenceType() ?: methodDesc.ownerType.asReferenceType()) + return doInvokeMethod(obj, method, invokePolicy) + } } private fun mapArguments(arguments: List, expecetedTypes: List): List { diff --git a/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt b/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt index c155c691bac..d665acfd1a3 100644 --- a/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt +++ b/eval4j/src/org/jetbrains/eval4j/jdi/jdiValues.kt @@ -25,10 +25,9 @@ import com.sun.jdi fun makeInitialFrame(methodNode: MethodNode, arguments: List): Frame { val isStatic = (methodNode.access and ACC_STATIC) != 0 - assert(isStatic, "Instance methods are not supported: $methodNode") val params = Type.getArgumentTypes(methodNode.desc) - assert(params.size == arguments.size(), "Wrong number of arguments for $methodNode: $arguments") + assert(arguments.size() == (if (isStatic) params.size else params.size + 1), "Wrong number of arguments for $methodNode: $arguments") val frame = Frame(methodNode.maxLocals, methodNode.maxStack) frame.setReturn(makeNotInitializedValue(Type.getReturnType(methodNode.desc))) diff --git a/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt b/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt index e1bf8a7dcbb..301830921a6 100644 --- a/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt +++ b/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt @@ -21,15 +21,14 @@ import com.sun.jdi import junit.framework.TestSuite import org.jetbrains.eval4j.test.buildTestSuite import junit.framework.TestCase -import org.jetbrains.eval4j.interpreterLoop import org.junit.Assert.* import java.util.concurrent.CountDownLatch import java.util.concurrent.atomic.AtomicInteger -import org.jetbrains.eval4j.ExceptionThrown -import org.jetbrains.eval4j.MethodDescription -import org.jetbrains.eval4j.ValueReturned import org.jetbrains.eval4j.jdi.* import java.io.File +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.eval4j.test.getTestName val DEBUGEE_CLASS = javaClass() @@ -98,15 +97,24 @@ fun suite(): TestSuite { val suite = buildTestSuite { methodNode, ownerClass, expected -> remainingTests.incrementAndGet() - object : TestCase("test" + methodNode.name.capitalize()) { + object : TestCase(getTestName(methodNode.name)) { override fun runTest() { - val eval = JDIEval( - vm, classLoader!!, thread!!, 0 - ) + val eval = JDIEval(vm, classLoader!!, thread!!, 0) + + val args = if ((methodNode.access and Opcodes.ACC_STATIC) == 0) { + // Instance method + val newInstance = eval.newInstance(Type.getType(ownerClass)) + val thisValue = eval.invokeMethod(newInstance, MethodDescription(ownerClass.getName(), "", "()V", false), listOf(), true) + listOf(thisValue) + } + else { + listOf() + } + val value = interpreterLoop( methodNode, - makeInitialFrame(methodNode, listOf()), + makeInitialFrame(methodNode, args), eval ) diff --git a/eval4j/test/org/jetbrains/eval4j/test/BaseTestData.java b/eval4j/test/org/jetbrains/eval4j/test/BaseTestData.java new file mode 100644 index 00000000000..514d24c0cf5 --- /dev/null +++ b/eval4j/test/org/jetbrains/eval4j/test/BaseTestData.java @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2014 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.eval4j.test; + +class BaseTestData { + String superCall() { + return "Base"; + } + + private String invokeSpecialPrivateFun(String s) { return "Derived"; } +} \ No newline at end of file diff --git a/eval4j/test/org/jetbrains/eval4j/test/TestData.java b/eval4j/test/org/jetbrains/eval4j/test/TestData.java index 4efccd6967f..00bcc84c8c3 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/TestData.java +++ b/eval4j/test/org/jetbrains/eval4j/test/TestData.java @@ -16,8 +16,8 @@ package org.jetbrains.eval4j.test; -class TestData { - static void returnVoid() { +class TestData extends BaseTestData { + static void returnVoid() { } static boolean returnBoolean() { @@ -691,6 +691,27 @@ class TestData { long l = 1; Long[] IFEQ_L = new Long[] { b ? 100L : 200L }; } + + @Override + String superCall() { + return "Derived"; + } + + String testInvokeSpecialForSuperCall() { + return super.superCall(); + } + + static String testInvokeSpecial() { + TestData td = new TestData(); + return td.invokeSpecialPrivateFun(""); + } + + private String invokeSpecialPrivateFun(String s) { return "Base"; } + + public TestData() { + } } + + diff --git a/eval4j/test/org/jetbrains/eval4j/test/main.kt b/eval4j/test/org/jetbrains/eval4j/test/main.kt index 0ec942f1710..56ff0890ec0 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/main.kt +++ b/eval4j/test/org/jetbrains/eval4j/test/main.kt @@ -33,7 +33,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame fun suite(): TestSuite = buildTestSuite { methodNode, ownerClass, expected -> - object : TestCase("test" + methodNode.name.capitalize()) { + object : TestCase(getTestName(methodNode.name)) { override fun runTest() { val value = interpreterLoop( @@ -62,7 +62,9 @@ fun initFrame( var local = 0 if ((m.access and ACC_STATIC) == 0) { val ctype = Type.getObjectType(owner) - current.setLocal(local++, makeNotInitializedValue(ctype)) + val newInstance = REFLECTION_EVAL.newInstance(ctype) + val thisValue = REFLECTION_EVAL.invokeMethod(newInstance, MethodDescription(owner, "", "()V", false), listOf(), true) + current.setLocal(local++, thisValue) } val args = Type.getArgumentTypes(m.desc) @@ -265,7 +267,7 @@ object REFLECTION_EVAL : Eval { } else { // TODO - throw UnsupportedOperationException("invokespecial is not suported yet") + throw UnsupportedOperationException("invokespecial is not suported in reflection eval") } } val obj = instance.obj().checkNull() diff --git a/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt b/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt index 9de6ed4cd4a..ba08f6dac56 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt +++ b/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt @@ -63,15 +63,16 @@ fun buildTestCase(ownerClass: Class, var expected: InterpreterResult? = null for (method in ownerClass.getDeclaredMethods()) { if (method.getName() == methodNode.name) { - if ((method.getModifiers() and Modifier.STATIC) == 0) { - println("Skipping instance method: $method") - } - else if (method.getParameterTypes()!!.size > 0) { + val isStatic = (method.getModifiers() and Modifier.STATIC) != 0 + if (method.getParameterTypes()!!.size > 0) { println("Skipping method with parameters: $method") } + else if (!isStatic && !method.getName()!!.startsWith("test")) { + println("Skipping instance method (should be started with 'test') : $method") + } else { method.setAccessible(true) - val result = method.invoke(null) + val result = method.invoke(if (isStatic) null else ownerClass.newInstance()) val returnType = Type.getType(method.getReturnType()!!) try { expected = ValueReturned(objectToValue(result, returnType)) diff --git a/eval4j/test/org/jetbrains/eval4j/test/util.kt b/eval4j/test/org/jetbrains/eval4j/test/util.kt new file mode 100644 index 00000000000..5813cf5579b --- /dev/null +++ b/eval4j/test/org/jetbrains/eval4j/test/util.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2014 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.eval4j.test + +fun getTestName(methodName: String) = if (methodName.startsWith("test")) methodName else "test${methodName.capitalize()}" \ No newline at end of file From c847d180a71a54c7a7bdf94846e9d02a2d9be0d2 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 20 Jun 2014 18:16:18 +0400 Subject: [PATCH 026/143] Eval4j: add ignore annotations for tests --- .../eval4j/test/IgnoreInReflectionTests.java | 24 +++++++++++++++++ .../org/jetbrains/eval4j/test/TestData.java | 2 ++ eval4j/test/org/jetbrains/eval4j/test/main.kt | 27 ++++++++++++------- 3 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 eval4j/test/org/jetbrains/eval4j/test/IgnoreInReflectionTests.java diff --git a/eval4j/test/org/jetbrains/eval4j/test/IgnoreInReflectionTests.java b/eval4j/test/org/jetbrains/eval4j/test/IgnoreInReflectionTests.java new file mode 100644 index 00000000000..f07142feff6 --- /dev/null +++ b/eval4j/test/org/jetbrains/eval4j/test/IgnoreInReflectionTests.java @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2014 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.eval4j.test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface IgnoreInReflectionTests { +} diff --git a/eval4j/test/org/jetbrains/eval4j/test/TestData.java b/eval4j/test/org/jetbrains/eval4j/test/TestData.java index 00bcc84c8c3..f154809d09b 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/TestData.java +++ b/eval4j/test/org/jetbrains/eval4j/test/TestData.java @@ -697,10 +697,12 @@ class TestData extends BaseTestData { return "Derived"; } + @IgnoreInReflectionTests String testInvokeSpecialForSuperCall() { return super.superCall(); } + @IgnoreInReflectionTests static String testInvokeSpecial() { TestData td = new TestData(); return td.invokeSpecialPrivateFun(""); diff --git a/eval4j/test/org/jetbrains/eval4j/test/main.kt b/eval4j/test/org/jetbrains/eval4j/test/main.kt index 56ff0890ec0..58138bb6d94 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/main.kt +++ b/eval4j/test/org/jetbrains/eval4j/test/main.kt @@ -36,16 +36,25 @@ fun suite(): TestSuite = buildTestSuite { object : TestCase(getTestName(methodNode.name)) { override fun runTest() { - val value = interpreterLoop( - methodNode, - initFrame( - ownerClass.getInternalName(), - methodNode - ), - REFLECTION_EVAL - ) + if (!isIgnored(methodNode)) { + val value = interpreterLoop( + methodNode, + initFrame( + ownerClass.getInternalName(), + methodNode + ), + REFLECTION_EVAL + ) + assertEquals(expected, value) + } + } - assertEquals(expected, value) + private fun isIgnored(methodNode: MethodNode): Boolean { + return methodNode.visibleAnnotations?.any { + val annotationDesc = it.desc + annotationDesc != null && + Type.getType(annotationDesc) == Type.getType(javaClass()) + } ?: false } } } From 28cbe95e0cbd20eac464535f40602fc4cd662c87 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Thu, 19 Jun 2014 15:51:48 +0400 Subject: [PATCH 027/143] Generate invokeSpecial for all private functions --- .../jet/codegen/state/JetTypeMapper.java | 3 +-- .../debugger/tinyApp/outs/privateMember.out | 7 ++++-- .../singleBreakpoint/privateMember.kt | 23 ++++++++++++++++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java index 38849663539..6dee5371442 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java @@ -446,8 +446,7 @@ public class JetTypeMapper { invokeOpcode = INVOKEINTERFACE; } else { - boolean isPrivateFunInvocation = isCallInsideSameClassAsDeclared(functionDescriptor, context) && - functionDescriptor.getVisibility() == Visibilities.PRIVATE; + boolean isPrivateFunInvocation = functionDescriptor.getVisibility() == Visibilities.PRIVATE; invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL; } diff --git a/idea/testData/debugger/tinyApp/outs/privateMember.out b/idea/testData/debugger/tinyApp/outs/privateMember.out index 64268d1cda5..94b8493961c 100644 --- a/idea/testData/debugger/tinyApp/outs/privateMember.out +++ b/idea/testData/debugger/tinyApp/outs/privateMember.out @@ -1,10 +1,13 @@ -LineBreakpoint created at privateMember.kt:5 +LineBreakpoint created at privateMember.kt:9 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! privateMember.PrivateMemberPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' -privateMember.kt:4 +privateMember.kt:8 Compile bytecode for MyClass().privateFun() Compile bytecode for MyClass().privateVal Compile bytecode for MyClass.PrivateClass().a +Compile bytecode for base.privateFun() +Compile bytecode for derived.privateFun() +Compile bytecode for derivedAsBase.privateFun() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt index 8559185ed2c..1ced9ae98d6 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt @@ -1,6 +1,10 @@ package privateMember fun main(args: Array) { + val base = Base() + val derived = Derived() + val derivedAsBase: Base = Derived() + //Breakpoint! args.size } @@ -14,6 +18,14 @@ class MyClass { } } +open class Base { + private fun privateFun() = 2 +} + +class Derived: Base() { + private fun privateFun() = 3 +} + // EXPRESSION: MyClass().privateFun() // RESULT: 1: I @@ -21,4 +33,13 @@ class MyClass { // RESULT: 1: I // EXPRESSION: MyClass.PrivateClass().a -// RESULT: 1: I \ No newline at end of file +// RESULT: 1: I + +// EXPRESSION: base.privateFun() +// RESULT: 2: I + +// EXPRESSION: derived.privateFun() +// RESULT: 3: I + +// EXPRESSION: derivedAsBase.privateFun() +// RESULT: 2: I From 1687b9cbca649de8aa874ce7e72c5583a7452821 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 20 Jun 2014 12:20:02 +0400 Subject: [PATCH 028/143] Eval4j: add exception type in ExceptionThrown result --- .../src/org/jetbrains/eval4j/interpreter.kt | 2 +- .../org/jetbrains/eval4j/interpreterLoop.kt | 28 +++++++++++++------ .../src/org/jetbrains/eval4j/jdi/jdiEval.kt | 17 ++++++----- eval4j/src/org/jetbrains/eval4j/values.kt | 4 +++ .../org/jetbrains/eval4j/jdi/test/jdiTest.kt | 11 ++++---- .../org/jetbrains/eval4j/test/TestData.java | 21 ++++++++++++++ eval4j/test/org/jetbrains/eval4j/test/main.kt | 8 +++++- .../org/jetbrains/eval4j/test/suiteBuilder.kt | 8 ++++-- 8 files changed, 75 insertions(+), 24 deletions(-) diff --git a/eval4j/src/org/jetbrains/eval4j/interpreter.kt b/eval4j/src/org/jetbrains/eval4j/interpreter.kt index 90ade0434bc..c1d916f4fac 100644 --- a/eval4j/src/org/jetbrains/eval4j/interpreter.kt +++ b/eval4j/src/org/jetbrains/eval4j/interpreter.kt @@ -194,7 +194,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter( ObjectValue(value.obj(), targetType) } else { - throwEvalException(ClassCastException("Value '$value' cannot be cast to $targetType")) + throwEvalException(ClassCastException("${value.asmType.getClassName()} cannot be cast to ${targetType.getClassName()}")) } } diff --git a/eval4j/src/org/jetbrains/eval4j/interpreterLoop.kt b/eval4j/src/org/jetbrains/eval4j/interpreterLoop.kt index 1f63176ab82..e6712a16519 100644 --- a/eval4j/src/org/jetbrains/eval4j/interpreterLoop.kt +++ b/eval4j/src/org/jetbrains/eval4j/interpreterLoop.kt @@ -26,13 +26,20 @@ import org.jetbrains.org.objectweb.asm.tree.VarInsnNode import org.jetbrains.org.objectweb.asm.util.Printer import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode import java.util.ArrayList +import org.jetbrains.eval4j.ExceptionThrown.ExceptionKind trait InterpreterResult { override fun toString(): String } -class ExceptionThrown(val exception: Value): InterpreterResult { - override fun toString(): String = "Thrown $exception" +class ExceptionThrown(val exception: Value, val kind: ExceptionKind): InterpreterResult { + override fun toString(): String = "Thrown $exception: $kind" + + enum class ExceptionKind { + FROM_EVALUATED_CODE + FROM_EVALUATOR + BROKEN_CODE + } } data class ValueReturned(val result: Value): InterpreterResult { @@ -60,10 +67,13 @@ trait InterpretationEventHandler { fun exceptionCaught(currentState: Frame, currentInsn: AbstractInsnNode, exception: Value): InterpreterResult? } -class ThrownFromEvalException(cause: Throwable): RuntimeException(cause) { +abstract class ThrownFromEvalExceptionBase(cause: Throwable): RuntimeException(cause) { override fun toString(): String = "Thrown by evaluator: ${getCause()}" } +class BrokenCode(cause: Throwable): ThrownFromEvalExceptionBase(cause) +class ThrownFromEvalException(cause: Throwable): ThrownFromEvalExceptionBase(cause) + class ThrownFromEvaluatedCodeException(val exception: Value): RuntimeException() { override fun toString(): String = "Thrown from evaluated code: $exception" } @@ -206,7 +216,7 @@ fun interpreterLoop( val handled = handler.exceptionThrown(frame, currentInsn, exceptionValue) if (handled != null) return handled if (exceptionCaught(exceptionValue)) continue - return ExceptionThrown(exceptionValue) + return ExceptionThrown(exceptionValue, ExceptionKind.FROM_EVALUATED_CODE) } // Workaround for a bug in Kotlin: NoPatterMatched exception is thrown otherwise! @@ -216,20 +226,22 @@ fun interpreterLoop( try { frame.execute(currentInsn, interpreter) } - catch (e: ThrownFromEvalException) { + catch (e: ThrownFromEvalExceptionBase) { val exception = e.getCause()!! val exceptionValue = ObjectValue(exception, Type.getType(exception.javaClass)) val handled = handler.exceptionThrown(frame, currentInsn, exceptionValue) if (handled != null) return handled if (exceptionFromEvalCaught(exception, exceptionValue)) continue - return ExceptionThrown(exceptionValue) + + val exceptionType = if (e is BrokenCode) ExceptionKind.BROKEN_CODE else ExceptionKind.FROM_EVALUATOR + return ExceptionThrown(exceptionValue, exceptionType) } catch (e: ThrownFromEvaluatedCodeException) { val handled = handler.exceptionThrown(frame, currentInsn, e.exception) if (handled != null) return handled if (exceptionCaught(e.exception)) continue - return ExceptionThrown(e.exception) + return ExceptionThrown(e.exception, ExceptionKind.FROM_EVALUATED_CODE) } } } @@ -245,7 +257,7 @@ fun interpreterLoop( } } -private fun Frame.getStackTop(i: Int = 0) = this.getStack(this.getStackSize() - 1 - i) ?: throwEvalException(IllegalArgumentException("Couldn't get value with index = $i from top of stack")) +private fun Frame.getStackTop(i: Int = 0) = this.getStack(this.getStackSize() - 1 - i) ?: throwBrokenCodeException(IllegalArgumentException("Couldn't get value with index = $i from top of stack")) // Copied from org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer.analyze() fun computeHandlers(m: MethodNode): Array?> { diff --git a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt index 4f5a1df4e0b..1a00df6675f 100644 --- a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt +++ b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt @@ -138,7 +138,7 @@ class JDIEval( val _class = fieldDesc.ownerType.asReferenceType() val field = _class.fieldByName(fieldDesc.name) if (field == null) { - throwEvalException(NoSuchFieldError("Field not found: $fieldDesc")) + throwBrokenCodeException(NoSuchFieldError("Field not found: $fieldDesc")) } return field } @@ -146,7 +146,7 @@ class JDIEval( private fun findStaticField(fieldDesc: FieldDescription): jdi.Field { val field = findField(fieldDesc) if (!field.isStatic()) { - throwEvalException(NoSuchFieldError("Field is not static: $fieldDesc")) + throwBrokenCodeException(NoSuchFieldError("Field is not static: $fieldDesc")) } return field } @@ -160,12 +160,12 @@ class JDIEval( val field = findStaticField(fieldDesc) if (field.isFinal()) { - throwEvalException(NoSuchFieldError("Can't modify a final field: $field")) + throwBrokenCodeException(NoSuchFieldError("Can't modify a final field: $field")) } val _class = field.declaringType() if (_class !is jdi.ClassType) { - throwEvalException(NoSuchFieldError("Can't a field in a non-class: $field")) + throwBrokenCodeException(NoSuchFieldError("Can't a field in a non-class: $field")) } val jdiValue = newValue.asJdiValue(vm, field.`type`().asType()) @@ -181,7 +181,7 @@ class JDIEval( else -> _class.methodsByName(methodDesc.name, methodDesc.desc) } if (method.isEmpty()) { - throwEvalException(NoSuchMethodError("Method not found: $methodDesc")) + throwBrokenCodeException(NoSuchMethodError("Method not found: $methodDesc")) } return method[0] } @@ -189,10 +189,10 @@ class JDIEval( override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List): Value { val method = findMethod(methodDesc) if (!method.isStatic()) { - throwEvalException(NoSuchMethodError("Method is not static: $methodDesc")) + throwBrokenCodeException(NoSuchMethodError("Method is not static: $methodDesc")) } val _class = method.declaringType() - if (_class !is jdi.ClassType) throwEvalException(NoSuchMethodError("Static method is a non-class type: $method")) + if (_class !is jdi.ClassType) throwBrokenCodeException(NoSuchMethodError("Static method is a non-class type: $method")) val args = mapArguments(arguments, method.safeArgumentTypes()) val result = mayThrow { _class.invokeMethod(thread, method, args, invokePolicy) } @@ -277,4 +277,7 @@ fun mayThrow(f: () -> T): T { catch (e: jdi.InvocationException) { throw ThrownFromEvaluatedCodeException(e.exception().asValue()) } + catch (e: Throwable) { + throwBrokenCodeException(e) + } } \ No newline at end of file diff --git a/eval4j/src/org/jetbrains/eval4j/values.kt b/eval4j/src/org/jetbrains/eval4j/values.kt index 4e15b5adda2..971aa6ad9f3 100644 --- a/eval4j/src/org/jetbrains/eval4j/values.kt +++ b/eval4j/src/org/jetbrains/eval4j/values.kt @@ -129,4 +129,8 @@ fun T?.checkNull(): T { fun throwEvalException(e: Throwable): Nothing { throw ThrownFromEvalException(e) +} + +fun throwBrokenCodeException(e: Throwable): Nothing { + throw BrokenCode(e) } \ No newline at end of file diff --git a/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt b/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt index 301830921a6..41968f8e2f6 100644 --- a/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt +++ b/eval4j/test/org/jetbrains/eval4j/jdi/test/jdiTest.kt @@ -29,6 +29,7 @@ import java.io.File import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.eval4j.test.getTestName +import com.sun.jdi.ObjectReference val DEBUGEE_CLASS = javaClass() @@ -133,14 +134,14 @@ fun suite(): TestSuite { } try { - if (value is ExceptionThrown) { - val str = value.exception.jdiObj.callToString() - System.err.println("Exception: $str") - } - if (expected is ValueReturned && value is ValueReturned && value.result is ObjectValue) { assertEquals(expected.result.obj().toString(), value.result.jdiObj.callToString()) } + else if (expected is ExceptionThrown && value is ExceptionThrown) { + val valueObj = value.exception.obj() + val actual = if (valueObj is ObjectReference) valueObj.callToString() else valueObj.toString() + assertEquals(expected.exception.obj().toString(), actual) + } else { assertEquals(expected, value) } diff --git a/eval4j/test/org/jetbrains/eval4j/test/TestData.java b/eval4j/test/org/jetbrains/eval4j/test/TestData.java index f154809d09b..0af5b48f738 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/TestData.java +++ b/eval4j/test/org/jetbrains/eval4j/test/TestData.java @@ -710,6 +710,27 @@ class TestData extends BaseTestData { private String invokeSpecialPrivateFun(String s) { return "Base"; } + static Throwable exception1() { + throw new IllegalStateException(); + } + + static void exception2() { + new ExceptionsTest().f1(); + } + + static void exceptionClassCast() { + ExceptionsTest.Derived test = (ExceptionsTest.Derived) new ExceptionsTest.Base(); + } + + static class ExceptionsTest { + void f1() { + throw new IllegalStateException(); + } + + static class Base {} + static class Derived extends Base {} + } + public TestData() { } } diff --git a/eval4j/test/org/jetbrains/eval4j/test/main.kt b/eval4j/test/org/jetbrains/eval4j/test/main.kt index 58138bb6d94..43ba26d572a 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/main.kt +++ b/eval4j/test/org/jetbrains/eval4j/test/main.kt @@ -45,7 +45,13 @@ fun suite(): TestSuite = buildTestSuite { ), REFLECTION_EVAL ) - assertEquals(expected, value) + + if (expected is ExceptionThrown && value is ExceptionThrown) { + assertEquals(expected.exception.toString(), value.exception.toString()) + } + else { + assertEquals(expected.toString(), value.toString()) + } } } diff --git a/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt b/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt index ba08f6dac56..eecfeac02f1 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt +++ b/eval4j/test/org/jetbrains/eval4j/test/suiteBuilder.kt @@ -72,14 +72,18 @@ fun buildTestCase(ownerClass: Class, } else { method.setAccessible(true) - val result = method.invoke(if (isStatic) null else ownerClass.newInstance()) - val returnType = Type.getType(method.getReturnType()!!) try { + val result = method.invoke(if (isStatic) null else ownerClass.newInstance()) + val returnType = Type.getType(method.getReturnType()!!) expected = ValueReturned(objectToValue(result, returnType)) } catch (e: UnsupportedOperationException) { println("Skipping $method: $e") } + catch (e: Throwable) { + val cause = e.getCause() ?: e + expected = ExceptionThrown(objectToValue(cause, Type.getType(cause.javaClass)), ExceptionThrown.ExceptionKind.FROM_EVALUATOR) + } } } } From a17bcce682b76e028b8068fee98e82be1731108d Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Mon, 23 Jun 2014 17:39:53 +0400 Subject: [PATCH 029/143] Add tests for exceptions from evaluate expression --- .../evaluate/KotlinEvaluationBuilder.kt | 2 +- .../debugger/tinyApp/outs/clearCache.out | 27 ++++---- .../debugger/tinyApp/outs/exceptions.out | 20 ++++++ .../multipleBreakpoints/clearCache.kt | 21 ------ .../multipleBreakpoints/exceptions.kt | 65 +++++++++++++++++++ ...KotlinEvaluateExpressionTestGenerated.java | 5 ++ 6 files changed, 102 insertions(+), 38 deletions(-) create mode 100644 idea/testData/debugger/tinyApp/outs/exceptions.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/exceptions.kt diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index 22942f81958..4ef6861a05d 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -100,7 +100,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment, val virtualMachine = context.getDebugProcess().getVirtualMachineProxy().getVirtualMachine() // If bytecode was taken from cache and exception was thrown - recompile bytecode and run eval4j again - if (result is ExceptionThrown && isCompiledDataFromCache) { + if (isCompiledDataFromCache && result is ExceptionThrown && result.kind == ExceptionThrown.ExceptionKind.BROKEN_CODE) { return runEval4j(context, extractAndCompile(codeFragment, sourcePosition), args).toJdiValue(virtualMachine) } diff --git a/idea/testData/debugger/tinyApp/outs/clearCache.out b/idea/testData/debugger/tinyApp/outs/clearCache.out index f5f1235bf62..1ea2db70d4c 100644 --- a/idea/testData/debugger/tinyApp/outs/clearCache.out +++ b/idea/testData/debugger/tinyApp/outs/clearCache.out @@ -9,14 +9,12 @@ LineBreakpoint created at clearCache.kt:86 LineBreakpoint created at clearCache.kt:95 LineBreakpoint created at clearCache.kt:105 LineBreakpoint created at clearCache.kt:113 -LineBreakpoint created at clearCache.kt:124 -LineBreakpoint created at clearCache.kt:133 -LineBreakpoint created at clearCache.kt:143 -LineBreakpoint created at clearCache.kt:151 +LineBreakpoint created at clearCache.kt:123 +LineBreakpoint created at clearCache.kt:131 +LineBreakpoint created at clearCache.kt:149 +LineBreakpoint created at clearCache.kt:154 +LineBreakpoint created at clearCache.kt:161 LineBreakpoint created at clearCache.kt:169 -LineBreakpoint created at clearCache.kt:174 -LineBreakpoint created at clearCache.kt:181 -LineBreakpoint created at clearCache.kt:189 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! clearCache.ClearCachePackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' clearCache.kt:11 @@ -39,18 +37,15 @@ clearCache.kt:94 clearCache.kt:104 clearCache.kt:112 Compile bytecode for c.size() -clearCache.kt:123 -Compile bytecode for c.get(0) -clearCache.kt:132 -clearCache.kt:142 +clearCache.kt:122 Compile bytecode for o.test() -clearCache.kt:150 -clearCache.kt:168 +clearCache.kt:130 +clearCache.kt:148 Compile bytecode for obj.test() -clearCache.kt:173 -clearCache.kt:180 +clearCache.kt:153 +clearCache.kt:160 Compile bytecode for o.test() -clearCache.kt:188 +clearCache.kt:168 Compile bytecode for o.test() Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' diff --git a/idea/testData/debugger/tinyApp/outs/exceptions.out b/idea/testData/debugger/tinyApp/outs/exceptions.out new file mode 100644 index 00000000000..2491cf5912d --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/exceptions.out @@ -0,0 +1,20 @@ +LineBreakpoint created at exceptions.kt:9 +LineBreakpoint created at exceptions.kt:14 +LineBreakpoint created at exceptions.kt:26 +LineBreakpoint created at exceptions.kt:31 +LineBreakpoint created at exceptions.kt:42 +LineBreakpoint created at exceptions.kt:51 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! exceptions.ExceptionsPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +exceptions.kt:8 +Compile bytecode for fail() +exceptions.kt:13 +exceptions.kt:25 +Compile bytecode for o as Derived +exceptions.kt:30 +exceptions.kt:41 +Compile bytecode for c.get(0) +exceptions.kt:50 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt index 290a9a81261..99f8c6c8f46 100644 --- a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt +++ b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt @@ -114,26 +114,6 @@ fun subTypePlatform() { } } -fun genericRerun() { - if (true) { - val c = ArrayList() - c.add(1) - // EXPRESSION: c.get(0) - // RESULT: 1: I - //Breakpoint! - val b = 1 - } - - if (true) { - val c = ArrayList() - c.add("a") - // EXPRESSION: c.get(0) - // RESULT: "a": Ljava/lang/String; - //Breakpoint! - val b = 1 - } -} - fun innerClass() { if (true) { val o = TestInnerClasses.Base() @@ -200,7 +180,6 @@ fun main(args: Array) { primitiveTypes() subType() subTypePlatform() - genericRerun() innerClass() objects() } diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/exceptions.kt b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/exceptions.kt new file mode 100644 index 00000000000..deb56b87e41 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/exceptions.kt @@ -0,0 +1,65 @@ +package exceptions + +import java.util.ArrayList + +fun throwException() { + // EXPRESSION: fail() + // RESULT: instance of java.lang.UnsupportedOperationException(id=ID): Ljava/lang/UnsupportedOperationException; + //Breakpoint! + val a = 1 + + // EXPRESSION: fail() + // RESULT: instance of java.lang.UnsupportedOperationException(id=ID): Ljava/lang/UnsupportedOperationException; + //Breakpoint! + val b = 1 +} + +fun fail() { + throw UnsupportedOperationException() +} + +fun classCast() { + val o = Base() + // EXPRESSION: o as Derived + // RESULT: java.lang.ClassCastException: exceptions.Base cannot be cast to exceptions.Derived: Ljava/lang/ClassCastException; + //Breakpoint! + val a = 1 + + // EXPRESSION: o as Derived + // RESULT: java.lang.ClassCastException: exceptions.Base cannot be cast to exceptions.Derived: Ljava/lang/ClassCastException; + //Breakpoint! + val b = 1 +} + + +fun genericClassCast() { + if (true) { + val c = ArrayList() + c.add(1) + // EXPRESSION: c.get(0) + // RESULT: 1: I + //Breakpoint! + val b = 1 + } + + if (true) { + val c = ArrayList() + c.add("a") + // EXPRESSION: c.get(0) + // RESULT: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number: Ljava/lang/ClassCastException; + //Breakpoint! + val b = 1 + } +} + +open class Base { + private fun test(): Int = 1 +} + +class Derived: Base() + +fun main(args: Array) { + throwException() + classCast() + genericClassCast() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index a9fe9459d19..538ea354fb7 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -151,6 +151,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doMultipleBreakpointsTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/clearCache.kt"); } + @TestMetadata("exceptions.kt") + public void testExceptions() throws Exception { + doMultipleBreakpointsTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/exceptions.kt"); + } + } public static Test suite() { From bdc60441c0663a268f36eff1715ba33345a35bdd Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 20 Jun 2014 15:54:37 +0400 Subject: [PATCH 030/143] Try-catch exception value is not visible in debugger's local variables #KT-3070 Fixed --- .../jetbrains/jet/codegen/ExpressionCodegen.java | 5 +++++ .../checkLocalVariablesTable/catchClause.kt | 15 +++++++++++++++ .../CheckLocalVariablesTableTestGenerated.java | 5 +++++ 3 files changed, 25 insertions(+) create mode 100644 compiler/testData/checkLocalVariablesTable/catchClause.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index b92daaf9f44..3624ea3bb2a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -3413,6 +3413,11 @@ The "returned" value of try expression with no finally is either the last expres myFrameMap.leave(descriptor); + Label clauseEnd = new Label(); + v.mark(clauseEnd); + + v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null, clauseStart, clauseEnd, index); + genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null); generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName()); diff --git a/compiler/testData/checkLocalVariablesTable/catchClause.kt b/compiler/testData/checkLocalVariablesTable/catchClause.kt new file mode 100644 index 00000000000..0c76d23638a --- /dev/null +++ b/compiler/testData/checkLocalVariablesTable/catchClause.kt @@ -0,0 +1,15 @@ +class A { + fun foo() { + try { + val a = 1 + } + catch(e : Throwable) { + + } + } +} + +// METHOD : A.foo()V +// VARIABLE : NAME=a TYPE=I INDEX=1 +// VARIABLE : NAME=e TYPE=Ljava/lang/Throwable; INDEX=1 +// VARIABLE : NAME=this TYPE=LA; INDEX=0 diff --git a/compiler/tests/org/jetbrains/jet/codegen/CheckLocalVariablesTableTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/CheckLocalVariablesTableTestGenerated.java index dbbbb0b758f..79c77dbeeec 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CheckLocalVariablesTableTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CheckLocalVariablesTableTestGenerated.java @@ -36,6 +36,11 @@ public class CheckLocalVariablesTableTestGenerated extends AbstractCheckLocalVar JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/checkLocalVariablesTable"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("catchClause.kt") + public void testCatchClause() throws Exception { + doTest("compiler/testData/checkLocalVariablesTable/catchClause.kt"); + } + @TestMetadata("copyFunction.kt") public void testCopyFunction() throws Exception { doTest("compiler/testData/checkLocalVariablesTable/copyFunction.kt"); From 0968ea6914dc8e8073acf087fc2a3665c7701214 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 20 Jun 2014 13:43:53 +0400 Subject: [PATCH 031/143] Eval4j: catch IndexOutOfBounds exceptions --- .../src/org/jetbrains/eval4j/jdi/jdiEval.kt | 17 ++++-- .../org/jetbrains/eval4j/test/TestData.java | 48 +++++++++++++++ eval4j/test/org/jetbrains/eval4j/test/main.kt | 58 ++++++++++--------- 3 files changed, 91 insertions(+), 32 deletions(-) diff --git a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt index 1a00df6675f..d0596a0c615 100644 --- a/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt +++ b/eval4j/src/org/jetbrains/eval4j/jdi/jdiEval.kt @@ -127,11 +127,21 @@ class JDIEval( } override fun getArrayElement(array: Value, index: Value): Value { - return array.array().getValue(index.int).asValue() + try { + return array.array().getValue(index.int).asValue() + } + catch (e: IndexOutOfBoundsException) { + throwEvalException(ArrayIndexOutOfBoundsException(e.getMessage())) + } } override fun setArrayElement(array: Value, index: Value, newValue: Value) { - array.array().setValue(index.int, newValue.asJdiValue(vm, array.asmType.arrayElementType)) + try { + return array.array().setValue(index.int, newValue.asJdiValue(vm, array.asmType.arrayElementType)) + } + catch (e: IndexOutOfBoundsException) { + throwEvalException(ArrayIndexOutOfBoundsException(e.getMessage())) + } } private fun findField(fieldDesc: FieldDescription): jdi.Field { @@ -277,7 +287,4 @@ fun mayThrow(f: () -> T): T { catch (e: jdi.InvocationException) { throw ThrownFromEvaluatedCodeException(e.exception().asValue()) } - catch (e: Throwable) { - throwBrokenCodeException(e) - } } \ No newline at end of file diff --git a/eval4j/test/org/jetbrains/eval4j/test/TestData.java b/eval4j/test/org/jetbrains/eval4j/test/TestData.java index 0af5b48f738..a1b80b86914 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/TestData.java +++ b/eval4j/test/org/jetbrains/eval4j/test/TestData.java @@ -731,6 +731,54 @@ class TestData extends BaseTestData { static class Derived extends Base {} } + static boolean exceptionIndexOutOfBounds() { + int[] ints = new int[1]; + try { int i = ints[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { ints[2] = 1; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + short[] shorts = new short[1]; + try { short s = shorts[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { shorts[2] = 1; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + char[] chars = new char[1]; + try { char c = chars[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { chars[2] = 1; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + byte[] bytes = new byte[1]; + try { byte b = bytes[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { bytes[2] = 1; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + long[] longs = new long[1]; + try { long l = longs[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { longs[2] = 1; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + double[] doubles = new double[1]; + try { double d = doubles[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { doubles[2] = 1.0; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + float[] floats = new float[1]; + try { float f = floats[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { floats[2] = 1; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + boolean[] booleans = new boolean[1]; + try { boolean bool = booleans[2];return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { booleans[2] = true; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + Object[] objects = new Object[1]; + try { Object o = objects[2]; return false; } catch (ArrayIndexOutOfBoundsException e) { } + try { objects[2] = 1; return false; } catch (ArrayIndexOutOfBoundsException e) { } + + return true; + } + + static boolean indexOutOfBoundsForString() { + String str = ""; + try { str.charAt(10); return false; } catch (IndexOutOfBoundsException e) { } + try { str.substring(10); return false; } catch (IndexOutOfBoundsException e) { } + + return true; + } + public TestData() { } } diff --git a/eval4j/test/org/jetbrains/eval4j/test/main.kt b/eval4j/test/org/jetbrains/eval4j/test/main.kt index 43ba26d572a..bff0af3c707 100644 --- a/eval4j/test/org/jetbrains/eval4j/test/main.kt +++ b/eval4j/test/org/jetbrains/eval4j/test/main.kt @@ -150,21 +150,23 @@ object REFLECTION_EVAL : Eval { val elementType = if (asmType.getDimensions() == 1) asmType.getElementType() else Type.getType(asmType.getDescriptor().substring(1)) val arr = array.obj().checkNull() val ind = index.int - return when (elementType.getSort()) { - Type.BOOLEAN -> boolean(JArray.getBoolean(arr, ind)) - Type.BYTE -> byte(JArray.getByte(arr, ind)) - Type.SHORT -> short(JArray.getShort(arr, ind)) - Type.CHAR -> char(JArray.getChar(arr, ind)) - Type.INT -> int(JArray.getInt(arr, ind)) - Type.LONG -> long(JArray.getLong(arr, ind)) - Type.FLOAT -> float(JArray.getFloat(arr, ind)) - Type.DOUBLE -> double(JArray.getDouble(arr, ind)) - Type.OBJECT, - Type.ARRAY -> { - val value = JArray.get(arr, ind) - if (value == null) NULL_VALUE else ObjectValue(value, Type.getType(value.javaClass)) + return mayThrow { + when (elementType.getSort()) { + Type.BOOLEAN -> boolean(JArray.getBoolean(arr, ind)) + Type.BYTE -> byte(JArray.getByte(arr, ind)) + Type.SHORT -> short(JArray.getShort(arr, ind)) + Type.CHAR -> char(JArray.getChar(arr, ind)) + Type.INT -> int(JArray.getInt(arr, ind)) + Type.LONG -> long(JArray.getLong(arr, ind)) + Type.FLOAT -> float(JArray.getFloat(arr, ind)) + Type.DOUBLE -> double(JArray.getDouble(arr, ind)) + Type.OBJECT, + Type.ARRAY -> { + val value = JArray.get(arr, ind) + if (value == null) NULL_VALUE else ObjectValue(value, Type.getType(value.javaClass)) + } + else -> throw UnsupportedOperationException("Unsupported array element type: $elementType") } - else -> throw UnsupportedOperationException("Unsupported array element type: $elementType") } } @@ -176,20 +178,22 @@ object REFLECTION_EVAL : Eval { return } val elementType = array.asmType.getElementType() - when (elementType.getSort()) { - Type.BOOLEAN -> JArray.setBoolean(arr, ind, newValue.boolean) - Type.BYTE -> JArray.setByte(arr, ind, newValue.int.toByte()) - Type.SHORT -> JArray.setShort(arr, ind, newValue.int.toShort()) - Type.CHAR -> JArray.setChar(arr, ind, newValue.int.toChar()) - Type.INT -> JArray.setInt(arr, ind, newValue.int) - Type.LONG -> JArray.setLong(arr, ind, newValue.long) - Type.FLOAT -> JArray.setFloat(arr, ind, newValue.float) - Type.DOUBLE -> JArray.setDouble(arr, ind, newValue.double) - Type.OBJECT, - Type.ARRAY -> { - JArray.set(arr, ind, newValue.obj()) + mayThrow { + when (elementType.getSort()) { + Type.BOOLEAN -> JArray.setBoolean(arr, ind, newValue.boolean) + Type.BYTE -> JArray.setByte(arr, ind, newValue.int.toByte()) + Type.SHORT -> JArray.setShort(arr, ind, newValue.int.toShort()) + Type.CHAR -> JArray.setChar(arr, ind, newValue.int.toChar()) + Type.INT -> JArray.setInt(arr, ind, newValue.int) + Type.LONG -> JArray.setLong(arr, ind, newValue.long) + Type.FLOAT -> JArray.setFloat(arr, ind, newValue.float) + Type.DOUBLE -> JArray.setDouble(arr, ind, newValue.double) + Type.OBJECT, + Type.ARRAY -> { + JArray.set(arr, ind, newValue.obj()) + } + else -> throw UnsupportedOperationException("Unsupported array element type: $elementType") } - else -> throw UnsupportedOperationException("Unsupported array element type: $elementType") } } From d01d1861305416315923702cafe2b063ac94398e Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:41 +0400 Subject: [PATCH 032/143] Pseudocode: Fix depth-first pseudocode traversal --- .../jetbrains/jet/lang/cfg/PseudocodeTraverser.kt | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt index 892aea97202..d6a40033efa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt @@ -181,18 +181,10 @@ fun traverseFollowingInstructions( while (!stack.isEmpty()) { val instruction = stack.pop() - visited.add(instruction) + if (!visited.add(instruction)) continue + if (handler != null && !handler(instruction)) return false - val followingInstructions = instruction.getNextInstructions(order) - - for (followingInstruction in followingInstructions) { - if (!visited.contains(followingInstruction)) { - if (handler != null && !handler(instruction)) { - return false - } - stack.push(followingInstruction) - } - } + instruction.getNextInstructions(order).forEach { stack.push(it) } } return true } From 4debb6eb6a110636f1ef8db1b63286e623fbe71a Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:42 +0400 Subject: [PATCH 033/143] Expression Typing: Record resolved calls for labeled this-expressions --- .../types/expressions/BasicExpressionTypingVisitor.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 71b008af17d..0fb97d20f3f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -378,8 +378,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (labelName != null) { LabelResolver.LabeledReceiverResolutionResult resolutionResult = LabelResolver.INSTANCE.resolveThisOrSuperLabel(expression, context, Name.identifier(labelName)); - if (onlyClassReceivers && resolutionResult.success()) { - if (!isDeclaredInClass(resolutionResult.getReceiverParameterDescriptor())) { + if (resolutionResult.success()) { + ReceiverParameterDescriptor receiverParameterDescriptor = resolutionResult.getReceiverParameterDescriptor(); + recordThisOrSuperCallInTraceAndCallExtension(context, receiverParameterDescriptor, expression); + if (onlyClassReceivers && !isDeclaredInClass(receiverParameterDescriptor)) { return LabelResolver.LabeledReceiverResolutionResult.labelResolutionSuccess(NO_RECEIVER_PARAMETER); } } @@ -402,7 +404,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (result != NO_RECEIVER_PARAMETER) { context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), result.getContainingDeclaration()); recordThisOrSuperCallInTraceAndCallExtension(context, result, expression); - } return LabelResolver.LabeledReceiverResolutionResult.labelResolutionSuccess(result); } From 7c837909d82937b739465aea7ea221d0702e6ec2 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 19:32:56 +0400 Subject: [PATCH 034/143] Pseudocode: Bind result values to elements retrieved from resolved calls --- .../jet/lang/cfg/JetControlFlowProcessor.java | 64 +++++++++---------- .../lang/resolve/calls/CallTransformer.java | 39 +++++++++-- .../cfg/conventions/incrementAtTheEnd.values | 6 +- .../cfg/expressions/Assignments.values | 45 +++++++------ 4 files changed, 93 insertions(+), 61 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 276c7c395f2..3fd84976263 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -276,7 +276,7 @@ public class JetControlFlowProcessor { CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); if (resultingDescriptor instanceof ReceiverParameterDescriptor) { - builder.readVariable(expression, expression, resolvedCall, getReceiverValues(expression, resolvedCall, true)); + builder.readVariable(expression, expression, resolvedCall, getReceiverValues(resolvedCall, true)); } copyValue(expression, expression.getInstanceReference()); @@ -293,9 +293,9 @@ public class JetControlFlowProcessor { ResolvedCall resolvedCall = getResolvedCall(expression); if (resolvedCall instanceof VariableAsFunctionResolvedCall) { VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; - generateCall(expression, expression, variableAsFunctionResolvedCall.getVariableCall()); + generateCall(expression, variableAsFunctionResolvedCall.getVariableCall()); } - else if (!generateCall(expression, expression) && !(expression.getParent() instanceof JetCallExpression)) { + else if (!generateCall(expression, true) && !(expression.getParent() instanceof JetCallExpression)) { createNonSyntheticValue(expression, generateAndGetReceiverIfAny(expression)); } } @@ -327,19 +327,14 @@ public class JetControlFlowProcessor { else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { ResolvedCall resolvedCall = getResolvedCall(operationReference); if (resolvedCall != null) { - CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); + PseudoValue rhsValue = generateCall(operationReference, resolvedCall).getOutputValue(); Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken()); - if (descriptor.getName().equals(assignMethodName)) { - generateCall(expression, operationReference, resolvedCall); - } - else { + if (!resolvedCall.getResultingDescriptor().getName().equals(assignMethodName)) { /* At this point assignment of the form a += b actually means a = a + b * So we first generate call of "+" operation and then use its output pseudo-value * as a right-hand side when generating assignment call */ - Function0 rhsDeferredValue = - getValueAsFunction(generateCall(null, operationReference, resolvedCall).getOutputValue()); - visitAssignment(left, rhsDeferredValue, expression); + visitAssignment(left, getValueAsFunction(rhsValue), expression); } } else { @@ -358,7 +353,7 @@ public class JetControlFlowProcessor { mergeValues(Arrays.asList(left, right), expression); } else { - if (!generateCall(expression, operationReference)) { + if (!generateCall(operationReference, true)) { generateBothArgumentsAndMark(expression); } } @@ -435,7 +430,7 @@ public class JetControlFlowProcessor { if (left instanceof JetSimpleNameExpression || left instanceof JetQualifiedExpression) { accessTarget = getResolvedCallAccessTarget(PsiUtilPackage.getQualifiedElementSelector(left)); if (accessTarget instanceof AccessTarget.Call) { - receiverValues = getReceiverValues(lhs, ((AccessTarget.Call) accessTarget).getResolvedCall(), true); + receiverValues = getReceiverValues(((AccessTarget.Call) accessTarget).getResolvedCall(), true); } } else if (left instanceof JetProperty) { @@ -473,7 +468,7 @@ public class JetControlFlowProcessor { generateInstructions(lhs.getArrayExpression()); - Map receiverValues = getReceiverValues(lhs, setResolvedCall, false); + Map receiverValues = getReceiverValues(setResolvedCall, false); SmartFMap argumentValues = getArraySetterArguments(rhsDeferredValue, setResolvedCall); @@ -540,7 +535,7 @@ public class JetControlFlowProcessor { private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression, @Nullable ResolvedCall resolvedCall) { mark(arrayAccessExpression); - if (!checkAndGenerateCall(arrayAccessExpression, arrayAccessExpression, resolvedCall)) { + if (!checkAndGenerateCall(arrayAccessExpression, resolvedCall, true)) { generateArrayAccessWithoutCall(arrayAccessExpression); } } @@ -581,7 +576,7 @@ public class JetControlFlowProcessor { PseudoValue rhsValue; if (resolvedCall != null) { - rhsValue = generateCall(incrementOrDecrement ? null : expression, operationSign, resolvedCall).getOutputValue(); + rhsValue = generateCall(operationSign, resolvedCall).getOutputValue(); } else { generateInstructions(baseExpression); @@ -1055,7 +1050,7 @@ public class JetControlFlowProcessor { @Override public void visitCallExpression(@NotNull JetCallExpression expression) { JetExpression calleeExpression = expression.getCalleeExpression(); - if (!generateCall(expression, calleeExpression)) { + if (!generateCall(calleeExpression, true)) { List inputExpressions = new ArrayList(); for (ValueArgument argument : expression.getValueArguments()) { JetExpression argumentExpression = argument.getArgumentExpression(); @@ -1128,7 +1123,7 @@ public class JetControlFlowProcessor { entry, entry, resolvedCall, - getReceiverValues(initializer, resolvedCall, false), + getReceiverValues(resolvedCall, false), Collections.emptyMap() ).getOutputValue(); } @@ -1182,7 +1177,7 @@ public class JetControlFlowProcessor { public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) { mark(expression); ResolvedCall getMethodResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_GET, expression); - if (!checkAndGenerateCall(expression, expression, getMethodResolvedCall)) { + if (!checkAndGenerateCall(expression, getMethodResolvedCall, true)) { generateArrayAccess(expression, getMethodResolvedCall); } } @@ -1363,29 +1358,32 @@ public class JetControlFlowProcessor { return trace.get(BindingContext.RESOLVED_CALL, expression); } - private boolean generateCall(JetExpression callExpression, @Nullable JetExpression calleeExpression) { + private boolean generateCall(@Nullable JetExpression calleeExpression, boolean bindResultValue) { if (calleeExpression == null) return false; - return checkAndGenerateCall(callExpression, calleeExpression, getResolvedCall(calleeExpression)); + return checkAndGenerateCall(calleeExpression, getResolvedCall(calleeExpression), bindResultValue); } - private boolean checkAndGenerateCall(JetExpression callExpression, JetExpression calleeExpression, @Nullable ResolvedCall resolvedCall) { + private boolean checkAndGenerateCall(JetExpression calleeExpression, @Nullable ResolvedCall resolvedCall, boolean bindResultValue) { if (resolvedCall == null) { builder.compilationError(calleeExpression, "No resolved call"); return false; } - generateCall(callExpression, calleeExpression, resolvedCall); + generateCall(calleeExpression, resolvedCall); return true; } @NotNull - private InstructionWithValue generateCall(JetExpression callExpression, JetExpression calleeExpression, ResolvedCall resolvedCall) { + private InstructionWithValue generateCall(JetExpression calleeExpression, ResolvedCall resolvedCall) { if (resolvedCall instanceof VariableAsFunctionResolvedCall) { VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall; - return generateCall(callExpression, calleeExpression, variableAsFunctionResolvedCall.getFunctionCall()); + return generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall()); } + JetElement callElement = resolvedCall.getCall().getCallElement(); + JetExpression callExpression = callElement instanceof JetExpression ? (JetExpression) callElement : null; + CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor(); - Map receivers = getReceiverValues(callExpression, resolvedCall, true); + Map receivers = getReceiverValues(resolvedCall, true); SmartFMap parameterValues = SmartFMap.emptyMap(); for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) { ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor); @@ -1395,8 +1393,10 @@ public class JetControlFlowProcessor { } if (resultingDescriptor instanceof VariableDescriptor) { + assert callExpression != null + : "Variable-based call without call expression: " + callElement.getText(); assert parameterValues.isEmpty() - : "Variable-based call with non-empty argument list: " + resolvedCall.getCall().getCallElement().getText(); + : "Variable-based call with non-empty argument list: " + callElement.getText(); return builder.readVariable(calleeExpression, callExpression, resolvedCall, receivers); } mark(resolvedCall.getCall().getCallElement()); @@ -1405,18 +1405,18 @@ public class JetControlFlowProcessor { @NotNull private Map getReceiverValues( - JetExpression callExpression, ResolvedCall resolvedCall, boolean generateInstructions) { SmartFMap receiverValues = SmartFMap.emptyMap(); - receiverValues = getReceiverValues(callExpression, resolvedCall.getThisObject(), generateInstructions, receiverValues); - receiverValues = getReceiverValues(callExpression, resolvedCall.getReceiverArgument(), generateInstructions, receiverValues); + JetElement callElement = resolvedCall.getCall().getCallElement(); + receiverValues = getReceiverValues(callElement, resolvedCall.getThisObject(), generateInstructions, receiverValues); + receiverValues = getReceiverValues(callElement, resolvedCall.getReceiverArgument(), generateInstructions, receiverValues); return receiverValues; } @NotNull private SmartFMap getReceiverValues( - JetExpression callExpression, + JetElement callElement, ReceiverValue receiver, boolean generateInstructions, SmartFMap receiverValues @@ -1425,7 +1425,7 @@ public class JetControlFlowProcessor { if (receiver instanceof ThisReceiver) { if (generateInstructions) { - receiverValues = receiverValues.plus(createSyntheticValue(callExpression), receiver); + receiverValues = receiverValues.plus(createSyntheticValue(callElement), receiver); } } else if (receiver instanceof ExpressionReceiver) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java index 1718a96ab8d..40f3d802061 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallTransformer.java @@ -102,18 +102,22 @@ public class CallTransformer { assert candidate.getDescriptor() instanceof VariableDescriptor; boolean hasReceiver = candidate.getReceiverArgument().exists(); - Call variableCall = stripCallArguments(task); + Call variableCall = stripCallArguments(task.call); + ResolutionCandidate variableCandidate = getVariableCallCandidate(candidate, variableCall); if (!hasReceiver) { CallCandidateResolutionContext context = CallCandidateResolutionContext.create( - ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall); + ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall); return Collections.singleton(context); } CallCandidateResolutionContext contextWithReceiver = createContextWithChainedTrace( - candidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER); + variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER); Call variableCallWithoutReceiver = stripReceiver(variableCall); ResolutionCandidate candidateWithoutReceiver = ResolutionCandidate.create( - candidate.getCall(), candidate.getDescriptor(), candidate.getThisObject(), ReceiverValue.NO_RECEIVER, + variableCandidate.getCall(), + variableCandidate.getDescriptor(), + variableCandidate.getThisObject(), + ReceiverValue.NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false); CallCandidateResolutionContext contextWithoutReceiver = createContextWithChainedTrace( @@ -131,8 +135,22 @@ public class CallTransformer { return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue); } - private Call stripCallArguments(@NotNull ResolutionTask task) { - return new DelegatingCall(task.call) { + @NotNull + private ResolutionCandidate getVariableCallCandidate( + @NotNull ResolutionCandidate candidate, + @NotNull Call variableCall + ) { + return ResolutionCandidate.create( + variableCall, + candidate.getDescriptor(), + candidate.getThisObject(), + candidate.getReceiverArgument(), + candidate.getExplicitReceiverKind(), + candidate.isSafeCall()); + } + + private Call stripCallArguments(@NotNull Call call) { + return new DelegatingCall(call) { @Override public JetValueArgumentList getValueArgumentList() { return null; @@ -160,6 +178,15 @@ public class CallTransformer { public JetTypeArgumentList getTypeArgumentList() { return null; } + + @NotNull + @Override + public JetElement getCallElement() { + JetExpression calleeExpression = getCalleeExpression(); + assert calleeExpression != null : "No callee expression: " + getCallElement().getText(); + + return calleeExpression; + } }; } diff --git a/compiler/testData/cfg/conventions/incrementAtTheEnd.values b/compiler/testData/cfg/conventions/incrementAtTheEnd.values index 708871cea55..c25eae8f5a4 100644 --- a/compiler/testData/cfg/conventions/incrementAtTheEnd.values +++ b/compiler/testData/cfg/conventions/incrementAtTheEnd.values @@ -4,6 +4,8 @@ fun foo() { i++ } --------------------- -1 NEW() -i NEW() +1 NEW() +i NEW() +i++ NEW() +{ var i = 1 i++ } COPY ===================== diff --git a/compiler/testData/cfg/expressions/Assignments.values b/compiler/testData/cfg/expressions/Assignments.values index 122e8516b37..80cc3e47236 100644 --- a/compiler/testData/cfg/expressions/Assignments.values +++ b/compiler/testData/cfg/expressions/Assignments.values @@ -20,25 +20,28 @@ fun assignments() : Unit { t.x += 1 } --------------------- -1 NEW() -2 NEW() -x NEW() -2 NEW() -true NEW() -1 NEW() -2 NEW() -if (true) 1 else 2 NEW(, ) -true NEW() -false NEW() -true && false NEW(, ) -false NEW() -true NEW() -false && true NEW(, ) -Test() NEW() -t NEW() -1 NEW() -t NEW() -x NEW() -t.x COPY -1 NEW() +1 NEW() +2 NEW() +x NEW() +2 NEW() +x += 2 NEW(, ) +true NEW() +1 NEW() +2 NEW() +if (true) 1 else 2 NEW(, ) +true NEW() +false NEW() +true && false NEW(, ) +false NEW() +true NEW() +false && true NEW(, ) +Test() NEW() +t NEW() +1 NEW() +t NEW() +x NEW() +t.x COPY +1 NEW() +t.x += 1 NEW(, ) +{ var x = 1 x = 2 x += 2 x = if (true) 1 else 2 val y = true && false val z = false && true val t = Test(); t.x = 1 t.x += 1 } COPY ===================== From 50228fa085b120560fba6c09dc8d9299d17985b8 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 23 Jun 2014 13:53:08 +0400 Subject: [PATCH 035/143] Pseudocode: Generate correct values for postfix increment/decrement --- .../jet/lang/cfg/JetControlFlowProcessor.java | 3 + compiler/testData/cfg/arrays/arrayInc.values | 4 +- .../cfg/conventions/incrementAtTheEnd.values | 4 +- .../cfg/expressions/incdec.instructions | 65 +++++++++++++++++++ compiler/testData/cfg/expressions/incdec.kt | 11 ++++ .../testData/cfg/expressions/incdec.values | 30 +++++++++ .../jet/cfg/ControlFlowTestGenerated.java | 5 ++ .../jet/cfg/PseudoValueTestGenerated.java | 5 ++ 8 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/cfg/expressions/incdec.instructions create mode 100644 compiler/testData/cfg/expressions/incdec.kt create mode 100644 compiler/testData/cfg/expressions/incdec.values diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 3fd84976263..03197059a86 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -585,6 +585,9 @@ public class JetControlFlowProcessor { if (incrementOrDecrement) { visitAssignment(baseExpression, getValueAsFunction(rhsValue), expression); + if (expression instanceof JetPostfixExpression) { + copyValue(baseExpression, expression); + } } } diff --git a/compiler/testData/cfg/arrays/arrayInc.values b/compiler/testData/cfg/arrays/arrayInc.values index 6f116496e1d..0b078b11564 100644 --- a/compiler/testData/cfg/arrays/arrayInc.values +++ b/compiler/testData/cfg/arrays/arrayInc.values @@ -6,6 +6,6 @@ fun foo(a: Array) { a NEW() 0 NEW() a[0] NEW(, ) -a[0]++ NEW(, , ) -{ a[0]++ } COPY +a[0]++ COPY +{ a[0]++ } COPY ===================== diff --git a/compiler/testData/cfg/conventions/incrementAtTheEnd.values b/compiler/testData/cfg/conventions/incrementAtTheEnd.values index c25eae8f5a4..af35d135232 100644 --- a/compiler/testData/cfg/conventions/incrementAtTheEnd.values +++ b/compiler/testData/cfg/conventions/incrementAtTheEnd.values @@ -6,6 +6,6 @@ fun foo() { --------------------- 1 NEW() i NEW() -i++ NEW() -{ var i = 1 i++ } COPY +i++ COPY +{ var i = 1 i++ } COPY ===================== diff --git a/compiler/testData/cfg/expressions/incdec.instructions b/compiler/testData/cfg/expressions/incdec.instructions new file mode 100644 index 00000000000..5fa70363fa8 --- /dev/null +++ b/compiler/testData/cfg/expressions/incdec.instructions @@ -0,0 +1,65 @@ +== bar == +fun bar(n: Int) { + +} +--------------------- +L0: + 1 + v(n: Int) + magic(n: Int) -> + w(n|) + 2 mark({ }) + read (Unit) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== foo == +fun foo() { + var a = 1 + bar(a++) + bar(a--) + bar(++a) + bar(--a) +} +--------------------- +L0: + 1 + 2 mark({ var a = 1 bar(a++) bar(a--) bar(++a) bar(--a) }) + v(var a = 1) + r(1) -> + w(a|) + r(a) -> + mark(a++) + call(++, inc|) -> + w(a|) + mark(bar(a++)) + call(bar, bar|) -> + r(a) -> + mark(a--) + call(--, dec|) -> + w(a|) + mark(bar(a--)) + call(bar, bar|) -> + r(a) -> + mark(++a) + call(++, inc|) -> + w(a|) + mark(bar(++a)) + call(bar, bar|) -> + r(a) -> + mark(--a) + call(--, dec|) -> + w(a|) + mark(bar(--a)) + call(bar, bar|) -> +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== \ No newline at end of file diff --git a/compiler/testData/cfg/expressions/incdec.kt b/compiler/testData/cfg/expressions/incdec.kt new file mode 100644 index 00000000000..55a90b5c61a --- /dev/null +++ b/compiler/testData/cfg/expressions/incdec.kt @@ -0,0 +1,11 @@ +fun bar(n: Int) { + +} + +fun foo() { + var a = 1 + bar(a++) + bar(a--) + bar(++a) + bar(--a) +} \ No newline at end of file diff --git a/compiler/testData/cfg/expressions/incdec.values b/compiler/testData/cfg/expressions/incdec.values new file mode 100644 index 00000000000..f593461f745 --- /dev/null +++ b/compiler/testData/cfg/expressions/incdec.values @@ -0,0 +1,30 @@ +== bar == +fun bar(n: Int) { + +} +--------------------- +===================== +== foo == +fun foo() { + var a = 1 + bar(a++) + bar(a--) + bar(++a) + bar(--a) +} +--------------------- +1 NEW() +a NEW() +a++ COPY +bar(a++) NEW() +a NEW() +a-- COPY +bar(a--) NEW() +a NEW() +++a NEW() +bar(++a) NEW() +a NEW() +--a NEW() +bar(--a) NEW() +{ var a = 1 bar(a++) bar(a--) bar(++a) bar(--a) } COPY +===================== \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index 597bde87fe3..4ea1536a2f6 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -359,6 +359,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { doTest("compiler/testData/cfg/expressions/expressionAsFunction.kt"); } + @TestMetadata("incdec.kt") + public void testIncdec() throws Exception { + doTest("compiler/testData/cfg/expressions/incdec.kt"); + } + @TestMetadata("LazyBooleans.kt") public void testLazyBooleans() throws Exception { doTest("compiler/testData/cfg/expressions/LazyBooleans.kt"); diff --git a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java index 4a9f13962dc..326aedc5a82 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java @@ -361,6 +361,11 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { doTest("compiler/testData/cfg/expressions/expressionAsFunction.kt"); } + @TestMetadata("incdec.kt") + public void testIncdec() throws Exception { + doTest("compiler/testData/cfg/expressions/incdec.kt"); + } + @TestMetadata("LazyBooleans.kt") public void testLazyBooleans() throws Exception { doTest("compiler/testData/cfg/expressions/LazyBooleans.kt"); From 5e2c2b4ecaafc8a1bd79d0aa7c18cb1a20e98b6a Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 23 Jun 2014 14:02:22 +0400 Subject: [PATCH 036/143] Pseudocode: Implement computation of expected type predicates --- .../jet/lang/cfg/JetControlFlowProcessor.java | 25 +- .../jet/lang/cfg/pseudocode/TypePredicate.kt | 38 ++- .../jet/lang/cfg/pseudocode/pseudocodeUtil.kt | 147 ++++++++- .../jet/lang/resolve/BindingContextUtils.kt | 27 +- .../basic/IfWithUninitialized.values | 20 +- .../basic/InitializedNotDeclared.values | 2 +- .../basic/UsageInFunctionLiteral.values | 18 +- .../basic/VariablesInitialization.values | 22 +- .../cfg-variables/basic/VariablesUsage.values | 18 +- .../referenceToPropertyInitializer.values | 32 +- .../bugs/varInitializationInIf.values | 16 +- .../bugs/varInitializationInIfInCycle.values | 18 +- .../lexicalScopes/doWhileScope.values | 14 +- .../lexicalScopes/forScope.values | 14 +- .../lexicalScopes/functionLiteralScope.values | 16 +- .../lexicalScopes/ifScope.values | 12 +- .../lexicalScopes/localClass.values | 10 +- .../lexicalScopes/localFunctionScope.values | 14 +- .../localFunctionScopeWithoutBody.values | 14 +- .../lexicalScopes/localObject.values | 10 +- .../lexicalScopes/objectLiteralScope.values | 12 +- .../propertyAccessorScope.values | 4 +- .../lexicalScopes/tryScope.values | 16 +- .../lexicalScopes/whileScope.values | 8 +- .../testData/cfg/arrays/ArrayAccess.values | 34 +- .../cfg/arrays/ArrayOfFunctions.values | 12 +- .../cfg/arrays/arrayAccessExpression.values | 12 +- compiler/testData/cfg/arrays/arrayInc.values | 10 +- compiler/testData/cfg/arrays/arraySet.values | 10 +- .../cfg/arrays/arraySetPlusAssign.values | 12 +- compiler/testData/cfg/basic/Basic.values | 60 ++-- .../testData/cfg/basic/ShortFunction.values | 2 +- .../testData/cfg/bugs/jumpToOuterScope.values | 6 +- .../cfg/controlStructures/Finally.values | 246 +++++++------- .../controlStructures/FinallyTestCopy.values | 70 ++-- .../testData/cfg/controlStructures/For.values | 12 +- .../testData/cfg/controlStructures/If.values | 32 +- .../OnlyWhileInFunctionBody.values | 16 +- .../controlStructures/returnsInWhen.values | 4 +- .../conventions/bothReceivers.instructions | 65 ++++ .../testData/cfg/conventions/bothReceivers.kt | 10 + .../cfg/conventions/bothReceivers.values | 26 ++ .../testData/cfg/conventions/equals.values | 6 +- .../cfg/conventions/incrementAtTheEnd.values | 8 +- .../testData/cfg/conventions/invoke.values | 6 +- .../testData/cfg/conventions/notEqual.values | 6 +- .../testData/cfg/deadCode/DeadCode.values | 6 +- .../cfg/deadCode/returnInElvis.values | 6 +- .../cfg/deadCode/stringTemplate.values | 8 +- .../AnonymousInitializers.values | 6 +- .../unusedFunctionLiteral.values | 4 +- .../functions/FailFunction.values | 4 +- .../functions/typeParameter.values | 4 +- .../local/LocalDeclarations.values | 34 +- .../local/ObjectExpression.values | 12 +- .../cfg/declarations/local/localClass.values | 4 +- .../declarations/local/localProperty.values | 2 +- .../multiDeclaration/MultiDecl.values | 12 +- .../multiDeclarationWithError.values | 6 +- .../properties/DelegatedProperty.values | 6 +- .../properties/backingFieldAccess.values | 4 +- .../backingFieldQualifiedWithThis.values | 12 +- .../cfg/expressions/Assignments.values | 48 +-- .../cfg/expressions/LazyBooleans.values | 60 ++-- .../expressions/ReturnFromExpression.values | 8 +- .../cfg/expressions/assignmentToThis.values | 2 +- .../chainedQualifiedExpression.values | 302 +++++++++--------- .../expressions/expressionAsFunction.values | 8 +- .../testData/cfg/expressions/incdec.values | 30 +- .../cfg/expressions/nothingExpr.values | 16 +- .../cfg/expressions/propertySafeCall.values | 8 +- .../qualifiedExpressionWithoutSelector.values | 6 +- .../cfg/expressions/thisExpression.values | 4 +- .../cfg/expressions/unresolvedCall.values | 8 +- .../cfg/expressions/unresolvedProperty.values | 8 +- .../unusedExpressionSimpleName.values | 4 +- .../DefaultValuesForArguments.values | 10 +- .../testData/cfg/tailCalls/finally.values | 4 +- .../cfg/tailCalls/finallyWithReturn.values | 2 +- compiler/testData/cfg/tailCalls/sum.values | 26 +- compiler/testData/cfg/tailCalls/try.values | 2 +- .../cfg/tailCalls/tryCatchFinally.values | 16 +- .../jet/cfg/AbstractPseudoValueTest.kt | 15 +- .../jet/cfg/ControlFlowTestGenerated.java | 5 + .../jet/cfg/PseudoValueTestGenerated.java | 5 + .../jet/lang/resolve/OverridingUtil.java | 36 ++- .../src/org/jetbrains/jet/utils/DFS.java | 2 +- 87 files changed, 1154 insertions(+), 803 deletions(-) create mode 100644 compiler/testData/cfg/conventions/bothReceivers.instructions create mode 100644 compiler/testData/cfg/conventions/bothReceivers.kt create mode 100644 compiler/testData/cfg/conventions/bothReceivers.values diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 03197059a86..5abdb9058f1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -860,15 +860,21 @@ public class JetControlFlowProcessor { JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); JetExpression loopRange = expression.getLoopRange(); - JetType loopRangeType = trace.get(BindingContext.EXPRESSION_TYPE, loopRange); - TypePredicate loopRangeTypeSet = loopRangeType != null ? new SingleType(loopRangeType) : AllTypes.instance$; - PseudoValue loopRangeValue = builder.getBoundValue(loopRange); + TypePredicate loopRangeTypePredicate = AllTypes.instance$; + ResolvedCall iteratorResolvedCall = trace.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange); + if (iteratorResolvedCall != null) { + ReceiverValue iteratorReceiver = getExplicitReceiverValue(iteratorResolvedCall); + if (iteratorReceiver.exists()) { + loopRangeTypePredicate = PseudocodePackage.getReceiverTypePredicate(iteratorResolvedCall, iteratorReceiver); + } + } + PseudoValue loopRangeValue = builder.getBoundValue(loopRange); PseudoValue value = builder.magic( loopRange != null ? loopRange : expression, null, Collections.singletonList(loopRangeValue), - Collections.singletonMap(loopRangeValue, loopRangeTypeSet), + Collections.singletonMap(loopRangeValue, loopRangeTypePredicate), true ).getOutputValue(); @@ -882,6 +888,17 @@ public class JetControlFlowProcessor { } } + private ReceiverValue getExplicitReceiverValue(ResolvedCall resolvedCall) { + switch(resolvedCall.getExplicitReceiverKind()) { + case THIS_OBJECT: + return resolvedCall.getThisObject(); + case RECEIVER_ARGUMENT: + return resolvedCall.getReceiverArgument(); + default: + return ReceiverValue.NO_RECEIVER; + } + } + @Override public void visitBreakExpression(@NotNull JetBreakExpression expression) { JetElement loop = getCorrespondingLoop(expression); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt index ac4bd2030cb..60aea47a0e1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt @@ -32,12 +32,48 @@ public data class SingleType(val targetType: JetType): TypePredicate { override fun toString(): String = targetType.render() } +public data class AllSubtypes(val upperBound: JetType): TypePredicate { + override fun invoke(typeToCheck: JetType): Boolean = JetTypeChecker.INSTANCE.isSubtypeOf(typeToCheck, upperBound) + + override fun toString(): String = "{<: ${upperBound.render()}}" +} + +public data class ForAllTypes(val typeSets: List): TypePredicate { + override fun invoke(typeToCheck: JetType): Boolean = typeSets.all { it(typeToCheck) } + + override fun toString(): String = "AND{${typeSets.makeString(", ")}}" +} + +public data class ForSomeType(val typeSets: List): TypePredicate { + override fun invoke(typeToCheck: JetType): Boolean = typeSets.any { it(typeToCheck) } + + override fun toString(): String = "OR{${typeSets.makeString(", ")}}" +} + public object AllTypes : TypePredicate { override fun invoke(typeToCheck: JetType): Boolean = true - override fun toString(): String = "" + override fun toString(): String = "*" } +// todo: simplify computed type predicate when possible +fun and(predicates: Collection): TypePredicate = + when (predicates.size) { + 0 -> AllTypes + 1 -> predicates.first() + else -> ForAllTypes(predicates.toList()) + } + +fun or(predicates: Collection): TypePredicate? = + when (predicates.size) { + 0 -> null + 1 -> predicates.first() + else -> ForSomeType(predicates.toList()) + } + +fun JetType.getSubtypesPredicate(): TypePredicate? = + if (TypeUtils.canHaveSubtypes(JetTypeChecker.INSTANCE, this)) AllSubtypes(this) else SingleType(this) + private fun JetType.render(): String = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(this) public fun TypePredicate.expectedTypeFor(keys: Iterable): Map = diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt index 01871a57938..41e3886f47b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt @@ -16,13 +16,21 @@ package org.jetbrains.jet.lang.cfg.pseudocode -import org.jetbrains.jet.lang.psi.JetExpression -import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.traverseFollowingInstructions -import java.util.HashSet -import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder -import org.jetbrains.jet.lang.psi.JetFunction -import org.jetbrains.jet.lang.psi.psiUtil.getParentByType -import org.jetbrains.jet.lang.psi.JetFunctionLiteral +import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.* +import org.jetbrains.jet.lang.cfg.pseudocode.instructions.* +import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.* +import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.* +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.resolve.bindingContextUtil.* +import org.jetbrains.jet.lang.resolve.calls.model.* +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lang.resolve.BindingContext +import java.util.* +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.jet.lang.resolve.OverridingUtil +import org.jetbrains.jet.lang.types.TypeUtils +import org.jetbrains.jet.lang.types.JetType fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean { val value = pseudocode.getElementValue(this); @@ -32,7 +40,7 @@ fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean { return when { (getParent() as? JetFunction)?.getBodyExpression() == this -> true - pseudocode.getElementValue(getParentByType(javaClass())?.getBodyExpression()) == value -> + value.implicitReturnValue -> true else -> false @@ -42,4 +50,127 @@ fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean { val instruction = value.createdAt if (considerUsedIfCreatedBeforeExit() && instruction.nextInstructions.any { it == pseudocode.getExitInstruction() }) return false return traverseFollowingInstructions(instruction, HashSet(), TraversalOrder.FORWARD) { value !in it.inputValues } +} + +val PseudoValue.implicitReturnValue: Boolean + get() { + val pseudocode = createdAt.owner + + val function = pseudocode.getCorrespondingElement() as? JetDeclarationWithBody + + if (function is JetFunctionLiteral || (function != null && !function.hasBlockBody())) { + return pseudocode.getElementValue(function.getBodyExpression()) == this + } + return false + } + +fun Pseudocode.collectValueUsages(): Map> { + val map = HashMap>() + traverseFollowingInstructions(getEnterInstruction(), HashSet(), TraversalOrder.FORWARD) { + for (value in it.inputValues) { + map.getOrPut(value){ ArrayList() }.add(it) + } + true + } + + return map +} + +fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? { + val callableDescriptor = resolvedCall.getResultingDescriptor() + if (callableDescriptor == null) return null + + when (receiverValue) { + resolvedCall.getReceiverArgument() -> { + val receiverParameter = callableDescriptor.getReceiverParameter() + if (receiverParameter != null) return receiverParameter.getType().getSubtypesPredicate() + } + resolvedCall.getThisObject() -> { + val rootCallableDescriptors = OverridingUtil.getTopmostOverridenDescriptors(callableDescriptor) + return or(rootCallableDescriptors.map { + it.getExpectedThisObject()?.getType()?.let { TypeUtils.makeNullableIfNeeded(it, resolvedCall.isSafeCall()) }?.getSubtypesPredicate() + }.filterNotNull()) + } + } + + return null +} + +fun getExpectedTypePredicate( + value: PseudoValue, + valueUsageMap: Map>, + bindingContext: BindingContext +): TypePredicate { + val typePredicates = HashSet() + + fun addSubtypesOf(jetType: JetType?) = typePredicates.add(jetType?.getSubtypesPredicate()) + + fun addTypePredicates(value: PseudoValue) { + if (value.implicitReturnValue) { + val function = value.createdAt.owner.getCorrespondingElement() as? JetDeclarationWithBody + val functionDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor + addSubtypesOf(functionDescriptor?.getReturnType()) + } + + valueUsageMap[value]?.forEach { + when (it) { + is ReturnValueInstruction -> { + val functionDescriptor = (it.element as JetReturnExpression).getTargetFunctionDescriptor(bindingContext) + addSubtypesOf(functionDescriptor?.getReturnType()) + } + + is ConditionalJumpInstruction -> + addSubtypesOf(KotlinBuiltIns.getInstance().getBooleanType()) + + is ThrowExceptionInstruction -> + addSubtypesOf(KotlinBuiltIns.getInstance().getThrowable().getDefaultType()) + + is MergeInstruction -> + addTypePredicates(it.outputValue) + + is AccessValueInstruction -> { + val accessTarget = it.target + val receiverValue = it.receiverValues[value] + if (receiverValue != null) { + typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue)) + } + else { + val expectedType = when (accessTarget) { + is AccessTarget.Call -> + (accessTarget.resolvedCall.getResultingDescriptor() as? VariableDescriptor)?.getType() + is AccessTarget.Declaration -> + accessTarget.descriptor.getType() + else -> + null + } + addSubtypesOf(expectedType) + } + } + + is CallInstruction -> { + val receiverValue = it.receiverValues[value] + if (receiverValue != null) { + typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue)) + } + else { + it.arguments[value]?.let { parameter -> + val expectedType = when (it.resolvedCall.getValueArguments()[parameter]) { + is VarargValueArgument -> + parameter.getVarargElementType() + else -> + parameter.getType() + } + addSubtypesOf(expectedType) + } + } + } + + is MagicInstruction -> + typePredicates.add(it.expectedTypes[value]) + } + } + } + + addTypePredicates(value) + return and(typePredicates.filterNotNull()) } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt index 2ab6943670f..1841ed6dfd7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.kt @@ -21,14 +21,18 @@ import org.jetbrains.jet.lang.psi.Call import org.jetbrains.jet.lang.psi.JetPsiUtil import org.jetbrains.jet.lang.psi.JetCallExpression import org.jetbrains.jet.lang.psi.JetQualifiedExpression -import org.jetbrains.jet.lang.psi.JetBinaryExpression -import org.jetbrains.jet.lang.psi.JetUnaryExpression -import org.jetbrains.jet.lang.psi.JetArrayAccessExpression import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.psi.JetOperationExpression import org.jetbrains.jet.lang.resolve.BindingContext.CALL -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression +import org.jetbrains.jet.lang.psi.JetReturnExpression +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.resolve.BindingContext.LABEL_TARGET +import org.jetbrains.jet.lang.resolve.BindingContext.FUNCTION +import org.jetbrains.jet.lang.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR +import org.jetbrains.jet.lang.psi.psiUtil.getParentByType +import org.jetbrains.jet.lang.psi.JetDeclarationWithBody +import org.jetbrains.jet.lang.resolve.DescriptorUtils +import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor /** * For expressions like a(), a[i], a.b.c(), +a, a + b, (a()), a(): Int, @label a() @@ -51,3 +55,16 @@ fun JetExpression.getCorrespondingCall(bindingContext: BindingContext): Call? { } return bindingContext[CALL, reference] } + +public fun JetReturnExpression.getTargetFunctionDescriptor(bindingContext: BindingContext): FunctionDescriptor? { + val targetLabel = getTargetLabel() + if (targetLabel != null) return bindingContext[LABEL_TARGET, targetLabel]?.let { bindingContext[FUNCTION, it] } + + val declarationDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, getParentByType(javaClass())] + val containingFunctionDescriptor = DescriptorUtils.getParentOfType(declarationDescriptor, javaClass(), false) + if (containingFunctionDescriptor == null) return null + + return stream(containingFunctionDescriptor) { DescriptorUtils.getParentOfType(it, javaClass()) } + .dropWhile { it is AnonymousFunctionDescriptor } + .firstOrNull() +} diff --git a/compiler/testData/cfg-variables/basic/IfWithUninitialized.values b/compiler/testData/cfg-variables/basic/IfWithUninitialized.values index 886eac6e86c..9e8d37ccb96 100644 --- a/compiler/testData/cfg-variables/basic/IfWithUninitialized.values +++ b/compiler/testData/cfg-variables/basic/IfWithUninitialized.values @@ -9,18 +9,18 @@ fun foo() { } } --------------------- -1 NEW() -2 NEW() -1 < 2 NEW(, ) -b NEW() -use(b) NEW() -{ use(b) } COPY -true NEW() -if (1 < 2) { use(b) } else { b = true } COPY -{ val b: Boolean if (1 < 2) { use(b) } else { b = true } } COPY +1 : {<: Comparable} NEW() +2 : Int NEW() +1 < 2 : Boolean NEW(, ) +b : {<: Any?} NEW() +use(b) : * NEW() +{ use(b) } : * COPY +true : Boolean NEW() +if (1 < 2) { use(b) } else { b = true } : * COPY +{ val b: Boolean if (1 < 2) { use(b) } else { b = true } } : * COPY ===================== == use == fun use(vararg a: Any?) = a --------------------- -a NEW() +a : {<: Array} NEW() ===================== diff --git a/compiler/testData/cfg-variables/basic/InitializedNotDeclared.values b/compiler/testData/cfg-variables/basic/InitializedNotDeclared.values index 13de2c9986d..6b99c7aaf59 100644 --- a/compiler/testData/cfg-variables/basic/InitializedNotDeclared.values +++ b/compiler/testData/cfg-variables/basic/InitializedNotDeclared.values @@ -6,5 +6,5 @@ class A { val x: Int } --------------------- -1 NEW() +1 : Int NEW() ===================== diff --git a/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.values b/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.values index c7195b6fb36..4c2009adf92 100644 --- a/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.values +++ b/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.values @@ -7,8 +7,8 @@ fun foo() { } } --------------------- -1 NEW() -{ (x: Int) -> val y = x + a use(a) } NEW() +1 : Int NEW() +{ (x: Int) -> val y = x + a use(a) } : {<: (Int) -> Array} NEW() ===================== == anonymous_0 == { (x: Int) -> @@ -16,15 +16,15 @@ fun foo() { use(a) } --------------------- -x NEW() -a NEW() -x + a NEW(, ) -a NEW() -use(a) NEW() -val y = x + a use(a) COPY +x : Int NEW() +a : Int NEW() +x + a : Int NEW(, ) +a : {<: Any?} NEW() +use(a) : {<: Array} NEW() +val y = x + a use(a) : {<: Array} COPY ===================== == use == fun use(vararg a: Any?) = a --------------------- -a NEW() +a : {<: Array} NEW() ===================== diff --git a/compiler/testData/cfg-variables/basic/VariablesInitialization.values b/compiler/testData/cfg-variables/basic/VariablesInitialization.values index 4288c843063..99f30cf9766 100644 --- a/compiler/testData/cfg-variables/basic/VariablesInitialization.values +++ b/compiler/testData/cfg-variables/basic/VariablesInitialization.values @@ -6,10 +6,10 @@ fun foo() { 42 } --------------------- -1 NEW() -2 NEW() -42 NEW() -{ val a = 1 val b: Int b = 2 42 } COPY +1 : Int NEW() +2 : Int NEW() +42 : * NEW() +{ val a = 1 val b: Int b = 2 42 } : * COPY ===================== == bar == fun bar(foo: Foo) { @@ -18,13 +18,13 @@ fun bar(foo: Foo) { 42 } --------------------- -foo NEW() -c NEW() -foo.c COPY -foo NEW() -2 NEW() -42 NEW() -{ foo.c foo.c = 2 42 } COPY +foo : {<: Foo} NEW() +c : * NEW() +foo.c : * COPY +foo : {<: Foo} NEW() +2 : Int NEW() +42 : * NEW() +{ foo.c foo.c = 2 42 } : * COPY ===================== == Foo == trait Foo { diff --git a/compiler/testData/cfg-variables/basic/VariablesUsage.values b/compiler/testData/cfg-variables/basic/VariablesUsage.values index f9713ca80ce..99496514298 100644 --- a/compiler/testData/cfg-variables/basic/VariablesUsage.values +++ b/compiler/testData/cfg-variables/basic/VariablesUsage.values @@ -6,13 +6,13 @@ fun foo() { use(a) } --------------------- -1 NEW() -a NEW() -use(a) NEW() -2 NEW() -a NEW() -use(a) NEW() -{ var a = 1 use(a) a = 2 use(a) } COPY +1 : Int NEW() +a : Int NEW() +use(a) : * NEW() +2 : Int NEW() +a : Int NEW() +use(a) : * NEW() +{ var a = 1 use(a) a = 2 use(a) } : * COPY ===================== == bar == fun bar() { @@ -20,10 +20,10 @@ fun bar() { b = 3 } --------------------- -3 NEW() +3 : Int NEW() ===================== == use == fun use(a: Int) = a --------------------- -a NEW() +a : Int NEW() ===================== diff --git a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.values b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.values index 0dfc529f7e4..2c25e090ff8 100644 --- a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.values +++ b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.values @@ -5,21 +5,21 @@ class TestFunctionLiteral { } } --------------------- -{ (x: Int) -> sum(x - 1) + x } NEW() +{ (x: Int) -> sum(x - 1) + x } : {<: (Int) -> Int} NEW() ===================== == anonymous_0 == { (x: Int) -> sum(x - 1) + x } --------------------- -sum NEW() -x NEW() -1 NEW() -x - 1 NEW(, ) -sum(x - 1) NEW(, ) -x NEW() -sum(x - 1) + x NEW(, ) -sum(x - 1) + x COPY +sum : {<: (Int) -> Int} NEW() +x : Int NEW() +1 : Int NEW() +x - 1 : Int NEW(, ) +sum(x - 1) : Int NEW(, ) +x : Int NEW() +sum(x - 1) + x : Int NEW(, ) +sum(x - 1) + x : Int COPY ===================== == A == open class A(val a: A) @@ -37,23 +37,23 @@ class TestObjectLiteral { } } --------------------- -obj NEW() -obj NEW() -object: A(obj) { { val x = obj } fun foo() { val y = obj } } NEW() +obj : * NEW() +obj : {<: A} NEW() +object: A(obj) { { val x = obj } fun foo() { val y = obj } } : {<: A} NEW() ===================== == foo == fun foo() { val y = obj } --------------------- -obj NEW() +obj : {<: A} NEW() ===================== == TestOther == class TestOther { val x: Int = x + 1 } --------------------- -x NEW() -1 NEW() -x + 1 NEW(, ) +x : Int NEW() +1 : Int NEW() +x + 1 : Int NEW(, ) ===================== diff --git a/compiler/testData/cfg-variables/bugs/varInitializationInIf.values b/compiler/testData/cfg-variables/bugs/varInitializationInIf.values index d87c23dbb1c..e14fe8f08f1 100644 --- a/compiler/testData/cfg-variables/bugs/varInitializationInIf.values +++ b/compiler/testData/cfg-variables/bugs/varInitializationInIf.values @@ -10,12 +10,12 @@ fun foo() { use(b) } --------------------- -1 NEW() -2 NEW() -1 < 2 NEW(, ) -false NEW() -true NEW() -b NEW() -use(b) NEW() -{ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) } COPY +1 : {<: Comparable} NEW() +2 : Int NEW() +1 < 2 : Boolean NEW(, ) +false : Boolean NEW() +true : Boolean NEW() +b : * NEW() +use(b) : * NEW() +{ val b: Boolean if (1 < 2) { b = false } else { b = true } use(b) } : * COPY ===================== diff --git a/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.values b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.values index 5719f3b7cfe..4b4eee75d7b 100644 --- a/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.values +++ b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.values @@ -13,17 +13,17 @@ fun foo(numbers: Collection) { } } --------------------- -numbers NEW() -1 NEW() -2 NEW() -1 < 2 NEW(, ) -false NEW() -true NEW() -b NEW() -use(b) NEW() +numbers : {<: Iterable} NEW() +1 : {<: Comparable} NEW() +2 : Int NEW() +1 < 2 : Boolean NEW(, ) +false : Boolean NEW() +true : Boolean NEW() +b : {<: Any?} NEW() +use(b) : * NEW() ===================== == use == fun use(vararg a: Any?) = a --------------------- -a NEW() +a : {<: Array} NEW() ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.values b/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.values index 6168d89842d..b54a25d7dbe 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/doWhileScope.values @@ -7,11 +7,11 @@ fun foo() { "after" } --------------------- -"before" NEW() -2 NEW() -a NEW() -0 NEW() -a > 0 NEW(, ) -"after" NEW() -{ "before" do { var a = 2 } while (a > 0) "after" } COPY +"before" : * NEW() +2 : Int NEW() +a : {<: Comparable} NEW() +0 : Int NEW() +a > 0 : Boolean NEW(, ) +"after" : * NEW() +{ "before" do { var a = 2 } while (a > 0) "after" } : * COPY ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/forScope.values b/compiler/testData/cfg-variables/lexicalScopes/forScope.values index a48bf428fda..8bcf01b3d9b 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/forScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/forScope.values @@ -7,11 +7,11 @@ fun foo() { "after" } --------------------- -"before" NEW() -1 NEW() -10 NEW() -1..10 NEW(, ) -i NEW() -"after" NEW() -{ "before" for (i in 1..10) { val a = i } "after" } COPY +"before" : * NEW() +1 : Int NEW() +10 : Int NEW() +1..10 : {<: Iterable} NEW(, ) +i : Int NEW() +"after" : * NEW() +{ "before" for (i in 1..10) { val a = i } "after" } : * COPY ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.values b/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.values index 5f8baa9bc50..94790e1fd76 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.values @@ -8,18 +8,18 @@ fun foo() { "after" } --------------------- -"before" NEW() -1 NEW() -{ (x: Int) -> val a = x + b } NEW() -"after" NEW() -{ "before" val b = 1 val f = { (x: Int) -> val a = x + b } "after" } COPY +"before" : * NEW() +1 : Int NEW() +{ (x: Int) -> val a = x + b } : {<: (Int) -> Unit} NEW() +"after" : * NEW() +{ "before" val b = 1 val f = { (x: Int) -> val a = x + b } "after" } : * COPY ===================== == anonymous_0 == { (x: Int) -> val a = x + b } --------------------- -x NEW() -b NEW() -x + b NEW(, ) +x : Int NEW() +b : Int NEW() +x + b : Int NEW(, ) ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/ifScope.values b/compiler/testData/cfg-variables/lexicalScopes/ifScope.values index 83e8b451ad0..2b5ab5da777 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/ifScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/ifScope.values @@ -10,10 +10,10 @@ fun foo() { "after" } --------------------- -"before" NEW() -true NEW() -1 NEW() -2 NEW() -"after" NEW() -{ "before" if (true) { val a = 1 } else { val b = 2 } "after" } COPY +"before" : * NEW() +true : Boolean NEW() +1 : Int NEW() +2 : Int NEW() +"after" : * NEW() +{ "before" if (true) { val a = 1 } else { val b = 2 } "after" } : * COPY ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/localClass.values b/compiler/testData/cfg-variables/lexicalScopes/localClass.values index c9e1ecde4a3..6787b010d9d 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localClass.values +++ b/compiler/testData/cfg-variables/lexicalScopes/localClass.values @@ -12,15 +12,15 @@ fun foo() { "after" } --------------------- -"before" NEW() -x NEW() -"after" NEW() -{ "before" class A(val x: Int) { { val a = x } fun foo() { val b = x } } "after" } COPY +"before" : * NEW() +x : Int NEW() +"after" : * NEW() +{ "before" class A(val x: Int) { { val a = x } fun foo() { val b = x } } "after" } : * COPY ===================== == foo == fun foo() { val b = x } --------------------- -x NEW() +x : Int NEW() ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.values b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.values index d995e457ecb..0cd7d1c50ea 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.values @@ -8,17 +8,17 @@ fun foo() { "after" } --------------------- -"before" NEW() -1 NEW() -"after" NEW() -{ "before" val b = 1 fun local(x: Int) { val a = x + b } "after" } COPY +"before" : * NEW() +1 : Int NEW() +"after" : * NEW() +{ "before" val b = 1 fun local(x: Int) { val a = x + b } "after" } : * COPY ===================== == local == fun local(x: Int) { val a = x + b } --------------------- -x NEW() -b NEW() -x + b NEW(, ) +x : Int NEW() +b : Int NEW() +x + b : Int NEW(, ) ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.values b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.values index 75d4a6fd6dc..b70862c6513 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.values +++ b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScopeWithoutBody.values @@ -6,15 +6,15 @@ fun foo() { "after" } --------------------- -"before" NEW() -1 NEW() -"after" NEW() -{ "before" val b = 1 fun local(x: Int) = x + b "after" } COPY +"before" : * NEW() +1 : Int NEW() +"after" : * NEW() +{ "before" val b = 1 fun local(x: Int) = x + b "after" } : * COPY ===================== == local == fun local(x: Int) = x + b --------------------- -x NEW() -b NEW() -x + b NEW(, ) +x : Int NEW() +b : Int NEW() +x + b : Int NEW(, ) ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/localObject.values b/compiler/testData/cfg-variables/lexicalScopes/localObject.values index ac41b36e842..0c9ae1d8ecf 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localObject.values +++ b/compiler/testData/cfg-variables/lexicalScopes/localObject.values @@ -12,15 +12,15 @@ fun foo() { "after" } --------------------- -"before" NEW() -1 NEW() -"after" NEW() -{ "before" object A { { val a = 1 } fun foo() { val b = 2 } } "after" } COPY +"before" : * NEW() +1 : Int NEW() +"after" : * NEW() +{ "before" object A { { val a = 1 } fun foo() { val b = 2 } } "after" } : * COPY ===================== == foo == fun foo() { val b = 2 } --------------------- -2 NEW() +2 : Int NEW() ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.values b/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.values index 73e6fa3cdef..0fc6f4bc18c 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.values @@ -12,16 +12,16 @@ fun foo() { "after" } --------------------- -"before" NEW() -1 NEW() -object { { val x = 1 } fun foo() { val a = 2 } } NEW() -"after" NEW() -{ "before" val bar = object { { val x = 1 } fun foo() { val a = 2 } } "after" } COPY +"before" : * NEW() +1 : Int NEW() +object { { val x = 1 } fun foo() { val a = 2 } } : NEW() +"after" : * NEW() +{ "before" val bar = object { { val x = 1 } fun foo() { val a = 2 } } "after" } : * COPY ===================== == foo == fun foo() { val a = 2 } --------------------- -2 NEW() +2 : Int NEW() ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/propertyAccessorScope.values b/compiler/testData/cfg-variables/lexicalScopes/propertyAccessorScope.values index ba1ceaa3737..a38dc2dc87b 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/propertyAccessorScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/propertyAccessorScope.values @@ -17,12 +17,12 @@ get() { return $a } --------------------- -$a NEW() +$a : Int NEW() ===================== == set_a == set(v: Int) { $a = v } --------------------- -v NEW() +v : Int NEW() ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/tryScope.values b/compiler/testData/cfg-variables/lexicalScopes/tryScope.values index 03919986b84..ce7d64a84c6 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/tryScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/tryScope.values @@ -13,12 +13,12 @@ fun foo() { "after" } --------------------- -"before" NEW() -foo() NEW() -{ foo() } COPY -e NEW() -1 NEW() -try { foo() } catch (e: Exception) { val a = e } finally { val a = 1 } COPY -"after" NEW() -{ "before" try { foo() } catch (e: Exception) { val a = e } finally { val a = 1 } "after" } COPY +"before" : * NEW() +foo() : * NEW() +{ foo() } : * COPY +e : {<: Exception} NEW() +1 : Int NEW() +try { foo() } catch (e: Exception) { val a = e } finally { val a = 1 } : * COPY +"after" : * NEW() +{ "before" try { foo() } catch (e: Exception) { val a = e } finally { val a = 1 } "after" } : * COPY ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/whileScope.values b/compiler/testData/cfg-variables/lexicalScopes/whileScope.values index 01858675810..a8c0d80a31a 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/whileScope.values +++ b/compiler/testData/cfg-variables/lexicalScopes/whileScope.values @@ -7,8 +7,8 @@ fun foo() { "after" } --------------------- -"before" NEW() -true NEW() -"after" NEW() -{ "before" while (true) { val a: Int } "after" } COPY +"before" : * NEW() +true : * NEW() +"after" : * NEW() +{ "before" while (true) { val a: Int } "after" } : * COPY ===================== diff --git a/compiler/testData/cfg/arrays/ArrayAccess.values b/compiler/testData/cfg/arrays/ArrayAccess.values index bc136e3fe81..c6a7315e367 100644 --- a/compiler/testData/cfg/arrays/ArrayAccess.values +++ b/compiler/testData/cfg/arrays/ArrayAccess.values @@ -9,21 +9,21 @@ fun foo() { a[10] += 1 } --------------------- -Array NEW() -3 NEW() -a NEW() -10 NEW() -4 NEW() -a[10] = 4 NEW(, , ) -2 NEW() -a NEW() -10 NEW() -a[10] NEW(, ) -100 NEW() -a NEW() -10 NEW() -a[10] NEW(, ) -1 NEW() -a[10] += 1 NEW(, , ) -{ val a = Array 3 a[10] = 4 2 a[10] 100 a[10] += 1 } COPY +Array : {<: Array} NEW() +3 : * NEW() +a : {<: Array} NEW() +10 : Int NEW() +4 : Int NEW() +a[10] = 4 : * NEW(, , ) +2 : * NEW() +a : {<: Array} NEW() +10 : Int NEW() +a[10] : * NEW(, ) +100 : * NEW() +a : {<: Array} NEW() +10 : Int NEW() +a[10] : Int NEW(, ) +1 : Int NEW() +a[10] += 1 : * NEW(, , ) +{ val a = Array 3 a[10] = 4 2 a[10] 100 a[10] += 1 } : * COPY ===================== diff --git a/compiler/testData/cfg/arrays/ArrayOfFunctions.values b/compiler/testData/cfg/arrays/ArrayOfFunctions.values index 789e1185393..2fd1a0238ac 100644 --- a/compiler/testData/cfg/arrays/ArrayOfFunctions.values +++ b/compiler/testData/cfg/arrays/ArrayOfFunctions.values @@ -3,10 +3,10 @@ fun test(array: Array<(Int)->Unit>) { array[11](3) } --------------------- -array NEW() -11 NEW() -array[11] NEW(, ) -3 NEW() -array[11](3) NEW(, ) -{ array[11](3) } COPY +array : {<: Array<(Int) -> Unit>} NEW() +11 : Int NEW() +array[11] : {<: (Int) -> Unit} NEW(, ) +3 : Int NEW() +array[11](3) : * NEW(, ) +{ array[11](3) } : * COPY ===================== diff --git a/compiler/testData/cfg/arrays/arrayAccessExpression.values b/compiler/testData/cfg/arrays/arrayAccessExpression.values index fee89dd84b8..0328f66872c 100644 --- a/compiler/testData/cfg/arrays/arrayAccessExpression.values +++ b/compiler/testData/cfg/arrays/arrayAccessExpression.values @@ -13,10 +13,10 @@ fun test(ab: Ab) { ab.getArray()[1] } --------------------- -ab NEW() -getArray() NEW() -ab.getArray() COPY -1 NEW() -ab.getArray()[1] NEW(, ) -{ ab.getArray()[1] } COPY +ab : {<: Ab} NEW() +getArray() : {<: Array} NEW() +ab.getArray() : {<: Array} COPY +1 : Int NEW() +ab.getArray()[1] : * NEW(, ) +{ ab.getArray()[1] } : * COPY ===================== diff --git a/compiler/testData/cfg/arrays/arrayInc.values b/compiler/testData/cfg/arrays/arrayInc.values index 0b078b11564..c2a550bd58b 100644 --- a/compiler/testData/cfg/arrays/arrayInc.values +++ b/compiler/testData/cfg/arrays/arrayInc.values @@ -3,9 +3,9 @@ fun foo(a: Array) { a[0]++ } --------------------- -a NEW() -0 NEW() -a[0] NEW(, ) -a[0]++ COPY -{ a[0]++ } COPY +a : {<: Array} NEW() +0 : Int NEW() +a[0] : Int NEW(, ) +a[0]++ : Int COPY +{ a[0]++ } : Int COPY ===================== diff --git a/compiler/testData/cfg/arrays/arraySet.values b/compiler/testData/cfg/arrays/arraySet.values index bfed5c9d479..15ca1d7a79f 100644 --- a/compiler/testData/cfg/arrays/arraySet.values +++ b/compiler/testData/cfg/arrays/arraySet.values @@ -3,9 +3,9 @@ fun foo(a: Array) { a[1] = 2 } --------------------- -a NEW() -1 NEW() -2 NEW() -a[1] = 2 NEW(, , ) -{ a[1] = 2 } COPY +a : {<: Array} NEW() +1 : Int NEW() +2 : Int NEW() +a[1] = 2 : * NEW(, , ) +{ a[1] = 2 } : * COPY ===================== diff --git a/compiler/testData/cfg/arrays/arraySetPlusAssign.values b/compiler/testData/cfg/arrays/arraySetPlusAssign.values index bd6d86ed9b6..e25b40da814 100644 --- a/compiler/testData/cfg/arrays/arraySetPlusAssign.values +++ b/compiler/testData/cfg/arrays/arraySetPlusAssign.values @@ -3,10 +3,10 @@ fun foo(a: Array) { a[0] += 1 } --------------------- -a NEW() -0 NEW() -a[0] NEW(, ) -1 NEW() -a[0] += 1 NEW(, , ) -{ a[0] += 1 } COPY +a : {<: Array} NEW() +0 : Int NEW() +a[0] : Int NEW(, ) +1 : Int NEW() +a[0] += 1 : * NEW(, , ) +{ a[0] += 1 } : * COPY ===================== diff --git a/compiler/testData/cfg/basic/Basic.values b/compiler/testData/cfg/basic/Basic.values index 979de60120b..2b597aef89a 100644 --- a/compiler/testData/cfg/basic/Basic.values +++ b/compiler/testData/cfg/basic/Basic.values @@ -17,40 +17,40 @@ fun f(a : Boolean) : Unit { } --------------------- -1 NEW() -a NEW() -2 NEW() -toLong() NEW() -2.toLong() COPY -a NEW() -3 NEW() -foo(a, 3) NEW(, ) -genfun() NEW() -{1} NEW() -flfun {1} NEW() -3 NEW() -4 NEW() -equals(4) NEW(, ) -3.equals(4) COPY -3 NEW() -4 NEW() -3 equals 4 NEW(, ) -1 NEW() -2 NEW() -1 + 2 NEW(, ) -a NEW() -true NEW() -a && true NEW(, ) -a NEW() -false NEW() -a || false NEW(, ) -{ 1 a 2.toLong() foo(a, 3) genfun() flfun {1} 3.equals(4) 3 equals 4 1 + 2 a && true a || false } COPY +1 : * NEW() +a : * NEW() +2 : {<: Number} NEW() +toLong() : * NEW() +2.toLong() : * COPY +a : Boolean NEW() +3 : Int NEW() +foo(a, 3) : * NEW(, ) +genfun() : * NEW() +{1} : {<: () -> Any} NEW() +flfun {1} : * NEW() +3 : OR{{<: Any}, {<: Any}} NEW() +4 : {<: Any?} NEW() +equals(4) : * NEW(, ) +3.equals(4) : * COPY +3 : OR{{<: Any}, {<: Any}} NEW() +4 : {<: Any?} NEW() +3 equals 4 : * NEW(, ) +1 : Int NEW() +2 : Int NEW() +1 + 2 : * NEW(, ) +a : Boolean NEW() +true : Boolean NEW() +a && true : * NEW(, ) +a : Boolean NEW() +false : Boolean NEW() +a || false : * NEW(, ) +{ 1 a 2.toLong() foo(a, 3) genfun() flfun {1} 3.equals(4) 3 equals 4 1 + 2 a && true a || false } : * COPY ===================== == anonymous_0 == {1} --------------------- -1 NEW() -1 COPY +1 : Int NEW() +1 : Int COPY ===================== == foo == fun foo(a : Boolean, b : Int) : Unit {} diff --git a/compiler/testData/cfg/basic/ShortFunction.values b/compiler/testData/cfg/basic/ShortFunction.values index c30b60d47d4..f2c7d17510e 100644 --- a/compiler/testData/cfg/basic/ShortFunction.values +++ b/compiler/testData/cfg/basic/ShortFunction.values @@ -1,5 +1,5 @@ == short == fun short() = 1 --------------------- -1 NEW() +1 : Int NEW() ===================== diff --git a/compiler/testData/cfg/bugs/jumpToOuterScope.values b/compiler/testData/cfg/bugs/jumpToOuterScope.values index 3f158c01d81..f58075297ea 100644 --- a/compiler/testData/cfg/bugs/jumpToOuterScope.values +++ b/compiler/testData/cfg/bugs/jumpToOuterScope.values @@ -7,9 +7,9 @@ fun foo(c: Collection) { } } --------------------- -c NEW() -{ break } NEW() -{ { break } } COPY +c : {<: Iterable} NEW() +{ break } : * NEW() +{ { break } } : * COPY ===================== == anonymous_0 == { diff --git a/compiler/testData/cfg/controlStructures/Finally.values b/compiler/testData/cfg/controlStructures/Finally.values index d6ffe48bae5..8765ede1b36 100644 --- a/compiler/testData/cfg/controlStructures/Finally.values +++ b/compiler/testData/cfg/controlStructures/Finally.values @@ -7,12 +7,12 @@ fun t1() { } } --------------------- -1 NEW() -{ 1 } COPY -2 NEW() -{ 2 } COPY -try { 1 } finally { 2 } COPY -{ try { 1 } finally { 2 } } COPY +1 : * NEW() +{ 1 } : * COPY +2 : * NEW() +{ 2 } : * COPY +try { 1 } finally { 2 } : * COPY +{ try { 1 } finally { 2 } } : * COPY ===================== == t2 == fun t2() { @@ -26,12 +26,12 @@ fun t2() { } } --------------------- -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -2 NEW() -{ 2 } COPY +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +2 : * NEW() +{ 2 } : * COPY ===================== == t3 == fun t3() { @@ -47,14 +47,14 @@ fun t3() { } } --------------------- -1 NEW() -{ () -> if (2 > 3) { return@l } } NEW() -@l{ () -> if (2 > 3) { return@l } } COPY -{ 1 @l{ () -> if (2 > 3) { return@l } } } COPY -2 NEW() -{ 2 } COPY -try { 1 @l{ () -> if (2 > 3) { return@l } } } finally { 2 } COPY -{ try { 1 @l{ () -> if (2 > 3) { return@l } } } finally { 2 } } COPY +1 : * NEW() +{ () -> if (2 > 3) { return@l } } : * NEW() +@l{ () -> if (2 > 3) { return@l } } : * COPY +{ 1 @l{ () -> if (2 > 3) { return@l } } } : * COPY +2 : * NEW() +{ 2 } : * COPY +try { 1 @l{ () -> if (2 > 3) { return@l } } } finally { 2 } : * COPY +{ try { 1 @l{ () -> if (2 > 3) { return@l } } } finally { 2 } } : * COPY ===================== == anonymous_0 == { () -> @@ -63,9 +63,9 @@ try { 1 @l{ () -> if (2 > 3) { return@l } } } finally { 2 } COPY } } --------------------- -2 NEW() -3 NEW() -2 > 3 NEW(, ) +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) ===================== == t4 == fun t4() { @@ -81,9 +81,9 @@ fun t4() { } } --------------------- -{ () -> try { 1 if (2 > 3) { return@l } } finally { 2 } } NEW() -@l{ () -> try { 1 if (2 > 3) { return@l } } finally { 2 } } COPY -{ @l{ () -> try { 1 if (2 > 3) { return@l } } finally { 2 } } } COPY +{ () -> try { 1 if (2 > 3) { return@l } } finally { 2 } } : * NEW() +@l{ () -> try { 1 if (2 > 3) { return@l } } finally { 2 } } : * COPY +{ @l{ () -> try { 1 if (2 > 3) { return@l } } finally { 2 } } } : * COPY ===================== == anonymous_1 == { () -> @@ -97,12 +97,12 @@ fun t4() { } } --------------------- -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -2 NEW() -{ 2 } COPY +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +2 : * NEW() +{ 2 } : * COPY ===================== == t5 == fun t5() { @@ -118,13 +118,13 @@ fun t5() { } } --------------------- -true NEW() -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -2 NEW() -{ 2 } COPY +true : * NEW() +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +2 : * NEW() +{ 2 } : * COPY ===================== == t6 == fun t6() { @@ -141,17 +141,17 @@ fun t6() { } } --------------------- -true NEW() -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -5 NEW() -{ @l while(true) { 1 if (2 > 3) { break @l } } 5 } COPY -2 NEW() -{ 2 } COPY -try { @l while(true) { 1 if (2 > 3) { break @l } } 5 } finally { 2 } COPY -{ try { @l while(true) { 1 if (2 > 3) { break @l } } 5 } finally { 2 } } COPY +true : * NEW() +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +5 : * NEW() +{ @l while(true) { 1 if (2 > 3) { break @l } } 5 } : * COPY +2 : * NEW() +{ 2 } : * COPY +try { @l while(true) { 1 if (2 > 3) { break @l } } 5 } finally { 2 } : * COPY +{ try { @l while(true) { 1 if (2 > 3) { break @l } } 5 } finally { 2 } } : * COPY ===================== == t7 == fun t7() { @@ -167,13 +167,13 @@ fun t7() { } } --------------------- -true NEW() -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -2 NEW() -{ 2 } COPY +true : * NEW() +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +2 : * NEW() +{ 2 } : * COPY ===================== == t8 == fun t8(a : Int) { @@ -189,15 +189,15 @@ fun t8(a : Int) { } } --------------------- -1 NEW() -a NEW() -1..a NEW(, ) -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -2 NEW() -{ 2 } COPY +1 : Int NEW() +a : Int NEW() +1..a : {<: Iterable} NEW(, ) +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +2 : * NEW() +{ 2 } : * COPY ===================== == t9 == fun t9(a : Int) { @@ -214,19 +214,19 @@ fun t9(a : Int) { } } --------------------- -1 NEW() -a NEW() -1..a NEW(, ) -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -5 NEW() -{ @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 } COPY -2 NEW() -{ 2 } COPY -try { @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 } finally { 2 } COPY -{ try { @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 } finally { 2 } } COPY +1 : Int NEW() +a : Int NEW() +1..a : {<: Iterable} NEW(, ) +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +5 : * NEW() +{ @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 } : * COPY +2 : * NEW() +{ 2 } : * COPY +try { @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 } finally { 2 } : * COPY +{ try { @l for (i in 1..a) { 1 if (2 > 3) { continue @l } } 5 } finally { 2 } } : * COPY ===================== == t10 == fun t10(a : Int) { @@ -242,15 +242,15 @@ fun t10(a : Int) { } } --------------------- -1 NEW() -a NEW() -1..a NEW(, ) -1 NEW() -2 NEW() -3 NEW() -2 > 3 NEW(, ) -2 NEW() -{ 2 } COPY +1 : Int NEW() +a : Int NEW() +1..a : {<: Iterable} NEW(, ) +1 : * NEW() +2 : {<: Comparable} NEW() +3 : Int NEW() +2 > 3 : Boolean NEW(, ) +2 : * NEW() +{ 2 } : * COPY ===================== == t11 == fun t11() { @@ -262,8 +262,8 @@ fun t11() { } } --------------------- -1 NEW() -2 NEW() +1 : * NEW() +2 : Unit NEW() ===================== == t12 == fun t12() : Int { @@ -275,10 +275,10 @@ fun t12() : Int { } } --------------------- -1 NEW() -3 NEW() -doSmth(3) NEW() -{ doSmth(3) } COPY +1 : Int NEW() +3 : Int NEW() +doSmth(3) : * NEW() +{ doSmth(3) } : * COPY ===================== == t13 == fun t13() : Int { @@ -293,15 +293,15 @@ fun t13() : Int { } } --------------------- -1 NEW() -2 NEW() -doSmth(2) NEW() -{ doSmth(2) } COPY -3 NEW() -doSmth(3) NEW() -{ doSmth(3) } COPY -try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } finally { doSmth(3) } COPY -{ try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } finally { doSmth(3) } } COPY +1 : Int NEW() +2 : Int NEW() +doSmth(2) : * NEW() +{ doSmth(2) } : * COPY +3 : Int NEW() +doSmth(3) : * NEW() +{ doSmth(3) } : * COPY +try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } finally { doSmth(3) } : * COPY +{ try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } finally { doSmth(3) } } : * COPY ===================== == t14 == fun t14() : Int { @@ -313,12 +313,12 @@ fun t14() : Int { } } --------------------- -1 NEW() -2 NEW() -doSmth(2) NEW() -{ doSmth(2) } COPY -try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } COPY -{ try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } } COPY +1 : Int NEW() +2 : Int NEW() +doSmth(2) : * NEW() +{ doSmth(2) } : * COPY +try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } : * COPY +{ try { return 1 } catch (e: UnsupportedOperationException) { doSmth(2) } } : * COPY ===================== == t15 == fun t15() : Int { @@ -333,11 +333,11 @@ fun t15() : Int { } } --------------------- -1 NEW() -2 NEW() -3 NEW() -doSmth(3) NEW() -{ doSmth(3) } COPY +1 : Int NEW() +2 : Int NEW() +3 : Int NEW() +doSmth(3) : * NEW() +{ doSmth(3) } : * COPY ===================== == t16 == fun t16() : Int { @@ -352,15 +352,15 @@ fun t16() : Int { } } --------------------- -1 NEW() -doSmth(1) NEW() -{ doSmth(1) } COPY -2 NEW() -3 NEW() -doSmth(3) NEW() -{ doSmth(3) } COPY -try { doSmth(1) } catch (e: UnsupportedOperationException) { return 2 } finally { doSmth(3) } COPY -{ try { doSmth(1) } catch (e: UnsupportedOperationException) { return 2 } finally { doSmth(3) } } COPY +1 : Int NEW() +doSmth(1) : * NEW() +{ doSmth(1) } : * COPY +2 : Int NEW() +3 : Int NEW() +doSmth(3) : * NEW() +{ doSmth(3) } : * COPY +try { doSmth(1) } catch (e: UnsupportedOperationException) { return 2 } finally { doSmth(3) } : * COPY +{ try { doSmth(1) } catch (e: UnsupportedOperationException) { return 2 } finally { doSmth(3) } } : * COPY ===================== == doSmth == fun doSmth(i: Int) { diff --git a/compiler/testData/cfg/controlStructures/FinallyTestCopy.values b/compiler/testData/cfg/controlStructures/FinallyTestCopy.values index 9a622cdbac2..e49fa806b52 100644 --- a/compiler/testData/cfg/controlStructures/FinallyTestCopy.values +++ b/compiler/testData/cfg/controlStructures/FinallyTestCopy.values @@ -30,15 +30,15 @@ fun testCopy1() : Int { } } --------------------- -doSmth() NEW() -{ doSmth() } COPY -doSmth1() NEW() -{ doSmth1() } COPY -doSmth2() NEW() -{ doSmth2() } COPY -1 NEW() -try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 } NEW(, , ) -{ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 } } COPY +doSmth() : * NEW() +{ doSmth() } : * COPY +doSmth1() : * NEW() +{ doSmth1() } : * COPY +doSmth2() : * NEW() +{ doSmth2() } : * COPY +1 : Int NEW() +try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 } : * NEW(, , ) +{ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 } } : * COPY ===================== == testCopy2 == fun testCopy2() { @@ -59,16 +59,16 @@ fun testCopy2() { } } --------------------- -cond() NEW() -doSmth() NEW() -{ doSmth() } COPY -doSmth1() NEW() -{ doSmth1() } COPY -doSmth2() NEW() -{ doSmth2() } COPY -cond() NEW() -try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } NEW(, , ) -{ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } } COPY +cond() : Boolean NEW() +doSmth() : * NEW() +{ doSmth() } : * COPY +doSmth1() : * NEW() +{ doSmth1() } : * COPY +doSmth2() : * NEW() +{ doSmth2() } : * COPY +cond() : Boolean NEW() +try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } : * NEW(, , ) +{ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue } } : * COPY ===================== == testCopy3 == fun testCopy3() { @@ -86,15 +86,15 @@ fun testCopy3() { } } --------------------- -doSmth() NEW() -{ doSmth() } COPY -doSmth1() NEW() -{ doSmth1() } COPY -doSmth2() NEW() -{ doSmth2() } COPY -cond() NEW() -try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); } NEW(, , ) -{ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); } } COPY +doSmth() : * NEW() +{ doSmth() } : * COPY +doSmth1() : * NEW() +{ doSmth1() } : * COPY +doSmth2() : * NEW() +{ doSmth2() } : * COPY +cond() : Boolean NEW() +try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); } : * NEW(, , ) +{ try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); } } : * COPY ===================== == doTestCopy4 == fun doTestCopy4(list: List?) : Int { @@ -107,11 +107,11 @@ fun doTestCopy4(list: List?) : Int { } } --------------------- -doSmth() NEW() -{ doSmth() } COPY -list NEW() -null NEW() -list != null NEW(, ) -try { doSmth() } finally { if(list != null) { } } COPY -{ try { doSmth() } finally { if(list != null) { } } } COPY +doSmth() : * NEW() +{ doSmth() } : * COPY +list : {<: Any?} NEW() +null : {<: Any?} NEW() +list != null : Boolean NEW(, ) +try { doSmth() } finally { if(list != null) { } } : * COPY +{ try { doSmth() } finally { if(list != null) { } } } : * COPY ===================== diff --git a/compiler/testData/cfg/controlStructures/For.values b/compiler/testData/cfg/controlStructures/For.values index c7b2ce12294..027b5496c73 100644 --- a/compiler/testData/cfg/controlStructures/For.values +++ b/compiler/testData/cfg/controlStructures/For.values @@ -5,12 +5,12 @@ fun t1() { } } --------------------- -1 NEW() -2 NEW() -1..2 NEW(, ) -i NEW() -doSmth(i) NEW() -{ doSmth(i) } COPY +1 : Int NEW() +2 : Int NEW() +1..2 : {<: Iterable} NEW(, ) +i : Int NEW() +doSmth(i) : * NEW() +{ doSmth(i) } : * COPY ===================== == doSmth == fun doSmth(i: Int) {} diff --git a/compiler/testData/cfg/controlStructures/If.values b/compiler/testData/cfg/controlStructures/If.values index f0055a9467d..e2c4f2cf276 100644 --- a/compiler/testData/cfg/controlStructures/If.values +++ b/compiler/testData/cfg/controlStructures/If.values @@ -16,16 +16,16 @@ fun t1(b: Boolean) { doSmth(r) } --------------------- -b NEW() -"s" NEW() -u NEW() -doSmth(u) NEW() -b NEW() -"s" NEW() -"t" NEW() -r NEW() -doSmth(r) NEW() -{ var u: String if (b) { u = "s" } doSmth(u) var r: String if (b) { r = "s" } else { r = "t" } doSmth(r) } COPY +b : Boolean NEW() +"s" : String NEW() +u : String NEW() +doSmth(u) : * NEW() +b : Boolean NEW() +"s" : String NEW() +"t" : String NEW() +r : String NEW() +doSmth(r) : * NEW() +{ var u: String if (b) { u = "s" } doSmth(u) var r: String if (b) { r = "s" } else { r = "t" } doSmth(r) } : * COPY ===================== == t2 == fun t2(b: Boolean) { @@ -39,12 +39,12 @@ fun t2(b: Boolean) { } } --------------------- -3 NEW() -b NEW() -i NEW() -doSmth(i) NEW() -i NEW() -i is Int NEW() +3 : Int NEW() +b : Boolean NEW() +i : String NEW() +doSmth(i) : * NEW() +i : * NEW() +i is Int : Boolean NEW() ===================== == doSmth == fun doSmth(s: String) {} diff --git a/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.values b/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.values index b01dad9a5e4..b6eaafa0d7c 100644 --- a/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.values +++ b/compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.values @@ -5,11 +5,11 @@ fun main() { } } --------------------- -0 NEW() -1 NEW() -0 > 1 NEW(, ) -2 NEW() -{ 2 } COPY +0 : {<: Comparable} NEW() +1 : Int NEW() +0 > 1 : Boolean NEW(, ) +2 : * NEW() +{ 2 } : * COPY ===================== == dowhile == fun dowhile() { @@ -17,7 +17,7 @@ fun dowhile() { while(0 > 1) } --------------------- -0 NEW() -1 NEW() -0 > 1 NEW(, ) +0 : * NEW() +1 : * NEW() +0 > 1 : * NEW(, ) ===================== diff --git a/compiler/testData/cfg/controlStructures/returnsInWhen.values b/compiler/testData/cfg/controlStructures/returnsInWhen.values index 6fb7648cce6..f1835c8c05d 100644 --- a/compiler/testData/cfg/controlStructures/returnsInWhen.values +++ b/compiler/testData/cfg/controlStructures/returnsInWhen.values @@ -5,6 +5,6 @@ fun illegalWhenBlock(a: Any): Any { } } --------------------- -a NEW() -a NEW() +a : * NEW() +a : {<: Any} NEW() ===================== diff --git a/compiler/testData/cfg/conventions/bothReceivers.instructions b/compiler/testData/cfg/conventions/bothReceivers.instructions new file mode 100644 index 00000000000..ee01e13b419 --- /dev/null +++ b/compiler/testData/cfg/conventions/bothReceivers.instructions @@ -0,0 +1,65 @@ +== Bar == +class Bar { +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== Foo == +class Foo() { + fun Bar.invoke() {} +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== invoke == +fun Bar.invoke() {} +--------------------- +L0: + 1 + 2 mark({}) + read (Unit) +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== foobar == +fun foobar(f: Foo) { + Bar().f() +} +--------------------- +L0: + 1 + v(f: Foo) + magic(f: Foo) -> + w(f|) + 2 mark({ Bar().f() }) + mark(Bar().f()) + r(f) -> + mark(Bar()) + call(Bar, ) -> + mark(f()) + call(f, invoke|, ) -> +L1: + 1 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/conventions/bothReceivers.kt b/compiler/testData/cfg/conventions/bothReceivers.kt new file mode 100644 index 00000000000..1ad462cb71d --- /dev/null +++ b/compiler/testData/cfg/conventions/bothReceivers.kt @@ -0,0 +1,10 @@ +class Bar { +} + +class Foo() { + fun Bar.invoke() {} +} + +fun foobar(f: Foo) { + Bar().f() +} \ No newline at end of file diff --git a/compiler/testData/cfg/conventions/bothReceivers.values b/compiler/testData/cfg/conventions/bothReceivers.values new file mode 100644 index 00000000000..0e2db937727 --- /dev/null +++ b/compiler/testData/cfg/conventions/bothReceivers.values @@ -0,0 +1,26 @@ +== Bar == +class Bar { +} +--------------------- +===================== +== Foo == +class Foo() { + fun Bar.invoke() {} +} +--------------------- +===================== +== invoke == +fun Bar.invoke() {} +--------------------- +===================== +== foobar == +fun foobar(f: Foo) { + Bar().f() +} +--------------------- +Bar() : Bar NEW() +f : Foo NEW() +f() : * NEW(, ) +Bar().f() : * COPY +{ Bar().f() } : * COPY +===================== \ No newline at end of file diff --git a/compiler/testData/cfg/conventions/equals.values b/compiler/testData/cfg/conventions/equals.values index fde14f3d634..9d4a5bf3270 100644 --- a/compiler/testData/cfg/conventions/equals.values +++ b/compiler/testData/cfg/conventions/equals.values @@ -4,7 +4,7 @@ fun foo(a: Int, b: Int) { } } --------------------- -a NEW() -b NEW() -a == b NEW(, ) +a : OR{{<: Any}, {<: Any}} NEW() +b : {<: Any?} NEW() +a == b : Boolean NEW(, ) ===================== diff --git a/compiler/testData/cfg/conventions/incrementAtTheEnd.values b/compiler/testData/cfg/conventions/incrementAtTheEnd.values index af35d135232..daed10577df 100644 --- a/compiler/testData/cfg/conventions/incrementAtTheEnd.values +++ b/compiler/testData/cfg/conventions/incrementAtTheEnd.values @@ -4,8 +4,8 @@ fun foo() { i++ } --------------------- -1 NEW() -i NEW() -i++ COPY -{ var i = 1 i++ } COPY +1 : Int NEW() +i : Int NEW() +i++ : Int COPY +{ var i = 1 i++ } : Int COPY ===================== diff --git a/compiler/testData/cfg/conventions/invoke.values b/compiler/testData/cfg/conventions/invoke.values index 448531f5c64..02c3e5b3466 100644 --- a/compiler/testData/cfg/conventions/invoke.values +++ b/compiler/testData/cfg/conventions/invoke.values @@ -3,7 +3,7 @@ fun foo(f: () -> Unit) { f() } --------------------- -f NEW() -f() NEW() -{ f() } COPY +f : {<: () -> Unit} NEW() +f() : * NEW() +{ f() } : * COPY ===================== diff --git a/compiler/testData/cfg/conventions/notEqual.values b/compiler/testData/cfg/conventions/notEqual.values index 0ec5fe6e8a7..5f758f0157a 100644 --- a/compiler/testData/cfg/conventions/notEqual.values +++ b/compiler/testData/cfg/conventions/notEqual.values @@ -3,7 +3,7 @@ fun neq(a: Int, b: Int) { if (a != b) {} } --------------------- -a NEW() -b NEW() -a != b NEW(, ) +a : OR{{<: Any}, {<: Any}} NEW() +b : {<: Any?} NEW() +a != b : Boolean NEW(, ) ===================== diff --git a/compiler/testData/cfg/deadCode/DeadCode.values b/compiler/testData/cfg/deadCode/DeadCode.values index 994dd1d105f..addf7ec3995 100644 --- a/compiler/testData/cfg/deadCode/DeadCode.values +++ b/compiler/testData/cfg/deadCode/DeadCode.values @@ -4,7 +4,7 @@ fun test() { test() } --------------------- -Exception() NEW() -test() NEW() -{ throw Exception() test() } COPY +Exception() : {<: Throwable} NEW() +test() : * NEW() +{ throw Exception() test() } : * COPY ===================== diff --git a/compiler/testData/cfg/deadCode/returnInElvis.values b/compiler/testData/cfg/deadCode/returnInElvis.values index a2105a61f56..0a2dabc4721 100644 --- a/compiler/testData/cfg/deadCode/returnInElvis.values +++ b/compiler/testData/cfg/deadCode/returnInElvis.values @@ -3,7 +3,7 @@ fun foo() { return ?: null } --------------------- -null NEW() -return ?: null COPY -{ return ?: null } COPY +null : * NEW() +return ?: null : * COPY +{ return ?: null } : * COPY ===================== diff --git a/compiler/testData/cfg/deadCode/stringTemplate.values b/compiler/testData/cfg/deadCode/stringTemplate.values index b4c1c1b7c16..280634698cd 100644 --- a/compiler/testData/cfg/deadCode/stringTemplate.values +++ b/compiler/testData/cfg/deadCode/stringTemplate.values @@ -3,8 +3,8 @@ fun test() { "${throw Exception()} ${1}" } --------------------- -Exception() NEW() -1 NEW() -"${throw Exception()} ${1}" NEW() -{ "${throw Exception()} ${1}" } COPY +Exception() : {<: Throwable} NEW() +1 : * NEW() +"${throw Exception()} ${1}" : * NEW() +{ "${throw Exception()} ${1}" } : * COPY ===================== diff --git a/compiler/testData/cfg/declarations/classesAndObjects/AnonymousInitializers.values b/compiler/testData/cfg/declarations/classesAndObjects/AnonymousInitializers.values index 1f09331a566..886da7ea362 100644 --- a/compiler/testData/cfg/declarations/classesAndObjects/AnonymousInitializers.values +++ b/compiler/testData/cfg/declarations/classesAndObjects/AnonymousInitializers.values @@ -15,7 +15,7 @@ class AnonymousInitializers() { } } --------------------- -34 NEW() -12 NEW() -13 NEW() +34 : Int NEW() +12 : Int NEW() +13 : Int NEW() ===================== diff --git a/compiler/testData/cfg/declarations/functionLiterals/unusedFunctionLiteral.values b/compiler/testData/cfg/declarations/functionLiterals/unusedFunctionLiteral.values index e5a74bb024f..5ac4b35aefe 100644 --- a/compiler/testData/cfg/declarations/functionLiterals/unusedFunctionLiteral.values +++ b/compiler/testData/cfg/declarations/functionLiterals/unusedFunctionLiteral.values @@ -3,8 +3,8 @@ fun foo() { {} } --------------------- -{} NEW() -{ {} } COPY +{} : * NEW() +{ {} } : * COPY ===================== == anonymous_0 == {} diff --git a/compiler/testData/cfg/declarations/functions/FailFunction.values b/compiler/testData/cfg/declarations/functions/FailFunction.values index 062ee86dcf5..7a6b3c52016 100644 --- a/compiler/testData/cfg/declarations/functions/FailFunction.values +++ b/compiler/testData/cfg/declarations/functions/FailFunction.values @@ -3,6 +3,6 @@ fun fail() : Nothing { throw java.lang.RuntimeException() } --------------------- -RuntimeException() NEW() -java.lang.RuntimeException() COPY +RuntimeException() : {<: Throwable} NEW() +java.lang.RuntimeException() : {<: Throwable} COPY ===================== diff --git a/compiler/testData/cfg/declarations/functions/typeParameter.values b/compiler/testData/cfg/declarations/functions/typeParameter.values index 4ee00400258..ab80f5a4ee4 100644 --- a/compiler/testData/cfg/declarations/functions/typeParameter.values +++ b/compiler/testData/cfg/declarations/functions/typeParameter.values @@ -3,6 +3,6 @@ fun foo() { T } --------------------- -T NEW() -{ T } COPY +T : * NEW() +{ T } : * COPY ===================== diff --git a/compiler/testData/cfg/declarations/local/LocalDeclarations.values b/compiler/testData/cfg/declarations/local/LocalDeclarations.values index 4972ccbbe1b..9c4fe5cf211 100644 --- a/compiler/testData/cfg/declarations/local/LocalDeclarations.values +++ b/compiler/testData/cfg/declarations/local/LocalDeclarations.values @@ -17,7 +17,7 @@ class C() { } } --------------------- -1 NEW() +1 : Int NEW() ===================== == doSmth == fun doSmth(i: Int) {} @@ -33,8 +33,8 @@ fun test1() { } } --------------------- -1 NEW() -object { val x : Int { $x = 1 } } NEW() +1 : Int NEW() +object { val x : Int { $x = 1 } } : NEW() ===================== == O == object O { @@ -44,7 +44,7 @@ object O { } } --------------------- -1 NEW() +1 : Int NEW() ===================== == test2 == fun test2() { @@ -54,9 +54,9 @@ fun test2() { } } --------------------- -1 NEW() -b NEW() -object { val x = b } NEW() +1 : Int NEW() +b : Int NEW() +object { val x = b } : NEW() ===================== == test3 == fun test3() { @@ -68,14 +68,14 @@ fun test3() { } } --------------------- -object { val y : Int fun inner_bar() { y = 10 } } NEW() +object { val y : Int fun inner_bar() { y = 10 } } : NEW() ===================== == inner_bar == fun inner_bar() { y = 10 } --------------------- -10 NEW() +10 : Int NEW() ===================== == test4 == fun test4() { @@ -91,15 +91,15 @@ fun test4() { } } --------------------- -1 NEW() -object { val x : Int val y : Int { $x = 1 } fun ggg() { y = 10 } } NEW() +1 : Int NEW() +object { val x : Int val y : Int { $x = 1 } fun ggg() { y = 10 } } : NEW() ===================== == ggg == fun ggg() { y = 10 } --------------------- -10 NEW() +10 : Int NEW() ===================== == test5 == fun test5() { @@ -117,21 +117,21 @@ fun test5() { } } --------------------- -1 NEW() -2 NEW() -object { var x = 1 { $x = 2 } fun foo() { x = 3 } fun bar() { x = 4 } } NEW() +1 : Int NEW() +2 : Int NEW() +object { var x = 1 { $x = 2 } fun foo() { x = 3 } fun bar() { x = 4 } } : NEW() ===================== == foo == fun foo() { x = 3 } --------------------- -3 NEW() +3 : Int NEW() ===================== == bar == fun bar() { x = 4 } --------------------- -4 NEW() +4 : Int NEW() ===================== diff --git a/compiler/testData/cfg/declarations/local/ObjectExpression.values b/compiler/testData/cfg/declarations/local/ObjectExpression.values index deaf3419903..bf8c6041316 100644 --- a/compiler/testData/cfg/declarations/local/ObjectExpression.values +++ b/compiler/testData/cfg/declarations/local/ObjectExpression.values @@ -17,7 +17,7 @@ class B : A { == foo == override fun foo() = 10 --------------------- -10 NEW() +10 : Int NEW() ===================== == foo == fun foo(b: B) : Int { @@ -25,9 +25,9 @@ fun foo(b: B) : Int { return o.foo() } --------------------- -b NEW() -object : A by b {} NEW() -o NEW() -foo() NEW() -o.foo() COPY +b : * NEW() +object : A by b {} : NEW() +o : {<: A} NEW() +foo() : Int NEW() +o.foo() : Int COPY ===================== diff --git a/compiler/testData/cfg/declarations/local/localClass.values b/compiler/testData/cfg/declarations/local/localClass.values index 901eba15d72..4b9ec1b16cd 100644 --- a/compiler/testData/cfg/declarations/local/localClass.values +++ b/compiler/testData/cfg/declarations/local/localClass.values @@ -21,12 +21,12 @@ fun f() { } } --------------------- -"" NEW() +"" : String NEW() ===================== == loc == fun loc() { val x3 = "" } --------------------- -"" NEW() +"" : String NEW() ===================== diff --git a/compiler/testData/cfg/declarations/local/localProperty.values b/compiler/testData/cfg/declarations/local/localProperty.values index 3f3f9bf7ac5..bd5c69a29c0 100644 --- a/compiler/testData/cfg/declarations/local/localProperty.values +++ b/compiler/testData/cfg/declarations/local/localProperty.values @@ -16,5 +16,5 @@ get() { return b } --------------------- -b NEW() +b : Int NEW() ===================== diff --git a/compiler/testData/cfg/declarations/multiDeclaration/MultiDecl.values b/compiler/testData/cfg/declarations/multiDeclaration/MultiDecl.values index 0cf5a4b0acd..99a44889fa0 100644 --- a/compiler/testData/cfg/declarations/multiDeclaration/MultiDecl.values +++ b/compiler/testData/cfg/declarations/multiDeclaration/MultiDecl.values @@ -8,12 +8,12 @@ class C { == component1 == fun component1() = 1 --------------------- -1 NEW() +1 : Int NEW() ===================== == component2 == fun component2() = 2 --------------------- -2 NEW() +2 : Int NEW() ===================== == test == fun test(c: C) { @@ -21,8 +21,8 @@ fun test(c: C) { val d = 1 } --------------------- -a NEW() -b NEW() -c NEW() -1 NEW() +a : Int NEW() +b : Int NEW() +c : C NEW() +1 : Int NEW() ===================== diff --git a/compiler/testData/cfg/declarations/multiDeclaration/multiDeclarationWithError.values b/compiler/testData/cfg/declarations/multiDeclaration/multiDeclarationWithError.values index 71f56d9b567..cad29edf6e3 100644 --- a/compiler/testData/cfg/declarations/multiDeclaration/multiDeclarationWithError.values +++ b/compiler/testData/cfg/declarations/multiDeclaration/multiDeclarationWithError.values @@ -4,7 +4,7 @@ fun foo(x: Int) { a } --------------------- -x NEW() -a NEW() -{ val (a, b) = x a } COPY +x : * NEW() +a : * NEW() +{ val (a, b) = x a } : * COPY ===================== diff --git a/compiler/testData/cfg/declarations/properties/DelegatedProperty.values b/compiler/testData/cfg/declarations/properties/DelegatedProperty.values index 0cb0fefa23e..7197e993c66 100644 --- a/compiler/testData/cfg/declarations/properties/DelegatedProperty.values +++ b/compiler/testData/cfg/declarations/properties/DelegatedProperty.values @@ -7,15 +7,15 @@ class Delegate { == get == fun get(_this: Any, p: PropertyMetadata): Int = 0 --------------------- -0 NEW() +0 : Int NEW() ===================== == a == val a = Delegate() --------------------- -Delegate() NEW() +Delegate() : Delegate NEW() ===================== == b == val b by a --------------------- -a NEW() +a : * NEW() ===================== diff --git a/compiler/testData/cfg/declarations/properties/backingFieldAccess.values b/compiler/testData/cfg/declarations/properties/backingFieldAccess.values index 1b32ec1b88e..163de356aa2 100644 --- a/compiler/testData/cfg/declarations/properties/backingFieldAccess.values +++ b/compiler/testData/cfg/declarations/properties/backingFieldAccess.values @@ -8,6 +8,6 @@ class C { } } --------------------- -$a NEW() -{ $a } COPY +$a : * NEW() +{ $a } : * COPY ===================== diff --git a/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.values b/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.values index 1e5f253264f..6c6f52e2a37 100644 --- a/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.values +++ b/compiler/testData/cfg/declarations/properties/backingFieldQualifiedWithThis.values @@ -8,10 +8,10 @@ abstract class Bar { == foo == fun foo() = "foo" + this.$bar --------------------- -"foo" NEW() -this COPY -this NEW() -$bar NEW() -this.$bar COPY -"foo" + this.$bar NEW(, ) +"foo" : String NEW() +this : {<: Bar} COPY +this : {<: Bar} NEW() +$bar : {<: Any?} NEW() +this.$bar : {<: Any?} COPY +"foo" + this.$bar : String NEW(, ) ===================== diff --git a/compiler/testData/cfg/expressions/Assignments.values b/compiler/testData/cfg/expressions/Assignments.values index 80cc3e47236..f532d04aa5c 100644 --- a/compiler/testData/cfg/expressions/Assignments.values +++ b/compiler/testData/cfg/expressions/Assignments.values @@ -20,28 +20,28 @@ fun assignments() : Unit { t.x += 1 } --------------------- -1 NEW() -2 NEW() -x NEW() -2 NEW() -x += 2 NEW(, ) -true NEW() -1 NEW() -2 NEW() -if (true) 1 else 2 NEW(, ) -true NEW() -false NEW() -true && false NEW(, ) -false NEW() -true NEW() -false && true NEW(, ) -Test() NEW() -t NEW() -1 NEW() -t NEW() -x NEW() -t.x COPY -1 NEW() -t.x += 1 NEW(, ) -{ var x = 1 x = 2 x += 2 x = if (true) 1 else 2 val y = true && false val z = false && true val t = Test(); t.x = 1 t.x += 1 } COPY +1 : Int NEW() +2 : Int NEW() +x : Int NEW() +2 : Int NEW() +x += 2 : Int NEW(, ) +true : Boolean NEW() +1 : Int NEW() +2 : Int NEW() +if (true) 1 else 2 : Int NEW(, ) +true : Boolean NEW() +false : Boolean NEW() +true && false : Boolean NEW(, ) +false : Boolean NEW() +true : Boolean NEW() +false && true : Boolean NEW(, ) +Test() : Test NEW() +t : Test NEW() +1 : Int NEW() +t : Test NEW() +x : Int NEW() +t.x : Int COPY +1 : Int NEW() +t.x += 1 : Int NEW(, ) +{ var x = 1 x = 2 x += 2 x = if (true) 1 else 2 val y = true && false val z = false && true val t = Test(); t.x = 1 t.x += 1 } : Int COPY ===================== diff --git a/compiler/testData/cfg/expressions/LazyBooleans.values b/compiler/testData/cfg/expressions/LazyBooleans.values index fcd696e1030..b432c87df86 100644 --- a/compiler/testData/cfg/expressions/LazyBooleans.values +++ b/compiler/testData/cfg/expressions/LazyBooleans.values @@ -17,34 +17,34 @@ fun lazyBooleans(a : Boolean, b : Boolean) : Unit { 14 } --------------------- -a NEW() -1 NEW() -{ 1 } COPY -2 NEW() -{ 2 } COPY -if (a) { 1 } else { 2 } NEW(, ) -3 NEW() -a NEW() -b NEW() -a && b NEW(, ) -5 NEW() -6 NEW() -if (a && b) 5 else 6 NEW(, ) -7 NEW() -a NEW() -b NEW() -a || b NEW(, ) -8 NEW() -9 NEW() -if (a || b) 8 else 9 NEW(, ) -10 NEW() -a NEW() -11 NEW() -if (a) 11 COPY -12 NEW() -a NEW() -13 NEW() -if (a) else 13 COPY -14 NEW() -{ if (a) { 1 } else { 2 } 3 if (a && b) 5 else 6 7 if (a || b) 8 else 9 10 if (a) 11 12 if (a) else 13 14 } COPY +a : Boolean NEW() +1 : * NEW() +{ 1 } : * COPY +2 : * NEW() +{ 2 } : * COPY +if (a) { 1 } else { 2 } : * NEW(, ) +3 : * NEW() +a : Boolean NEW() +b : Boolean NEW() +a && b : Boolean NEW(, ) +5 : * NEW() +6 : * NEW() +if (a && b) 5 else 6 : * NEW(, ) +7 : * NEW() +a : Boolean NEW() +b : Boolean NEW() +a || b : Boolean NEW(, ) +8 : * NEW() +9 : * NEW() +if (a || b) 8 else 9 : * NEW(, ) +10 : * NEW() +a : Boolean NEW() +11 : * NEW() +if (a) 11 : * COPY +12 : * NEW() +a : Boolean NEW() +13 : * NEW() +if (a) else 13 : * COPY +14 : * NEW() +{ if (a) { 1 } else { 2 } 3 if (a && b) 5 else 6 7 if (a || b) 8 else 9 10 if (a) 11 12 if (a) else 13 14 } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/ReturnFromExpression.values b/compiler/testData/cfg/expressions/ReturnFromExpression.values index fefb44006b9..dc871c3aa57 100644 --- a/compiler/testData/cfg/expressions/ReturnFromExpression.values +++ b/compiler/testData/cfg/expressions/ReturnFromExpression.values @@ -3,8 +3,8 @@ fun blockAndAndMismatch() : Boolean { false || (return false) } --------------------- -false NEW() -false NEW() -false || (return false) NEW() -{ false || (return false) } COPY +false : Boolean NEW() +false : Boolean NEW() +false || (return false) : * NEW() +{ false || (return false) } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/assignmentToThis.values b/compiler/testData/cfg/expressions/assignmentToThis.values index 45d0ff07d35..2571d44967f 100644 --- a/compiler/testData/cfg/expressions/assignmentToThis.values +++ b/compiler/testData/cfg/expressions/assignmentToThis.values @@ -3,5 +3,5 @@ fun Int.bar(c: C) { this = c } --------------------- -c NEW() +c : * NEW() ===================== diff --git a/compiler/testData/cfg/expressions/chainedQualifiedExpression.values b/compiler/testData/cfg/expressions/chainedQualifiedExpression.values index 54a5ded8e24..03ec485f499 100644 --- a/compiler/testData/cfg/expressions/chainedQualifiedExpression.values +++ b/compiler/testData/cfg/expressions/chainedQualifiedExpression.values @@ -50,141 +50,141 @@ public open class JetKeywordCompletionContributor() { } } --------------------- -1.0 NEW() -BunchKeywordRegister() NEW() -ABSTRACT_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -FINAL_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -OPEN_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -INTERNAL_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) COPY -PRIVATE_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) COPY -PROTECTED_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) COPY -PUBLIC_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) COPY -CLASS_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -ENUM_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -FUN_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -GET_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -SET_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -TRAIT_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -VAL_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -VAR_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -TYPE_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -inTopLevel NEW() -add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) NEW(, , , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) COPY -IMPORT_KEYWORD NEW() -inTopLevel NEW() -add(IMPORT_KEYWORD, inTopLevel) NEW(, , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) COPY -PACKAGE_KEYWORD NEW() -inTopLevel NEW() -add(PACKAGE_KEYWORD, inTopLevel) NEW(, , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) COPY -OVERRIDE_KEYWORD NEW() -inTopLevel NEW() -add(OVERRIDE_KEYWORD, inTopLevel) NEW(, , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) COPY -IN_KEYWORD NEW() -inTopLevel NEW() -inTopLevel NEW() -add(IN_KEYWORD, inTopLevel, inTopLevel) NEW(, , , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) COPY -OUT_KEYWORD NEW() -inTopLevel NEW() -add(OUT_KEYWORD, inTopLevel) NEW(, , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) COPY -OBJECT_KEYWORD NEW() -unresolvedCode NEW() -add(OBJECT_KEYWORD, unresolvedCode) NEW(, , ) -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode) COPY -registerAll() NEW() -BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode) .registerAll() COPY -{ val inTopLevel = 1.0 BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode) .registerAll() } COPY +1.0 : Double NEW() +BunchKeywordRegister() : JetKeywordCompletionContributor.BunchKeywordRegister NEW() +ABSTRACT_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +FINAL_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +OPEN_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +INTERNAL_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +PRIVATE_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +PROTECTED_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +PUBLIC_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +CLASS_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +ENUM_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +FUN_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +GET_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +SET_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +TRAIT_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +VAL_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +VAR_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +TYPE_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +IMPORT_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +add(IMPORT_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +PACKAGE_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +add(PACKAGE_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +OVERRIDE_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +add(OVERRIDE_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +IN_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +inTopLevel : Double NEW() +add(IN_KEYWORD, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +OUT_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +inTopLevel : Double NEW() +add(OUT_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +OBJECT_KEYWORD : {<: [ERROR : Type annotation was missing]} NEW() +unresolvedCode : Double NEW() +add(OBJECT_KEYWORD, unresolvedCode) : JetKeywordCompletionContributor.BunchKeywordRegister NEW(, , ) +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode) : JetKeywordCompletionContributor.BunchKeywordRegister COPY +registerAll() : * NEW() +BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode) .registerAll() : * COPY +{ val inTopLevel = 1.0 BunchKeywordRegister() .add(ABSTRACT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FINAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(OPEN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(INTERNAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PRIVATE_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PROTECTED_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(PUBLIC_KEYWORD, inTopLevel, inTopLevel, inTopLevel, inTopLevel) .add(CLASS_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(ENUM_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(FUN_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(GET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(SET_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TRAIT_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAL_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(VAR_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(TYPE_KEYWORD, inTopLevel, inTopLevel, inTopLevel) .add(IMPORT_KEYWORD, inTopLevel) .add(PACKAGE_KEYWORD, inTopLevel) .add(OVERRIDE_KEYWORD, inTopLevel) .add(IN_KEYWORD, inTopLevel, inTopLevel) .add(OUT_KEYWORD, inTopLevel) .add(OBJECT_KEYWORD, unresolvedCode) .registerAll() } : * COPY ===================== == ABSTRACT_KEYWORD == val ABSTRACT_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == FINAL_KEYWORD == val FINAL_KEYWORD OPEN_KEYWORD = JetToken() @@ -193,100 +193,100 @@ val FINAL_KEYWORD OPEN_KEYWORD = JetToken() == OPEN_KEYWORD == val OPEN_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == INTERNAL_KEYWORD == val INTERNAL_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == PRIVATE_KEYWORD == val PRIVATE_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == PROTECTED_KEYWORD == val PROTECTED_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == PUBLIC_KEYWORD == val PUBLIC_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == CLASS_KEYWORD == val CLASS_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == ENUM_KEYWORD == val ENUM_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == FUN_KEYWORD == val FUN_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == GET_KEYWORD == val GET_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == SET_KEYWORD == val SET_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == TRAIT_KEYWORD == val TRAIT_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == VAL_KEYWORD == val VAL_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == VAR_KEYWORD == val VAR_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == TYPE_KEYWORD == val TYPE_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == IMPORT_KEYWORD == val IMPORT_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == PACKAGE_KEYWORD == val PACKAGE_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == OVERRIDE_KEYWORD == val OVERRIDE_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == IN_KEYWORD == val IN_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == OUT_KEYWORD == val OUT_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== == OBJECT_KEYWORD == val OBJECT_KEYWORD = JetToken() --------------------- -JetToken() NEW() +JetToken() : JetToken NEW() ===================== diff --git a/compiler/testData/cfg/expressions/expressionAsFunction.values b/compiler/testData/cfg/expressions/expressionAsFunction.values index 2d458dfdcc0..52a6534275b 100644 --- a/compiler/testData/cfg/expressions/expressionAsFunction.values +++ b/compiler/testData/cfg/expressions/expressionAsFunction.values @@ -3,8 +3,8 @@ fun invoke(f: () -> Unit) { (f)() } --------------------- -f NEW() -(f) COPY -(f)() NEW() -{ (f)() } COPY +f : {<: () -> Unit} NEW() +(f) : {<: () -> Unit} COPY +(f)() : * NEW() +{ (f)() } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/incdec.values b/compiler/testData/cfg/expressions/incdec.values index f593461f745..060a72f960d 100644 --- a/compiler/testData/cfg/expressions/incdec.values +++ b/compiler/testData/cfg/expressions/incdec.values @@ -13,18 +13,18 @@ fun foo() { bar(--a) } --------------------- -1 NEW() -a NEW() -a++ COPY -bar(a++) NEW() -a NEW() -a-- COPY -bar(a--) NEW() -a NEW() -++a NEW() -bar(++a) NEW() -a NEW() ---a NEW() -bar(--a) NEW() -{ var a = 1 bar(a++) bar(a--) bar(++a) bar(--a) } COPY -===================== \ No newline at end of file +1 : Int NEW() +a : Int NEW() +a++ : Int COPY +bar(a++) : * NEW() +a : Int NEW() +a-- : Int COPY +bar(a--) : * NEW() +a : Int NEW() +++a : Int NEW() +bar(++a) : * NEW() +a : Int NEW() +--a : Int NEW() +bar(--a) : * NEW() +{ var a = 1 bar(a++) bar(a--) bar(++a) bar(--a) } : * COPY +===================== diff --git a/compiler/testData/cfg/expressions/nothingExpr.values b/compiler/testData/cfg/expressions/nothingExpr.values index 11eb2496563..4cd3916aecd 100644 --- a/compiler/testData/cfg/expressions/nothingExpr.values +++ b/compiler/testData/cfg/expressions/nothingExpr.values @@ -5,7 +5,7 @@ fun Any?.doSomething() {} == bar == fun bar(): Nothing = throw Exception() --------------------- -Exception() NEW() +Exception() : {<: Throwable} NEW() ===================== == foo == fun foo() { @@ -13,11 +13,11 @@ fun foo() { bar().doSomething } --------------------- -null NEW() -null!! NEW() -doSomething() NEW() -null!!.doSomething() COPY -doSomething NEW() -bar().doSomething COPY -{ null!!.doSomething() bar().doSomething } COPY +null : * NEW() +null!! : * NEW() +doSomething() : * NEW() +null!!.doSomething() : * COPY +doSomething : * NEW() +bar().doSomething : * COPY +{ null!!.doSomething() bar().doSomething } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/propertySafeCall.values b/compiler/testData/cfg/expressions/propertySafeCall.values index 80da9017c57..a288285f8f4 100644 --- a/compiler/testData/cfg/expressions/propertySafeCall.values +++ b/compiler/testData/cfg/expressions/propertySafeCall.values @@ -3,8 +3,8 @@ fun test(s: String?) { s?.length } --------------------- -s NEW() -length NEW() -s?.length COPY -{ s?.length } COPY +s : {<: CharSequence?} NEW() +length : * NEW() +s?.length : * COPY +{ s?.length } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/qualifiedExpressionWithoutSelector.values b/compiler/testData/cfg/expressions/qualifiedExpressionWithoutSelector.values index 8ac8e57cef1..71888c1db6a 100644 --- a/compiler/testData/cfg/expressions/qualifiedExpressionWithoutSelector.values +++ b/compiler/testData/cfg/expressions/qualifiedExpressionWithoutSelector.values @@ -3,7 +3,7 @@ fun foo(s: String) { s. } --------------------- -s NEW() -s. NEW() -{ s. } COPY +s : * NEW() +s. : * NEW() +{ s. } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/thisExpression.values b/compiler/testData/cfg/expressions/thisExpression.values index 36c7359fc2e..a1db0a07d38 100644 --- a/compiler/testData/cfg/expressions/thisExpression.values +++ b/compiler/testData/cfg/expressions/thisExpression.values @@ -3,6 +3,6 @@ fun Function0.foo() { this() } --------------------- -this() NEW() -{ this() } COPY +this() : * NEW() +{ this() } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/unresolvedCall.values b/compiler/testData/cfg/expressions/unresolvedCall.values index 54739cc2bc7..e7c190cc644 100644 --- a/compiler/testData/cfg/expressions/unresolvedCall.values +++ b/compiler/testData/cfg/expressions/unresolvedCall.values @@ -3,8 +3,8 @@ fun test(a: Any) { a.foo() } --------------------- -a NEW() -foo() NEW() -a.foo() COPY -{ a.foo() } COPY +a : * NEW() +foo() : * NEW() +a.foo() : * COPY +{ a.foo() } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/unresolvedProperty.values b/compiler/testData/cfg/expressions/unresolvedProperty.values index 242d96f7738..a9903e08e05 100644 --- a/compiler/testData/cfg/expressions/unresolvedProperty.values +++ b/compiler/testData/cfg/expressions/unresolvedProperty.values @@ -3,8 +3,8 @@ fun test(a: Any) { a.foo } --------------------- -a NEW() -foo NEW() -a.foo COPY -{ a.foo } COPY +a : * NEW() +foo : * NEW() +a.foo : * COPY +{ a.foo } : * COPY ===================== diff --git a/compiler/testData/cfg/expressions/unusedExpressionSimpleName.values b/compiler/testData/cfg/expressions/unusedExpressionSimpleName.values index 21c1d285846..6e60c264f8f 100644 --- a/compiler/testData/cfg/expressions/unusedExpressionSimpleName.values +++ b/compiler/testData/cfg/expressions/unusedExpressionSimpleName.values @@ -3,6 +3,6 @@ fun main(arg : Array) { a } --------------------- -a NEW() -{ a } COPY +a : * NEW() +{ a } : * COPY ===================== diff --git a/compiler/testData/cfg/functions/DefaultValuesForArguments.values b/compiler/testData/cfg/functions/DefaultValuesForArguments.values index ce90d8c6d3c..1f17659350c 100644 --- a/compiler/testData/cfg/functions/DefaultValuesForArguments.values +++ b/compiler/testData/cfg/functions/DefaultValuesForArguments.values @@ -1,9 +1,9 @@ == foo == fun foo(i: Int = 1, j: Int) = i + j --------------------- -1 NEW() -i: Int = 1 NEW(, ) -i NEW() -j NEW() -i + j NEW(, ) +1 : Int NEW() +i: Int = 1 : Int NEW(, ) +i : Int NEW() +j : Int NEW() +i + j : Int NEW(, ) ===================== diff --git a/compiler/testData/cfg/tailCalls/finally.values b/compiler/testData/cfg/tailCalls/finally.values index 3c892f5ed05..164bdd47631 100644 --- a/compiler/testData/cfg/tailCalls/finally.values +++ b/compiler/testData/cfg/tailCalls/finally.values @@ -7,6 +7,6 @@ tailRecursive fun test() : Int { } } --------------------- -test() NEW() -{ test() } COPY +test() : * NEW() +{ test() } : * COPY ===================== diff --git a/compiler/testData/cfg/tailCalls/finallyWithReturn.values b/compiler/testData/cfg/tailCalls/finallyWithReturn.values index ae6a6469285..11c80464648 100644 --- a/compiler/testData/cfg/tailCalls/finallyWithReturn.values +++ b/compiler/testData/cfg/tailCalls/finallyWithReturn.values @@ -7,5 +7,5 @@ tailRecursive fun test() : Int { } } --------------------- -test() NEW() +test() : Int NEW() ===================== diff --git a/compiler/testData/cfg/tailCalls/sum.values b/compiler/testData/cfg/tailCalls/sum.values index 89681b86d73..7df26749973 100644 --- a/compiler/testData/cfg/tailCalls/sum.values +++ b/compiler/testData/cfg/tailCalls/sum.values @@ -4,17 +4,17 @@ tailRecursive fun sum(x: Long, sum: Long): Long { return sum(x - 1, sum + x) } --------------------- -x NEW() -0 NEW() -toLong() NEW() -0.toLong() COPY -x == 0.toLong() NEW(, ) -sum NEW() -x NEW() -1 NEW() -x - 1 NEW(, ) -sum NEW() -x NEW() -sum + x NEW(, ) -sum(x - 1, sum + x) NEW(, ) +x : OR{{<: Any}, {<: Any}} NEW() +0 : {<: Number} NEW() +toLong() : {<: Any?} NEW() +0.toLong() : {<: Any?} COPY +x == 0.toLong() : Boolean NEW(, ) +sum : Long NEW() +x : Long NEW() +1 : Int NEW() +x - 1 : Long NEW(, ) +sum : Long NEW() +x : Long NEW() +sum + x : Long NEW(, ) +sum(x - 1, sum + x) : Long NEW(, ) ===================== diff --git a/compiler/testData/cfg/tailCalls/try.values b/compiler/testData/cfg/tailCalls/try.values index 8605d77c651..269ddaa7c86 100644 --- a/compiler/testData/cfg/tailCalls/try.values +++ b/compiler/testData/cfg/tailCalls/try.values @@ -7,5 +7,5 @@ tailRecursive fun foo() { } } --------------------- -foo() NEW() +foo() : Unit NEW() ===================== diff --git a/compiler/testData/cfg/tailCalls/tryCatchFinally.values b/compiler/testData/cfg/tailCalls/tryCatchFinally.values index e555ef8ad11..08302009127 100644 --- a/compiler/testData/cfg/tailCalls/tryCatchFinally.values +++ b/compiler/testData/cfg/tailCalls/tryCatchFinally.values @@ -9,12 +9,12 @@ fun test() : Unit { } } --------------------- -test() NEW() -{ test() } COPY -test() NEW() -{ test() } COPY -test() NEW() -{ test() } COPY -try { test() } catch (any : Exception) { test() } finally { test() } NEW(, ) -{ try { test() } catch (any : Exception) { test() } finally { test() } } COPY +test() : * NEW() +{ test() } : * COPY +test() : * NEW() +{ test() } : * COPY +test() : * NEW() +{ test() } : * COPY +try { test() } catch (any : Exception) { test() } finally { test() } : * NEW(, ) +{ try { test() } catch (any : Exception) { test() } finally { test() } } : * COPY ===================== diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt index f795983e262..f980f195c5b 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt @@ -22,9 +22,15 @@ import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid import org.jetbrains.jet.lang.resolve.BindingContext import java.util.* +import org.jetbrains.jet.lang.cfg.pseudocode.collectValueUsages +import org.jetbrains.jet.lang.cfg.pseudocode.TypePredicate +import org.jetbrains.jet.lang.cfg.pseudocode.getExpectedTypePredicate public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() { override fun dumpInstructions(pseudocode: PseudocodeImpl, out: StringBuilder, bindingContext: BindingContext) { + val valueUsageMap = pseudocode.collectValueUsages() + val expectedTypePredicateMap = HashMap() + fun getElementToValueMap(pseudocode: PseudocodeImpl): Map { val elementToValues = LinkedHashMap() pseudocode.getCorrespondingElement().accept(object : JetTreeVisitorVoid() { @@ -44,6 +50,11 @@ public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() { fun elementText(element: JetElement): String = element.getText()!!.replaceAll("\\s+", " ") + fun valueDecl(value: PseudoValue): String { + val typePredicate = expectedTypePredicateMap.getOrPut(value) { getExpectedTypePredicate(value, valueUsageMap, bindingContext) } + return "${value.debugName}: $typePredicate" + } + fun valueDescription(element: JetElement, value: PseudoValue): String { return if (value.element != element) "COPY" else "NEW${value.createdAt.inputValues.makeString(", ", "(", ")")}" } @@ -52,14 +63,14 @@ public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() { if (elementToValues.isEmpty()) return val elementColumnWidth = elementToValues.keySet().map { elementText(it).length() }.max()!! - val valueColumnWidth = elementToValues.values().map { it.debugName.length() }.max()!! + val valueColumnWidth = elementToValues.values().map { valueDecl(it).length() }.max()!! val valueDescColumnWidth = elementToValues.entrySet().map { valueDescription(it.key, it.value).length }.max()!! for ((element, value) in elementToValues.entrySet()) { out .append("%1$-${elementColumnWidth}s".format(elementText(element))) .append(" ") - .append("%1$-${valueColumnWidth}s".format(value.debugName)) + .append("%1$-${valueColumnWidth}s".format(valueDecl(value))) .append(" ") .append("%1$-${valueDescColumnWidth}s".format(valueDescription(element, value))) .append("\n") diff --git a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java index 4ea1536a2f6..b4f0f972387 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/ControlFlowTestGenerated.java @@ -155,6 +155,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg/conventions"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("bothReceivers.kt") + public void testBothReceivers() throws Exception { + doTest("compiler/testData/cfg/conventions/bothReceivers.kt"); + } + @TestMetadata("equals.kt") public void testEquals() throws Exception { doTest("compiler/testData/cfg/conventions/equals.kt"); diff --git a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java index 326aedc5a82..f530d7e7c02 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/PseudoValueTestGenerated.java @@ -157,6 +157,11 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg/conventions"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("bothReceivers.kt") + public void testBothReceivers() throws Exception { + doTest("compiler/testData/cfg/conventions/bothReceivers.kt"); + } + @TestMetadata("equals.kt") public void testEquals() throws Exception { doTest("compiler/testData/cfg/conventions/equals.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 7c29790768c..578d071ffed 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -17,10 +17,13 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.base.Predicate; -import com.google.common.collect.*; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.intellij.util.containers.ContainerUtil; import kotlin.Function1; import kotlin.Unit; +import kotlin.jvm.KotlinSignature; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -31,12 +34,11 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeConstructor; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.utils.DFS; import java.util.*; -import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.CONFLICT; -import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE; -import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE; +import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*; public class OverridingUtil { @@ -512,6 +514,32 @@ public class OverridingUtil { return maxVisibility; } + + @NotNull + @KotlinSignature("fun getTopmostOverridenDescriptors(originalDescriptor: CallableDescriptor): List") + public static List getTopmostOverridenDescriptors(@NotNull CallableDescriptor originalDescriptor) { + return DFS.dfs( + Collections.singletonList(originalDescriptor), + new DFS.Neighbors() { + @NotNull + @Override + public Iterable getNeighbors(CallableDescriptor current) { + return current.getOverriddenDescriptors(); + } + }, + new DFS.CollectingNodeHandler>( + new ArrayList() + ) { + @Override + public void afterChildren(CallableDescriptor current) { + if (current.getOverriddenDescriptors().isEmpty()) { + result.add(current); + } + } + } + ); + } + public interface DescriptorSink { void addToScope(@NotNull CallableMemberDescriptor fakeOverride); diff --git a/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java b/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java index 648b0215d5c..ca9103af9ff 100644 --- a/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java +++ b/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java @@ -91,7 +91,7 @@ public class DFS { public interface Neighbors { @KotlinSignature("fun getNeighbors(current: N): Iterable") @NotNull - Iterable getNeighbors(N current); + Iterable getNeighbors(N current); } public interface Visited { From 53c49b633322ee605269b70b46d270e019a8ea76 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:46 +0400 Subject: [PATCH 037/143] Shorten References: Do not shorten qualified expression if receiver values are changed #KT-5180 Fixed --- .../jet/plugin/codeInsight/ShortenReferences.kt | 16 ++++++++++++++-- .../extractThis/explicitThisInExtension.kt.after | 2 +- .../implicitAndExplicitThisInExtension.kt.after | 2 +- idea/testData/shortenRefs/noShortening.kt | 7 +++++++ idea/testData/shortenRefs/noShortening.kt.after | 7 +++++++ .../shortenRefs/ShortenRefsTestGenerated.java | 5 +++++ 6 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 idea/testData/shortenRefs/noShortening.kt create mode 100644 idea/testData/shortenRefs/noShortening.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt index 6d1aa4df7fc..13f1ffa4586 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt @@ -33,9 +33,11 @@ import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentForJavaClass import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor import com.intellij.openapi.util.TextRange -import com.intellij.psi.SmartPointerManager import com.intellij.psi.PsiDocumentManager import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.jet.renderer.DescriptorRenderer.FQ_NAMES_IN_TYPES public object ShortenReferences { public fun process(element: JetElement) { @@ -313,7 +315,13 @@ public object ShortenReferences { private fun resolveState(referenceExpression: JetReferenceExpression, bindingContext: BindingContext): Any? { val target = bindingContext[BindingContext.REFERENCE_TARGET, referenceExpression] - if (target != null) return target.asString() + if (target != null) { + val resolvedCallKey = (referenceExpression.getParent() as? JetThisExpression) ?: referenceExpression + val resolvedCall = bindingContext[BindingContext.RESOLVED_CALL, resolvedCallKey] + if (resolvedCall != null) return resolvedCall.asString() + + return target.asString() + } val targets = bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression] if (targets != null) return HashSet(targets.map{it.asString()}) @@ -334,6 +342,10 @@ public object ShortenReferences { private fun DeclarationDescriptor.asString() = DescriptorRenderer.FQ_NAMES_IN_TYPES.render(this) + private fun ResolvedCall<*>.asString(): String { + return "${getReceiverArgument()}, ${getThisObject()} -> ${getResultingDescriptor()?.let {FQ_NAMES_IN_TYPES.render(it)}}" + } + //TODO: do we need this "IfNeeded" check? private fun addImportIfNeeded(descriptor: DeclarationDescriptor, file: JetFile) { ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file) diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after index db4d498bd74..bec9686c4dc 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after @@ -6,5 +6,5 @@ fun Z.foo(): Int { } fun Z.i(): Int { - return a + return this.a } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after index 5686b9478dd..ffa4e81dd31 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after @@ -6,5 +6,5 @@ fun Z.foo(): Int { } fun Z.i(): Int { - return a + a + return this.a + a } diff --git a/idea/testData/shortenRefs/noShortening.kt b/idea/testData/shortenRefs/noShortening.kt new file mode 100644 index 00000000000..89b75813155 --- /dev/null +++ b/idea/testData/shortenRefs/noShortening.kt @@ -0,0 +1,7 @@ +trait T : Iterable + +abstract class C : T { + fun foo(c: C) { + if (c.any { it.size > 1 }) {} + } +} \ No newline at end of file diff --git a/idea/testData/shortenRefs/noShortening.kt.after b/idea/testData/shortenRefs/noShortening.kt.after new file mode 100644 index 00000000000..bd5285f3b1c --- /dev/null +++ b/idea/testData/shortenRefs/noShortening.kt.after @@ -0,0 +1,7 @@ +trait T : Iterable + +abstract class C : T { + fun foo(c: C) { + if (c.any { it.size > 1 }) {} + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java b/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java index 27fad679ecc..b7af568ad50 100644 --- a/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java @@ -47,6 +47,11 @@ public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { doTest("idea/testData/shortenRefs/JavaStaticMethod.kt"); } + @TestMetadata("noShortening.kt") + public void testNoShortening() throws Exception { + doTest("idea/testData/shortenRefs/noShortening.kt"); + } + @TestMetadata("idea/testData/shortenRefs/constructor") public static class Constructor extends AbstractShortenRefsTest { public void testAllFilesPresentInConstructor() throws Exception { From 5be7eb8a5c2e7451672b621c50d04476da385e45 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:54 +0400 Subject: [PATCH 038/143] Shorten References: Do not optimize imports until shortening is finished #KT-5227 Fixed --- .../com/intellij/codeInsight/annotations.xml | 5 ++ .../plugin/codeInsight/ShortenReferences.kt | 4 +- .../plugin/quickfix/ImportInsertHelper.java | 34 +++++++-- .../imports/leaveQualifiedConstructor.kt | 4 ++ .../leaveQualifiedConstructor.kt.after | 4 ++ .../shortenRefs/imports/leaveQualifiedType.kt | 4 ++ .../imports/leaveQualifiedType.kt.after | 4 ++ .../imports/optimizeMultipleImports.kt | 4 ++ .../imports/optimizeMultipleImports.kt.after | 5 ++ .../shortenRefs/AbstractShortenRefsTest.kt | 72 +++++++++---------- .../shortenRefs/ShortenRefsTestGenerated.java | 26 ++++++- 11 files changed, 119 insertions(+), 47 deletions(-) create mode 100644 annotations/com/intellij/codeInsight/annotations.xml create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedType.kt create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after create mode 100644 idea/testData/shortenRefs/imports/optimizeMultipleImports.kt create mode 100644 idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after diff --git a/annotations/com/intellij/codeInsight/annotations.xml b/annotations/com/intellij/codeInsight/annotations.xml new file mode 100644 index 00000000000..0ef0480992d --- /dev/null +++ b/annotations/com/intellij/codeInsight/annotations.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt index 13f1ffa4586..e75d61165c7 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt @@ -102,6 +102,8 @@ public object ShortenReferences { private fun process(elements: Iterable, elementFilter: (PsiElement) -> FilterResult) { for ((file, fileElements) in elements.groupBy { element -> element.getContainingJetFile() }) { + ImportInsertHelper.optimizeImportsIfNeeded(file) + // first resolve all qualified references - optimization val referenceToContext = JetFileReferencesResolver.resolve(file, fileElements, visitShortNames = false) @@ -348,6 +350,6 @@ public object ShortenReferences { //TODO: do we need this "IfNeeded" check? private fun addImportIfNeeded(descriptor: DeclarationDescriptor, file: JetFile) { - ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file) + ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file, false) } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java index 2c4fb190de5..66ea97590db 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java @@ -43,12 +43,21 @@ public class ImportInsertHelper { * * @param importFqn full name of the import * @param file File where directive should be added. + * @param optimize Optimize existing imports before adding new one. */ - public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file) { - addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file); + public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file, boolean optimize) { + addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file, optimize); } - public static void addImportDirectiveOrChangeToFqName(@NotNull FqName importFqn, @NotNull JetFile file, int refOffset, @NotNull PsiElement targetElement) { + public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file) { + addImportDirectiveIfNeeded(importFqn, file, true); + } + + public static void addImportDirectiveOrChangeToFqName( + @NotNull FqName importFqn, + @NotNull JetFile file, + int refOffset, + @NotNull PsiElement targetElement) { PsiReference reference = file.findReferenceAt(refOffset); if (reference instanceof JetReference) { PsiElement target = reference.resolve(); @@ -80,12 +89,12 @@ public class ImportInsertHelper { return; } } - addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file); + addImportDirectiveIfNeeded(importFqn, file); } - public static void addImportDirectiveIfNeeded(@NotNull ImportPath importPath, @NotNull JetFile file) { - if (CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) { - new OptimizeImportsProcessor(file.getProject(), file).runWithoutProgress(); + public static void addImportDirectiveIfNeeded(@NotNull ImportPath importPath, @NotNull JetFile file, boolean optimize) { + if (optimize) { + optimizeImportsIfNeeded(file); } if (!needImport(importPath, file)) { @@ -95,6 +104,16 @@ public class ImportInsertHelper { writeImportToFile(importPath, file); } + public static void optimizeImportsIfNeeded(JetFile file) { + if (CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) { + optimizeImports(file); + } + } + + public static void optimizeImports(JetFile file) { + new OptimizeImportsProcessor(file.getProject(), file).runWithoutProgress(); + } + public static void writeImportToFile(@NotNull ImportPath importPath, @NotNull JetFile file) { if (file instanceof JetCodeFragment) { JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath); @@ -105,6 +124,7 @@ public class ImportInsertHelper { JetImportList importList = file.getImportList(); if (importList != null) { JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath); + importList.add(JetPsiFactory.createNewLine(file.getProject())); importList.add(newDirective); } else { diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt new file mode 100644 index 00000000000..0d08370f9a1 --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.util.Date + +val x = java.sql.Date(1) diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after new file mode 100644 index 00000000000..0bce500e37a --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.sql.Date + +val x = Date(1) diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt new file mode 100644 index 00000000000..94bee0a3da3 --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.util.Date + +class A : java.sql.Date \ No newline at end of file diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after new file mode 100644 index 00000000000..baf93cfc2c9 --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.sql.Date + +class A : Date \ No newline at end of file diff --git a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt new file mode 100644 index 00000000000..7d2b6bb180f --- /dev/null +++ b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.io.* + +class A(val d: java.sql.Date, val rs: java.sql.ResultSet) diff --git a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after new file mode 100644 index 00000000000..e421fe4a1e0 --- /dev/null +++ b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after @@ -0,0 +1,5 @@ +// OPTIMIZE_IMPORTS +import java.sql.Date +import java.sql.ResultSet + +class A(val d: Date, val rs: ResultSet) diff --git a/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt b/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt index 214941370ee..e733742adef 100644 --- a/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt +++ b/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt @@ -17,59 +17,55 @@ package org.jetbrains.jet.shortenRefs import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase -import org.jetbrains.jet.InTextDirectivesUtils -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression -import org.jetbrains.jet.lang.psi.JetExpression -import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.lang.psi.JetFile -import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils -import org.jetbrains.jet.lang.resolve.name.FqName -import org.jetbrains.jet.plugin.project.TargetPlatform import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor -import org.jetbrains.jet.lang.resolve.name.Name -import com.intellij.util.containers.Predicate -import org.jetbrains.jet.lang.descriptors.ClassDescriptor -import com.intellij.openapi.application.Application import com.intellij.openapi.application.ApplicationManager -import org.jetbrains.jet.plugin.PluginTestCaseBase import java.io.File import com.intellij.openapi.command.CommandProcessor -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.jet.lang.psi.JetReferenceExpression -import com.intellij.psi.PsiElement import org.jetbrains.jet.plugin.codeInsight.ShortenReferences -import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.JetTestCaseBuilder +import com.intellij.codeInsight.CodeInsightSettings +import org.jetbrains.jet.InTextDirectivesUtils abstract class AbstractShortenRefsTest : LightCodeInsightFixtureTestCase() { override fun getTestDataPath() = JetTestCaseBuilder.getHomeDirectory() override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE protected fun doTest(testPath: String) { - val fixture = myFixture - val dependencyPath = testPath.replace(".kt", ".dependency.kt") - if (File(dependencyPath).exists()) { - fixture.configureByFile(dependencyPath) - } - val javaDependencyPath = testPath.replace(".kt", ".dependency.java") - if (File(javaDependencyPath).exists()) { - fixture.configureByFile(javaDependencyPath) - } + val codeInsightSettings = CodeInsightSettings.getInstance() + val optimizeImportsBefore = codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY - fixture.configureByFile(testPath) - - val file = fixture.getFile() as JetFile - val selectionModel = fixture.getEditor().getSelectionModel() - if (!selectionModel.hasSelection()) error("No selection in input file") - - CommandProcessor.getInstance().executeCommand(getProject(), { - ApplicationManager.getApplication()!!.runWriteAction { - ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) + try { + val fixture = myFixture + val dependencyPath = testPath.replace(".kt", ".dependency.kt") + if (File(dependencyPath).exists()) { + fixture.configureByFile(dependencyPath) + } + val javaDependencyPath = testPath.replace(".kt", ".dependency.java") + if (File(javaDependencyPath).exists()) { + fixture.configureByFile(javaDependencyPath) } - }, null, null) - selectionModel.removeSelection() - fixture.checkResultByFile(testPath + ".after") + fixture.configureByFile(testPath) + + val file = fixture.getFile() as JetFile + val selectionModel = fixture.getEditor().getSelectionModel() + if (!selectionModel.hasSelection()) error("No selection in input file") + + codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = + InTextDirectivesUtils.isDirectiveDefined(file.getText(), "// OPTIMIZE_IMPORTS") + + CommandProcessor.getInstance().executeCommand(getProject(), { + ApplicationManager.getApplication()!!.runWriteAction { + ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) + } + }, null, null) + selectionModel.removeSelection() + + fixture.checkResultByFile(testPath + ".after") + } + finally { + codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = optimizeImportsBefore + } } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java b/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java index b7af568ad50..03e71a462e5 100644 --- a/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.shortenRefs.AbstractShortenRefsTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("idea/testData/shortenRefs") -@InnerTestClasses({ShortenRefsTestGenerated.Constructor.class, ShortenRefsTestGenerated.Java.class, ShortenRefsTestGenerated.Type.class}) +@InnerTestClasses({ShortenRefsTestGenerated.Constructor.class, ShortenRefsTestGenerated.Imports.class, ShortenRefsTestGenerated.Java.class, ShortenRefsTestGenerated.Type.class}) public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { public void testAllFilesPresentInShortenRefs() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/shortenRefs"), Pattern.compile("^([^\\.]+)\\.kt$"), true); @@ -130,6 +130,29 @@ public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { } + @TestMetadata("idea/testData/shortenRefs/imports") + public static class Imports extends AbstractShortenRefsTest { + public void testAllFilesPresentInImports() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/shortenRefs/imports"), Pattern.compile("^([^\\.]+)\\.kt$"), true); + } + + @TestMetadata("leaveQualifiedConstructor.kt") + public void testLeaveQualifiedConstructor() throws Exception { + doTest("idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt"); + } + + @TestMetadata("leaveQualifiedType.kt") + public void testLeaveQualifiedType() throws Exception { + doTest("idea/testData/shortenRefs/imports/leaveQualifiedType.kt"); + } + + @TestMetadata("optimizeMultipleImports.kt") + public void testOptimizeMultipleImports() throws Exception { + doTest("idea/testData/shortenRefs/imports/optimizeMultipleImports.kt"); + } + + } + @TestMetadata("idea/testData/shortenRefs/java") public static class Java extends AbstractShortenRefsTest { public void testAllFilesPresentInJava() throws Exception { @@ -275,6 +298,7 @@ public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { TestSuite suite = new TestSuite("ShortenRefsTestGenerated"); suite.addTestSuite(ShortenRefsTestGenerated.class); suite.addTestSuite(Constructor.class); + suite.addTestSuite(Imports.class); suite.addTestSuite(Java.class); suite.addTestSuite(Type.class); return suite; From 6bc3772d29989d20848ff917978cbbd2d1752e38 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:56 +0400 Subject: [PATCH 039/143] Override/Implement: Add test to cover import optimization in the case of multiple import insertion (see #KT-4732) --- .../checkNotImportedTypesFromJava/bar/Bar.java | 5 +++++ .../checkNotImportedTypesFromJava/bar/Other.java | 5 +++++ .../checkNotImportedTypesFromJava/foo/Foo.java | 9 +++++++++ .../checkNotImportedTypesFromJava/foo/Impl.kt | 7 +++++++ .../foo/Impl.kt.after | 14 ++++++++++++++ .../plugin/codeInsight/OverrideImplementTest.java | 12 ++++++++++++ 6 files changed, 52 insertions(+) create mode 100644 idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Bar.java create mode 100644 idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Other.java create mode 100644 idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Foo.java create mode 100644 idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt create mode 100644 idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt.after diff --git a/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Bar.java b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Bar.java new file mode 100644 index 00000000000..44d04659de6 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Bar.java @@ -0,0 +1,5 @@ +package bar; + +public interface Bar { + +} diff --git a/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Other.java b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Other.java new file mode 100644 index 00000000000..4cc642287e9 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/bar/Other.java @@ -0,0 +1,5 @@ +package bar; + +public interface Other { + +} diff --git a/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Foo.java b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Foo.java new file mode 100644 index 00000000000..42b96fd46d6 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Foo.java @@ -0,0 +1,9 @@ +package foo; + +import bar.Bar; +import bar.Other; +import java.util.ArrayList; + +public class Foo { + abstract public Bar foo(ArrayList list, Other other); +} diff --git a/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt new file mode 100644 index 00000000000..7e84873434b --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt @@ -0,0 +1,7 @@ +package foo + +class Impl: Foo() { + +} + +// KT-4732 Override/Implement action does not add all imports when "Optimize imports on the fly" is enabled diff --git a/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt.after b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt.after new file mode 100644 index 00000000000..d97d2fb4a0f --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/checkNotImportedTypesFromJava/foo/Impl.kt.after @@ -0,0 +1,14 @@ +package foo + +import java.util.ArrayList +import bar.Other +import bar.Bar + +class Impl: Foo() { + + override fun foo(list: ArrayList?, other: Other?): Bar? { + throw UnsupportedOperationException() + } +} + +// KT-4732 Override/Implement action does not add all imports when "Optimize imports on the fly" is enabled diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java index ff051f8b675..418f1711ae3 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.plugin.codeInsight; +import com.intellij.codeInsight.CodeInsightSettings; import org.jetbrains.jet.plugin.PluginTestCaseBase; public final class OverrideImplementTest extends AbstractOverrideImplementTest { @@ -146,6 +147,17 @@ public final class OverrideImplementTest extends AbstractOverrideImplementTest { doImplementDirectoryTest(); } + public void testCheckNotImportedTypesFromJava() { + boolean oldValue = CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY; + try { + CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY = true; + doImplementDirectoryTest(); + } + finally { + CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY = oldValue; + } + } + public void testOverrideSamAdapters() { doOverrideDirectoryTest("foo"); } From c7d8ab8219cca0ff430eac0858ca3b00f9927f54 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:48 +0400 Subject: [PATCH 040/143] Extract Function: Add support of property-as-function calls #KT-5179 Fixed --- .../refactoring/extractFunction/ExtractionData.kt | 5 ++++- .../extractFunction/extractFunctionUtils.kt | 13 ++++--------- .../parameters/misc/variableAsFunction.kt | 9 +++++++++ .../parameters/misc/variableAsFunction.kt.after | 13 +++++++++++++ .../JetExtractionTestGenerated.java | 5 +++++ 5 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt index c98a1cc68bd..4f8681f7cc9 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt @@ -45,6 +45,7 @@ import org.jetbrains.jet.lang.psi.psiUtil.getParentByType import org.jetbrains.jet.lang.psi.JetDeclaration import org.jetbrains.jet.lang.psi.JetDeclarationWithBody import org.jetbrains.jet.lang.psi.JetUserType +import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall data class ExtractionOptions(val inferUnitTypeForUnusedValues: Boolean) { class object { @@ -102,7 +103,9 @@ class ExtractionData( if (ref !is JetSimpleNameExpression) continue val resolvedCallKey = (ref.getParent() as? JetThisExpression) ?: ref - val resolvedCall = context[BindingContext.RESOLVED_CALL, resolvedCallKey] + val resolvedCall = context[BindingContext.RESOLVED_CALL, resolvedCallKey]?.let { + (it as? VariableAsFunctionResolvedCall)?.functionCall ?: it + } val descriptor = context[BindingContext.REFERENCE_TARGET, ref] if (descriptor == null) continue diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index eac0647d964..199d01c6713 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -379,15 +379,10 @@ private fun ExtractionData.inferParametersInfo( val extractParameter = extractThis || extractLocalVar if (extractParameter) { - val parameterType = - if (hasThisReceiver) { - when (descriptorToExtract) { - is ClassDescriptor -> descriptorToExtract.getDefaultType() - is CallableDescriptor -> descriptorToExtract.getReceiverParameter()?.getType() - else -> null - } ?: DEFAULT_PARAMETER_TYPE - } - else bindingContext[BindingContext.EXPRESSION_TYPE, originalRef] ?: DEFAULT_PARAMETER_TYPE + val parameterType = when { + receiver.exists() -> receiver.getType() + else -> bindingContext[BindingContext.EXPRESSION_TYPE, originalRef] ?: DEFAULT_PARAMETER_TYPE + } if (!parameterType.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes)) continue diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt b/idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt new file mode 100644 index 00000000000..c2f7f75c3b8 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt @@ -0,0 +1,9 @@ +// PARAM_TYPES: A +class A { + fun invoke() = 20 +} +// SIBLING: +fun testProp() { + val foo = A() + foo() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt.after b/idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt.after new file mode 100644 index 00000000000..565522f7989 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt.after @@ -0,0 +1,13 @@ +// PARAM_TYPES: A +class A { + fun invoke() = 20 +} +// SIBLING: +fun testProp() { + val foo = A() + unit(foo) +} + +fun unit(foo: A) { + foo() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index a867122af38..8678c9e7db2 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -794,6 +794,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt"); } + @TestMetadata("variableAsFunction.kt") + public void testVariableAsFunction() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/misc/variableAsFunction.kt"); + } + } @TestMetadata("idea/testData/refactoring/extractFunction/parameters/nonDenotableTypes") From 14362134bdc0cbde4d7208bc6862ea9ce17d2abe Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 20 Jun 2014 17:29:54 +0400 Subject: [PATCH 041/143] Extract Function: Traverse nested pseudocode instructions #KT-5178 Fixed --- .../extractFunction/extractFunctionUtils.kt | 102 +++++++++++------- .../valueUsedInAnonymousObject.kt | 11 ++ .../valueUsedInAnonymousObject.kt.conflicts | 1 + .../unextractable/valueUsedInLambda.kt | 9 ++ .../valueUsedInLambda.kt.conflicts | 1 + .../unextractable/valueUsedInLocalFunction.kt | 5 + .../valueUsedInLocalFunction.kt.conflicts | 1 + .../JetExtractionTestGenerated.java | 15 +++ 8 files changed, 104 insertions(+), 41 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt.conflicts create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt.conflicts create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt.conflicts diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index 199d01c6713..af8d682135b 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -67,7 +67,10 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.ReadValueInstruct import org.jetbrains.jet.lang.cfg.pseudocode.instructions.* import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.* import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.* -import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.getNextInstructions +import kotlin.properties.Delegates +import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.traverse +import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder +import org.jetbrains.jet.lang.resolve.bindingContextUtil.getTargetFunctionDescriptor private val DEFAULT_FUNCTION_NAME = "myFun" private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType() @@ -84,7 +87,10 @@ private fun List.getModifiedVarDescriptors(bindingContext: BindingC private fun List.getExitPoints(): List = filter { localInstruction -> localInstruction.nextInstructions.any { it !in this } } -private fun List.getResultType(bindingContext: BindingContext, options: ExtractionOptions): JetType { +private fun List.getResultType( + pseudocode: Pseudocode, + bindingContext: BindingContext, + options: ExtractionOptions): JetType { fun instructionToType(instruction: Instruction): JetType? { val expression = when (instruction) { is ReturnValueInstruction -> { @@ -101,10 +107,7 @@ private fun List.getResultType(bindingContext: BindingContext, opti } if (expression == null) return null - if (options.inferUnitTypeForUnusedValues) { - val pseudocode = firstOrNull()?.owner - if (pseudocode != null && expression.isStatement(pseudocode)) return null - } + if (options.inferUnitTypeForUnusedValues && expression.isStatement(pseudocode)) return null return bindingContext[BindingContext.EXPRESSION_TYPE, expression] } @@ -123,10 +126,17 @@ private fun JetType.isMeaningful(): Boolean { } private fun List.analyzeControlFlow( + pseudocode: Pseudocode, bindingContext: BindingContext, options: ExtractionOptions, parameters: Set ): Pair { + fun isCurrentFunctionReturn(expression: JetReturnExpression): Boolean { + val functionDescriptor = expression.getTargetFunctionDescriptor(bindingContext) + val function = functionDescriptor?.let { BindingContextUtils.descriptorToDeclaration(bindingContext, it) } + return function == pseudocode.getCorrespondingElement() + } + val exitPoints = getExitPoints() val valuedReturnExits = ArrayList() @@ -135,19 +145,26 @@ private fun List.analyzeControlFlow( exitPoints.forEach { val e = (it as? UnconditionalJumpInstruction)?.element val insn = - if (e != null && e !is JetBreakExpression && e !is JetContinueExpression) { - it.previousInstructions.firstOrNull() + when { + it !is ReturnValueInstruction && it !is ReturnNoValueInstruction && it.owner != pseudocode -> + null + e != null && e !is JetBreakExpression && e !is JetContinueExpression -> + it.previousInstructions.firstOrNull() + else -> + it } - else it when (insn) { - is ReturnValueInstruction -> valuedReturnExits.add(insn) + is ReturnValueInstruction -> + if (isCurrentFunctionReturn(insn.element as JetReturnExpression)) { + valuedReturnExits.add(insn) + } is AbstractJumpInstruction -> { val element = insn.element - if (element is JetReturnExpression - || element is JetBreakExpression - || element is JetContinueExpression) { + if ((element is JetReturnExpression && isCurrentFunctionReturn(element)) + || element is JetBreakExpression + || element is JetContinueExpression) { jumpExits.add(insn) } else if (element !is JetThrowExpression) { @@ -161,8 +178,8 @@ private fun List.analyzeControlFlow( } } - val typeOfDefaultFlow = defaultExits.getResultType(bindingContext, options) - val returnValueType = valuedReturnExits.getResultType(bindingContext, options) + val typeOfDefaultFlow = defaultExits.getResultType(pseudocode, bindingContext, options) + val returnValueType = valuedReturnExits.getResultType(pseudocode, bindingContext, options) val defaultControlFlow = DefaultControlFlow(if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow) val outParameters = parameters.filterTo(HashSet()) { it.mirrorVarName != null } @@ -204,7 +221,7 @@ private fun List.analyzeControlFlow( } if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError - return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(bindingContext, options)), null) + return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(pseudocode, bindingContext, options)), null) } if (jumpExits.isNotEmpty()) { @@ -307,15 +324,13 @@ private fun JetType.processTypeIfExtractable( } } -private fun ExtractionData.inferParametersInfo( - commonParent: PsiElement, - localInstructions: List, - bindingContext: BindingContext, - replacementMap: MutableMap, - parameters: MutableSet, - typeParameters: MutableSet, - nonDenotableTypes: MutableSet -): ErrorMessage? { +private fun ExtractionData.inferParametersInfo(commonParent: PsiElement, + localInstructions: List, + bindingContext: BindingContext, + replacementMap: MutableMap, + parameters: MutableSet, + typeParameters: MutableSet, + nonDenotableTypes: MutableSet): ErrorMessage? { val varNameValidator = JetNameValidatorImpl( commonParent.getParentByType(javaClass()), originalElements.first, @@ -446,20 +461,19 @@ private fun ExtractionData.inferParametersInfo( } private fun ExtractionData.checkLocalDeclarationsWithNonLocalUsages( - allInstructions: List, localInstructions: List, bindingContext: BindingContext ): ErrorMessage? { // todo: non-locally used declaration can be turned into the output value val declarations = ArrayList() - for (instruction in allInstructions) { - if (instruction in localInstructions) continue - - PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.let { descriptor -> - val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor, bindingContext) - if (declaration is JetNamedDeclaration && declaration.isInsideOf(originalElements)) { - declarations.add(declaration) + localInstructions.firstOrNull()?.owner?.traverse(TraversalOrder.FORWARD) { instruction -> + if (instruction !in localInstructions) { + PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.let { descriptor -> + val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor, bindingContext) + if (declaration is JetNamedDeclaration && declaration.isInsideOf(originalElements)) { + declarations.add(declaration) + } } } } @@ -495,6 +509,16 @@ private fun ExtractionData.checkDeclarationsMovingOutOfScope(controlFlow: Contro return null } +private fun ExtractionData.getLocalInstructions(pseudocode: Pseudocode): List { + val instructions = ArrayList() + pseudocode.traverse(TraversalOrder.FORWARD) { + if (it is JetElementInstruction && it.element.isInsideOf(originalElements)) { + instructions.add(it) + } + } + return instructions +} + fun ExtractionData.performAnalysis(): AnalysisResult { if (originalElements.empty) { return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(ErrorMessage.NO_EXPRESSION)) @@ -511,24 +535,20 @@ fun ExtractionData.performAnalysis(): AnalysisResult { val bindingContext = resolveSession.resolveToElement(enclosingDeclaration.getBodyExpression()) val pseudocode = PseudocodeUtil.generatePseudocode(enclosingDeclaration, bindingContext) - val localInstructions = pseudocode.getInstructions().filter { - it is JetElementInstruction && it.element.isInsideOf(originalElements) - } + val localInstructions = getLocalInstructions(pseudocode) val replacementMap = HashMap() val parameters = HashSet() val typeParameters = HashSet() val nonDenotableTypes = HashSet() - val parameterError = inferParametersInfo( - commonParent, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes - ) + val parameterError = inferParametersInfo(commonParent, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes) if (parameterError != null) { return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(parameterError)) } val messages = ArrayList() - val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(bindingContext, options, parameters) + val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(pseudocode, bindingContext, options, parameters) controlFlowMessage?.let { messages.add(it) } controlFlow.returnType.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes) @@ -542,7 +562,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult { ) } - checkLocalDeclarationsWithNonLocalUsages(pseudocode.getInstructions(), localInstructions, bindingContext)?.let { messages.add(it) } + checkLocalDeclarationsWithNonLocalUsages(localInstructions, bindingContext)?.let { messages.add(it) } checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) } val functionNameValidator = diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt new file mode 100644 index 00000000000..b061ff68f50 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt @@ -0,0 +1,11 @@ +// SIBLING: +fun main(args: Array) { + val a = 1 + val t = object: T { + override fun foo(n: Int) = n + a + } +} + +trait T { + fun foo(n: Int): Int +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt.conflicts new file mode 100644 index 00000000000..87517ea9e65 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt.conflicts @@ -0,0 +1 @@ +Following variables are used outside of selected code fragment: a \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt new file mode 100644 index 00000000000..f0f0342ec3a --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt @@ -0,0 +1,9 @@ +// SIBLING: +fun main(args: Array) { + val a = 1 + lambda { + a + } +} + +fun lambda(f: () -> Unit) {} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt.conflicts new file mode 100644 index 00000000000..87517ea9e65 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt.conflicts @@ -0,0 +1 @@ +Following variables are used outside of selected code fragment: a \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt new file mode 100644 index 00000000000..c0461c825ad --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt @@ -0,0 +1,5 @@ +// SIBLING: +fun main(args: Array) { + val a = 1 + fun foo() = a +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt.conflicts new file mode 100644 index 00000000000..87517ea9e65 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt.conflicts @@ -0,0 +1 @@ +Following variables are used outside of selected code fragment: a \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index 8678c9e7db2..755411bfb9c 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -576,6 +576,21 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithReturn.kt"); } + @TestMetadata("valueUsedInAnonymousObject.kt") + public void testValueUsedInAnonymousObject() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt"); + } + + @TestMetadata("valueUsedInLambda.kt") + public void testValueUsedInLambda() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt"); + } + + @TestMetadata("valueUsedInLocalFunction.kt") + public void testValueUsedInLocalFunction() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.kt"); + } + @TestMetadata("variablesOutOfScope.kt") public void testVariablesOutOfScope() throws Exception { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt"); From a3f215fb34d0c758e5283bebdfc6eeb64bd239d1 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:52 +0400 Subject: [PATCH 042/143] Extract Function: Support extraction of "it" parameter from lambdas --- .../extractFunction/ExtractionData.kt | 16 +++++++++- .../extractFunction/extractFunctionUtils.kt | 9 +++--- .../extractFunction/parameters/it/innerIt.kt | 9 ++++++ .../parameters/it/innerIt.kt.after | 13 ++++++++ .../parameters/it/lambdaWithIt.kt | 9 ++++++ .../parameters/it/lambdaWithIt.kt.after | 13 ++++++++ .../extractFunction/parameters/it/outerIt.kt | 9 ++++++ .../parameters/it/outerIt.kt.after | 13 ++++++++ .../extractFunction/parameters/it/simpleIt.kt | 9 ++++++ .../parameters/it/simpleIt.kt.after | 13 ++++++++ .../JetExtractionTestGenerated.java | 31 ++++++++++++++++++- 11 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt index 4f8681f7cc9..a077d119d24 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt @@ -46,6 +46,11 @@ import org.jetbrains.jet.lang.psi.JetDeclaration import org.jetbrains.jet.lang.psi.JetDeclarationWithBody import org.jetbrains.jet.lang.psi.JetUserType import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall +import org.jetbrains.jet.lang.psi.JetParameter +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor +import org.jetbrains.jet.lang.psi.JetPsiFactory +import org.jetbrains.jet.lang.resolve.BindingContextUtils +import org.jetbrains.jet.lang.psi.JetFunctionLiteral data class ExtractionOptions(val inferUnitTypeForUnusedValues: Boolean) { class object { @@ -96,9 +101,18 @@ class ExtractionData( val originalStartOffset = originalElements.first?.let { e -> e.getTextRange()!!.getStartOffset() } + private val itFakeDeclaration by Delegates.lazy { JetPsiFactory.createParameter(project, "it", null) } + val refOffsetToDeclaration by Delegates.lazy { + fun isExtractableIt(descriptor: DeclarationDescriptor, context: BindingContext): Boolean { + if (!(descriptor is ValueParameterDescriptor && (context[BindingContext.AUTO_CREATED_IT, descriptor] ?: false))) return false + val function = BindingContextUtils.descriptorToDeclaration(context, descriptor.getContainingDeclaration()) as? JetFunctionLiteral + return function == null || !function.isInsideOf(originalElements) + } + if (originalStartOffset != null) { val resultMap = HashMap() + for ((ref, context) in JetFileReferencesResolver.resolve(originalFile, getExpressions())) { if (ref !is JetSimpleNameExpression) continue @@ -111,7 +125,7 @@ class ExtractionData( if (descriptor == null) continue val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor, context) as? PsiNamedElement - if (declaration == null) continue + ?: if (isExtractableIt(descriptor, context)) itFakeDeclaration else continue val offset = ref.getTextRange()!!.getStartOffset() - originalStartOffset resultMap[offset] = ResolveResult(ref, declaration, descriptor, resolvedCall) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index af8d682135b..c7e2042d439 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -133,8 +133,8 @@ private fun List.analyzeControlFlow( ): Pair { fun isCurrentFunctionReturn(expression: JetReturnExpression): Boolean { val functionDescriptor = expression.getTargetFunctionDescriptor(bindingContext) - val function = functionDescriptor?.let { BindingContextUtils.descriptorToDeclaration(bindingContext, it) } - return function == pseudocode.getCorrespondingElement() + val currentDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, pseudocode.getCorrespondingElement()] + return currentDescriptor == functionDescriptor } val exitPoints = getExitPoints() @@ -461,13 +461,14 @@ private fun ExtractionData.inferParametersInfo(commonParent: PsiElement, } private fun ExtractionData.checkLocalDeclarationsWithNonLocalUsages( + pseudocode: Pseudocode, localInstructions: List, bindingContext: BindingContext ): ErrorMessage? { // todo: non-locally used declaration can be turned into the output value val declarations = ArrayList() - localInstructions.firstOrNull()?.owner?.traverse(TraversalOrder.FORWARD) { instruction -> + pseudocode.traverse(TraversalOrder.FORWARD) { instruction -> if (instruction !in localInstructions) { PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.let { descriptor -> val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor, bindingContext) @@ -562,7 +563,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult { ) } - checkLocalDeclarationsWithNonLocalUsages(localInstructions, bindingContext)?.let { messages.add(it) } + checkLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext)?.let { messages.add(it) } checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) } val functionNameValidator = diff --git a/idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt b/idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt new file mode 100644 index 00000000000..a78c1a188cc --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt @@ -0,0 +1,9 @@ +// PARAM_TYPES: kotlin.Int +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array>) { + if (t.check { it.check{ it + 1 > 1 } }) { + println("OK") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt.after b/idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt.after new file mode 100644 index 00000000000..68d4a5e2af0 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt.after @@ -0,0 +1,13 @@ +// PARAM_TYPES: kotlin.Int +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array>) { + if (t.check { it.check{ i(it) > 1 } }) { + println("OK") + } +} + +fun i(it: Int): Int { + return it + 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt b/idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt new file mode 100644 index 00000000000..5e2a55eec06 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt @@ -0,0 +1,9 @@ +// PARAM_TYPES: kotlin.Array +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + if (t.check { it + 1 > 1 }) { + println("OK") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt.after b/idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt.after new file mode 100644 index 00000000000..6aa70ab366d --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt.after @@ -0,0 +1,13 @@ +// PARAM_TYPES: kotlin.Array +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + if (b(t)) { + println("OK") + } +} + +fun b(t: Array): Boolean { + return t.check { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt b/idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt new file mode 100644 index 00000000000..2022e6452c0 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt @@ -0,0 +1,9 @@ +// PARAM_TYPES: kotlin.Array +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array>) { + if (t.check { it.check{ it + 1 > 1 } }) { + println("OK") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt.after b/idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt.after new file mode 100644 index 00000000000..f5c2eaa5e1b --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt.after @@ -0,0 +1,13 @@ +// PARAM_TYPES: kotlin.Array +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array>) { + if (t.check { b(it) }) { + println("OK") + } +} + +fun b(it: Array): Boolean { + return it.check { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt b/idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt new file mode 100644 index 00000000000..a81b51a5574 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt @@ -0,0 +1,9 @@ +// PARAM_TYPES: kotlin.Int +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + if (t.check { it + 1 > 1 }) { + println("OK") + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt.after b/idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt.after new file mode 100644 index 00000000000..bcdc0a3349a --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt.after @@ -0,0 +1,13 @@ +// PARAM_TYPES: kotlin.Int +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + if (t.check { i(it) > 1 }) { + println("OK") + } +} + +fun i(it: Int): Int { + return it + 1 +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index 755411bfb9c..747ff5bb6ec 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -651,7 +651,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { } @TestMetadata("idea/testData/refactoring/extractFunction/parameters") - @InnerTestClasses({Parameters.ExtractSuper.class, Parameters.ExtractThis.class, Parameters.Misc.class, Parameters.NonDenotableTypes.class}) + @InnerTestClasses({Parameters.ExtractSuper.class, Parameters.ExtractThis.class, Parameters.It.class, Parameters.Misc.class, Parameters.NonDenotableTypes.class}) public static class Parameters extends AbstractJetExtractionTest { public void testAllFilesPresentInParameters() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/parameters"), Pattern.compile("^(.+)\\.kt$"), true); @@ -728,6 +728,34 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { } + @TestMetadata("idea/testData/refactoring/extractFunction/parameters/it") + public static class It extends AbstractJetExtractionTest { + public void testAllFilesPresentInIt() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/parameters/it"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("innerIt.kt") + public void testInnerIt() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/it/innerIt.kt"); + } + + @TestMetadata("lambdaWithIt.kt") + public void testLambdaWithIt() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/it/lambdaWithIt.kt"); + } + + @TestMetadata("outerIt.kt") + public void testOuterIt() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/it/outerIt.kt"); + } + + @TestMetadata("simpleIt.kt") + public void testSimpleIt() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/it/simpleIt.kt"); + } + + } + @TestMetadata("idea/testData/refactoring/extractFunction/parameters/misc") public static class Misc extends AbstractJetExtractionTest { public void testAllFilesPresentInMisc() throws Exception { @@ -839,6 +867,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { suite.addTestSuite(Parameters.class); suite.addTestSuite(ExtractSuper.class); suite.addTestSuite(ExtractThis.class); + suite.addTestSuite(It.class); suite.addTestSuite(Misc.class); suite.addTestSuite(NonDenotableTypes.class); return suite; From e5ce5b7127ca96db3d0e49ba2fdded8eb9e99c74 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:57 +0400 Subject: [PATCH 043/143] Extract Function: Fix call replacement for the case of lambda extraction --- .../extractFunction/extractFunctionUtils.kt | 24 ++++++++++++++++++- .../trailingLambdaEmptyArgList.kt | 6 +++++ .../trailingLambdaEmptyArgList.kt.after | 10 ++++++++ .../trailingLambdaNoArgList.kt | 6 +++++ .../trailingLambdaNoArgList.kt.after | 10 ++++++++ .../trailingLambdaNonEmptyArgList.kt | 6 +++++ .../trailingLambdaNonEmptyArgList.kt.after | 10 ++++++++ .../JetExtractionTestGenerated.java | 15 ++++++++++++ 8 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index c7e2042d439..2508fd05c12 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -71,6 +71,7 @@ import kotlin.properties.Delegates import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.traverse import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder import org.jetbrains.jet.lang.resolve.bindingContextUtil.getTargetFunctionDescriptor +import com.intellij.psi.PsiWhiteSpace private val DEFAULT_FUNCTION_NAME = "myFun" private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType() @@ -811,6 +812,27 @@ fun ExtractionDescriptor.generateFunction( } } + fun insertCall(anchor: PsiElement, wrappedCall: JetExpression) { + val firstExpression = extractionData.getExpressions().firstOrNull() + val enclosingCall = firstExpression?.getParent() as? JetCallExpression + if (enclosingCall == null || firstExpression !in enclosingCall.getFunctionLiteralArguments()) { + anchor.replace(wrappedCall) + return + } + + val argumentListExt = JetPsiFactory.createCallArguments(project, "(${wrappedCall.getText()})") + val argumentList = enclosingCall.getValueArgumentList() + if (argumentList == null) { + (anchor.getPrevSibling() as? PsiWhiteSpace)?.let { it.delete() } + anchor.replace(argumentListExt) + return + } + + val newArgText = (argumentList.getArguments() + argumentListExt.getArguments()).map { it.getText() }.joinToString(", ", "(", ")") + argumentList.replace(JetPsiFactory.createCallArguments(project, newArgText)) + anchor.delete() + } + fun makeCall(function: JetNamedFunction): JetNamedFunction { val anchor = extractionData.originalElements.first if (anchor == null) return function @@ -849,7 +871,7 @@ fun ExtractionDescriptor.generateFunction( else -> JetPsiFactory.createExpression(project, callText) } - anchor.replace(wrappedCall) + insertCall(anchor, wrappedCall) return function } diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt new file mode 100644 index 00000000000..12fb1251f33 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt @@ -0,0 +1,6 @@ +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + t.check() { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt.after new file mode 100644 index 00000000000..c21ead68b75 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt.after @@ -0,0 +1,10 @@ +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + t.check(function()) +} + +fun function(): (Int) -> Boolean { + return { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt new file mode 100644 index 00000000000..8abdecfdd41 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt @@ -0,0 +1,6 @@ +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + t.check { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt.after new file mode 100644 index 00000000000..c21ead68b75 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt.after @@ -0,0 +1,10 @@ +fun Array.check(f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + t.check(function()) +} + +fun function(): (Int) -> Boolean { + return { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt new file mode 100644 index 00000000000..be50018ca90 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt @@ -0,0 +1,6 @@ +fun Array.check(a: Int, b: Int f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + t.check(1, 2) { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt.after new file mode 100644 index 00000000000..567ab21da22 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt.after @@ -0,0 +1,10 @@ +fun Array.check(a: Int, b: Int f: (T) -> Boolean): Boolean = false + +// SIBLING: +fun foo(t: Array) { + t.check(1, 2, function()) +} + +fun function(): (Int) -> Boolean { + return { it + 1 > 1 } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index 747ff5bb6ec..4e8097718c9 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -447,6 +447,21 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt"); } + @TestMetadata("trailingLambdaEmptyArgList.kt") + public void testTrailingLambdaEmptyArgList() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaEmptyArgList.kt"); + } + + @TestMetadata("trailingLambdaNoArgList.kt") + public void testTrailingLambdaNoArgList() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNoArgList.kt"); + } + + @TestMetadata("trailingLambdaNonEmptyArgList.kt") + public void testTrailingLambdaNonEmptyArgList() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/trailingLambdaNonEmptyArgList.kt"); + } + } @TestMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues") From 96557e6d3f74456a6717e92ef0967f303234953b Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 23 Jun 2014 19:26:41 +0400 Subject: [PATCH 044/143] DFS: Terminate traversal if node handler returns false --- .../jet/lang/resolve/OverridingUtil.java | 32 +++++++++++++++++++ .../jet/lang/types/DescriptorSubstitutor.java | 4 ++- .../jetbrains/jet/lang/types/TypeUtils.java | 4 ++- .../src/org/jetbrains/jet/utils/DFS.java | 14 ++++---- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 578d071ffed..f5e744d2da5 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -540,6 +540,38 @@ public class OverridingUtil { ); } + public static boolean traverseOverridenDescriptors( + @NotNull CallableDescriptor originalDescriptor, + @NotNull final Function1 handler + ) { + return DFS.dfs( + Collections.singletonList(originalDescriptor), + new DFS.Neighbors() { + @NotNull + @Override + public Iterable getNeighbors(CallableDescriptor current) { + return current.getOverriddenDescriptors(); + } + }, + new DFS.AbstractNodeHandler() { + private boolean result = true; + + @Override + public boolean beforeChildren(CallableDescriptor current) { + if (!handler.invoke(current)) { + result = false; + } + return result; + } + + @Override + public Boolean result() { + return result; + } + } + ); + } + public interface DescriptorSink { void addToScope(@NotNull CallableMemberDescriptor fakeOverride); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java b/core/descriptors/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java index 1d456a61807..3615141469b 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java @@ -147,13 +147,15 @@ public class DescriptorSubstitutor { }, new DFS.NodeHandlerWithListResult() { @Override - public void beforeChildren(JetType current) { + public boolean beforeChildren(JetType current) { ClassifierDescriptor declarationDescriptor = current.getConstructor().getDeclarationDescriptor(); // typeParameters in a list, but it contains very few elements, so it's fine to call contains() on it //noinspection SuspiciousMethodCalls if (typeParameters.contains(declarationDescriptor)) { result.add((TypeParameterDescriptor) declarationDescriptor); } + + return true; } } ); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java index 47a5f1fcbe8..3b81f28f08b 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -634,7 +634,7 @@ public class TypeUtils { }, new DFS.NodeHandlerWithListResult() { @Override - public void beforeChildren(JetType current) { + public boolean beforeChildren(JetType current) { TypeConstructor constructor = current.getConstructor(); Set instances = constructorToAllInstances.get(constructor); @@ -643,6 +643,8 @@ public class TypeUtils { constructorToAllInstances.put(constructor, instances); } instances.add(current); + + return true; } @Override diff --git a/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java b/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java index ca9103af9ff..17e738c75a0 100644 --- a/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java +++ b/core/util.runtime/src/org/jetbrains/jet/utils/DFS.java @@ -68,10 +68,9 @@ public class DFS { } private static void doDfs(@NotNull N current, @NotNull Neighbors neighbors, @NotNull Visited visited, @NotNull NodeHandler handler) { - if (!visited.checkAndMarkVisited(current)) { - return; - } - handler.beforeChildren(current); + if (!visited.checkAndMarkVisited(current)) return; + if (!handler.beforeChildren(current)) return; + for (N neighbor : neighbors.getNeighbors(current)) { doDfs(neighbor, neighbors, visited, handler); } @@ -79,8 +78,8 @@ public class DFS { } public interface NodeHandler { - @KotlinSignature("fun beforeChildren(current: N): Unit") - void beforeChildren(N current); + @KotlinSignature("fun beforeChildren(current: N): Boolean") + boolean beforeChildren(N current); @KotlinSignature("fun afterChildren(current: N): Unit") void afterChildren(N current); @@ -100,7 +99,8 @@ public class DFS { public static abstract class AbstractNodeHandler implements NodeHandler { @Override - public void beforeChildren(N current) { + public boolean beforeChildren(N current) { + return true; } @Override From ca16f4231f749286fcf2b0f56e31531ea206e65c Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 20 Jun 2014 17:33:57 +0400 Subject: [PATCH 045/143] Extract Function: Infer parameter type candidates #KT-4940 Fixed --- .../jetbrains/jet/lang/types/TypeUtils.java | 6 +- .../ExtractKotlinFunctionHandler.kt | 5 +- .../extractFunction/ExtractionDescriptor.kt | 18 ++- .../extractFunction/extractFunctionUtils.kt | 147 +++++++++++------- .../ui/KotlinParameterTablePanel.java | 10 +- .../basic/fragmentWithComment.kt | 1 + .../basic/fragmentWithComment.kt.after | 1 + .../basic/fragmentWithMultilineComment.kt | 1 + .../fragmentWithMultilineComment.kt.after | 1 + .../extractFunction/basic/refInReturn.kt | 1 + .../basic/refInReturn.kt.after | 1 + .../conditionalBreakWithIf.kt | 2 + .../conditionalBreakWithIf.kt.after | 2 + .../conditionalBreakWithIfElse.kt | 2 + .../conditionalBreakWithIfElse.kt.after | 2 + .../conditionalBreakWithWhen.kt | 2 + .../conditionalBreakWithWhen.kt.after | 2 + .../conditionalReturnWithIf.kt | 2 + .../conditionalReturnWithIf.kt.after | 2 + .../conditionalReturnWithIfElse.kt | 2 + .../conditionalReturnWithIfElse.kt.after | 2 + .../conditionalReturnWithWhen.kt | 2 + .../conditionalReturnWithWhen.kt.after | 2 + .../unconditionalBreakWithIf.kt | 2 + .../unconditionalBreakWithIf.kt.after | 2 + .../unconditionalBreakWithIfElse.kt | 2 + .../unconditionalBreakWithIfElse.kt.after | 2 + .../unconditionalBreakWithWhen.kt | 2 + .../unconditionalBreakWithWhen.kt.after | 2 + .../controlFlow/default/defaultCF.kt | 2 + .../controlFlow/default/defaultCF.kt.after | 2 + .../controlFlow/default/defaultCFWithJumps.kt | 1 + .../default/defaultCFWithJumps.kt.after | 1 + .../default/ignoredReturnValueWithIf.kt | 2 + .../default/ignoredReturnValueWithIf.kt.after | 2 + .../ignoredReturnValueWithIfNoBlocks.kt | 2 + .../ignoredReturnValueWithIfNoBlocks.kt.after | 2 + .../default/ignoredReturnValueWithWhen.kt | 2 + .../ignoredReturnValueWithWhen.kt.after | 2 + .../ignoredReturnValueWithWhenNoBlocks.kt | 2 + ...gnoredReturnValueWithWhenNoBlocks.kt.after | 2 + .../definiteReturns/definiteReturnWithIf.kt | 2 + .../definiteReturnWithIf.kt.after | 2 + .../definiteReturns/definiteReturnWithWhen.kt | 2 + .../definiteReturnWithWhen.kt.after | 2 + .../definiteReturns/singleDefiniteReturn.kt | 2 + .../singleDefiniteReturn.kt.after | 2 + .../evalExprInIfCondition.kt | 2 + .../evalExprInIfCondition.kt.after | 2 + .../evaluateExpression/evalExprInIfElse.kt | 2 + .../evalExprInIfElse.kt.after | 2 + .../evalExprInWhenBranch.kt | 1 + .../evalExprInWhenBranch.kt.after | 1 + .../evalExprInWhenSubject.kt | 2 + .../evalExprInWhenSubject.kt.after | 2 + .../evalExpressionBodyFunction.kt | 2 + .../evalExpressionBodyFunction.kt.after | 2 + .../evaluateExpression/evalIfExpr.kt | 2 + .../evaluateExpression/evalIfExpr.kt.after | 2 + .../evaluateExpression/evalWhenExpr.kt | 2 + .../evaluateExpression/evalWhenExpr.kt.after | 2 + .../evaluateExpression/simpleEvalExpr.kt | 2 + .../simpleEvalExpr.kt.after | 2 + .../outputValues/singleOutputValue.kt | 2 + .../outputValues/singleOutputValue.kt.after | 2 + .../outputValues/singleOutputValueWithIf.kt | 2 + .../singleOutputValueWithIf.kt.after | 2 + .../singleOutputValueWithIfElse.kt | 2 + .../singleOutputValueWithIfElse.kt.after | 2 + .../outputValues/singleOutputValueWithWhen.kt | 2 + .../singleOutputValueWithWhen.kt.after | 2 + .../singleOutputValueWithWhenElse.kt | 2 + .../singleOutputValueWithWhenElse.kt.after | 2 + .../controlFlow/throws/breakWithThrow.kt | 2 + .../throws/breakWithThrow.kt.after | 2 + .../controlFlow/throws/continueWithThrow.kt | 2 + .../throws/continueWithThrow.kt.after | 2 + .../throws/evalExpressionWithThrow.kt | 2 + .../throws/evalExpressionWithThrow.kt.after | 2 + .../throws/nonValuedReturnWithThrow.kt | 2 + .../throws/nonValuedReturnWithThrow.kt.after | 2 + .../throws/outputValueWithThrow.kt | 1 + .../throws/outputValueWithThrow.kt.after | 1 + .../controlFlow/throws/returnWithThrow.kt | 2 + .../throws/returnWithThrow.kt.after | 2 + .../defaultContainer/classFunction.kt | 2 + .../defaultContainer/classFunction.kt.after | 2 + .../defaultContainer/topLevelFunction.kt | 2 + .../topLevelFunction.kt.after | 2 + .../candidateTypes/nonNullableTypes.kt | 14 ++ .../candidateTypes/nonNullableTypes.kt.after | 18 +++ .../candidateTypes/nullableTypes.kt | 14 ++ .../candidateTypes/nullableTypes.kt.after | 18 +++ .../candidateTypes/typeHierarchy1.kt | 35 +++++ .../candidateTypes/typeHierarchy1.kt.after | 39 +++++ .../candidateTypes/typeHierarchy2.kt | 35 +++++ .../candidateTypes/typeHierarchy2.kt.after | 39 +++++ .../candidateTypes/typeHierarchy3.kt | 35 +++++ .../candidateTypes/typeHierarchy3.kt.after | 39 +++++ .../candidateTypes/typeHierarchy4.kt | 35 +++++ .../candidateTypes/typeHierarchy4.kt.after | 39 +++++ .../explicitLabeledThisInMember.kt | 2 + .../explicitLabeledThisInMember.kt.after | 2 + .../extractThis/explicitThisInExtension.kt | 1 + .../explicitThisInExtension.kt.after | 1 + .../extractThis/explicitThisInMember.kt | 2 + .../extractThis/explicitThisInMember.kt.after | 2 + .../implicitAndExplicitLabeledThisInMember.kt | 2 + ...citAndExplicitLabeledThisInMember.kt.after | 2 + .../implicitAndExplicitThisInExtension.kt | 1 + ...mplicitAndExplicitThisInExtension.kt.after | 1 + .../extractThis/implicitThisInExtension.kt | 1 + .../implicitThisInExtension.kt.after | 1 + .../extractThis/implicitThisInMember.kt | 2 + .../extractThis/implicitThisInMember.kt.after | 2 + .../parameters/misc/multiDeclaration.kt | 1 + .../parameters/misc/multiDeclaration.kt.after | 1 + .../parameters/misc/multipleOccurrences.kt | 3 + .../misc/multipleOccurrences.kt.after | 3 + .../parameters/misc/usagesInCallArgs.kt | 4 + .../parameters/misc/usagesInCallArgs.kt.after | 4 + .../typeParameters/simpleTypeParameter.kt | 1 + .../simpleTypeParameter.kt.after | 1 + .../simpleTypeParameterWithConstraint.kt | 1 + ...simpleTypeParameterWithConstraint.kt.after | 1 + .../typeParameters/typeParamInArgument.kt | 1 + .../typeParamInArgument.kt.after | 1 + .../typeParametersAndConstraintsCombined1.kt | 3 + ...ParametersAndConstraintsCombined1.kt.after | 3 + .../typeParametersAndConstraintsCombined2.kt | 2 + ...ParametersAndConstraintsCombined2.kt.after | 2 + .../typeParametersAndConstraintsCombined3.kt | 1 + ...ParametersAndConstraintsCombined3.kt.after | 1 + .../typeParameters/typeParametersCombined1.kt | 3 + .../typeParametersCombined1.kt.after | 3 + .../typeParameters/typeParametersCombined2.kt | 2 + .../typeParametersCombined2.kt.after | 2 + .../typeParameters/typeParametersCombined3.kt | 1 + .../typeParametersCombined3.kt.after | 1 + .../typeParametersCombinedAndThis.kt | 2 + .../typeParametersCombinedAndThis.kt.after | 2 + .../AbstractJetExtractionTest.kt | 22 ++- .../JetExtractionTestGenerated.java | 41 ++++- 143 files changed, 759 insertions(+), 78 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt.after diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java index 3b81f28f08b..084f1b64deb 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -376,9 +376,13 @@ public class TypeUtils { } private static void collectImmediateSupertypes(@NotNull JetType type, @NotNull Collection result) { + boolean isNullable = type.isNullable(); TypeSubstitutor substitutor = TypeSubstitutor.create(type); for (JetType supertype : type.getConstructor().getSupertypes()) { - result.add(substitutor.substitute(supertype, Variance.INVARIANT)); + JetType substitutedType = substitutor.substitute(supertype, Variance.INVARIANT); + if (substitutedType != null) { + result.add(makeNullableIfNeeded(substitutedType, isNullable)); + } } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt index 86c3240f65f..69a2419c3cd 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractKotlinFunctionHandler.kt @@ -59,7 +59,8 @@ public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boole editor: Editor, file: JetFile, elements: List, - targetSibling: PsiElement + targetSibling: PsiElement, + preprocessor: ((ExtractionDescriptor) -> Unit)? = null ) { val project = file.getProject() @@ -83,7 +84,7 @@ public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boole dialog.getCurrentDescriptor() } - + preprocessor?.invoke(descriptor) project.executeWriteCommand(EXTRACT_FUNCTION) { descriptor.generateFunction() } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt index c0684afe901..aa3ea32f116 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt @@ -31,19 +31,21 @@ import org.jetbrains.jet.lang.psi.psiUtil.replaced import org.jetbrains.jet.lang.psi.JetQualifiedExpression import org.jetbrains.jet.lang.psi.JetTypeParameter import org.jetbrains.jet.lang.psi.JetTypeConstraint -import kotlin.properties.Delegates import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage -data class Parameter( - val argumentText: String, - val name: String, - var mirrorVarName: String?, - val parameterType: JetType, - val receiverCandidate: Boolean -) { +trait Parameter { + val argumentText: String + val name: String + val mirrorVarName: String? + val parameterType: JetType + val parameterTypeCandidates: List + val receiverCandidate: Boolean + val nameForRef: String get() = mirrorVarName ?: name + + fun copy(name: String): Parameter } data class TypeParameter( diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index 2508fd05c12..d2e8bcf7635 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -38,7 +38,6 @@ import org.jetbrains.jet.lang.psi.JetPsiFactory.FunctionBuilder import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil import org.jetbrains.jet.plugin.imports.canBeReferencedViaImport -import org.jetbrains.jet.lang.types.checker.JetTypeChecker import org.jetbrains.jet.lang.resolve.DescriptorUtils import com.intellij.psi.PsiNamedElement import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor @@ -56,14 +55,7 @@ import org.jetbrains.jet.lang.diagnostics.Errors import org.jetbrains.jet.lang.psi.psiUtil.replaced import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.* import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.WriteValueInstruction -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.CallInstruction -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.JetElementInstruction -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.OperationInstruction -import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.ReadValueInstruction import org.jetbrains.jet.lang.cfg.pseudocode.instructions.* import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.* import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.* @@ -72,6 +64,7 @@ import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.traverse import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder import org.jetbrains.jet.lang.resolve.bindingContextUtil.getTargetFunctionDescriptor import com.intellij.psi.PsiWhiteSpace +import org.jetbrains.jet.lang.resolve.OverridingUtil private val DEFAULT_FUNCTION_NAME = "myFun" private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType() @@ -325,13 +318,57 @@ private fun JetType.processTypeIfExtractable( } } -private fun ExtractionData.inferParametersInfo(commonParent: PsiElement, - localInstructions: List, - bindingContext: BindingContext, - replacementMap: MutableMap, - parameters: MutableSet, - typeParameters: MutableSet, - nonDenotableTypes: MutableSet): ErrorMessage? { +private class MutableParameter( + override val argumentText: String, + override val name: String, + override val mirrorVarName: String?, + override val receiverCandidate: Boolean +): Parameter { + // All modifications happen in the same thread + private var writable: Boolean = true + private val defaultTypes = HashSet() + private val typePredicates = HashSet() + + fun addDefaultType(jetType: JetType) { + assert(writable, "Can't add type to non-writable parameter $name") + defaultTypes.add(jetType) + } + + fun addTypePredicate(predicate: TypePredicate) { + assert(writable, "Can't add type predicate to non-writable parameter $name") + typePredicates.add(predicate) + } + + override val parameterTypeCandidates: List by Delegates.lazy { + writable = false + listOf(parameterType) + TypeUtils.getAllSupertypes(parameterType).filter(and(typePredicates)) + } + + override val parameterType: JetType by Delegates.lazy { + writable = false + CommonSupertypes.commonSupertype(defaultTypes) + } + + override fun copy(name: String): Parameter = DelegatingParameter(this, name) +} + +private class DelegatingParameter( + val original: Parameter, + override val name: String +): Parameter by original { + override fun copy(name: String): Parameter = DelegatingParameter(original, name) +} + +private fun ExtractionData.inferParametersInfo( + commonParent: PsiElement, + pseudocode: Pseudocode, + localInstructions: List, + bindingContext: BindingContext, + replacementMap: MutableMap, + parameters: MutableSet, + typeParameters: MutableSet, + nonDenotableTypes: MutableSet +): ErrorMessage? { val varNameValidator = JetNameValidatorImpl( commonParent.getParentByType(javaClass()), originalElements.first, @@ -339,7 +376,9 @@ private fun ExtractionData.inferParametersInfo(commonParent: PsiElement, ) val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext) - val extractedDescriptorToParameter = HashMap() + val extractedDescriptorToParameter = HashMap() + + val valueUsageMap = pseudocode.collectValueUsages() for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) { val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult @@ -397,57 +436,40 @@ private fun ExtractionData.inferParametersInfo(commonParent: PsiElement, if (extractParameter) { val parameterType = when { receiver.exists() -> receiver.getType() - else -> bindingContext[BindingContext.EXPRESSION_TYPE, originalRef] ?: DEFAULT_PARAMETER_TYPE + else -> bindingContext[BindingContext.AUTOCAST, originalRef] + ?: bindingContext[BindingContext.EXPRESSION_TYPE, originalRef] + ?: DEFAULT_PARAMETER_TYPE } if (!parameterType.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes)) continue - val existingParameter = extractedDescriptorToParameter[descriptorToExtract] - val parameter: Parameter = - if (existingParameter != null) { - if (!JetTypeChecker.INSTANCE.equalTypes(existingParameter.parameterType, parameterType)) { - val newParameter = existingParameter.copy( - parameterType = CommonSupertypes.commonSupertype(listOf(existingParameter.parameterType, parameterType)) - ) + val parameterTypePredicate = + pseudocode.getElementValue(originalRef)?.let { getExpectedTypePredicate(it, valueUsageMap, bindingContext) } ?: AllTypes - extractedDescriptorToParameter[descriptorToExtract] = newParameter - - for ((offset, replacement) in replacementMap) { - if (replacement is ParameterReplacement && replacement.parameter == existingParameter) { - replacementMap[offset] = replacement.copy(newParameter) - } - } - - newParameter + val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) { + val parameterName = + if (extractThis) { + JetNameSuggester.suggestNames(parameterType, varNameValidator, null).first() } - else existingParameter - } - else { - val parameterName = - if (extractThis) { - JetNameSuggester.suggestNames(parameterType, varNameValidator, null).first() - } - else originalDeclaration.getName()!! + else originalDeclaration.getName()!! - val mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors) - varNameValidator.validateName(parameterName)!! - else null + val mirrorVarName = + if (descriptorToExtract in modifiedVarDescriptors) varNameValidator.validateName(parameterName)!! else null - val argumentText = - if (hasThisReceiver && extractThis) - "this@${parameterType.getConstructor().getDeclarationDescriptor()!!.getName().asString()}" - else - (thisExpr ?: ref).getText() ?: throw AssertionError("'this' reference shouldn't be empty: code fragment = ${getCodeFragmentText()}") + val argumentText = + if (hasThisReceiver && extractThis) + "this@${parameterType.getConstructor().getDeclarationDescriptor()!!.getName().asString()}" + else + (thisExpr ?: ref).getText() ?: throw AssertionError("'this' reference shouldn't be empty: code fragment = ${getCodeFragmentText()}") - val parameter = Parameter(argumentText, parameterName, mirrorVarName, parameterType, extractThis) + MutableParameter(argumentText, parameterName, mirrorVarName, extractThis) + } - extractedDescriptorToParameter[descriptorToExtract] = parameter - - parameter - } + parameter.addDefaultType(parameterType) + parameter.addTypePredicate(parameterTypePredicate) replacementMap[refInfo.offsetInBody] = - if (hasThisReceiver && extractThis) AddPrefixReplacement(parameter) else RenameReplacement(parameter) + if (hasThisReceiver && extractThis) AddPrefixReplacement(parameter) else RenameReplacement(parameter) } } } @@ -543,7 +565,9 @@ fun ExtractionData.performAnalysis(): AnalysisResult { val parameters = HashSet() val typeParameters = HashSet() val nonDenotableTypes = HashSet() - val parameterError = inferParametersInfo(commonParent, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes) + val parameterError = inferParametersInfo( + commonParent, pseudocode, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes + ) if (parameterError != null) { return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(parameterError)) } @@ -624,7 +648,7 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts { if (diagnostics.any { it.getFactory() == Errors.UNRESOLVED_REFERENCE } || (currentDescriptor != null && !ErrorUtils.isError(currentDescriptor) - && !compareDescriptors(currentDescriptor, resolveResult.descriptor))) { + && !comparePossiblyOverridingDescriptors(currentDescriptor, resolveResult.descriptor))) { conflicts.putValue( currentRefExpr, JetRefactoringBundle.message( @@ -649,6 +673,15 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts { return ExtractionDescriptorWithConflicts(this, conflicts) } +private fun comparePossiblyOverridingDescriptors(currentDescriptor: DeclarationDescriptor?, originalDescriptor: DeclarationDescriptor?): Boolean { + if (compareDescriptors(currentDescriptor, originalDescriptor)) return true + if (originalDescriptor is CallableDescriptor) { + if (!OverridingUtil.traverseOverridenDescriptors(originalDescriptor) { !compareDescriptors(currentDescriptor, it) }) return true + } + + return false +} + fun ExtractionDescriptor.getFunctionText( withBody: Boolean = true, descriptorRenderer: DescriptorRenderer = DescriptorRenderer.FQ_NAMES_IN_TYPES diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java index 119c3cb47f2..2de47490a08 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java @@ -70,17 +70,11 @@ public class KotlinParameterTablePanel extends JPanel { } public String getTypeAsString() { - return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getOriginalParameter().getParameterType()); + return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getOriginalParameter().getParameterTypeCandidates().get(0)); } public Parameter toParameter() { - return new Parameter( - originalParameter.getArgumentText(), - name, - originalParameter.getMirrorVarName(), - originalParameter.getParameterType(), - originalParameter.getReceiverCandidate() - ); + return originalParameter.copy(name); } } diff --git a/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt b/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt index 18c78fd61bb..3372cfd9265 100644 --- a/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt +++ b/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { // test diff --git a/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt.after b/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt.after index 608dabf999a..b8aaaec2df4 100644 --- a/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt.after +++ b/idea/testData/refactoring/extractFunction/basic/fragmentWithComment.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { if (b(a)) return a diff --git a/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt b/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt index 7a6adf3d142..1a112d5181b 100644 --- a/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt +++ b/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { /* diff --git a/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt.after b/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt.after index 442909f5953..1879862bb0a 100644 --- a/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt.after +++ b/idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { if (b(a)) return a diff --git a/idea/testData/refactoring/extractFunction/basic/refInReturn.kt b/idea/testData/refactoring/extractFunction/basic/refInReturn.kt index 0fd72488273..029b2dca931 100644 --- a/idea/testData/refactoring/extractFunction/basic/refInReturn.kt +++ b/idea/testData/refactoring/extractFunction/basic/refInReturn.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { println(a) diff --git a/idea/testData/refactoring/extractFunction/basic/refInReturn.kt.after b/idea/testData/refactoring/extractFunction/basic/refInReturn.kt.after index ffe390de69e..e9052bbf124 100644 --- a/idea/testData/refactoring/extractFunction/basic/refInReturn.kt.after +++ b/idea/testData/refactoring/extractFunction/basic/refInReturn.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { if (b(a)) return a diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt index f836b2a6581..0963d801a51 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt.after index e10096f1f3d..3efbe1b4c57 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt index 03e115b80d6..92d438a0062 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt.after index ac6cf45ac2c..867bfdceda6 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt index 4286e85cc20..f564b6bf2df 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt.after index 4c18664b220..239d825363d 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithWhen.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt index ecd386b198d..3158bd16036 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt.after index 4fc2c0ba18c..154bd1413a6 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIf.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt index 199f2ba5304..819f00074b8 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt.after index a1c786aa896..0ef66d95783 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithIfElse.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt index ffa88f296c7..741510eda5a 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt.after index 81e18d6d4a9..7e4c43b906e 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalReturnWithWhen.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt index 0e4a5dcd7d7..1af325848c9 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt.after index e0378144224..580507294f3 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIf.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt index 7bb6f8d2bde..ceddd650382 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt.after index 2c2cb51f5d2..fb152f9057a 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithIfElse.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt index f25eda5649f..a5ff642baa0 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt.after index f40ffbefe6d..1d272a7ca5d 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/unconditionalBreakWithWhen.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt index 9e380c0605e..626f08973f4 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any // SIBLING: fun foo(a: Int) { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt.after index 70a1a7925d7..4ccdf286943 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any // SIBLING: fun foo(a: Int) { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt index e2399edb49f..7dcfff262f3 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int) { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt.after index 0a6786457c3..f032a9a01d5 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int) { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt index c9d2cd5315d..7b4ae2ec974 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after index b2f3082b36f..b7eca1131bd 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt index 776c48ce0a4..7ee6d3ef64d 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after index 8dbbebfbb6e..2c123ba930f 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt index 7d8e025b621..e4e643561b5 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after index 82c1f66c80e..e6422989354 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt index 88a828799ed..3b98c0fc77c 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after index b8aa0d9e44d..bf7a312045e 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any fun bar(a: Int): Int { println(a) return a + 10 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt index 1d23aa7b381..3984a3238a6 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt.after index 96feeacb740..fce0d54ffba 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithIf.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt index 117adfe3791..8b3ddc1ca47 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt.after index f8fceed3237..cf488a71e8f 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/definiteReturnWithWhen.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt index fa31f31fdda..43084f4ef5e 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt.after index 2ac53541783..3b3bc9b1e0c 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/definiteReturns/singleDefiniteReturn.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt index c5e075ff91c..a84a001f9d2 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after index 1085b675856..594bee9b23e 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt index 39ac60a8466..d5df8a1f9af 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after index 957aa383f92..ec9b09d88a7 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt index afee5edb18f..6bd445a3073 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after index e916a7f5b11..ae9d877f7ce 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt index 5e4cca26943..c6a90882e00 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after index 28242ea436c..3a3bd47e9d4 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt index d2cfaeddfe5..b3b22875daf 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt @@ -1,2 +1,4 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int, b: Int): Int = a + b diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after index c5ef5bfc557..3a7fc579e04 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int, b: Int): Int = i(a, b) diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt index 3222a55b7d7..66668cd0b4b 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt.after index effcbf7e4cc..61c2300399c 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt index 3b198ecc4be..b3e1079cea2 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt.after index 3c7904f49d0..42d92c15c5c 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt index 77991cf0170..d42e002c5c0 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt.after index 2ac53541783..3b3bc9b1e0c 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/simpleEvalExpr.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt index 4fa1218b258..50f8e17ccfa 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt.after index d02accf3487..f125443db71 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValue.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt index 02665c4eb3e..2d7a4b3b1c6 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt.after index 211b37c956d..34458f1ff65 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIf.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt index cd0880bf48c..c42c15350e1 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt.after index f85082d6c38..c4af982ba6b 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithIfElse.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt index 710aebe5ff3..c804d9d1eb2 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt.after index d51486fd376..a2ce6551c1c 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhen.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt index 62cb4836a34..e49a2b0e424 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt.after index b7dfbc2c107..70755a7e64d 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/singleOutputValueWithWhenElse.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt index 60e5b4f04e6..4d97b3dae34 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt.after index b8eb407c5da..1849ddf19f7 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/breakWithThrow.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt index 919ffd16e73..8b775628609 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after index 3241bcc9ddd..35e7cbd7555 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt index 3710051cd59..e3ac46dc63a 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt.after index bda988ff2f0..a31337f0084 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/evalExpressionWithThrow.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt index 7c1c6f1a4cf..5e830e28a1d 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int) { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after index e2c66d8ce95..c11246bb9dc 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int) { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt index 514aa2941ff..06211d31505 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after index 430e72c1b3a..466c582391d 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { var b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt index fcff707f1d0..d0c974d147a 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt.after index 819b4b274e0..9fed3c2fe1b 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int): Int { val b: Int = 1 diff --git a/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt b/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt index 5b2f79699e1..6cf938ac03d 100644 --- a/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt +++ b/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int class A { class B { fun foo(a: Int, b: Int): Int { diff --git a/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt.after b/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt.after index 41d443a15c6..efd25e31a75 100644 --- a/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt.after +++ b/idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int class A { class B { fun foo(a: Int, b: Int): Int { diff --git a/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt b/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt index 3d8111d8964..943cd2cb1de 100644 --- a/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt +++ b/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int fun foo(a: Int, b: Int): Int { return a + b - 1 } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt.after b/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt.after index 7d4acfb97ea..ae7efed9cba 100644 --- a/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt.after +++ b/idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int fun foo(a: Int, b: Int): Int { return i(a, b) } diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt new file mode 100644 index 00000000000..4dafde070ed --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt @@ -0,0 +1,14 @@ +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, kotlin.Any +// PARAM_TYPES: X +class X { + fun add(t: T) { + + } +} + +// SIBLING: +fun foo(s: String?, x: X) { + when { + s != null -> x.add(s) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after new file mode 100644 index 00000000000..e16d1ea3903 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt.after @@ -0,0 +1,18 @@ +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, kotlin.Any +// PARAM_TYPES: X +class X { + fun add(t: T) { + + } +} + +// SIBLING: +fun foo(s: String?, x: X) { + when { + s != null -> unit(s, x) + } +} + +fun unit(s: String, x: X) { + x.add(s) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt new file mode 100644 index 00000000000..ce80d833f72 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt @@ -0,0 +1,14 @@ +// PARAM_TYPES: kotlin.String?, kotlin.Comparable?, kotlin.CharSequence?, kotlin.Any? +// PARAM_TYPES: X +class X { + fun add(t: T) { + + } +} + +// SIBLING: +fun foo(s: String?, x: X) { + when { + s != null -> x.add(s) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt.after new file mode 100644 index 00000000000..b3b116f5ad4 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt.after @@ -0,0 +1,18 @@ +// PARAM_TYPES: kotlin.String?, kotlin.Comparable?, kotlin.CharSequence?, kotlin.Any? +// PARAM_TYPES: X +class X { + fun add(t: T) { + + } +} + +// SIBLING: +fun foo(s: String?, x: X) { + when { + s != null -> unit(s, x) + } +} + +fun unit(s: String?, x: X) { + x.add(s) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt new file mode 100644 index 00000000000..0110855a2cf --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt @@ -0,0 +1,35 @@ +//PARAM_TYPES: C, AImpl, A +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + c.doA() + c.doB() + c.doC() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt.after new file mode 100644 index 00000000000..c0aa5718d2d --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt.after @@ -0,0 +1,39 @@ +//PARAM_TYPES: C, AImpl, A +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + unit(c) + c.doB() + c.doC() +} + +fun unit(c: C) { + c.doA() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt new file mode 100644 index 00000000000..c5d4010f69d --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt @@ -0,0 +1,35 @@ +//PARAM_TYPES: C, B +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + c.doA() + c.doB() + c.doC() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt.after new file mode 100644 index 00000000000..96645ea7142 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt.after @@ -0,0 +1,39 @@ +//PARAM_TYPES: C, B +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + c.doA() + unit(c) + c.doC() +} + +fun unit(c: C) { + c.doB() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt new file mode 100644 index 00000000000..578290918ab --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt @@ -0,0 +1,35 @@ +//PARAM_TYPES: C +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + c.doA() + c.doB() + c.doC() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt.after new file mode 100644 index 00000000000..05d6290919b --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt.after @@ -0,0 +1,39 @@ +//PARAM_TYPES: C +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + c.doA() + c.doB() + unit(c) +} + +fun unit(c: C) { + c.doC() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt new file mode 100644 index 00000000000..e7495780bba --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt @@ -0,0 +1,35 @@ +//PARAM_TYPES: C +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + c.doA() + c.doB() + c.doC() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt.after b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt.after new file mode 100644 index 00000000000..75594210f4b --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt.after @@ -0,0 +1,39 @@ +//PARAM_TYPES: C +trait A { + fun doA() +} + +open class AImpl: A { + override fun doA() { + throw UnsupportedOperationException() + } +} + +trait B { + fun doB() +} + +class C: AImpl(), B { + override fun doA() { + throw UnsupportedOperationException() + } + + override fun doB() { + throw UnsupportedOperationException() + } + + fun doC() { + throw UnsupportedOperationException() + } +} + +// SIBLING: +fun foo(c: C) { + unit(c) + c.doC() +} + +fun unit(c: C) { + c.doA() + c.doB() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt index 9b793169806..55672bccccd 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt.after index 932c04b5a0d..19c2d063532 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitLabeledThisInMember.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt index de578bee1e2..f6aca51d5c7 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: Z class Z(val a: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after index bec9686c4dc..051cb4833e7 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInExtension.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: Z class Z(val a: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt index 6bf09f98e4f..c37338507bf 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt.after index 48d65eb567b..55bb2b0b28b 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisInMember.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt index a9ef6b95ce9..2d338b4b8fe 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt.after index 932c04b5a0d..19c2d063532 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt index 0946bdd5021..171724d966b 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: Z class Z(val a: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after index ffa4e81dd31..16cda1746fc 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitThisInExtension.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: Z class Z(val a: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt index 51e55077b5a..2a8b91855c5 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: Z class Z(val a: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt.after index db4d498bd74..9000c97c6a6 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInExtension.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: Z class Z(val a: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt index ed05565e00d..b6f4e488ce9 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt.after index 72160c11655..8c0a5e68db8 100644 --- a/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisInMember.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B public open class Z { val z: Int = 0 } diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt b/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt index e3e6b45d5a7..35c49a8987e 100644 --- a/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt +++ b/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any // SIBLING: fun main(args: Array) { val (a, b) = Data(1, 2) diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt.after b/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt.after index 6197dc5540b..374ce76203e 100644 --- a/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/misc/multiDeclaration.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: kotlin.Int, Number, Comparable, Any // SIBLING: fun main(args: Array) { val (a, b) = Data(1, 2) diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt b/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt index 9a876cd41c8..6f824a05a7a 100644 --- a/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt +++ b/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt @@ -1,3 +1,6 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int, b: Int, c: Int): Int { return (a + b*a - c) + b*c diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt.after b/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt.after index b82bcb36d27..0a54daa0e54 100644 --- a/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/misc/multipleOccurrences.kt.after @@ -1,3 +1,6 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: fun foo(a: Int, b: Int, c: Int): Int { return i(a, b, c) diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt b/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt index 5761a4b2bff..6b381cd32b6 100644 --- a/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt +++ b/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt @@ -1,3 +1,7 @@ +// PARAM_TYPES: A +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: public class A() { fun bar(a: Int, b: Int): Int { diff --git a/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt.after b/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt.after index 885b558f0a3..4b19703b654 100644 --- a/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt.after +++ b/idea/testData/refactoring/extractFunction/parameters/misc/usagesInCallArgs.kt.after @@ -1,3 +1,7 @@ +// PARAM_TYPES: A +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int // SIBLING: public class A() { fun bar(a: Int, b: Int): Int { diff --git a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt index e742a9b01dd..b625943954d 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: V open class Data(val x: Int) class Pair(val a: A, val b: B) diff --git a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt.after index de2341f088b..d0f22c861d5 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameter.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: V open class Data(val x: Int) class Pair(val a: A, val b: B) diff --git a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt index d5f09c3dc63..32cc2939d3c 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: V open class Data(val x: Int) trait DataEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt.after index a6e6466e197..0a6fe47d0a8 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/simpleTypeParameterWithConstraint.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: V open class Data(val x: Int) trait DataEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt index ceb82dc3794..57e94ee0871 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: Data class Data(val t: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt.after index 9cd97061b3f..4a5fe65d03f 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParamInArgument.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: Data class Data(val t: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt index b0a9f7e494a..40ab68a7289 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt @@ -1,3 +1,6 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx trait DataExEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt.after index e7dc5965d8a..f5493f70dc8 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined1.kt.after @@ -1,3 +1,6 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx trait DataExEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt index 0802d6e3bf6..1d669a511e8 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx trait DataExEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt.after index cea3de19fdd..98ea1f8394c 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined2.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx trait DataExEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt index 744b08cd3f5..86d701ab736 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx trait DataExEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt.after index 1faeda07004..7d12e02d8b2 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersAndConstraintsCombined3.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx trait DataExEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt index 95b7b5dc375..4b7a69df8c9 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt @@ -1,3 +1,6 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt.after index b8bda4914c7..82c63d9844b 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined1.kt.after @@ -1,3 +1,6 @@ +// PARAM_TYPES: A +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) // SIBLING: diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt index 9bbcb0101a0..29f47a485c3 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) class A(val t: T) { diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt.after index fadf4ee100b..7f093f0d6c6 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined2.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: A.B +// PARAM_TYPES: V, Data open class Data(val x: Int) class A(val t: T) { diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt index 23422827e45..25804fef6a9 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt @@ -1,3 +1,4 @@ +// PARAM_TYPES: V, Data open class Data(val x: Int) class A(val t: T) { diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt.after index c67966c5ee4..0b63c4e431b 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombined3.kt.after @@ -1,3 +1,4 @@ +// PARAM_TYPES: V, Data open class Data(val x: Int) class A(val t: T) { diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt index d32eebe2c14..e2290712601 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx diff --git a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt.after b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt.after index 03d814aff07..6f2f7c0681d 100644 --- a/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt.after +++ b/idea/testData/refactoring/extractFunction/typeParameters/typeParametersCombinedAndThis.kt.after @@ -1,3 +1,5 @@ +// PARAM_TYPES: A +// PARAM_TYPES: V, Data open class Data(val x: Int) trait DataEx diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt index 4992e099eb2..8e9e8feb446 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt @@ -32,6 +32,11 @@ import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.PsiWhiteSpace import org.jetbrains.jet.lang.psi.JetPackageDirective +import org.jetbrains.jet.InTextDirectivesUtils +import org.jetbrains.jet.renderer.DescriptorRenderer +import java.util.ArrayList +import com.intellij.util.containers.ContainerUtil +import kotlin.test.assertEquals public abstract class AbstractJetExtractionTest() : LightCodeInsightFixtureTestCase() { val fixture: JavaCodeInsightTestFixture get() = myFixture @@ -65,9 +70,24 @@ public abstract class AbstractJetExtractionTest() : LightCodeInsightFixtureTestC } ) + val expectedParameterTypes = ArrayList() + val fileText = file.getText() + val expectedTypes = + InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ") + .mapTo(expectedParameterTypes) { "[$it]" } + .makeString() + + val renderer = DescriptorRenderer.DEBUG_TEXT + val editor = fixture.getEditor() selectElements(editor, file) { (elements, previousSibling) -> - ExtractKotlinFunctionHandler().doInvoke(editor, file, elements, explicitPreviousSibling ?: previousSibling) + ExtractKotlinFunctionHandler().doInvoke(editor, file, elements, explicitPreviousSibling ?: previousSibling) { + val actualTypes = (ContainerUtil.createMaybeSingletonList(it.receiverParameter) + it.parameters).map { + it.parameterTypeCandidates.map { renderer.renderType(it) }. makeString(", ", "[", "]") + }.makeString() + + assertEquals(expectedTypes, actualTypes, "Expected types mismatch.") + } } } } diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index 4e8097718c9..1769329e2d3 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -666,12 +666,50 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { } @TestMetadata("idea/testData/refactoring/extractFunction/parameters") - @InnerTestClasses({Parameters.ExtractSuper.class, Parameters.ExtractThis.class, Parameters.It.class, Parameters.Misc.class, Parameters.NonDenotableTypes.class}) + @InnerTestClasses({Parameters.CandidateTypes.class, Parameters.ExtractSuper.class, Parameters.ExtractThis.class, Parameters.It.class, Parameters.Misc.class, Parameters.NonDenotableTypes.class}) public static class Parameters extends AbstractJetExtractionTest { public void testAllFilesPresentInParameters() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/parameters"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes") + public static class CandidateTypes extends AbstractJetExtractionTest { + public void testAllFilesPresentInCandidateTypes() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/parameters/candidateTypes"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("nonNullableTypes.kt") + public void testNonNullableTypes() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt"); + } + + @TestMetadata("nullableTypes.kt") + public void testNullableTypes() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/candidateTypes/nullableTypes.kt"); + } + + @TestMetadata("typeHierarchy1.kt") + public void testTypeHierarchy1() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt"); + } + + @TestMetadata("typeHierarchy2.kt") + public void testTypeHierarchy2() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy2.kt"); + } + + @TestMetadata("typeHierarchy3.kt") + public void testTypeHierarchy3() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy3.kt"); + } + + @TestMetadata("typeHierarchy4.kt") + public void testTypeHierarchy4() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy4.kt"); + } + + } + @TestMetadata("idea/testData/refactoring/extractFunction/parameters/extractSuper") public static class ExtractSuper extends AbstractJetExtractionTest { public void testAllFilesPresentInExtractSuper() throws Exception { @@ -880,6 +918,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { public static Test innerSuite() { TestSuite suite = new TestSuite("Parameters"); suite.addTestSuite(Parameters.class); + suite.addTestSuite(CandidateTypes.class); suite.addTestSuite(ExtractSuper.class); suite.addTestSuite(ExtractThis.class); suite.addTestSuite(It.class); From 0a89b260300c641f0cd031947a9aa88a0cbfbafc Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 20 Jun 2014 18:01:33 +0400 Subject: [PATCH 046/143] Extract Function: Implement UI for parameter type selection --- .../extractFunction/ExtractionDescriptor.kt | 2 +- .../extractFunction/extractFunctionUtils.kt | 7 +- .../ui/KotlinParameterTablePanel.java | 97 ++++++++++++++++--- 3 files changed, 87 insertions(+), 19 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt index aa3ea32f116..8ea801675c4 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt @@ -45,7 +45,7 @@ trait Parameter { val nameForRef: String get() = mirrorVarName ?: name - fun copy(name: String): Parameter + fun copy(name: String, parameterType: JetType): Parameter } data class TypeParameter( diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index d2e8bcf7635..5e732b9d507 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -349,14 +349,15 @@ private class MutableParameter( CommonSupertypes.commonSupertype(defaultTypes) } - override fun copy(name: String): Parameter = DelegatingParameter(this, name) + override fun copy(name: String, parameterType: JetType): Parameter = DelegatingParameter(this, name, parameterType) } private class DelegatingParameter( val original: Parameter, - override val name: String + override val name: String, + override val parameterType: JetType ): Parameter by original { - override fun copy(name: String): Parameter = DelegatingParameter(original, name) + override fun copy(name: String, parameterType: JetType): Parameter = DelegatingParameter(original, name, parameterType) } private fun ExtractionData.inferParametersInfo( diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java index 2de47490a08..0781b39f848 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java @@ -19,18 +19,25 @@ package org.jetbrains.jet.plugin.refactoring.extractFunction.ui; import com.intellij.ui.BooleanTableCellRenderer; import com.intellij.ui.TableUtil; import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.components.JBComboBoxLabel; +import com.intellij.ui.components.editors.JBComboBoxTableCellEditorComponent; import com.intellij.ui.table.JBTable; +import com.intellij.util.Function; +import com.intellij.util.ui.AbstractTableCellEditor; import com.intellij.util.ui.EditableModel; import kotlin.Function1; import kotlin.KotlinPackage; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.refactoring.JetNameSuggester; import org.jetbrains.jet.plugin.refactoring.extractFunction.Parameter; import org.jetbrains.jet.renderer.DescriptorRenderer; import javax.swing.*; import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableColumn; import java.awt.*; @@ -42,11 +49,13 @@ public class KotlinParameterTablePanel extends JPanel { public static class ParameterInfo { private final Parameter originalParameter; private String name; + private JetType type; private boolean enabled = true; public ParameterInfo(Parameter originalParameter) { this.originalParameter = originalParameter; this.name = originalParameter.getName(); + this.type = originalParameter.getParameterType(); } public Parameter getOriginalParameter() { @@ -69,12 +78,16 @@ public class KotlinParameterTablePanel extends JPanel { this.name = name; } - public String getTypeAsString() { - return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getOriginalParameter().getParameterTypeCandidates().get(0)); + public JetType getType() { + return type; + } + + public void setType(JetType type) { + this.type = type; } public Parameter toParameter() { - return originalParameter.copy(name); + return originalParameter.copy(name, type); } } @@ -122,6 +135,55 @@ public class KotlinParameterTablePanel extends JPanel { } ); + myTable.getColumnModel().getColumn(MyTableModel.PARAMETER_TYPE_COLUMN).setCellRenderer(new DefaultTableCellRenderer() { + private final JBComboBoxLabel myLabel = new JBComboBoxLabel(); + + @Override + @NotNull + public Component getTableCellRendererComponent( + @NotNull JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column + ) { + myLabel.setText(String.valueOf(value)); + myLabel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground()); + myLabel.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground()); + if (isSelected) { + myLabel.setSelectionIcon(); + } else { + myLabel.setRegularIcon(); + } + return myLabel; + } + }); + + myTable.getColumnModel().getColumn(MyTableModel.PARAMETER_TYPE_COLUMN).setCellEditor(new AbstractTableCellEditor() { + final JBComboBoxTableCellEditorComponent myEditorComponent = new JBComboBoxTableCellEditorComponent(); + + @Override + @Nullable + public Object getCellEditorValue() { + return myEditorComponent.getEditorValue(); + } + + @Override + public Component getTableCellEditorComponent( + JTable table, Object value, boolean isSelected, int row, int column + ) { + ParameterInfo info = parameterInfos.get(row); + + myEditorComponent.setCell(table, row, column); + myEditorComponent.setOptions(info.getOriginalParameter().getParameterTypeCandidates().toArray()); + myEditorComponent.setDefaultValue(info.getType()); + myEditorComponent.setToString(new Function() { + @Override + public String fun(Object o) { + return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType((JetType) o); + } + }); + + return myEditorComponent; + } + }); + myTable.setPreferredScrollableViewportSize(new Dimension(250, myTable.getRowHeight() * 5)); myTable.setShowGrid(false); myTable.setIntercellSpacing(new Dimension(0, 0)); @@ -260,32 +322,29 @@ public class KotlinParameterTablePanel extends JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { switch (columnIndex) { - case CHECKMARK_COLUMN: { + case CHECKMARK_COLUMN: return parameterInfos.get(rowIndex).isEnabled(); - } - case PARAMETER_NAME_COLUMN: { + case PARAMETER_NAME_COLUMN: return parameterInfos.get(rowIndex).getName(); - } - case PARAMETER_TYPE_COLUMN: { - return parameterInfos.get(rowIndex).getTypeAsString(); - } + case PARAMETER_TYPE_COLUMN: + return parameterInfos.get(rowIndex).getType(); + default: + return null; } - assert false; - return null; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + ParameterInfo info = parameterInfos.get(rowIndex); switch (columnIndex) { case CHECKMARK_COLUMN: { - parameterInfos.get(rowIndex).setEnabled((Boolean) aValue); + info.setEnabled((Boolean) aValue); fireTableRowsUpdated(rowIndex, rowIndex); myTable.getSelectionModel().setSelectionInterval(rowIndex, rowIndex); updateSignature(); break; } case PARAMETER_NAME_COLUMN: { - ParameterInfo info = parameterInfos.get(rowIndex); String name = (String) aValue; if (JetNameSuggester.isIdentifier(name)) { info.setName(name); @@ -293,16 +352,24 @@ public class KotlinParameterTablePanel extends JPanel { updateSignature(); break; } + case PARAMETER_TYPE_COLUMN: { + info.setType((JetType) aValue); + updateSignature(); + break; + } } } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { + ParameterInfo info = parameterInfos.get(rowIndex); switch (columnIndex) { case CHECKMARK_COLUMN: return isEnabled(); case PARAMETER_NAME_COLUMN: - return isEnabled() && parameterInfos.get(rowIndex).isEnabled(); + return isEnabled() && info.isEnabled(); + case PARAMETER_TYPE_COLUMN: + return isEnabled() && info.isEnabled() && info.getOriginalParameter().getParameterTypeCandidates().size() > 1; default: return false; } From 64a2fde80a9f3aa71ac5c0e0b479c242bcecb561 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 23 Jun 2014 18:03:26 +0400 Subject: [PATCH 047/143] Extract Function: Fix signature update on dialog opening --- .../ui/KotlinExtractFunctionDialog.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinExtractFunctionDialog.java b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinExtractFunctionDialog.java index e5df89c5e73..26b599ac49d 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinExtractFunctionDialog.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinExtractFunctionDialog.java @@ -63,7 +63,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { setModal(true); setTitle(JetRefactoringBundle.message("extract.function")); init(); - update(false); + update(); } private void createUIComponents() { @@ -94,10 +94,8 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { return true; } - private void update(boolean recreateDescriptor) { - if (recreateDescriptor) { - this.currentDescriptor = createDescriptor(); - } + private void update() { + this.currentDescriptor = createDescriptor(); setOKActionEnabled(checkNames()); signaturePreviewField.setText( @@ -116,7 +114,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { new DocumentAdapter() { @Override public void documentChanged(DocumentEvent event) { - update(true); + update(); } } ); @@ -130,7 +128,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { new ItemListener() { @Override public void itemStateChanged(@NotNull ItemEvent e) { - update(true); + update(); } } ); @@ -138,7 +136,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { parameterTablePanel = new KotlinParameterTablePanel() { @Override protected void updateSignature() { - KotlinExtractFunctionDialog.this.update(true); + KotlinExtractFunctionDialog.this.update(); } @Override From 6be8ea5b19e2855071695b1c62819ffaa18c3aed Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 20 Jun 2014 17:36:38 +0400 Subject: [PATCH 048/143] Minor: Replace deprecated function call --- .../refactoring/extractFunction/extractFunctionUtils.kt | 2 +- .../introduceVariable/AbstractJetExtractionTest.kt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index 5e732b9d507..2d276e5abea 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -880,7 +880,7 @@ fun ExtractionDescriptor.generateFunction( val callText = parameters .map { it.argumentText } - .makeString(separator = ", ", prefix = "$name(", postfix = ")") + .joinToString(separator = ", ", prefix = "$name(", postfix = ")") val wrappedCall = when (controlFlow) { is ExpressionEvaluationWithCallSiteReturn -> JetPsiFactory.createReturn(project, callText) diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt index 8e9e8feb446..46f1298e74a 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt @@ -75,7 +75,7 @@ public abstract class AbstractJetExtractionTest() : LightCodeInsightFixtureTestC val expectedTypes = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ") .mapTo(expectedParameterTypes) { "[$it]" } - .makeString() + .joinToString() val renderer = DescriptorRenderer.DEBUG_TEXT @@ -83,8 +83,8 @@ public abstract class AbstractJetExtractionTest() : LightCodeInsightFixtureTestC selectElements(editor, file) { (elements, previousSibling) -> ExtractKotlinFunctionHandler().doInvoke(editor, file, elements, explicitPreviousSibling ?: previousSibling) { val actualTypes = (ContainerUtil.createMaybeSingletonList(it.receiverParameter) + it.parameters).map { - it.parameterTypeCandidates.map { renderer.renderType(it) }. makeString(", ", "[", "]") - }.makeString() + it.parameterTypeCandidates.map { renderer.renderType(it) }. joinToString(", ", "[", "]") + }.joinToString() assertEquals(expectedTypes, actualTypes, "Expected types mismatch.") } @@ -108,7 +108,7 @@ public abstract class AbstractJetExtractionTest() : LightCodeInsightFixtureTestC JetTestUtils.assertEqualsToFile(afterFile, file.getText()!!) } catch(e: Exception) { - val message = if (e is ConflictsInTestsException) e.getMessages().sort().makeString(" ") else e.getMessage() + val message = if (e is ConflictsInTestsException) e.getMessages().sort().joinToString(" ") else e.getMessage() JetTestUtils.assertEqualsToFile(conflictFile, message?.replace("\n", " ") ?: e.javaClass.getName()) } } From 66405cf88315bcb663720030d8b410d8c88f4523 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 23 Jun 2014 20:20:31 +0400 Subject: [PATCH 049/143] Minor: Allow to select individual cells in Extract Function dialog --- .../extractFunction/ui/KotlinParameterTablePanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java index 0781b39f848..b0aa81aa5a1 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java @@ -118,6 +118,7 @@ public class KotlinParameterTablePanel extends JPanel { myTable.setTableHeader(null); myTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + myTable.setCellSelectionEnabled(true); TableColumn checkBoxColumn = myTable.getColumnModel().getColumn(MyTableModel.CHECKMARK_COLUMN); TableUtil.setupCheckboxColumn(checkBoxColumn); From d6755b91eea6700a3ad55881a13ef26247fb0f2c Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 23 Jun 2014 20:21:02 +0400 Subject: [PATCH 050/143] Minor: Remove unnecessary action binding --- .../ui/KotlinParameterTablePanel.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java index b0aa81aa5a1..72416c626b0 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ui/KotlinParameterTablePanel.java @@ -216,20 +216,6 @@ public class KotlinParameterTablePanel extends JPanel { } }); - // F2: edit parameter name - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "edit_parameter_name"); - actionMap.put("edit_parameter_name", new AbstractAction() { - @Override - public void actionPerformed(@NotNull ActionEvent e) { - if (!myTable.isEditing()) { - int row = myTable.getSelectedRow(); - if (row >= 0 && row < myTableModel.getRowCount()) { - TableUtil.editCellAt(myTable, row, MyTableModel.PARAMETER_NAME_COLUMN); - } - } - } - }); - // make ENTER work when the table has focus inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "invoke_impl"); actionMap.put("invoke_impl", new AbstractAction() { From 324040a02f0a8762593652e527a5774ff40ed1a7 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 10 Jun 2014 14:34:37 +0400 Subject: [PATCH 051/143] Java to Kotlin converter: no usage search and body analysis for members out of conversion scope --- .../plugin/actions/JavaToKotlinAction.java | 8 ++- .../actions/JavaToKotlinActionUtil.java | 15 +++-- .../copy/ConvertJavaCopyPastePostProcessor.kt | 28 ++++----- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 12 +++- .../jet/j2k/JavaToKotlinTranslator.kt | 7 +-- .../org/jetbrains/jet/j2k/TypeConverter.kt | 7 ++- .../test/AbstractJavaToKotlinConverterTest.kt | 57 +++++++++---------- 7 files changed, 67 insertions(+), 67 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java index e434f58b207..59779950ffb 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java @@ -26,9 +26,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiJavaFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.j2k.Converter; import org.jetbrains.jet.j2k.ConverterSettings; +import org.jetbrains.jet.j2k.FilesConversionScope; import java.util.List; @@ -43,7 +45,7 @@ public class JavaToKotlinAction extends AnAction { assert virtualFiles != null; final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); assert project != null; - final List selectedJavaFiles = getAllJavaFiles(virtualFiles, project); + final List selectedJavaFiles = getAllJavaFiles(virtualFiles, project); if (selectedJavaFiles.isEmpty()) { return; } @@ -77,8 +79,8 @@ public class JavaToKotlinAction extends AnAction { } @NotNull - private static Converter prepareConverter(@NotNull Project project, @NotNull List selectedJavaFiles) { - Converter converter = new Converter(project, ConverterSettings.defaultSettings); + private static Converter prepareConverter(@NotNull Project project, @NotNull List selectedJavaFiles) { + Converter converter = new Converter(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); converter.clearClassIdentifiers(); for (PsiFile f : selectedJavaFiles) { if (f.getFileType() instanceof JavaFileType) { diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java index 9f3c3c2729d..103a5462508 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.plugin.actions; -import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ex.MessagesEx; @@ -53,14 +52,14 @@ public class JavaToKotlinActionUtil { } @NotNull - /*package*/ static List getAllJavaFiles(@NotNull VirtualFile[] vFiles, Project project) { + /*package*/ static List getAllJavaFiles(@NotNull VirtualFile[] vFiles, Project project) { Set filesSet = allVirtualFiles(vFiles); PsiManager manager = PsiManager.getInstance(project); - List res = new ArrayList(); + List res = new ArrayList(); for (VirtualFile file : filesSet) { PsiFile psiFile = manager.findFile(file); - if (psiFile != null && psiFile.getFileType() instanceof JavaFileType) { - res.add(psiFile); + if (psiFile != null && psiFile instanceof PsiJavaFile) { + res.add((PsiJavaFile)psiFile); } } return res; @@ -92,7 +91,7 @@ public class JavaToKotlinActionUtil { } @NotNull - static List convertFiles(final Converter converter, List allJavaFilesNear) { + static List convertFiles(final Converter converter, List allJavaFilesNear) { final List result = new LinkedList(); for (final PsiFile f : allJavaFilesNear) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -108,7 +107,7 @@ public class JavaToKotlinActionUtil { return result; } - static void deleteFiles(List allJavaFilesNear) { + static void deleteFiles(List allJavaFilesNear) { for (final PsiFile f : allJavaFilesNear) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override @@ -150,7 +149,7 @@ public class JavaToKotlinActionUtil { return null; } - static void renameFiles(@NotNull List psiFiles) { + static void renameFiles(@NotNull List psiFiles) { for (final PsiFile f : psiFiles) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override diff --git a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt index 4ad242f2c06..143f9b75d50 100644 --- a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt @@ -48,44 +48,38 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor, value: TextBlockTransferableData) { - if (value !is CopiedCode) - return + if (value !is CopiedCode) return + val sourceFile = value.getFile() ?: return - if (value.getFile() == null) - return - - val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()) - if (file !is JetFile) - return + val targetFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()) + if (targetFile !is JetFile) return val jetEditorOptions = JetEditorOptions.getInstance()!! val needConvert = jetEditorOptions.isEnableJavaToKotlinConversion() && (jetEditorOptions.isDonTShowConversionDialog() || okFromDialog(project)) if (needConvert) { - val text = convertCopiedCodeToKotlin(value, file.getProject()) + val text = convertCopiedCodeToKotlin(value, sourceFile) if (text.isNotEmpty()) { ApplicationManager.getApplication()!!.runWriteAction { val startOffset = bounds.getStartOffset() editor.getDocument().replaceString(bounds.getStartOffset(), bounds.getEndOffset(), text) val endOffsetAfterCopy = startOffset + text.length() editor.getCaretModel().moveToOffset(endOffsetAfterCopy) - CodeStyleManager.getInstance(project)!!.reformatText(file, startOffset, endOffsetAfterCopy) - PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()) + CodeStyleManager.getInstance(project)!!.reformatText(targetFile, startOffset, endOffsetAfterCopy) + PsiDocumentManager.getInstance(targetFile.getProject()).commitDocument(editor.getDocument()) } } } } - private fun convertCopiedCodeToKotlin(code: CopiedCode, project: Project): String { - val converter = Converter(project, ConverterSettings.defaultSettings) + private fun convertCopiedCodeToKotlin(code: CopiedCode, file: PsiJavaFile): String { + val converter = Converter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) val startOffsets = code.getStartOffsets() val endOffsets = code.getEndOffsets() assert(startOffsets.size == endOffsets.size) { "Must have the same size" } @@ -93,7 +87,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor) : ConversionScope { + override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it } +} + +public class Converter(val project: Project, val settings: ConverterSettings, val conversionScope: ConversionScope) { + + private val typeConverter = TypeConverter(settings, conversionScope) private var classIdentifiersSet: MutableSet = HashSet() diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt index 4715ee6f6df..a15c8c21678 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt @@ -19,7 +19,6 @@ package org.jetbrains.jet.j2k import com.intellij.core.JavaCoreApplicationEnvironment import com.intellij.core.JavaCoreProjectEnvironment import com.intellij.lang.java.JavaLanguage -import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer import com.intellij.psi.PsiElement @@ -40,8 +39,8 @@ public object JavaToKotlinTranslator { return PsiFileFactory.getInstance(javaCoreEnvironment?.getProject())?.createFileFromText("test.java", JavaLanguage.INSTANCE, text) } - fun createFile(project: Project, text: String): PsiFile? { - return PsiFileFactory.getInstance(project)?.createFileFromText("test.java", JavaLanguage.INSTANCE, text) + fun createFile(project: Project, text: String): PsiJavaFile { + return PsiFileFactory.getInstance(project)?.createFileFromText("test.java", JavaLanguage.INSTANCE, text) as PsiJavaFile } fun setUpJavaCoreEnvironment(): JavaCoreProjectEnvironment { @@ -98,7 +97,7 @@ public object JavaToKotlinTranslator { fun generateKotlinCode(javaCode: String): String { val file = createFile(javaCode) if (file is PsiJavaFile) { - val converter = Converter(file.getProject(), ConverterSettings.defaultSettings) + val converter = Converter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) setClassIdentifiers(converter, file) return prettify(converter.convertFile(file).toKotlin()) } diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 3b379e08f97..1fa6f166021 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -22,7 +22,7 @@ import com.intellij.psi.* import org.jetbrains.jet.j2k.visitors.TypeVisitor import java.util.HashMap -class TypeConverter(val settings: ConverterSettings) { +class TypeConverter(val settings: ConverterSettings, val conversionScope: ConversionScope) { private val nullabilityCache = HashMap() public fun convertType(`type`: PsiType?, nullability: Nullability = Nullability.Default): Type { @@ -68,6 +68,8 @@ class TypeConverter(val settings: ConverterSettings) { } } + if (!conversionScope.contains(variable)) return nullability // do not analyze usages of fields out of our conversion scope + if (nullability == Nullability.Default) { val scope = searchScope(variable) if (scope != null) { @@ -114,6 +116,8 @@ class TypeConverter(val settings: ConverterSettings) { private fun methodNullabilityNoCache(method: PsiMethod): Nullability { var nullability = method.nullabilityFromAnnotations() + if (!conversionScope.contains(method)) return nullability // do not analyze body and usages of methods out of our conversion scope + if (nullability == Nullability.Default) { method.getBody()?.accept(object: JavaRecursiveElementVisitor() { override fun visitReturnStatement(statement: PsiReturnStatement) { @@ -196,7 +200,6 @@ class TypeConverter(val settings: ConverterSettings) { return when(this) { is PsiLocalVariable -> !hasWriteAccesses(getContainingMethod()) is PsiField -> if (hasModifierProperty(PsiModifier.PRIVATE)) !hasWriteAccesses(getContainingClass()) else false - is PsiParameter -> true else -> false } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index b988bff7328..d924e6e6f6f 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -33,6 +33,7 @@ import org.jetbrains.jet.JetTestUtils import com.intellij.openapi.project.Project import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.application.ApplicationManager +import org.jetbrains.jet.j2k.FilesConversionScope abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n") @@ -74,15 +75,14 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { else -> throw IllegalArgumentException("Unknown option: $name") } } - val converter = Converter(project, settings) val rawConverted = when (prefix) { - "element" -> elementToKotlin(converter, javaCode) - "expression" -> expressionToKotlin(converter, javaCode) - "statement" -> statementToKotlin(converter, javaCode) - "method" -> methodToKotlin(converter, javaCode) - "class" -> fileToKotlin(converter, javaCode) - "file" -> fileToKotlin(converter, javaCode) + "element" -> elementToKotlin(javaCode, settings, project) + "expression" -> expressionToKotlin(javaCode, settings, project) + "statement" -> statementToKotlin(javaCode, settings, project) + "method" -> methodToKotlin(javaCode, settings, project) + "class" -> fileToKotlin(javaCode, settings, project) + "file" -> fileToKotlin(javaCode, settings, project) else -> throw IllegalStateException("Specify what is it: file, class, method, statement or expression " + "using the first line of test data file") } @@ -114,42 +114,37 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { reformattedText } - private fun elementToKotlin(converter: Converter, text: String): String { - val fileWithText = JavaToKotlinTranslator.createFile(converter.project, text)!! + private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String { + val fileWithText = JavaToKotlinTranslator.createFile(project, text) + val converter = Converter(project, settings, FilesConversionScope(listOf(fileWithText))) val element = fileWithText.getFirstChild()!! return converter.elementToKotlin(element) } - private fun fileToKotlin(converter: Converter, text: String): String { - return generateKotlinCode(converter, JavaToKotlinTranslator.createFile(converter.project, text)) + private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { + val file = JavaToKotlinTranslator.createFile(project, text) + val converter = Converter(project, settings, FilesConversionScope(listOf(file))) + return generateKotlinCode(converter, file) } - private fun methodToKotlin(converter: Converter, text: String?): String { - var result = fileToKotlin(converter, "final class C {" + text + "}").replaceAll("class C\\(\\) \\{", "") - result = result.substring(0, (result.lastIndexOf("}"))).trim() - return result + private fun methodToKotlin(text: String, settings: ConverterSettings, project: Project): String { + val result = fileToKotlin("final class C {" + text + "}", settings, project).replaceAll("class C\\(\\) \\{", "") + return result.substring(0, (result.lastIndexOf("}"))).trim() } - private fun statementToKotlin(converter: Converter, text: String?): String { - var result = methodToKotlin(converter, "void main() {" + text + "}") - val pos = result.lastIndexOf("}") - result = result.substring(0, pos).replaceFirst("fun main\\(\\) \\{", "").trim() - return result + private fun statementToKotlin(text: String, settings: ConverterSettings, project: Project): String { + val result = methodToKotlin("void main() {" + text + "}", settings, project) + return result.substring(0, result.lastIndexOf("}")).replaceFirst("fun main\\(\\) \\{", "").trim() } - private fun expressionToKotlin(converter: Converter, code: String?): String { - var result = statementToKotlin(converter, "final Object o =" + code + "}") - result = result.replaceFirst("val o : Any\\? =", "").replaceFirst("val o : Any = ", "").replaceFirst("val o = ", "").trim() - return result + private fun expressionToKotlin(code: String, settings: ConverterSettings, project: Project): String { + val result = statementToKotlin("final Object o =" + code + "}", settings, project) + return result.replaceFirst("val o : Any\\? =", "").replaceFirst("val o : Any = ", "").replaceFirst("val o = ", "").trim() } - private fun generateKotlinCode(converter: Converter, file: PsiFile?): String { - if (file is PsiJavaFile) { - JavaToKotlinTranslator.setClassIdentifiers(converter, file) - return converter.elementToKotlin(file) - } - - return "" + private fun generateKotlinCode(converter: Converter, file: PsiJavaFile): String { + JavaToKotlinTranslator.setClassIdentifiers(converter, file) + return converter.elementToKotlin(file) } override fun getProjectJDK(): Sdk? { From 6fd8ac52367818df6844de5fe383aad8692f4aa4 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 10 Jun 2014 15:42:51 +0400 Subject: [PATCH 052/143] Java to Kotlin converter: no more setting 'class identifiers', use ConversionScope --- .../plugin/actions/JavaToKotlinAction.java | 16 +-------- .../actions/JavaToKotlinActionUtil.java | 8 ----- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 18 ++-------- .../jet/j2k/JavaToKotlinTranslator.kt | 9 ----- .../jet/j2k/visitors/ClassVisitor.kt | 36 ------------------- .../jet/j2k/visitors/ExpressionVisitor.kt | 27 +++++++------- .../test/AbstractJavaToKotlinConverterTest.kt | 7 +--- 7 files changed, 18 insertions(+), 103 deletions(-) delete mode 100644 j2k/src/org/jetbrains/jet/j2k/visitors/ClassVisitor.kt diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java index 59779950ffb..8404703307d 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.plugin.actions; -import com.intellij.ide.highlighter.JavaFileType; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -25,7 +24,6 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; import com.intellij.psi.PsiJavaFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.j2k.Converter; @@ -54,7 +52,7 @@ public class JavaToKotlinAction extends AnAction { return; } - final Converter converter = prepareConverter(project, selectedJavaFiles); + final Converter converter = new Converter(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); CommandProcessor.getInstance().executeCommand( project, new Runnable() { @@ -78,18 +76,6 @@ public class JavaToKotlinAction extends AnAction { ); } - @NotNull - private static Converter prepareConverter(@NotNull Project project, @NotNull List selectedJavaFiles) { - Converter converter = new Converter(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); - converter.clearClassIdentifiers(); - for (PsiFile f : selectedJavaFiles) { - if (f.getFileType() instanceof JavaFileType) { - setClassIdentifiers(converter, f); - } - } - return converter; - } - private static enum DialogResult { BACKUP_FILES, DELETE_FILES, diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java index 103a5462508..e52740e2a0b 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java @@ -28,19 +28,11 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.j2k.Converter; -import org.jetbrains.jet.j2k.visitors.ClassVisitor; import java.io.IOException; import java.util.*; public class JavaToKotlinActionUtil { - - static void setClassIdentifiers(@NotNull Converter converter, @NotNull PsiFile psiFile) { - ClassVisitor c = new ClassVisitor(); - psiFile.accept(c); - converter.setClassIdentifiers(new HashSet(c.getClassIdentifiers())); - } - @NotNull private static List getChildrenRecursive(@Nullable VirtualFile baseDir) { List result = new LinkedList(); diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index ff8f08858a3..da2413809e3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -37,25 +37,11 @@ public class Converter(val project: Project, val settings: ConverterSettings, va private val typeConverter = TypeConverter(settings, conversionScope) - private var classIdentifiersSet: MutableSet = HashSet() - private val dispatcher: Dispatcher = Dispatcher(this, typeConverter) public var methodReturnType: PsiType? = null private set - public fun setClassIdentifiers(identifiers: MutableSet) { - classIdentifiersSet = identifiers - } - - public fun getClassIdentifiers(): Set { - return Collections.unmodifiableSet(classIdentifiersSet) - } - - public fun clearClassIdentifiers() { - classIdentifiersSet.clear() - } - public fun elementToKotlin(element: PsiElement): String = convertTopElement(element)?.toKotlin() ?: "" @@ -307,9 +293,9 @@ public class Converter(val project: Project, val settings: ConverterSettings, va val containing = method.getContainingClass() if (containing != null) { val hasOtherJavaSuperclasses = containing.getSuperTypes().any { - val canonicalText = it.getCanonicalText() //TODO: correctly check for kotlin class - canonicalText != JAVA_LANG_OBJECT && !getClassIdentifiers().contains(canonicalText) + val `class` = it.resolve() + `class` != null && `class`.getQualifiedName() != JAVA_LANG_OBJECT && !conversionScope.contains(`class`) } if (hasOtherJavaSuperclasses) return true } diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt index a15c8c21678..88f488124c0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt @@ -25,7 +25,6 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiJavaFile -import org.jetbrains.jet.j2k.visitors.ClassVisitor import org.jetbrains.jet.utils.PathUtil import java.io.File import java.net.URLClassLoader @@ -87,18 +86,10 @@ public object JavaToKotlinTranslator { return null } - fun setClassIdentifiers(converter: Converter, psiFile: PsiElement) { - val c = ClassVisitor() - psiFile.accept(c) - converter.clearClassIdentifiers() - converter.setClassIdentifiers(HashSet(c.classIdentifiers)) - } - fun generateKotlinCode(javaCode: String): String { val file = createFile(javaCode) if (file is PsiJavaFile) { val converter = Converter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) - setClassIdentifiers(converter, file) return prettify(converter.convertFile(file).toKotlin()) } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ClassVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ClassVisitor.kt deleted file mode 100644 index 388707d8c58..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ClassVisitor.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2010-2013 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.j2k.visitors - -import com.intellij.psi.JavaRecursiveElementVisitor -import com.intellij.psi.PsiClass -import java.util.HashSet - -public open class ClassVisitor() : JavaRecursiveElementVisitor() { - private val _classIdentifiers = HashSet() - - public val classIdentifiers: Set - get() = _classIdentifiers - - override fun visitClass(aClass: PsiClass) { - val qName = aClass.getQualifiedName() - if (qName != null) { - _classIdentifiers.add(qName) - } - super.visitClass(aClass) - } -} diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index c8e06909f38..50202f2f6c3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -243,22 +243,23 @@ class ExpressionVisitor(private val converter: Converter, private fun createNewClassExpression(expression: PsiNewExpression): Expression { val anonymousClass = expression.getAnonymousClass() - val constructor = expression.resolveMethod() val classReference = expression.getClassOrAnonymousClassReference() - val isNotConvertedClass = classReference != null && !converter.getClassIdentifiers().contains(classReference.getQualifiedName()) - val argumentList = expression.getArgumentList() - var arguments = argumentList?.getExpressions() ?: array() - if (constructor == null || constructor.isPrimaryConstructor() || isNotConvertedClass) { - return NewClassExpression(converter.convertElement(classReference), - convertArguments(expression), - converter.convertExpression(expression.getQualifier()), - if (anonymousClass != null) converter.convertAnonymousClass(anonymousClass) else null) + var arguments = expression.getArgumentList()?.getExpressions() ?: array() + + val constructor = expression.resolveMethod() + if (constructor != null && !constructor.isPrimaryConstructor() && converter.conversionScope.contains(constructor)) { + //TODO: handle anonymous class! + // non-primary constructor converted to factory method in class object + val reference = expression.getClassReference() + val typeParameters = if (reference != null) typeConverter.convertTypes(reference.getTypeParameters()) else listOf() + return QualifiedExpression(Identifier(constructor.getName(), false), + MethodCallExpression(Identifier("init"), converter.convertExpressions(arguments), typeParameters, false)) } - val reference = expression.getClassReference() - val typeParameters = if (reference != null) typeConverter.convertTypes(reference.getTypeParameters()) else listOf() - return QualifiedExpression(Identifier(constructor.getName(), false), - MethodCallExpression(Identifier("init"), converter.convertExpressions(arguments), typeParameters, false)) + return NewClassExpression(converter.convertElement(classReference), + convertArguments(expression), + converter.convertExpression(expression.getQualifier()), + if (anonymousClass != null) converter.convertAnonymousClass(anonymousClass) else null) } private fun createNewEmptyArrayWithoutInitialization(expression: PsiNewExpression): Expression { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index d924e6e6f6f..c5e68d2fa7f 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -124,7 +124,7 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { val file = JavaToKotlinTranslator.createFile(project, text) val converter = Converter(project, settings, FilesConversionScope(listOf(file))) - return generateKotlinCode(converter, file) + return converter.elementToKotlin(file) } private fun methodToKotlin(text: String, settings: ConverterSettings, project: Project): String { @@ -142,11 +142,6 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { return result.replaceFirst("val o : Any\\? =", "").replaceFirst("val o : Any = ", "").replaceFirst("val o = ", "").trim() } - private fun generateKotlinCode(converter: Converter, file: PsiJavaFile): String { - JavaToKotlinTranslator.setClassIdentifiers(converter, file) - return converter.elementToKotlin(file) - } - override fun getProjectJDK(): Sdk? { return PluginTestCaseBase.jdkFromIdeaHome() } From f2ace97c6c0c5e16f51bea5d216ef21e385d937c Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 10 Jun 2014 15:44:52 +0400 Subject: [PATCH 053/143] Java to Kotlin converter: minor --- j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt index 13519d0dbce..0941f08a9af 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt @@ -19,6 +19,6 @@ package org.jetbrains.jet.j2k.visitors import org.jetbrains.jet.j2k.Converter import org.jetbrains.jet.j2k.TypeConverter -open class Dispatcher(converter: Converter, typeConverter: TypeConverter) { +class Dispatcher(converter: Converter, typeConverter: TypeConverter) { var expressionVisitor: ExpressionVisitor = ExpressionVisitor(converter, typeConverter) } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index db3ce2944fc..4702d1d1554 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -27,7 +27,7 @@ import org.jetbrains.jet.j2k.TypeConverter private val PRIMITIVE_TYPES_NAMES = JvmPrimitiveType.values().map { it.getName() } -open class TypeVisitor(private val converter: TypeConverter) : PsiTypeVisitor() { +class TypeVisitor(private val converter: TypeConverter) : PsiTypeVisitor() { override fun visitPrimitiveType(primitiveType: PsiPrimitiveType): Type { val name = primitiveType.getCanonicalText() return if (name == "void") { From a07dae97346738ba663e10f65de825ad3989534d Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 10 Jun 2014 18:08:40 +0400 Subject: [PATCH 054/143] Java to Kotlin converter: minor code refining --- .../ArrayWithoutInitializationExpression.kt | 46 +++++++------------ .../jet/j2k/ast/DummyStringExpression.kt | 3 +- j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 8 ++-- .../jet/j2k/visitors/ExpressionVisitor.kt | 18 ++------ 4 files changed, 26 insertions(+), 49 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt index d1432a41e10..631196362b9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt @@ -16,14 +16,9 @@ package org.jetbrains.jet.j2k.ast -open class ArrayWithoutInitializationExpression(val `type`: Type, val expressions: List) : Expression() { - override fun toKotlin(): String { - if (`type` is ArrayType) { - return constructInnerType(`type`, expressions) - } - - return getConstructorName(`type`, expressions.size() != 0) - } +open class ArrayWithoutInitializationExpression(val `type`: ArrayType, val expressions: List) : Expression() { + override fun toKotlin(): String + = constructInnerType(`type`, expressions) private fun constructInnerType(hostType: ArrayType, expressions: List): String { if (expressions.size() == 1) { @@ -38,30 +33,21 @@ open class ArrayWithoutInitializationExpression(val `type`: Type, val expression return getConstructorName(hostType, expressions.size() != 0) } - class object { - private open fun oneDim(`type`: Type, size: Expression): String { - return oneDim(`type`, size, "") - } + private fun oneDim(`type`: ArrayType, size: Expression, init: String = ""): String { + return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin() + init.withPrefix(", ") + ")" + } - private open fun oneDim(`type`: Type, size: Expression, init: String): String { - return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin() + init.withPrefix(", ") + ")" - } - - private open fun getConstructorName(`type`: Type, hasInit: Boolean): String { - return if (`type` is ArrayType) - when (`type`.elementType) { - is PrimitiveType -> - `type`.toNotNullType().toKotlin() - is ArrayType -> - if (hasInit) - `type`.toNotNullType().toKotlin() - else - "arrayOfNulls<" + `type`.elementType.toKotlin() + ">" - else -> - "arrayOfNulls<" + `type`.elementType.toKotlin() + ">" - } - else + private fun getConstructorName(`type`: ArrayType, hasInit: Boolean): String { + return when (`type`.elementType) { + is PrimitiveType -> `type`.toNotNullType().toKotlin() + is ArrayType -> + if (hasInit) + `type`.toNotNullType().toKotlin() + else + "arrayOfNulls<" + `type`.elementType.toKotlin() + ">" + else -> + "arrayOfNulls<" + `type`.elementType.toKotlin() + ">" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt index 607c7550262..3971b3acb04 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt @@ -16,7 +16,6 @@ package org.jetbrains.jet.j2k.ast - -open class DummyStringExpression(val string: String) : Expression() { +class DummyStringExpression(val string: String) : Expression() { override fun toKotlin(): String = string } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 122b3b90e7a..35c21717bde 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -75,13 +75,13 @@ trait Type : Element { override fun toString(): String = toKotlin() } -class ClassType(val `type`: Identifier, val parameters: List, nullability: Nullability, settings: ConverterSettings) +class ClassType(val `type`: Identifier, val typeArgs: List, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { override fun toKotlin(): String { // TODO change to map() when KT-2051 is fixed val parametersToKotlin = ArrayList() - for (param in parameters) { + for (param in typeArgs) { parametersToKotlin.add(param.toKotlin()) } var params: String = if (parametersToKotlin.size() == 0) @@ -92,8 +92,8 @@ class ClassType(val `type`: Identifier, val parameters: List, nullabili } - override fun toNotNullType(): Type = ClassType(`type`, parameters, Nullability.NotNull, settings) - override fun toNullableType(): Type = ClassType(`type`, parameters, Nullability.Nullable, settings) + override fun toNotNullType(): Type = ClassType(`type`, typeArgs, Nullability.NotNull, settings) + override fun toNullableType(): Type = ClassType(`type`, typeArgs, Nullability.Nullable, settings) } class ArrayType(val elementType: Type, nullability: Nullability, settings: ConverterSettings) diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 50202f2f6c3..e168941b40d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -231,10 +231,12 @@ class ExpressionVisitor(private val converter: Converter, override fun visitNewExpression(expression: PsiNewExpression) { if (expression.getArrayInitializer() != null) { - result = createNewEmptyArray(expression) + result = converter.convertExpression(expression.getArrayInitializer()) } - else if (expression.getArrayDimensions().size > 0) { - result = createNewEmptyArrayWithoutInitialization(expression) + else if (expression.getArrayDimensions().size > 0 && expression.getType() is PsiArrayType) { + result = ArrayWithoutInitializationExpression( + typeConverter.convertType(expression.getType(), Nullability.NotNull) as ArrayType, + converter.convertExpressions(expression.getArrayDimensions())) } else { result = createNewClassExpression(expression) @@ -262,16 +264,6 @@ class ExpressionVisitor(private val converter: Converter, if (anonymousClass != null) converter.convertAnonymousClass(anonymousClass) else null) } - private fun createNewEmptyArrayWithoutInitialization(expression: PsiNewExpression): Expression { - return ArrayWithoutInitializationExpression( - typeConverter.convertType(expression.getType(), Nullability.NotNull), - converter.convertExpressions(expression.getArrayDimensions())) - } - - private fun createNewEmptyArray(expression: PsiNewExpression): Expression { - return converter.convertExpression(expression.getArrayInitializer()) - } - override fun visitParenthesizedExpression(expression: PsiParenthesizedExpression) { result = ParenthesizedExpression(converter.convertExpression(expression.getExpression())) } From b71061eb5c491b26a6843b3a2f7c4d5b13a462fc Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 10 Jun 2014 18:30:58 +0400 Subject: [PATCH 055/143] Java to Kotlin converter: generate "!!." instead of "?." for nullable values #KT-3943 Fixed --- j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt | 7 ++----- .../jetbrains/jet/j2k/ast/MethodCallExpression.kt | 15 +++++++-------- .../testData/ast/annotations/jetbrainsNotNull.kt | 2 +- .../ast/annotations/jetbrainsNotNullChainExpr.kt | 6 +++--- .../assignmentExpression/nullability-settings.kt | 2 +- .../libraryMethodCallFromInstance-settings.kt | 4 ++-- j2k/tests/testData/ast/issues/kt-824-isDir.kt | 4 ++-- .../CorrectFunNullabilityDetected.kt | 2 +- .../kotlinApiAccess/CorrectNullabilityDetected.kt | 2 +- .../ast/nullability/NullableMethodDotAccess.kt | 4 ++-- .../ast/nullability/NullableVariableDotAccess.kt | 2 +- .../testData/ast/prefixOperator/nullableIf.kt | 2 +- 12 files changed, 24 insertions(+), 28 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index decdf5a7333..312452f741c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -73,14 +73,11 @@ class SuperExpression(val identifier: Identifier) : Expression() { class QualifiedExpression(val expression: Expression, val identifier: Expression) : Expression() { override val isNullable: Boolean - get() { - if (!expression.isEmpty && expression.isNullable) return true - return identifier.isNullable - } + get() = identifier.isNullable override fun toKotlin(): String { if (!expression.isEmpty) { - return operandToKotlin(expression) + (if (expression.isNullable) "?." else ".") + identifier.toKotlin() + return operandToKotlin(expression) + (if (expression.isNullable) "!!." else ".") + identifier.toKotlin() } return identifier.toKotlin() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 28aa928cea1..bea2bd5b9bd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -18,20 +18,19 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -open class MethodCallExpression( +class MethodCallExpression( val methodExpression: Expression, val arguments: List, val typeParameters: List, - val resultIsNullable: Boolean = false + override val isNullable: Boolean = false ) : Expression() { - override val isNullable: Boolean - get() = methodExpression.isNullable || resultIsNullable - override fun toKotlin(): String { - val typeParamsToKotlin: String = typeParameters.toKotlin(", ", "<", ">") - val argumentsMapped = arguments.map { it.toKotlin() } - return operandToKotlin(methodExpression) + typeParamsToKotlin + "(" + argumentsMapped.makeString(", ") + ")" + return operandToKotlin(methodExpression) + + typeParameters.toKotlin(", ", "<", ">") + + "(" + + arguments.map { it.toKotlin() }.makeString(", ") + + ")" } class object { diff --git a/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt b/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt index 7598605805e..c17e1652311 100644 --- a/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt +++ b/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt @@ -6,7 +6,7 @@ public class Test(str: String) { var myStr: String = "String2" public fun sout(str: String) { - System.out?.println(str) + System.out!!.println(str) } public fun dummy(str: String): String { diff --git a/j2k/tests/testData/ast/annotations/jetbrainsNotNullChainExpr.kt b/j2k/tests/testData/ast/annotations/jetbrainsNotNullChainExpr.kt index b3b71dabab0..8d6ab2860e1 100644 --- a/j2k/tests/testData/ast/annotations/jetbrainsNotNullChainExpr.kt +++ b/j2k/tests/testData/ast/annotations/jetbrainsNotNullChainExpr.kt @@ -15,8 +15,8 @@ class Bar() { class Test() { public fun test(barNotNull: Bar, barNullable: Bar?) { barNotNull.fooNotNull.execute() - barNotNull.fooNullable?.execute() - barNullable?.fooNotNull?.execute() - barNullable?.fooNullable?.execute() + barNotNull.fooNullable!!.execute() + barNullable!!.fooNotNull.execute() + barNullable!!.fooNullable!!.execute() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/assignmentExpression/nullability-settings.kt b/j2k/tests/testData/ast/assignmentExpression/nullability-settings.kt index 907706ff69f..cf6a283fc4e 100644 --- a/j2k/tests/testData/ast/assignmentExpression/nullability-settings.kt +++ b/j2k/tests/testData/ast/assignmentExpression/nullability-settings.kt @@ -6,6 +6,6 @@ class Foo() { fun foo(o: BitSet?) { val o2: BitSet? = o val foo: Int = 0 - foo = o2?.size()!! + foo = o2!!.size() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/callChainExpression/libraryMethodCallFromInstance-settings.kt b/j2k/tests/testData/ast/callChainExpression/libraryMethodCallFromInstance-settings.kt index 3a175bc155e..4225353cd8f 100644 --- a/j2k/tests/testData/ast/callChainExpression/libraryMethodCallFromInstance-settings.kt +++ b/j2k/tests/testData/ast/callChainExpression/libraryMethodCallFromInstance-settings.kt @@ -13,9 +13,9 @@ class User() { fun main() { val lib: Library = Library() lib.call() - lib.getString()?.isEmpty() + lib.getString()!!.isEmpty() Library().call() - Library().getString()?.isEmpty() + Library().getString()!!.isEmpty() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-824-isDir.kt b/j2k/tests/testData/ast/issues/kt-824-isDir.kt index a723949070d..a02066bb927 100644 --- a/j2k/tests/testData/ast/issues/kt-824-isDir.kt +++ b/j2k/tests/testData/ast/issues/kt-824-isDir.kt @@ -8,11 +8,11 @@ import java.io.File public class Test() { class object { public fun isDir(parent: File?): Boolean { - if (parent == null || !parent?.exists()!!) { + if (parent == null || !parent!!.exists()) { return false } val result = true - if (parent?.isDirectory()!!) { + if (parent!!.isDirectory()) { return true } else return false diff --git a/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.kt b/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.kt index 636dbbc12e0..fc60f982b07 100644 --- a/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.kt +++ b/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.kt @@ -2,6 +2,6 @@ import kotlinApi.* class A() { fun foo(t: KotlinTrait): Int { - return t.nullableFun()?.length()!! + t.notNullableFun().length() + return t.nullableFun()!!.length() + t.notNullableFun().length() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.kt b/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.kt index c6e87d24074..5f0a497b350 100644 --- a/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.kt +++ b/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.kt @@ -2,6 +2,6 @@ import kotlinApi.* class A() { fun foo(c: KotlinClass): Int { - return c.nullableProperty?.length()!! + c.property.length() + KotlinClass.nullableStaticVar!! + KotlinClass.staticVar + KotlinClass.nullableStaticFun(1)!! + KotlinClass.staticFun(1) + nullableGlobalFunction("")?.length()!! + globalFunction("").length() + return c.nullableProperty!!.length() + c.property.length() + KotlinClass.nullableStaticVar!! + KotlinClass.staticVar + KotlinClass.nullableStaticFun(1)!! + KotlinClass.staticFun(1) + nullableGlobalFunction("")!!.length() + globalFunction("").length() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.kt b/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.kt index efc5e709736..4bef51b9f32 100644 --- a/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.kt +++ b/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.kt @@ -4,6 +4,6 @@ class C() { } fun foo(): Int { - return getString(true)?.length()!! + return getString(true)!!.length() } -} \ No newline at end of file +} diff --git a/j2k/tests/testData/ast/nullability/NullableVariableDotAccess.kt b/j2k/tests/testData/ast/nullability/NullableVariableDotAccess.kt index 93b77147fd1..01480307817 100644 --- a/j2k/tests/testData/ast/nullability/NullableVariableDotAccess.kt +++ b/j2k/tests/testData/ast/nullability/NullableVariableDotAccess.kt @@ -1,5 +1,5 @@ fun foo(s: String?, b: Boolean): Int { if (s == null) System.out.println("null") - if (b) return s?.length()!! + if (b) return s!!.length() return 10 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/prefixOperator/nullableIf.kt b/j2k/tests/testData/ast/prefixOperator/nullableIf.kt index 209e96d341b..d294f76c13d 100644 --- a/j2k/tests/testData/ast/prefixOperator/nullableIf.kt +++ b/j2k/tests/testData/ast/prefixOperator/nullableIf.kt @@ -1,3 +1,3 @@ val s = null -if (!s?.isEmpty()!!) { +if (!s!!.isEmpty()) { } \ No newline at end of file From 1b948ef8f13a6862d999d6552da7a43b180d1d64 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 10 Jun 2014 18:45:07 +0400 Subject: [PATCH 056/143] Java to Kotlin converter: minor code refactoring --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 4 +-- .../jet/j2k/ast/MethodCallExpression.kt | 31 ++++++++++++++----- .../jet/j2k/visitors/ExpressionVisitor.kt | 28 +++++++++-------- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index da2413809e3..6331e6f5ec0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -481,7 +481,7 @@ public class Converter(val project: Project, val settings: ConverterSettings, va if (isConversionNeeded(actualType, expectedType) && expression !is LiteralExpression) { val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedType?.getCanonicalText()] if (conversion != null) { - expression = MethodCallExpression.build(expression, conversion) + expression = MethodCallExpression.buildNotNull(expression, conversion) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 312452f741c..2ff597097af 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -116,7 +116,7 @@ fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List null } if (conversionFunction != null) { - return MethodCallExpression(QualifiedExpression(initializer, Identifier(conversionFunction)), listOf(), listOf()) + return MethodCallExpression.buildNotNull(initializer, conversionFunction) } } } @@ -124,5 +124,5 @@ fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List, - val typeParameters: List, - override val isNullable: Boolean = false + val typeArguments: List, + override val isNullable: Boolean ) : Expression() { override fun toKotlin(): String { return operandToKotlin(methodExpression) + - typeParameters.toKotlin(", ", "<", ">") + + typeArguments.toKotlin(", ", "<", ">") + "(" + arguments.map { it.toKotlin() }.makeString(", ") + ")" } class object { - public fun build(receiver: Expression, methodName: String, arguments: List = ArrayList()): MethodCallExpression { - return MethodCallExpression(QualifiedExpression(receiver, Identifier(methodName, false)), + public fun buildNotNull(receiver: Expression?, + methodName: String, + arguments: List = listOf(), + typeArguments: List = listOf()): MethodCallExpression + = build(receiver, methodName, arguments, typeArguments, false) + + public fun buildNullable(receiver: Expression?, + methodName: String, + arguments: List = listOf(), + typeArguments: List = listOf()): MethodCallExpression + = build(receiver, methodName, arguments, typeArguments, true) + + public fun build(receiver: Expression?, + methodName: String, + arguments: List, + typeArguments: List, + isNullable: Boolean): MethodCallExpression { + val identifier = Identifier(methodName, false) + return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier) else identifier, arguments, - listOf(), - false) + typeArguments, + isNullable) } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index e168941b40d..e1ff68221f4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -82,7 +82,7 @@ class ExpressionVisitor(private val converter: Converter, val lhs = converter.convertExpression(expression.getLOperand(), expression.getType()) val rhs = converter.convertExpression(expression.getROperand(), expression.getType()) if (expression.getOperationSign().getTokenType() == JavaTokenType.GTGTGT) { - result = MethodCallExpression.build(lhs, "ushr", listOf(rhs)) + result = MethodCallExpression.buildNotNull(lhs, "ushr", listOf(rhs)) } else { result = BinaryExpression(lhs, rhs, getOperatorString(expression.getOperationSign().getTokenType())) @@ -91,7 +91,7 @@ class ExpressionVisitor(private val converter: Converter, override fun visitClassObjectAccessExpression(expression: PsiClassObjectAccessExpression) { val typeElement = converter.convertTypeElement(expression.getOperand()) - result = MethodCallExpression(Identifier("javaClass"), listOf(), listOf(typeElement.`type`.toNotNullType()), false) + result = MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(typeElement.`type`.toNotNullType())) } override fun visitConditionalExpression(expression: PsiConditionalExpression) { @@ -193,16 +193,18 @@ class ExpressionVisitor(private val converter: Converter, if (isTopLevel) { result = if (origin.isExtensionDeclaration()) { val qualifier = converter.convertExpression(arguments.firstOrNull()) - MethodCallExpression(QualifiedExpression(qualifier, Identifier(origin.getName()!!, false)), - convertArguments(expression, isExtension = true), - typeArguments, - isNullable) + MethodCallExpression.build(qualifier, + origin.getName()!!, + convertArguments(expression, isExtension = true), + typeArguments, + isNullable) } else { - MethodCallExpression(Identifier(origin.getName()!!, false), - convertArguments(expression), - typeArguments, - isNullable) + MethodCallExpression.build(null, + origin.getName()!!, + convertArguments(expression), + typeArguments, + isNullable) } return } @@ -255,7 +257,7 @@ class ExpressionVisitor(private val converter: Converter, val reference = expression.getClassReference() val typeParameters = if (reference != null) typeConverter.convertTypes(reference.getTypeParameters()) else listOf() return QualifiedExpression(Identifier(constructor.getName(), false), - MethodCallExpression(Identifier("init"), converter.convertExpressions(arguments), typeParameters, false)) + MethodCallExpression.buildNotNull(null, "init", converter.convertExpressions(arguments), typeParameters)) } return NewClassExpression(converter.convertElement(classReference), @@ -277,7 +279,7 @@ class ExpressionVisitor(private val converter: Converter, val operand = converter.convertExpression(expression.getOperand(), expression.getOperand()!!.getType()) val token = expression.getOperationTokenType() if (token == JavaTokenType.TILDE) { - result = MethodCallExpression.build(operand, "inv", ArrayList()) + result = MethodCallExpression.buildNotNull(operand, "inv") } else if (token == JavaTokenType.EXCL && operand is BinaryExpression && operand.op == "==") { // happens when equals is converted to == result = BinaryExpression(operand.left, operand.right, "!=") @@ -366,7 +368,7 @@ class ExpressionVisitor(private val converter: Converter, val typeText = castType.getType().getCanonicalText() val typeConversion = PRIMITIVE_TYPE_CONVERSIONS[typeText] if (operandType is PsiPrimitiveType && typeConversion != null) { - result = MethodCallExpression.build(converter.convertExpression(operand), typeConversion) + result = MethodCallExpression.buildNotNull(converter.convertExpression(operand), typeConversion) } else { result = TypeCastExpression(typeConverter.convertType(castType.getType()), From 149ea16f5cc84157adea1c7bcacc2562821070ff Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 13:07:13 +0400 Subject: [PATCH 057/143] Java to Kotlin converter: supported try-with-resource construct, fixed anonymous class generation + fixed a bug with method return type #KT-4488 Fixed --- .../plugin/actions/JavaToKotlinAction.java | 2 +- .../copy/ConvertJavaCopyPastePostProcessor.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 56 ++++++------ .../jet/j2k/JavaToKotlinTranslator.kt | 2 +- ...nonymousClass.kt => AnonymousClassBody.kt} | 6 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 13 +++ .../jet/j2k/ast/MethodCallExpression.kt | 44 +++++---- .../jet/j2k/ast/NewClassExpression.kt | 17 ++-- .../jetbrains/jet/j2k/visitors/Dispatcher.kt | 24 ----- .../jet/j2k/visitors/ElementVisitor.kt | 4 +- .../jet/j2k/visitors/ExpressionVisitor.kt | 5 +- .../jet/j2k/visitors/StatementVisitor.kt | 89 ++++++++++++++++--- .../test/AbstractJavaToKotlinConverterTest.kt | 4 +- .../JavaToKotlinConverterTestGenerated.java | 86 ++++++++++++++++-- j2k/tests/testData/KotlinApi.kt | 2 + ...ymousScope.java => newAnonymousClass.java} | 0 ...AnonymousScope.kt => newAnonymousClass.kt} | 2 +- .../newAnonymousClass2.java | 13 +++ .../newClassExpression/newAnonymousClass2.kt | 11 +++ .../newAnonymousClass3.java | 27 ++++++ .../newClassExpression/newAnonymousClass3.kt | 19 ++++ .../MethodReturnsNullInAnonymousClass.kt | 2 +- .../ast/returnStatement/CurrentMethodBug.java | 22 +++++ .../ast/returnStatement/currentMethodBug.kt | 19 ++++ .../ast/tryWithResource/Multiline.java | 12 +++ .../testData/ast/tryWithResource/Multiline.kt | 11 +++ .../tryWithResource/MultipleResources.java | 12 +++ .../ast/tryWithResource/MultipleResources.kt | 12 +++ .../testData/ast/tryWithResource/Simple.java | 10 +++ .../testData/ast/tryWithResource/Simple.kt | 7 ++ .../ast/tryWithResource/WithCatch.java | 15 ++++ .../testData/ast/tryWithResource/WithCatch.kt | 16 ++++ .../tryWithResource/WithCatchAndFinally.java | 18 ++++ .../tryWithResource/WithCatchAndFinally.kt | 17 ++++ .../ast/tryWithResource/WithCatches.java | 18 ++++ .../ast/tryWithResource/WithCatches.kt | 18 ++++ .../ast/tryWithResource/WithFinally.java | 15 ++++ .../ast/tryWithResource/WithFinally.kt | 15 ++++ .../ast/tryWithResource/WithReturn.java.todo | 17 ++++ .../ast/tryWithResource/WithReturnAtEnd.java | 16 ++++ .../ast/tryWithResource/WithReturnAtEnd.kt | 17 ++++ .../WithReturnInAnonymousClass.java | 23 +++++ .../WithReturnInAnonymousClass.kt | 21 +++++ .../WithReturnInAnonymousClass2.java | 23 +++++ .../WithReturnInAnonymousClass2.kt | 21 +++++ .../WithReturnInAnonymousClass3.java.todo | 26 ++++++ 46 files changed, 724 insertions(+), 107 deletions(-) rename j2k/src/org/jetbrains/jet/j2k/ast/{AnonymousClass.kt => AnonymousClassBody.kt} (86%) delete mode 100644 j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt rename j2k/tests/testData/ast/newClassExpression/{newClassWithAnonymousScope.java => newAnonymousClass.java} (100%) rename j2k/tests/testData/ast/newClassExpression/{newClassWithAnonymousScope.kt => newAnonymousClass.kt} (75%) create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt create mode 100644 j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java create mode 100644 j2k/tests/testData/ast/returnStatement/currentMethodBug.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/Multiline.java create mode 100644 j2k/tests/testData/ast/tryWithResource/Multiline.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/MultipleResources.java create mode 100644 j2k/tests/testData/ast/tryWithResource/MultipleResources.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/Simple.java create mode 100644 j2k/tests/testData/ast/tryWithResource/Simple.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatch.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatch.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatches.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatches.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithFinally.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithFinally.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java index 8404703307d..a8250c61b51 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java @@ -52,7 +52,7 @@ public class JavaToKotlinAction extends AnAction { return; } - final Converter converter = new Converter(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); + final Converter converter = Converter.object$.create(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); CommandProcessor.getInstance().executeCommand( project, new Runnable() { diff --git a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt index 143f9b75d50..ebeefcdcb73 100644 --- a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt @@ -79,7 +79,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor) : Conversi override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it } } -public class Converter(val project: Project, val settings: ConverterSettings, val conversionScope: ConversionScope) { +public class Converter private(val project: Project, val settings: ConverterSettings, val conversionScope: ConversionScope, val state: Converter.State) { + private class State(val typeConverter: TypeConverter, + val methodReturnType: PsiType?, + val expressionVisitorFactory: (Converter) -> ExpressionVisitor, + val statementVisitorFactory: (Converter) -> StatementVisitor) - private val typeConverter = TypeConverter(settings, conversionScope) + val typeConverter: TypeConverter get() = state.typeConverter + val methodReturnType: PsiType? get() = state.methodReturnType - private val dispatcher: Dispatcher = Dispatcher(this, typeConverter) + class object { + public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope): Converter + = Converter(project, settings, conversionScope, State(TypeConverter(settings, conversionScope), null, { ExpressionVisitor(it) }, { StatementVisitor(it) })) + } - public var methodReturnType: PsiType? = null - private set + fun withMethodReturnType(methodReturnType: PsiType?): Converter + = Converter(project, settings, conversionScope, State(typeConverter, methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory)) + + fun withExpressionVisitor(factory: (Converter) -> ExpressionVisitor): Converter + = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, factory, state.statementVisitorFactory)) + + fun withStatementVisitor(factory: (Converter) -> StatementVisitor): Converter + = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, state.expressionVisitorFactory, factory)) public fun elementToKotlin(element: PsiElement): String = convertTopElement(element)?.toKotlin() ?: "" @@ -65,8 +79,8 @@ public class Converter(val project: Project, val settings: ConverterSettings, va return File(fileMembers, createMainFunction(javaFile)) } - public fun convertAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass { - return AnonymousClass(this, convertClassBody(anonymousClass)) + public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { + return AnonymousClassBody(this, convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) } private fun convertClassBody(psiClass: PsiClass): List { @@ -216,7 +230,10 @@ public class Converter(val project: Project, val settings: ConverterSettings, va } private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { - methodReturnType = method.getReturnType() + return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove) + } + + private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { val returnType = typeConverter.convertMethodReturnType(method) val modifiers = convertModifiers(method) @@ -340,13 +357,8 @@ public class Converter(val project: Project, val settings: ConverterSettings, va usageReplacementMap.put(parameter, field.getName()!!) } } - dispatcher.expressionVisitor = ExpressionVisitor(this, typeConverter, usageReplacementMap) - try { - convertBlock(body, false, { !statementsToRemove.contains(it) }) - } - finally { - dispatcher.expressionVisitor = ExpressionVisitor(this, typeConverter, mapOf()) - } + + withExpressionVisitor { ExpressionVisitor(it, usageReplacementMap) }.convertBlock(body, false, { !statementsToRemove.contains(it) }) } else { Block.Empty @@ -409,7 +421,7 @@ public class Converter(val project: Project, val settings: ConverterSettings, va public fun convertStatement(statement: PsiStatement?): Statement { if (statement == null) return Statement.Empty - val statementVisitor: StatementVisitor = StatementVisitor(this) + val statementVisitor = state.statementVisitorFactory(this) statement.accept(statementVisitor) return statementVisitor.result } @@ -420,7 +432,7 @@ public class Converter(val project: Project, val settings: ConverterSettings, va public fun convertExpression(expression: PsiExpression?): Expression { if (expression == null) return Expression.Empty - val expressionVisitor = dispatcher.expressionVisitor + val expressionVisitor = state.expressionVisitorFactory(this) expression.accept(expressionVisitor) return expressionVisitor.result } @@ -428,19 +440,11 @@ public class Converter(val project: Project, val settings: ConverterSettings, va public fun convertElement(element: PsiElement?): Element { if (element == null) return Element.Empty - val elementVisitor = ElementVisitor(this, typeConverter) + val elementVisitor = ElementVisitor(this) element.accept(elementVisitor) return elementVisitor.result } - fun convertElements(elements: Array): List { - val result = ArrayList() - for (element in elements) { - result.add(convertElement(element)) - } - return result - } - public fun convertTypeElement(element: PsiTypeElement?): TypeElement = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())) diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt index 88f488124c0..355a5d846c5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt @@ -89,7 +89,7 @@ public object JavaToKotlinTranslator { fun generateKotlinCode(javaCode: String): String { val file = createFile(javaCode) if (file is PsiJavaFile) { - val converter = Converter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) + val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) return prettify(converter.convertFile(file).toKotlin()) } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt similarity index 86% rename from j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt rename to j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index ac6dc1a4c88..0b464a4778a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -19,11 +19,11 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.Collections -class AnonymousClass(converter: Converter, bodyElements: List) +class AnonymousClassBody(converter: Converter, bodyElements: List, val extendsTrait: Boolean) : Class(converter, - Identifier("anonClass"), + Identifier(""), MemberComments.Empty, - Collections.emptySet(), + setOf(), TypeParameterList.Empty, listOf(), listOf(), diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 2ff597097af..4082fa010b3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -91,6 +91,19 @@ class PolyadicExpression(val expressions: List, val token: String) : } } +class LambdaExpression(val arguments: String?, val statementList: StatementList) : Expression() { + override fun toKotlin(): String { + val statementsText = statementList.toKotlin().trim() + if (arguments != null) { + val br = if (statementsText.indexOf('\n') < 0 && statementsText.indexOf('\r') < 0) " " else "\n" + return "{ $arguments ->$br$statementsText }" + } + else { + return "{ $statementsText }" + } + } +} + fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List) : MethodCallExpression { val elementType = arrayType.elementType val createArrayFunction = if (elementType.isPrimitive()) { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 6f2c13cb2d2..aefcd1c5cc2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -16,46 +16,54 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList - class MethodCallExpression( val methodExpression: Expression, val arguments: List, val typeArguments: List, - override val isNullable: Boolean + override val isNullable: Boolean, + val lambdaArgument: LambdaExpression? = null ) : Expression() { override fun toKotlin(): String { - return operandToKotlin(methodExpression) + - typeArguments.toKotlin(", ", "<", ">") + - "(" + - arguments.map { it.toKotlin() }.makeString(", ") + - ")" + val builder = StringBuilder() + builder.append(operandToKotlin(methodExpression)) + builder.append(typeArguments.toKotlin(", ", "<", ">")) + if (arguments.isNotEmpty() || lambdaArgument == null) { + builder.append("(").append(arguments.map { it.toKotlin() }.makeString(", ")).append(")") + } + if (lambdaArgument != null) { + builder.append(lambdaArgument.toKotlin()) + } + return builder.toString() } class object { public fun buildNotNull(receiver: Expression?, - methodName: String, - arguments: List = listOf(), - typeArguments: List = listOf()): MethodCallExpression - = build(receiver, methodName, arguments, typeArguments, false) + methodName: String, + arguments: List = listOf(), + typeArguments: List = listOf(), + lambdaArgument: LambdaExpression? = null): MethodCallExpression + = build(receiver, methodName, arguments, typeArguments, false, lambdaArgument) public fun buildNullable(receiver: Expression?, - methodName: String, - arguments: List = listOf(), - typeArguments: List = listOf()): MethodCallExpression - = build(receiver, methodName, arguments, typeArguments, true) + methodName: String, + arguments: List = listOf(), + typeArguments: List = listOf(), + lambdaArgument: LambdaExpression? = null): MethodCallExpression + = build(receiver, methodName, arguments, typeArguments, true, lambdaArgument) public fun build(receiver: Expression?, methodName: String, arguments: List, typeArguments: List, - isNullable: Boolean): MethodCallExpression { + isNullable: Boolean, + lambdaArgument: LambdaExpression? = null): MethodCallExpression { val identifier = Identifier(methodName, false) return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier) else identifier, arguments, typeArguments, - isNullable) + isNullable, + lambdaArgument) } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt index 45fff2a8fde..77e4427e170 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt @@ -16,20 +16,25 @@ package org.jetbrains.jet.j2k.ast -open class NewClassExpression( +class NewClassExpression( val name: Element, val arguments: List, val qualifier: Expression = Expression.Empty, - val anonymousClass: AnonymousClass? = null + val anonymousClass: AnonymousClassBody? = null ) : Expression() { override fun toKotlin(): String { - val callOperator = if (qualifier.isNullable) "?." else "." + val callOperator = if (qualifier.isNullable) "!!." else "." val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin() + callOperator val appliedArguments = arguments.toKotlin(", ") - return if (anonymousClass != null) - "object : " + qualifier + name.toKotlin() + "(" + appliedArguments + ")" + anonymousClass.toKotlin() - else + return if (anonymousClass != null) { + if (anonymousClass.extendsTrait) + "object : " + qualifier + name.toKotlin() + anonymousClass.toKotlin() + else + "object : " + qualifier + name.toKotlin() + "(" + appliedArguments + ")" + anonymousClass.toKotlin() + } + else{ qualifier + name.toKotlin() + "(" + appliedArguments + ")" + } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt deleted file mode 100644 index 0941f08a9af..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2010-2013 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.j2k.visitors - -import org.jetbrains.jet.j2k.Converter -import org.jetbrains.jet.j2k.TypeConverter - -class Dispatcher(converter: Converter, typeConverter: TypeConverter) { - var expressionVisitor: ExpressionVisitor = ExpressionVisitor(converter, typeConverter) -} diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt index 68410680a48..5323567154e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt @@ -20,7 +20,9 @@ import com.intellij.psi.* import org.jetbrains.jet.j2k.* import org.jetbrains.jet.j2k.ast.* -class ElementVisitor(private val converter: Converter, private val typeConverter: TypeConverter) : JavaElementVisitor() { +class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { + private val typeConverter = converter.typeConverter + public var result: Element = Element.Empty protected set diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index e1ff68221f4..35e234b3e6a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -36,8 +36,9 @@ import com.intellij.psi.impl.light.LightField import org.jetbrains.jet.lang.resolve.java.JvmAbi class ExpressionVisitor(private val converter: Converter, - private val typeConverter: TypeConverter, private val usageReplacementMap: Map = mapOf()) : JavaElementVisitor() { + private val typeConverter = converter.typeConverter + public var result: Expression = Expression.Empty protected set @@ -263,7 +264,7 @@ class ExpressionVisitor(private val converter: Converter, return NewClassExpression(converter.convertElement(classReference), convertArguments(expression), converter.convertExpression(expression.getQualifier()), - if (anonymousClass != null) converter.convertAnonymousClass(anonymousClass) else null) + if (anonymousClass != null) converter.convertAnonymousClassBody(anonymousClass) else null) } override fun visitParenthesizedExpression(expression: PsiParenthesizedExpression) { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index a0e5e85d440..6518a05bc97 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -23,10 +23,11 @@ import org.jetbrains.jet.j2k.countWriteAccesses import java.util.ArrayList import org.jetbrains.jet.j2k.hasWriteAccesses import org.jetbrains.jet.j2k.isInSingleLine +import org.jetbrains.jet.j2k.getContainingMethod -class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { +open class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { public var result: Statement = Statement.Empty - private set + protected set override fun visitAssertStatement(statement: PsiAssertStatement) { result = AssertStatement(converter.convertExpression(statement.getAssertCondition()), @@ -56,7 +57,7 @@ class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { } override fun visitDeclarationStatement(statement: PsiDeclarationStatement) { - result = DeclarationStatement(converter.convertElements(statement.getDeclaredElements())) + result = DeclarationStatement(statement.getDeclaredElements().map { converter.convertElement(it) }) } override fun visitDoWhileStatement(statement: PsiDoWhileStatement) { @@ -217,16 +218,76 @@ class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { result = ThrowStatement(converter.convertExpression(statement.getException())) } - override fun visitTryStatement(statement: PsiTryStatement) { - val catches = ArrayList() - val catchBlocks = statement.getCatchBlocks() - val catchBlockParameters = statement.getCatchBlockParameters() - for (i in 0..catchBlocks.size - 1) { - catches.add(CatchStatement(converter.convertParameter(catchBlockParameters[i], Nullability.NotNull), - converter.convertBlock(catchBlocks[i]))) + override fun visitTryStatement(tryStatement: PsiTryStatement) { + val tryBlock = tryStatement.getTryBlock() + val catchesConverted = run { + val catchBlocks = tryStatement.getCatchBlocks() + val catchBlockParameters = tryStatement.getCatchBlockParameters() + catchBlocks.indices.map { + CatchStatement(converter.convertParameter(catchBlockParameters[it], Nullability.NotNull), + converter.convertBlock(catchBlocks[it])) + } } - result = TryStatement(converter.convertBlock(statement.getTryBlock()), - catches, converter.convertBlock(statement.getFinallyBlock())) + val finallyConverted = converter.convertBlock(tryStatement.getFinallyBlock()) + + val resourceList = tryStatement.getResourceList() + if (resourceList != null) { + val variables = resourceList.getResourceVariables() + if (variables.isNotEmpty()) { + var wrapResultStatement: (Expression) -> Statement = { it } + var converterForBody = converter + + val returns = collectReturns(tryBlock) + //TODO: support other returns when non-local returns supported by Kotlin + if (returns.size == 1 && returns.single() == tryBlock!!.getStatements().last()) { + wrapResultStatement = { ReturnStatement(it) } + converterForBody = converter.withStatementVisitor { object : StatementVisitor(it) { + override fun visitReturnStatement(statement: PsiReturnStatement) { + if (statement == returns.single()) { + result = converter.convertExpression(statement.getReturnValue(), tryStatement.getContainingMethod()?.getReturnType()) + } + else { + super.visitReturnStatement(statement) + } + } + }} + } + + var bodyConverted = converterForBody.convertBlock(tryBlock) + var statementList = bodyConverted.statementList + var expression: Expression = Expression.Empty + for (variable in variables.reverse()) { + val lambda = LambdaExpression(Identifier(variable.getName()!!).toKotlin(), statementList) + expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda) + statementList = StatementList(listOf(expression)) + } + + if (catchesConverted.isEmpty() && finallyConverted.isEmpty) { + result = wrapResultStatement(expression) + return + } + + bodyConverted = Block(StatementList(listOf(wrapResultStatement(expression))), true) + result = TryStatement(bodyConverted, catchesConverted, finallyConverted) + return + } + } + + result = TryStatement(converter.convertBlock(tryBlock), catchesConverted, finallyConverted) + } + + private fun collectReturns(block: PsiCodeBlock?): Collection { + val returns = ArrayList() + block?.accept(object: JavaRecursiveElementVisitor() { + override fun visitReturnStatement(statement: PsiReturnStatement) { + returns.add(statement) + } + + override fun visitMethod(method: PsiMethod) { + // do not go inside any other method (e.g. in anonymous class) + } + }) + return returns } override fun visitWhileStatement(statement: PsiWhileStatement) { @@ -241,10 +302,10 @@ class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { override fun visitReturnStatement(statement: PsiReturnStatement) { val returnValue = statement.getReturnValue() val methodReturnType = converter.methodReturnType - val expression = (if (returnValue != null && methodReturnType != null) + val expression = if (returnValue != null && methodReturnType != null) converter.convertExpression(returnValue, methodReturnType) else - converter.convertExpression(returnValue)) + converter.convertExpression(returnValue) result = ReturnStatement(expression) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index c5e68d2fa7f..d1d2e21ea08 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -116,14 +116,14 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String { val fileWithText = JavaToKotlinTranslator.createFile(project, text) - val converter = Converter(project, settings, FilesConversionScope(listOf(fileWithText))) + val converter = Converter.create(project, settings, FilesConversionScope(listOf(fileWithText))) val element = fileWithText.getFirstChild()!! return converter.elementToKotlin(element) } private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { val file = JavaToKotlinTranslator.createFile(project, text) - val converter = Converter(project, settings, FilesConversionScope(listOf(file))) + val converter = Converter.create(project, settings, FilesConversionScope(listOf(file))) return converter.elementToKotlin(file) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index ad6d08d33fd..97953f10520 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("j2k/tests/testData/ast") -@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.KotlinExclusion.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) +@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.KotlinExclusion.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInAst() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true); @@ -1863,16 +1863,26 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/newClassExpression/genericClassInvocation.java"); } + @TestMetadata("newAnonymousClass.java") + public void testNewAnonymousClass() throws Exception { + doTest("j2k/tests/testData/ast/newClassExpression/newAnonymousClass.java"); + } + + @TestMetadata("newAnonymousClass2.java") + public void testNewAnonymousClass2() throws Exception { + doTest("j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java"); + } + + @TestMetadata("newAnonymousClass3.java") + public void testNewAnonymousClass3() throws Exception { + doTest("j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java"); + } + @TestMetadata("newClassByFullName.java") public void testNewClassByFullName() throws Exception { doTest("j2k/tests/testData/ast/newClassExpression/newClassByFullName.java"); } - @TestMetadata("newClassWithAnonymousScope.java") - public void testNewClassWithAnonymousScope() throws Exception { - doTest("j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.java"); - } - @TestMetadata("newInnerClass.java") public void testNewInnerClass() throws Exception { doTest("j2k/tests/testData/ast/newClassExpression/newInnerClass.java"); @@ -2203,6 +2213,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/returnStatement"), Pattern.compile("^(.+)\\.java$"), true); } + @TestMetadata("currentMethodBug.java") + public void testCurrentMethodBug() throws Exception { + doTest("j2k/tests/testData/ast/returnStatement/currentMethodBug.java"); + } + @TestMetadata("returnChar.java") public void testReturnChar() throws Exception { doTest("j2k/tests/testData/ast/returnStatement/returnChar.java"); @@ -2452,6 +2467,64 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } + @TestMetadata("j2k/tests/testData/ast/tryWithResource") + public static class TryWithResource extends AbstractJavaToKotlinConverterTest { + public void testAllFilesPresentInTryWithResource() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/tryWithResource"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("Multiline.java") + public void testMultiline() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/Multiline.java"); + } + + @TestMetadata("MultipleResources.java") + public void testMultipleResources() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/MultipleResources.java"); + } + + @TestMetadata("Simple.java") + public void testSimple() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/Simple.java"); + } + + @TestMetadata("WithCatch.java") + public void testWithCatch() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithCatch.java"); + } + + @TestMetadata("WithCatchAndFinally.java") + public void testWithCatchAndFinally() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java"); + } + + @TestMetadata("WithCatches.java") + public void testWithCatches() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithCatches.java"); + } + + @TestMetadata("WithFinally.java") + public void testWithFinally() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithFinally.java"); + } + + @TestMetadata("WithReturnAtEnd.java") + public void testWithReturnAtEnd() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java"); + } + + @TestMetadata("WithReturnInAnonymousClass.java") + public void testWithReturnInAnonymousClass() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java"); + } + + @TestMetadata("WithReturnInAnonymousClass2.java") + public void testWithReturnInAnonymousClass2() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java"); + } + + } + @TestMetadata("j2k/tests/testData/ast/typeCastExpression") public static class TypeCastExpression extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInTypeCastExpression() throws Exception { @@ -2677,6 +2750,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(ThrowStatement.class); suite.addTestSuite(Trait.class); suite.addTestSuite(TryStatement.class); + suite.addTestSuite(TryWithResource.class); suite.addTestSuite(TypeCastExpression.class); suite.addTestSuite(TypeParameters.class); suite.addTestSuite(VarArg.class); diff --git a/j2k/tests/testData/KotlinApi.kt b/j2k/tests/testData/KotlinApi.kt index 344233b6959..21eb3270a7e 100644 --- a/j2k/tests/testData/KotlinApi.kt +++ b/j2k/tests/testData/KotlinApi.kt @@ -19,6 +19,8 @@ public open class KotlinClass { public trait KotlinTrait { public fun nullableFun(): String? public fun notNullableFun(): String + + public fun nonAbstractFun(): Int = 1 } public fun globalFunction(s: String): String = s diff --git a/j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.java b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass.java similarity index 100% rename from j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.java rename to j2k/tests/testData/ast/newClassExpression/newAnonymousClass.java diff --git a/j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.kt b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass.kt similarity index 75% rename from j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.kt rename to j2k/tests/testData/ast/newClassExpression/newAnonymousClass.kt index 7c22181b2aa..da09fb6ea84 100644 --- a/j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.kt +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass.kt @@ -1,4 +1,4 @@ -object : Runnable() { +object : Runnable { override fun run() { System.out.println("Run") } diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java new file mode 100644 index 00000000000..dc732c71ca6 --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java @@ -0,0 +1,13 @@ +//file +abstract class A {} + +class C { + void foo() { + A a = new A() { + @Override + public String toString() { + return "a"; + } + }; + } +} diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt new file mode 100644 index 00000000000..e8d2763a65a --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt @@ -0,0 +1,11 @@ +abstract class A() + +class C() { + fun foo() { + val a = object : A() { + override fun toString(): String { + return "a" + } + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java new file mode 100644 index 00000000000..34283df60aa --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java @@ -0,0 +1,27 @@ +//file +import kotlinApi.KotlinTrait; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class C { + void foo() { + KotlinTrait t = new KotlinTrait() { + @Nullable + @Override + public String nullableFun() { + return null; + } + + @NotNull + @Override + public String notNullableFun() { + return ""; + } + + @Override + public int nonAbstractFun() { + return 0; + } + }; + } +} diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt new file mode 100644 index 00000000000..bd3ffc22d48 --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt @@ -0,0 +1,19 @@ +import kotlinApi.KotlinTrait + +class C() { + fun foo() { + val t = object : KotlinTrait { + override fun nullableFun(): String? { + return null + } + + override fun notNullableFun(): String { + return "" + } + + override fun nonAbstractFun(): Int { + return 0 + } + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt b/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt index 9dd3ed82b41..b3b27e608e2 100644 --- a/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt +++ b/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt @@ -4,7 +4,7 @@ trait Getter { class C() { fun foo(b: Boolean): String { - val getter = object : Getter() { + val getter = object : Getter { override fun get(): String? { return null } diff --git a/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java b/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java new file mode 100644 index 00000000000..688643d3a5d --- /dev/null +++ b/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java @@ -0,0 +1,22 @@ +//file +import org.jetbrains.annotations.Nullable; + +interface I { + int getInt(); +} + +class C { + @Nullable Object getObject() { + foo(new I() { + @Override + public int getInt() { + return 0; + } + }); + return string; + } + + void foo(I i) {} + + @Nullable String string; +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/returnStatement/currentMethodBug.kt b/j2k/tests/testData/ast/returnStatement/currentMethodBug.kt new file mode 100644 index 00000000000..1b5e724938a --- /dev/null +++ b/j2k/tests/testData/ast/returnStatement/currentMethodBug.kt @@ -0,0 +1,19 @@ +trait I { + public fun getInt(): Int +} + +class C() { + fun getObject(): Any? { + foo(object : I { + override fun getInt(): Int { + return 0 + } + }) + return string + } + + fun foo(i: I) { + } + + var string: String? = null +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/Multiline.java b/j2k/tests/testData/ast/tryWithResource/Multiline.java new file mode 100644 index 00000000000..4bc2473a748 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Multiline.java @@ -0,0 +1,12 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/Multiline.kt b/j2k/tests/testData/ast/tryWithResource/Multiline.kt new file mode 100644 index 00000000000..4319e413066 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Multiline.kt @@ -0,0 +1,11 @@ +import java.io.* + +public class C() { + fun foo() { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/MultipleResources.java b/j2k/tests/testData/ast/tryWithResource/MultipleResources.java new file mode 100644 index 00000000000..f3dc33b5a36 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/MultipleResources.java @@ -0,0 +1,12 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream input = new FileInputStream("foo"); + OutputStream output = new FileOutputStream("bar")) { + output.write(input.read()); + output.write(0); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt b/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt new file mode 100644 index 00000000000..544c6137ecf --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt @@ -0,0 +1,12 @@ +import java.io.* + +public class C() { + fun foo() { + FileInputStream("foo").use { input -> + FileOutputStream("bar").use { output -> + output.write(input.read()) + output.write(0) + } + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/Simple.java b/j2k/tests/testData/ast/tryWithResource/Simple.java new file mode 100644 index 00000000000..c07eaf8b42e --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Simple.java @@ -0,0 +1,10 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + System.out.println(stream.read()); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/Simple.kt b/j2k/tests/testData/ast/tryWithResource/Simple.kt new file mode 100644 index 00000000000..6d5d5cfacc2 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Simple.kt @@ -0,0 +1,7 @@ +import java.io.* + +public class C() { + fun foo() { + FileInputStream("foo").use { stream -> System.out.println(stream.read()) } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatch.java b/j2k/tests/testData/ast/tryWithResource/WithCatch.java new file mode 100644 index 00000000000..50e2bb22b68 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatch.java @@ -0,0 +1,15 @@ +//file +import java.io.*; + +public class C { + void foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + catch (IOException e) { + System.out.println(e); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatch.kt b/j2k/tests/testData/ast/tryWithResource/WithCatch.kt new file mode 100644 index 00000000000..dbce19f57cf --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatch.kt @@ -0,0 +1,16 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } catch (e: IOException) { + System.out.println(e) + } + + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java new file mode 100644 index 00000000000..76821717110 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java @@ -0,0 +1,18 @@ +//file +import java.io.*; + +public class C { + void foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + catch (IOException e) { + System.out.println(e); + } + finally { + System.out.println("Finally!"); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt new file mode 100644 index 00000000000..0f2747e0540 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt @@ -0,0 +1,17 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } catch (e: IOException) { + System.out.println(e) + } finally { + System.out.println("Finally!") + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatches.java b/j2k/tests/testData/ast/tryWithResource/WithCatches.java new file mode 100644 index 00000000000..91317aa109a --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatches.java @@ -0,0 +1,18 @@ +//file +import java.io.*; + +public class C { + void foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + catch (IOException e) { + System.out.println(e); + } + catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatches.kt b/j2k/tests/testData/ast/tryWithResource/WithCatches.kt new file mode 100644 index 00000000000..87634a2cf45 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatches.kt @@ -0,0 +1,18 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } catch (e: IOException) { + System.out.println(e) + } catch (e: Exception) { + System.err.println(e) + } + + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithFinally.java b/j2k/tests/testData/ast/tryWithResource/WithFinally.java new file mode 100644 index 00000000000..e6d40d475e1 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithFinally.java @@ -0,0 +1,15 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + finally { + // dispose something else + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithFinally.kt b/j2k/tests/testData/ast/tryWithResource/WithFinally.kt new file mode 100644 index 00000000000..f127ac2ee0f --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithFinally.kt @@ -0,0 +1,15 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } finally { + // dispose something else + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo b/j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo new file mode 100644 index 00000000000..27183fa29bc --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo @@ -0,0 +1,17 @@ +//file +import java.io.*; + +public class C { + int foo() { + try(InputStream stream = new FileInputStream("foo")) { + while(true) { + int c = stream.read(); + if (c < 0 || c > 127) return c; + } + } + catch (IOException e) { + System.out.println(e); + return -1; + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java new file mode 100644 index 00000000000..7a9be09c5ea --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java @@ -0,0 +1,16 @@ +//file +import java.io.*; + +public class C { + int foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + return c; + } + catch (IOException e) { + System.out.println(e); + return -1; + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt new file mode 100644 index 00000000000..f9fdc00d481 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt @@ -0,0 +1,17 @@ +import java.io.* + +public class C() { + fun foo(): Int { + try { + return FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + c + } + } catch (e: IOException) { + System.out.println(e) + return -1 + } + + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java new file mode 100644 index 00000000000..9bc3f676075 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java @@ -0,0 +1,23 @@ +//file +import java.io.*; + +interface I { + int doIt(InputStream stream) throws IOException; +} + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + bar(new I() { + @Override + public int doIt(InputStream stream) throws IOException { + return stream.available(); + } + }, stream); + } + } + + int bar(I i, InputStream stream) throws IOException { + return i.doIt(stream); + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt new file mode 100644 index 00000000000..326bf6b2abf --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt @@ -0,0 +1,21 @@ +import java.io.* + +trait I { + public fun doIt(stream: InputStream): Int +} + +public class C() { + fun foo() { + FileInputStream("foo").use { stream -> + bar(object : I { + override fun doIt(stream: InputStream): Int { + return stream.available() + } + }, stream) + } + } + + fun bar(i: I, stream: InputStream): Int { + return i.doIt(stream) + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java new file mode 100644 index 00000000000..4f1e06a7f2a --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java @@ -0,0 +1,23 @@ +//file +import java.io.*; + +interface I { + int doIt(InputStream stream) throws IOException; +} + +public class C { + int foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + return bar(new I() { + @Override + public int doIt(InputStream stream) throws IOException { + return stream.available(); + } + }, stream); + } + } + + int bar(I i, InputStream stream) throws IOException { + return i.doIt(stream); + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt new file mode 100644 index 00000000000..cbaf5dfeb4c --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt @@ -0,0 +1,21 @@ +import java.io.* + +trait I { + public fun doIt(stream: InputStream): Int +} + +public class C() { + fun foo(): Int { + return FileInputStream("foo").use { stream -> + bar(object : I { + override fun doIt(stream: InputStream): Int { + return stream.available() + } + }, stream) + } + } + + fun bar(i: I, stream: InputStream): Int { + return i.doIt(stream) + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo new file mode 100644 index 00000000000..1872fdbede8 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo @@ -0,0 +1,26 @@ +//file +import java.io.*; + +interface I { + int doIt(InputStream stream) throws IOException; +} + +public class C { + int foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + if (stream.read() >= 0) { + return bar(new I() { + @Override + public int doIt(InputStream stream) throws IOException { + return stream.available(); + } + }, stream); + } + } + return -1; + } + + int bar(I i, InputStream stream) throws IOException { + return i.doIt(stream); + } +} From ed290178d51e3801f1bc29741e80b8b51a168a95 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 13:17:51 +0400 Subject: [PATCH 058/143] Fixed KT-4437 Converter for java: do not generate assert with lambda for constant message #KT-4437 Fixed --- .../jetbrains/jet/j2k/ast/AssertStatement.kt | 28 ------------------- .../jet/j2k/visitors/StatementVisitor.kt | 16 +++++++++-- .../JavaToKotlinConverterTestGenerated.java | 5 ++++ .../ast/assertStatement/withStringDetail.kt | 2 +- .../assertStatement/withStringDetail2.java | 2 ++ .../ast/assertStatement/withStringDetail2.kt | 1 + 6 files changed, 23 insertions(+), 31 deletions(-) delete mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/AssertStatement.kt create mode 100644 j2k/tests/testData/ast/assertStatement/withStringDetail2.java create mode 100644 j2k/tests/testData/ast/assertStatement/withStringDetail2.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AssertStatement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AssertStatement.kt deleted file mode 100644 index a43fef22c9f..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AssertStatement.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2010-2013 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.j2k.ast - - -class AssertStatement(val condition: Expression, val detail: Expression) : Statement() { - override fun toKotlin(): String { - val lazyStringMessage = if (detail != Expression.Empty) - " {" + detail.toKotlin() + "}" - else - "" - return "assert(${condition.toKotlin()})$lazyStringMessage" - } -} diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index 6518a05bc97..04b61e433e9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -30,8 +30,20 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito protected set override fun visitAssertStatement(statement: PsiAssertStatement) { - result = AssertStatement(converter.convertExpression(statement.getAssertCondition()), - converter.convertExpression(statement.getAssertDescription())) + val descriptionExpr = statement.getAssertDescription() + val condition = converter.convertExpression(statement.getAssertCondition()) + if (descriptionExpr == null) { + result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition)) + } + else { + val description = converter.convertExpression(descriptionExpr) + if (descriptionExpr is PsiLiteralExpression) { + result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition, description)) + } + else { + result = MethodCallExpression.build(null, "assert", listOf(condition), listOf(), false, LambdaExpression(null, StatementList(listOf(description)))) + } + } } override fun visitBlockStatement(statement: PsiBlockStatement) { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 97953f10520..a968d0189bc 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -248,6 +248,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/assertStatement/withStringDetail.java"); } + @TestMetadata("withStringDetail2.java") + public void testWithStringDetail2() throws Exception { + doTest("j2k/tests/testData/ast/assertStatement/withStringDetail2.java"); + } + } @TestMetadata("j2k/tests/testData/ast/assignmentExpression") diff --git a/j2k/tests/testData/ast/assertStatement/withStringDetail.kt b/j2k/tests/testData/ast/assertStatement/withStringDetail.kt index dbf44bd5eb8..720ccd99f52 100644 --- a/j2k/tests/testData/ast/assertStatement/withStringDetail.kt +++ b/j2k/tests/testData/ast/assertStatement/withStringDetail.kt @@ -1 +1 @@ -assert(true) { "string details" } \ No newline at end of file +assert(true, "string details") \ No newline at end of file diff --git a/j2k/tests/testData/ast/assertStatement/withStringDetail2.java b/j2k/tests/testData/ast/assertStatement/withStringDetail2.java new file mode 100644 index 00000000000..c8b9e98482f --- /dev/null +++ b/j2k/tests/testData/ast/assertStatement/withStringDetail2.java @@ -0,0 +1,2 @@ +//statement +assert true : "string details:" + x; \ No newline at end of file diff --git a/j2k/tests/testData/ast/assertStatement/withStringDetail2.kt b/j2k/tests/testData/ast/assertStatement/withStringDetail2.kt new file mode 100644 index 00000000000..97aa2c8f30f --- /dev/null +++ b/j2k/tests/testData/ast/assertStatement/withStringDetail2.kt @@ -0,0 +1 @@ +assert(true) { "string details:" + x } \ No newline at end of file From b00316f93afbe5cb1a78f1645a1fe979aad34d87 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 15:18:53 +0400 Subject: [PATCH 059/143] Fixed KT-4417 Converter from java to kotlin incorrectly places nested classes under class object #KT-4417 Fixed --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 146 ++++++++++++------ .../jet/j2k/ast/AnonymousClassBody.kt | 6 +- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 36 +---- .../org/jetbrains/jet/j2k/ast/Constructors.kt | 1 - j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 11 +- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Members.kt | 69 ++++----- j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 4 +- .../JavaToKotlinConverterTestGenerated.java | 15 ++ .../ast/class/innerClassInInterface.java | 4 + .../ast/class/innerClassInInterface.kt | 3 + .../testData/ast/class/innerEmptyClass.kt | 2 +- j2k/tests/testData/ast/class/innerEnum.java | 8 + j2k/tests/testData/ast/class/innerEnum.kt | 7 + .../testData/ast/class/innerInterface.java | 4 + .../testData/ast/class/innerInterface.kt | 3 + .../testData/ast/class/innerStaticClass.kt | 4 +- j2k/tests/testData/ast/enum/emptyEnum.kt | 2 +- .../ast/enum/enumImplementsOneInterface.kt | 2 +- .../enum/enumImplementsSeveralInterfaces.kt | 2 +- j2k/tests/testData/ast/enum/internalEnum.kt | 2 +- j2k/tests/testData/ast/enum/privateEnum.kt | 2 +- j2k/tests/testData/ast/enum/protectedEnum.kt | 2 +- j2k/tests/testData/ast/enum/publicEnum.kt | 2 +- .../ast/newClassExpression/newInnerClass.kt | 2 +- .../newClassExpression/newStaticInnerClass.kt | 4 +- .../ast/superExpression/classAdotSuperFoo.kt | 2 +- .../ast/thisExpression/classAdotThisFoo.kt | 2 +- 29 files changed, 204 insertions(+), 147 deletions(-) create mode 100644 j2k/tests/testData/ast/class/innerClassInInterface.java create mode 100644 j2k/tests/testData/ast/class/innerClassInInterface.kt create mode 100644 j2k/tests/testData/ast/class/innerEnum.java create mode 100644 j2k/tests/testData/ast/class/innerEnum.kt create mode 100644 j2k/tests/testData/ast/class/innerInterface.java create mode 100644 j2k/tests/testData/ast/class/innerInterface.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 73a54ca35d0..d935e618f20 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -83,18 +83,65 @@ public class Converter private(val project: Project, val settings: ConverterSett return AnonymousClassBody(this, convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) } - private fun convertClassBody(psiClass: PsiClass): List { + private fun convertClassBody(psiClass: PsiClass): ClassBody { val membersToRemove = HashSet() - val convertedMembers = LinkedHashMap() + val convertedElements = LinkedHashMap() var inBody = false val lBrace = psiClass.getLBrace() for (element in psiClass.getChildren()) { if (element == lBrace) inBody = true if (inBody) { - convertedMembers.put(element, convertMember(element, membersToRemove)) + convertedElements.put(element, convertMember(element, membersToRemove)) } } - return convertedMembers.keySet().filter { !membersToRemove.contains(it) }.map { convertedMembers[it]!! } + + for(member in membersToRemove) { + convertedElements.remove(member) + } + + val membersMap = splitIntoMembers(convertedElements) + + val constructors = membersMap.values().filter { it.member is Constructor } + val primaryConstructor = constructors.map { it.member }.filterIsInstance(javaClass()).firstOrNull() + val secondaryConstructors = constructors.filter { it.member is SecondaryConstructor } + + val normalMembers = ArrayList() + val classObjectMembers = ArrayList() + for((psiMember, member) in membersMap) { + if (member.member is Constructor) continue + if (!psiClass.isEnum() && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) { + classObjectMembers.add(member) + } + else { + normalMembers.add(member) + } + } + + return ClassBody(primaryConstructor, + secondaryConstructors.toMemberList(), + normalMembers.toMemberList(), + classObjectMembers.toMemberList()) + + } + + private fun List.toMemberList() = MemberList(flatMap { it.elements }) + + private fun splitIntoMembers(elements: Map): Map { + val result = LinkedHashMap() + var currentGroup = ArrayList() + var lastMember: PsiMember? = null + for ((psiElement, element) in elements) { + currentGroup.add(element) + if (element is Member) { + result.put(psiElement as PsiMember, MemberWithComments(element, currentGroup)) + currentGroup = ArrayList() + lastMember = psiElement + } + } + if (lastMember != null) { + (result[lastMember]!!.elements as MutableList).addAll(currentGroup) + } + return result } private fun convertMember(element: PsiElement, membersToRemove: MutableSet): Element = when(element) { @@ -123,16 +170,16 @@ public class Converter private(val project: Project, val settings: ConverterSett val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes()) val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes()) val name = Identifier(psiClass.getName()!!) - val classBodyElements = ArrayList(convertClassBody(psiClass)) + var classBody = convertClassBody(psiClass) when { - psiClass.isInterface() -> return Trait(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBodyElements) + psiClass.isInterface() -> return Trait(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) - psiClass.isEnum() -> return Enum(this, name, getComments(psiClass), modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBodyElements) + psiClass.isEnum() -> return Enum(this, name, getComments(psiClass), modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) else -> { if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) { - generateArtificialPrimaryConstructor(name, classBodyElements) + classBody = generateArtificialPrimaryConstructor(name, classBody) } val baseClassParams: List = run { @@ -151,46 +198,52 @@ public class Converter private(val project: Project, val settings: ConverterSett modifiers.add(Modifier.OPEN) } - return Class(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBodyElements) + if (psiClass.getContainingClass() != null && !psiClass.hasModifierProperty(PsiModifier.STATIC)) { + modifiers.add(Modifier.INNER) + } + + return Class(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) } } } - private fun generateArtificialPrimaryConstructor(className: Identifier, classBodyElements: MutableList) { - val finalOrWithEmptyInitializerFields = classBodyElements.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.toKotlin().isEmpty() } + private fun generateArtificialPrimaryConstructor(className: Identifier, classBody: ClassBody): ClassBody { + assert(classBody.primaryConstructor == null) + + val finalOrWithEmptyInitializerFields = classBody.normalMembers.members.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.toKotlin().isEmpty() } val initializers = HashMap() - for (element in classBodyElements) { - if (element is SecondaryConstructor) { - for (field in finalOrWithEmptyInitializerFields) { - initializers.put(field.identifier.toKotlin(), getDefaultInitializer(field)) - } + for (constructor in classBody.secondaryConstructors.members) { + constructor as SecondaryConstructor - val newStatements = ArrayList() - for (statement in element.block!!.statements) { - var keepStatement = true - if (statement is AssignmentExpression) { - val assignee = statement.left - if (assignee is QualifiedExpression) { - for (field in finalOrWithEmptyInitializerFields) { - val id = field.identifier.toKotlin() - if (assignee.identifier.toKotlin().endsWith("." + id)) { - initializers.put(id, statement.right.toKotlin()) - keepStatement = false - } - - } - } - - } - - if (keepStatement) { - newStatements.add(statement) - } - - } - newStatements.add(0, DummyStringExpression("val __ = " + createPrimaryConstructorInvocation(className.toKotlin(), finalOrWithEmptyInitializerFields, initializers))) - element.block = Block(newStatements) + for (field in finalOrWithEmptyInitializerFields) { + initializers.put(field.identifier.toKotlin(), getDefaultInitializer(field)) } + + val newStatements = ArrayList() + for (statement in constructor.block!!.statements) { + var keepStatement = true + if (statement is AssignmentExpression) { + val assignee = statement.left + if (assignee is QualifiedExpression) { + for (field in finalOrWithEmptyInitializerFields) { + val id = field.identifier.toKotlin() + if (assignee.identifier.toKotlin().endsWith("." + id)) { + initializers.put(id, statement.right.toKotlin()) + keepStatement = false + } + + } + } + + } + + if (keepStatement) { + newStatements.add(statement) + } + + } + newStatements.add(0, DummyStringExpression("val __ = " + createPrimaryConstructorInvocation(className.toKotlin(), finalOrWithEmptyInitializerFields, initializers))) + constructor.block = Block(newStatements) } //TODO: comments? @@ -198,12 +251,10 @@ public class Converter private(val project: Project, val settings: ConverterSett val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var Parameter(field.identifier, field.`type`, varValModifier, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) } - classBodyElements.add(PrimaryConstructor(this, - MemberComments.Empty, - setOf(Modifier.PRIVATE), - ParameterList(parameters), - Block.Empty)) - classBodyElements.removeAll(finalOrWithEmptyInitializerFields) + + val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) + val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) }) + return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers) } private fun convertInitializer(initializer: PsiClassInitializer): Initializer { @@ -509,7 +560,6 @@ public class Converter private(val project: Project, val settings: ConverterSett private val MODIFIERS_MAP = listOf( PsiModifier.ABSTRACT to Modifier.ABSTRACT, - PsiModifier.STATIC to Modifier.STATIC, PsiModifier.PUBLIC to Modifier.PUBLIC, PsiModifier.PROTECTED to Modifier.PROTECTED, PsiModifier.PRIVATE to Modifier.PRIVATE diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index 0b464a4778a..3ce640ac8bd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -19,7 +19,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.Collections -class AnonymousClassBody(converter: Converter, bodyElements: List, val extendsTrait: Boolean) +class AnonymousClassBody(converter: Converter, body: ClassBody, val extendsTrait: Boolean) : Class(converter, Identifier(""), MemberComments.Empty, @@ -28,6 +28,6 @@ class AnonymousClassBody(converter: Converter, bodyElements: List, val listOf(), listOf(), listOf(), - bodyElements) { - override fun toKotlin() = bodyToKotlin() + body) { + override fun toKotlin() = body.toKotlin(null) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index 268fe1d8cfa..96887af8117 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -28,7 +28,7 @@ open class Class( val extendsTypes: List, val baseClassParams: List, val implementsTypes: List, - val bodyElements: List + val body: ClassBody ) : Member(comments, modifiers) { override fun toKotlin(): String = @@ -39,27 +39,13 @@ open class Class( primaryConstructorSignatureToKotlin() + implementTypesToKotlin() + typeParameterList.whereToKotlin().withPrefix(" ") + - bodyToKotlin() + body.toKotlin(this) protected open val keyword: String get() = "class" - protected val classMembers: ClassMembers = ClassMembers.fromBodyElements(bodyElements) - protected open fun primaryConstructorSignatureToKotlin(): String - = classMembers.primaryConstructor?.signatureToKotlin() ?: "()" - - protected fun primaryConstructorBodyToKotlin(): String { - val constructor = classMembers.primaryConstructor - if (constructor != null && !(constructor.block?.isEmpty ?: true)) { - return "\n" + constructor.bodyToKotlin() + "\n" - } - return "" - } - - private fun secondaryConstructorsAsStaticInitFunctions(): MemberList { - return MemberList(classMembers.secondaryConstructors.elements.map { if (it is SecondaryConstructor) it.toInitFunction(this) else it }) - } + = body.primaryConstructor?.signatureToKotlin() ?: "()" private fun baseClassSignatureWithParams(): List { if (keyword.equals("class") && extendsTypes.size() == 1) { @@ -91,18 +77,10 @@ open class Class( modifierList.add(Modifier.OPEN) } + if (modifiers.contains(Modifier.INNER)) { + modifierList.add(Modifier.INNER) + } + return modifierList.toKotlin() } - - fun bodyToKotlin(): String { - val innerBody = classMembers.nonStaticMembers.toKotlin() + primaryConstructorBodyToKotlin() + classObjectToKotlin() - return if (innerBody.trim().isNotEmpty()) " {" + innerBody + "}" else "" - } - - private fun classObjectToKotlin(): String { - val secondaryConstructorsAsStaticInitFunctions = secondaryConstructorsAsStaticInitFunctions() - val staticMembers = classMembers.staticMembers - if (secondaryConstructorsAsStaticInitFunctions.isEmpty() && staticMembers.isEmpty()) return "" - return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin()}${staticMembers.toKotlin()}}" - } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index fd47996ca5e..b1589bc8874 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -53,7 +53,6 @@ class SecondaryConstructor(converter: Converter, public fun toInitFunction(containingClass: Class): Function { val modifiers = HashSet(modifiers) - modifiers.add(Modifier.STATIC) val statements = ArrayList(block?.statements ?: listOf()) statements.add(ReturnStatement(Identifier("__"))) val block = Block(statements) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index b30e6bfd203..1b816c665de 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -27,12 +27,12 @@ class Enum( extendsTypes: List, baseClassParams: List, implementsTypes: List, - bodyElements: List + body: ClassBody ) : Class(converter, name, comments, modifiers, typeParameterList, - extendsTypes, baseClassParams, implementsTypes, bodyElements) { + extendsTypes, baseClassParams, implementsTypes, body) { override fun primaryConstructorSignatureToKotlin(): String - = classMembers.primaryConstructor?.signatureToKotlin() ?: "" + = body.primaryConstructor?.signatureToKotlin() ?: "" override fun toKotlin(): String { return modifiersToKotlin() + @@ -40,9 +40,6 @@ class Enum( primaryConstructorSignatureToKotlin() + typeParameterList.toKotlin() + implementTypesToKotlin() + - " {" + - classMembers.allMembers.toKotlin() + - primaryConstructorBodyToKotlin() + - "}" + body.toKotlin(this) } } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index ddd6248345f..03fb319b21a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -32,7 +32,7 @@ open class Field( override fun toKotlin(): String { val declaration = commentsToKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin() return if (initializer.isEmpty) - declaration + (if (isVal && !isStatic() && hasWriteAccesses) "" else " = " + getDefaultInitializer(this)) + declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this)) else declaration + " = " + initializer.toKotlin() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt index 746eb79237d..5b293c61692 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt @@ -17,6 +17,12 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList +import com.intellij.psi.PsiClass +import org.jetbrains.jet.j2k.Converter +import java.util.HashSet +import com.intellij.psi.PsiMember +import java.util.LinkedHashMap +import com.intellij.psi.PsiElement class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NoSpace) { class object { @@ -25,56 +31,43 @@ class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(e } abstract class Member(val comments: MemberComments, val modifiers: Set) : Element { - fun isStatic(): Boolean = modifiers.contains(Modifier.STATIC) fun commentsToKotlin(): String = comments.toKotlin() } //member itself and all the elements before it in the code (comments, whitespaces) -class MemberHolder(val member: Member, val elements: List) +class MemberWithComments(val member: Member, val elements: List) class MemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) { val members: List get() = elements.filter { it is Member }.map { it as Member } } -class ClassMembers private( +class ClassBody ( val primaryConstructor: PrimaryConstructor?, val secondaryConstructors: MemberList, - val allMembers: MemberList, - val staticMembers: MemberList, - val nonStaticMembers: MemberList) { - class object { - public fun fromBodyElements(elements: List): ClassMembers { - val groups = splitInGroups(elements) - val constructors = groups.filter { it.member is Constructor } - val primaryConstructor = constructors.map { it.member }.filterIsInstance(javaClass()).firstOrNull() - val secondaryConstructors = constructors.filter { it.member is SecondaryConstructor } - val nonConstructors = groups.filter { it.member !is Constructor } - val staticMembers = nonConstructors.filter { it.member.isStatic() } - val nonStaticMembers = nonConstructors.filter { !it.member.isStatic() } - return ClassMembers(primaryConstructor, - secondaryConstructors.toMemberList(), - nonConstructors.toMemberList(), - staticMembers.toMemberList(), - nonStaticMembers.toMemberList()) + val normalMembers: MemberList, + val classObjectMembers: MemberList) { + + fun toKotlin(containingClass: Class?): String { + val innerBody = normalMembers.toKotlin() + primaryConstructorBodyToKotlin() + classObjectToKotlin(containingClass) + return if (innerBody.trim().isNotEmpty()) " {" + innerBody + "}" else "" + } + + private fun primaryConstructorBodyToKotlin(): String { + val constructor = primaryConstructor + if (constructor != null && !(constructor.block?.isEmpty ?: true)) { + return "\n" + constructor.bodyToKotlin() + "\n" } + return "" + } + + private fun classObjectToKotlin(containingClass: Class?): String { + val secondaryConstructorsAsStaticInitFunctions = secondaryConstructorsAsStaticInitFunctions(containingClass) + if (secondaryConstructorsAsStaticInitFunctions.isEmpty() && classObjectMembers.isEmpty()) return "" + return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin()}${classObjectMembers.toKotlin()}}" + } + + private fun secondaryConstructorsAsStaticInitFunctions(containingClass: Class?): MemberList { + return MemberList(secondaryConstructors.elements.map { if (it is SecondaryConstructor && containingClass != null) it.toInitFunction(containingClass) else it }) } } - -private fun List.toMemberList() = MemberList(flatMap { it.elements }) - -private fun splitInGroups(elements: List): List { - val result = ArrayList>>() - var currentGroup = ArrayList() - for (element in elements) { - currentGroup.add(element) - if (element is Member) { - result.add(element to currentGroup) - currentGroup = ArrayList() - } - } - if (result.isNotEmpty()) { - result.last!!.second.addAll(currentGroup) - } - return result map { MemberHolder(it.first, it.second) } -} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt index 08883ac09fc..b8655b41024 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt @@ -20,10 +20,10 @@ enum class Modifier(val name: String) { PUBLIC: Modifier("public") PROTECTED: Modifier("protected") PRIVATE: Modifier("private") - STATIC: Modifier("static") ABSTRACT: Modifier("abstract") OPEN: Modifier("open") OVERRIDE: Modifier("override") + INNER: Modifier("inner") public fun toKotlin(): String = name } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index 4238c0bde6d..49d03da2868 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -28,9 +28,9 @@ class Trait( extendsTypes: List, baseClassParams: List, implementsTypes: List, - bodyElements: List + body: ClassBody ) : Class(converter, name, comments, modifiers, typeParameterList, - extendsTypes, baseClassParams, implementsTypes, bodyElements) { + extendsTypes, baseClassParams, implementsTypes, body) { override val keyword: String get() = "trait" diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index a968d0189bc..58f40257970 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -621,11 +621,26 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/class/genericClass.java"); } + @TestMetadata("innerClassInInterface.java") + public void testInnerClassInInterface() throws Exception { + doTest("j2k/tests/testData/ast/class/innerClassInInterface.java"); + } + @TestMetadata("innerEmptyClass.java") public void testInnerEmptyClass() throws Exception { doTest("j2k/tests/testData/ast/class/innerEmptyClass.java"); } + @TestMetadata("innerEnum.java") + public void testInnerEnum() throws Exception { + doTest("j2k/tests/testData/ast/class/innerEnum.java"); + } + + @TestMetadata("innerInterface.java") + public void testInnerInterface() throws Exception { + doTest("j2k/tests/testData/ast/class/innerInterface.java"); + } + @TestMetadata("innerStaticClass.java") public void testInnerStaticClass() throws Exception { doTest("j2k/tests/testData/ast/class/innerStaticClass.java"); diff --git a/j2k/tests/testData/ast/class/innerClassInInterface.java b/j2k/tests/testData/ast/class/innerClassInInterface.java new file mode 100644 index 00000000000..9e5d2fa1dbf --- /dev/null +++ b/j2k/tests/testData/ast/class/innerClassInInterface.java @@ -0,0 +1,4 @@ +//file +interface A { + class B {} +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/innerClassInInterface.kt b/j2k/tests/testData/ast/class/innerClassInInterface.kt new file mode 100644 index 00000000000..bf27807d862 --- /dev/null +++ b/j2k/tests/testData/ast/class/innerClassInInterface.kt @@ -0,0 +1,3 @@ +trait A { + public class B() +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/innerEmptyClass.kt b/j2k/tests/testData/ast/class/innerEmptyClass.kt index 316afd78138..b87118b1c28 100644 --- a/j2k/tests/testData/ast/class/innerEmptyClass.kt +++ b/j2k/tests/testData/ast/class/innerEmptyClass.kt @@ -1,3 +1,3 @@ class A() { - class B() + inner class B() } \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/innerEnum.java b/j2k/tests/testData/ast/class/innerEnum.java new file mode 100644 index 00000000000..ae26b82b66b --- /dev/null +++ b/j2k/tests/testData/ast/class/innerEnum.java @@ -0,0 +1,8 @@ +//file +class A { + enum E { + A, + B, + C + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/innerEnum.kt b/j2k/tests/testData/ast/class/innerEnum.kt new file mode 100644 index 00000000000..98202a1484b --- /dev/null +++ b/j2k/tests/testData/ast/class/innerEnum.kt @@ -0,0 +1,7 @@ +class A() { + enum class E { + A + B + C + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/innerInterface.java b/j2k/tests/testData/ast/class/innerInterface.java new file mode 100644 index 00000000000..5031f3345b2 --- /dev/null +++ b/j2k/tests/testData/ast/class/innerInterface.java @@ -0,0 +1,4 @@ +//file +class A { + interface I {} +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/innerInterface.kt b/j2k/tests/testData/ast/class/innerInterface.kt new file mode 100644 index 00000000000..344a7196097 --- /dev/null +++ b/j2k/tests/testData/ast/class/innerInterface.kt @@ -0,0 +1,3 @@ +class A() { + trait I +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/innerStaticClass.kt b/j2k/tests/testData/ast/class/innerStaticClass.kt index 21c9a0e2e11..86108fe20b2 100644 --- a/j2k/tests/testData/ast/class/innerStaticClass.kt +++ b/j2k/tests/testData/ast/class/innerStaticClass.kt @@ -1,5 +1,3 @@ class S() { - class object { - class Inner() - } + class Inner() } \ No newline at end of file diff --git a/j2k/tests/testData/ast/enum/emptyEnum.kt b/j2k/tests/testData/ast/enum/emptyEnum.kt index cf0c22de5bd..7bce4477266 100644 --- a/j2k/tests/testData/ast/enum/emptyEnum.kt +++ b/j2k/tests/testData/ast/enum/emptyEnum.kt @@ -1 +1 @@ -enum class A {} \ No newline at end of file +enum class A \ No newline at end of file diff --git a/j2k/tests/testData/ast/enum/enumImplementsOneInterface.kt b/j2k/tests/testData/ast/enum/enumImplementsOneInterface.kt index 09b2e590bef..da87d3bc15c 100644 --- a/j2k/tests/testData/ast/enum/enumImplementsOneInterface.kt +++ b/j2k/tests/testData/ast/enum/enumImplementsOneInterface.kt @@ -1 +1 @@ -enum class A : I {} \ No newline at end of file +enum class A : I \ No newline at end of file diff --git a/j2k/tests/testData/ast/enum/enumImplementsSeveralInterfaces.kt b/j2k/tests/testData/ast/enum/enumImplementsSeveralInterfaces.kt index 183b15c4fff..7aef4bc20ed 100644 --- a/j2k/tests/testData/ast/enum/enumImplementsSeveralInterfaces.kt +++ b/j2k/tests/testData/ast/enum/enumImplementsSeveralInterfaces.kt @@ -1 +1 @@ -enum class A : I0, I1, I2 {} \ No newline at end of file +enum class A : I0, I1, I2 \ No newline at end of file diff --git a/j2k/tests/testData/ast/enum/internalEnum.kt b/j2k/tests/testData/ast/enum/internalEnum.kt index 04f0bcf787a..6153151d301 100644 --- a/j2k/tests/testData/ast/enum/internalEnum.kt +++ b/j2k/tests/testData/ast/enum/internalEnum.kt @@ -1 +1 @@ -enum class Test {} \ No newline at end of file +enum class Test \ No newline at end of file diff --git a/j2k/tests/testData/ast/enum/privateEnum.kt b/j2k/tests/testData/ast/enum/privateEnum.kt index 3dc188a912b..9d651c5ae4a 100644 --- a/j2k/tests/testData/ast/enum/privateEnum.kt +++ b/j2k/tests/testData/ast/enum/privateEnum.kt @@ -1 +1 @@ -private enum class Test {} \ No newline at end of file +private enum class Test \ No newline at end of file diff --git a/j2k/tests/testData/ast/enum/protectedEnum.kt b/j2k/tests/testData/ast/enum/protectedEnum.kt index 0cfa23e3ab5..064c2ca3809 100644 --- a/j2k/tests/testData/ast/enum/protectedEnum.kt +++ b/j2k/tests/testData/ast/enum/protectedEnum.kt @@ -1 +1 @@ -protected enum class Test {} \ No newline at end of file +protected enum class Test \ No newline at end of file diff --git a/j2k/tests/testData/ast/enum/publicEnum.kt b/j2k/tests/testData/ast/enum/publicEnum.kt index 0059e39d75d..8fc2d84c388 100644 --- a/j2k/tests/testData/ast/enum/publicEnum.kt +++ b/j2k/tests/testData/ast/enum/publicEnum.kt @@ -1 +1 @@ -public enum class Test {} \ No newline at end of file +public enum class Test \ No newline at end of file diff --git a/j2k/tests/testData/ast/newClassExpression/newInnerClass.kt b/j2k/tests/testData/ast/newClassExpression/newInnerClass.kt index 48064b3ce9f..e7d3a2927cf 100644 --- a/j2k/tests/testData/ast/newClassExpression/newInnerClass.kt +++ b/j2k/tests/testData/ast/newClassExpression/newInnerClass.kt @@ -1,7 +1,7 @@ package org.test class OuterClass() { - class InnerClass() + inner class InnerClass() } class User() { diff --git a/j2k/tests/testData/ast/newClassExpression/newStaticInnerClass.kt b/j2k/tests/testData/ast/newClassExpression/newStaticInnerClass.kt index 5dea1cbe8f3..f55170cf603 100644 --- a/j2k/tests/testData/ast/newClassExpression/newStaticInnerClass.kt +++ b/j2k/tests/testData/ast/newClassExpression/newStaticInnerClass.kt @@ -1,9 +1,7 @@ package demo class Foo() { - class object { - class Bar() - } + class Bar() } class User() { diff --git a/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt b/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt index 3ed8769e54b..dbbc9f934db 100644 --- a/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt +++ b/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt @@ -3,7 +3,7 @@ class Base() { } class A() : Base() { - class C() { + inner class C() { fun test() { super@A.foo() } diff --git a/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt b/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt index 9cd50bbe58d..f8802aeaba4 100644 --- a/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt +++ b/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt @@ -4,7 +4,7 @@ class Base() { } class A() : Base() { - class C() { + inner class C() { fun test() { this@A.foo() } From ab714f168c4cff3341fddcd21f8944079983fd3c Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 16:17:05 +0400 Subject: [PATCH 060/143] Converter from Java: do not produce class object for just private methods + fixed bug with unnecessary static member qualification --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 22 ++++++++-- .../jet/j2k/visitors/ExpressionVisitor.kt | 2 +- .../JavaToKotlinConverterTestGenerated.java | 41 ++++++++++++++++++- .../ast/issues/doNotQualifyStatic.java | 10 +++++ .../testData/ast/issues/doNotQualifyStatic.kt | 12 ++++++ .../staticMembers/PrivateStaticMembers.java | 12 ++++++ .../ast/staticMembers/PrivateStaticMembers.kt | 16 ++++++++ .../staticMembers/PrivateStaticMethods1.java | 10 +++++ .../staticMembers/PrivateStaticMethods1.kt | 11 +++++ .../staticMembers/PrivateStaticMethods2.java | 14 +++++++ .../staticMembers/PrivateStaticMethods2.kt | 18 ++++++++ .../staticMembers/PrivateStaticMethods3.java | 15 +++++++ .../staticMembers/PrivateStaticMethods3.kt | 19 +++++++++ .../staticMembers/PrivateStaticMethods4.java | 15 +++++++ .../staticMembers/PrivateStaticMethods4.kt | 16 ++++++++ 15 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 j2k/tests/testData/ast/issues/doNotQualifyStatic.java create mode 100644 j2k/tests/testData/ast/issues/doNotQualifyStatic.kt create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.java create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.java create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.kt create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.java create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.kt create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.java create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.kt create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.java create mode 100644 j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index d935e618f20..2f0534fbde6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -95,7 +95,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } } - for(member in membersToRemove) { + for (member in membersToRemove) { convertedElements.remove(member) } @@ -105,11 +105,27 @@ public class Converter private(val project: Project, val settings: ConverterSett val primaryConstructor = constructors.map { it.member }.filterIsInstance(javaClass()).firstOrNull() val secondaryConstructors = constructors.filter { it.member is SecondaryConstructor } + // do not convert private static methods into class object if possible + val useClassObject = if (psiClass.isEnum()) { + false + } + else { + val members = membersMap.keySet().filter { it !is PsiMethod || !it.isConstructor() } + val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) } + val nestedClasses = members.filterIsInstance(javaClass()).filter { it.hasModifierProperty(PsiModifier.STATIC) } + if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) { + nestedClasses.any { nestedClass -> classObjectMembers.any { findMethodCalls(it as PsiMethod, nestedClass).isNotEmpty() } } + } + else { + true + } + } + val normalMembers = ArrayList() val classObjectMembers = ArrayList() - for((psiMember, member) in membersMap) { + for ((psiMember, member) in membersMap) { if (member.member is Constructor) continue - if (!psiClass.isEnum() && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) { + if (useClassObject && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) { classObjectMembers.add(member) } else { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 35e234b3e6a..49af8936c60 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -328,7 +328,7 @@ class ExpressionVisitor(private val converter: Converter, if (target is PsiMember && target.hasModifierProperty(PsiModifier.STATIC) && target.getContainingClass() != null - && PsiTreeUtil.getParentOfType(expression, javaClass()) != target.getContainingClass() + && !PsiTreeUtil.isAncestor(target.getContainingClass(), expression, true) && !isStaticallyImported(target, expression)) { var member: PsiMember = target var code = Identifier(referencedName).toKotlin() diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 58f40257970..fbd629f6dcb 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("j2k/tests/testData/ast") -@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.KotlinExclusion.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) +@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.KotlinExclusion.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInAst() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true); @@ -1476,6 +1476,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/issues/comments.java"); } + @TestMetadata("doNotQualifyStatic.java") + public void testDoNotQualifyStatic() throws Exception { + doTest("j2k/tests/testData/ast/issues/doNotQualifyStatic.java"); + } + @TestMetadata("kt-1016.java") public void testKt_1016() throws Exception { doTest("j2k/tests/testData/ast/issues/kt-1016.java"); @@ -2296,6 +2301,39 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } + @TestMetadata("j2k/tests/testData/ast/staticMembers") + public static class StaticMembers extends AbstractJavaToKotlinConverterTest { + public void testAllFilesPresentInStaticMembers() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/staticMembers"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("PrivateStaticMembers.java") + public void testPrivateStaticMembers() throws Exception { + doTest("j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.java"); + } + + @TestMetadata("PrivateStaticMethods1.java") + public void testPrivateStaticMethods1() throws Exception { + doTest("j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.java"); + } + + @TestMetadata("PrivateStaticMethods2.java") + public void testPrivateStaticMethods2() throws Exception { + doTest("j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.java"); + } + + @TestMetadata("PrivateStaticMethods3.java") + public void testPrivateStaticMethods3() throws Exception { + doTest("j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.java"); + } + + @TestMetadata("PrivateStaticMethods4.java") + public void testPrivateStaticMethods4() throws Exception { + doTest("j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.java"); + } + + } + @TestMetadata("j2k/tests/testData/ast/superExpression") public static class SuperExpression extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInSuperExpression() throws Exception { @@ -2763,6 +2801,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(ReturnStatement.class); suite.addTestSuite(Settings.class); suite.addTestSuite(StarProjectionType.class); + suite.addTestSuite(StaticMembers.class); suite.addTestSuite(SuperExpression.class); suite.addTestSuite(Switch.class); suite.addTestSuite(SynchronizedStatement.class); diff --git a/j2k/tests/testData/ast/issues/doNotQualifyStatic.java b/j2k/tests/testData/ast/issues/doNotQualifyStatic.java new file mode 100644 index 00000000000..21c3eddb23c --- /dev/null +++ b/j2k/tests/testData/ast/issues/doNotQualifyStatic.java @@ -0,0 +1,10 @@ +//file +class Outer { + public static Object o = new Object(); + + public static class Nested { + public void foo() { + o = null; + } + } +} diff --git a/j2k/tests/testData/ast/issues/doNotQualifyStatic.kt b/j2k/tests/testData/ast/issues/doNotQualifyStatic.kt new file mode 100644 index 00000000000..d9e1d59ea45 --- /dev/null +++ b/j2k/tests/testData/ast/issues/doNotQualifyStatic.kt @@ -0,0 +1,12 @@ +class Outer() { + + public class Nested() { + public fun foo() { + o = null + } + } + + class object { + public var o: Any? = Object() + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.java b/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.java new file mode 100644 index 00000000000..498381b2684 --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.java @@ -0,0 +1,12 @@ +//file +class A { + private static final String s = "abc"; + + public void foo() { + privateStatic1(); + privateStatic2(); + } + + private static void privateStatic1(){} + private static void privateStatic2(){} +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt b/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt new file mode 100644 index 00000000000..d02168a612e --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt @@ -0,0 +1,16 @@ +class A() { + + public fun foo() { + privateStatic1() + privateStatic2() + } + + class object { + private val s: String = "abc" + + private fun privateStatic1() { + } + private fun privateStatic2() { + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.java b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.java new file mode 100644 index 00000000000..9768e323943 --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.java @@ -0,0 +1,10 @@ +//file +class A { + public void foo() { + privateStatic1(); + privateStatic2(); + } + + private static void privateStatic1(){} + private static void privateStatic2(){} +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.kt b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.kt new file mode 100644 index 00000000000..229e28304da --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods1.kt @@ -0,0 +1,11 @@ +class A() { + public fun foo() { + privateStatic1() + privateStatic2() + } + + private fun privateStatic1() { + } + private fun privateStatic2() { + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.java b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.java new file mode 100644 index 00000000000..5b0423188fd --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.java @@ -0,0 +1,14 @@ +//file +class A { + public void foo() { + privateStatic1(); + privateStatic2(); + } + + public static void publicStatic(){ + privateStatic1(); + } + + private static void privateStatic1(){} + private static void privateStatic2(){} +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.kt b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.kt new file mode 100644 index 00000000000..3b82bb877b5 --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods2.kt @@ -0,0 +1,18 @@ +class A() { + public fun foo() { + privateStatic1() + privateStatic2() + } + + class object { + + public fun publicStatic() { + privateStatic1() + } + + private fun privateStatic1() { + } + private fun privateStatic2() { + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.java b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.java new file mode 100644 index 00000000000..126fea3b83b --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.java @@ -0,0 +1,15 @@ +//file +class A { + public static class Nested { + void foo() { + privateStatic1(); + } + } + + void bar() { + privateStatic2(); + } + + private static void privateStatic1(){} + private static void privateStatic2(){} +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.kt b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.kt new file mode 100644 index 00000000000..6790b6973dd --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods3.kt @@ -0,0 +1,19 @@ +class A() { + public class Nested() { + fun foo() { + privateStatic1() + } + } + + fun bar() { + privateStatic2() + } + + class object { + + private fun privateStatic1() { + } + private fun privateStatic2() { + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.java b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.java new file mode 100644 index 00000000000..b0696b6fa61 --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.java @@ -0,0 +1,15 @@ +//file +class A { + public class Inner { + void foo() { + privateStatic1(); + } + } + + void bar() { + privateStatic2(); + } + + private static void privateStatic1(){} + private static void privateStatic2(){} +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.kt b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.kt new file mode 100644 index 00000000000..31929271185 --- /dev/null +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMethods4.kt @@ -0,0 +1,16 @@ +class A() { + public inner class Inner() { + fun foo() { + privateStatic1() + } + } + + fun bar() { + privateStatic2() + } + + private fun privateStatic1() { + } + private fun privateStatic2() { + } +} \ No newline at end of file From c36624a58e305eba63e42a2cdbc4c3a1c0c7094b Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 16:21:50 +0400 Subject: [PATCH 061/143] Converter from Java: optimization to not instantiate visitor objects each time --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 7 +++++-- .../org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt | 4 ++++ j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 2f0534fbde6..a37cafc84e8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -42,6 +42,9 @@ public class Converter private(val project: Project, val settings: ConverterSett val typeConverter: TypeConverter get() = state.typeConverter val methodReturnType: PsiType? get() = state.methodReturnType + private val expressionVisitor = state.expressionVisitorFactory(this) + private val statementVisitor = state.statementVisitorFactory(this) + class object { public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope): Converter = Converter(project, settings, conversionScope, State(TypeConverter(settings, conversionScope), null, { ExpressionVisitor(it) }, { StatementVisitor(it) })) @@ -488,7 +491,7 @@ public class Converter private(val project: Project, val settings: ConverterSett public fun convertStatement(statement: PsiStatement?): Statement { if (statement == null) return Statement.Empty - val statementVisitor = state.statementVisitorFactory(this) + statementVisitor.reset() statement.accept(statementVisitor) return statementVisitor.result } @@ -499,7 +502,7 @@ public class Converter private(val project: Project, val settings: ConverterSett public fun convertExpression(expression: PsiExpression?): Expression { if (expression == null) return Expression.Empty - val expressionVisitor = state.expressionVisitorFactory(this) + expressionVisitor.reset() expression.accept(expressionVisitor) return expressionVisitor.result } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 49af8936c60..ee05a5c2bdc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -42,6 +42,10 @@ class ExpressionVisitor(private val converter: Converter, public var result: Expression = Expression.Empty protected set + public fun reset() { + result = Expression.Empty + } + override fun visitArrayAccessExpression(expression: PsiArrayAccessExpression) { val assignment = PsiTreeUtil.getParentOfType(expression, javaClass()) val lvalue = assignment != null && expression == assignment.getLExpression(); diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index 04b61e433e9..9719fe6dcf9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -29,6 +29,10 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito public var result: Statement = Statement.Empty protected set + public fun reset() { + result = Statement.Empty + } + override fun visitAssertStatement(statement: PsiAssertStatement) { val descriptionExpr = statement.getAssertDescription() val condition = converter.convertExpression(statement.getAssertCondition()) From da5fe7adb0b5b0b8f083d27b607dba9d64e10d0b Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 18:42:40 +0400 Subject: [PATCH 062/143] Converter from Java: better conversion from java-specific to Kotlin classes #KT-5173 Fixed --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 21 +++- .../org/jetbrains/jet/j2k/TypeConverter.kt | 18 +++- j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt | 2 +- .../jetbrains/jet/j2k/visitors/TypeVisitor.kt | 99 +++++++++---------- .../JavaToKotlinConverterTestGenerated.java | 45 ++++++--- .../javaLangDoubleArray.kt | 2 +- .../javaLangFloatArray.kt | 2 +- .../testData/ast/kotlinExclusion/kt-656.kt | 23 ----- .../IterableAndIterator.java} | 0 .../toKotlinClasses/TypeParameterBound.java | 8 ++ .../ast/toKotlinClasses/TypeParameterBound.kt | 7 ++ .../toKotlinClasses/iterableAndIterator.kt | 23 +++++ .../toKotlinClasses/iterableAndIterator2.java | 28 ++++++ .../toKotlinClasses/iterableAndIterator2.kt | 26 +++++ .../toKotlinClasses/iterableAndIterator3.java | 16 +++ .../toKotlinClasses/iterableAndIterator3.kt | 12 +++ 16 files changed, 238 insertions(+), 94 deletions(-) delete mode 100644 j2k/tests/testData/ast/kotlinExclusion/kt-656.kt rename j2k/tests/testData/ast/{kotlinExclusion/kt-656.java => toKotlinClasses/IterableAndIterator.java} (100%) create mode 100644 j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.java create mode 100644 j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.kt create mode 100644 j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.kt create mode 100644 j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.java create mode 100644 j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.kt create mode 100644 j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.java create mode 100644 j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index a37cafc84e8..8bb98e3d03f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -78,8 +78,25 @@ public class Converter private(val project: Project, val settings: ConverterSett } public fun convertFile(javaFile: PsiJavaFile): File { - val fileMembers = FileMemberList(javaFile.getChildren().map { convertTopElement(it) }.filterNotNull()) - return File(fileMembers, createMainFunction(javaFile)) + var convertedChildren = javaFile.getChildren().map { + if (it is PsiImportList) { + val importList = convertImportList(it) + typeConverter.importList = importList + importList + } + else { + convertTopElement(it) + } + }.filterNotNull() + + typeConverter.importList = null + if (typeConverter.importsToAdd.isNotEmpty()) { + val importList = convertedChildren.filterIsInstance(javaClass()).first() + val newImportList = ImportList(importList.imports + typeConverter.importsToAdd) + convertedChildren = convertedChildren.map { if (it == importList) newImportList else it } + } + + return File(FileMemberList(convertedChildren), createMainFunction(javaFile)) } public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 1fa6f166021..48345f04168 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -21,14 +21,30 @@ import org.jetbrains.jet.j2k.ast.Nullability import com.intellij.psi.* import org.jetbrains.jet.j2k.visitors.TypeVisitor import java.util.HashMap +import java.util.HashSet +import org.jetbrains.jet.j2k.ast.Import +import org.jetbrains.jet.j2k.ast.ImportList class TypeConverter(val settings: ConverterSettings, val conversionScope: ConversionScope) { private val nullabilityCache = HashMap() + private val classesToImport = HashSet() + + public var importList: ImportList? = null + set(value) { + $importList = value + importNames = importList?.imports?.mapTo(HashSet()) { it.name } ?: setOf() + + } + public var importNames: Set = setOf() + private set + + public val importsToAdd: Collection + get() = classesToImport.map { Import(it) } public fun convertType(`type`: PsiType?, nullability: Nullability = Nullability.Default): Type { if (`type` == null) return Type.Empty - val result = `type`.accept(TypeVisitor(this))!! + val result = `type`.accept(TypeVisitor(this, classesToImport))!! return when (nullability) { Nullability.NotNull -> result.toNotNullType() Nullability.Nullable -> result.toNullableType() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt index f939a873a5f..3219dd22112 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt @@ -28,7 +28,7 @@ class Import(val name: String) : Element { override fun toKotlin() = "import " + name } -class ImportList(private val imports: List) : Element { +class ImportList(public val imports: List) : Element { override val isEmpty: Boolean get() = imports.isEmpty() diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index 4702d1d1554..22b3258385b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -27,7 +27,7 @@ import org.jetbrains.jet.j2k.TypeConverter private val PRIMITIVE_TYPES_NAMES = JvmPrimitiveType.values().map { it.getName() } -class TypeVisitor(private val converter: TypeConverter) : PsiTypeVisitor() { +class TypeVisitor(private val converter: TypeConverter, private val classesToImport: MutableSet) : PsiTypeVisitor() { override fun visitPrimitiveType(primitiveType: PsiPrimitiveType): Type { val name = primitiveType.getCanonicalText() return if (name == "void") { @@ -68,40 +68,74 @@ class TypeVisitor(private val converter: TypeConverter) : PsiTypeVisitor() } } + private val toKotlinTypesMap = mapOf( + CommonClassNames.JAVA_LANG_OBJECT to "kotlin.Any", + CommonClassNames.JAVA_LANG_BYTE to "kotlin.Byte", + CommonClassNames.JAVA_LANG_CHARACTER to "kotlin.Char", + CommonClassNames.JAVA_LANG_DOUBLE to "kotlin.Double", + CommonClassNames.JAVA_LANG_FLOAT to "kotlin.Float", + CommonClassNames.JAVA_LANG_INTEGER to "kotlin.Int", + CommonClassNames.JAVA_LANG_LONG to "kotlin.Long", + CommonClassNames.JAVA_LANG_SHORT to "kotlin.Short", + CommonClassNames.JAVA_LANG_BOOLEAN to "kotlin.Boolean", + CommonClassNames.JAVA_LANG_ITERABLE to "kotlin.Iterable", + CommonClassNames.JAVA_UTIL_ITERATOR to "kotlin.Iterator", + CommonClassNames.JAVA_UTIL_LIST to "kotlin.List", + CommonClassNames.JAVA_UTIL_COLLECTION to "kotlin.Collection", + CommonClassNames.JAVA_UTIL_SET to "kotlin.Set", + CommonClassNames.JAVA_UTIL_MAP to "kotlin.Map" + ) + private fun constructClassTypeIdentifier(classType: PsiClassType): Identifier { val psiClass = classType.resolve() if (psiClass != null) { - val qualifiedName = psiClass.getQualifiedName() - when(qualifiedName) { - CommonClassNames.JAVA_LANG_ITERABLE -> return Identifier(CommonClassNames.JAVA_LANG_ITERABLE) - CommonClassNames.JAVA_UTIL_ITERATOR -> return Identifier(CommonClassNames.JAVA_UTIL_ITERATOR) - CommonClassNames.JAVA_UTIL_LIST -> return Identifier("MutableList") + val javaClassName = psiClass.getQualifiedName() + val kotlinClassName = toKotlinTypesMap[javaClassName] + if (kotlinClassName != null) { + val kotlinShortName = getShortName(kotlinClassName) + if (kotlinShortName == getShortName(javaClassName!!) && converter.importNames.contains(getPackageName(javaClassName) + ".*")) { + classesToImport.add(kotlinClassName) + } + return Identifier(kotlinShortName) } } - val classTypeName = createQualifiedName(classType) - if (classTypeName.isEmpty()) { - return Identifier(getClassTypeName(classType)) + if (classType is PsiClassReferenceType) { + val reference = classType.getReference() + if (reference.isQualified()) { + var result = Identifier(reference.getReferenceName()!!).toKotlin() + var qualifier = reference.getQualifier() + while (qualifier != null) { + val codeRefElement = qualifier as PsiJavaCodeReferenceElement + result = Identifier(codeRefElement.getReferenceName()!!).toKotlin() + "." + result + qualifier = codeRefElement.getQualifier() + } + return Identifier(result) + } } - return Identifier(classTypeName) + return Identifier(classType.getClassName() ?: "") } + private fun getPackageName(className: String): String = className.substring(0, className.lastIndexOf('.')) + private fun getShortName(className: String): String = className.substring(className.lastIndexOf('.') + 1) + private fun createRawTypesForResolvedReference(classType: PsiClassType): List { val typeParams = LinkedList() if (classType is PsiClassReferenceType) { - val reference = classType.getReference() - val resolve = reference.resolve() + val resolve = classType.getReference().resolve() if (resolve is PsiClass) { for (typeParam in resolve.getTypeParameters()) { val superTypes = typeParam.getSuperTypes() - val boundType = if (superTypes.size > 0) - ClassType(Identifier(getClassTypeName(superTypes[0])), + val boundType = if (superTypes.size > 0) { + ClassType(constructClassTypeIdentifier(superTypes[0]), converter.convertTypes(superTypes[0].getParameters()), Nullability.Default, converter.settings) - else + } + else { StarProjectionType() + } typeParams.add(boundType) } } @@ -121,39 +155,4 @@ class TypeVisitor(private val converter: TypeConverter) : PsiTypeVisitor() override fun visitEllipsisType(ellipsisType: PsiEllipsisType): Type { return VarArgType(converter.convertType(ellipsisType.getComponentType())) } - - private fun createQualifiedName(classType: PsiClassType): String { - if (classType is PsiClassReferenceType) { - val reference = classType.getReference() - if (reference.isQualified()) { - var result = Identifier(reference.getReferenceName()!!).toKotlin() - var qualifier = reference.getQualifier() - while (qualifier != null) { - val codeRefElement = qualifier as PsiJavaCodeReferenceElement - result = Identifier(codeRefElement.getReferenceName()!!).toKotlin() + "." + result - qualifier = codeRefElement.getQualifier() - } - return result - } - } - - return "" - } - - private fun getClassTypeName(classType: PsiClassType): String { - var canonicalTypeStr: String? = classType.getCanonicalText() - return when(canonicalTypeStr) { - CommonClassNames.JAVA_LANG_OBJECT -> "Any" - CommonClassNames.JAVA_LANG_BYTE -> "Byte" - CommonClassNames.JAVA_LANG_CHARACTER -> "Char" - CommonClassNames.JAVA_LANG_DOUBLE -> "Double" - CommonClassNames.JAVA_LANG_FLOAT -> "Float" - CommonClassNames.JAVA_LANG_INTEGER -> "Int" - CommonClassNames.JAVA_LANG_LONG -> "Long" - CommonClassNames.JAVA_LANG_SHORT -> "Short" - CommonClassNames.JAVA_LANG_BOOLEAN -> "Boolean" - - else -> classType.getClassName() ?: classType.getCanonicalText() - } - } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index fbd629f6dcb..21eebb3b267 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("j2k/tests/testData/ast") -@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.KotlinExclusion.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) +@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInAst() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true); @@ -1691,19 +1691,6 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } - @TestMetadata("j2k/tests/testData/ast/kotlinExclusion") - public static class KotlinExclusion extends AbstractJavaToKotlinConverterTest { - public void testAllFilesPresentInKotlinExclusion() throws Exception { - JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/kotlinExclusion"), Pattern.compile("^(.+)\\.java$"), true); - } - - @TestMetadata("kt-656.java") - public void testKt_656() throws Exception { - doTest("j2k/tests/testData/ast/kotlinExclusion/kt-656.java"); - } - - } - @TestMetadata("j2k/tests/testData/ast/labelStatement") public static class LabelStatement extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInLabelStatement() throws Exception { @@ -2434,6 +2421,34 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } + @TestMetadata("j2k/tests/testData/ast/toKotlinClasses") + public static class ToKotlinClasses extends AbstractJavaToKotlinConverterTest { + public void testAllFilesPresentInToKotlinClasses() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/toKotlinClasses"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("iterableAndIterator.java") + public void testIterableAndIterator() throws Exception { + doTest("j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.java"); + } + + @TestMetadata("iterableAndIterator2.java") + public void testIterableAndIterator2() throws Exception { + doTest("j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.java"); + } + + @TestMetadata("iterableAndIterator3.java") + public void testIterableAndIterator3() throws Exception { + doTest("j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.java"); + } + + @TestMetadata("TypeParameterBound.java") + public void testTypeParameterBound() throws Exception { + doTest("j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.java"); + } + + } + @TestMetadata("j2k/tests/testData/ast/trait") public static class Trait extends AbstractJavaToKotlinConverterTest { @TestMetadata("abstactInterface.java") @@ -2781,7 +2796,6 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(IsOperator.class); suite.addTestSuite(Issues.class); suite.addTestSuite(KotlinApiAccess.class); - suite.addTestSuite(KotlinExclusion.class); suite.addTestSuite(LabelStatement.class); suite.addTestSuite(List.class); suite.addTestSuite(LiteralExpression.class); @@ -2807,6 +2821,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(SynchronizedStatement.class); suite.addTestSuite(ThisExpression.class); suite.addTestSuite(ThrowStatement.class); + suite.addTestSuite(ToKotlinClasses.class); suite.addTestSuite(Trait.class); suite.addTestSuite(TryStatement.class); suite.addTestSuite(TryWithResource.class); diff --git a/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt b/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt index e45850509f1..d2060c45afe 100644 --- a/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt +++ b/j2k/tests/testData/ast/arrayInitializerExpression/javaLangDoubleArray.kt @@ -1 +1 @@ -val a = array(1.0, 2.0, 3.0) \ No newline at end of file +val a = array(1.0, 2.0, 3.0) \ No newline at end of file diff --git a/j2k/tests/testData/ast/arrayInitializerExpression/javaLangFloatArray.kt b/j2k/tests/testData/ast/arrayInitializerExpression/javaLangFloatArray.kt index f7863159886..34498907cd2 100644 --- a/j2k/tests/testData/ast/arrayInitializerExpression/javaLangFloatArray.kt +++ b/j2k/tests/testData/ast/arrayInitializerExpression/javaLangFloatArray.kt @@ -1 +1 @@ -val a = array(1.0, 2.0, 3.0) \ No newline at end of file +val a = array(1.0, 2.0, 3.0) \ No newline at end of file diff --git a/j2k/tests/testData/ast/kotlinExclusion/kt-656.kt b/j2k/tests/testData/ast/kotlinExclusion/kt-656.kt deleted file mode 100644 index c937addb228..00000000000 --- a/j2k/tests/testData/ast/kotlinExclusion/kt-656.kt +++ /dev/null @@ -1,23 +0,0 @@ -package demo - -class Test() : java.lang.Iterable { - override fun iterator(): java.util.Iterator? { - return null - } - - public fun push(i: java.util.Iterator): java.util.Iterator { - val j = i - return j - } -} - -class FullTest() : java.lang.Iterable { - override fun iterator(): java.util.Iterator? { - return null - } - - public fun push(i: java.util.Iterator): java.util.Iterator { - val j = i - return j - } -} \ No newline at end of file diff --git a/j2k/tests/testData/ast/kotlinExclusion/kt-656.java b/j2k/tests/testData/ast/toKotlinClasses/IterableAndIterator.java similarity index 100% rename from j2k/tests/testData/ast/kotlinExclusion/kt-656.java rename to j2k/tests/testData/ast/toKotlinClasses/IterableAndIterator.java diff --git a/j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.java b/j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.java new file mode 100644 index 00000000000..ab21c84b55a --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.java @@ -0,0 +1,8 @@ +//file +import java.util.*; + +interface I>> { +} + +class C implements I>> { +} diff --git a/j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.kt b/j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.kt new file mode 100644 index 00000000000..f385c2f6829 --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/TypeParameterBound.kt @@ -0,0 +1,7 @@ +import java.util.* +import kotlin.List +import kotlin.Iterator + +trait I>> + +class C() : I>> diff --git a/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.kt b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.kt new file mode 100644 index 00000000000..97687578f5e --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.kt @@ -0,0 +1,23 @@ +package demo + +class Test() : Iterable { + override fun iterator(): Iterator? { + return null + } + + public fun push(i: Iterator): Iterator { + val j = i + return j + } +} + +class FullTest() : Iterable { + override fun iterator(): Iterator? { + return null + } + + public fun push(i: Iterator): Iterator { + val j = i + return j + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.java b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.java new file mode 100644 index 00000000000..4edc5a4835c --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.java @@ -0,0 +1,28 @@ +//file +package demo; + +import java.util.*; + +class Test implements Iterable { + @Override + public Iterator iterator() { + return null; + } + + public Iterator push(Iterator i) { + Iterator j = i; + return j; + } +} + +class FullTest implements java.lang.Iterable { + @Override + public java.util.Iterator iterator() { + return null; + } + + public java.util.Iterator push(java.util.Iterator i) { + java.util.Iterator j = i; + return j; + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.kt b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.kt new file mode 100644 index 00000000000..868627c5061 --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator2.kt @@ -0,0 +1,26 @@ +package demo + +import java.util.* +import kotlin.Iterator + +class Test() : Iterable { + override fun iterator(): Iterator? { + return null + } + + public fun push(i: Iterator): Iterator { + val j = i + return j + } +} + +class FullTest() : Iterable { + override fun iterator(): Iterator? { + return null + } + + public fun push(i: Iterator): Iterator { + val j = i + return j + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.java b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.java new file mode 100644 index 00000000000..b6651131a14 --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.java @@ -0,0 +1,16 @@ +//file +package demo; + +import java.util.Iterator; + +class Test implements Iterable { + @Override + public Iterator iterator() { + return null; + } + + public Iterator push(Iterator i) { + Iterator j = i; + return j; + } +} diff --git a/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.kt b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.kt new file mode 100644 index 00000000000..c741d5c583c --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator3.kt @@ -0,0 +1,12 @@ +package demo + +class Test() : Iterable { + override fun iterator(): Iterator? { + return null + } + + public fun push(i: Iterator): Iterator { + val j = i + return j + } +} \ No newline at end of file From 93ba66b2a39d3c7d14409df1483f3977809bc262 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 18:47:02 +0400 Subject: [PATCH 063/143] Converter from Java: generate "create" for factory methods instead of "init" --- j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt | 2 +- .../jetbrains/jet/j2k/visitors/ExpressionVisitor.kt | 2 +- j2k/tests/testData/ast/class/kt-639.kt | 8 ++++---- .../testData/ast/constructors/allCallsPrimary.kt | 8 ++++---- .../testData/ast/constructors/allCallsPrimary2.kt | 8 ++++---- .../testData/ast/constructors/genericIdentifier.kt | 12 ++++++------ j2k/tests/testData/ast/constructors/identifier.kt | 12 ++++++------ .../testData/ast/constructors/privateConstructors.kt | 6 +++--- .../ast/constructors/withManyDefaultParams.kt | 6 +++--- j2k/tests/testData/ast/issues/kt-638.kt | 12 ++++++------ 10 files changed, 38 insertions(+), 38 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index b1589bc8874..1227f1793e9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -58,7 +58,7 @@ class SecondaryConstructor(converter: Converter, val block = Block(statements) val typeParameters = ArrayList() typeParameters.addAll(containingClass.typeParameterList.parameters) - return Function(converter, Identifier("init"), MemberComments.Empty, modifiers, + return Function(converter, Identifier("create"), MemberComments.Empty, modifiers, ClassType(containingClass.name, typeParameters, Nullability.NotNull, converter.settings), TypeParameterList(typeParameters), parameterList, block, false) } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index ee05a5c2bdc..43fe4f2f50a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -262,7 +262,7 @@ class ExpressionVisitor(private val converter: Converter, val reference = expression.getClassReference() val typeParameters = if (reference != null) typeConverter.convertTypes(reference.getTypeParameters()) else listOf() return QualifiedExpression(Identifier(constructor.getName(), false), - MethodCallExpression.buildNotNull(null, "init", converter.convertExpressions(arguments), typeParameters)) + MethodCallExpression.buildNotNull(null, "create", converter.convertExpressions(arguments), typeParameters)) } return NewClassExpression(converter.convertElement(classReference), diff --git a/j2k/tests/testData/ast/class/kt-639.kt b/j2k/tests/testData/ast/class/kt-639.kt index ddaee0f171b..b9d664921b9 100644 --- a/j2k/tests/testData/ast/class/kt-639.kt +++ b/j2k/tests/testData/ast/class/kt-639.kt @@ -4,11 +4,11 @@ import java.util.HashMap class Test private() { class object { - fun init(): Test { + fun create(): Test { val __ = Test() return __ } - fun init(s: String): Test { + fun create(s: String): Test { val __ = Test() return __ } @@ -20,7 +20,7 @@ class User() { val m = HashMap(1) val m2 = HashMap(10) - val t1 = Test.init() - val t2 = Test.init("") + val t1 = Test.create() + val t2 = Test.create("") } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/constructors/allCallsPrimary.kt b/j2k/tests/testData/ast/constructors/allCallsPrimary.kt index 59223e27a74..df84622b5c6 100644 --- a/j2k/tests/testData/ast/constructors/allCallsPrimary.kt +++ b/j2k/tests/testData/ast/constructors/allCallsPrimary.kt @@ -1,12 +1,12 @@ class C(arg1: Int, arg2: Int, arg3: Int) { class object { - fun init(arg1: Int, arg2: Int): C { + fun create(arg1: Int, arg2: Int): C { val __ = C(arg1, arg2, 0) return __ } - fun init(arg1: Int): C { + fun create(arg1: Int): C { val __ = C(arg1, 0, 0) return __ } @@ -17,8 +17,8 @@ public class User() { class object { public fun main() { val c1 = C(100, 100, 100) - val c2 = C.init(100, 100) - val c3 = C.init(100) + val c2 = C.create(100, 100) + val c3 = C.create(100) } } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/constructors/allCallsPrimary2.kt b/j2k/tests/testData/ast/constructors/allCallsPrimary2.kt index c1249fd7180..d52b169f49d 100644 --- a/j2k/tests/testData/ast/constructors/allCallsPrimary2.kt +++ b/j2k/tests/testData/ast/constructors/allCallsPrimary2.kt @@ -9,14 +9,14 @@ class C(val myArg1: Int) { class object { - fun init(arg1: Int, arg2: Int, arg3: Int): C { + fun create(arg1: Int, arg2: Int, arg3: Int): C { val __ = C(arg1) __.myArg2 = arg2 __.myArg3 = arg3 return __ } - fun init(arg1: Int, arg2: Int): C { + fun create(arg1: Int, arg2: Int): C { val __ = C(arg1) __.myArg2 = arg2 __.myArg3 = 0 @@ -28,8 +28,8 @@ class C(val myArg1: Int) { public class User() { class object { public fun main() { - val c1 = C.init(100, 100, 100) - val c2 = C.init(100, 100) + val c1 = C.create(100, 100, 100) + val c2 = C.create(100, 100) val c3 = C(100) } } diff --git a/j2k/tests/testData/ast/constructors/genericIdentifier.kt b/j2k/tests/testData/ast/constructors/genericIdentifier.kt index 0bbd7ccfb40..bd04550571f 100644 --- a/j2k/tests/testData/ast/constructors/genericIdentifier.kt +++ b/j2k/tests/testData/ast/constructors/genericIdentifier.kt @@ -7,18 +7,18 @@ public class Identifier private(private val myName: T, private var myHasDolla class object { - public fun init(name: T): Identifier { + public fun create(name: T): Identifier { val __ = Identifier(name, false) return __ } - public fun init(name: T, isNullable: Boolean): Identifier { + public fun create(name: T, isNullable: Boolean): Identifier { val __ = Identifier(name, false) __.myNullable = isNullable return __ } - public fun init(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier { + public fun create(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier { val __ = Identifier(name, hasDollar) __.myNullable = isNullable return __ @@ -29,9 +29,9 @@ public class Identifier private(private val myName: T, private var myHasDolla public class User() { class object { public fun main() { - val i1 = Identifier.init("name", false, true) - val i2 = Identifier.init("name", false) - val i3 = Identifier.init("name") + val i1 = Identifier.create("name", false, true) + val i2 = Identifier.create("name", false) + val i3 = Identifier.create("name") } } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/constructors/identifier.kt b/j2k/tests/testData/ast/constructors/identifier.kt index 5e6c067fe8f..065a38f2edd 100644 --- a/j2k/tests/testData/ast/constructors/identifier.kt +++ b/j2k/tests/testData/ast/constructors/identifier.kt @@ -7,18 +7,18 @@ public class Identifier private(private val myName: String, private var myHasDol class object { - public fun init(name: String): Identifier { + public fun create(name: String): Identifier { val __ = Identifier(name, false) return __ } - public fun init(name: String, isNullable: Boolean): Identifier { + public fun create(name: String, isNullable: Boolean): Identifier { val __ = Identifier(name, false) __.myNullable = isNullable return __ } - public fun init(name: String, hasDollar: Boolean, isNullable: Boolean): Identifier { + public fun create(name: String, hasDollar: Boolean, isNullable: Boolean): Identifier { val __ = Identifier(name, hasDollar) __.myNullable = isNullable return __ @@ -29,9 +29,9 @@ public class Identifier private(private val myName: String, private var myHasDol public class User() { class object { public fun main() { - val i1 = Identifier.init("name", false, true) - val i2 = Identifier.init("name", false) - val i3 = Identifier.init("name") + val i1 = Identifier.create("name", false, true) + val i2 = Identifier.create("name", false) + val i3 = Identifier.create("name") } } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/constructors/privateConstructors.kt b/j2k/tests/testData/ast/constructors/privateConstructors.kt index 884b005389f..60c966bb8ac 100644 --- a/j2k/tests/testData/ast/constructors/privateConstructors.kt +++ b/j2k/tests/testData/ast/constructors/privateConstructors.kt @@ -1,14 +1,14 @@ class C private(arg1: Int, arg2: Int, arg3: Int) { class object { - private fun init(arg1: Int, arg2: Int): C { + private fun create(arg1: Int, arg2: Int): C { val __ = C(arg1, arg2, 0) return __ } - public fun init(arg1: Int): C { + public fun create(arg1: Int): C { val __ = C(arg1, 0, 0) return __ } } -} \ No newline at end of file +} diff --git a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt index 9a651b687c1..10a1911bad5 100644 --- a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt +++ b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt @@ -1,12 +1,12 @@ public class Test private(private val myName: String, private var a: Boolean, private var b: Double, private var c: Float, private var d: Long, private var e: Int, private var f: Short, private var g: Char) { class object { - public fun init(): Test { + public fun create(): Test { val __ = Test(0, false, 0.toDouble(), 0.toFloat(), 0, 0, 0, ' ') return __ } - public fun init(name: String): Test { + public fun create(name: String): Test { val __ = Test(foo(name), false, 0.toDouble(), 0.toFloat(), 0, 0, 0, ' ') return __ } @@ -21,7 +21,7 @@ public class Test private(private val myName: String, private var a: Boolean, pr public class User() { class object { public fun main() { - val t = Test.init("name") + val t = Test.create("name") } } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-638.kt b/j2k/tests/testData/ast/issues/kt-638.kt index 5e8777317de..211646d6498 100644 --- a/j2k/tests/testData/ast/issues/kt-638.kt +++ b/j2k/tests/testData/ast/issues/kt-638.kt @@ -7,18 +7,18 @@ public class Identifier private(private val myName: T, private var myHasDolla class object { - public fun init(name: T): Identifier { + public fun create(name: T): Identifier { val __ = Identifier(name, false) return __ } - public fun init(name: T, isNullable: Boolean): Identifier { + public fun create(name: T, isNullable: Boolean): Identifier { val __ = Identifier(name, false) __.myNullable = isNullable return __ } - public fun init(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier { + public fun create(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier { val __ = Identifier(name, hasDollar) __.myNullable = isNullable return __ @@ -29,9 +29,9 @@ public class Identifier private(private val myName: T, private var myHasDolla public class User() { class object { public fun main(args: Array) { - val i1 = Identifier.init("name", false, true) - val i2 = Identifier.init("name", false) - val i3 = Identifier.init("name") + val i1 = Identifier.create("name", false, true) + val i2 = Identifier.create("name", false) + val i3 = Identifier.create("name") } } } From c0a535592836ff00fc328c03aa8248bedce49de0 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 21:54:20 +0400 Subject: [PATCH 064/143] Converter from Java: basic implementation of annotations conversion --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 78 ++++++++++++++++--- .../org/jetbrains/jet/j2k/ast/Annotation.kt | 34 ++++++++ .../jet/j2k/ast/AnonymousClassBody.kt | 12 +-- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 6 +- .../org/jetbrains/jet/j2k/ast/Constructors.kt | 11 ++- j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 10 +-- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 7 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 4 + j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 5 +- j2k/src/org/jetbrains/jet/j2k/ast/Function.kt | 16 ++-- .../org/jetbrains/jet/j2k/ast/Identifier.kt | 2 + j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Initializer.kt | 2 +- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 9 ++- j2k/src/org/jetbrains/jet/j2k/ast/Members.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 7 +- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 22 +++--- .../jet/j2k/visitors/ElementVisitor.kt | 11 +-- .../test/AbstractJavaToKotlinConverterTest.kt | 14 +++- .../JavaToKotlinConverterTestGenerated.java | 5 ++ j2k/tests/testData/JavaApi.java | 37 +++++++++ .../ast/annotations/annotationUsages.java | 11 +++ .../ast/annotations/annotationUsages.kt | 9 +++ 23 files changed, 242 insertions(+), 74 deletions(-) create mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt create mode 100644 j2k/tests/testData/JavaApi.java create mode 100644 j2k/tests/testData/ast/annotations/annotationUsages.java create mode 100644 j2k/tests/testData/ast/annotations/annotationUsages.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 8bb98e3d03f..142c9c8f741 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -72,6 +72,7 @@ public class Converter private(val project: Project, val settings: ConverterSett is PsiComment -> Comment(element.getText()!!) is PsiImportList -> convertImportList(element) is PsiImportStatementBase -> convertImport(element, false) + is PsiAnnotation -> convertAnnotation(element) is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: "")) is PsiWhiteSpace -> WhiteSpace(element.getText()!!) else -> null @@ -100,7 +101,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { - return AnonymousClassBody(this, convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) + return AnonymousClassBody(convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) } private fun convertClassBody(psiClass: PsiClass): ClassBody { @@ -201,6 +202,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } private fun convertClass(psiClass: PsiClass): Class { + val annotations = convertAnnotations(psiClass) val modifiers = convertModifiers(psiClass) val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList()) val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes()) @@ -209,9 +211,9 @@ public class Converter private(val project: Project, val settings: ConverterSett var classBody = convertClassBody(psiClass) when { - psiClass.isInterface() -> return Trait(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) + psiClass.isInterface() -> return Trait(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) - psiClass.isEnum() -> return Enum(this, name, getComments(psiClass), modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) + psiClass.isEnum() -> return Enum(name, getComments(psiClass), annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) else -> { if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) { @@ -238,7 +240,7 @@ public class Converter private(val project: Project, val settings: ConverterSett modifiers.add(Modifier.INNER) } - return Class(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) + return Class(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) } } } @@ -285,10 +287,10 @@ public class Converter private(val project: Project, val settings: ConverterSett //TODO: comments? val parameters = finalOrWithEmptyInitializerFields.map { field -> val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var - Parameter(field.identifier, field.`type`, varValModifier, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) + Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) } - val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) + val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, listOf(), setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) }) return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers) } @@ -298,10 +300,12 @@ public class Converter private(val project: Project, val settings: ConverterSett } private fun convertField(field: PsiField): Field { + val annotations = convertAnnotations(field) val modifiers = convertModifiers(field) if (field is PsiEnumConstant) { return EnumConstant(Identifier(field.getName()!!), getComments(field), + annotations, modifiers, typeConverter.convertType(field.getType(), Nullability.NotNull), convertElement(field.getArgumentList())) @@ -309,6 +313,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return Field(Identifier(field.getName()!!), getComments(field), + annotations, modifiers, typeConverter.convertVariableType(field), convertExpression(field.getInitializer(), field.getType()), @@ -323,17 +328,18 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { val returnType = typeConverter.convertMethodReturnType(method) + val annotations = convertAnnotations(method) val modifiers = convertModifiers(method) val comments = getComments(method) if (method.isConstructor()) { if (method.isPrimaryConstructor()) { - return convertPrimaryConstructor(method, modifiers, comments, membersToRemove) + return convertPrimaryConstructor(method, annotations, modifiers, comments, membersToRemove) } else { val params = convertParameterList(method.getParameterList()) - return SecondaryConstructor(this, comments, modifiers, params, convertBlock(method.getBody())) + return SecondaryConstructor(this, comments, annotations, modifiers, params, convertBlock(method.getBody())) } } else { @@ -364,6 +370,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val correctedParameter = Parameter(Identifier("other"), ClassType(Identifier("Any"), listOf(), Nullability.Nullable, settings), Parameter.VarValModifier.None, + params.parameters.single().annotations, listOf()) params = ParameterList(listOf(correctedParameter)) } @@ -371,7 +378,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val typeParameterList = convertTypeParameterList(method.getTypeParameterList()) val block = convertBlock(method.getBody()) - return Function(this, Identifier(method.getName()), comments, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) + return Function(this, Identifier(method.getName()), comments, annotations, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) } } @@ -411,6 +418,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } private fun convertPrimaryConstructor(constructor: PsiMethod, + annotations: List, modifiers: Set, comments: MemberComments, membersToRemove: MutableSet): PrimaryConstructor { @@ -460,10 +468,11 @@ public class Converter private(val project: Project, val settings: ConverterSett Parameter(Identifier(field.getName()!!), `type`, if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var, + convertAnnotations(it) + convertAnnotations(field), convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) }) } }) - return PrimaryConstructor(this, comments, modifiers, parameterList, block) + return PrimaryConstructor(this, comments, annotations, modifiers, parameterList, block) } private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair? { @@ -550,7 +559,7 @@ public class Converter private(val project: Project, val settings: ConverterSett Nullability.NotNull -> `type` = `type`.toNotNullType() Nullability.Nullable -> `type` = `type`.toNullableType() } - return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, modifiers) + return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, convertAnnotations(parameter), modifiers) } public fun convertExpression(argument: PsiExpression?, expectedType: PsiType?): Expression { @@ -601,6 +610,52 @@ public class Converter private(val project: Project, val settings: ConverterSett PsiModifier.PRIVATE to Modifier.PRIVATE ) + public fun convertAnnotations(owner: PsiModifierListOwner): List { + return owner.getModifierList()?.getAnnotations() + ?.filter { it.getQualifiedName() !in ANNOTATIONS_TO_REMOVE } + ?.map { convertAnnotation(it) } + ?.filterNotNull() ?: listOf() + } + + public fun convertAnnotation(annotation: PsiAnnotation): Annotation? { + val name = Identifier((annotation.getNameReferenceElement() ?: return null).getText()!!) + val annotationClass = annotation.getNameReferenceElement()?.resolve() as? PsiClass + val lastMethod = annotationClass?.getMethods()?.lastOrNull() + val arguments = annotation.getParameterList().getAttributes().flatMap { + val method = annotationClass?.findMethodsByName(it.getName() ?: "value", false)?.firstOrNull() + val expectedType = method?.getReturnType() + + val attrName = it.getName()?.let { Identifier(it) } + val value = it.getValue() + + val attrValues = when(value) { + is PsiExpression -> listOf(convertExpression(it.getValue() as? PsiExpression, expectedType)) + + is PsiArrayInitializerMemberValue -> { + val isVarArg = method == lastMethod /* converted to vararg in Kotlin */ + if (isVarArg && it.getName() == null) { + value.getInitializers().map { DummyStringExpression(it.getText()!!)/*TODO*/ } + } + else { + val expectedTypeConverted = typeConverter.convertType(expectedType) + if (expectedTypeConverted is ArrayType) { + val array = createArrayInitializerExpression(expectedTypeConverted, value.getInitializers().map { DummyStringExpression(it.getText()!!)/*TODO*/ }) + listOf(if (isVarArg) StarExpression(array) else array) + } + else { + listOf(DummyStringExpression(value.getText()!!)) + } + } + } + + else -> listOf(DummyStringExpression(value?.getText() ?: "")) + } + + attrValues.map { attrName to it } + } + return Annotation(name, arguments) + } + private val TYPE_MAP: Map = mapOf( JAVA_LANG_BYTE to "byte", JAVA_LANG_SHORT to "short", @@ -625,6 +680,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val NOT_NULL_ANNOTATIONS: Set = setOf("org.jetbrains.annotations.NotNull", "com.sun.istack.internal.NotNull", "javax.annotation.Nonnull") val NULLABLE_ANNOTATIONS: Set = setOf("org.jetbrains.annotations.Nullable", "com.sun.istack.internal.Nullable", "javax.annotation.Nullable") +val ANNOTATIONS_TO_REMOVE: Set = HashSet(NOT_NULL_ANNOTATIONS + NULLABLE_ANNOTATIONS + listOf(CommonClassNames.JAVA_LANG_OVERRIDE)) val PRIMITIVE_TYPE_CONVERSIONS: Map = mapOf( "byte" to BYTE.asString(), diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt new file mode 100644 index 00000000000..ef656749545 --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2014 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.j2k.ast + +import java.util.HashSet + +class Annotation(val name: Identifier, val arguments: List>) : Element { + override fun toKotlin(): String { + if (arguments.isEmpty()) return name.toKotlin() + + return name.toKotlin() + "(" + arguments.map { + if (it.first != null) + it.first!!.toKotlin() + " = " + it.second.toKotlin() + else + it.second.toKotlin() + }.makeString(", ") + ")" + } +} + +fun List.toKotlin(): String = if (isNotEmpty()) map { it.toKotlin() }.makeString("\n") + "\n" else "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index 3ce640ac8bd..60d2054379f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -19,15 +19,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.Collections -class AnonymousClassBody(converter: Converter, body: ClassBody, val extendsTrait: Boolean) -: Class(converter, - Identifier(""), - MemberComments.Empty, - setOf(), - TypeParameterList.Empty, - listOf(), - listOf(), - listOf(), - body) { +class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) +: Class(Identifier(""), MemberComments.Empty, listOf(), setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { override fun toKotlin() = body.toKotlin(null) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index 96887af8117..544ebf3785b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -16,23 +16,23 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.Converter import java.util.ArrayList open class Class( - val converter: Converter, val name: Identifier, comments: MemberComments, + annotations: List, modifiers: Set, val typeParameterList: TypeParameterList, val extendsTypes: List, val baseClassParams: List, val implementsTypes: List, val body: ClassBody -) : Member(comments, modifiers) { +) : Member(comments, annotations, modifiers) { override fun toKotlin(): String = commentsToKotlin() + + annotations.toKotlin() + modifiersToKotlin() + keyword + " " + name.toKotlin() + typeParameterList.toKotlin() + diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 1227f1793e9..4169f22f9b5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -23,17 +23,19 @@ import java.util.ArrayList abstract class Constructor( converter: Converter, comments: MemberComments, + annotations: List, modifiers: Set, parameterList: ParameterList, block: Block -) : Function(converter, Identifier.Empty, comments, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) +) : Function(converter, Identifier.Empty, comments, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) class PrimaryConstructor(converter: Converter, comments: MemberComments, + annotations: List, modifiers: Set, parameterList: ParameterList, block: Block) - : Constructor(converter, comments, modifiers, parameterList, block) { + : Constructor(converter, comments, annotations, modifiers, parameterList, block) { public fun signatureToKotlin(): String { val accessModifier = modifiers.accessModifier() @@ -46,10 +48,11 @@ class PrimaryConstructor(converter: Converter, class SecondaryConstructor(converter: Converter, comments: MemberComments, + annotations: List, modifiers: Set, parameterList: ParameterList, block: Block) - : Constructor(converter, comments, modifiers, parameterList, block) { + : Constructor(converter, comments, annotations, modifiers, parameterList, block) { public fun toInitFunction(containingClass: Class): Function { val modifiers = HashSet(modifiers) @@ -58,7 +61,7 @@ class SecondaryConstructor(converter: Converter, val block = Block(statements) val typeParameters = ArrayList() typeParameters.addAll(containingClass.typeParameterList.parameters) - return Function(converter, Identifier("create"), MemberComments.Empty, modifiers, + return Function(converter, Identifier("create"), comments, annotations, modifiers, ClassType(containingClass.name, typeParameters, Nullability.NotNull, converter.settings), TypeParameterList(typeParameters), parameterList, block, false) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index 1b816c665de..0f92b411590 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -16,26 +16,26 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.Converter - class Enum( - converter: Converter, name: Identifier, comments: MemberComments, + annotations: List, modifiers: Set, typeParameterList: TypeParameterList, extendsTypes: List, baseClassParams: List, implementsTypes: List, body: ClassBody -) : Class(converter, name, comments, modifiers, typeParameterList, +) : Class(name, comments, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { override fun primaryConstructorSignatureToKotlin(): String = body.primaryConstructor?.signatureToKotlin() ?: "" override fun toKotlin(): String { - return modifiersToKotlin() + + return commentsToKotlin() + + annotations.toKotlin() + + modifiersToKotlin() + "enum class " + name.toKotlin() + primaryConstructorSignatureToKotlin() + typeParameterList.toKotlin() + diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index c850c968683..60f2c77c072 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -19,17 +19,18 @@ package org.jetbrains.jet.j2k.ast class EnumConstant( identifier: Identifier, members: MemberComments, + annotations: List, modifiers: Set, `type`: Type, params: Element -) : Field(identifier, members, modifiers, `type`.toNotNullType(), params, true, false) { +) : Field(identifier, members, annotations, modifiers, `type`.toNotNullType(), params, true, false) { override fun toKotlin(): String { if (initializer.toKotlin().isEmpty()) { - return identifier.toKotlin() + return annotations.toKotlin() + identifier.toKotlin() } - return identifier.toKotlin() + " : " + `type`.toKotlin() + "(" + initializer.toKotlin() + ")" + return annotations.toKotlin() + identifier.toKotlin() + " : " + `type`.toKotlin() + "(" + initializer.toKotlin() + ")" } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 4082fa010b3..35415f9ccd6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -104,6 +104,10 @@ class LambdaExpression(val arguments: String?, val statementList: StatementList) } } +class StarExpression(val methodCall: MethodCallExpression) : Expression() { + override fun toKotlin() = "*" + methodCall.toKotlin() +} + fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List) : MethodCallExpression { val elementType = arrayType.elementType val createArrayFunction = if (elementType.isPrimitive()) { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index 03fb319b21a..dece98e1dc3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -22,15 +22,16 @@ import java.util.ArrayList open class Field( val identifier: Identifier, comments: MemberComments, + annotations: List, modifiers: Set, val `type`: Type, val initializer: Element, val isVal: Boolean, private val hasWriteAccesses: Boolean -) : Member(comments, modifiers) { +) : Member(comments, annotations, modifiers) { override fun toKotlin(): String { - val declaration = commentsToKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin() + val declaration = commentsToKotlin() + annotations.toKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin() return if (initializer.isEmpty) declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this)) else diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt index a2f9a1e06e1..9ab8e42149e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt @@ -23,13 +23,14 @@ open class Function( val converter: Converter, val name: Identifier, comments: MemberComments, + annotations: List, modifiers: Set, val `type`: Type, val typeParameterList: TypeParameterList, val parameterList: ParameterList, var block: Block?, val isInTrait: Boolean -) : Member(comments, modifiers) { +) : Member(comments, annotations, modifiers) { private fun modifiersToKotlin(): String { val resultingModifiers = ArrayList() @@ -58,11 +59,12 @@ open class Function( override fun toKotlin(): String { return commentsToKotlin() + - modifiersToKotlin() + - "fun ${typeParameterList.toKotlin().withSuffix(" ")}${name.toKotlin()}" + - "(${parameterList.toKotlin()})" + - returnTypeToKotlin() + - typeParameterList.whereToKotlin() + - block?.toKotlin() + annotations.toKotlin() + + modifiersToKotlin() + + "fun ${typeParameterList.toKotlin().withSuffix(" ")}${name.toKotlin()}" + + "(${parameterList.toKotlin()})" + + returnTypeToKotlin() + + typeParameterList.whereToKotlin() + + block?.toKotlin() } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt index 35027e25253..f8e409769c9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt @@ -36,6 +36,8 @@ class Identifier( private fun quote(str: String): String = "`" + str + "`" + override fun toString() = if (isNullable) "$name?" else name + class object { val Empty = Identifier("") diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt index 3219dd22112..c1af1fd9b11 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt @@ -57,7 +57,7 @@ public fun Converter.convertImport(anImport: PsiImportStatementBase, filter: Boo } private fun filterImport(name: String, ref: PsiJavaCodeReferenceElement): String? { - if (name in NOT_NULL_ANNOTATIONS || name in NULLABLE_ANNOTATIONS) return null + if (name in ANNOTATIONS_TO_REMOVE) return null // If imported class has a kotlin analog, drop the import if (!JavaToKotlinClassMap.getInstance().mapPlatformClass(FqName(name)).isEmpty()) return null diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt index f6616007bb1..0edf00c85c8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt @@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast //TODO: is a member? -class Initializer(val block: Block, modifiers: Set) : Member(MemberComments.Empty, modifiers) { +class Initializer(val block: Block, modifiers: Set) : Member(MemberComments.Empty, listOf(), modifiers) { override fun toKotlin(): String { return block.toKotlin() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index d40d43fb34f..8b87543957d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -20,6 +20,7 @@ import org.jetbrains.jet.j2k.ConverterSettings class LocalVariable( private val identifier: Identifier, + private val annotations: List, private val modifiers: Set, private val typeCalculator: () -> Type /* we use lazy type calculation for better performance */, private val initializer: Expression, @@ -28,16 +29,16 @@ class LocalVariable( ) : Element { override fun toKotlin(): String { - val varVal = if (isVal) "val" else "var" + val start = annotations.toKotlin() + if (isVal) "val" else "var" return if (initializer.isEmpty) { - "$varVal ${identifier.toKotlin()} : ${typeCalculator().toKotlin()}" + "$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()}" } else { val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault if (shouldSpecifyType) - "$varVal ${identifier.toKotlin()} : ${typeCalculator().toKotlin()} = ${initializer.toKotlin()}" + "$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()} = ${initializer.toKotlin()}" else - "$varVal ${identifier.toKotlin()} = ${initializer.toKotlin()}" + "$start ${identifier.toKotlin()} = ${initializer.toKotlin()}" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt index 5b293c61692..e30440da539 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt @@ -30,7 +30,7 @@ class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(e } } -abstract class Member(val comments: MemberComments, val modifiers: Set) : Element { +abstract class Member(val comments: MemberComments, val annotations: List, val modifiers: Set) : Element { fun commentsToKotlin(): String = comments.toKotlin() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 3e5758c0c12..770bfb6f06e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -16,7 +16,11 @@ package org.jetbrains.jet.j2k.ast -class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parameter.VarValModifier, val modifiers: Collection) : Element { +class Parameter(val identifier: Identifier, + val `type`: Type, + val varVal: Parameter.VarValModifier, + val annotations: List, + val modifiers: Collection) : Element { public enum class VarValModifier { None Val @@ -26,6 +30,7 @@ class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parame override fun toKotlin(): String { val builder = StringBuilder() + builder.append(annotations.toKotlin()) builder.append(modifiers.toKotlin()) if (`type` is VarArgType) { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index 49d03da2868..5f05c2f9f71 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -19,18 +19,16 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.ArrayList -class Trait( - converter: Converter, - name: Identifier, - comments: MemberComments, - modifiers: Set, - typeParameterList: TypeParameterList, - extendsTypes: List, - baseClassParams: List, - implementsTypes: List, - body: ClassBody -) : Class(converter, name, comments, modifiers, typeParameterList, - extendsTypes, baseClassParams, implementsTypes, body) { +class Trait(name: Identifier, + comments: MemberComments, + annotations: List, + modifiers: Set, + typeParameterList: TypeParameterList, + extendsTypes: List, + baseClassParams: List, + implementsTypes: List, + body: ClassBody +) : Class(name, comments, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { override val keyword: String get() = "trait" diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt index 5323567154e..8732312f2d4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt @@ -28,11 +28,12 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { override fun visitLocalVariable(variable: PsiLocalVariable) { result = LocalVariable(Identifier(variable.getName()!!), - converter.convertModifiers(variable), - { typeConverter.convertVariableType(variable) }, - converter.convertExpression(variable.getInitializer(), variable.getType()), - converter.settings.forceLocalVariableImmutability || variable.hasModifierProperty(PsiModifier.FINAL), - converter.settings) + converter.convertAnnotations(variable), + converter.convertModifiers(variable), + { typeConverter.convertVariableType(variable) }, + converter.convertExpression(variable.getInitializer(), variable.getType()), + converter.settings.forceLocalVariableImmutability || variable.hasModifierProperty(PsiModifier.FINAL), + converter.settings) } override fun visitExpressionList(list: PsiExpressionList) { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index d1d2e21ea08..664f8435fb2 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -41,11 +41,17 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { override fun setUp() { super.setUp() + fun addFile(fileName: String, packageName: String) { + val code = FileUtil.loadFile(File("j2k/tests/testData/$fileName"), true) + val root = LightPlatformTestCase.getSourceRoot()!! + val dir = root.findChild(packageName) ?: root.createChildDirectory(null, packageName) + val file = dir.createChildData(null, fileName)!! + file.getOutputStream(null)!!.writer().use { it.write(code) } + } + ApplicationManager.getApplication()!!.runWriteAction{ - val kotlinApiFileName = "KotlinApi.kt" - val kotlinCode = FileUtil.loadFile(File("j2k/tests/testData/$kotlinApiFileName"), true) - val kotlinFile = LightPlatformTestCase.getSourceRoot()!!.createChildData(null, kotlinApiFileName)!! - kotlinFile.getOutputStream(null)!!.writer().use { it.write(kotlinCode) } + addFile("KotlinApi.kt", "kotlinApi") + addFile("JavaApi.java", "javaApi") } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 21eebb3b267..520ad29f48b 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -43,6 +43,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/annotations"), Pattern.compile("^(.+)\\.java$"), true); } + @TestMetadata("annotationUsages.java") + public void testAnnotationUsages() throws Exception { + doTest("j2k/tests/testData/ast/annotations/annotationUsages.java"); + } + @TestMetadata("jetbrainsNotNull.java") public void testJetbrainsNotNull() throws Exception { doTest("j2k/tests/testData/ast/annotations/jetbrainsNotNull.java"); diff --git a/j2k/tests/testData/JavaApi.java b/j2k/tests/testData/JavaApi.java new file mode 100644 index 00000000000..fe7d506ad72 --- /dev/null +++ b/j2k/tests/testData/JavaApi.java @@ -0,0 +1,37 @@ +package javaApi; + +public @interface Anon1 { + String[] value(); + String[] stringArray(); + int[] intArray(); + String string(); +} + +public @interface Anon2 { + String value(); + int intValue(); + char charValue(); +} + +public @interface Anon3 { + E e(); + String[] stringArray(); + String[] value(); +} + +public @interface Anon4 { + String[] value(); +} + +public @interface Anon5 { + int value(); +} + +public @interface Anon6 { + String[] value(); + int intValue() default 10; +} + +public enum E { + A, B, C +} diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.java b/j2k/tests/testData/ast/annotations/annotationUsages.java new file mode 100644 index 00000000000..58ff9a6edaf --- /dev/null +++ b/j2k/tests/testData/ast/annotations/annotationUsages.java @@ -0,0 +1,11 @@ +//file +import javaApi.*; + +@Anon1(value = {"a"}, stringArray = {"b"}, intArray = {1, 2}, string = "x") +@Anon2(value = "a", intValue = 1, charValue = 'a') +@Anon3(e = E.A, stringArray = {}, value = {"a", "b"}) +@Anon4({"x", "y"}) +@Anon5(1) +@Anon6({"x", "y"}) +class C { +} diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.kt b/j2k/tests/testData/ast/annotations/annotationUsages.kt new file mode 100644 index 00000000000..8d0d68d9a79 --- /dev/null +++ b/j2k/tests/testData/ast/annotations/annotationUsages.kt @@ -0,0 +1,9 @@ +import javaApi.* + +Anon1(value = array("a"), stringArray = array("b"), intArray = intArray(1, 2), string = "x") +Anon2(value = "a", intValue = 1, charValue = 'a') +Anon3(e = E.A, stringArray = array(), value = *array("a", "b")) +Anon4("x", "y") +Anon5(1) +Anon6(array("x", "y")) +class C() \ No newline at end of file From 26b66263585d97e082ef314dd17c6228444cd99a Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 22:50:48 +0400 Subject: [PATCH 065/143] Converter from Java: added proper annotations formatting --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 36 +++++++++++++------ .../org/jetbrains/jet/j2k/ast/Annotation.kt | 27 ++++++++++---- .../jet/j2k/ast/AnonymousClassBody.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Constructors.kt | 6 ++-- j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 2 +- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Function.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Initializer.kt | 4 +-- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Members.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 2 +- .../ast/annotations/annotationUsages.java | 16 +++++++++ .../ast/annotations/annotationUsages.kt | 20 ++++++++++- 16 files changed, 96 insertions(+), 33 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 142c9c8f741..dc622babb73 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -72,7 +72,7 @@ public class Converter private(val project: Project, val settings: ConverterSett is PsiComment -> Comment(element.getText()!!) is PsiImportList -> convertImportList(element) is PsiImportStatementBase -> convertImport(element, false) - is PsiAnnotation -> convertAnnotation(element) + is PsiAnnotation -> convertAnnotation(element, false) is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: "")) is PsiWhiteSpace -> WhiteSpace(element.getText()!!) else -> null @@ -290,7 +290,7 @@ public class Converter private(val project: Project, val settings: ConverterSett Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) } - val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, listOf(), setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) + val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, Annotations.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) }) return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers) } @@ -418,7 +418,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } private fun convertPrimaryConstructor(constructor: PsiMethod, - annotations: List, + annotations: Annotations, modifiers: Set, comments: MemberComments, membersToRemove: MutableSet): PrimaryConstructor { @@ -610,14 +610,30 @@ public class Converter private(val project: Project, val settings: ConverterSett PsiModifier.PRIVATE to Modifier.PRIVATE ) - public fun convertAnnotations(owner: PsiModifierListOwner): List { - return owner.getModifierList()?.getAnnotations() - ?.filter { it.getQualifiedName() !in ANNOTATIONS_TO_REMOVE } - ?.map { convertAnnotation(it) } - ?.filterNotNull() ?: listOf() + public fun convertAnnotations(owner: PsiModifierListOwner): Annotations { + val modifierList = owner.getModifierList() + val annotations = modifierList?.getAnnotations()?.filter { it.getQualifiedName() !in ANNOTATIONS_TO_REMOVE } + if (annotations == null || annotations.isEmpty()) return Annotations.Empty + + val newLines = run { + if (!modifierList!!.isInSingleLine()) { + true + } + else { + var child: PsiElement? = modifierList + while(true) { + child = child!!.getNextSibling() + if (child == null || child!!.getTextLength() != 0) break + } + if (child is PsiWhiteSpace) !child!!.isInSingleLine() else false + } + } + + val list = annotations.map { convertAnnotation(it, owner is PsiLocalVariable) }.filterNotNull() + return Annotations(list, newLines) } - public fun convertAnnotation(annotation: PsiAnnotation): Annotation? { + public fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean): Annotation? { val name = Identifier((annotation.getNameReferenceElement() ?: return null).getText()!!) val annotationClass = annotation.getNameReferenceElement()?.resolve() as? PsiClass val lastMethod = annotationClass?.getMethods()?.lastOrNull() @@ -653,7 +669,7 @@ public class Converter private(val project: Project, val settings: ConverterSett attrValues.map { attrName to it } } - return Annotation(name, arguments) + return Annotation(name, arguments, brackets) } private val TYPE_MAP: Map = mapOf( diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index ef656749545..d1632772225 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -18,17 +18,32 @@ package org.jetbrains.jet.j2k.ast import java.util.HashSet -class Annotation(val name: Identifier, val arguments: List>) : Element { - override fun toKotlin(): String { - if (arguments.isEmpty()) return name.toKotlin() +class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean) : Element { + private fun surroundWithBrackets(text: String) = if (brackets) "[$text]" else text - return name.toKotlin() + "(" + arguments.map { + override fun toKotlin(): String { + if (arguments.isEmpty()) { + return surroundWithBrackets(name.toKotlin()) + } + + val argsText = arguments.map { if (it.first != null) it.first!!.toKotlin() + " = " + it.second.toKotlin() else it.second.toKotlin() - }.makeString(", ") + ")" + }.makeString(", ") + return surroundWithBrackets(name.toKotlin() + "(" + argsText + ")") } } -fun List.toKotlin(): String = if (isNotEmpty()) map { it.toKotlin() }.makeString("\n") + "\n" else "" +class Annotations(val annotations: List, val newLines: Boolean) { + private val br = if (newLines) "\n" else " " + + fun toKotlin(): String = if (annotations.isNotEmpty()) annotations.map { it.toKotlin() }.makeString(br) + br else "" + + fun plus(other: Annotations) = Annotations(annotations + other.annotations, newLines || other.newLines) + + class object { + val Empty = Annotations(listOf(), false) + } +} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index 60d2054379f..87535864a53 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -20,6 +20,6 @@ import org.jetbrains.jet.j2k.Converter import java.util.Collections class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) -: Class(Identifier(""), MemberComments.Empty, listOf(), setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { +: Class(Identifier(""), MemberComments.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { override fun toKotlin() = body.toKotlin(null) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index 544ebf3785b..89341e7f4ba 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -21,7 +21,7 @@ import java.util.ArrayList open class Class( val name: Identifier, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, val typeParameterList: TypeParameterList, val extendsTypes: List, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 4169f22f9b5..2fdef678779 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -23,7 +23,7 @@ import java.util.ArrayList abstract class Constructor( converter: Converter, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block @@ -31,7 +31,7 @@ abstract class Constructor( class PrimaryConstructor(converter: Converter, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block) @@ -48,7 +48,7 @@ class PrimaryConstructor(converter: Converter, class SecondaryConstructor(converter: Converter, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index 0f92b411590..f0ab0b3f621 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -19,7 +19,7 @@ package org.jetbrains.jet.j2k.ast class Enum( name: Identifier, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, typeParameterList: TypeParameterList, extendsTypes: List, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index 60f2c77c072..a3c2b2808b4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -19,7 +19,7 @@ package org.jetbrains.jet.j2k.ast class EnumConstant( identifier: Identifier, members: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, `type`: Type, params: Element diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index dece98e1dc3..8e34ece0e49 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -22,7 +22,7 @@ import java.util.ArrayList open class Field( val identifier: Identifier, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, val `type`: Type, val initializer: Element, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt index 9ab8e42149e..0bb87b07cfb 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt @@ -23,7 +23,7 @@ open class Function( val converter: Converter, val name: Identifier, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, val `type`: Type, val typeParameterList: TypeParameterList, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt index 0edf00c85c8..6f2adb2cec6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt @@ -16,9 +16,7 @@ package org.jetbrains.jet.j2k.ast - -//TODO: is a member? -class Initializer(val block: Block, modifiers: Set) : Member(MemberComments.Empty, listOf(), modifiers) { +class Initializer(val block: Block, modifiers: Set) : Member(MemberComments.Empty, Annotations.Empty, modifiers) { override fun toKotlin(): String { return block.toKotlin() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index 8b87543957d..52cf1a7c575 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -20,7 +20,7 @@ import org.jetbrains.jet.j2k.ConverterSettings class LocalVariable( private val identifier: Identifier, - private val annotations: List, + private val annotations: Annotations, private val modifiers: Set, private val typeCalculator: () -> Type /* we use lazy type calculation for better performance */, private val initializer: Expression, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt index e30440da539..7b74c695e09 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt @@ -30,7 +30,7 @@ class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(e } } -abstract class Member(val comments: MemberComments, val annotations: List, val modifiers: Set) : Element { +abstract class Member(val comments: MemberComments, val annotations: Annotations, val modifiers: Set) : Element { fun commentsToKotlin(): String = comments.toKotlin() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 770bfb6f06e..70ce20c83ed 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -19,7 +19,7 @@ package org.jetbrains.jet.j2k.ast class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parameter.VarValModifier, - val annotations: List, + val annotations: Annotations, val modifiers: Collection) : Element { public enum class VarValModifier { None diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index 5f05c2f9f71..f5ff5c77fbc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -21,7 +21,7 @@ import java.util.ArrayList class Trait(name: Identifier, comments: MemberComments, - annotations: List, + annotations: Annotations, modifiers: Set, typeParameterList: TypeParameterList, extendsTypes: List, diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.java b/j2k/tests/testData/ast/annotations/annotationUsages.java index 58ff9a6edaf..7c5577f721c 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.java +++ b/j2k/tests/testData/ast/annotations/annotationUsages.java @@ -8,4 +8,20 @@ import javaApi.*; @Anon5(1) @Anon6({"x", "y"}) class C { + @Anon5(1) @Deprecated private int field1 = 0; + + @Anon5(1) + private int field2 = 0; + + @Anon5(1) int field3 = 0; + + @Anon5(1) + int field4 = 0; + + @Anon6({}) + void foo(@Deprecated int p1, @Deprecated @Anon5(2) char p2) { + @Deprecated @Anon5(3) char c = 'a'; + } + + @Anon5(1) void bar(){} } diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.kt b/j2k/tests/testData/ast/annotations/annotationUsages.kt index 8d0d68d9a79..8bad5c3e6bf 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.kt +++ b/j2k/tests/testData/ast/annotations/annotationUsages.kt @@ -6,4 +6,22 @@ Anon3(e = E.A, stringArray = array(), value = *array("a", "b")) Anon4("x", "y") Anon5(1) Anon6(array("x", "y")) -class C() \ No newline at end of file +class C() { + Anon5(1) Deprecated private var field1: Int = 0 + + Anon5(1) + private var field2: Int = 0 + + Anon5(1) var field3: Int = 0 + + Anon5(1) + var field4: Int = 0 + + Anon6(array()) + fun foo(Deprecated p1: Int, Deprecated Anon5(2) p2: Char) { + [Deprecated] [Anon5(3)] val c = 'a' + } + + Anon5(1) fun bar() { + } +} From 84a566b034fef5bf991517a1aa418b4fa04dd738 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 14:16:17 +0400 Subject: [PATCH 066/143] Converter from Java: minor change --- .../jetbrains/jet/j2k/visitors/TypeVisitor.kt | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index 22b3258385b..9e1eaa766e9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -68,24 +68,6 @@ class TypeVisitor(private val converter: TypeConverter, private val classesToImp } } - private val toKotlinTypesMap = mapOf( - CommonClassNames.JAVA_LANG_OBJECT to "kotlin.Any", - CommonClassNames.JAVA_LANG_BYTE to "kotlin.Byte", - CommonClassNames.JAVA_LANG_CHARACTER to "kotlin.Char", - CommonClassNames.JAVA_LANG_DOUBLE to "kotlin.Double", - CommonClassNames.JAVA_LANG_FLOAT to "kotlin.Float", - CommonClassNames.JAVA_LANG_INTEGER to "kotlin.Int", - CommonClassNames.JAVA_LANG_LONG to "kotlin.Long", - CommonClassNames.JAVA_LANG_SHORT to "kotlin.Short", - CommonClassNames.JAVA_LANG_BOOLEAN to "kotlin.Boolean", - CommonClassNames.JAVA_LANG_ITERABLE to "kotlin.Iterable", - CommonClassNames.JAVA_UTIL_ITERATOR to "kotlin.Iterator", - CommonClassNames.JAVA_UTIL_LIST to "kotlin.List", - CommonClassNames.JAVA_UTIL_COLLECTION to "kotlin.Collection", - CommonClassNames.JAVA_UTIL_SET to "kotlin.Set", - CommonClassNames.JAVA_UTIL_MAP to "kotlin.Map" - ) - private fun constructClassTypeIdentifier(classType: PsiClassType): Identifier { val psiClass = classType.resolve() if (psiClass != null) { @@ -155,4 +137,24 @@ class TypeVisitor(private val converter: TypeConverter, private val classesToImp override fun visitEllipsisType(ellipsisType: PsiEllipsisType): Type { return VarArgType(converter.convertType(ellipsisType.getComponentType())) } + + class object { + private val toKotlinTypesMap: Map = mapOf( + CommonClassNames.JAVA_LANG_OBJECT to "kotlin.Any", + CommonClassNames.JAVA_LANG_BYTE to "kotlin.Byte", + CommonClassNames.JAVA_LANG_CHARACTER to "kotlin.Char", + CommonClassNames.JAVA_LANG_DOUBLE to "kotlin.Double", + CommonClassNames.JAVA_LANG_FLOAT to "kotlin.Float", + CommonClassNames.JAVA_LANG_INTEGER to "kotlin.Int", + CommonClassNames.JAVA_LANG_LONG to "kotlin.Long", + CommonClassNames.JAVA_LANG_SHORT to "kotlin.Short", + CommonClassNames.JAVA_LANG_BOOLEAN to "kotlin.Boolean", + CommonClassNames.JAVA_LANG_ITERABLE to "kotlin.Iterable", + CommonClassNames.JAVA_UTIL_ITERATOR to "kotlin.Iterator", + CommonClassNames.JAVA_UTIL_LIST to "kotlin.List", + CommonClassNames.JAVA_UTIL_COLLECTION to "kotlin.Collection", + CommonClassNames.JAVA_UTIL_SET to "kotlin.Set", + CommonClassNames.JAVA_UTIL_MAP to "kotlin.Map" + ) + } } From be44c5b7befcb6637ff363b10a8c34790cdd9c06 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 15:59:48 +0400 Subject: [PATCH 067/143] Fixed test for java to Kotlin copy/paste - java standard classes used to not be resolved --- .../AbstractJavaToKotlinCopyPasteConversionTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/idea/tests/org/jetbrains/jet/plugin/conversion/copy/AbstractJavaToKotlinCopyPasteConversionTest.java b/idea/tests/org/jetbrains/jet/plugin/conversion/copy/AbstractJavaToKotlinCopyPasteConversionTest.java index 5996ffba61a..7a2eff686db 100644 --- a/idea/tests/org/jetbrains/jet/plugin/conversion/copy/AbstractJavaToKotlinCopyPasteConversionTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/conversion/copy/AbstractJavaToKotlinCopyPasteConversionTest.java @@ -17,7 +17,10 @@ package org.jetbrains.jet.plugin.conversion.copy; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor; import org.jetbrains.jet.plugin.PluginTestCaseBase; import org.jetbrains.jet.plugin.editor.JetEditorOptions; @@ -26,6 +29,12 @@ public abstract class AbstractJavaToKotlinCopyPasteConversionTest extends LightC private static final String BASE_PATH = PluginTestCaseBase.getTestDataPathBase() + "/copyPaste/conversion"; private JetEditorOptions oldState = null; + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE; + } + @Override protected void setUp() throws Exception { super.setUp(); From 8a1dbcdfc6b4edccc5773a4f8df8838fac233089 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 18:21:34 +0400 Subject: [PATCH 068/143] Java to Kotlin: deleted test data files with wrong case --- .../ast/returnStatement/CurrentMethodBug.java | 22 --------------- .../toKotlinClasses/IterableAndIterator.java | 28 ------------------- 2 files changed, 50 deletions(-) delete mode 100644 j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java delete mode 100644 j2k/tests/testData/ast/toKotlinClasses/IterableAndIterator.java diff --git a/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java b/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java deleted file mode 100644 index 688643d3a5d..00000000000 --- a/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java +++ /dev/null @@ -1,22 +0,0 @@ -//file -import org.jetbrains.annotations.Nullable; - -interface I { - int getInt(); -} - -class C { - @Nullable Object getObject() { - foo(new I() { - @Override - public int getInt() { - return 0; - } - }); - return string; - } - - void foo(I i) {} - - @Nullable String string; -} \ No newline at end of file diff --git a/j2k/tests/testData/ast/toKotlinClasses/IterableAndIterator.java b/j2k/tests/testData/ast/toKotlinClasses/IterableAndIterator.java deleted file mode 100644 index 1a3b16843bd..00000000000 --- a/j2k/tests/testData/ast/toKotlinClasses/IterableAndIterator.java +++ /dev/null @@ -1,28 +0,0 @@ -//file -package demo; - -import java.util.Iterator; - -class Test implements Iterable { - @Override - public Iterator iterator() { - return null; - } - - public Iterator push(Iterator i) { - Iterator j = i; - return j; - } -} - -class FullTest implements java.lang.Iterable { - @Override - public java.util.Iterator iterator() { - return null; - } - - public java.util.Iterator push(java.util.Iterator i) { - java.util.Iterator j = i; - return j; - } -} \ No newline at end of file From a8c61b377af96fd1398adccfe98d0ea0ab1d47c4 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 18:22:32 +0400 Subject: [PATCH 069/143] Java to Kotlin: restored test data files with correct case --- .../ast/returnStatement/currentMethodBug.java | 22 +++++++++++++++ .../toKotlinClasses/iterableAndIterator.java | 28 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 j2k/tests/testData/ast/returnStatement/currentMethodBug.java create mode 100644 j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.java diff --git a/j2k/tests/testData/ast/returnStatement/currentMethodBug.java b/j2k/tests/testData/ast/returnStatement/currentMethodBug.java new file mode 100644 index 00000000000..688643d3a5d --- /dev/null +++ b/j2k/tests/testData/ast/returnStatement/currentMethodBug.java @@ -0,0 +1,22 @@ +//file +import org.jetbrains.annotations.Nullable; + +interface I { + int getInt(); +} + +class C { + @Nullable Object getObject() { + foo(new I() { + @Override + public int getInt() { + return 0; + } + }); + return string; + } + + void foo(I i) {} + + @Nullable String string; +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.java b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.java new file mode 100644 index 00000000000..1a3b16843bd --- /dev/null +++ b/j2k/tests/testData/ast/toKotlinClasses/iterableAndIterator.java @@ -0,0 +1,28 @@ +//file +package demo; + +import java.util.Iterator; + +class Test implements Iterable { + @Override + public Iterator iterator() { + return null; + } + + public Iterator push(Iterator i) { + Iterator j = i; + return j; + } +} + +class FullTest implements java.lang.Iterable { + @Override + public java.util.Iterator iterator() { + return null; + } + + public java.util.Iterator push(java.util.Iterator i) { + java.util.Iterator j = i; + return j; + } +} \ No newline at end of file From 65b3ec6dfd0a0120ecc7b55e2c7c55a221d537e0 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 18:30:48 +0400 Subject: [PATCH 070/143] Java to Kotlin: Deprecated annotation conversion --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 5 +++++ j2k/tests/testData/ast/annotations/annotationUsages.kt | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index dc622babb73..3fe00cf8837 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -634,6 +634,11 @@ public class Converter private(val project: Project, val settings: ConverterSett } public fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean): Annotation? { + val qualifiedName = annotation.getQualifiedName() + if (qualifiedName == CommonClassNames.JAVA_LANG_DEPRECATED && annotation.getParameterList().getAttributes().isEmpty()) { + return Annotation(Identifier("deprecated"), listOf(null to LiteralExpression("\"\"")), brackets) //TODO: insert comment + } + val name = Identifier((annotation.getNameReferenceElement() ?: return null).getText()!!) val annotationClass = annotation.getNameReferenceElement()?.resolve() as? PsiClass val lastMethod = annotationClass?.getMethods()?.lastOrNull() diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.kt b/j2k/tests/testData/ast/annotations/annotationUsages.kt index 8bad5c3e6bf..9ef317ef824 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.kt +++ b/j2k/tests/testData/ast/annotations/annotationUsages.kt @@ -7,7 +7,7 @@ Anon4("x", "y") Anon5(1) Anon6(array("x", "y")) class C() { - Anon5(1) Deprecated private var field1: Int = 0 + Anon5(1) deprecated("") private var field1: Int = 0 Anon5(1) private var field2: Int = 0 @@ -18,8 +18,8 @@ class C() { var field4: Int = 0 Anon6(array()) - fun foo(Deprecated p1: Int, Deprecated Anon5(2) p2: Char) { - [Deprecated] [Anon5(3)] val c = 'a' + fun foo(deprecated("") p1: Int, deprecated("") Anon5(2) p2: Char) { + [deprecated("")] [Anon5(3)] val c = 'a' } Anon5(1) fun bar() { From bd30ae572eab17a57ab04816fcca12851871a514 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 19:10:58 +0400 Subject: [PATCH 071/143] Java to Kotlin: correct conversion of array components in annotation attributes --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 52 +++++++++++-------- j2k/tests/testData/JavaApi.java | 8 +++ .../ast/annotations/annotationUsages.java | 2 + .../ast/annotations/annotationUsages.kt | 2 + 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 3fe00cf8837..07ce8fb2a90 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -629,7 +629,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } } - val list = annotations.map { convertAnnotation(it, owner is PsiLocalVariable) }.filterNotNull() + val list = annotations.map { convertAnnotation(it, owner is PsiLocalVariable) }.filterNotNull() //TODO: brackets are also needed for local classes return Annotations(list, newLines) } @@ -649,34 +649,40 @@ public class Converter private(val project: Project, val settings: ConverterSett val attrName = it.getName()?.let { Identifier(it) } val value = it.getValue() - val attrValues = when(value) { - is PsiExpression -> listOf(convertExpression(it.getValue() as? PsiExpression, expectedType)) - - is PsiArrayInitializerMemberValue -> { - val isVarArg = method == lastMethod /* converted to vararg in Kotlin */ - if (isVarArg && it.getName() == null) { - value.getInitializers().map { DummyStringExpression(it.getText()!!)/*TODO*/ } - } - else { - val expectedTypeConverted = typeConverter.convertType(expectedType) - if (expectedTypeConverted is ArrayType) { - val array = createArrayInitializerExpression(expectedTypeConverted, value.getInitializers().map { DummyStringExpression(it.getText()!!)/*TODO*/ }) - listOf(if (isVarArg) StarExpression(array) else array) - } - else { - listOf(DummyStringExpression(value.getText()!!)) - } - } - } - - else -> listOf(DummyStringExpression(value?.getText() ?: "")) - } + val isVarArg = method == lastMethod /* converted to vararg in Kotlin */ + val attrValues = convertAttributeValue(value, expectedType, isVarArg, it.getName() == null) attrValues.map { attrName to it } } return Annotation(name, arguments, brackets) } + private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List { + return when(value) { + is PsiExpression -> listOf(convertExpression(value as? PsiExpression, expectedType)) + + is PsiArrayInitializerMemberValue -> { + val componentType = (expectedType as? PsiArrayType)?.getComponentType() + val componentsConverted = value.getInitializers().map { convertAttributeValue(it, componentType, false, true).single() } + if (isVararg && isUnnamed) { + componentsConverted + } + else { + val expectedTypeConverted = typeConverter.convertType(expectedType) + if (expectedTypeConverted is ArrayType) { + val array = createArrayInitializerExpression(expectedTypeConverted, componentsConverted) + listOf(if (isVararg) StarExpression(array) else array) + } + else { + listOf(DummyStringExpression(value.getText()!!)) + } + } + } + + else -> listOf(DummyStringExpression(value?.getText() ?: "")) + } + } + private val TYPE_MAP: Map = mapOf( JAVA_LANG_BYTE to "byte", JAVA_LANG_SHORT to "short", diff --git a/j2k/tests/testData/JavaApi.java b/j2k/tests/testData/JavaApi.java index fe7d506ad72..f0d51257d23 100644 --- a/j2k/tests/testData/JavaApi.java +++ b/j2k/tests/testData/JavaApi.java @@ -32,6 +32,14 @@ public @interface Anon6 { int intValue() default 10; } +public @interface Anon7 { + Class[] value(); +} + +public @interface Anon8 { + Class[] classes(); +} + public enum E { A, B, C } diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.java b/j2k/tests/testData/ast/annotations/annotationUsages.java index 7c5577f721c..0ef69bb0679 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.java +++ b/j2k/tests/testData/ast/annotations/annotationUsages.java @@ -7,6 +7,8 @@ import javaApi.*; @Anon4({"x", "y"}) @Anon5(1) @Anon6({"x", "y"}) +@Anon7({ String.class, StringBuilder.class }) +@Anon8(classes = { String.class, StringBuilder.class }) class C { @Anon5(1) @Deprecated private int field1 = 0; diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.kt b/j2k/tests/testData/ast/annotations/annotationUsages.kt index 9ef317ef824..853a29131eb 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.kt +++ b/j2k/tests/testData/ast/annotations/annotationUsages.kt @@ -6,6 +6,8 @@ Anon3(e = E.A, stringArray = array(), value = *array("a", "b")) Anon4("x", "y") Anon5(1) Anon6(array("x", "y")) +Anon7(javaClass(), javaClass()) +Anon8(classes = *array>(javaClass(), javaClass())) class C() { Anon5(1) deprecated("") private var field1: Int = 0 From eef4e548e574a4dcce4b8ddf39dd53b98f47635c Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 19:40:45 +0400 Subject: [PATCH 072/143] Java to Kotlin: annotations conversion - no redundant array type arguments #KT-4487 Fixed --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt | 9 +++++---- .../jetbrains/jet/j2k/visitors/ExpressionVisitor.kt | 3 ++- j2k/tests/testData/ast/annotations/annotationUsages.kt | 10 +++++----- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 07ce8fb2a90..b6e101e9fc6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -670,7 +670,7 @@ public class Converter private(val project: Project, val settings: ConverterSett else { val expectedTypeConverted = typeConverter.convertType(expectedType) if (expectedTypeConverted is ArrayType) { - val array = createArrayInitializerExpression(expectedTypeConverted, componentsConverted) + val array = createArrayInitializerExpression(expectedTypeConverted, componentsConverted, needExplicitType = false) listOf(if (isVararg) StarExpression(array) else array) } else { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 35415f9ccd6..e1e5d1ead1e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -108,13 +108,14 @@ class StarExpression(val methodCall: MethodCallExpression) : Expression() { override fun toKotlin() = "*" + methodCall.toKotlin() } -fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List) : MethodCallExpression { +fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List, needExplicitType: Boolean) : MethodCallExpression { val elementType = arrayType.elementType - val createArrayFunction = if (elementType.isPrimitive()) { + val createArrayFunction = if (elementType.isPrimitive()) (elementType.toNotNullType().toKotlin() + "Array").decapitalize() - } - else + else if (needExplicitType) arrayType.toNotNullType().toKotlin().decapitalize() + else + "array" val doubleOrFloatTypes = setOf("double", "float", "java.lang.double", "java.lang.float") val afterReplace = arrayType.toNotNullType().toKotlin().replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 43fe4f2f50a..478fc774ae0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -58,7 +58,8 @@ class ExpressionVisitor(private val converter: Converter, val expressionType = typeConverter.convertType(expression.getType()) assert(expressionType is ArrayType, "Array initializer must have array type") result = createArrayInitializerExpression(expressionType as ArrayType, - converter.convertExpressions(expression.getInitializers())) + converter.convertExpressions(expression.getInitializers()), + needExplicitType = true/*TODO: it's often redundant*/) } override fun visitAssignmentExpression(expression: PsiAssignmentExpression) { diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.kt b/j2k/tests/testData/ast/annotations/annotationUsages.kt index 853a29131eb..ced7214ba69 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.kt +++ b/j2k/tests/testData/ast/annotations/annotationUsages.kt @@ -1,13 +1,13 @@ import javaApi.* -Anon1(value = array("a"), stringArray = array("b"), intArray = intArray(1, 2), string = "x") +Anon1(value = array("a"), stringArray = array("b"), intArray = intArray(1, 2), string = "x") Anon2(value = "a", intValue = 1, charValue = 'a') -Anon3(e = E.A, stringArray = array(), value = *array("a", "b")) +Anon3(e = E.A, stringArray = array(), value = *array("a", "b")) Anon4("x", "y") Anon5(1) -Anon6(array("x", "y")) +Anon6(array("x", "y")) Anon7(javaClass(), javaClass()) -Anon8(classes = *array>(javaClass(), javaClass())) +Anon8(classes = *array(javaClass(), javaClass())) class C() { Anon5(1) deprecated("") private var field1: Int = 0 @@ -19,7 +19,7 @@ class C() { Anon5(1) var field4: Int = 0 - Anon6(array()) + Anon6(array()) fun foo(deprecated("") p1: Int, deprecated("") Anon5(2) p2: Char) { [deprecated("")] [Anon5(3)] val c = 'a' } From 09120015608fbabcd3ada7854e6a19cda63622de Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 19:59:21 +0400 Subject: [PATCH 073/143] Fixed KT-5223 Converter from Java should convert "throws" in method declaration #KT-5223 Fixed --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 11 ++++++++++- .../j2k/test/JavaToKotlinConverterTestGenerated.java | 5 +++++ .../ast/function/extendsBaseWhichExtendsObject.kt | 4 ++++ j2k/tests/testData/ast/function/overrideObject.kt | 2 ++ j2k/tests/testData/ast/function/overrideObject2.kt | 1 + j2k/tests/testData/ast/function/throws.java | 2 ++ j2k/tests/testData/ast/function/throws.kt | 2 ++ j2k/tests/testData/ast/tryWithResource/Multiline.kt | 1 + .../testData/ast/tryWithResource/MultipleResources.kt | 1 + j2k/tests/testData/ast/tryWithResource/Simple.kt | 1 + j2k/tests/testData/ast/tryWithResource/WithFinally.kt | 1 + .../ast/tryWithResource/WithReturnInAnonymousClass.kt | 4 ++++ .../tryWithResource/WithReturnInAnonymousClass2.kt | 4 ++++ 13 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 j2k/tests/testData/ast/function/throws.java create mode 100644 j2k/tests/testData/ast/function/throws.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index b6e101e9fc6..77ffac60388 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -328,7 +328,7 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { val returnType = typeConverter.convertMethodReturnType(method) - val annotations = convertAnnotations(method) + val annotations = convertAnnotations(method) + convertThrows(method) val modifiers = convertModifiers(method) val comments = getComments(method) @@ -683,6 +683,15 @@ public class Converter private(val project: Project, val settings: ConverterSett } } + private fun convertThrows(method: PsiMethod): Annotations { + val types = method.getThrowsList().getReferencedTypes() + if (types.isEmpty()) return Annotations.Empty + return Annotations(listOf(Annotation(Identifier("throws"), + types.map { null to MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(typeConverter.convertType(it, Nullability.NotNull))) }, + false)), + true) + } + private val TYPE_MAP: Map = mapOf( JAVA_LANG_BYTE to "byte", JAVA_LANG_SHORT to "short", diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 520ad29f48b..efe6226c743 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -1305,6 +1305,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/function/public.java"); } + @TestMetadata("throws.java") + public void testThrows() throws Exception { + doTest("j2k/tests/testData/ast/function/throws.java"); + } + @TestMetadata("varVararg.java") public void testVarVararg() throws Exception { doTest("j2k/tests/testData/ast/function/varVararg.java"); diff --git a/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt b/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt index d5089fa31bc..e7f0ebe62dc 100644 --- a/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt +++ b/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt @@ -9,6 +9,7 @@ class Test() : Base() { return super.equals(o) } + throws(javaClass()) override fun clone(): Any { return super.clone() } @@ -17,6 +18,7 @@ class Test() : Base() { return super.toString() } + throws(javaClass()) override fun finalize() { super.finalize() } @@ -31,6 +33,7 @@ class Base() { return super.equals(o) } + throws(javaClass()) protected fun clone(): Any { return super.clone() } @@ -39,6 +42,7 @@ class Base() { return super.toString() } + throws(javaClass()) protected fun finalize() { super.finalize() } diff --git a/j2k/tests/testData/ast/function/overrideObject.kt b/j2k/tests/testData/ast/function/overrideObject.kt index 8d8a5919c85..2bebbe28944 100644 --- a/j2k/tests/testData/ast/function/overrideObject.kt +++ b/j2k/tests/testData/ast/function/overrideObject.kt @@ -11,12 +11,14 @@ class X() { return super.toString() } + throws(javaClass()) protected fun clone(): Any { return super.clone() } } class Y() : Thread() { + throws(javaClass()) override fun clone(): Any { return super.clone() } diff --git a/j2k/tests/testData/ast/function/overrideObject2.kt b/j2k/tests/testData/ast/function/overrideObject2.kt index 38360355781..40f8b234ba3 100644 --- a/j2k/tests/testData/ast/function/overrideObject2.kt +++ b/j2k/tests/testData/ast/function/overrideObject2.kt @@ -13,6 +13,7 @@ class X() : Base() { return super.toString() } + throws(javaClass()) protected fun clone(): Any { return super.clone() } diff --git a/j2k/tests/testData/ast/function/throws.java b/j2k/tests/testData/ast/function/throws.java new file mode 100644 index 00000000000..74c4bfea6db --- /dev/null +++ b/j2k/tests/testData/ast/function/throws.java @@ -0,0 +1,2 @@ +//method +void foo() throws IOException, SerializationException; \ No newline at end of file diff --git a/j2k/tests/testData/ast/function/throws.kt b/j2k/tests/testData/ast/function/throws.kt new file mode 100644 index 00000000000..adc20745905 --- /dev/null +++ b/j2k/tests/testData/ast/function/throws.kt @@ -0,0 +1,2 @@ +throws(javaClass(), javaClass()) +fun foo() \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/Multiline.kt b/j2k/tests/testData/ast/tryWithResource/Multiline.kt index 4319e413066..2a9e653db33 100644 --- a/j2k/tests/testData/ast/tryWithResource/Multiline.kt +++ b/j2k/tests/testData/ast/tryWithResource/Multiline.kt @@ -1,6 +1,7 @@ import java.io.* public class C() { + throws(javaClass()) fun foo() { FileInputStream("foo").use { stream -> // reading something diff --git a/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt b/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt index 544c6137ecf..9e4868f4566 100644 --- a/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt +++ b/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt @@ -1,6 +1,7 @@ import java.io.* public class C() { + throws(javaClass()) fun foo() { FileInputStream("foo").use { input -> FileOutputStream("bar").use { output -> diff --git a/j2k/tests/testData/ast/tryWithResource/Simple.kt b/j2k/tests/testData/ast/tryWithResource/Simple.kt index 6d5d5cfacc2..40a727ec4c0 100644 --- a/j2k/tests/testData/ast/tryWithResource/Simple.kt +++ b/j2k/tests/testData/ast/tryWithResource/Simple.kt @@ -1,6 +1,7 @@ import java.io.* public class C() { + throws(javaClass()) fun foo() { FileInputStream("foo").use { stream -> System.out.println(stream.read()) } } diff --git a/j2k/tests/testData/ast/tryWithResource/WithFinally.kt b/j2k/tests/testData/ast/tryWithResource/WithFinally.kt index f127ac2ee0f..79df2e2cd39 100644 --- a/j2k/tests/testData/ast/tryWithResource/WithFinally.kt +++ b/j2k/tests/testData/ast/tryWithResource/WithFinally.kt @@ -1,6 +1,7 @@ import java.io.* public class C() { + throws(javaClass()) fun foo() { try { FileInputStream("foo").use { stream -> diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt index 326bf6b2abf..304f88ac3af 100644 --- a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt @@ -1,13 +1,16 @@ import java.io.* trait I { + throws(javaClass()) public fun doIt(stream: InputStream): Int } public class C() { + throws(javaClass()) fun foo() { FileInputStream("foo").use { stream -> bar(object : I { + throws(javaClass()) override fun doIt(stream: InputStream): Int { return stream.available() } @@ -15,6 +18,7 @@ public class C() { } } + throws(javaClass()) fun bar(i: I, stream: InputStream): Int { return i.doIt(stream) } diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt index cbaf5dfeb4c..0b06d409b5d 100644 --- a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt @@ -1,13 +1,16 @@ import java.io.* trait I { + throws(javaClass()) public fun doIt(stream: InputStream): Int } public class C() { + throws(javaClass()) fun foo(): Int { return FileInputStream("foo").use { stream -> bar(object : I { + throws(javaClass()) override fun doIt(stream: InputStream): Int { return stream.available() } @@ -15,6 +18,7 @@ public class C() { } } + throws(javaClass()) fun bar(i: I, stream: InputStream): Int { return i.doIt(stream) } From 7463da8fe0e6faa3c8c610d660aaaea37edecdf7 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 16 Jun 2014 20:26:51 +0400 Subject: [PATCH 074/143] Java to Kotlin: dropped Node interface --- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 5 +++-- j2k/src/org/jetbrains/jet/j2k/ast/Node.kt | 22 -------------------- j2k/src/org/jetbrains/jet/j2k/ast/Util.kt | 2 +- 3 files changed, 4 insertions(+), 25 deletions(-) delete mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/Node.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 4e4f0f2bed5..07a5282cf70 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -16,9 +16,10 @@ package org.jetbrains.jet.j2k.ast +trait Element { + public fun toKotlin(): String -trait Element : Node { - val isEmpty: Boolean get() = false + public val isEmpty: Boolean get() = false object Empty : Element { override fun toKotlin() = "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Node.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Node.kt deleted file mode 100644 index 39e27714dab..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Node.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2010-2013 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.j2k.ast - - -trait Node { - public fun toKotlin(): String -} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt index 739fecfb8a5..1df00b18f67 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt @@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -fun List.toKotlin(separator: String, prefix: String = "", postfix: String = ""): String +fun List.toKotlin(separator: String, prefix: String = "", postfix: String = ""): String = if (isNotEmpty()) map { it.toKotlin() }.makeString(separator, prefix, postfix) else "" fun String.withSuffix(suffix: String): String = if (isEmpty()) "" else this + suffix From 600446bbd2d089f47d1bf9700cc81b16dfe468db Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 17 Jun 2014 13:32:03 +0400 Subject: [PATCH 075/143] Java to Kotlin converter: working on not loosing comments - refactored redundant .toKotlin() calls --- .../actions/JavaToKotlinActionUtil.java | 2 +- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 63 ++++++++++--------- .../jet/j2k/JavaToKotlinTranslator.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/Utils.kt | 27 ++++---- .../org/jetbrains/jet/j2k/ast/Constructors.kt | 6 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 6 +- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Identifier.kt | 8 ++- j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 10 +-- .../jet/j2k/visitors/ElementVisitor.kt | 4 +- .../jet/j2k/visitors/ExpressionVisitor.kt | 8 +-- .../jet/j2k/visitors/StatementVisitor.kt | 2 +- .../jetbrains/jet/j2k/visitors/TypeVisitor.kt | 4 +- 13 files changed, 75 insertions(+), 69 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java index e52740e2a0b..5047f3e56f0 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinActionUtil.java @@ -124,7 +124,7 @@ public class JavaToKotlinActionUtil { if (psiFile instanceof PsiJavaFile && virtualFile != null) { String result = ""; try { - result = converter.convertFile((PsiJavaFile) psiFile).toKotlin(); + result = converter.elementToKotlin(psiFile); } catch (Exception e) { //noinspection CallToPrintStackTrace e.printStackTrace(); diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 77ffac60388..c0921baa502 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -60,7 +60,7 @@ public class Converter private(val project: Project, val settings: ConverterSett = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, state.expressionVisitorFactory, factory)) public fun elementToKotlin(element: PsiElement): String - = convertTopElement(element)?.toKotlin() ?: "" + = convertTopElement(element)?.toKotlin(/*CommentConverter(element)*/) ?: "" private fun convertTopElement(element: PsiElement?): Element? = when(element) { is PsiJavaFile -> convertFile(element) @@ -69,7 +69,7 @@ public class Converter private(val project: Project, val settings: ConverterSett is PsiField -> convertField(element) is PsiStatement -> convertStatement(element) is PsiExpression -> convertExpression(element) - is PsiComment -> Comment(element.getText()!!) + is PsiComment -> Comment(element.getText()!!/*, listOf(element)*/) is PsiImportList -> convertImportList(element) is PsiImportStatementBase -> convertImport(element, false) is PsiAnnotation -> convertAnnotation(element, false) @@ -78,7 +78,7 @@ public class Converter private(val project: Project, val settings: ConverterSett else -> null } - public fun convertFile(javaFile: PsiJavaFile): File { + fun convertFile(javaFile: PsiJavaFile): File { var convertedChildren = javaFile.getChildren().map { if (it is PsiImportList) { val importList = convertImportList(it) @@ -100,7 +100,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return File(FileMemberList(convertedChildren), createMainFunction(javaFile)) } - public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { + fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { return AnonymousClassBody(convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) } @@ -248,13 +248,13 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun generateArtificialPrimaryConstructor(className: Identifier, classBody: ClassBody): ClassBody { assert(classBody.primaryConstructor == null) - val finalOrWithEmptyInitializerFields = classBody.normalMembers.members.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.toKotlin().isEmpty() } - val initializers = HashMap() + val finalOrWithEmptyInitializerFields = classBody.normalMembers.members.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.isEmpty } + val initializers = HashMap() for (constructor in classBody.secondaryConstructors.members) { constructor as SecondaryConstructor for (field in finalOrWithEmptyInitializerFields) { - initializers.put(field.identifier.toKotlin(), getDefaultInitializer(field)) + initializers.put(field, getDefaultInitializer(field)) } val newStatements = ArrayList() @@ -262,11 +262,11 @@ public class Converter private(val project: Project, val settings: ConverterSett var keepStatement = true if (statement is AssignmentExpression) { val assignee = statement.left - if (assignee is QualifiedExpression) { + if (assignee is QualifiedExpression && (assignee.qualifier as? Identifier)?.name == SecondaryConstructor.tempValIdentifier.name) { + val name = (assignee.identifier as Identifier).name for (field in finalOrWithEmptyInitializerFields) { - val id = field.identifier.toKotlin() - if (assignee.identifier.toKotlin().endsWith("." + id)) { - initializers.put(id, statement.right.toKotlin()) + if (name == field.identifier.name) { + initializers.put(field, statement.right) keepStatement = false } @@ -280,7 +280,16 @@ public class Converter private(val project: Project, val settings: ConverterSett } } - newStatements.add(0, DummyStringExpression("val __ = " + createPrimaryConstructorInvocation(className.toKotlin(), finalOrWithEmptyInitializerFields, initializers))) + + val initializer = MethodCallExpression.buildNotNull(null, className.name, finalOrWithEmptyInitializerFields.map { initializers[it]!! }) + val localVar = LocalVariable(SecondaryConstructor.tempValIdentifier, + Annotations.Empty, + setOf(), + { ClassType(className, listOf(), Nullability.NotNull, settings) }, + initializer, + true, + settings) + newStatements.add(0, DeclarationStatement(listOf(localVar))) constructor.block = Block(newStatements) } @@ -506,7 +515,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return null } - public fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = {true}): Block { + fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = {true}): Block { if (block == null) return Block.Empty val filteredChildren = block.getChildren().filter { it !is PsiStatement || statementFilter(it) } @@ -514,7 +523,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return Block(statementList, notEmpty) } - public fun convertStatement(statement: PsiStatement?): Statement { + fun convertStatement(statement: PsiStatement?): Statement { if (statement == null) return Statement.Empty statementVisitor.reset() @@ -522,10 +531,10 @@ public class Converter private(val project: Project, val settings: ConverterSett return statementVisitor.result } - public fun convertExpressions(expressions: Array): List + fun convertExpressions(expressions: Array): List = expressions.map { convertExpression(it) } - public fun convertExpression(expression: PsiExpression?): Expression { + fun convertExpression(expression: PsiExpression?): Expression { if (expression == null) return Expression.Empty expressionVisitor.reset() @@ -533,7 +542,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return expressionVisitor.result } - public fun convertElement(element: PsiElement?): Element { + fun convertElement(element: PsiElement?): Element { if (element == null) return Element.Empty val elementVisitor = ElementVisitor(this) @@ -541,16 +550,16 @@ public class Converter private(val project: Project, val settings: ConverterSett return elementVisitor.result } - public fun convertTypeElement(element: PsiTypeElement?): TypeElement + fun convertTypeElement(element: PsiTypeElement?): TypeElement = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())) private fun convertToNotNullableTypes(types: Array): List = types.map { typeConverter.convertType(it, Nullability.NotNull) } - public fun convertParameterList(parameterList: PsiParameterList): ParameterList + fun convertParameterList(parameterList: PsiParameterList): ParameterList = ParameterList(parameterList.getParameters().map { convertParameter(it) }) - public fun convertParameter(parameter: PsiParameter, + fun convertParameter(parameter: PsiParameter, nullability: Nullability = Nullability.Default, varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None, modifiers: Collection = listOf()): Parameter { @@ -562,7 +571,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, convertAnnotations(parameter), modifiers) } - public fun convertExpression(argument: PsiExpression?, expectedType: PsiType?): Expression { + fun convertExpression(argument: PsiExpression?, expectedType: PsiType?): Expression { if (argument == null) return Identifier.Empty var expression = convertExpression(argument) @@ -590,17 +599,13 @@ public class Converter private(val project: Project, val settings: ConverterSett return expression } - private fun createPrimaryConstructorInvocation(s: String, fields: List, initializers: Map): String { - return s + "(" + fields.map { initializers[it.identifier.toKotlin()] }.makeString(", ") + ")" - } - - public fun convertIdentifier(identifier: PsiIdentifier?): Identifier { + fun convertIdentifier(identifier: PsiIdentifier?): Identifier { if (identifier == null) return Identifier.Empty return Identifier(identifier.getText()!!) } - public fun convertModifiers(owner: PsiModifierListOwner): MutableSet + fun convertModifiers(owner: PsiModifierListOwner): MutableSet = HashSet(MODIFIERS_MAP.filter { owner.hasModifierProperty(it.first) }.map { it.second }) private val MODIFIERS_MAP = listOf( @@ -610,7 +615,7 @@ public class Converter private(val project: Project, val settings: ConverterSett PsiModifier.PRIVATE to Modifier.PRIVATE ) - public fun convertAnnotations(owner: PsiModifierListOwner): Annotations { + fun convertAnnotations(owner: PsiModifierListOwner): Annotations { val modifierList = owner.getModifierList() val annotations = modifierList?.getAnnotations()?.filter { it.getQualifiedName() !in ANNOTATIONS_TO_REMOVE } if (annotations == null || annotations.isEmpty()) return Annotations.Empty @@ -633,7 +638,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return Annotations(list, newLines) } - public fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean): Annotation? { + private fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean): Annotation? { val qualifiedName = annotation.getQualifiedName() if (qualifiedName == CommonClassNames.JAVA_LANG_DEPRECATED && annotation.getParameterList().getAttributes().isEmpty()) { return Annotation(Identifier("deprecated"), listOf(null to LiteralExpression("\"\"")), brackets) //TODO: insert comment diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt index 355a5d846c5..8c97cd0e710 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt @@ -90,7 +90,7 @@ public object JavaToKotlinTranslator { val file = createFile(javaCode) if (file is PsiJavaFile) { val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) - return prettify(converter.convertFile(file).toKotlin()) + return prettify(converter.elementToKotlin(file)) } return "" } diff --git a/j2k/src/org/jetbrains/jet/j2k/Utils.kt b/j2k/src/org/jetbrains/jet/j2k/Utils.kt index d887d22b105..196db199a0d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Utils.kt @@ -16,14 +16,12 @@ package org.jetbrains.jet.j2k -import org.jetbrains.jet.j2k.ast.Identifier -import org.jetbrains.jet.j2k.ast.Field import org.jetbrains.jet.lang.types.expressions.OperatorConventions -import org.jetbrains.jet.j2k.ast.Nullability import com.intellij.psi.* import com.intellij.psi.util.PsiUtil import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch +import org.jetbrains.jet.j2k.ast.* fun quoteKeywords(packageName: String): String = packageName.split("\\.").map { Identifier(it).toKotlin() }.makeString(".") @@ -59,19 +57,22 @@ fun PsiModifierListOwner.nullabilityFromAnnotations(): Nullability { Nullability.Default } -fun getDefaultInitializer(field: Field): String { - if (field.`type`.isNullable) { - return "null" +fun getDefaultInitializer(field: Field): Expression { + val t = field.`type` + if (t.isNullable) { + return LiteralExpression("null") } - else { - return when(field.`type`.toKotlin()) { - "Boolean" -> "false" - "Char" -> "' '" - "Double" -> "0." + OperatorConventions.DOUBLE + "()" - "Float" -> "0." + OperatorConventions.FLOAT + "()" - else -> "0" + + if (t is PrimitiveType) { + when(t.`type`.name) { + "Boolean" -> return LiteralExpression("false") + "Char" -> return LiteralExpression("' '") + "Double" -> return MethodCallExpression.buildNotNull(LiteralExpression("0"), OperatorConventions.DOUBLE.toString()) + "Float" -> return MethodCallExpression.buildNotNull(LiteralExpression("0"), OperatorConventions.FLOAT.toString()) } } + + return LiteralExpression("0") } fun isQualifierEmptyOrThis(ref: PsiReferenceExpression): Boolean { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 2fdef678779..bd33205e1cd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -57,7 +57,7 @@ class SecondaryConstructor(converter: Converter, public fun toInitFunction(containingClass: Class): Function { val modifiers = HashSet(modifiers) val statements = ArrayList(block?.statements ?: listOf()) - statements.add(ReturnStatement(Identifier("__"))) + statements.add(ReturnStatement(tempValIdentifier)) val block = Block(statements) val typeParameters = ArrayList() typeParameters.addAll(containingClass.typeParameterList.parameters) @@ -65,4 +65,8 @@ class SecondaryConstructor(converter: Converter, ClassType(containingClass.name, typeParameters, Nullability.NotNull, converter.settings), TypeParameterList(typeParameters), parameterList, block, false) } + + class object { + public val tempValIdentifier: Identifier = Identifier("__", false) + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index e1e5d1ead1e..d5eb98c534b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -71,13 +71,13 @@ class SuperExpression(val identifier: Identifier) : Expression() { override fun toKotlin() = "super" + identifier.withPrefix("@") } -class QualifiedExpression(val expression: Expression, val identifier: Expression) : Expression() { +class QualifiedExpression(val qualifier: Expression, val identifier: Expression) : Expression() { override val isNullable: Boolean get() = identifier.isNullable override fun toKotlin(): String { - if (!expression.isEmpty) { - return operandToKotlin(expression) + (if (expression.isNullable) "!!." else ".") + identifier.toKotlin() + if (!qualifier.isEmpty) { + return operandToKotlin(qualifier) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin() } return identifier.toKotlin() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index 8e34ece0e49..ac07c21bd4f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -33,7 +33,7 @@ open class Field( override fun toKotlin(): String { val declaration = commentsToKotlin() + annotations.toKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin() return if (initializer.isEmpty) - declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this)) + declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin()) else declaration + " = " + initializer.toKotlin() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt index f8e409769c9..fb417e38a9a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt @@ -26,7 +26,7 @@ class Identifier( override val isEmpty: Boolean get() = name.isEmpty() - override fun toKotlin(): String { + private fun identifierToKotlin(): String { if (quotingNeeded && ONLY_KOTLIN_KEYWORDS.contains(name) || name.contains("$")) { return quote(name) } @@ -34,6 +34,8 @@ class Identifier( return name } + override fun toKotlin(): String = identifierToKotlin() + private fun quote(str: String): String = "`" + str + "`" override fun toString() = if (isNullable) "$name?" else name @@ -43,6 +45,8 @@ class Identifier( val ONLY_KOTLIN_KEYWORDS: Set = setOf( "package", "as", "type", "val", "var", "fun", "is", "in", "object", "when", "trait", "This" - ); + ) + + fun toKotlin(name: String): String = Identifier(name).identifierToKotlin() } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 35c21717bde..d9323120e59 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -79,15 +79,7 @@ class ClassType(val `type`: Identifier, val typeArgs: List, nullability : MayBeNullableType(nullability, settings) { override fun toKotlin(): String { - // TODO change to map() when KT-2051 is fixed - val parametersToKotlin = ArrayList() - for (param in typeArgs) { - parametersToKotlin.add(param.toKotlin()) - } - var params: String = if (parametersToKotlin.size() == 0) - "" - else - "<" + parametersToKotlin.makeString(", ") + ">" + var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin() }.makeString(", ", "<", ">") return `type`.toKotlin() + params + isNullableStr() } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt index 8732312f2d4..6a370792ceb 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt @@ -46,11 +46,11 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { result = ReferenceElement(Identifier(reference.getReferenceName()!!), types) } else { - var code = Identifier(reference.getReferenceName()!!).toKotlin() + var code = Identifier.toKotlin(reference.getReferenceName()!!) var qualifier = reference.getQualifier() while (qualifier != null) { val p = qualifier as PsiJavaCodeReferenceElement - code = Identifier(p.getReferenceName()!!).toKotlin() + "." + code + code = Identifier.toKotlin(p.getReferenceName()!!) + "." + code qualifier = p.getQualifier() } result = ReferenceElement(Identifier(code), types) diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 478fc774ae0..f3e0d56830f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -306,7 +306,7 @@ class ExpressionVisitor(private val converter: Converter, val insideSecondaryConstructor = containingConstructor != null && !containingConstructor.isPrimaryConstructor() if (insideSecondaryConstructor && (expression.getReference()?.resolve() as? PsiField)?.getContainingClass() == containingConstructor!!.getContainingClass()) { - identifier = QualifiedExpression(Identifier("__", false), Identifier(referencedName, isNullable)) + identifier = QualifiedExpression(SecondaryConstructor.tempValIdentifier, Identifier(referencedName, isNullable)) } else if (insideSecondaryConstructor && expression.isThisConstructorCall()) { identifier = Identifier("val __ = " + (containingConstructor?.getContainingClass()?.getNameIdentifier()?.getText() ?: "")) @@ -336,9 +336,9 @@ class ExpressionVisitor(private val converter: Converter, && !PsiTreeUtil.isAncestor(target.getContainingClass(), expression, true) && !isStaticallyImported(target, expression)) { var member: PsiMember = target - var code = Identifier(referencedName).toKotlin() + var code = Identifier.toKotlin(referencedName) while (member.getContainingClass() != null) { - code = Identifier(member.getContainingClass()!!.getName()!!).toKotlin() + "." + code + code = Identifier.toKotlin(member.getContainingClass()!!.getName()!!) + "." + code member = member.getContainingClass()!! } result = Identifier(code, false, false) @@ -354,7 +354,7 @@ class ExpressionVisitor(private val converter: Converter, } - result = QualifiedExpression(converter.convertExpression(qualifier), identifier) + result = if (qualifier != null) QualifiedExpression(converter.convertExpression(qualifier), identifier) else identifier } override fun visitSuperExpression(expression: PsiSuperExpression) { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index 9719fe6dcf9..feb536f6856 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -273,7 +273,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito var statementList = bodyConverted.statementList var expression: Expression = Expression.Empty for (variable in variables.reverse()) { - val lambda = LambdaExpression(Identifier(variable.getName()!!).toKotlin(), statementList) + val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), statementList) expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda) statementList = StatementList(listOf(expression)) } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index 9e1eaa766e9..9ab3db30cec 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -85,11 +85,11 @@ class TypeVisitor(private val converter: TypeConverter, private val classesToImp if (classType is PsiClassReferenceType) { val reference = classType.getReference() if (reference.isQualified()) { - var result = Identifier(reference.getReferenceName()!!).toKotlin() + var result = Identifier.toKotlin(reference.getReferenceName()!!) var qualifier = reference.getQualifier() while (qualifier != null) { val codeRefElement = qualifier as PsiJavaCodeReferenceElement - result = Identifier(codeRefElement.getReferenceName()!!).toKotlin() + "." + result + result = Identifier.toKotlin(codeRefElement.getReferenceName()!!) + "." + result qualifier = codeRefElement.getQualifier() } return Identifier(result) From c4bac83cc9713fcdc7356b2c78fb8e114507b247 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 17 Jun 2014 13:36:22 +0400 Subject: [PATCH 076/143] Java to Kotlin converter: working on not loosing comments - Element made Class instead of Trait --- .../org/jetbrains/jet/j2k/CommentConverter.kt | 58 +++++++++++++++++++ .../org/jetbrains/jet/j2k/ast/Annotation.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 10 ++-- j2k/src/org/jetbrains/jet/j2k/ast/File.kt | 4 +- j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt | 4 +- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Members.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 2 +- .../jetbrains/jet/j2k/ast/ParameterList.kt | 2 +- .../jetbrains/jet/j2k/ast/ReferenceElement.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Statements.kt | 2 +- .../org/jetbrains/jet/j2k/ast/TypeElement.kt | 2 +- .../jetbrains/jet/j2k/ast/TypeParameters.kt | 9 +-- .../org/jetbrains/jet/j2k/ast/WhiteSpace.kt | 2 +- 14 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt b/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt new file mode 100644 index 00000000000..eec149b07d1 --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2014 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.j2k + +import com.intellij.psi.* +import java.util.ArrayList +import org.jetbrains.jet.j2k.ast.Element + +class CommentConverter(private val topElement: PsiElement) { + private enum class CommentPlacement { + Before + SameLineBefore + SameLineAfter + After + } + + private class CommentInfo(val comment: PsiComment) { + val startOffset: Int + val endOffset: Int + var isAttached = false + + { + val range = comment.getTextRange()!! + startOffset = range.getStartOffset() + endOffset = range.getEndOffset() + } + } + + private val allComments: List = run { + val list = ArrayList() + topElement.accept(object : JavaRecursiveElementVisitor(){ + override fun visitComment(comment: PsiComment) { + list.add(CommentInfo(comment)) + } + }) + list + } + + /* + public fun toKotlin(elementToKotlin: () -> String, originalElements: List): String { + + } + */ +} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index d1632772225..37cd44175cf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast import java.util.HashSet -class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean) : Element { +class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean) : Element() { private fun surroundWithBrackets(text: String) = if (brackets) "[$text]" else text override fun toKotlin(): String { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 07a5282cf70..9ce7175baf5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -16,17 +16,17 @@ package org.jetbrains.jet.j2k.ast -trait Element { - public fun toKotlin(): String +abstract class Element { + public abstract fun toKotlin(): String - public val isEmpty: Boolean get() = false + public open val isEmpty: Boolean get() = false - object Empty : Element { + object Empty : Element() { override fun toKotlin() = "" override val isEmpty: Boolean get() = true } } -class Comment(val text: String) : Element { +class Comment(val text: String) : Element() { override fun toKotlin() = text } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt index 351fbf149ce..2e625434767 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt @@ -18,14 +18,14 @@ package org.jetbrains.jet.j2k.ast class FileMemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine, false) -class PackageStatement(val packageName: String) : Element { +class PackageStatement(val packageName: String) : Element() { override fun toKotlin(): String = "package " + packageName } class File( val body: FileMemberList, val mainFunction: String -) : Element { +) : Element() { override fun toKotlin(): String { return body.toKotlin() + mainFunction diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt index c1af1fd9b11..ce658abb8a2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt @@ -24,11 +24,11 @@ import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap import com.intellij.psi.PsiJavaCodeReferenceElement import org.jetbrains.jet.asJava.KotlinLightClassForPackage -class Import(val name: String) : Element { +class Import(val name: String) : Element() { override fun toKotlin() = "import " + name } -class ImportList(public val imports: List) : Element { +class ImportList(public val imports: List) : Element() { override val isEmpty: Boolean get() = imports.isEmpty() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index 52cf1a7c575..c3668b6563d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -26,7 +26,7 @@ class LocalVariable( private val initializer: Expression, private val isVal: Boolean, private val settings: ConverterSettings -) : Element { +) : Element() { override fun toKotlin(): String { val start = annotations.toKotlin() + if (isVal) "val" else "var" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt index 7b74c695e09..abf43f9d002 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt @@ -30,7 +30,7 @@ class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(e } } -abstract class Member(val comments: MemberComments, val annotations: Annotations, val modifiers: Set) : Element { +abstract class Member(val comments: MemberComments, val annotations: Annotations, val modifiers: Set) : Element() { fun commentsToKotlin(): String = comments.toKotlin() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 70ce20c83ed..1e133700619 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -20,7 +20,7 @@ class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parameter.VarValModifier, val annotations: Annotations, - val modifiers: Collection) : Element { + val modifiers: Collection) : Element() { public enum class VarValModifier { None Val diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt index d87508ec2c5..f4b35a9cc3f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast -open class ParameterList(val parameters: List) : Element { +open class ParameterList(val parameters: List) : Element() { override fun toKotlin() = parameters.map { it.toKotlin() }.makeString(", ") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt index 4c551aa1176..b2045e8dd63 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt @@ -16,6 +16,6 @@ package org.jetbrains.jet.j2k.ast -class ReferenceElement(val reference: Identifier, val types: List) : Element { +class ReferenceElement(val reference: Identifier, val types: List) : Element() { override fun toKotlin() = reference.toKotlin() + types.toKotlin(", ", "<", ">") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt index 3e1e786d122..577e66b663c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast -abstract class Statement() : Element { +abstract class Statement() : Element() { object Empty : Statement() { override fun toKotlin() = "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt index 5b0e8cc1bc7..320efd119b8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -class TypeElement(val `type`: Type) : Element { +class TypeElement(val `type`: Type) : Element() { override fun toKotlin() = `type`.toKotlin() fun toKotlinNotNull(): String = `type`.toNotNullType().toKotlin() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt index a1d3b5bd199..87c1a0ef95c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt @@ -21,11 +21,12 @@ import org.jetbrains.jet.j2k.Converter import com.intellij.psi.PsiTypeParameterList import java.util.ArrayList -class TypeParameter(val name: Identifier, val extendsTypes: List) : Element { +class TypeParameter(val name: Identifier, val extendsTypes: List) : Element() { fun hasWhere(): Boolean = extendsTypes.size() > 1 + fun getWhereToKotlin(): String { if (hasWhere()) { - return name.toKotlin() + " : " + extendsTypes.get(1).toKotlin() + return name.toKotlin() + " : " + extendsTypes[1].toKotlin() } return "" @@ -33,14 +34,14 @@ class TypeParameter(val name: Identifier, val extendsTypes: List) : Elemen override fun toKotlin(): String { if (extendsTypes.size() > 0) { - return name.toKotlin() + " : " + extendsTypes [0].toKotlin() + return name.toKotlin() + " : " + extendsTypes[0].toKotlin() } return name.toKotlin() } } -class TypeParameterList(val parameters: List) : Element { +class TypeParameterList(val parameters: List) : Element() { override fun toKotlin(): String = if (!parameters.isEmpty()) parameters.map { it.toKotlin() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt b/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt index 4f0e275932a..3f5c1b8835c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast -class WhiteSpace(val text: String) : Element { +class WhiteSpace(val text: String) : Element() { override fun toKotlin() = text override val isEmpty: Boolean From d01a2237b5a171f7282270adbbc3aabb7ddbe959 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 17 Jun 2014 14:11:08 +0400 Subject: [PATCH 077/143] Java to Kotlin converter: working on not loosing comments - CommentConverter is passed when converting to Kotlin --- .../org/jetbrains/jet/j2k/CommentConverter.kt | 8 ++- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/Utils.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Annotation.kt | 18 +++--- .../jet/j2k/ast/AnonymousClassBody.kt | 5 +- .../ArrayWithoutInitializationExpression.kt | 53 +++++++-------- j2k/src/org/jetbrains/jet/j2k/ast/Block.kt | 5 +- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 37 +++++------ .../org/jetbrains/jet/j2k/ast/Constructors.kt | 7 +- .../jet/j2k/ast/DummyStringExpression.kt | 4 +- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 10 ++- j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 22 ++++--- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 10 +-- .../org/jetbrains/jet/j2k/ast/Expression.kt | 4 +- .../jetbrains/jet/j2k/ast/ExpressionList.kt | 4 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 53 +++++++-------- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 14 ++-- j2k/src/org/jetbrains/jet/j2k/ast/File.kt | 8 ++- j2k/src/org/jetbrains/jet/j2k/ast/Function.kt | 19 +++--- .../org/jetbrains/jet/j2k/ast/Identifier.kt | 8 ++- j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt | 4 +- .../org/jetbrains/jet/j2k/ast/Initializer.kt | 6 +- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 11 ++-- j2k/src/org/jetbrains/jet/j2k/ast/Members.kt | 23 +++---- .../jet/j2k/ast/MethodCallExpression.kt | 12 ++-- j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt | 2 + .../jet/j2k/ast/NewClassExpression.kt | 14 ++-- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 8 ++- .../jetbrains/jet/j2k/ast/ParameterList.kt | 4 +- .../jetbrains/jet/j2k/ast/ReferenceElement.kt | 4 +- .../org/jetbrains/jet/j2k/ast/Statements.kt | 54 ++++++++-------- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 4 +- .../org/jetbrains/jet/j2k/ast/TypeElement.kt | 6 +- .../jetbrains/jet/j2k/ast/TypeParameters.kt | 34 +++++----- j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 64 +++++++++---------- j2k/src/org/jetbrains/jet/j2k/ast/Util.kt | 15 +++-- .../org/jetbrains/jet/j2k/ast/WhiteSpace.kt | 4 +- 37 files changed, 308 insertions(+), 254 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt b/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt index eec149b07d1..ce9f22c79cf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt @@ -20,7 +20,7 @@ import com.intellij.psi.* import java.util.ArrayList import org.jetbrains.jet.j2k.ast.Element -class CommentConverter(private val topElement: PsiElement) { +class CommentConverter(private val topElement: PsiElement?) { private enum class CommentPlacement { Before SameLineBefore @@ -42,7 +42,7 @@ class CommentConverter(private val topElement: PsiElement) { private val allComments: List = run { val list = ArrayList() - topElement.accept(object : JavaRecursiveElementVisitor(){ + topElement?.accept(object : JavaRecursiveElementVisitor(){ override fun visitComment(comment: PsiComment) { list.add(CommentInfo(comment)) } @@ -55,4 +55,8 @@ class CommentConverter(private val topElement: PsiElement) { } */ + + class object { + val Dummy: CommentConverter = CommentConverter(null) + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index c0921baa502..6cbc279c55e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -60,7 +60,7 @@ public class Converter private(val project: Project, val settings: ConverterSett = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, state.expressionVisitorFactory, factory)) public fun elementToKotlin(element: PsiElement): String - = convertTopElement(element)?.toKotlin(/*CommentConverter(element)*/) ?: "" + = convertTopElement(element)?.toKotlin(CommentConverter(element)) ?: "" private fun convertTopElement(element: PsiElement?): Element? = when(element) { is PsiJavaFile -> convertFile(element) diff --git a/j2k/src/org/jetbrains/jet/j2k/Utils.kt b/j2k/src/org/jetbrains/jet/j2k/Utils.kt index 196db199a0d..90dfa838385 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Utils.kt @@ -23,7 +23,7 @@ import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch import org.jetbrains.jet.j2k.ast.* -fun quoteKeywords(packageName: String): String = packageName.split("\\.").map { Identifier(it).toKotlin() }.makeString(".") +fun quoteKeywords(packageName: String): String = packageName.split("\\.").map { Identifier.toKotlin(it) }.makeString(".") fun findVariableUsages(variable: PsiVariable, scope: PsiElement): Collection { return ReferencesSearch.search(variable, LocalSearchScope(scope)).findAll().filterIsInstance(javaClass()) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index 37cd44175cf..5345c90d6ff 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -16,30 +16,32 @@ package org.jetbrains.jet.j2k.ast -import java.util.HashSet +import org.jetbrains.jet.j2k.CommentConverter class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean) : Element() { private fun surroundWithBrackets(text: String) = if (brackets) "[$text]" else text - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { if (arguments.isEmpty()) { - return surroundWithBrackets(name.toKotlin()) + return surroundWithBrackets(name.toKotlin(commentConverter)) } val argsText = arguments.map { if (it.first != null) - it.first!!.toKotlin() + " = " + it.second.toKotlin() + it.first!!.toKotlin(commentConverter) + " = " + it.second.toKotlin(commentConverter) else - it.second.toKotlin() + it.second.toKotlin(commentConverter) }.makeString(", ") - return surroundWithBrackets(name.toKotlin() + "(" + argsText + ")") + return surroundWithBrackets(name.toKotlin(commentConverter) + "(" + argsText + ")") } } -class Annotations(val annotations: List, val newLines: Boolean) { +class Annotations(val annotations: List, val newLines: Boolean) : Element() { private val br = if (newLines) "\n" else " " - fun toKotlin(): String = if (annotations.isNotEmpty()) annotations.map { it.toKotlin() }.makeString(br) + br else "" + override fun toKotlinImpl(commentConverter: CommentConverter): String { + return if (annotations.isNotEmpty()) annotations.map { it.toKotlin(commentConverter) }.makeString(br) + br else "" + } fun plus(other: Annotations) = Annotations(annotations + other.annotations, newLines || other.newLines) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index 87535864a53..d2606aaba63 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -16,10 +16,9 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.Converter -import java.util.Collections +import org.jetbrains.jet.j2k.CommentConverter class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) : Class(Identifier(""), MemberComments.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { - override fun toKotlin() = body.toKotlin(null) + override fun toKotlinImpl(commentConverter: CommentConverter) = body.toKotlin(null, commentConverter) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt index 631196362b9..96eb2a3c8ee 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt @@ -16,38 +16,41 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + open class ArrayWithoutInitializationExpression(val `type`: ArrayType, val expressions: List) : Expression() { - override fun toKotlin(): String - = constructInnerType(`type`, expressions) - - private fun constructInnerType(hostType: ArrayType, expressions: List): String { - if (expressions.size() == 1) { - return oneDim(hostType, expressions[0]) + override fun toKotlinImpl(commentConverter: CommentConverter): String { + fun getConstructorName(`type`: ArrayType, hasInit: Boolean): String { + return when (`type`.elementType) { + is PrimitiveType -> + `type`.toNotNullType().toKotlin(commentConverter) + is ArrayType -> + if (hasInit) + `type`.toNotNullType().toKotlin(commentConverter) + else + "arrayOfNulls<" + `type`.elementType.toKotlin(commentConverter) + ">" + else -> + "arrayOfNulls<" + `type`.elementType.toKotlin(commentConverter) + ">" + } } - val innerType = hostType.elementType - if (expressions.size() > 1 && innerType is ArrayType) { - return oneDim(hostType, expressions[0], "{" + constructInnerType(innerType, expressions.subList(1, expressions.size())) + "}") + fun oneDim(`type`: ArrayType, size: Expression, init: String = ""): String { + return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin(commentConverter) + init.withPrefix(", ") + ")" } - return getConstructorName(hostType, expressions.size() != 0) - } + fun constructInnerType(hostType: ArrayType, expressions: List): String { + if (expressions.size() == 1) { + return oneDim(hostType, expressions[0]) + } - private fun oneDim(`type`: ArrayType, size: Expression, init: String = ""): String { - return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin() + init.withPrefix(", ") + ")" - } + val innerType = hostType.elementType + if (expressions.size() > 1 && innerType is ArrayType) { + return oneDim(hostType, expressions[0], "{" + constructInnerType(innerType, expressions.subList(1, expressions.size())) + "}") + } - private fun getConstructorName(`type`: ArrayType, hasInit: Boolean): String { - return when (`type`.elementType) { - is PrimitiveType -> - `type`.toNotNullType().toKotlin() - is ArrayType -> - if (hasInit) - `type`.toNotNullType().toKotlin() - else - "arrayOfNulls<" + `type`.elementType.toKotlin() + ">" - else -> - "arrayOfNulls<" + `type`.elementType.toKotlin() + ">" + return getConstructorName(hostType, expressions.size() != 0) } + + return constructInnerType(`type`, expressions) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt index 807e51a27f0..ebccce581b1 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt @@ -17,6 +17,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList +import org.jetbrains.jet.j2k.CommentConverter fun Block(statements: List, notEmpty: Boolean = false): Block { val elements = ArrayList() @@ -33,9 +34,9 @@ class Block(val statementList: StatementList, val notEmpty: Boolean = false) : S override val isEmpty: Boolean get() = !notEmpty && statements.all { it.isEmpty } - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { if (!isEmpty) { - return "{${statementList.toKotlin()}}" + return "{${statementList.toKotlin(commentConverter)}}" } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index 89341e7f4ba..c9b80664aca 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -17,6 +17,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList +import org.jetbrains.jet.j2k.CommentConverter open class Class( val name: Identifier, @@ -30,35 +31,35 @@ open class Class( val body: ClassBody ) : Member(comments, annotations, modifiers) { - override fun toKotlin(): String = - commentsToKotlin() + - annotations.toKotlin() + + override fun toKotlinImpl(commentConverter: CommentConverter): String = + commentsToKotlin(commentConverter) + + annotations.toKotlin(commentConverter) + modifiersToKotlin() + - keyword + " " + name.toKotlin() + - typeParameterList.toKotlin() + - primaryConstructorSignatureToKotlin() + - implementTypesToKotlin() + - typeParameterList.whereToKotlin().withPrefix(" ") + - body.toKotlin(this) + keyword + " " + name.toKotlin(commentConverter) + + typeParameterList.toKotlin(commentConverter) + + primaryConstructorSignatureToKotlin(commentConverter) + + implementTypesToKotlin(commentConverter) + + typeParameterList.whereToKotlin(commentConverter).withPrefix(" ") + + body.toKotlin(this, commentConverter) protected open val keyword: String get() = "class" - protected open fun primaryConstructorSignatureToKotlin(): String - = body.primaryConstructor?.signatureToKotlin() ?: "()" + protected open fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter): String + = body.primaryConstructor?.signatureToKotlin(commentConverter) ?: "()" - private fun baseClassSignatureWithParams(): List { + private fun baseClassSignatureWithParams(commentConverter: CommentConverter): List { if (keyword.equals("class") && extendsTypes.size() == 1) { - val baseParams = baseClassParams.toKotlin(", ") - return arrayListOf(extendsTypes[0].toKotlin() + "(" + baseParams + ")") + val baseParams = baseClassParams.toKotlin(commentConverter, ", ") + return arrayListOf(extendsTypes[0].toKotlin(commentConverter) + "(" + baseParams + ")") } - return extendsTypes.map { it.toKotlin() } + return extendsTypes.map { it.toKotlin(commentConverter) } } - protected fun implementTypesToKotlin(): String { + protected fun implementTypesToKotlin(commentConverter: CommentConverter): String { val allTypes = ArrayList() - allTypes.addAll(baseClassSignatureWithParams()) - allTypes.addAll(implementsTypes.map { it.toKotlin() }) + allTypes.addAll(baseClassSignatureWithParams(commentConverter)) + allTypes.addAll(implementsTypes.map { it.toKotlin(commentConverter) }) return if (allTypes.size() == 0) "" else diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index bd33205e1cd..2f6c3287922 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -19,6 +19,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.HashSet import java.util.ArrayList +import org.jetbrains.jet.j2k.CommentConverter abstract class Constructor( converter: Converter, @@ -37,13 +38,13 @@ class PrimaryConstructor(converter: Converter, block: Block) : Constructor(converter, comments, annotations, modifiers, parameterList, block) { - public fun signatureToKotlin(): String { + public fun signatureToKotlin(commentConverter: CommentConverter): String { val accessModifier = modifiers.accessModifier() val modifiersString = if (accessModifier != null && accessModifier != Modifier.PUBLIC) " " + accessModifier.toKotlin() else "" - return modifiersString + "(" + parameterList.toKotlin() + ")" + return modifiersString + "(" + parameterList.toKotlin(commentConverter) + ")" } - public fun bodyToKotlin(): String = block!!.toKotlin() + public fun bodyToKotlin(commentConverter: CommentConverter): String = block!!.toKotlin(commentConverter) } class SecondaryConstructor(converter: Converter, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt index 3971b3acb04..248b9bbf902 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class DummyStringExpression(val string: String) : Expression() { - override fun toKotlin(): String = string + override fun toKotlinImpl(commentConverter: CommentConverter): String = string } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 9ce7175baf5..83cee59e7de 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -16,17 +16,21 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + abstract class Element { - public abstract fun toKotlin(): String + public fun toKotlin(commentConverter: CommentConverter): String = toKotlinImpl(commentConverter) + + protected abstract fun toKotlinImpl(commentConverter: CommentConverter): String public open val isEmpty: Boolean get() = false object Empty : Element() { - override fun toKotlin() = "" + override fun toKotlinImpl(commentConverter: CommentConverter) = "" override val isEmpty: Boolean get() = true } } class Comment(val text: String) : Element() { - override fun toKotlin() = text + override fun toKotlinImpl(commentConverter: CommentConverter) = text } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index f0ab0b3f621..1bf0f80eb70 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class Enum( name: Identifier, comments: MemberComments, @@ -29,17 +31,17 @@ class Enum( ) : Class(name, comments, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { - override fun primaryConstructorSignatureToKotlin(): String - = body.primaryConstructor?.signatureToKotlin() ?: "" + override fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter): String + = body.primaryConstructor?.signatureToKotlin(commentConverter) ?: "" - override fun toKotlin(): String { - return commentsToKotlin() + - annotations.toKotlin() + + override fun toKotlinImpl(commentConverter: CommentConverter): String { + return commentsToKotlin(commentConverter) + + annotations.toKotlin(commentConverter) + modifiersToKotlin() + - "enum class " + name.toKotlin() + - primaryConstructorSignatureToKotlin() + - typeParameterList.toKotlin() + - implementTypesToKotlin() + - body.toKotlin(this) + "enum class " + name.toKotlin(commentConverter) + + primaryConstructorSignatureToKotlin(commentConverter) + + typeParameterList.toKotlin(commentConverter) + + implementTypesToKotlin(commentConverter) + + body.toKotlin(this, commentConverter) } } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index a3c2b2808b4..d38ac5675f3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class EnumConstant( identifier: Identifier, members: MemberComments, @@ -25,12 +27,12 @@ class EnumConstant( params: Element ) : Field(identifier, members, annotations, modifiers, `type`.toNotNullType(), params, true, false) { - override fun toKotlin(): String { - if (initializer.toKotlin().isEmpty()) { - return annotations.toKotlin() + identifier.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter): String { + if (initializer.toKotlin(commentConverter).isEmpty()) { + return annotations.toKotlin(commentConverter) + identifier.toKotlin(commentConverter) } - return annotations.toKotlin() + identifier.toKotlin() + " : " + `type`.toKotlin() + "(" + initializer.toKotlin() + ")" + return annotations.toKotlin(commentConverter) + identifier.toKotlin(commentConverter) + " : " + `type`.toKotlin(commentConverter) + "(" + initializer.toKotlin(commentConverter) + ")" } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt index 2152a1d6fa3..2aeba61b327 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt @@ -16,12 +16,14 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + abstract class Expression() : Statement() { open val isNullable: Boolean get() = false object Empty : Expression() { - override fun toKotlin() = "" + override fun toKotlinImpl(commentConverter: CommentConverter) = "" override val isEmpty: Boolean get() = true } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt index 614dd5f9114..082acb95d3b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt @@ -16,8 +16,10 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + open class ExpressionList(val expressions: List) : Expression() { - override fun toKotlin(): String = expressions.map { it.toKotlin() }.makeString(", ") + override fun toKotlinImpl(commentConverter: CommentConverter): String = expressions.map { it.toKotlin(commentConverter) }.makeString(", ") override val isEmpty: Boolean get() = expressions.isEmpty() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index d5eb98c534b..699e727752d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -17,83 +17,84 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.lang.types.expressions.OperatorConventions +import org.jetbrains.jet.j2k.CommentConverter class ArrayAccessExpression(val expression: Expression, val index: Expression, val lvalue: Boolean) : Expression() { - override fun toKotlin() = operandToKotlin(expression) + + override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + (if (!lvalue && expression.isNullable) "!!" else "") + - "[" + index.toKotlin() + "]" + "[" + index.toKotlin(commentConverter) + "]" } class AssignmentExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlin() = operandToKotlin(left) + " " + op + " " + operandToKotlin(right) + override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(left, commentConverter) + " " + op + " " + operandToKotlin(right, commentConverter) } class BangBangExpression(val expr: Expression) : Expression() { - override fun toKotlin() = operandToKotlin(expr) + "!!" + override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expr, commentConverter) + "!!" } class BinaryExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlin() = operandToKotlin(left, false) + " " + op + " " + operandToKotlin(right, true) + override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(left, commentConverter, false) + " " + op + " " + operandToKotlin(right, commentConverter, true) } class IsOperator(val expression: Expression, val typeElement: TypeElement) : Expression() { - override fun toKotlin() = operandToKotlin(expression) + " is " + typeElement.toKotlinNotNull() + override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + " is " + typeElement.`type`.toNotNullType().toKotlin(commentConverter) } class TypeCastExpression(val `type`: Type, val expression: Expression) : Expression() { - override fun toKotlin() = operandToKotlin(expression) + " as " + `type`.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + " as " + `type`.toKotlin(commentConverter) } class LiteralExpression(val literalText: String) : Expression() { - override fun toKotlin() = literalText + override fun toKotlinImpl(commentConverter: CommentConverter) = literalText } class ParenthesizedExpression(val expression: Expression) : Expression() { - override fun toKotlin() = "(" + expression.toKotlin() + ")" + override fun toKotlinImpl(commentConverter: CommentConverter) = "(" + expression.toKotlin(commentConverter) + ")" } class PrefixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlin() = op + operandToKotlin(expression) + override fun toKotlinImpl(commentConverter: CommentConverter) = op + operandToKotlin(expression, commentConverter) override val isNullable: Boolean get() = expression.isNullable } class PostfixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlin() = operandToKotlin(expression) + op + override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + op } class ThisExpression(val identifier: Identifier) : Expression() { - override fun toKotlin() = "this" + identifier.withPrefix("@") + override fun toKotlinImpl(commentConverter: CommentConverter) = "this" + identifier.withPrefix("@", commentConverter) } class SuperExpression(val identifier: Identifier) : Expression() { - override fun toKotlin() = "super" + identifier.withPrefix("@") + override fun toKotlinImpl(commentConverter: CommentConverter) = "super" + identifier.withPrefix("@", commentConverter) } class QualifiedExpression(val qualifier: Expression, val identifier: Expression) : Expression() { override val isNullable: Boolean get() = identifier.isNullable - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { if (!qualifier.isEmpty) { - return operandToKotlin(qualifier) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin() + return operandToKotlin(qualifier, commentConverter) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin(commentConverter) } - return identifier.toKotlin() + return identifier.toKotlin(commentConverter) } } class PolyadicExpression(val expressions: List, val token: String) : Expression() { - override fun toKotlin(): String { - val expressionsWithConversions = expressions.map { it.toKotlin() } + override fun toKotlinImpl(commentConverter: CommentConverter): String { + val expressionsWithConversions = expressions.map { it.toKotlin(commentConverter) } return expressionsWithConversions.makeString(" " + token + " ") } } class LambdaExpression(val arguments: String?, val statementList: StatementList) : Expression() { - override fun toKotlin(): String { - val statementsText = statementList.toKotlin().trim() + override fun toKotlinImpl(commentConverter: CommentConverter): String { + val statementsText = statementList.toKotlin(commentConverter).trim() if (arguments != null) { val br = if (statementsText.indexOf('\n') < 0 && statementsText.indexOf('\r') < 0) " " else "\n" return "{ $arguments ->$br$statementsText }" @@ -105,25 +106,25 @@ class LambdaExpression(val arguments: String?, val statementList: StatementList) } class StarExpression(val methodCall: MethodCallExpression) : Expression() { - override fun toKotlin() = "*" + methodCall.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = "*" + methodCall.toKotlin(commentConverter) } fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List, needExplicitType: Boolean) : MethodCallExpression { val elementType = arrayType.elementType - val createArrayFunction = if (elementType.isPrimitive()) - (elementType.toNotNullType().toKotlin() + "Array").decapitalize() + val createArrayFunction = if (elementType is PrimitiveType) + (elementType.toNotNullType().toKotlin(CommentConverter.Dummy) + "Array").decapitalize() else if (needExplicitType) - arrayType.toNotNullType().toKotlin().decapitalize() + arrayType.toNotNullType().toKotlin(CommentConverter.Dummy).decapitalize() else "array" val doubleOrFloatTypes = setOf("double", "float", "java.lang.double", "java.lang.float") - val afterReplace = arrayType.toNotNullType().toKotlin().replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") + val afterReplace = arrayType.toNotNullType().toKotlin(CommentConverter.Dummy).replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") fun explicitConvertIfNeeded(initializer: Expression): Expression { if (doubleOrFloatTypes.contains(afterReplace)) { if (initializer is LiteralExpression) { - if (!initializer.toKotlin().contains(".")) { + if (!initializer.toKotlin(CommentConverter.Dummy).contains(".")) { return LiteralExpression(initializer.literalText + ".0") } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index ac07c21bd4f..3498fabfd9c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -30,12 +30,18 @@ open class Field( private val hasWriteAccesses: Boolean ) : Member(comments, annotations, modifiers) { - override fun toKotlin(): String { - val declaration = commentsToKotlin() + annotations.toKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter): String { + val declaration = commentsToKotlin(commentConverter) + + annotations.toKotlin(commentConverter) + + modifiersToKotlin() + + (if (isVal) "val " else "var ") + + identifier.toKotlin(commentConverter) + + " : " + + `type`.toKotlin(commentConverter) return if (initializer.isEmpty) - declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin()) + declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin(commentConverter)) else - declaration + " = " + initializer.toKotlin() + declaration + " = " + initializer.toKotlin(commentConverter) } private fun modifiersToKotlin(): String { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt index 2e625434767..d1175ca8806 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt @@ -16,10 +16,12 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class FileMemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine, false) class PackageStatement(val packageName: String) : Element() { - override fun toKotlin(): String = "package " + packageName + override fun toKotlinImpl(commentConverter: CommentConverter): String = "package " + packageName } class File( @@ -27,7 +29,7 @@ class File( val mainFunction: String ) : Element() { - override fun toKotlin(): String { - return body.toKotlin() + mainFunction + override fun toKotlinImpl(commentConverter: CommentConverter): String { + return body.toKotlin(commentConverter) + mainFunction } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt index 0bb87b07cfb..6020b9777a4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt @@ -18,6 +18,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList import org.jetbrains.jet.j2k.Converter +import org.jetbrains.jet.j2k.CommentConverter open class Function( val converter: Converter, @@ -55,16 +56,14 @@ open class Function( return resultingModifiers.toKotlin() } - private fun returnTypeToKotlin() = if (!`type`.isUnit()) " : " + `type`.toKotlin() + " " else " " - - override fun toKotlin(): String { - return commentsToKotlin() + - annotations.toKotlin() + + override fun toKotlinImpl(commentConverter: CommentConverter): String { + return commentsToKotlin(commentConverter) + + annotations.toKotlin(commentConverter) + modifiersToKotlin() + - "fun ${typeParameterList.toKotlin().withSuffix(" ")}${name.toKotlin()}" + - "(${parameterList.toKotlin()})" + - returnTypeToKotlin() + - typeParameterList.whereToKotlin() + - block?.toKotlin() + "fun ${typeParameterList.toKotlin(commentConverter).withSuffix(" ")}${name.toKotlin(commentConverter)}" + + "(${parameterList.toKotlin(commentConverter)})" + + (if (!`type`.isUnit()) " : " + `type`.toKotlin(commentConverter) + " " else " ") + + typeParameterList.whereToKotlin(commentConverter) + + block?.toKotlin(commentConverter) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt index fb417e38a9a..9e229d17ca7 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class Identifier( val name: String, @@ -26,7 +28,7 @@ class Identifier( override val isEmpty: Boolean get() = name.isEmpty() - private fun identifierToKotlin(): String { + private fun toKotlin(): String { if (quotingNeeded && ONLY_KOTLIN_KEYWORDS.contains(name) || name.contains("$")) { return quote(name) } @@ -34,7 +36,7 @@ class Identifier( return name } - override fun toKotlin(): String = identifierToKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter): String = toKotlin() private fun quote(str: String): String = "`" + str + "`" @@ -47,6 +49,6 @@ class Identifier( "package", "as", "type", "val", "var", "fun", "is", "in", "object", "when", "trait", "This" ) - fun toKotlin(name: String): String = Identifier(name).identifierToKotlin() + fun toKotlin(name: String): String = Identifier(name).toKotlin() } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt index ce658abb8a2..82f85682e0e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt @@ -25,14 +25,14 @@ import com.intellij.psi.PsiJavaCodeReferenceElement import org.jetbrains.jet.asJava.KotlinLightClassForPackage class Import(val name: String) : Element() { - override fun toKotlin() = "import " + name + override fun toKotlinImpl(commentConverter: CommentConverter) = "import " + name } class ImportList(public val imports: List) : Element() { override val isEmpty: Boolean get() = imports.isEmpty() - override fun toKotlin() = imports.toKotlin("\n") + override fun toKotlinImpl(commentConverter: CommentConverter) = imports.toKotlin(commentConverter, "\n") } public fun Converter.convertImportList(importList: PsiImportList): ImportList = diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt index 6f2adb2cec6..ca90d460077 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt @@ -16,8 +16,10 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class Initializer(val block: Block, modifiers: Set) : Member(MemberComments.Empty, Annotations.Empty, modifiers) { - override fun toKotlin(): String { - return block.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter): String { + return block.toKotlin(commentConverter) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index c3668b6563d..a98f47ba5b4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -17,6 +17,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.ConverterSettings +import org.jetbrains.jet.j2k.CommentConverter class LocalVariable( private val identifier: Identifier, @@ -28,17 +29,17 @@ class LocalVariable( private val settings: ConverterSettings ) : Element() { - override fun toKotlin(): String { - val start = annotations.toKotlin() + if (isVal) "val" else "var" + override fun toKotlinImpl(commentConverter: CommentConverter): String { + val start = annotations.toKotlin(commentConverter) + if (isVal) "val" else "var" return if (initializer.isEmpty) { - "$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()}" + "$start ${identifier.toKotlin(commentConverter)} : ${typeCalculator().toKotlin(commentConverter)}" } else { val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault if (shouldSpecifyType) - "$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()} = ${initializer.toKotlin()}" + "$start ${identifier.toKotlin(commentConverter)} : ${typeCalculator().toKotlin(commentConverter)} = ${initializer.toKotlin(commentConverter)}" else - "$start ${identifier.toKotlin()} = ${initializer.toKotlin()}" + "$start ${identifier.toKotlin(commentConverter)} = ${initializer.toKotlin(commentConverter)}" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt index abf43f9d002..846a6b39498 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt @@ -17,12 +17,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import com.intellij.psi.PsiClass -import org.jetbrains.jet.j2k.Converter -import java.util.HashSet -import com.intellij.psi.PsiMember -import java.util.LinkedHashMap -import com.intellij.psi.PsiElement +import org.jetbrains.jet.j2k.CommentConverter class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NoSpace) { class object { @@ -31,7 +26,7 @@ class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(e } abstract class Member(val comments: MemberComments, val annotations: Annotations, val modifiers: Set) : Element() { - fun commentsToKotlin(): String = comments.toKotlin() + fun commentsToKotlin(commentConverter: CommentConverter): String = comments.toKotlin(commentConverter) } //member itself and all the elements before it in the code (comments, whitespaces) @@ -48,23 +43,25 @@ class ClassBody ( val normalMembers: MemberList, val classObjectMembers: MemberList) { - fun toKotlin(containingClass: Class?): String { - val innerBody = normalMembers.toKotlin() + primaryConstructorBodyToKotlin() + classObjectToKotlin(containingClass) + fun toKotlin(containingClass: Class?, commentConverter: CommentConverter): String { + val innerBody = normalMembers.toKotlin(commentConverter) + + primaryConstructorBodyToKotlin(commentConverter) + + classObjectToKotlin(containingClass, commentConverter) return if (innerBody.trim().isNotEmpty()) " {" + innerBody + "}" else "" } - private fun primaryConstructorBodyToKotlin(): String { + private fun primaryConstructorBodyToKotlin(commentConverter: CommentConverter): String { val constructor = primaryConstructor if (constructor != null && !(constructor.block?.isEmpty ?: true)) { - return "\n" + constructor.bodyToKotlin() + "\n" + return "\n" + constructor.bodyToKotlin(commentConverter) + "\n" } return "" } - private fun classObjectToKotlin(containingClass: Class?): String { + private fun classObjectToKotlin(containingClass: Class?, commentConverter: CommentConverter): String { val secondaryConstructorsAsStaticInitFunctions = secondaryConstructorsAsStaticInitFunctions(containingClass) if (secondaryConstructorsAsStaticInitFunctions.isEmpty() && classObjectMembers.isEmpty()) return "" - return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin()}${classObjectMembers.toKotlin()}}" + return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin(commentConverter)}${classObjectMembers.toKotlin(commentConverter)}}" } private fun secondaryConstructorsAsStaticInitFunctions(containingClass: Class?): MemberList { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index aefcd1c5cc2..30795dd45a0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class MethodCallExpression( val methodExpression: Expression, val arguments: List, @@ -24,15 +26,15 @@ class MethodCallExpression( val lambdaArgument: LambdaExpression? = null ) : Expression() { - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { val builder = StringBuilder() - builder.append(operandToKotlin(methodExpression)) - builder.append(typeArguments.toKotlin(", ", "<", ">")) + builder.append(operandToKotlin(methodExpression, commentConverter)) + builder.append(typeArguments.toKotlin(commentConverter, ", ", "<", ">")) if (arguments.isNotEmpty() || lambdaArgument == null) { - builder.append("(").append(arguments.map { it.toKotlin() }.makeString(", ")).append(")") + builder.append("(").append(arguments.map { it.toKotlin(commentConverter) }.makeString(", ")).append(")") } if (lambdaArgument != null) { - builder.append(lambdaArgument.toKotlin()) + builder.append(lambdaArgument.toKotlin(commentConverter)) } return builder.toString() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt index b8655b41024..59511daa58c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + enum class Modifier(val name: String) { PUBLIC: Modifier("public") PROTECTED: Modifier("protected") diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt index 77e4427e170..e931089712f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class NewClassExpression( val name: Element, val arguments: List, @@ -23,18 +25,18 @@ class NewClassExpression( val anonymousClass: AnonymousClassBody? = null ) : Expression() { - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { val callOperator = if (qualifier.isNullable) "!!." else "." - val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin() + callOperator - val appliedArguments = arguments.toKotlin(", ") + val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin(commentConverter) + callOperator + val appliedArguments = arguments.toKotlin(commentConverter, ", ") return if (anonymousClass != null) { if (anonymousClass.extendsTrait) - "object : " + qualifier + name.toKotlin() + anonymousClass.toKotlin() + "object : " + qualifier + name.toKotlin(commentConverter) + anonymousClass.toKotlin(commentConverter) else - "object : " + qualifier + name.toKotlin() + "(" + appliedArguments + ")" + anonymousClass.toKotlin() + "object : " + qualifier + name.toKotlin(commentConverter) + "(" + appliedArguments + ")" + anonymousClass.toKotlin(commentConverter) } else{ - qualifier + name.toKotlin() + "(" + appliedArguments + ")" + qualifier + name.toKotlin(commentConverter) + "(" + appliedArguments + ")" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 1e133700619..2c1692907df 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parameter.VarValModifier, @@ -27,10 +29,10 @@ class Parameter(val identifier: Identifier, Var } - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { val builder = StringBuilder() - builder.append(annotations.toKotlin()) + builder.append(annotations.toKotlin(commentConverter)) builder.append(modifiers.toKotlin()) if (`type` is VarArgType) { @@ -43,7 +45,7 @@ class Parameter(val identifier: Identifier, VarValModifier.Val -> builder.append("val ") } - builder.append(identifier.toKotlin()).append(": ").append(`type`.toKotlin()) + builder.append(identifier.toKotlin(commentConverter)).append(": ").append(`type`.toKotlin(commentConverter)) return builder.toString() } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt index f4b35a9cc3f..8a3e770801c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt @@ -16,8 +16,10 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + open class ParameterList(val parameters: List) : Element() { - override fun toKotlin() = parameters.map { it.toKotlin() }.makeString(", ") + override fun toKotlinImpl(commentConverter: CommentConverter) = parameters.map { it.toKotlin(commentConverter) }.makeString(", ") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt index b2045e8dd63..98b7eff616c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt @@ -16,6 +16,8 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class ReferenceElement(val reference: Identifier, val types: List) : Element() { - override fun toKotlin() = reference.toKotlin() + types.toKotlin(", ", "<", ">") + override fun toKotlinImpl(commentConverter: CommentConverter) = reference.toKotlin(commentConverter) + types.toKotlin(commentConverter, ", ", "<", ">") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt index 577e66b663c..a059e1bafea 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt @@ -16,10 +16,12 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + abstract class Statement() : Element() { object Empty : Statement() { - override fun toKotlin() = "" + override fun toKotlinImpl(commentConverter: CommentConverter) = "" override val isEmpty: Boolean get() = true @@ -27,20 +29,20 @@ abstract class Statement() : Element() { } class DeclarationStatement(val elements: List) : Statement() { - override fun toKotlin(): String - = elements.filterIsInstance(javaClass()).map { it.toKotlin() }.makeString("\n") + override fun toKotlinImpl(commentConverter: CommentConverter): String + = elements.filterIsInstance(javaClass()).map { it.toKotlin(commentConverter) }.makeString("\n") } class ExpressionListStatement(val expressions: List) : Expression() { - override fun toKotlin() = expressions.toKotlin("\n") + override fun toKotlinImpl(commentConverter: CommentConverter) = expressions.toKotlin(commentConverter, "\n") } class LabelStatement(val name: Identifier, val statement: Element) : Statement() { - override fun toKotlin(): String = "@" + name.toKotlin() + " " + statement.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter): String = "@" + name.toKotlin(commentConverter) + " " + statement.toKotlin(commentConverter) } class ReturnStatement(val expression: Expression) : Statement() { - override fun toKotlin() = "return " + expression.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = "return " + expression.toKotlin(commentConverter) } class IfStatement( @@ -51,10 +53,10 @@ class IfStatement( ) : Expression() { private val br = if (singleLine) " " else "\n" - override fun toKotlin(): String { - val result = "if (" + condition.toKotlin() + ")$br" + thenStatement.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter): String { + val result = "if (" + condition.toKotlin(commentConverter) + ")$br" + thenStatement.toKotlin(commentConverter) if (!elseStatement.isEmpty) { - return "$result${br}else$br${elseStatement.toKotlin()}" + return "$result${br}else$br${elseStatement.toKotlin(commentConverter)}" } return result } @@ -65,13 +67,13 @@ class IfStatement( class WhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlin() = "while (" + condition.toKotlin() + ")$br" + body.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = "while (" + condition.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) } class DoWhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlin() = "do$br" + body.toKotlin() + "${br}while (" + condition.toKotlin() + ")" + override fun toKotlinImpl(commentConverter: CommentConverter) = "do$br" + body.toKotlin(commentConverter) + "${br}while (" + condition.toKotlin(commentConverter) + ")" } class ForeachStatement( @@ -83,7 +85,7 @@ class ForeachStatement( private val br = if (singleLine) " " else "\n" - override fun toKotlin() = "for (" + variable.identifier.toKotlin() + " in " + expression.toKotlin() + ")$br" + body.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = "for (" + variable.identifier.toKotlin(commentConverter) + " in " + expression.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) } class ForeachWithRangeStatement(val identifier: Identifier, @@ -93,66 +95,66 @@ class ForeachWithRangeStatement(val identifier: Identifier, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlin() = "for (" + identifier.toKotlin() + " in " + start.toKotlin() + ".." + end.toKotlin() + ")$br" + body.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = "for (" + identifier.toKotlin(commentConverter) + " in " + start.toKotlin(commentConverter) + ".." + end.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) } class BreakStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlin() = "break" + label.withPrefix("@") + override fun toKotlinImpl(commentConverter: CommentConverter) = "break" + label.withPrefix("@", commentConverter) } class ContinueStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlin() = "continue" + label.withPrefix("@") + override fun toKotlinImpl(commentConverter: CommentConverter) = "continue" + label.withPrefix("@", commentConverter) } // Exceptions ---------------------------------------------------------------------------------------------- class TryStatement(val block: Block, val catches: List, val finallyBlock: Block) : Statement() { - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { val builder = StringBuilder() .append("try\n") - .append(block.toKotlin()) + .append(block.toKotlin(commentConverter)) .append("\n") - .append(catches.toKotlin("\n")) + .append(catches.toKotlin(commentConverter, "\n")) .append("\n") if (!finallyBlock.isEmpty) { - builder.append("finally\n").append(finallyBlock.toKotlin()) + builder.append("finally\n").append(finallyBlock.toKotlin(commentConverter)) } return builder.toString() } } class ThrowStatement(val expression: Expression) : Expression() { - override fun toKotlin() = "throw " + expression.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = "throw " + expression.toKotlin(commentConverter) } class CatchStatement(val variable: Parameter, val block: Block) : Statement() { - override fun toKotlin(): String = "catch (" + variable.toKotlin() + ") " + block.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter): String = "catch (" + variable.toKotlin(commentConverter) + ") " + block.toKotlin(commentConverter) } // Switch -------------------------------------------------------------------------------------------------- class SwitchContainer(val expression: Expression, val caseContainers: List) : Statement() { - override fun toKotlin() = "when (" + expression.toKotlin() + ") {\n" + caseContainers.toKotlin("\n") + "\n}" + override fun toKotlinImpl(commentConverter: CommentConverter) = "when (" + expression.toKotlin(commentConverter) + ") {\n" + caseContainers.toKotlin(commentConverter, "\n") + "\n}" } class CaseContainer(val caseStatement: List, statements: List) : Statement() { private val block = Block(statements.filterNot { it is BreakStatement || it is ContinueStatement }, true) - override fun toKotlin() = caseStatement.toKotlin(", ") + " -> " + block.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = caseStatement.toKotlin(commentConverter, ", ") + " -> " + block.toKotlin(commentConverter) } class SwitchLabelStatement(val expression: Expression) : Statement() { - override fun toKotlin() = expression.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = expression.toKotlin(commentConverter) } class DefaultSwitchLabelStatement() : Statement() { - override fun toKotlin() = "else" + override fun toKotlinImpl(commentConverter: CommentConverter) = "else" } // Other ------------------------------------------------------------------------------------------------------ class SynchronizedStatement(val expression: Expression, val block: Block) : Statement() { - override fun toKotlin() = "synchronized (" + expression.toKotlin() + ") " + block.toKotlin() + override fun toKotlinImpl(commentConverter: CommentConverter) = "synchronized (" + expression.toKotlin(commentConverter) + ") " + block.toKotlin(commentConverter) } class StatementList(elements: List) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index f5ff5c77fbc..881c04e3e6e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.Converter import java.util.ArrayList +import org.jetbrains.jet.j2k.CommentConverter class Trait(name: Identifier, comments: MemberComments, @@ -33,7 +33,7 @@ class Trait(name: Identifier, override val keyword: String get() = "trait" - override fun primaryConstructorSignatureToKotlin() = "" + override fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter) = "" override fun modifiersToKotlin(): String { val modifierList = ArrayList() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt index 320efd119b8..0a4a7961270 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -class TypeElement(val `type`: Type) : Element() { - override fun toKotlin() = `type`.toKotlin() +import org.jetbrains.jet.j2k.CommentConverter - fun toKotlinNotNull(): String = `type`.toNotNullType().toKotlin() +class TypeElement(val `type`: Type) : Element() { + override fun toKotlinImpl(commentConverter: CommentConverter) = `type`.toKotlin(commentConverter) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt index 87c1a0ef95c..7ecbb5ba7f0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt @@ -20,37 +20,39 @@ import com.intellij.psi.PsiTypeParameter import org.jetbrains.jet.j2k.Converter import com.intellij.psi.PsiTypeParameterList import java.util.ArrayList +import org.jetbrains.jet.j2k.CommentConverter class TypeParameter(val name: Identifier, val extendsTypes: List) : Element() { fun hasWhere(): Boolean = extendsTypes.size() > 1 - fun getWhereToKotlin(): String { + fun whereToKotlin(commentConverter: CommentConverter): String { if (hasWhere()) { - return name.toKotlin() + " : " + extendsTypes[1].toKotlin() + return name.toKotlin(commentConverter) + " : " + extendsTypes[1].toKotlin(commentConverter) } return "" } - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { if (extendsTypes.size() > 0) { - return name.toKotlin() + " : " + extendsTypes[0].toKotlin() + return name.toKotlin(commentConverter) + " : " + extendsTypes[0].toKotlin(commentConverter) } - return name.toKotlin() + return name.toKotlin(commentConverter) } } class TypeParameterList(val parameters: List) : Element() { - override fun toKotlin(): String = if (!parameters.isEmpty()) - parameters.map { - it.toKotlin() - }.makeString(", ", "<", ">") - else "" + override fun toKotlinImpl(commentConverter: CommentConverter): String { + return if (parameters.isNotEmpty()) + parameters.map { it.toKotlin(commentConverter) }.makeString(", ", "<", ">") + else + "" + } - fun whereToKotlin(): String { + fun whereToKotlin(commentConverter: CommentConverter): String { if (hasWhere()) { - val wheres = parameters.map { it.getWhereToKotlin() } + val wheres = parameters.map { it.whereToKotlin(commentConverter) } return "where " + wheres.makeString(", ") } return "" @@ -71,7 +73,9 @@ fun Converter.convertTypeParameter(psiTypeParameter: PsiTypeParameter): TypePara return convertElement(psiTypeParameter) as TypeParameter } -fun Converter.convertTypeParameterList(psiTypeParameterlist: PsiTypeParameterList?): TypeParameterList { - return if (psiTypeParameterlist == null) TypeParameterList.Empty - else TypeParameterList(psiTypeParameterlist.getTypeParameters()!!.toList().map { convertTypeParameter(it) }) +fun Converter.convertTypeParameterList(typeParameterList: PsiTypeParameterList?): TypeParameterList { + return if (typeParameterList != null) + TypeParameterList(typeParameterList.getTypeParameters()!!.toList().map { convertTypeParameter(it) }) + else + TypeParameterList.Empty } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index d9323120e59..2c81c825e2c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -16,10 +16,9 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList import org.jetbrains.jet.j2k.ConverterSettings +import org.jetbrains.jet.j2k.CommentConverter -fun Type.isPrimitive(): Boolean = this is PrimitiveType fun Type.isUnit(): Boolean = this == Type.Unit enum class Nullability { @@ -34,17 +33,20 @@ fun Nullability.isNullable(settings: ConverterSettings) = when(this) { Nullability.Default -> !settings.forceNotNullTypes } -abstract class MayBeNullableType(nullability: Nullability, val settings: ConverterSettings) : Type { +abstract class MayBeNullableType(nullability: Nullability, val settings: ConverterSettings) : Type() { override val isNullable: Boolean = nullability.isNullable(settings) + + protected val isNullableStr: String + get() = if (isNullable) "?" else "" } -trait NotNullType : Type { +abstract class NotNullType() : Type() { override val isNullable: Boolean get() = false } -trait Type : Element { - val isNullable: Boolean +abstract class Type() : Element() { + abstract val isNullable: Boolean open fun toNotNullType(): Type { if (isNullable) throw UnsupportedOperationException("toNotNullType must be defined") @@ -56,31 +58,27 @@ trait Type : Element { return this } - protected fun isNullableStr(): String? { - return if (isNullable) "?" else "" + object Empty : NotNullType() { + override fun toKotlinImpl(commentConverter: CommentConverter): String = "UNRESOLVED_TYPE" } - object Empty : NotNullType { - override fun toKotlin(): String = "UNRESOLVED_TYPE" + object Unit: NotNullType() { + override fun toKotlinImpl(commentConverter: CommentConverter) = "Unit" } - object Unit: NotNullType { - override fun toKotlin() = "Unit" - } + override fun equals(other: Any?): Boolean = other is Type && other.toKotlin(CommentConverter.Dummy) == this.toKotlin(CommentConverter.Dummy) - override fun equals(other: Any?): Boolean = other is Type && other.toKotlin() == this.toKotlin() + override fun hashCode(): Int = toKotlin(CommentConverter.Dummy).hashCode() - override fun hashCode(): Int = toKotlin().hashCode() - - override fun toString(): String = toKotlin() + override fun toString(): String = toKotlin(CommentConverter.Dummy) } class ClassType(val `type`: Identifier, val typeArgs: List, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlin(): String { - var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin() }.makeString(", ", "<", ">") - return `type`.toKotlin() + params + isNullableStr() + override fun toKotlinImpl(commentConverter: CommentConverter): String { + var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin(commentConverter) }.makeString(", ", "<", ">") + return `type`.toKotlin(commentConverter) + params + isNullableStr } @@ -91,34 +89,34 @@ class ClassType(val `type`: Identifier, val typeArgs: List, nullability class ArrayType(val elementType: Type, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlin(): String { + override fun toKotlinImpl(commentConverter: CommentConverter): String { if (elementType is PrimitiveType) { - return elementType.toKotlin() + "Array" + isNullableStr() + return elementType.toKotlin(commentConverter) + "Array" + isNullableStr } - return "Array<" + elementType.toKotlin() + ">" + isNullableStr() + return "Array<" + elementType.toKotlin(commentConverter) + ">" + isNullableStr } override fun toNotNullType(): Type = ArrayType(elementType, Nullability.NotNull, settings) override fun toNullableType(): Type = ArrayType(elementType, Nullability.Nullable, settings) } -class InProjectionType(val bound: Type) : NotNullType { - override fun toKotlin(): String = "in " + bound.toKotlin() +class InProjectionType(val bound: Type) : NotNullType() { + override fun toKotlinImpl(commentConverter: CommentConverter): String = "in " + bound.toKotlin(commentConverter) } -class OutProjectionType(val bound: Type) : NotNullType { - override fun toKotlin(): String = "out " + bound.toKotlin() +class OutProjectionType(val bound: Type) : NotNullType() { + override fun toKotlinImpl(commentConverter: CommentConverter): String = "out " + bound.toKotlin(commentConverter) } -class StarProjectionType() : NotNullType { - override fun toKotlin(): String = "*" +class StarProjectionType() : NotNullType() { + override fun toKotlinImpl(commentConverter: CommentConverter): String = "*" } -class PrimitiveType(val `type`: Identifier) : NotNullType { - override fun toKotlin(): String = `type`.toKotlin() +class PrimitiveType(val `type`: Identifier) : NotNullType() { + override fun toKotlinImpl(commentConverter: CommentConverter): String = `type`.toKotlin(commentConverter) } -class VarArgType(val `type`: Type) : NotNullType { - override fun toKotlin(): String = `type`.toKotlin() +class VarArgType(val `type`: Type) : NotNullType() { + override fun toKotlinImpl(commentConverter: CommentConverter): String = `type`.toKotlin(commentConverter) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt index 1df00b18f67..39282ad01f4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt @@ -17,13 +17,14 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList +import org.jetbrains.jet.j2k.CommentConverter -fun List.toKotlin(separator: String, prefix: String = "", postfix: String = ""): String - = if (isNotEmpty()) map { it.toKotlin() }.makeString(separator, prefix, postfix) else "" +fun List.toKotlin(commentConverter: CommentConverter, separator: String, prefix: String = "", postfix: String = ""): String + = if (isNotEmpty()) map { it.toKotlin(commentConverter) }.makeString(separator, prefix, postfix) else "" fun String.withSuffix(suffix: String): String = if (isEmpty()) "" else this + suffix fun String.withPrefix(prefix: String): String = if (isEmpty()) "" else prefix + this -fun Expression.withPrefix(prefix: String): String = if (isEmpty) "" else prefix + toKotlin() +fun Expression.withPrefix(prefix: String, commentConverter: CommentConverter): String = if (isEmpty) "" else prefix + toKotlin(commentConverter) open class WhiteSpaceSeparatedElementList( val elements: List, @@ -34,9 +35,9 @@ open class WhiteSpaceSeparatedElementList( fun isEmpty() = nonEmptyElements.all { it is WhiteSpace } - fun toKotlin(): String { + fun toKotlin(commentConverter: CommentConverter): String { if (isEmpty()) return "" - return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin() }.makeString("") + return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin(commentConverter) }.makeString("") } private fun List.surroundWithWhiteSpaces(): List @@ -71,9 +72,9 @@ open class WhiteSpaceSeparatedElementList( } } -fun Expression.operandToKotlin(operand: Expression, parenthesisForSamePrecedence: Boolean = false): String { +fun Expression.operandToKotlin(operand: Expression, commentConverter: CommentConverter, parenthesisForSamePrecedence: Boolean = false): String { val parentPrecedence = precedence() ?: throw IllegalArgumentException("Unknown precendence for $this") - val kotlinCode = operand.toKotlin() + val kotlinCode = operand.toKotlin(commentConverter) val operandPrecedence = operand.precedence() ?: return kotlinCode val needParenthesis = parentPrecedence < operandPrecedence || parentPrecedence == operandPrecedence && parenthesisForSamePrecedence return if (needParenthesis) "($kotlinCode)" else kotlinCode diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt b/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt index 3f5c1b8835c..30e53f184fa 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt @@ -16,9 +16,11 @@ package org.jetbrains.jet.j2k.ast +import org.jetbrains.jet.j2k.CommentConverter + class WhiteSpace(val text: String) : Element() { - override fun toKotlin() = text + override fun toKotlinImpl(commentConverter: CommentConverter) = text override val isEmpty: Boolean get() = text.isEmpty() From 8b5f169dd870b753438c5322f9337dd746d0b0b4 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 18 Jun 2014 16:57:15 +0400 Subject: [PATCH 078/143] Java to Kotlin converter: new way of preserving comments and blank lines implemented (not completely though) --- .../org/jetbrains/jet/j2k/CommentConverter.kt | 62 ----- .../jetbrains/jet/j2k/CommentsAndSpaces.kt | 174 +++++++++++++ j2k/src/org/jetbrains/jet/j2k/Converter.kt | 228 ++++++++---------- .../org/jetbrains/jet/j2k/MainMethodUtils.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Annotation.kt | 16 +- .../jet/j2k/ast/AnonymousClassBody.kt | 6 +- .../ArrayWithoutInitializationExpression.kt | 16 +- j2k/src/org/jetbrains/jet/j2k/ast/Block.kt | 40 +-- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 40 ++- .../org/jetbrains/jet/j2k/ast/ClassBody.kt | 64 +++++ .../org/jetbrains/jet/j2k/ast/Constructors.kt | 31 ++- .../jet/j2k/ast/DummyStringExpression.kt | 4 +- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 42 +++- j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 24 +- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 13 +- .../org/jetbrains/jet/j2k/ast/Expression.kt | 4 +- .../jetbrains/jet/j2k/ast/ExpressionList.kt | 6 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 61 ++--- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 16 +- j2k/src/org/jetbrains/jet/j2k/ast/File.kt | 12 +- j2k/src/org/jetbrains/jet/j2k/ast/Function.kt | 20 +- .../org/jetbrains/jet/j2k/ast/Identifier.kt | 9 +- j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt | 32 +-- .../org/jetbrains/jet/j2k/ast/Initializer.kt | 8 +- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 12 +- j2k/src/org/jetbrains/jet/j2k/ast/Members.kt | 70 ------ .../jet/j2k/ast/MethodCallExpression.kt | 12 +- j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt | 2 +- .../jet/j2k/ast/NewClassExpression.kt | 14 +- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 8 +- .../jetbrains/jet/j2k/ast/ParameterList.kt | 7 +- .../jetbrains/jet/j2k/ast/ReferenceElement.kt | 4 +- .../org/jetbrains/jet/j2k/ast/Statements.kt | 62 +++-- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 7 +- .../org/jetbrains/jet/j2k/ast/TypeElement.kt | 4 +- .../jetbrains/jet/j2k/ast/TypeParameters.kt | 20 +- j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 34 +-- j2k/src/org/jetbrains/jet/j2k/ast/Util.kt | 61 +---- .../org/jetbrains/jet/j2k/ast/WhiteSpace.kt | 46 ---- .../jet/j2k/visitors/ElementVisitor.kt | 14 +- .../jet/j2k/visitors/StatementVisitor.kt | 25 +- .../JavaToKotlinConverterTestGenerated.java | 16 +- j2k/tests/testData/ast/comments/Comments.kt | 30 +++ j2k/tests/testData/ast/comments/comments.java | 26 ++ .../testData/ast/comments/comments.kt.todo | 25 ++ .../ast/constructors/withManyDefaultParams.kt | 1 - .../ast/formatting/nonStaticMembers.kt | 1 - .../nonStaticMembersWithComments.kt | 1 - .../staticAndNonStaticMembersWithComments.kt | 7 +- .../formatting/staticMembersWithComments.kt | 5 +- j2k/tests/testData/ast/issues/kt-836.kt | 1 - j2k/tests/testData/ast/issues/kt-837.kt | 1 - 52 files changed, 756 insertions(+), 690 deletions(-) delete mode 100644 j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt create mode 100644 j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt create mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt delete mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/Members.kt delete mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt create mode 100644 j2k/tests/testData/ast/comments/Comments.kt create mode 100644 j2k/tests/testData/ast/comments/comments.java create mode 100644 j2k/tests/testData/ast/comments/comments.kt.todo diff --git a/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt b/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt deleted file mode 100644 index ce9f22c79cf..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2010-2014 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.j2k - -import com.intellij.psi.* -import java.util.ArrayList -import org.jetbrains.jet.j2k.ast.Element - -class CommentConverter(private val topElement: PsiElement?) { - private enum class CommentPlacement { - Before - SameLineBefore - SameLineAfter - After - } - - private class CommentInfo(val comment: PsiComment) { - val startOffset: Int - val endOffset: Int - var isAttached = false - - { - val range = comment.getTextRange()!! - startOffset = range.getStartOffset() - endOffset = range.getEndOffset() - } - } - - private val allComments: List = run { - val list = ArrayList() - topElement?.accept(object : JavaRecursiveElementVisitor(){ - override fun visitComment(comment: PsiComment) { - list.add(CommentInfo(comment)) - } - }) - list - } - - /* - public fun toKotlin(elementToKotlin: () -> String, originalElements: List): String { - - } - */ - - class object { - val Dummy: CommentConverter = CommentConverter(null) - } -} diff --git a/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt b/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt new file mode 100644 index 00000000000..7d306d1d5a3 --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt @@ -0,0 +1,174 @@ +/* + * Copyright 2010-2014 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.j2k + +import com.intellij.psi.* +import java.util.HashSet +import org.jetbrains.jet.lang.psi.psiUtil.isAncestor +import java.util.ArrayList +import org.jetbrains.jet.j2k.ast.PrototypeInfo + +class CommentsAndSpaces(private val topElement: PsiElement?) { + private val commentsAndSpacesUsed = HashSet() + + public fun wrapElement(elementToKotlin: () -> String, prototypes: List): String { + if (prototypes.isEmpty() || topElement == null) return elementToKotlin() + + val prefix = StringBuilder() + val postfix = StringBuilder() + for ((element, inheritBlankLinesBefore) in prototypes) { + assert(element !is PsiComment) + assert(element !is PsiWhiteSpace) + assert(topElement.isAncestor(element)) + prefix.collectPrefix(element, inheritBlankLinesBefore) + postfix.collectPostfix(element) + } + + return prefix.toString() + elementToKotlin() + postfix.toString() + } + + private fun StringBuilder.collectPrefix(element: PsiElement, allowBlankLinesBefore: Boolean) { + val atStart = ArrayList(2).addCommentsAndSpacesAtStart(element) + + val before = ArrayList(2).addCommentsAndSpacesBefore(element) + if (before.isNotEmpty()) { + val last = before.last() + if (last is PsiWhiteSpace) { + if (allowBlankLinesBefore) { + val blankLines = last.newLinesCount() - 1 + if (blankLines > 0) { + append("\n") // insert at maximum one blank line + commentsAndSpacesUsed.add(last) + } + } + before.remove(before.size - 1) + } + } + + if (before.isEmpty() && atStart.isEmpty()) return + + for (e in before.reverse() + atStart) { + append(e.getText()) + commentsAndSpacesUsed.add(e) + } + } + + private fun StringBuilder.collectPostfix(element: PsiElement) { + val atEnd = ArrayList(2).addCommentsAndSpacesAtEnd(element) + + val after = ArrayList(2).addCommentsAndSpacesAfter(element) + if (after.isNotEmpty()) { + val last = after.last() + if (last is PsiWhiteSpace) { + after.remove(after.size - 1) + } + } + + if (after.isEmpty() && atEnd.isEmpty()) return + + for (e in atEnd.reverse() + after) { + append(e.getText()) + commentsAndSpacesUsed.add(e) + } + } + + private fun MutableList.addCommentsAndSpacesBefore(element: PsiElement): MutableList { + if (element == topElement) return this + + val prev = element.getPrevSibling() + if (prev != null) { + if (prev.isCommentOrSpace()) { + if (prev !in commentsAndSpacesUsed) { + add(prev) + addCommentsAndSpacesBefore(prev) + } + } + else if (prev.isEmptyElement()){ + addCommentsAndSpacesBefore(prev) + } + } + else { + addCommentsAndSpacesBefore(element.getParent()!!) + } + return this + } + + private fun MutableList.addCommentsAndSpacesAfter(element: PsiElement): MutableList { + if (element == topElement) return this + + val next = element.getNextSibling() + if (next != null) { + if (next.isCommentOrSpace()) { + if (next is PsiWhiteSpace && next.hasNewLines()) return this // do not attach anything on next line after element + if (next !in commentsAndSpacesUsed) { + add(next) + addCommentsAndSpacesAfter(next) + } + } + else if (next.isEmptyElement()){ + addCommentsAndSpacesAfter(next) + } + } + else { + addCommentsAndSpacesAfter(element.getParent()!!) + } + return this + } + + private fun MutableList.addCommentsAndSpacesAtStart(element: PsiElement): MutableList { + var child = element.getFirstChild() + while(child != null) { + if (child!!.isCommentOrSpace()) { + if (child !in commentsAndSpacesUsed) add(child!!) else break + } + else if (!child!!.isEmptyElement()) { + addCommentsAndSpacesAtStart(child!!) + break + } + child = child!!.getNextSibling() + } + return this + } + + private fun MutableList.addCommentsAndSpacesAtEnd(element: PsiElement): MutableList { + var child = element.getLastChild() + while(child != null) { + if (child!!.isCommentOrSpace()) { + if (child !in commentsAndSpacesUsed) add(child!!) else break + } + else if (!child!!.isEmptyElement()) { + addCommentsAndSpacesAtEnd(child!!) + break + } + child = child!!.getPrevSibling() + } + return this + } + + private fun PsiElement.isCommentOrSpace() = this is PsiComment || this is PsiWhiteSpace + + private fun PsiElement.isEmptyElement() = getFirstChild() == null && getTextLength() == 0 + + private fun PsiWhiteSpace.newLinesCount() = getText()!!.count { it == '\n' } //TODO: this is not correct!! + + private fun PsiWhiteSpace.hasNewLines() = getText()!!.any { it == '\n' || it == '\r' } + + class object { + val None: CommentsAndSpaces = CommentsAndSpaces(null) + } +} + diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 6cbc279c55e..c23b8512880 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -60,7 +60,7 @@ public class Converter private(val project: Project, val settings: ConverterSett = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, state.expressionVisitorFactory, factory)) public fun elementToKotlin(element: PsiElement): String - = convertTopElement(element)?.toKotlin(CommentConverter(element)) ?: "" + = convertTopElement(element)?.toKotlin(CommentsAndSpaces(element)) ?: "" private fun convertTopElement(element: PsiElement?): Element? = when(element) { is PsiJavaFile -> convertFile(element) @@ -69,12 +69,10 @@ public class Converter private(val project: Project, val settings: ConverterSett is PsiField -> convertField(element) is PsiStatement -> convertStatement(element) is PsiExpression -> convertExpression(element) - is PsiComment -> Comment(element.getText()!!/*, listOf(element)*/) is PsiImportList -> convertImportList(element) is PsiImportStatementBase -> convertImport(element, false) is PsiAnnotation -> convertAnnotation(element, false) - is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: "")) - is PsiWhiteSpace -> WhiteSpace(element.getText()!!) + is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: "")).assignPrototype(element) else -> null } @@ -93,45 +91,42 @@ public class Converter private(val project: Project, val settings: ConverterSett typeConverter.importList = null if (typeConverter.importsToAdd.isNotEmpty()) { val importList = convertedChildren.filterIsInstance(javaClass()).first() - val newImportList = ImportList(importList.imports + typeConverter.importsToAdd) + val newImportList = ImportList(importList.imports + typeConverter.importsToAdd).assignPrototypesFrom(importList) convertedChildren = convertedChildren.map { if (it == importList) newImportList else it } } - return File(FileMemberList(convertedChildren), createMainFunction(javaFile)) + return File(convertedChildren, createMainFunction(javaFile)).assignPrototype(javaFile) } fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { - return AnonymousClassBody(convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) + return AnonymousClassBody(convertBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false).assignPrototype(anonymousClass) } - private fun convertClassBody(psiClass: PsiClass): ClassBody { + private fun convertBody(psiClass: PsiClass): ClassBody { val membersToRemove = HashSet() - val convertedElements = LinkedHashMap() - var inBody = false - val lBrace = psiClass.getLBrace() + val convertedMembers = LinkedHashMap() for (element in psiClass.getChildren()) { - if (element == lBrace) inBody = true - if (inBody) { - convertedElements.put(element, convertMember(element, membersToRemove)) + if (element is PsiMember) { + val converted = convertMember(element, membersToRemove) + if (!converted.isEmpty) { + convertedMembers.put(element, converted) + } } } for (member in membersToRemove) { - convertedElements.remove(member) + convertedMembers.remove(member) } - val membersMap = splitIntoMembers(convertedElements) - - val constructors = membersMap.values().filter { it.member is Constructor } - val primaryConstructor = constructors.map { it.member }.filterIsInstance(javaClass()).firstOrNull() - val secondaryConstructors = constructors.filter { it.member is SecondaryConstructor } + val primaryConstructor = convertedMembers.values().filterIsInstance(javaClass()).firstOrNull() + val secondaryConstructors = convertedMembers.values().filterIsInstance(javaClass()) // do not convert private static methods into class object if possible val useClassObject = if (psiClass.isEnum()) { false } else { - val members = membersMap.keySet().filter { it !is PsiMethod || !it.isConstructor() } + val members = convertedMembers.keySet().filter { it !is PsiMethod || !it.isConstructor() } val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) } val nestedClasses = members.filterIsInstance(javaClass()).filter { it.hasModifierProperty(PsiModifier.STATIC) } if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) { @@ -142,10 +137,10 @@ public class Converter private(val project: Project, val settings: ConverterSett } } - val normalMembers = ArrayList() - val classObjectMembers = ArrayList() - for ((psiMember, member) in membersMap) { - if (member.member is Constructor) continue + val normalMembers = ArrayList() + val classObjectMembers = ArrayList() + for ((psiMember, member) in convertedMembers) { + if (member is Constructor) continue if (useClassObject && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) { classObjectMembers.add(member) } @@ -154,51 +149,17 @@ public class Converter private(val project: Project, val settings: ConverterSett } } - return ClassBody(primaryConstructor, - secondaryConstructors.toMemberList(), - normalMembers.toMemberList(), - classObjectMembers.toMemberList()) - + val lBrace = LBrace().assignPrototype(psiClass.getLBrace()) + val rBrace = RBrace().assignPrototype(psiClass.getRBrace()) + return ClassBody(primaryConstructor, secondaryConstructors, normalMembers, classObjectMembers, lBrace, rBrace) } - private fun List.toMemberList() = MemberList(flatMap { it.elements }) - - private fun splitIntoMembers(elements: Map): Map { - val result = LinkedHashMap() - var currentGroup = ArrayList() - var lastMember: PsiMember? = null - for ((psiElement, element) in elements) { - currentGroup.add(element) - if (element is Member) { - result.put(psiElement as PsiMember, MemberWithComments(element, currentGroup)) - currentGroup = ArrayList() - lastMember = psiElement - } - } - if (lastMember != null) { - (result[lastMember]!!.elements as MutableList).addAll(currentGroup) - } - return result - } - - private fun convertMember(element: PsiElement, membersToRemove: MutableSet): Element = when(element) { - is PsiMethod -> convertMethod(element, membersToRemove) - is PsiField -> convertField(element) - is PsiClass -> convertClass(element) - is PsiClassInitializer -> convertInitializer(element) - else -> convertElement(element) - } - - private fun getComments(member: PsiMember): MemberComments { - var relevantChildren = member.getChildren().toList() - if (member is PsiClass) { - val leftBraceIndex = relevantChildren.indexOf(member.getLBrace()) - relevantChildren = relevantChildren.subList(0, leftBraceIndex) - } - val whiteSpacesAndComments = relevantChildren - .filter { it is PsiWhiteSpace || it is PsiComment } - .map { convertElement(it) } - return MemberComments(whiteSpacesAndComments) + private fun convertMember(member: PsiMember, membersToRemove: MutableSet): Member = when(member) { + is PsiMethod -> convertMethod(member, membersToRemove) + is PsiField -> convertField(member) + is PsiClass -> convertClass(member) + is PsiClassInitializer -> convertInitializer(member) + else -> throw IllegalArgumentException("Unknown member: $member") } private fun convertClass(psiClass: PsiClass): Class { @@ -207,13 +168,13 @@ public class Converter private(val project: Project, val settings: ConverterSett val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList()) val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes()) val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes()) - val name = Identifier(psiClass.getName()!!) - var classBody = convertClassBody(psiClass) + val name = psiClass.declarationIdentifier() + var classBody = convertBody(psiClass) - when { - psiClass.isInterface() -> return Trait(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) + return when { + psiClass.isInterface() -> Trait(name, annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) - psiClass.isEnum() -> return Enum(name, getComments(psiClass), annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) + psiClass.isEnum() -> Enum(name, annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) else -> { if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) { @@ -240,19 +201,17 @@ public class Converter private(val project: Project, val settings: ConverterSett modifiers.add(Modifier.INNER) } - return Class(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) + Class(name, annotations, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) } - } + }.assignPrototype(psiClass) } private fun generateArtificialPrimaryConstructor(className: Identifier, classBody: ClassBody): ClassBody { assert(classBody.primaryConstructor == null) - val finalOrWithEmptyInitializerFields = classBody.normalMembers.members.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.isEmpty } + val finalOrWithEmptyInitializerFields = classBody.normalMembers.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.isEmpty } val initializers = HashMap() - for (constructor in classBody.secondaryConstructors.members) { - constructor as SecondaryConstructor - + for (constructor in classBody.secondaryConstructors) { for (field in finalOrWithEmptyInitializerFields) { initializers.put(field, getDefaultInitializer(field)) } @@ -290,7 +249,7 @@ public class Converter private(val project: Project, val settings: ConverterSett true, settings) newStatements.add(0, DeclarationStatement(listOf(localVar))) - constructor.block = Block(newStatements) + constructor.block = Block(newStatements, LBrace(), RBrace()) } //TODO: comments? @@ -299,39 +258,40 @@ public class Converter private(val project: Project, val settings: ConverterSett Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) } - val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, Annotations.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) - val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) }) - return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers) + val primaryConstructor = PrimaryConstructor(this, Annotations.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) + val updatedMembers = classBody.normalMembers.filter { !finalOrWithEmptyInitializerFields.contains(it) } + return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers, classBody.lBrace, classBody.rBrace) } private fun convertInitializer(initializer: PsiClassInitializer): Initializer { - return Initializer(convertBlock(initializer.getBody()), convertModifiers(initializer)) + return Initializer(convertBlock(initializer.getBody()), convertModifiers(initializer)).assignPrototype(initializer) } private fun convertField(field: PsiField): Field { val annotations = convertAnnotations(field) val modifiers = convertModifiers(field) - if (field is PsiEnumConstant) { - return EnumConstant(Identifier(field.getName()!!), - getComments(field), - annotations, - modifiers, - typeConverter.convertType(field.getType(), Nullability.NotNull), - convertElement(field.getArgumentList())) + val name = field.declarationIdentifier() + val converted = if (field is PsiEnumConstant) { + EnumConstant(name, + annotations, + modifiers, + typeConverter.convertType(field.getType(), Nullability.NotNull), + convertElement(field.getArgumentList())) } - - return Field(Identifier(field.getName()!!), - getComments(field), - annotations, - modifiers, - typeConverter.convertVariableType(field), - convertExpression(field.getInitializer(), field.getType()), - field.hasModifierProperty(PsiModifier.FINAL), - field.hasWriteAccesses(field.getContainingClass())) + else { + Field(name, + annotations, + modifiers, + typeConverter.convertVariableType(field), + convertExpression(field.getInitializer(), field.getType()), + field.hasModifierProperty(PsiModifier.FINAL), + field.hasWriteAccesses(field.getContainingClass())) + } + return converted.assignPrototype(field) } private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { - return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove) + return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove).assignPrototype(method) } private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { @@ -340,15 +300,13 @@ public class Converter private(val project: Project, val settings: ConverterSett val annotations = convertAnnotations(method) + convertThrows(method) val modifiers = convertModifiers(method) - val comments = getComments(method) - if (method.isConstructor()) { if (method.isPrimaryConstructor()) { - return convertPrimaryConstructor(method, annotations, modifiers, comments, membersToRemove) + return convertPrimaryConstructor(method, annotations, modifiers, membersToRemove) } else { val params = convertParameterList(method.getParameterList()) - return SecondaryConstructor(this, comments, annotations, modifiers, params, convertBlock(method.getBody())) + return SecondaryConstructor(this, annotations, modifiers, params, convertBlock(method.getBody())) } } else { @@ -387,7 +345,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val typeParameterList = convertTypeParameterList(method.getTypeParameterList()) val block = convertBlock(method.getBody()) - return Function(this, Identifier(method.getName()), comments, annotations, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) + return Function(this, method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) } } @@ -429,7 +387,6 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun convertPrimaryConstructor(constructor: PsiMethod, annotations: Annotations, modifiers: Set, - comments: MemberComments, membersToRemove: MutableSet): PrimaryConstructor { val params = constructor.getParameterList().getParameters() val parameterToField = HashMap>() @@ -468,20 +425,20 @@ public class Converter private(val project: Project, val settings: ConverterSett Block.Empty } - val parameterList = ParameterList(params.map { - if (!parameterToField.containsKey(it)) { - convertParameter(it) + val parameterList = ParameterList(params.map { parameter -> + if (!parameterToField.containsKey(parameter)) { + convertParameter(parameter) } else { - val (field, `type`) = parameterToField[it]!! - Parameter(Identifier(field.getName()!!), + val (field, `type`) = parameterToField[parameter]!! + Parameter(field.declarationIdentifier(), `type`, if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var, - convertAnnotations(it) + convertAnnotations(field), - convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) }) + convertAnnotations(parameter) + convertAnnotations(field), + convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) }).assignPrototypes(listOf(parameter, field), inheritBlankLinesBefore = false) } }) - return PrimaryConstructor(this, comments, annotations, modifiers, parameterList, block) + return PrimaryConstructor(this, annotations, modifiers, parameterList, block).assignPrototype(constructor) } private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair? { @@ -518,9 +475,9 @@ public class Converter private(val project: Project, val settings: ConverterSett fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = {true}): Block { if (block == null) return Block.Empty - val filteredChildren = block.getChildren().filter { it !is PsiStatement || statementFilter(it) } - val statementList = StatementList(filteredChildren.map { if (it is PsiStatement) convertStatement(it) else convertElement(it) }) - return Block(statementList, notEmpty) + val lBrace = LBrace().assignPrototype(block.getLBrace()) + val rBrace = RBrace().assignPrototype(block.getRBrace()) + return Block(block.getStatements().filter(statementFilter).map { convertStatement(it) }, lBrace, rBrace, notEmpty).assignPrototype(block) } fun convertStatement(statement: PsiStatement?): Statement { @@ -528,7 +485,7 @@ public class Converter private(val project: Project, val settings: ConverterSett statementVisitor.reset() statement.accept(statementVisitor) - return statementVisitor.result + return statementVisitor.result.assignPrototype(statement) } fun convertExpressions(expressions: Array): List @@ -539,7 +496,7 @@ public class Converter private(val project: Project, val settings: ConverterSett expressionVisitor.reset() expression.accept(expressionVisitor) - return expressionVisitor.result + return expressionVisitor.result.assignPrototype(expression) } fun convertElement(element: PsiElement?): Element { @@ -547,17 +504,17 @@ public class Converter private(val project: Project, val settings: ConverterSett val elementVisitor = ElementVisitor(this) element.accept(elementVisitor) - return elementVisitor.result + return elementVisitor.result.assignPrototype(element) } fun convertTypeElement(element: PsiTypeElement?): TypeElement - = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())) + = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())).assignPrototype(element) private fun convertToNotNullableTypes(types: Array): List = types.map { typeConverter.convertType(it, Nullability.NotNull) } fun convertParameterList(parameterList: PsiParameterList): ParameterList - = ParameterList(parameterList.getParameters().map { convertParameter(it) }) + = ParameterList(parameterList.getParameters().map { convertParameter(it) }).assignPrototype(parameterList) fun convertParameter(parameter: PsiParameter, nullability: Nullability = Nullability.Default, @@ -568,7 +525,7 @@ public class Converter private(val project: Project, val settings: ConverterSett Nullability.NotNull -> `type` = `type`.toNotNullType() Nullability.Nullable -> `type` = `type`.toNullableType() } - return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, convertAnnotations(parameter), modifiers) + return Parameter(parameter.declarationIdentifier(), `type`, varValModifier, convertAnnotations(parameter), modifiers).assignPrototype(parameter) } fun convertExpression(argument: PsiExpression?, expectedType: PsiType?): Expression { @@ -596,13 +553,13 @@ public class Converter private(val project: Project, val settings: ConverterSett } - return expression + return expression.assignPrototype(argument) } fun convertIdentifier(identifier: PsiIdentifier?): Identifier { if (identifier == null) return Identifier.Empty - return Identifier(identifier.getText()!!) + return Identifier(identifier.getText()!!).assignPrototype(identifier) } fun convertModifiers(owner: PsiModifierListOwner): MutableSet @@ -641,11 +598,12 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean): Annotation? { val qualifiedName = annotation.getQualifiedName() if (qualifiedName == CommonClassNames.JAVA_LANG_DEPRECATED && annotation.getParameterList().getAttributes().isEmpty()) { - return Annotation(Identifier("deprecated"), listOf(null to LiteralExpression("\"\"")), brackets) //TODO: insert comment + return Annotation(Identifier("deprecated"), listOf(null to LiteralExpression("\"\"")), brackets).assignPrototype(annotation) //TODO: insert comment } - val name = Identifier((annotation.getNameReferenceElement() ?: return null).getText()!!) - val annotationClass = annotation.getNameReferenceElement()?.resolve() as? PsiClass + val nameRef = annotation.getNameReferenceElement() + val name = Identifier((nameRef ?: return null).getText()!!).assignPrototype(nameRef) + val annotationClass = nameRef!!.resolve() as? PsiClass val lastMethod = annotationClass?.getMethods()?.lastOrNull() val arguments = annotation.getParameterList().getAttributes().flatMap { val method = annotationClass?.findMethodsByName(it.getName() ?: "value", false)?.firstOrNull() @@ -659,7 +617,7 @@ public class Converter private(val project: Project, val settings: ConverterSett attrValues.map { attrName to it } } - return Annotation(name, arguments, brackets) + return Annotation(name, arguments, brackets).assignPrototype(annotation) } private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List { @@ -689,11 +647,13 @@ public class Converter private(val project: Project, val settings: ConverterSett } private fun convertThrows(method: PsiMethod): Annotations { - val types = method.getThrowsList().getReferencedTypes() + val throwsList = method.getThrowsList() + val types = throwsList.getReferencedTypes() if (types.isEmpty()) return Annotations.Empty - return Annotations(listOf(Annotation(Identifier("throws"), - types.map { null to MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(typeConverter.convertType(it, Nullability.NotNull))) }, - false)), + val annotation = Annotation(Identifier("throws"), + types.map { null to MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(typeConverter.convertType(it, Nullability.NotNull))) }, + false) + return Annotations(listOf(annotation.assignPrototype(throwsList)), true) } diff --git a/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt b/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt index efbb1142f45..c508d8dd507 100644 --- a/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt @@ -38,7 +38,7 @@ fun createMainFunction(file: PsiFile): String { } if (classNamesWithMains.size() > 0) { - var className = classNamesWithMains.get(0).first + var className = classNamesWithMains[0].first return MessageFormat.format("fun main(args : Array) = {0}.main(args as Array?)", className) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index 5345c90d6ff..a96ed874910 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -16,31 +16,31 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean) : Element() { private fun surroundWithBrackets(text: String) = if (brackets) "[$text]" else text - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (arguments.isEmpty()) { - return surroundWithBrackets(name.toKotlin(commentConverter)) + return surroundWithBrackets(name.toKotlin(commentsAndSpaces)) } val argsText = arguments.map { if (it.first != null) - it.first!!.toKotlin(commentConverter) + " = " + it.second.toKotlin(commentConverter) + it.first!!.toKotlin(commentsAndSpaces) + " = " + it.second.toKotlin(commentsAndSpaces) else - it.second.toKotlin(commentConverter) + it.second.toKotlin(commentsAndSpaces) }.makeString(", ") - return surroundWithBrackets(name.toKotlin(commentConverter) + "(" + argsText + ")") + return surroundWithBrackets(name.toKotlin(commentsAndSpaces) + "(" + argsText + ")") } } class Annotations(val annotations: List, val newLines: Boolean) : Element() { private val br = if (newLines) "\n" else " " - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return if (annotations.isNotEmpty()) annotations.map { it.toKotlin(commentConverter) }.makeString(br) + br else "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return if (annotations.isNotEmpty()) annotations.map { it.toKotlin(commentsAndSpaces) }.makeString(br) + br else "" } fun plus(other: Annotations) = Annotations(annotations + other.annotations, newLines || other.newLines) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index d2606aaba63..8ea24070061 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -16,9 +16,9 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) -: Class(Identifier(""), MemberComments.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { - override fun toKotlinImpl(commentConverter: CommentConverter) = body.toKotlin(null, commentConverter) +: Class(Identifier.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = body.toKotlin(null, commentsAndSpaces) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt index 96eb2a3c8ee..30519ce89bc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt @@ -16,26 +16,26 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -open class ArrayWithoutInitializationExpression(val `type`: ArrayType, val expressions: List) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { +class ArrayWithoutInitializationExpression(val `type`: ArrayType, val expressions: List) : Expression() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { fun getConstructorName(`type`: ArrayType, hasInit: Boolean): String { return when (`type`.elementType) { is PrimitiveType -> - `type`.toNotNullType().toKotlin(commentConverter) + `type`.toNotNullType().toKotlin(commentsAndSpaces) is ArrayType -> if (hasInit) - `type`.toNotNullType().toKotlin(commentConverter) + `type`.toNotNullType().toKotlin(commentsAndSpaces) else - "arrayOfNulls<" + `type`.elementType.toKotlin(commentConverter) + ">" + "arrayOfNulls<" + `type`.elementType.toKotlin(commentsAndSpaces) + ">" else -> - "arrayOfNulls<" + `type`.elementType.toKotlin(commentConverter) + ">" + "arrayOfNulls<" + `type`.elementType.toKotlin(commentsAndSpaces) + ">" } } fun oneDim(`type`: ArrayType, size: Expression, init: String = ""): String { - return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin(commentConverter) + init.withPrefix(", ") + ")" + return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin(commentsAndSpaces) + init.withPrefix(", ") + ")" } fun constructInnerType(hostType: ArrayType, expressions: List): String { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt index ebccce581b1..1a85bf35949 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt @@ -16,33 +16,33 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter - -fun Block(statements: List, notEmpty: Boolean = false): Block { - val elements = ArrayList() - elements.add(WhiteSpace.NewLine) - elements.addAll(statements) - elements.add(WhiteSpace.NewLine) - return Block(StatementList(elements), notEmpty) -} - -class Block(val statementList: StatementList, val notEmpty: Boolean = false) : Statement() { - val statements: List = statementList.statements - +import org.jetbrains.jet.j2k.CommentsAndSpaces +class Block(val statements: List, val lBrace: LBrace, val rBrace: RBrace, val notEmpty: Boolean = false) : Statement() { override val isEmpty: Boolean get() = !notEmpty && statements.all { it.isEmpty } - override fun toKotlinImpl(commentConverter: CommentConverter): String { - if (!isEmpty) { - return "{${statementList.toKotlin(commentConverter)}}" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + if (statements.all { it.isEmpty }) { + return if (isEmpty) "" else lBrace.toKotlin(commentsAndSpaces) + rBrace.toKotlin(commentsAndSpaces) } - - return "" + return lBrace.toKotlin(commentsAndSpaces) + + "\n" + + statements.toKotlin(commentsAndSpaces, "\n") + + "\n" + + rBrace.toKotlin(commentsAndSpaces) } class object { - val Empty = Block(StatementList(listOf())) + val Empty = Block(listOf(), LBrace(), RBrace()) } } + +// we use LBrace and RBrace elements to better handle comments around them +class LBrace() : Element() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "{" +} + +class RBrace() : Element() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "}" +} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index c9b80664aca..7ca280e905a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -17,11 +17,10 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces open class Class( val name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, val typeParameterList: TypeParameterList, @@ -29,37 +28,36 @@ open class Class( val baseClassParams: List, val implementsTypes: List, val body: ClassBody -) : Member(comments, annotations, modifiers) { +) : Member(annotations, modifiers) { - override fun toKotlinImpl(commentConverter: CommentConverter): String = - commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = + annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + - keyword + " " + name.toKotlin(commentConverter) + - typeParameterList.toKotlin(commentConverter) + - primaryConstructorSignatureToKotlin(commentConverter) + - implementTypesToKotlin(commentConverter) + - typeParameterList.whereToKotlin(commentConverter).withPrefix(" ") + - body.toKotlin(this, commentConverter) + keyword + " " + name.toKotlin(commentsAndSpaces) + + typeParameterList.toKotlin(commentsAndSpaces) + + primaryConstructorSignatureToKotlin(commentsAndSpaces) + + implementTypesToKotlin(commentsAndSpaces) + + typeParameterList.whereToKotlin(commentsAndSpaces).withPrefix(" ") + + body.toKotlin(this, commentsAndSpaces) protected open val keyword: String get() = "class" - protected open fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter): String - = body.primaryConstructor?.signatureToKotlin(commentConverter) ?: "()" + protected open fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String + = body.primaryConstructor?.signatureToKotlin(commentsAndSpaces) ?: "()" - private fun baseClassSignatureWithParams(commentConverter: CommentConverter): List { + private fun baseClassSignatureWithParams(commentsAndSpaces: CommentsAndSpaces): List { if (keyword.equals("class") && extendsTypes.size() == 1) { - val baseParams = baseClassParams.toKotlin(commentConverter, ", ") - return arrayListOf(extendsTypes[0].toKotlin(commentConverter) + "(" + baseParams + ")") + val baseParams = baseClassParams.toKotlin(commentsAndSpaces, ", ") + return arrayListOf(extendsTypes[0].toKotlin(commentsAndSpaces) + "(" + baseParams + ")") } - return extendsTypes.map { it.toKotlin(commentConverter) } + return extendsTypes.map { it.toKotlin(commentsAndSpaces) } } - protected fun implementTypesToKotlin(commentConverter: CommentConverter): String { + protected fun implementTypesToKotlin(commentsAndSpaces: CommentsAndSpaces): String { val allTypes = ArrayList() - allTypes.addAll(baseClassSignatureWithParams(commentConverter)) - allTypes.addAll(implementsTypes.map { it.toKotlin(commentConverter) }) + allTypes.addAll(baseClassSignatureWithParams(commentsAndSpaces)) + allTypes.addAll(implementsTypes.map { it.toKotlin(commentsAndSpaces) }) return if (allTypes.size() == 0) "" else diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt new file mode 100644 index 00000000000..05b5bdfe2db --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2013 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.j2k.ast + +import org.jetbrains.jet.j2k.CommentsAndSpaces + +abstract class Member(val annotations: Annotations, val modifiers: Set) : Element() + +class ClassBody ( + val primaryConstructor: PrimaryConstructor?, + val secondaryConstructors: List, + val normalMembers: List, + val classObjectMembers: List, + val lBrace: LBrace, + val rBrace: RBrace) { + + fun toKotlin(containingClass: Class?, commentsAndSpaces: CommentsAndSpaces): String { + val builder = StringBuilder() + builder.append(normalMembers.toKotlin(commentsAndSpaces, "\n")) + + val primaryConstructor = primaryConstructorBodyToKotlin(commentsAndSpaces) + if (primaryConstructor.isNotEmpty() && builder.length() > 0) { + builder.append("\n\n") // blank line before constructor body + } + builder.append(primaryConstructor) + + val classObject = classObjectToKotlin(containingClass, commentsAndSpaces) + if (classObject.isNotEmpty() && builder.length() > 0) { + builder.append("\n\n") // blank line before class object + } + builder.append(classObject) + + return if (builder.length() > 0) + " " + lBrace.toKotlin(commentsAndSpaces) + "\n" + builder + "\n" + rBrace.toKotlin(commentsAndSpaces) + else + "" + } + + private fun primaryConstructorBodyToKotlin(commentsAndSpaces: CommentsAndSpaces): String { + val constructor = primaryConstructor + if (constructor == null || constructor.block?.isEmpty ?: true) return "" + return constructor.bodyToKotlin(commentsAndSpaces) + } + + private fun classObjectToKotlin(containingClass: Class?, commentsAndSpaces: CommentsAndSpaces): String { + if (secondaryConstructors.isEmpty() && classObjectMembers.isEmpty()) return "" + val factoryFunctions = secondaryConstructors.map { it.toFactoryFunction(containingClass) } + return "class object {\n" + (factoryFunctions + classObjectMembers).toKotlin(commentsAndSpaces, "\n") + "\n}" + } +} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 2f6c3287922..2a0964dd8ca 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -19,52 +19,51 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.HashSet import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces abstract class Constructor( converter: Converter, - comments: MemberComments, annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block -) : Function(converter, Identifier.Empty, comments, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) +) : Function(converter, Identifier.Empty, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) class PrimaryConstructor(converter: Converter, - comments: MemberComments, annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block) - : Constructor(converter, comments, annotations, modifiers, parameterList, block) { + : Constructor(converter, annotations, modifiers, parameterList, block) { - public fun signatureToKotlin(commentConverter: CommentConverter): String { + public fun signatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String { val accessModifier = modifiers.accessModifier() val modifiersString = if (accessModifier != null && accessModifier != Modifier.PUBLIC) " " + accessModifier.toKotlin() else "" - return modifiersString + "(" + parameterList.toKotlin(commentConverter) + ")" + return modifiersString + "(" + parameterList.toKotlin(commentsAndSpaces) + ")" } - public fun bodyToKotlin(commentConverter: CommentConverter): String = block!!.toKotlin(commentConverter) + public fun bodyToKotlin(commentsAndSpaces: CommentsAndSpaces): String = block!!.toKotlin(commentsAndSpaces) } class SecondaryConstructor(converter: Converter, - comments: MemberComments, annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block) - : Constructor(converter, comments, annotations, modifiers, parameterList, block) { + : Constructor(converter, annotations, modifiers, parameterList, block) { - public fun toInitFunction(containingClass: Class): Function { + public fun toFactoryFunction(containingClass: Class?): Function { val modifiers = HashSet(modifiers) val statements = ArrayList(block?.statements ?: listOf()) statements.add(ReturnStatement(tempValIdentifier)) - val block = Block(statements) + val block = Block(statements, block?.lBrace ?: LBrace(), block?.rBrace ?: RBrace()) val typeParameters = ArrayList() - typeParameters.addAll(containingClass.typeParameterList.parameters) - return Function(converter, Identifier("create"), comments, annotations, modifiers, - ClassType(containingClass.name, typeParameters, Nullability.NotNull, converter.settings), - TypeParameterList(typeParameters), parameterList, block, false) + if (containingClass != null) { + typeParameters.addAll(containingClass.typeParameterList.parameters) + } + return Function(converter, Identifier("create"), annotations, modifiers, + ClassType(containingClass?.name ?: Identifier.Empty, typeParameters, Nullability.NotNull, converter.settings), + TypeParameterList(typeParameters), parameterList, block, false).assignPrototypesFrom(this) } class object { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt index 248b9bbf902..dbd7c03f1fe 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class DummyStringExpression(val string: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = string + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = string } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 83cee59e7de..2a61fc6a7e6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -16,21 +16,47 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces +import com.intellij.psi.PsiElement + +fun TElement.assignPrototype(prototype: PsiElement?): TElement { + assignPrototypeInfos(if (prototype != null) listOf(PrototypeInfo(prototype, true)) else listOf()) + return this +} + +fun TElement.assignPrototypes(prototypes: List, inheritBlankLinesBefore: Boolean): TElement { + assignPrototypeInfos(prototypes.map { PrototypeInfo(it, inheritBlankLinesBefore) }) + return this +} + +fun TElement.assignPrototypesFrom(element: Element): TElement { + assignPrototypeInfos(element.prototypes) + return this +} + +data class PrototypeInfo(val element: PsiElement, val inheritBlankLinesBefore: Boolean) abstract class Element { - public fun toKotlin(commentConverter: CommentConverter): String = toKotlinImpl(commentConverter) + public var prototypes: List = listOf() + private set - protected abstract fun toKotlinImpl(commentConverter: CommentConverter): String + public fun assignPrototypeInfos(prototypes: List) { + this.prototypes = prototypes + } + + public fun toKotlin(commentsAndSpaces: CommentsAndSpaces): String { + return if (isEmpty) // do not insert comment and spaces for empty elements to avoid multiple blank lines + "" + else + commentsAndSpaces.wrapElement({ toKotlinImpl(commentsAndSpaces) }, prototypes) + } + + protected abstract fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String public open val isEmpty: Boolean get() = false object Empty : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" override val isEmpty: Boolean get() = true } } - -class Comment(val text: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = text -} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index 1bf0f80eb70..baa37ee79a7 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -16,11 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Enum( name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, typeParameterList: TypeParameterList, @@ -28,20 +27,19 @@ class Enum( baseClassParams: List, implementsTypes: List, body: ClassBody -) : Class(name, comments, annotations, modifiers, typeParameterList, +) : Class(name, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { - override fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter): String - = body.primaryConstructor?.signatureToKotlin(commentConverter) ?: "" + override fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String + = body.primaryConstructor?.signatureToKotlin(commentsAndSpaces) ?: "" - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + - "enum class " + name.toKotlin(commentConverter) + - primaryConstructorSignatureToKotlin(commentConverter) + - typeParameterList.toKotlin(commentConverter) + - implementTypesToKotlin(commentConverter) + - body.toKotlin(this, commentConverter) + "enum class " + name.toKotlin(commentsAndSpaces) + + primaryConstructorSignatureToKotlin(commentsAndSpaces) + + typeParameterList.toKotlin(commentsAndSpaces) + + implementTypesToKotlin(commentsAndSpaces) + + body.toKotlin(this, commentsAndSpaces) } } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index d38ac5675f3..0c70faebecf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -16,23 +16,22 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class EnumConstant( identifier: Identifier, - members: MemberComments, annotations: Annotations, modifiers: Set, `type`: Type, params: Element -) : Field(identifier, members, annotations, modifiers, `type`.toNotNullType(), params, true, false) { +) : Field(identifier, annotations, modifiers, `type`.toNotNullType(), params, true, false) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - if (initializer.toKotlin(commentConverter).isEmpty()) { - return annotations.toKotlin(commentConverter) + identifier.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + if (initializer.toKotlin(commentsAndSpaces).isEmpty()) { + return annotations.toKotlin(commentsAndSpaces) + identifier.toKotlin(commentsAndSpaces) } - return annotations.toKotlin(commentConverter) + identifier.toKotlin(commentConverter) + " : " + `type`.toKotlin(commentConverter) + "(" + initializer.toKotlin(commentConverter) + ")" + return annotations.toKotlin(commentsAndSpaces) + identifier.toKotlin(commentsAndSpaces) + " : " + `type`.toKotlin(commentsAndSpaces) + "(" + initializer.toKotlin(commentsAndSpaces) + ")" } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt index 2aeba61b327..b8f65aa4fee 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt @@ -16,14 +16,14 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces abstract class Expression() : Statement() { open val isNullable: Boolean get() = false object Empty : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" override val isEmpty: Boolean get() = true } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt index 082acb95d3b..6c1a9ba657a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt @@ -16,10 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -open class ExpressionList(val expressions: List) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = expressions.map { it.toKotlin(commentConverter) }.makeString(", ") +class ExpressionList(val expressions: List) : Expression() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = expressions.map { it.toKotlin(commentsAndSpaces) }.makeString(", ") override val isEmpty: Boolean get() = expressions.isEmpty() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 699e727752d..3baccc78413 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -17,114 +17,115 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.lang.types.expressions.OperatorConventions -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class ArrayAccessExpression(val expression: Expression, val index: Expression, val lvalue: Boolean) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + (if (!lvalue && expression.isNullable) "!!" else "") + - "[" + index.toKotlin(commentConverter) + "]" + "[" + index.toKotlin(commentsAndSpaces) + "]" } class AssignmentExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(left, commentConverter) + " " + op + " " + operandToKotlin(right, commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(left, commentsAndSpaces) + " " + op + " " + operandToKotlin(right, commentsAndSpaces) } class BangBangExpression(val expr: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expr, commentConverter) + "!!" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expr, commentsAndSpaces) + "!!" } class BinaryExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(left, commentConverter, false) + " " + op + " " + operandToKotlin(right, commentConverter, true) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(left, commentsAndSpaces, false) + " " + op + " " + operandToKotlin(right, commentsAndSpaces, true) } class IsOperator(val expression: Expression, val typeElement: TypeElement) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + " is " + typeElement.`type`.toNotNullType().toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + " is " + typeElement.`type`.toNotNullType().toKotlin(commentsAndSpaces) } class TypeCastExpression(val `type`: Type, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + " as " + `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + " as " + `type`.toKotlin(commentsAndSpaces) } class LiteralExpression(val literalText: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = literalText + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = literalText } class ParenthesizedExpression(val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "(" + expression.toKotlin(commentConverter) + ")" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "(" + expression.toKotlin(commentsAndSpaces) + ")" } class PrefixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = op + operandToKotlin(expression, commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = op + operandToKotlin(expression, commentsAndSpaces) override val isNullable: Boolean get() = expression.isNullable } class PostfixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + op + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + op } class ThisExpression(val identifier: Identifier) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "this" + identifier.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "this" + identifier.withPrefix("@", commentsAndSpaces) } class SuperExpression(val identifier: Identifier) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "super" + identifier.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "super" + identifier.withPrefix("@", commentsAndSpaces) } class QualifiedExpression(val qualifier: Expression, val identifier: Expression) : Expression() { override val isNullable: Boolean get() = identifier.isNullable - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (!qualifier.isEmpty) { - return operandToKotlin(qualifier, commentConverter) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin(commentConverter) + return operandToKotlin(qualifier, commentsAndSpaces) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin(commentsAndSpaces) } - return identifier.toKotlin(commentConverter) + return identifier.toKotlin(commentsAndSpaces) } } class PolyadicExpression(val expressions: List, val token: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val expressionsWithConversions = expressions.map { it.toKotlin(commentConverter) } + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val expressionsWithConversions = expressions.map { it.toKotlin(commentsAndSpaces) } return expressionsWithConversions.makeString(" " + token + " ") } } -class LambdaExpression(val arguments: String?, val statementList: StatementList) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val statementsText = statementList.toKotlin(commentConverter).trim() - if (arguments != null) { +class LambdaExpression(val arguments: String?, val block: Block) : Expression() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val statementsText = block.statements.toKotlin(commentsAndSpaces, "\n").trim() + val innerBody = if (arguments != null) { val br = if (statementsText.indexOf('\n') < 0 && statementsText.indexOf('\r') < 0) " " else "\n" - return "{ $arguments ->$br$statementsText }" + "$arguments ->$br$statementsText" } else { - return "{ $statementsText }" + statementsText } + return block.lBrace.toKotlin(commentsAndSpaces) + " " + innerBody + " " + block.rBrace.toKotlin(commentsAndSpaces) } } class StarExpression(val methodCall: MethodCallExpression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "*" + methodCall.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "*" + methodCall.toKotlin(commentsAndSpaces) } fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List, needExplicitType: Boolean) : MethodCallExpression { val elementType = arrayType.elementType val createArrayFunction = if (elementType is PrimitiveType) - (elementType.toNotNullType().toKotlin(CommentConverter.Dummy) + "Array").decapitalize() + (elementType.toNotNullType().toKotlin(CommentsAndSpaces.None) + "Array").decapitalize() else if (needExplicitType) - arrayType.toNotNullType().toKotlin(CommentConverter.Dummy).decapitalize() + arrayType.toNotNullType().toKotlin(CommentsAndSpaces.None).decapitalize() else "array" val doubleOrFloatTypes = setOf("double", "float", "java.lang.double", "java.lang.float") - val afterReplace = arrayType.toNotNullType().toKotlin(CommentConverter.Dummy).replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") + val afterReplace = arrayType.toNotNullType().toKotlin(CommentsAndSpaces.None).replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") fun explicitConvertIfNeeded(initializer: Expression): Expression { if (doubleOrFloatTypes.contains(afterReplace)) { if (initializer is LiteralExpression) { - if (!initializer.toKotlin(CommentConverter.Dummy).contains(".")) { + if (!initializer.toKotlin(CommentsAndSpaces.None).contains(".")) { return LiteralExpression(initializer.literalText + ".0") } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index 3498fabfd9c..20f27b093fa 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -21,27 +21,25 @@ import java.util.ArrayList open class Field( val identifier: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, val `type`: Type, val initializer: Element, val isVal: Boolean, private val hasWriteAccesses: Boolean -) : Member(comments, annotations, modifiers) { +) : Member(annotations, modifiers) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val declaration = commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val declaration = annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + (if (isVal) "val " else "var ") + - identifier.toKotlin(commentConverter) + + identifier.toKotlin(commentsAndSpaces) + " : " + - `type`.toKotlin(commentConverter) + `type`.toKotlin(commentsAndSpaces) return if (initializer.isEmpty) - declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin(commentConverter)) + declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin(commentsAndSpaces)) else - declaration + " = " + initializer.toKotlin(commentConverter) + declaration + " = " + initializer.toKotlin(commentsAndSpaces) } private fun modifiersToKotlin(): String { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt index d1175ca8806..e4173edd52c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt @@ -16,20 +16,18 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter - -class FileMemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine, false) +import org.jetbrains.jet.j2k.CommentsAndSpaces class PackageStatement(val packageName: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "package " + packageName + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "package " + packageName } class File( - val body: FileMemberList, + val elements: List, val mainFunction: String ) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return body.toKotlin(commentConverter) + mainFunction + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return elements.toKotlin(commentsAndSpaces, "\n") + mainFunction } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt index 6020b9777a4..3298a2ffd84 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt @@ -18,12 +18,11 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList import org.jetbrains.jet.j2k.Converter -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces open class Function( val converter: Converter, val name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, val `type`: Type, @@ -31,7 +30,7 @@ open class Function( val parameterList: ParameterList, var block: Block?, val isInTrait: Boolean -) : Member(comments, annotations, modifiers) { +) : Member(annotations, modifiers) { private fun modifiersToKotlin(): String { val resultingModifiers = ArrayList() @@ -56,14 +55,13 @@ open class Function( return resultingModifiers.toKotlin() } - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + - "fun ${typeParameterList.toKotlin(commentConverter).withSuffix(" ")}${name.toKotlin(commentConverter)}" + - "(${parameterList.toKotlin(commentConverter)})" + - (if (!`type`.isUnit()) " : " + `type`.toKotlin(commentConverter) + " " else " ") + - typeParameterList.whereToKotlin(commentConverter) + - block?.toKotlin(commentConverter) + "fun ${typeParameterList.toKotlin(commentsAndSpaces).withSuffix(" ")}${name.toKotlin(commentsAndSpaces)}" + + "(${parameterList.toKotlin(commentsAndSpaces)})" + + (if (!`type`.isUnit()) " : " + `type`.toKotlin(commentsAndSpaces) + " " else " ") + + typeParameterList.whereToKotlin(commentsAndSpaces) + + block?.toKotlin(commentsAndSpaces) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt index 9e229d17ca7..4361838b0b6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt @@ -16,8 +16,13 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces +import com.intellij.psi.PsiNameIdentifierOwner +fun PsiNameIdentifierOwner.declarationIdentifier(): Identifier { + val name = getName() + return if (name != null) Identifier(name, false).assignPrototype(getNameIdentifier()!!) else Identifier.Empty +} class Identifier( val name: String, @@ -36,7 +41,7 @@ class Identifier( return name } - override fun toKotlinImpl(commentConverter: CommentConverter): String = toKotlin() + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = toKotlin() private fun quote(str: String): String = "`" + str + "`" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt index 82f85682e0e..50007b9a8c7 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt @@ -25,35 +25,39 @@ import com.intellij.psi.PsiJavaCodeReferenceElement import org.jetbrains.jet.asJava.KotlinLightClassForPackage class Import(val name: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "import " + name + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "import " + name } class ImportList(public val imports: List) : Element() { override val isEmpty: Boolean get() = imports.isEmpty() - override fun toKotlinImpl(commentConverter: CommentConverter) = imports.toKotlin(commentConverter, "\n") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = imports.toKotlin(commentsAndSpaces, "\n") } public fun Converter.convertImportList(importList: PsiImportList): ImportList = - ImportList(importList.getAllImportStatements().map { convertImport(it, true) }.filterNotNull()) + ImportList(importList.getAllImportStatements().map { convertImport(it, true) }.filterNotNull()).assignPrototype(importList) public fun Converter.convertImport(anImport: PsiImportStatementBase, filter: Boolean): Import? { - val reference = anImport.getImportReference() - if (reference == null) return null - val qualifiedName = quoteKeywords(reference.getQualifiedName()!!) - if (anImport.isOnDemand()) { - return Import(qualifiedName + ".*") - } - else { - return if (filter) { - val filteredName = filterImport(qualifiedName, reference) - if (filteredName != null) Import(filteredName) else null + fun doConvert(): Import? { + val reference = anImport.getImportReference() + if (reference == null) return null + val qualifiedName = quoteKeywords(reference.getQualifiedName()!!) + if (anImport.isOnDemand()) { + return Import(qualifiedName + ".*") } else { - Import(qualifiedName) + return if (filter) { + val filteredName = filterImport(qualifiedName, reference) + if (filteredName != null) Import(filteredName) else null + } + else { + Import(qualifiedName) + } } } + + return doConvert()?.assignPrototype(anImport) } private fun filterImport(name: String, ref: PsiJavaCodeReferenceElement): String? { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt index ca90d460077..3386c36a33a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt @@ -16,10 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -class Initializer(val block: Block, modifiers: Set) : Member(MemberComments.Empty, Annotations.Empty, modifiers) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return block.toKotlin(commentConverter) +class Initializer(val block: Block, modifiers: Set) : Member(Annotations.Empty, modifiers) { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return block.toKotlin(commentsAndSpaces) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index a98f47ba5b4..ba225477abc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.ConverterSettings -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class LocalVariable( private val identifier: Identifier, @@ -29,17 +29,17 @@ class LocalVariable( private val settings: ConverterSettings ) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val start = annotations.toKotlin(commentConverter) + if (isVal) "val" else "var" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val start = annotations.toKotlin(commentsAndSpaces) + if (isVal) "val" else "var" return if (initializer.isEmpty) { - "$start ${identifier.toKotlin(commentConverter)} : ${typeCalculator().toKotlin(commentConverter)}" + "$start ${identifier.toKotlin(commentsAndSpaces)} : ${typeCalculator().toKotlin(commentsAndSpaces)}" } else { val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault if (shouldSpecifyType) - "$start ${identifier.toKotlin(commentConverter)} : ${typeCalculator().toKotlin(commentConverter)} = ${initializer.toKotlin(commentConverter)}" + "$start ${identifier.toKotlin(commentsAndSpaces)} : ${typeCalculator().toKotlin(commentsAndSpaces)} = ${initializer.toKotlin(commentsAndSpaces)}" else - "$start ${identifier.toKotlin(commentConverter)} = ${initializer.toKotlin(commentConverter)}" + "$start ${identifier.toKotlin(commentsAndSpaces)} = ${initializer.toKotlin(commentsAndSpaces)}" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt deleted file mode 100644 index 846a6b39498..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2010-2013 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.j2k.ast - -import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter - -class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NoSpace) { - class object { - val Empty = MemberComments(ArrayList()) - } -} - -abstract class Member(val comments: MemberComments, val annotations: Annotations, val modifiers: Set) : Element() { - fun commentsToKotlin(commentConverter: CommentConverter): String = comments.toKotlin(commentConverter) -} - -//member itself and all the elements before it in the code (comments, whitespaces) -class MemberWithComments(val member: Member, val elements: List) - -class MemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) { - val members: List - get() = elements.filter { it is Member }.map { it as Member } -} - -class ClassBody ( - val primaryConstructor: PrimaryConstructor?, - val secondaryConstructors: MemberList, - val normalMembers: MemberList, - val classObjectMembers: MemberList) { - - fun toKotlin(containingClass: Class?, commentConverter: CommentConverter): String { - val innerBody = normalMembers.toKotlin(commentConverter) + - primaryConstructorBodyToKotlin(commentConverter) + - classObjectToKotlin(containingClass, commentConverter) - return if (innerBody.trim().isNotEmpty()) " {" + innerBody + "}" else "" - } - - private fun primaryConstructorBodyToKotlin(commentConverter: CommentConverter): String { - val constructor = primaryConstructor - if (constructor != null && !(constructor.block?.isEmpty ?: true)) { - return "\n" + constructor.bodyToKotlin(commentConverter) + "\n" - } - return "" - } - - private fun classObjectToKotlin(containingClass: Class?, commentConverter: CommentConverter): String { - val secondaryConstructorsAsStaticInitFunctions = secondaryConstructorsAsStaticInitFunctions(containingClass) - if (secondaryConstructorsAsStaticInitFunctions.isEmpty() && classObjectMembers.isEmpty()) return "" - return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin(commentConverter)}${classObjectMembers.toKotlin(commentConverter)}}" - } - - private fun secondaryConstructorsAsStaticInitFunctions(containingClass: Class?): MemberList { - return MemberList(secondaryConstructors.elements.map { if (it is SecondaryConstructor && containingClass != null) it.toInitFunction(containingClass) else it }) - } -} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 30795dd45a0..4cdeb67142f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class MethodCallExpression( val methodExpression: Expression, @@ -26,15 +26,15 @@ class MethodCallExpression( val lambdaArgument: LambdaExpression? = null ) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val builder = StringBuilder() - builder.append(operandToKotlin(methodExpression, commentConverter)) - builder.append(typeArguments.toKotlin(commentConverter, ", ", "<", ">")) + builder.append(operandToKotlin(methodExpression, commentsAndSpaces)) + builder.append(typeArguments.toKotlin(commentsAndSpaces, ", ", "<", ">")) if (arguments.isNotEmpty() || lambdaArgument == null) { - builder.append("(").append(arguments.map { it.toKotlin(commentConverter) }.makeString(", ")).append(")") + builder.append("(").append(arguments.map { it.toKotlin(commentsAndSpaces) }.makeString(", ")).append(")") } if (lambdaArgument != null) { - builder.append(lambdaArgument.toKotlin(commentConverter)) + builder.append(lambdaArgument.toKotlin(commentsAndSpaces)) } return builder.toString() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt index 59511daa58c..9baec7f14fd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces enum class Modifier(val name: String) { PUBLIC: Modifier("public") diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt index e931089712f..0ffc786bfa8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class NewClassExpression( val name: Element, @@ -25,18 +25,18 @@ class NewClassExpression( val anonymousClass: AnonymousClassBody? = null ) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val callOperator = if (qualifier.isNullable) "!!." else "." - val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin(commentConverter) + callOperator - val appliedArguments = arguments.toKotlin(commentConverter, ", ") + val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin(commentsAndSpaces) + callOperator + val appliedArguments = arguments.toKotlin(commentsAndSpaces, ", ") return if (anonymousClass != null) { if (anonymousClass.extendsTrait) - "object : " + qualifier + name.toKotlin(commentConverter) + anonymousClass.toKotlin(commentConverter) + "object : " + qualifier + name.toKotlin(commentsAndSpaces) + anonymousClass.toKotlin(commentsAndSpaces) else - "object : " + qualifier + name.toKotlin(commentConverter) + "(" + appliedArguments + ")" + anonymousClass.toKotlin(commentConverter) + "object : " + qualifier + name.toKotlin(commentsAndSpaces) + "(" + appliedArguments + ")" + anonymousClass.toKotlin(commentsAndSpaces) } else{ - qualifier + name.toKotlin(commentConverter) + "(" + appliedArguments + ")" + qualifier + name.toKotlin(commentsAndSpaces) + "(" + appliedArguments + ")" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 2c1692907df..83d4ad89d9c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Parameter(val identifier: Identifier, val `type`: Type, @@ -29,10 +29,10 @@ class Parameter(val identifier: Identifier, Var } - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val builder = StringBuilder() - builder.append(annotations.toKotlin(commentConverter)) + builder.append(annotations.toKotlin(commentsAndSpaces)) builder.append(modifiers.toKotlin()) if (`type` is VarArgType) { @@ -45,7 +45,7 @@ class Parameter(val identifier: Identifier, VarValModifier.Val -> builder.append("val ") } - builder.append(identifier.toKotlin(commentConverter)).append(": ").append(`type`.toKotlin(commentConverter)) + builder.append(identifier.toKotlin(commentsAndSpaces)).append(": ").append(`type`.toKotlin(commentsAndSpaces)) return builder.toString() } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt index 8a3e770801c..096a58850b0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt @@ -16,10 +16,9 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces - -open class ParameterList(val parameters: List) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = parameters.map { it.toKotlin(commentConverter) }.makeString(", ") +class ParameterList(val parameters: List) : Element() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = parameters.map { it.toKotlin(commentsAndSpaces) }.makeString(", ") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt index 98b7eff616c..b9e5f1f4f5b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class ReferenceElement(val reference: Identifier, val types: List) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = reference.toKotlin(commentConverter) + types.toKotlin(commentConverter, ", ", "<", ">") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = reference.toKotlin(commentsAndSpaces) + types.toKotlin(commentsAndSpaces, ", ", "<", ">") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt index a059e1bafea..e4bd15dbea4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt @@ -16,12 +16,12 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces abstract class Statement() : Element() { object Empty : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" override val isEmpty: Boolean get() = true @@ -29,20 +29,20 @@ abstract class Statement() : Element() { } class DeclarationStatement(val elements: List) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String - = elements.filterIsInstance(javaClass()).map { it.toKotlin(commentConverter) }.makeString("\n") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String + = elements.filterIsInstance(javaClass()).map { it.toKotlin(commentsAndSpaces) }.makeString("\n") } class ExpressionListStatement(val expressions: List) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = expressions.toKotlin(commentConverter, "\n") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = expressions.toKotlin(commentsAndSpaces, "\n") } class LabelStatement(val name: Identifier, val statement: Element) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "@" + name.toKotlin(commentConverter) + " " + statement.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "@" + name.toKotlin(commentsAndSpaces) + " " + statement.toKotlin(commentsAndSpaces) } class ReturnStatement(val expression: Expression) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "return " + expression.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "return " + expression.toKotlin(commentsAndSpaces) } class IfStatement( @@ -53,10 +53,10 @@ class IfStatement( ) : Expression() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val result = "if (" + condition.toKotlin(commentConverter) + ")$br" + thenStatement.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val result = "if (" + condition.toKotlin(commentsAndSpaces) + ")$br" + thenStatement.toKotlin(commentsAndSpaces) if (!elseStatement.isEmpty) { - return "$result${br}else$br${elseStatement.toKotlin(commentConverter)}" + return "$result${br}else$br${elseStatement.toKotlin(commentsAndSpaces)}" } return result } @@ -67,13 +67,13 @@ class IfStatement( class WhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "while (" + condition.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "while (" + condition.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) } class DoWhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "do$br" + body.toKotlin(commentConverter) + "${br}while (" + condition.toKotlin(commentConverter) + ")" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "do$br" + body.toKotlin(commentsAndSpaces) + "${br}while (" + condition.toKotlin(commentsAndSpaces) + ")" } class ForeachStatement( @@ -85,7 +85,7 @@ class ForeachStatement( private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "for (" + variable.identifier.toKotlin(commentConverter) + " in " + expression.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "for (" + variable.identifier.toKotlin(commentsAndSpaces) + " in " + expression.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) } class ForeachWithRangeStatement(val identifier: Identifier, @@ -95,70 +95,64 @@ class ForeachWithRangeStatement(val identifier: Identifier, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "for (" + identifier.toKotlin(commentConverter) + " in " + start.toKotlin(commentConverter) + ".." + end.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "for (" + identifier.toKotlin(commentsAndSpaces) + " in " + start.toKotlin(commentsAndSpaces) + ".." + end.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) } class BreakStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "break" + label.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "break" + label.withPrefix("@", commentsAndSpaces) } class ContinueStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "continue" + label.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "continue" + label.withPrefix("@", commentsAndSpaces) } // Exceptions ---------------------------------------------------------------------------------------------- class TryStatement(val block: Block, val catches: List, val finallyBlock: Block) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val builder = StringBuilder() .append("try\n") - .append(block.toKotlin(commentConverter)) + .append(block.toKotlin(commentsAndSpaces)) .append("\n") - .append(catches.toKotlin(commentConverter, "\n")) + .append(catches.toKotlin(commentsAndSpaces, "\n")) .append("\n") if (!finallyBlock.isEmpty) { - builder.append("finally\n").append(finallyBlock.toKotlin(commentConverter)) + builder.append("finally\n").append(finallyBlock.toKotlin(commentsAndSpaces)) } return builder.toString() } } class ThrowStatement(val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "throw " + expression.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "throw " + expression.toKotlin(commentsAndSpaces) } class CatchStatement(val variable: Parameter, val block: Block) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "catch (" + variable.toKotlin(commentConverter) + ") " + block.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "catch (" + variable.toKotlin(commentsAndSpaces) + ") " + block.toKotlin(commentsAndSpaces) } // Switch -------------------------------------------------------------------------------------------------- class SwitchContainer(val expression: Expression, val caseContainers: List) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "when (" + expression.toKotlin(commentConverter) + ") {\n" + caseContainers.toKotlin(commentConverter, "\n") + "\n}" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "when (" + expression.toKotlin(commentsAndSpaces) + ") {\n" + caseContainers.toKotlin(commentsAndSpaces, "\n") + "\n}" } class CaseContainer(val caseStatement: List, statements: List) : Statement() { - private val block = Block(statements.filterNot { it is BreakStatement || it is ContinueStatement }, true) + private val block = Block(statements.filterNot { it is BreakStatement || it is ContinueStatement }, LBrace(), RBrace(), true) - override fun toKotlinImpl(commentConverter: CommentConverter) = caseStatement.toKotlin(commentConverter, ", ") + " -> " + block.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = caseStatement.toKotlin(commentsAndSpaces, ", ") + " -> " + block.toKotlin(commentsAndSpaces) } class SwitchLabelStatement(val expression: Expression) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = expression.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = expression.toKotlin(commentsAndSpaces) } class DefaultSwitchLabelStatement() : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "else" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "else" } // Other ------------------------------------------------------------------------------------------------------ class SynchronizedStatement(val expression: Expression, val block: Block) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "synchronized (" + expression.toKotlin(commentConverter) + ") " + block.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "synchronized (" + expression.toKotlin(commentsAndSpaces) + ") " + block.toKotlin(commentsAndSpaces) } - -class StatementList(elements: List) - : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) { - val statements: List - get() = elements.filterIsInstance(javaClass()) -} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index 881c04e3e6e..462e9dc0477 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -17,10 +17,9 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Trait(name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, typeParameterList: TypeParameterList, @@ -28,12 +27,12 @@ class Trait(name: Identifier, baseClassParams: List, implementsTypes: List, body: ClassBody -) : Class(name, comments, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { +) : Class(name, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { override val keyword: String get() = "trait" - override fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter) = "" + override fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces) = "" override fun modifiersToKotlin(): String { val modifierList = ArrayList() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt index 0a4a7961270..4259c1804cb 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class TypeElement(val `type`: Type) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = `type`.toKotlin(commentsAndSpaces) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt index 7ecbb5ba7f0..b77cca56b31 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt @@ -20,39 +20,39 @@ import com.intellij.psi.PsiTypeParameter import org.jetbrains.jet.j2k.Converter import com.intellij.psi.PsiTypeParameterList import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class TypeParameter(val name: Identifier, val extendsTypes: List) : Element() { fun hasWhere(): Boolean = extendsTypes.size() > 1 - fun whereToKotlin(commentConverter: CommentConverter): String { + fun whereToKotlin(commentsAndSpaces: CommentsAndSpaces): String { if (hasWhere()) { - return name.toKotlin(commentConverter) + " : " + extendsTypes[1].toKotlin(commentConverter) + return name.toKotlin(commentsAndSpaces) + " : " + extendsTypes[1].toKotlin(commentsAndSpaces) } return "" } - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (extendsTypes.size() > 0) { - return name.toKotlin(commentConverter) + " : " + extendsTypes[0].toKotlin(commentConverter) + return name.toKotlin(commentsAndSpaces) + " : " + extendsTypes[0].toKotlin(commentsAndSpaces) } - return name.toKotlin(commentConverter) + return name.toKotlin(commentsAndSpaces) } } class TypeParameterList(val parameters: List) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { return if (parameters.isNotEmpty()) - parameters.map { it.toKotlin(commentConverter) }.makeString(", ", "<", ">") + parameters.map { it.toKotlin(commentsAndSpaces) }.makeString(", ", "<", ">") else "" } - fun whereToKotlin(commentConverter: CommentConverter): String { + fun whereToKotlin(commentsAndSpaces: CommentsAndSpaces): String { if (hasWhere()) { - val wheres = parameters.map { it.whereToKotlin(commentConverter) } + val wheres = parameters.map { it.whereToKotlin(commentsAndSpaces) } return "where " + wheres.makeString(", ") } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 2c81c825e2c..4894ee96bbd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.ConverterSettings -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces fun Type.isUnit(): Boolean = this == Type.Unit @@ -59,26 +59,26 @@ abstract class Type() : Element() { } object Empty : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "UNRESOLVED_TYPE" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "UNRESOLVED_TYPE" } object Unit: NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "Unit" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "Unit" } - override fun equals(other: Any?): Boolean = other is Type && other.toKotlin(CommentConverter.Dummy) == this.toKotlin(CommentConverter.Dummy) + override fun equals(other: Any?): Boolean = other is Type && other.toKotlin(CommentsAndSpaces.None) == this.toKotlin(CommentsAndSpaces.None) - override fun hashCode(): Int = toKotlin(CommentConverter.Dummy).hashCode() + override fun hashCode(): Int = toKotlin(CommentsAndSpaces.None).hashCode() - override fun toString(): String = toKotlin(CommentConverter.Dummy) + override fun toString(): String = toKotlin(CommentsAndSpaces.None) } class ClassType(val `type`: Identifier, val typeArgs: List, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin(commentConverter) }.makeString(", ", "<", ">") - return `type`.toKotlin(commentConverter) + params + isNullableStr + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin(commentsAndSpaces) }.makeString(", ", "<", ">") + return `type`.toKotlin(commentsAndSpaces) + params + isNullableStr } @@ -89,12 +89,12 @@ class ClassType(val `type`: Identifier, val typeArgs: List, nullability class ArrayType(val elementType: Type, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (elementType is PrimitiveType) { - return elementType.toKotlin(commentConverter) + "Array" + isNullableStr + return elementType.toKotlin(commentsAndSpaces) + "Array" + isNullableStr } - return "Array<" + elementType.toKotlin(commentConverter) + ">" + isNullableStr + return "Array<" + elementType.toKotlin(commentsAndSpaces) + ">" + isNullableStr } override fun toNotNullType(): Type = ArrayType(elementType, Nullability.NotNull, settings) @@ -102,21 +102,21 @@ class ArrayType(val elementType: Type, nullability: Nullability, settings: Conve } class InProjectionType(val bound: Type) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "in " + bound.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "in " + bound.toKotlin(commentsAndSpaces) } class OutProjectionType(val bound: Type) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "out " + bound.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "out " + bound.toKotlin(commentsAndSpaces) } class StarProjectionType() : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "*" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "*" } class PrimitiveType(val `type`: Identifier) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = `type`.toKotlin(commentsAndSpaces) } class VarArgType(val `type`: Type) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = `type`.toKotlin(commentsAndSpaces) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt index 39282ad01f4..4f719813a55 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt @@ -16,65 +16,20 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -fun List.toKotlin(commentConverter: CommentConverter, separator: String, prefix: String = "", postfix: String = ""): String - = if (isNotEmpty()) map { it.toKotlin(commentConverter) }.makeString(separator, prefix, postfix) else "" +fun List.toKotlin(commentsAndSpaces: CommentsAndSpaces, separator: String, prefix: String = "", postfix: String = ""): String { + val texts = map { it.toKotlin(commentsAndSpaces) }.filter { it.isNotEmpty() } + return if (texts.isNotEmpty()) texts.makeString(separator, prefix, postfix) else "" +} fun String.withSuffix(suffix: String): String = if (isEmpty()) "" else this + suffix fun String.withPrefix(prefix: String): String = if (isEmpty()) "" else prefix + this -fun Expression.withPrefix(prefix: String, commentConverter: CommentConverter): String = if (isEmpty) "" else prefix + toKotlin(commentConverter) +fun Expression.withPrefix(prefix: String, commentsAndSpaces: CommentsAndSpaces): String = if (isEmpty) "" else prefix + toKotlin(commentsAndSpaces) -open class WhiteSpaceSeparatedElementList( - val elements: List, - val minimalWhiteSpace: WhiteSpace, - val ensureSurroundedByWhiteSpace: Boolean = true -) { - val nonEmptyElements = elements.filter { !it.isEmpty } - - fun isEmpty() = nonEmptyElements.all { it is WhiteSpace } - - fun toKotlin(commentConverter: CommentConverter): String { - if (isEmpty()) return "" - return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin(commentConverter) }.makeString("") - } - - private fun List.surroundWithWhiteSpaces(): List - = if (ensureSurroundedByWhiteSpace) listOf(minimalWhiteSpace) + this + listOf(minimalWhiteSpace) else this - - - // ensure that there is whitespace between non-whitespace elements - // choose maximum among subsequent whitespaces - // all resulting whitespaces are at least minimal whitespace - private fun List.insertAndMergeWhiteSpaces(): List { - var currentWhiteSpace: WhiteSpace? = null - val result = ArrayList() - for (i in 0..lastIndex) { - val element = get(i) - if (element is WhiteSpace) { - if (currentWhiteSpace == null || element > currentWhiteSpace!!) { - currentWhiteSpace = if (element > minimalWhiteSpace) element else minimalWhiteSpace - } - } - else { - if (i != 0) { //do not insert whitespace before first element - result.add(currentWhiteSpace ?: minimalWhiteSpace) - } - result.add(element) - currentWhiteSpace = null - } - } - if (currentWhiteSpace != null) { - result.add(currentWhiteSpace!!) - } - return result - } -} - -fun Expression.operandToKotlin(operand: Expression, commentConverter: CommentConverter, parenthesisForSamePrecedence: Boolean = false): String { +fun Expression.operandToKotlin(operand: Expression, commentsAndSpaces: CommentsAndSpaces, parenthesisForSamePrecedence: Boolean = false): String { val parentPrecedence = precedence() ?: throw IllegalArgumentException("Unknown precendence for $this") - val kotlinCode = operand.toKotlin(commentConverter) + val kotlinCode = operand.toKotlin(commentsAndSpaces) val operandPrecedence = operand.precedence() ?: return kotlinCode val needParenthesis = parentPrecedence < operandPrecedence || parentPrecedence == operandPrecedence && parenthesisForSamePrecedence return if (needParenthesis) "($kotlinCode)" else kotlinCode diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt b/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt deleted file mode 100644 index 30e53f184fa..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2010-2013 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.j2k.ast - -import org.jetbrains.jet.j2k.CommentConverter - - -class WhiteSpace(val text: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = text - - override val isEmpty: Boolean - get() = text.isEmpty() - - fun compareTo(other: WhiteSpace): Int { - - fun newLinesCount(w: WhiteSpace) = w.text.count { it == '\n' } - - val lineCountDiff = newLinesCount(this) - newLinesCount(other) - if (lineCountDiff != 0) return lineCountDiff - - fun spacesCount(w: WhiteSpace) = w.text.count { it == ' ' } - - return spacesCount(this) - spacesCount(other) - } - - class object { - val NewLine = WhiteSpace("\n") - val NoSpace = WhiteSpace("") - } -} - - diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt index 6a370792ceb..04ae75a7702 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt @@ -27,7 +27,7 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { protected set override fun visitLocalVariable(variable: PsiLocalVariable) { - result = LocalVariable(Identifier(variable.getName()!!), + result = LocalVariable(variable.declarationIdentifier(), converter.convertAnnotations(variable), converter.convertModifiers(variable), { typeConverter.convertVariableType(variable) }, @@ -62,19 +62,11 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { } override fun visitTypeParameter(classParameter: PsiTypeParameter) { - result = TypeParameter(Identifier(classParameter.getName()!!), - classParameter.getExtendsListTypes().map { typeConverter.convertType(it) }) + result = TypeParameter(classParameter.declarationIdentifier(), + classParameter.getExtendsListTypes().map { typeConverter.convertType(it) }) } override fun visitParameterList(list: PsiParameterList) { result = converter.convertParameterList(list) } - - override fun visitComment(comment: PsiComment) { - result = Comment(comment.getText()!!) - } - - override fun visitWhiteSpace(space: PsiWhiteSpace) { - result = WhiteSpace(space.getText()!!) - } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index feb536f6856..783f711b72b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -45,7 +45,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition, description)) } else { - result = MethodCallExpression.build(null, "assert", listOf(condition), listOf(), false, LambdaExpression(null, StatementList(listOf(description)))) + result = MethodCallExpression.build(null, "assert", listOf(condition), listOf(), false, LambdaExpression(null, Block(listOf(description), LBrace(), RBrace()))) } } } @@ -117,11 +117,8 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito && loopVar.getNameIdentifier() != null && onceWritableIterator) { val end = converter.convertExpression((condition as PsiBinaryExpression).getROperand()) - val endExpression = if (operationTokenType == JavaTokenType.LT) - BinaryExpression(end, Identifier("1"), "-") - else - end - result = ForeachWithRangeStatement(Identifier(loopVar.getName()!!), + val endExpression = if (operationTokenType == JavaTokenType.LT) BinaryExpression(end, LiteralExpression("1"), "-") else end + result = ForeachWithRangeStatement(loopVar.declarationIdentifier(), converter.convertExpression(loopVar.getInitializer()), endExpression, converter.convertStatement(body), @@ -131,12 +128,12 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito var forStatements = ArrayList() forStatements.add(converter.convertStatement(initialization)) val bodyAndUpdate = listOf(converter.convertStatement(body), - Block(listOf(converter.convertStatement(update)))) + Block(listOf(converter.convertStatement(update)), LBrace(), RBrace())) forStatements.add(WhileStatement( if (condition == null) LiteralExpression("true") else converter.convertExpression(condition), - Block(bodyAndUpdate), + Block(bodyAndUpdate, LBrace(), RBrace()), statement.isInSingleLine())) - result = Block(forStatements) + result = Block(forStatements, LBrace(), RBrace()) } } @@ -269,13 +266,12 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito }} } - var bodyConverted = converterForBody.convertBlock(tryBlock) - var statementList = bodyConverted.statementList + var block = converterForBody.convertBlock(tryBlock) var expression: Expression = Expression.Empty for (variable in variables.reverse()) { - val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), statementList) + val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), block) expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda) - statementList = StatementList(listOf(expression)) + block = Block(listOf(expression), LBrace(), RBrace()) } if (catchesConverted.isEmpty() && finallyConverted.isEmpty) { @@ -283,8 +279,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito return } - bodyConverted = Block(StatementList(listOf(wrapResultStatement(expression))), true) - result = TryStatement(bodyConverted, catchesConverted, finallyConverted) + result = TryStatement(Block(listOf(wrapResultStatement(expression)), LBrace(), RBrace(), true), catchesConverted, finallyConverted) return } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index efe6226c743..b01a2402ac0 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("j2k/tests/testData/ast") -@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) +@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.Comments.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInAst() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true); @@ -731,6 +731,19 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } + @TestMetadata("j2k/tests/testData/ast/comments") + public static class Comments extends AbstractJavaToKotlinConverterTest { + public void testAllFilesPresentInComments() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/comments"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("Comments.java") + public void testComments() throws Exception { + doTest("j2k/tests/testData/ast/comments/Comments.java"); + } + + } + @TestMetadata("j2k/tests/testData/ast/conditionalExpression") public static class ConditionalExpression extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInConditionalExpression() throws Exception { @@ -2786,6 +2799,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(CallChainExpression.class); suite.addTestSuite(Class.class); suite.addTestSuite(ClassExpression.class); + suite.addTestSuite(Comments.class); suite.addTestSuite(ConditionalExpression.class); suite.addTestSuite(Constructors.class); suite.addTestSuite(ContinueStatement.class); diff --git a/j2k/tests/testData/ast/comments/Comments.kt b/j2k/tests/testData/ast/comments/Comments.kt new file mode 100644 index 00000000000..8fbef48f875 --- /dev/null +++ b/j2k/tests/testData/ast/comments/Comments.kt @@ -0,0 +1,30 @@ +package foo + +// we use package 'foo' + +// imports: +import java.util.ArrayList + +// we need ArrayList + +// let's declare a class: +class A /* just a sample name*/() : Runnable /* let's implement Runnable */ { + fun foo/* again a sample name */(p: Int /* parameter p */, c: Char /* parameter c */) { + // let's print something: + System.out.println("1") // print 1 + System.out.println("2") // print 2 + + System.out.println("3") // print 3 + + // end of printing + + if (p > 0) { + // do this only when p > 0 + // we print 4 and return + System.out.println("3") + return // do not continue + } + + // some code to be added + } +} // end of class A \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/comments.java b/j2k/tests/testData/ast/comments/comments.java new file mode 100644 index 00000000000..61c1099cc74 --- /dev/null +++ b/j2k/tests/testData/ast/comments/comments.java @@ -0,0 +1,26 @@ +//file +package foo; // we use package 'foo' + +// imports: +import java.util.ArrayList; // we need ArrayList + +// let's declare a class: +class A /* just a sample name*/ implements Runnable /* let's implement Runnable */ { + void foo /* again a sample name */(int p /* parameter p */, char c /* parameter c */) { + // let's print something: + System.out.println("1"); // print 1 + System.out.println("2"); // print 2 + + System.out.println("3"); // print 3 + + // end of printing + + if (p > 0) { // do this only when p > 0 + // we print 4 and return + System.out.println("3"); + return; // do not continue + } + + // some code to be added + } +} // end of class A \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/comments.kt.todo b/j2k/tests/testData/ast/comments/comments.kt.todo new file mode 100644 index 00000000000..c2b1c4c52da --- /dev/null +++ b/j2k/tests/testData/ast/comments/comments.kt.todo @@ -0,0 +1,25 @@ +package foo // we use package 'foo' + +// imports: +import java.util.ArrayList // we need ArrayList + +// let's declare a class: +class A /* just a sample name*/() : Runnable /* let's implement Runnable */ { + fun foo /* again a sample name */( p: Int /* parameter p */, c: Char /* parameter c */) { + // let's print something: + System.out.println("1") // print 1 + System.out.println("2") // print 2 + + System.out.println("3") // print 3 + + // end of printing + + if (p > 0) { // do this only when p > 0 + // we print 4 and return + System.out.println("3") + return // do not continue + } + + // some code to be added + } +} // end of class A diff --git a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt index 10a1911bad5..2e19d45aa08 100644 --- a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt +++ b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt @@ -11,7 +11,6 @@ public class Test private(private val myName: String, private var a: Boolean, pr return __ } - fun foo(n: String): String { return "" } diff --git a/j2k/tests/testData/ast/formatting/nonStaticMembers.kt b/j2k/tests/testData/ast/formatting/nonStaticMembers.kt index 32ea2da202f..72079e2c1e7 100644 --- a/j2k/tests/testData/ast/formatting/nonStaticMembers.kt +++ b/j2k/tests/testData/ast/formatting/nonStaticMembers.kt @@ -3,7 +3,6 @@ class F() { fun f1() { } - fun f2() { } var i: Int = 0 diff --git a/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt index 163c5d65b5a..61be9023894 100644 --- a/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt @@ -7,7 +7,6 @@ class F() { fun f1() { } - //c3 diff --git a/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt index 7840a9982f7..482f5783f08 100644 --- a/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt @@ -1,6 +1,5 @@ class F() { - //c3 @@ -31,8 +30,8 @@ class F() { fun f5() { } - - //c6 - } + + //c6 + } \ No newline at end of file diff --git a/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt index c3197e5af63..51c1ee14d3c 100644 --- a/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt @@ -8,7 +8,6 @@ class F() { fun f1() { } - //c3 @@ -22,7 +21,7 @@ class F() { fun f3() { } - - //c5 } + + //c5 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-836.kt b/j2k/tests/testData/ast/issues/kt-836.kt index e1799b31b15..1737733743c 100644 --- a/j2k/tests/testData/ast/issues/kt-836.kt +++ b/j2k/tests/testData/ast/issues/kt-836.kt @@ -9,7 +9,6 @@ public class Language(protected var code: String) : Serializable { } } - class Base() { fun test() { } diff --git a/j2k/tests/testData/ast/issues/kt-837.kt b/j2k/tests/testData/ast/issues/kt-837.kt index 587bc252bcc..0a85e5bb9cc 100644 --- a/j2k/tests/testData/ast/issues/kt-837.kt +++ b/j2k/tests/testData/ast/issues/kt-837.kt @@ -11,7 +11,6 @@ public class Language(protected var code: String) : Serializable { class object { public var ENGLISH: Language = Language("en") public var SWEDISH: Language = Language("sv") - private val serialVersionUID: Long = -2442762969929206780 } } \ No newline at end of file From ef62600d5e70fc4d5e76ed745f4080524c767430 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 19 Jun 2014 18:46:50 +0400 Subject: [PATCH 079/143] Java to Kotlin converter: big refactoring of code generation to never allow end of line comments to stick together with further code #KT-4421 Fixed --- j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt | 222 ++++++++++++++++++ .../jetbrains/jet/j2k/CommentsAndSpaces.kt | 174 -------------- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 10 +- j2k/src/org/jetbrains/jet/j2k/Utils.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Annotation.kt | 41 +++- .../jet/j2k/ast/AnonymousClassBody.kt | 6 +- .../ArrayWithoutInitializationExpression.kt | 52 ++-- j2k/src/org/jetbrains/jet/j2k/ast/Block.kt | 22 +- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 53 ++--- .../org/jetbrains/jet/j2k/ast/ClassBody.kt | 44 ++-- .../org/jetbrains/jet/j2k/ast/Constructors.kt | 9 +- .../jet/j2k/ast/DummyStringExpression.kt | 6 +- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 20 +- j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 22 +- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 11 +- .../org/jetbrains/jet/j2k/ast/Expression.kt | 4 +- .../jetbrains/jet/j2k/ast/ExpressionList.kt | 6 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 95 +++++--- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 30 ++- j2k/src/org/jetbrains/jet/j2k/ast/File.kt | 11 +- j2k/src/org/jetbrains/jet/j2k/ast/Function.kt | 34 ++- .../org/jetbrains/jet/j2k/ast/Identifier.kt | 6 +- j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt | 8 +- .../org/jetbrains/jet/j2k/ast/Initializer.kt | 6 +- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 15 +- .../jet/j2k/ast/MethodCallExpression.kt | 13 +- j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt | 12 +- .../jet/j2k/ast/NewClassExpression.kt | 29 ++- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 14 +- .../jetbrains/jet/j2k/ast/ParameterList.kt | 6 +- .../jetbrains/jet/j2k/ast/ReferenceElement.kt | 6 +- .../org/jetbrains/jet/j2k/ast/Statements.kt | 92 +++++--- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 8 +- .../org/jetbrains/jet/j2k/ast/TypeElement.kt | 6 +- .../jetbrains/jet/j2k/ast/TypeParameters.kt | 32 +-- j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 60 +++-- j2k/src/org/jetbrains/jet/j2k/ast/Util.kt | 26 +- .../jetbrains/jet/j2k/visitors/TypeVisitor.kt | 2 +- .../test/AbstractJavaToKotlinConverterTest.kt | 2 +- .../JavaToKotlinConverterTestGenerated.java | 14 +- .../comments/fieldWithEndOfLineComment.java | 4 + .../ast/comments/fieldWithEndOfLineComment.kt | 3 + .../comments/fieldsInitializedFromParams.java | 17 ++ .../comments/fieldsInitializedFromParams.kt | 6 + 44 files changed, 736 insertions(+), 525 deletions(-) create mode 100644 j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt delete mode 100644 j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt create mode 100644 j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.java create mode 100644 j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt create mode 100644 j2k/tests/testData/ast/comments/fieldsInitializedFromParams.java create mode 100644 j2k/tests/testData/ast/comments/fieldsInitializedFromParams.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt new file mode 100644 index 00000000000..b47da7a9bc8 --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt @@ -0,0 +1,222 @@ +/* + * Copyright 2010-2014 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.j2k + +import com.intellij.psi.* +import java.util.HashSet +import org.jetbrains.jet.lang.psi.psiUtil.isAncestor +import java.util.ArrayList +import org.jetbrains.jet.j2k.ast.Element +import kotlin.platform.platformName + +fun CodeBuilder.append(generators: Collection<() -> T>, separator: String, prefix: String = "", suffix: String = ""): CodeBuilder { + if (generators.isNotEmpty()) { + append(prefix) + var first = true + for (generator in generators) { + if (!first) { + append(separator) + } + generator() + first = false + } + append(suffix) + } + return this +} + +platformName("appendElements") +fun CodeBuilder.append(elements: Collection, separator: String, prefix: String = "", suffix: String = ""): CodeBuilder { + return append(elements.filter { !it.isEmpty }.map { { append(it) } }, separator, prefix, suffix) +} + +class CodeBuilder(private val topElement: PsiElement?) { + private val builder = StringBuilder() + private var endOfLineCommentAtEnd = false + + private val commentsAndSpacesUsed = HashSet() + + public fun append(text: String, endOfLineComment: Boolean = false): CodeBuilder { + if (text.isEmpty()) { + assert(!endOfLineComment) + return this + } + + if (endOfLineCommentAtEnd) { + if (text[0] != '\n' && text[0] != '\r') builder.append('\n') + endOfLineCommentAtEnd = false + } + + builder.append(text) + endOfLineCommentAtEnd = endOfLineComment + return this + } + + public val result: String + get() = builder.toString() + + public fun append(element: Element): CodeBuilder { + if (element.isEmpty) return this // do not insert comment and spaces for empty elements to avoid multiple blank lines + + if (element.prototypes.isEmpty() || topElement == null) { + element.generateCode(this) + return this + } + + val prefixElements = ArrayList(2) + val postfixElements = ArrayList(2) + for ((prototype, inheritBlankLinesBefore) in element.prototypes) { + assert(prototype !is PsiComment) + assert(prototype !is PsiWhiteSpace) + assert(topElement.isAncestor(prototype)) + prefixElements.collectPrefixElements(prototype, inheritBlankLinesBefore) + postfixElements.collectPostfixElements(prototype) + } + + commentsAndSpacesUsed.addAll(prefixElements) + commentsAndSpacesUsed.addAll(postfixElements) + + for (i in prefixElements.indices) { + val e = prefixElements[i] + if (i == 0 && e is PsiWhiteSpace) { + if (e.newLinesCount() > 1) { // insert at maximum one blank line + append("\n") + } + } + else { + append(e.getText()!!, e.isEndOfLineComment()) + } + } + + element.generateCode(this) + + postfixElements.forEach { append(it.getText()!!, it.isEndOfLineComment()) } + + return this + } + + private fun MutableList.collectPrefixElements(element: PsiElement, allowBlankLinesBefore: Boolean) { + val atStart = ArrayList(2).collectCommentsAndSpacesAtStart(element) + + val before = ArrayList(2).collectCommentsAndSpacesBefore(element) + if (!allowBlankLinesBefore && before.lastOrNull() is PsiWhiteSpace) { + before.remove(before.size - 1) + } + + addAll(before.reverse()) + addAll(atStart) + } + + private fun MutableList.collectPostfixElements(element: PsiElement) { + val atEnd = ArrayList(2).collectCommentsAndSpacesAtEnd(element) + + val after = ArrayList(2).collectCommentsAndSpacesAfter(element) + if (after.isNotEmpty()) { + val last = after.last() + if (last is PsiWhiteSpace) { + after.remove(after.size - 1) + } + } + + addAll(atEnd.reverse()) + addAll(after) + } + + private fun MutableList.collectCommentsAndSpacesBefore(element: PsiElement): MutableList { + if (element == topElement) return this + + val prev = element.getPrevSibling() + if (prev != null) { + if (prev.isCommentOrSpace()) { + if (prev !in commentsAndSpacesUsed) { + add(prev) + collectCommentsAndSpacesBefore(prev) + } + } + else if (prev.isEmptyElement()){ + collectCommentsAndSpacesBefore(prev) + } + } + else { + collectCommentsAndSpacesBefore(element.getParent()!!) + } + return this + } + + private fun MutableList.collectCommentsAndSpacesAfter(element: PsiElement): MutableList { + if (element == topElement) return this + + val next = element.getNextSibling() + if (next != null) { + if (next.isCommentOrSpace()) { + if (next is PsiWhiteSpace && next.hasNewLines()) return this // do not attach anything on next line after element + if (next !in commentsAndSpacesUsed) { + add(next) + collectCommentsAndSpacesAfter(next) + } + } + else if (next.isEmptyElement()){ + collectCommentsAndSpacesAfter(next) + } + } + else { + collectCommentsAndSpacesAfter(element.getParent()!!) + } + return this + } + + private fun MutableList.collectCommentsAndSpacesAtStart(element: PsiElement): MutableList { + var child = element.getFirstChild() + while(child != null) { + if (child!!.isCommentOrSpace()) { + if (child !in commentsAndSpacesUsed) add(child!!) else break + } + else if (!child!!.isEmptyElement()) { + collectCommentsAndSpacesAtStart(child!!) + break + } + child = child!!.getNextSibling() + } + return this + } + + private fun MutableList.collectCommentsAndSpacesAtEnd(element: PsiElement): MutableList { + var child = element.getLastChild() + while(child != null) { + if (child!!.isCommentOrSpace()) { + if (child !in commentsAndSpacesUsed) add(child!!) else break + } + else if (!child!!.isEmptyElement()) { + collectCommentsAndSpacesAtEnd(child!!) + break + } + child = child!!.getPrevSibling() + } + return this + } + + private fun PsiElement.isCommentOrSpace() = this is PsiComment || this is PsiWhiteSpace + + private fun PsiElement.isEndOfLineComment() = this is PsiComment && getTokenType() == JavaTokenType.END_OF_LINE_COMMENT + + private fun PsiElement.isEmptyElement() = getFirstChild() == null && getTextLength() == 0 + + private fun PsiWhiteSpace.newLinesCount() = getText()!!.count { it == '\n' } //TODO: this is not correct!! + + private fun PsiWhiteSpace.hasNewLines() = getText()!!.any { it == '\n' || it == '\r' } +} + diff --git a/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt b/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt deleted file mode 100644 index 7d306d1d5a3..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2010-2014 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.j2k - -import com.intellij.psi.* -import java.util.HashSet -import org.jetbrains.jet.lang.psi.psiUtil.isAncestor -import java.util.ArrayList -import org.jetbrains.jet.j2k.ast.PrototypeInfo - -class CommentsAndSpaces(private val topElement: PsiElement?) { - private val commentsAndSpacesUsed = HashSet() - - public fun wrapElement(elementToKotlin: () -> String, prototypes: List): String { - if (prototypes.isEmpty() || topElement == null) return elementToKotlin() - - val prefix = StringBuilder() - val postfix = StringBuilder() - for ((element, inheritBlankLinesBefore) in prototypes) { - assert(element !is PsiComment) - assert(element !is PsiWhiteSpace) - assert(topElement.isAncestor(element)) - prefix.collectPrefix(element, inheritBlankLinesBefore) - postfix.collectPostfix(element) - } - - return prefix.toString() + elementToKotlin() + postfix.toString() - } - - private fun StringBuilder.collectPrefix(element: PsiElement, allowBlankLinesBefore: Boolean) { - val atStart = ArrayList(2).addCommentsAndSpacesAtStart(element) - - val before = ArrayList(2).addCommentsAndSpacesBefore(element) - if (before.isNotEmpty()) { - val last = before.last() - if (last is PsiWhiteSpace) { - if (allowBlankLinesBefore) { - val blankLines = last.newLinesCount() - 1 - if (blankLines > 0) { - append("\n") // insert at maximum one blank line - commentsAndSpacesUsed.add(last) - } - } - before.remove(before.size - 1) - } - } - - if (before.isEmpty() && atStart.isEmpty()) return - - for (e in before.reverse() + atStart) { - append(e.getText()) - commentsAndSpacesUsed.add(e) - } - } - - private fun StringBuilder.collectPostfix(element: PsiElement) { - val atEnd = ArrayList(2).addCommentsAndSpacesAtEnd(element) - - val after = ArrayList(2).addCommentsAndSpacesAfter(element) - if (after.isNotEmpty()) { - val last = after.last() - if (last is PsiWhiteSpace) { - after.remove(after.size - 1) - } - } - - if (after.isEmpty() && atEnd.isEmpty()) return - - for (e in atEnd.reverse() + after) { - append(e.getText()) - commentsAndSpacesUsed.add(e) - } - } - - private fun MutableList.addCommentsAndSpacesBefore(element: PsiElement): MutableList { - if (element == topElement) return this - - val prev = element.getPrevSibling() - if (prev != null) { - if (prev.isCommentOrSpace()) { - if (prev !in commentsAndSpacesUsed) { - add(prev) - addCommentsAndSpacesBefore(prev) - } - } - else if (prev.isEmptyElement()){ - addCommentsAndSpacesBefore(prev) - } - } - else { - addCommentsAndSpacesBefore(element.getParent()!!) - } - return this - } - - private fun MutableList.addCommentsAndSpacesAfter(element: PsiElement): MutableList { - if (element == topElement) return this - - val next = element.getNextSibling() - if (next != null) { - if (next.isCommentOrSpace()) { - if (next is PsiWhiteSpace && next.hasNewLines()) return this // do not attach anything on next line after element - if (next !in commentsAndSpacesUsed) { - add(next) - addCommentsAndSpacesAfter(next) - } - } - else if (next.isEmptyElement()){ - addCommentsAndSpacesAfter(next) - } - } - else { - addCommentsAndSpacesAfter(element.getParent()!!) - } - return this - } - - private fun MutableList.addCommentsAndSpacesAtStart(element: PsiElement): MutableList { - var child = element.getFirstChild() - while(child != null) { - if (child!!.isCommentOrSpace()) { - if (child !in commentsAndSpacesUsed) add(child!!) else break - } - else if (!child!!.isEmptyElement()) { - addCommentsAndSpacesAtStart(child!!) - break - } - child = child!!.getNextSibling() - } - return this - } - - private fun MutableList.addCommentsAndSpacesAtEnd(element: PsiElement): MutableList { - var child = element.getLastChild() - while(child != null) { - if (child!!.isCommentOrSpace()) { - if (child !in commentsAndSpacesUsed) add(child!!) else break - } - else if (!child!!.isEmptyElement()) { - addCommentsAndSpacesAtEnd(child!!) - break - } - child = child!!.getPrevSibling() - } - return this - } - - private fun PsiElement.isCommentOrSpace() = this is PsiComment || this is PsiWhiteSpace - - private fun PsiElement.isEmptyElement() = getFirstChild() == null && getTextLength() == 0 - - private fun PsiWhiteSpace.newLinesCount() = getText()!!.count { it == '\n' } //TODO: this is not correct!! - - private fun PsiWhiteSpace.hasNewLines() = getText()!!.any { it == '\n' || it == '\r' } - - class object { - val None: CommentsAndSpaces = CommentsAndSpaces(null) - } -} - diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index c23b8512880..e36c812a901 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -59,8 +59,12 @@ public class Converter private(val project: Project, val settings: ConverterSett fun withStatementVisitor(factory: (Converter) -> StatementVisitor): Converter = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, state.expressionVisitorFactory, factory)) - public fun elementToKotlin(element: PsiElement): String - = convertTopElement(element)?.toKotlin(CommentsAndSpaces(element)) ?: "" + public fun elementToKotlin(element: PsiElement): String { + val converted = convertTopElement(element) ?: return "" + val builder = CodeBuilder(element) + builder.append(converted) + return builder.result + } private fun convertTopElement(element: PsiElement?): Element? = when(element) { is PsiJavaFile -> convertFile(element) @@ -519,7 +523,7 @@ public class Converter private(val project: Project, val settings: ConverterSett fun convertParameter(parameter: PsiParameter, nullability: Nullability = Nullability.Default, varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None, - modifiers: Collection = listOf()): Parameter { + modifiers: List = listOf()): Parameter { var `type` = typeConverter.convertVariableType(parameter) when (nullability) { Nullability.NotNull -> `type` = `type`.toNotNullType() diff --git a/j2k/src/org/jetbrains/jet/j2k/Utils.kt b/j2k/src/org/jetbrains/jet/j2k/Utils.kt index 90dfa838385..13b83b6e1ab 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Utils.kt @@ -64,7 +64,7 @@ fun getDefaultInitializer(field: Field): Expression { } if (t is PrimitiveType) { - when(t.`type`.name) { + when(t.name.name) { "Boolean" -> return LiteralExpression("false") "Char" -> return LiteralExpression("' '") "Double" -> return MethodCallExpression.buildNotNull(LiteralExpression("0"), OperatorConventions.DOUBLE.toString()) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index a96ed874910..57b51cc5775 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -16,31 +16,46 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean) : Element() { - private fun surroundWithBrackets(text: String) = if (brackets) "[$text]" else text + private fun CodeBuilder.surroundWithBrackets(action: () -> Unit) { + if (brackets) append("[") + action() + if (brackets) append("]") + } - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + override fun generateCode(builder: CodeBuilder) { if (arguments.isEmpty()) { - return surroundWithBrackets(name.toKotlin(commentsAndSpaces)) + builder.surroundWithBrackets { builder.append(name) } + return } - val argsText = arguments.map { - if (it.first != null) - it.first!!.toKotlin(commentsAndSpaces) + " = " + it.second.toKotlin(commentsAndSpaces) - else - it.second.toKotlin(commentsAndSpaces) - }.makeString(", ") - return surroundWithBrackets(name.toKotlin(commentsAndSpaces) + "(" + argsText + ")") + builder.surroundWithBrackets { + builder.append(name) + .append("(") + .append(arguments.map { + { + if (it.first != null) { + builder append it.first!! append " = " append it.second + } + else { + builder append it.second + } + } + }, ", ") + .append(")") + } } } class Annotations(val annotations: List, val newLines: Boolean) : Element() { private val br = if (newLines) "\n" else " " - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - return if (annotations.isNotEmpty()) annotations.map { it.toKotlin(commentsAndSpaces) }.makeString(br) + br else "" + override fun generateCode(builder: CodeBuilder) { + if (annotations.isNotEmpty()) { + builder.append(annotations, br, "", br) + } } fun plus(other: Annotations) = Annotations(annotations + other.annotations, newLines || other.newLines) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index 8ea24070061..738c22cc822 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -16,9 +16,11 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) : Class(Identifier.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = body.toKotlin(null, commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + body.append(builder, null) + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt index 30519ce89bc..c9f5f003f75 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt @@ -16,41 +16,51 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder +import org.jetbrains.jet.j2k.append class ArrayWithoutInitializationExpression(val `type`: ArrayType, val expressions: List) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - fun getConstructorName(`type`: ArrayType, hasInit: Boolean): String { - return when (`type`.elementType) { - is PrimitiveType -> - `type`.toNotNullType().toKotlin(commentsAndSpaces) - is ArrayType -> - if (hasInit) - `type`.toNotNullType().toKotlin(commentsAndSpaces) - else - "arrayOfNulls<" + `type`.elementType.toKotlin(commentsAndSpaces) + ">" - else -> - "arrayOfNulls<" + `type`.elementType.toKotlin(commentsAndSpaces) + ">" + override fun generateCode(builder: CodeBuilder) { + fun appendConstructorName(`type`: ArrayType, hasInit: Boolean): CodeBuilder = when (`type`.elementType) { + is PrimitiveType -> builder.append(`type`.toNotNullType()) + + is ArrayType -> + if (hasInit) { + builder.append(`type`.toNotNullType()) + } + else { + builder.append("arrayOfNulls<").append(`type`.elementType).append(">") + } + + else -> builder.append("arrayOfNulls<").append(`type`.elementType).append(">") + } + + fun oneDim(`type`: ArrayType, size: Expression, init: (() -> Unit)? = null): CodeBuilder { + appendConstructorName(`type`, init != null).append("(").append(size) + if (init != null) { + builder.append(", ") + init() } + return builder.append(")") } - fun oneDim(`type`: ArrayType, size: Expression, init: String = ""): String { - return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin(commentsAndSpaces) + init.withPrefix(", ") + ")" - } - - fun constructInnerType(hostType: ArrayType, expressions: List): String { + fun constructInnerType(hostType: ArrayType, expressions: List): CodeBuilder { if (expressions.size() == 1) { return oneDim(hostType, expressions[0]) } val innerType = hostType.elementType if (expressions.size() > 1 && innerType is ArrayType) { - return oneDim(hostType, expressions[0], "{" + constructInnerType(innerType, expressions.subList(1, expressions.size())) + "}") + return oneDim(hostType, expressions[0], { + builder.append("{") + constructInnerType(innerType, expressions.subList(1, expressions.size())) + builder.append("}") + }) } - return getConstructorName(hostType, expressions.size() != 0) + return appendConstructorName(hostType, expressions.isNotEmpty()) } - return constructInnerType(`type`, expressions) + constructInnerType(`type`, expressions) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt index 1a85bf35949..15b417ffe06 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt @@ -16,21 +16,19 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class Block(val statements: List, val lBrace: LBrace, val rBrace: RBrace, val notEmpty: Boolean = false) : Statement() { override val isEmpty: Boolean get() = !notEmpty && statements.all { it.isEmpty } - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + override fun generateCode(builder: CodeBuilder) { if (statements.all { it.isEmpty }) { - return if (isEmpty) "" else lBrace.toKotlin(commentsAndSpaces) + rBrace.toKotlin(commentsAndSpaces) + if (!isEmpty) builder.append(lBrace).append(rBrace) + return } - return lBrace.toKotlin(commentsAndSpaces) + - "\n" + - statements.toKotlin(commentsAndSpaces, "\n") + - "\n" + - rBrace.toKotlin(commentsAndSpaces) + + builder.append(lBrace).append(statements, "\n", "\n", "\n").append(rBrace) } class object { @@ -40,9 +38,13 @@ class Block(val statements: List, val lBrace: LBrace, val rBrace: RBr // we use LBrace and RBrace elements to better handle comments around them class LBrace() : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "{" + override fun generateCode(builder: CodeBuilder) { + builder.append("{") + } } class RBrace() : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "}" + override fun generateCode(builder: CodeBuilder) { + builder.append("}") + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index 7ca280e905a..2b04dfbe1fd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* open class Class( val name: Identifier, @@ -30,41 +30,38 @@ open class Class( val body: ClassBody ) : Member(annotations, modifiers) { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = - annotations.toKotlin(commentsAndSpaces) + - modifiersToKotlin() + - keyword + " " + name.toKotlin(commentsAndSpaces) + - typeParameterList.toKotlin(commentsAndSpaces) + - primaryConstructorSignatureToKotlin(commentsAndSpaces) + - implementTypesToKotlin(commentsAndSpaces) + - typeParameterList.whereToKotlin(commentsAndSpaces).withPrefix(" ") + - body.toKotlin(this, commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(annotations) + appendModifiers(builder).append(keyword).append(" ").append(name).append(typeParameterList) + appendPrimaryConstructorSignature(builder) + appendBaseTypes(builder) + typeParameterList.appendWhere(builder) + body.append(builder, this) + } protected open val keyword: String get() = "class" - protected open fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String - = body.primaryConstructor?.signatureToKotlin(commentsAndSpaces) ?: "()" + protected open fun appendPrimaryConstructorSignature(builder: CodeBuilder) { + body.primaryConstructor?.appendSignature(builder) ?: builder.append("()") + } - private fun baseClassSignatureWithParams(commentsAndSpaces: CommentsAndSpaces): List { + protected fun appendBaseTypes(builder: CodeBuilder) { + builder.append(baseClassSignatureWithParams(builder) + implementsTypes.map { { builder.append(it) } }, ", ", ":") + } + + private fun baseClassSignatureWithParams(builder: CodeBuilder): List<() -> CodeBuilder> { if (keyword.equals("class") && extendsTypes.size() == 1) { - val baseParams = baseClassParams.toKotlin(commentsAndSpaces, ", ") - return arrayListOf(extendsTypes[0].toKotlin(commentsAndSpaces) + "(" + baseParams + ")") + return listOf({ + builder append extendsTypes[0] append "(" + builder.append(baseClassParams, ", ") + builder append ")" + }) } - return extendsTypes.map { it.toKotlin(commentsAndSpaces) } + return extendsTypes.map { { builder.append(it) } } } - protected fun implementTypesToKotlin(commentsAndSpaces: CommentsAndSpaces): String { - val allTypes = ArrayList() - allTypes.addAll(baseClassSignatureWithParams(commentsAndSpaces)) - allTypes.addAll(implementsTypes.map { it.toKotlin(commentsAndSpaces) }) - return if (allTypes.size() == 0) - "" - else - " : " + allTypes.makeString(", ") - } - - protected open fun modifiersToKotlin(): String { + protected open fun appendModifiers(builder: CodeBuilder): CodeBuilder { val modifierList = ArrayList() modifiers.accessModifier()?.let { modifierList.add(it) } @@ -80,6 +77,6 @@ open class Class( modifierList.add(Modifier.INNER) } - return modifierList.toKotlin() + return builder.append(modifierList) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt index 05b5bdfe2db..33319fe2640 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* abstract class Member(val annotations: Annotations, val modifiers: Set) : Element() @@ -28,37 +28,33 @@ class ClassBody ( val lBrace: LBrace, val rBrace: RBrace) { - fun toKotlin(containingClass: Class?, commentsAndSpaces: CommentsAndSpaces): String { - val builder = StringBuilder() - builder.append(normalMembers.toKotlin(commentsAndSpaces, "\n")) + fun append(builder: CodeBuilder, containingClass: Class?) { + if (normalMembers.isEmpty() && classObjectMembers.isEmpty() && secondaryConstructors.isEmpty() && (primaryConstructor?.block?.isEmpty ?: true)) return - val primaryConstructor = primaryConstructorBodyToKotlin(commentsAndSpaces) - if (primaryConstructor.isNotEmpty() && builder.length() > 0) { - builder.append("\n\n") // blank line before constructor body - } - builder.append(primaryConstructor) + builder append " " append lBrace append "\n" - val classObject = classObjectToKotlin(containingClass, commentsAndSpaces) - if (classObject.isNotEmpty() && builder.length() > 0) { - builder.append("\n\n") // blank line before class object - } - builder.append(classObject) + builder.append(normalMembers, "\n") + var notEmpty = normalMembers.isNotEmpty() - return if (builder.length() > 0) - " " + lBrace.toKotlin(commentsAndSpaces) + "\n" + builder + "\n" + rBrace.toKotlin(commentsAndSpaces) - else - "" + notEmpty = appendPrimaryConstructorBody(builder, notEmpty) || notEmpty + + appendClassObject(builder, containingClass, notEmpty) + + builder append "\n" append rBrace } - private fun primaryConstructorBodyToKotlin(commentsAndSpaces: CommentsAndSpaces): String { + private fun appendPrimaryConstructorBody(builder: CodeBuilder, blankLineBefore: Boolean): Boolean { val constructor = primaryConstructor - if (constructor == null || constructor.block?.isEmpty ?: true) return "" - return constructor.bodyToKotlin(commentsAndSpaces) + if (constructor == null || constructor.block?.isEmpty ?: true) return false + if (blankLineBefore) builder.append("\n\n") + constructor.appendBody(builder) + return true } - private fun classObjectToKotlin(containingClass: Class?, commentsAndSpaces: CommentsAndSpaces): String { - if (secondaryConstructors.isEmpty() && classObjectMembers.isEmpty()) return "" + private fun appendClassObject(builder: CodeBuilder, containingClass: Class?, blankLineBefore: Boolean) { + if (secondaryConstructors.isEmpty() && classObjectMembers.isEmpty()) return + if (blankLineBefore) builder.append("\n\n") val factoryFunctions = secondaryConstructors.map { it.toFactoryFunction(containingClass) } - return "class object {\n" + (factoryFunctions + classObjectMembers).toKotlin(commentsAndSpaces, "\n") + "\n}" + builder.append(factoryFunctions + classObjectMembers, "\n", "class object {\n", "\n}") } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 2a0964dd8ca..4cb3dc0c8bf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -16,10 +16,9 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.Converter import java.util.HashSet import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* abstract class Constructor( converter: Converter, @@ -36,13 +35,13 @@ class PrimaryConstructor(converter: Converter, block: Block) : Constructor(converter, annotations, modifiers, parameterList, block) { - public fun signatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String { + public fun appendSignature(builder: CodeBuilder): CodeBuilder { val accessModifier = modifiers.accessModifier() val modifiersString = if (accessModifier != null && accessModifier != Modifier.PUBLIC) " " + accessModifier.toKotlin() else "" - return modifiersString + "(" + parameterList.toKotlin(commentsAndSpaces) + ")" + return builder.append(modifiersString).append("(").append(parameterList).append(")") } - public fun bodyToKotlin(commentsAndSpaces: CommentsAndSpaces): String = block!!.toKotlin(commentsAndSpaces) + public fun appendBody(builder: CodeBuilder): CodeBuilder = builder.append(block!!) } class SecondaryConstructor(converter: Converter, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt index dbd7c03f1fe..106e841a940 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt @@ -16,8 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder class DummyStringExpression(val string: String) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = string + override fun generateCode(builder: CodeBuilder) { + builder.append(string) + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 2a61fc6a7e6..3fb80b56a23 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* import com.intellij.psi.PsiElement fun TElement.assignPrototype(prototype: PsiElement?): TElement { @@ -36,6 +36,12 @@ fun TElement.assignPrototypesFrom(element: Element): TElemen data class PrototypeInfo(val element: PsiElement, val inheritBlankLinesBefore: Boolean) +fun Element.canonicalCode(): String { + val builder = CodeBuilder(null) + builder.append(this) + return builder.result +} + abstract class Element { public var prototypes: List = listOf() private set @@ -44,19 +50,13 @@ abstract class Element { this.prototypes = prototypes } - public fun toKotlin(commentsAndSpaces: CommentsAndSpaces): String { - return if (isEmpty) // do not insert comment and spaces for empty elements to avoid multiple blank lines - "" - else - commentsAndSpaces.wrapElement({ toKotlinImpl(commentsAndSpaces) }, prototypes) - } - - protected abstract fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String + /** This method should not be used anywhere except for CodeBuilder! Use CodeBuilder.append instead. */ + public abstract fun generateCode(builder: CodeBuilder) public open val isEmpty: Boolean get() = false object Empty : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" + override fun generateCode(builder: CodeBuilder) { } override val isEmpty: Boolean get() = true } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index baa37ee79a7..6c5f33edd27 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class Enum( name: Identifier, @@ -30,16 +30,16 @@ class Enum( ) : Class(name, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { - override fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String - = body.primaryConstructor?.signatureToKotlin(commentsAndSpaces) ?: "" + override fun appendPrimaryConstructorSignature(builder: CodeBuilder) { + body.primaryConstructor?.appendSignature(builder) + } - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - return annotations.toKotlin(commentsAndSpaces) + - modifiersToKotlin() + - "enum class " + name.toKotlin(commentsAndSpaces) + - primaryConstructorSignatureToKotlin(commentsAndSpaces) + - typeParameterList.toKotlin(commentsAndSpaces) + - implementTypesToKotlin(commentsAndSpaces) + - body.toKotlin(this, commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append annotations + appendModifiers(builder) append "enum class " append name + appendPrimaryConstructorSignature(builder) + builder append typeParameterList + appendBaseTypes(builder) + body.append(builder, this) } } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index 0c70faebecf..296b7c9282a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class EnumConstant( identifier: Identifier, @@ -26,12 +26,13 @@ class EnumConstant( params: Element ) : Field(identifier, annotations, modifiers, `type`.toNotNullType(), params, true, false) { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - if (initializer.toKotlin(commentsAndSpaces).isEmpty()) { - return annotations.toKotlin(commentsAndSpaces) + identifier.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + if (initializer.isEmpty) { + builder append annotations append identifier + return } - return annotations.toKotlin(commentsAndSpaces) + identifier.toKotlin(commentsAndSpaces) + " : " + `type`.toKotlin(commentsAndSpaces) + "(" + initializer.toKotlin(commentsAndSpaces) + ")" + builder append annotations append identifier append " : " append `type` append "(" append initializer append ")" } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt index b8f65aa4fee..e9fa4713ae3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt @@ -16,14 +16,14 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder abstract class Expression() : Statement() { open val isNullable: Boolean get() = false object Empty : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" + override fun generateCode(builder: CodeBuilder) {} override val isEmpty: Boolean get() = true } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt index 6c1a9ba657a..eaee0fe4c92 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt @@ -16,10 +16,12 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class ExpressionList(val expressions: List) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = expressions.map { it.toKotlin(commentsAndSpaces) }.makeString(", ") + override fun generateCode(builder: CodeBuilder) { + builder.append(expressions, ", ") + } override val isEmpty: Boolean get() = expressions.isEmpty() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 3baccc78413..efd2a66692d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -17,115 +17,144 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.lang.types.expressions.OperatorConventions -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class ArrayAccessExpression(val expression: Expression, val index: Expression, val lvalue: Boolean) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + - (if (!lvalue && expression.isNullable) "!!" else "") + - "[" + index.toKotlin(commentsAndSpaces) + "]" + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, expression) + if (!lvalue && expression.isNullable) builder.append("!!") + builder append "[" append index append "]" + } } class AssignmentExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(left, commentsAndSpaces) + " " + op + " " + operandToKotlin(right, commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, left).append(op).appendOperand(this, right) + } } class BangBangExpression(val expr: Expression) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expr, commentsAndSpaces) + "!!" + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, expr).append("!!") + } } class BinaryExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(left, commentsAndSpaces, false) + " " + op + " " + operandToKotlin(right, commentsAndSpaces, true) + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, left, false).append(" ").append(op).append(" ").appendOperand(this, right, true) + } } class IsOperator(val expression: Expression, val typeElement: TypeElement) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + " is " + typeElement.`type`.toNotNullType().toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, expression).append(" is ").append(typeElement.`type`.toNotNullType()) + } } class TypeCastExpression(val `type`: Type, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + " as " + `type`.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, expression).append(" as ").append(`type`) + } } class LiteralExpression(val literalText: String) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = literalText + override fun generateCode(builder: CodeBuilder) { + builder.append(literalText) + } } class ParenthesizedExpression(val expression: Expression) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "(" + expression.toKotlin(commentsAndSpaces) + ")" + override fun generateCode(builder: CodeBuilder) { + builder append "(" append expression append ")" + } } class PrefixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = op + operandToKotlin(expression, commentsAndSpaces) + override fun generateCode(builder: CodeBuilder){ + builder.append(op).appendOperand(this, expression) + } override val isNullable: Boolean get() = expression.isNullable } class PostfixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + op + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, expression) append op + } } class ThisExpression(val identifier: Identifier) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "this" + identifier.withPrefix("@", commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append("this").appendWithPrefix(identifier, "@") + } } class SuperExpression(val identifier: Identifier) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "super" + identifier.withPrefix("@", commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append("super").appendWithPrefix(identifier, "@") + } } class QualifiedExpression(val qualifier: Expression, val identifier: Expression) : Expression() { override val isNullable: Boolean get() = identifier.isNullable - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + override fun generateCode(builder: CodeBuilder) { if (!qualifier.isEmpty) { - return operandToKotlin(qualifier, commentsAndSpaces) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin(commentsAndSpaces) + builder.appendOperand(this, qualifier).append(if (qualifier.isNullable) "!!." else ".") } - return identifier.toKotlin(commentsAndSpaces) + builder.append(identifier) } } class PolyadicExpression(val expressions: List, val token: String) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val expressionsWithConversions = expressions.map { it.toKotlin(commentsAndSpaces) } - return expressionsWithConversions.makeString(" " + token + " ") + override fun generateCode(builder: CodeBuilder) { + builder.append(expressions, " " + token + " ") } } class LambdaExpression(val arguments: String?, val block: Block) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val statementsText = block.statements.toKotlin(commentsAndSpaces, "\n").trim() - val innerBody = if (arguments != null) { - val br = if (statementsText.indexOf('\n') < 0 && statementsText.indexOf('\r') < 0) " " else "\n" - "$arguments ->$br$statementsText" + override fun generateCode(builder: CodeBuilder) { + builder append block.lBrace append " " + + if (arguments != null) { + builder.append(arguments) + .append("->") + .append(if (block.statements.size > 1) "\n" else " ") + .append(block.statements, "\n") } else { - statementsText + builder.append(block.statements, "\n") } - return block.lBrace.toKotlin(commentsAndSpaces) + " " + innerBody + " " + block.rBrace.toKotlin(commentsAndSpaces) + + builder append " " append block.rBrace } } class StarExpression(val methodCall: MethodCallExpression) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "*" + methodCall.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "*" append methodCall + } } fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List, needExplicitType: Boolean) : MethodCallExpression { val elementType = arrayType.elementType val createArrayFunction = if (elementType is PrimitiveType) - (elementType.toNotNullType().toKotlin(CommentsAndSpaces.None) + "Array").decapitalize() + (elementType.toNotNullType().canonicalCode() + "Array").decapitalize() else if (needExplicitType) - arrayType.toNotNullType().toKotlin(CommentsAndSpaces.None).decapitalize() + arrayType.toNotNullType().canonicalCode().decapitalize() else "array" val doubleOrFloatTypes = setOf("double", "float", "java.lang.double", "java.lang.float") - val afterReplace = arrayType.toNotNullType().toKotlin(CommentsAndSpaces.None).replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") + val afterReplace = arrayType.toNotNullType().canonicalCode().replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") fun explicitConvertIfNeeded(initializer: Expression): Expression { if (doubleOrFloatTypes.contains(afterReplace)) { if (initializer is LiteralExpression) { - if (!initializer.toKotlin(CommentsAndSpaces.None).contains(".")) { + if (!initializer.canonicalCode().contains(".")) { return LiteralExpression(initializer.literalText + ".0") } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index 20f27b093fa..495153bf717 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -29,20 +29,24 @@ open class Field( private val hasWriteAccesses: Boolean ) : Member(annotations, modifiers) { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val declaration = annotations.toKotlin(commentsAndSpaces) + - modifiersToKotlin() + - (if (isVal) "val " else "var ") + - identifier.toKotlin(commentsAndSpaces) + - " : " + - `type`.toKotlin(commentsAndSpaces) - return if (initializer.isEmpty) - declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin(commentsAndSpaces)) - else - declaration + " = " + initializer.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(annotations) + .appendModifiers() + .append(if (isVal) "val " else "var ") + .append(identifier) + .append(" : ") + .append(`type`) + + var initializerToUse = initializer + if (initializerToUse.isEmpty && !(isVal && hasWriteAccesses)) { + initializerToUse = getDefaultInitializer(this) + } + if (!initializerToUse.isEmpty) { + builder append "=" append initializerToUse + } } - private fun modifiersToKotlin(): String { + private fun CodeBuilder.appendModifiers(): CodeBuilder { val modifierList = ArrayList() if (modifiers.contains(Modifier.ABSTRACT)) { modifierList.add(Modifier.ABSTRACT) @@ -50,6 +54,6 @@ open class Field( modifiers.accessModifier()?.let { modifierList.add(it) } - return modifierList.toKotlin() + return append(modifierList) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt index e4173edd52c..01ec9127bab 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt @@ -16,10 +16,13 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder +import org.jetbrains.jet.j2k.append class PackageStatement(val packageName: String) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "package " + packageName + override fun generateCode(builder: CodeBuilder) { + builder append "package " append packageName + } } class File( @@ -27,7 +30,7 @@ class File( val mainFunction: String ) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - return elements.toKotlin(commentsAndSpaces, "\n") + mainFunction + override fun generateCode(builder: CodeBuilder) { + builder.append(elements, "\n").append(mainFunction) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt index 3298a2ffd84..e12535a2554 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt @@ -17,8 +17,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import org.jetbrains.jet.j2k.Converter -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* open class Function( val converter: Converter, @@ -32,7 +31,7 @@ open class Function( val isInTrait: Boolean ) : Member(annotations, modifiers) { - private fun modifiersToKotlin(): String { + private fun CodeBuilder.appendModifiers(): CodeBuilder { val resultingModifiers = ArrayList() val isOverride = modifiers.contains(Modifier.OVERRIDE) if (isOverride) { @@ -52,16 +51,27 @@ open class Function( resultingModifiers.add(Modifier.OPEN) } - return resultingModifiers.toKotlin() + return append(resultingModifiers) } - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - return annotations.toKotlin(commentsAndSpaces) + - modifiersToKotlin() + - "fun ${typeParameterList.toKotlin(commentsAndSpaces).withSuffix(" ")}${name.toKotlin(commentsAndSpaces)}" + - "(${parameterList.toKotlin(commentsAndSpaces)})" + - (if (!`type`.isUnit()) " : " + `type`.toKotlin(commentsAndSpaces) + " " else " ") + - typeParameterList.whereToKotlin(commentsAndSpaces) + - block?.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(annotations) + .appendModifiers() + .append(" fun ") + .appendWithSuffix(typeParameterList, " ") + .append(name) + .append("(") + .append(parameterList) + .append(")") + + if (!`type`.isUnit()) { + builder append ":" append `type` + } + + typeParameterList.appendWhere(builder) + + if (block != null) { + builder append " " append block!! + } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt index 4361838b0b6..6066082eda3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder import com.intellij.psi.PsiNameIdentifierOwner fun PsiNameIdentifierOwner.declarationIdentifier(): Identifier { @@ -41,7 +41,9 @@ class Identifier( return name } - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = toKotlin() + override fun generateCode(builder: CodeBuilder) { + builder.append(toKotlin()) + } private fun quote(str: String): String = "`" + str + "`" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt index 50007b9a8c7..70d363d442f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt @@ -25,14 +25,18 @@ import com.intellij.psi.PsiJavaCodeReferenceElement import org.jetbrains.jet.asJava.KotlinLightClassForPackage class Import(val name: String) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "import " + name + override fun generateCode(builder: CodeBuilder) { + builder append "import " append name + } } class ImportList(public val imports: List) : Element() { override val isEmpty: Boolean get() = imports.isEmpty() - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = imports.toKotlin(commentsAndSpaces, "\n") + override fun generateCode(builder: CodeBuilder) { + builder.append(imports, "\n") + } } public fun Converter.convertImportList(importList: PsiImportList): ImportList = diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt index 3386c36a33a..b2a6a317ad0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt @@ -16,10 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class Initializer(val block: Block, modifiers: Set) : Member(Annotations.Empty, modifiers) { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - return block.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(block) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index ba225477abc..b80f19f9691 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -17,7 +17,8 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.ConverterSettings -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder +import org.jetbrains.jet.j2k.append class LocalVariable( private val identifier: Identifier, @@ -29,17 +30,17 @@ class LocalVariable( private val settings: ConverterSettings ) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val start = annotations.toKotlin(commentsAndSpaces) + if (isVal) "val" else "var" - return if (initializer.isEmpty) { - "$start ${identifier.toKotlin(commentsAndSpaces)} : ${typeCalculator().toKotlin(commentsAndSpaces)}" + override fun generateCode(builder: CodeBuilder) { + builder.append(annotations).append(if (isVal) "val " else "var ") + if (initializer.isEmpty) { + builder append identifier append ":" append typeCalculator() } else { val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault if (shouldSpecifyType) - "$start ${identifier.toKotlin(commentsAndSpaces)} : ${typeCalculator().toKotlin(commentsAndSpaces)} = ${initializer.toKotlin(commentsAndSpaces)}" + builder append identifier append ":" append typeCalculator() append "=" append initializer else - "$start ${identifier.toKotlin(commentsAndSpaces)} = ${initializer.toKotlin(commentsAndSpaces)}" + builder append identifier append "=" append initializer } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 4cdeb67142f..2ef4af8227a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class MethodCallExpression( val methodExpression: Expression, @@ -26,17 +26,14 @@ class MethodCallExpression( val lambdaArgument: LambdaExpression? = null ) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val builder = StringBuilder() - builder.append(operandToKotlin(methodExpression, commentsAndSpaces)) - builder.append(typeArguments.toKotlin(commentsAndSpaces, ", ", "<", ">")) + override fun generateCode(builder: CodeBuilder) { + builder.appendOperand(this, methodExpression).append(typeArguments, ", ", "<", ">") if (arguments.isNotEmpty() || lambdaArgument == null) { - builder.append("(").append(arguments.map { it.toKotlin(commentsAndSpaces) }.makeString(", ")).append(")") + builder.append("(").append(arguments, ", ").append(")") } if (lambdaArgument != null) { - builder.append(lambdaArgument.toKotlin(commentsAndSpaces)) + builder.append(lambdaArgument) } - return builder.toString() } class object { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt index 9baec7f14fd..985b646e510 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder enum class Modifier(val name: String) { PUBLIC: Modifier("public") @@ -36,7 +36,13 @@ fun Collection.accessModifier(): Modifier? { return firstOrNull { ACCESS_MODIFIERS.contains(it) } } -fun Collection.toKotlin(): String - = if (isNotEmpty()) map { it.toKotlin() }.makeString(" ") + " " else "" +fun CodeBuilder.append(modifiers: List): CodeBuilder { + if (!modifiers.isEmpty()) { + for (modifier in modifiers) { + append(modifier.toKotlin()).append(" ") + } + } + return this +} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt index 0ffc786bfa8..bf4b77386c8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class NewClassExpression( val name: Element, @@ -25,18 +25,23 @@ class NewClassExpression( val anonymousClass: AnonymousClassBody? = null ) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val callOperator = if (qualifier.isNullable) "!!." else "." - val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin(commentsAndSpaces) + callOperator - val appliedArguments = arguments.toKotlin(commentsAndSpaces, ", ") - return if (anonymousClass != null) { - if (anonymousClass.extendsTrait) - "object : " + qualifier + name.toKotlin(commentsAndSpaces) + anonymousClass.toKotlin(commentsAndSpaces) - else - "object : " + qualifier + name.toKotlin(commentsAndSpaces) + "(" + appliedArguments + ")" + anonymousClass.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + if (anonymousClass != null) { + builder.append("object:") } - else{ - qualifier + name.toKotlin(commentsAndSpaces) + "(" + appliedArguments + ")" + + if (!qualifier.isEmpty) { + builder.append(qualifier).append(if (qualifier.isNullable) "!!." else ".") + } + + builder.append(name) + + if (anonymousClass == null || !anonymousClass.extendsTrait) { + builder.append("(").append(arguments, ", ").append(")") + } + + if (anonymousClass != null) { + builder.append(anonymousClass) } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 83d4ad89d9c..103ba544ff8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -16,24 +16,21 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parameter.VarValModifier, val annotations: Annotations, - val modifiers: Collection) : Element() { + val modifiers: List) : Element() { public enum class VarValModifier { None Val Var } - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val builder = StringBuilder() - - builder.append(annotations.toKotlin(commentsAndSpaces)) - builder.append(modifiers.toKotlin()) + override fun generateCode(builder: CodeBuilder) { + builder.append(annotations).append(modifiers) if (`type` is VarArgType) { assert(varVal == VarValModifier.None) @@ -45,7 +42,6 @@ class Parameter(val identifier: Identifier, VarValModifier.Val -> builder.append("val ") } - builder.append(identifier.toKotlin(commentsAndSpaces)).append(": ").append(`type`.toKotlin(commentsAndSpaces)) - return builder.toString() + builder.append(identifier).append(":").append(`type`) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt index 096a58850b0..36d62b48e87 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt @@ -16,9 +16,11 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class ParameterList(val parameters: List) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = parameters.map { it.toKotlin(commentsAndSpaces) }.makeString(", ") + override fun generateCode(builder: CodeBuilder) { + builder.append(parameters, ", ") + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt index b9e5f1f4f5b..9e03f71646f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt @@ -16,8 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class ReferenceElement(val reference: Identifier, val types: List) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = reference.toKotlin(commentsAndSpaces) + types.toKotlin(commentsAndSpaces, ", ", "<", ">") + override fun generateCode(builder: CodeBuilder) { + builder.append(reference).append(types, ", ", "<", ">") + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt index e4bd15dbea4..91956cb8c85 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt @@ -16,12 +16,12 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* abstract class Statement() : Element() { object Empty : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" + override fun generateCode(builder: CodeBuilder) { } override val isEmpty: Boolean get() = true @@ -29,20 +29,27 @@ abstract class Statement() : Element() { } class DeclarationStatement(val elements: List) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String - = elements.filterIsInstance(javaClass()).map { it.toKotlin(commentsAndSpaces) }.makeString("\n") + override fun generateCode(builder: CodeBuilder) { + builder.append(elements, "\n") + } } class ExpressionListStatement(val expressions: List) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = expressions.toKotlin(commentsAndSpaces, "\n") + override fun generateCode(builder: CodeBuilder) { + builder.append(expressions, "\n") + } } class LabelStatement(val name: Identifier, val statement: Element) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "@" + name.toKotlin(commentsAndSpaces) + " " + statement.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "@" append name append " " append statement + } } class ReturnStatement(val expression: Expression) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "return " + expression.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "return " append expression + } } class IfStatement( @@ -53,12 +60,11 @@ class IfStatement( ) : Expression() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val result = "if (" + condition.toKotlin(commentsAndSpaces) + ")$br" + thenStatement.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "if (" append condition append ")" append br append thenStatement if (!elseStatement.isEmpty) { - return "$result${br}else$br${elseStatement.toKotlin(commentsAndSpaces)}" + builder append br append "else" append br append elseStatement } - return result } } @@ -67,13 +73,17 @@ class IfStatement( class WhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "while (" + condition.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "while (" append condition append ")" append br append body + } } class DoWhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "do$br" + body.toKotlin(commentsAndSpaces) + "${br}while (" + condition.toKotlin(commentsAndSpaces) + ")" + override fun generateCode(builder: CodeBuilder) { + builder append "do" append br append body append br append "while (" append condition append ")" + } } class ForeachStatement( @@ -85,7 +95,9 @@ class ForeachStatement( private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "for (" + variable.identifier.toKotlin(commentsAndSpaces) + " in " + expression.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "for (" append variable.identifier append " in " append expression append ")" append br append body + } } class ForeachWithRangeStatement(val identifier: Identifier, @@ -95,64 +107,78 @@ class ForeachWithRangeStatement(val identifier: Identifier, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "for (" + identifier.toKotlin(commentsAndSpaces) + " in " + start.toKotlin(commentsAndSpaces) + ".." + end.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "for (" append identifier append " in " append start append ".." append end append ")" append br append body + } } class BreakStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "break" + label.withPrefix("@", commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append("break").appendWithPrefix(label, "@") + } } class ContinueStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "continue" + label.withPrefix("@", commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append("continue").appendWithPrefix(label, "@") + } } // Exceptions ---------------------------------------------------------------------------------------------- class TryStatement(val block: Block, val catches: List, val finallyBlock: Block) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - val builder = StringBuilder() - .append("try\n") - .append(block.toKotlin(commentsAndSpaces)) - .append("\n") - .append(catches.toKotlin(commentsAndSpaces, "\n")) - .append("\n") + override fun generateCode(builder: CodeBuilder) { + builder.append("try\n").append(block).append("\n").append(catches, "\n").append("\n") if (!finallyBlock.isEmpty) { - builder.append("finally\n").append(finallyBlock.toKotlin(commentsAndSpaces)) + builder append "finally\n" append finallyBlock } - return builder.toString() } } class ThrowStatement(val expression: Expression) : Expression() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "throw " + expression.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "throw " append expression + } } class CatchStatement(val variable: Parameter, val block: Block) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "catch (" + variable.toKotlin(commentsAndSpaces) + ") " + block.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "catch (" append variable append ") " append block + } } // Switch -------------------------------------------------------------------------------------------------- class SwitchContainer(val expression: Expression, val caseContainers: List) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "when (" + expression.toKotlin(commentsAndSpaces) + ") {\n" + caseContainers.toKotlin(commentsAndSpaces, "\n") + "\n}" + override fun generateCode(builder: CodeBuilder) { + builder.append("when (").append(expression).append(") {\n").append(caseContainers, "\n").append("\n}") + } } class CaseContainer(val caseStatement: List, statements: List) : Statement() { private val block = Block(statements.filterNot { it is BreakStatement || it is ContinueStatement }, LBrace(), RBrace(), true) - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = caseStatement.toKotlin(commentsAndSpaces, ", ") + " -> " + block.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(caseStatement, ", ").append(" -> ").append(block) + } } class SwitchLabelStatement(val expression: Expression) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = expression.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(expression) + } } class DefaultSwitchLabelStatement() : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "else" + override fun generateCode(builder: CodeBuilder) { + builder.append("else") + } } // Other ------------------------------------------------------------------------------------------------------ class SynchronizedStatement(val expression: Expression, val block: Block) : Statement() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "synchronized (" + expression.toKotlin(commentsAndSpaces) + ") " + block.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "synchronized (" append expression append ") " append block + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index 462e9dc0477..f174b7f7c8e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.CodeBuilder class Trait(name: Identifier, annotations: Annotations, @@ -32,12 +32,12 @@ class Trait(name: Identifier, override val keyword: String get() = "trait" - override fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces) = "" + override fun appendPrimaryConstructorSignature(builder: CodeBuilder) { } - override fun modifiersToKotlin(): String { + override fun appendModifiers(builder: CodeBuilder): CodeBuilder { val modifierList = ArrayList() modifiers.accessModifier()?.let { modifierList.add(it) } - return modifierList.toKotlin() + return builder.append(modifierList) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt index 4259c1804cb..b33e322a564 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt @@ -16,8 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* class TypeElement(val `type`: Type) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = `type`.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(`type`) + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt index b77cca56b31..049d69702ee 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt @@ -17,45 +17,37 @@ package org.jetbrains.jet.j2k.ast import com.intellij.psi.PsiTypeParameter -import org.jetbrains.jet.j2k.Converter +import org.jetbrains.jet.j2k.* import com.intellij.psi.PsiTypeParameterList import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentsAndSpaces class TypeParameter(val name: Identifier, val extendsTypes: List) : Element() { fun hasWhere(): Boolean = extendsTypes.size() > 1 - fun whereToKotlin(commentsAndSpaces: CommentsAndSpaces): String { + fun whereToKotlin(builder: CodeBuilder) { if (hasWhere()) { - return name.toKotlin(commentsAndSpaces) + " : " + extendsTypes[1].toKotlin(commentsAndSpaces) + builder append name append " : " append extendsTypes[1] } - - return "" } - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - if (extendsTypes.size() > 0) { - return name.toKotlin(commentsAndSpaces) + " : " + extendsTypes[0].toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append name + if (extendsTypes.isNotEmpty()) { + builder append " : " append extendsTypes[0] } - - return name.toKotlin(commentsAndSpaces) } } class TypeParameterList(val parameters: List) : Element() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - return if (parameters.isNotEmpty()) - parameters.map { it.toKotlin(commentsAndSpaces) }.makeString(", ", "<", ">") - else - "" + override fun generateCode(builder: CodeBuilder) { + if (parameters.isNotEmpty()) builder.append(parameters, ", ", "<", ">") } - fun whereToKotlin(commentsAndSpaces: CommentsAndSpaces): String { + fun appendWhere(builder: CodeBuilder): CodeBuilder { if (hasWhere()) { - val wheres = parameters.map { it.whereToKotlin(commentsAndSpaces) } - return "where " + wheres.makeString(", ") + builder.append( parameters.map { { it.whereToKotlin(builder) } }, ", ", " where ", "") } - return "" + return builder } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 4894ee96bbd..6acfa64caf2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -16,8 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.ConverterSettings -import org.jetbrains.jet.j2k.CommentsAndSpaces +import org.jetbrains.jet.j2k.* fun Type.isUnit(): Boolean = this == Type.Unit @@ -59,42 +58,45 @@ abstract class Type() : Element() { } object Empty : NotNullType() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "UNRESOLVED_TYPE" + override fun generateCode(builder: CodeBuilder) { + builder.append("UNRESOLVED_TYPE") + } } object Unit: NotNullType() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "Unit" + override fun generateCode(builder: CodeBuilder) { + builder.append("Unit") + } } - override fun equals(other: Any?): Boolean = other is Type && other.toKotlin(CommentsAndSpaces.None) == this.toKotlin(CommentsAndSpaces.None) + override fun equals(other: Any?): Boolean = other is Type && other.canonicalCode() == this.canonicalCode() - override fun hashCode(): Int = toKotlin(CommentsAndSpaces.None).hashCode() + override fun hashCode(): Int = canonicalCode().hashCode() - override fun toString(): String = toKotlin(CommentsAndSpaces.None) + override fun toString(): String = canonicalCode() } -class ClassType(val `type`: Identifier, val typeArgs: List, nullability: Nullability, settings: ConverterSettings) +class ClassType(val name: Identifier, val typeArgs: List, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { - var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin(commentsAndSpaces) }.makeString(", ", "<", ">") - return `type`.toKotlin(commentsAndSpaces) + params + isNullableStr + override fun generateCode(builder: CodeBuilder) { + builder.append(name).append(typeArgs, ", ", "<", ">").append(isNullableStr) } - - override fun toNotNullType(): Type = ClassType(`type`, typeArgs, Nullability.NotNull, settings) - override fun toNullableType(): Type = ClassType(`type`, typeArgs, Nullability.Nullable, settings) + override fun toNotNullType(): Type = ClassType(name, typeArgs, Nullability.NotNull, settings) + override fun toNullableType(): Type = ClassType(name, typeArgs, Nullability.Nullable, settings) } class ArrayType(val elementType: Type, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + override fun generateCode(builder: CodeBuilder) { if (elementType is PrimitiveType) { - return elementType.toKotlin(commentsAndSpaces) + "Array" + isNullableStr + builder append elementType append "Array" append isNullableStr + } + else { + builder append "Array<" append elementType append ">" append isNullableStr } - - return "Array<" + elementType.toKotlin(commentsAndSpaces) + ">" + isNullableStr } override fun toNotNullType(): Type = ArrayType(elementType, Nullability.NotNull, settings) @@ -102,21 +104,31 @@ class ArrayType(val elementType: Type, nullability: Nullability, settings: Conve } class InProjectionType(val bound: Type) : NotNullType() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "in " + bound.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "in " append bound + } } class OutProjectionType(val bound: Type) : NotNullType() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "out " + bound.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder append "out " append bound + } } class StarProjectionType() : NotNullType() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "*" + override fun generateCode(builder: CodeBuilder) { + builder.append("*") + } } -class PrimitiveType(val `type`: Identifier) : NotNullType() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = `type`.toKotlin(commentsAndSpaces) +class PrimitiveType(val name: Identifier) : NotNullType() { + override fun generateCode(builder: CodeBuilder) { + builder.append(name) + } } class VarArgType(val `type`: Type) : NotNullType() { - override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = `type`.toKotlin(commentsAndSpaces) + override fun generateCode(builder: CodeBuilder) { + builder.append(`type`) + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt index 4f719813a55..f42384e21f6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt @@ -16,23 +16,23 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentsAndSpaces - -fun List.toKotlin(commentsAndSpaces: CommentsAndSpaces, separator: String, prefix: String = "", postfix: String = ""): String { - val texts = map { it.toKotlin(commentsAndSpaces) }.filter { it.isNotEmpty() } - return if (texts.isNotEmpty()) texts.makeString(separator, prefix, postfix) else "" -} +import org.jetbrains.jet.j2k.* fun String.withSuffix(suffix: String): String = if (isEmpty()) "" else this + suffix fun String.withPrefix(prefix: String): String = if (isEmpty()) "" else prefix + this -fun Expression.withPrefix(prefix: String, commentsAndSpaces: CommentsAndSpaces): String = if (isEmpty) "" else prefix + toKotlin(commentsAndSpaces) -fun Expression.operandToKotlin(operand: Expression, commentsAndSpaces: CommentsAndSpaces, parenthesisForSamePrecedence: Boolean = false): String { - val parentPrecedence = precedence() ?: throw IllegalArgumentException("Unknown precendence for $this") - val kotlinCode = operand.toKotlin(commentsAndSpaces) - val operandPrecedence = operand.precedence() ?: return kotlinCode - val needParenthesis = parentPrecedence < operandPrecedence || parentPrecedence == operandPrecedence && parenthesisForSamePrecedence - return if (needParenthesis) "($kotlinCode)" else kotlinCode +fun CodeBuilder.appendWithPrefix(element: Element, prefix: String): CodeBuilder = if (!element.isEmpty) this append prefix append element else this +fun CodeBuilder.appendWithSuffix(element: Element, suffix: String): CodeBuilder = if (!element.isEmpty) this append element append suffix else this + +fun CodeBuilder.appendOperand(expression: Expression, operand: Expression, parenthesisForSamePrecedence: Boolean = false): CodeBuilder { + val parentPrecedence = expression.precedence() ?: throw IllegalArgumentException("Unknown precendence for $this") + val operandPrecedence = operand.precedence() + val needParenthesis = operandPrecedence != null && + (parentPrecedence < operandPrecedence || parentPrecedence == operandPrecedence && parenthesisForSamePrecedence) + if (needParenthesis) append("(") + append(operand) + if (needParenthesis) append(")") + return this } private fun Expression.precedence(): Int? { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index 9ab3db30cec..39f6ef5a425 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -51,7 +51,7 @@ class TypeVisitor(private val converter: TypeConverter, private val classesToImp if (classType.getParameterCount() == 0 && resolvedClassTypeParams.size() > 0) { val starParamList = ArrayList() if (resolvedClassTypeParams.size() == 1) { - if ((resolvedClassTypeParams.single() as ClassType).`type`.name == "Any") { + if ((resolvedClassTypeParams.single() as ClassType).name.name == "Any") { starParamList.add(StarProjectionType()) return ClassType(identifier, starParamList, Nullability.Default, converter.settings) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index 664f8435fb2..859f5c5ea88 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -145,7 +145,7 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { private fun expressionToKotlin(code: String, settings: ConverterSettings, project: Project): String { val result = statementToKotlin("final Object o =" + code + "}", settings, project) - return result.replaceFirst("val o : Any\\? =", "").replaceFirst("val o : Any = ", "").replaceFirst("val o = ", "").trim() + return result.replaceFirst("val o:Any\\?=", "").replaceFirst("val o:Any=", "").replaceFirst("val o=", "").trim() } override fun getProjectJDK(): Sdk? { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index b01a2402ac0..3f394093cb3 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -737,9 +737,19 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/comments"), Pattern.compile("^(.+)\\.java$"), true); } - @TestMetadata("Comments.java") + @TestMetadata("comments.java") public void testComments() throws Exception { - doTest("j2k/tests/testData/ast/comments/Comments.java"); + doTest("j2k/tests/testData/ast/comments/comments.java"); + } + + @TestMetadata("fieldWithEndOfLineComment.java") + public void testFieldWithEndOfLineComment() throws Exception { + doTest("j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.java"); + } + + @TestMetadata("fieldsInitializedFromParams.java") + public void testFieldsInitializedFromParams() throws Exception { + doTest("j2k/tests/testData/ast/comments/fieldsInitializedFromParams.java"); } } diff --git a/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.java b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.java new file mode 100644 index 00000000000..340ae032186 --- /dev/null +++ b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.java @@ -0,0 +1,4 @@ +//file +class A { + private boolean isOpen = true; // ideally should be atomic boolean +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt new file mode 100644 index 00000000000..ec3f0bf94e6 --- /dev/null +++ b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt @@ -0,0 +1,3 @@ +class A() { + private var isOpen: Boolean = true // ideally should be atomic boolean +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/fieldsInitializedFromParams.java b/j2k/tests/testData/ast/comments/fieldsInitializedFromParams.java new file mode 100644 index 00000000000..efcc082ae6f --- /dev/null +++ b/j2k/tests/testData/ast/comments/fieldsInitializedFromParams.java @@ -0,0 +1,17 @@ +//file +class C { + private final int p1; // field p1 + + /** + * Field myP2 + */ + private final int myP2; + + /* Field p3 */ public int p3; + + public C(int p1 /* parameter p1 */, int p2, int p3) { + this.p1 = p1; + myP2 = p2; + this.p3 = p3; + } +} diff --git a/j2k/tests/testData/ast/comments/fieldsInitializedFromParams.kt b/j2k/tests/testData/ast/comments/fieldsInitializedFromParams.kt new file mode 100644 index 00000000000..f8654e83f46 --- /dev/null +++ b/j2k/tests/testData/ast/comments/fieldsInitializedFromParams.kt @@ -0,0 +1,6 @@ +class C(private val p1: Int /* parameter p1 */ // field p1 + , + /** + * Field myP2 + */ + private val myP2: Int, /* Field p3 */ public var p3: Int) From 116c27117f987e730323e2f25469698523e26af9 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 20 Jun 2014 14:30:37 +0400 Subject: [PATCH 080/143] Java to Kotlin converter: better comments preserving, never lose any comment #KT-4489 Fixed --- j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt | 12 ++++++ j2k/src/org/jetbrains/jet/j2k/Converter.kt | 34 ++++++++-------- .../org/jetbrains/jet/j2k/TypeConverter.kt | 5 ++- .../jet/j2k/ast/AnonymousClassBody.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 29 ++++---------- .../org/jetbrains/jet/j2k/ast/ClassBody.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Constructors.kt | 16 ++++---- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 4 +- j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 5 +-- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 16 +------- j2k/src/org/jetbrains/jet/j2k/ast/Function.kt | 31 +++++--------- .../org/jetbrains/jet/j2k/ast/Initializer.kt | 2 +- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt | 40 +++++++++++++++---- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 4 +- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 11 ++--- .../JavaToKotlinConverterTestGenerated.java | 5 +++ .../testData/ast/comments/comments2.java | 20 ++++++++++ j2k/tests/testData/ast/comments/comments2.kt | 26 ++++++++++++ 20 files changed, 157 insertions(+), 111 deletions(-) create mode 100644 j2k/tests/testData/ast/comments/comments2.java create mode 100644 j2k/tests/testData/ast/comments/comments2.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt index b47da7a9bc8..3927e0725ab 100644 --- a/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt +++ b/j2k/src/org/jetbrains/jet/j2k/CodeBuilder.kt @@ -21,6 +21,7 @@ import java.util.HashSet import org.jetbrains.jet.lang.psi.psiUtil.isAncestor import java.util.ArrayList import org.jetbrains.jet.j2k.ast.Element +import org.jetbrains.jet.j2k.ast.Modifiers import kotlin.platform.platformName fun CodeBuilder.append(generators: Collection<() -> T>, separator: String, prefix: String = "", suffix: String = ""): CodeBuilder { @@ -104,6 +105,17 @@ class CodeBuilder(private val topElement: PsiElement?) { element.generateCode(this) + // scan for all comments inside which are not yet used in the text and put them here to not loose any comment from code + for ((prototype, _) in element.prototypes) { + prototype.accept(object : JavaRecursiveElementVisitor(){ + override fun visitComment(comment: PsiComment) { + if (commentsAndSpacesUsed.add(comment)) { + append(comment.getText()!!, comment.isEndOfLineComment()) + } + } + }) + } + postfixElements.forEach { append(it.getText()!!, it.isEndOfLineComment()) } return this diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index e36c812a901..3ba4c87e7f9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -168,7 +168,7 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun convertClass(psiClass: PsiClass): Class { val annotations = convertAnnotations(psiClass) - val modifiers = convertModifiers(psiClass) + var modifiers = convertModifiers(psiClass) val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList()) val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes()) val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes()) @@ -198,11 +198,11 @@ public class Converter private(val project: Project, val settings: ConverterSett } if (settings.openByDefault && !psiClass.hasModifierProperty(PsiModifier.FINAL)) { - modifiers.add(Modifier.OPEN) + modifiers = modifiers.with(Modifier.OPEN) } if (psiClass.getContainingClass() != null && !psiClass.hasModifierProperty(PsiModifier.STATIC)) { - modifiers.add(Modifier.INNER) + modifiers = modifiers.with(Modifier.INNER) } Class(name, annotations, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) @@ -247,7 +247,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val initializer = MethodCallExpression.buildNotNull(null, className.name, finalOrWithEmptyInitializerFields.map { initializers[it]!! }) val localVar = LocalVariable(SecondaryConstructor.tempValIdentifier, Annotations.Empty, - setOf(), + Modifiers.Empty, { ClassType(className, listOf(), Nullability.NotNull, settings) }, initializer, true, @@ -259,10 +259,10 @@ public class Converter private(val project: Project, val settings: ConverterSett //TODO: comments? val parameters = finalOrWithEmptyInitializerFields.map { field -> val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var - Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) + Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { it in ACCESS_MODIFIERS }) } - val primaryConstructor = PrimaryConstructor(this, Annotations.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) + val primaryConstructor = PrimaryConstructor(this, Annotations.Empty, Modifiers(listOf(Modifier.PRIVATE)), ParameterList(parameters), Block.Empty) val updatedMembers = classBody.normalMembers.filter { !finalOrWithEmptyInitializerFields.contains(it) } return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers, classBody.lBrace, classBody.rBrace) } @@ -302,7 +302,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val returnType = typeConverter.convertMethodReturnType(method) val annotations = convertAnnotations(method) + convertThrows(method) - val modifiers = convertModifiers(method) + var modifiers = convertModifiers(method) if (method.isConstructor()) { if (method.isPrimaryConstructor()) { @@ -316,7 +316,7 @@ public class Converter private(val project: Project, val settings: ConverterSett else { val isOverride = isOverride(method) if (isOverride) { - modifiers.add(Modifier.OVERRIDE) + modifiers = modifiers.with(Modifier.OVERRIDE) } val containingClass = method.getContainingClass() @@ -325,7 +325,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val isEffectivelyFinal = method.hasModifierProperty(PsiModifier.FINAL) || containingClass != null && (containingClass.hasModifierProperty(PsiModifier.FINAL) || containingClass.isEnum()) if (!isEffectivelyFinal && !modifiers.contains(Modifier.ABSTRACT) && !modifiers.contains(Modifier.PRIVATE)) { - modifiers.add(Modifier.OPEN) + modifiers = modifiers.with(Modifier.OPEN) } } @@ -342,7 +342,7 @@ public class Converter private(val project: Project, val settings: ConverterSett ClassType(Identifier("Any"), listOf(), Nullability.Nullable, settings), Parameter.VarValModifier.None, params.parameters.single().annotations, - listOf()) + Modifiers.Empty) params = ParameterList(listOf(correctedParameter)) } } @@ -390,7 +390,7 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun convertPrimaryConstructor(constructor: PsiMethod, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, membersToRemove: MutableSet): PrimaryConstructor { val params = constructor.getParameterList().getParameters() val parameterToField = HashMap>() @@ -439,7 +439,7 @@ public class Converter private(val project: Project, val settings: ConverterSett `type`, if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var, convertAnnotations(parameter) + convertAnnotations(field), - convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) }).assignPrototypes(listOf(parameter, field), inheritBlankLinesBefore = false) + convertModifiers(field).filter { it in ACCESS_MODIFIERS }).assignPrototypes(listOf(parameter, field), inheritBlankLinesBefore = false) } }) return PrimaryConstructor(this, annotations, modifiers, parameterList, block).assignPrototype(constructor) @@ -521,9 +521,9 @@ public class Converter private(val project: Project, val settings: ConverterSett = ParameterList(parameterList.getParameters().map { convertParameter(it) }).assignPrototype(parameterList) fun convertParameter(parameter: PsiParameter, - nullability: Nullability = Nullability.Default, - varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None, - modifiers: List = listOf()): Parameter { + nullability: Nullability = Nullability.Default, + varValModifier: Parameter.VarValModifier = Parameter.VarValModifier.None, + modifiers: Modifiers = Modifiers.Empty): Parameter { var `type` = typeConverter.convertVariableType(parameter) when (nullability) { Nullability.NotNull -> `type` = `type`.toNotNullType() @@ -566,8 +566,8 @@ public class Converter private(val project: Project, val settings: ConverterSett return Identifier(identifier.getText()!!).assignPrototype(identifier) } - fun convertModifiers(owner: PsiModifierListOwner): MutableSet - = HashSet(MODIFIERS_MAP.filter { owner.hasModifierProperty(it.first) }.map { it.second }) + fun convertModifiers(owner: PsiModifierListOwner): Modifiers + = Modifiers(MODIFIERS_MAP.filter { owner.hasModifierProperty(it.first) }.map { it.second }).assignPrototype(owner.getModifierList(), false) private val MODIFIERS_MAP = listOf( PsiModifier.ABSTRACT to Modifier.ABSTRACT, diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 48345f04168..e7ed3cba81a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -24,6 +24,7 @@ import java.util.HashMap import java.util.HashSet import org.jetbrains.jet.j2k.ast.Import import org.jetbrains.jet.j2k.ast.ImportList +import org.jetbrains.jet.j2k.ast.assignPrototype class TypeConverter(val settings: ConverterSettings, val conversionScope: ConversionScope) { private val nullabilityCache = HashMap() @@ -56,7 +57,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver = types.map { convertType(it) } public fun convertVariableType(variable: PsiVariable): Type - = convertType(variable.getType(), variableNullability(variable)) + = convertType(variable.getType(), variableNullability(variable)).assignPrototype(variable.getTypeElement()) public fun variableNullability(variable: PsiVariable): Nullability { val cached = nullabilityCache[variable] @@ -119,7 +120,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver } public fun convertMethodReturnType(method: PsiMethod): Type - = convertType(method.getReturnType(), methodNullability(method)) + = convertType(method.getReturnType(), methodNullability(method)).assignPrototype(method.getReturnTypeElement()) public fun methodNullability(method: PsiMethod): Nullability { val cached = nullabilityCache[method] diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index 738c22cc822..0c9d2c3b953 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -19,7 +19,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.CodeBuilder class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) -: Class(Identifier.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { +: Class(Identifier.Empty, Annotations.Empty, Modifiers.Empty, TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { override fun generateCode(builder: CodeBuilder) { body.append(builder, null) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index 2b04dfbe1fd..8c5fe900747 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -16,13 +16,12 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList import org.jetbrains.jet.j2k.* open class Class( val name: Identifier, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, val typeParameterList: TypeParameterList, val extendsTypes: List, val baseClassParams: List, @@ -32,7 +31,11 @@ open class Class( override fun generateCode(builder: CodeBuilder) { builder.append(annotations) - appendModifiers(builder).append(keyword).append(" ").append(name).append(typeParameterList) + .appendWithSpaceAfter(presentationModifiers()) + .append(keyword) + .append(" ") + .append(name) + .append(typeParameterList) appendPrimaryConstructorSignature(builder) appendBaseTypes(builder) typeParameterList.appendWhere(builder) @@ -61,22 +64,6 @@ open class Class( return extendsTypes.map { { builder.append(it) } } } - protected open fun appendModifiers(builder: CodeBuilder): CodeBuilder { - val modifierList = ArrayList() - - modifiers.accessModifier()?.let { modifierList.add(it) } - - if (modifiers.contains(Modifier.ABSTRACT)) { - modifierList.add(Modifier.ABSTRACT) - } - else if (modifiers.contains(Modifier.OPEN)) { - modifierList.add(Modifier.OPEN) - } - - if (modifiers.contains(Modifier.INNER)) { - modifierList.add(Modifier.INNER) - } - - return builder.append(modifierList) - } + protected open fun presentationModifiers(): Modifiers + = if (modifiers.contains(Modifier.ABSTRACT)) modifiers.without(Modifier.OPEN) else modifiers } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt index 33319fe2640..97b1100ce7f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt @@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* -abstract class Member(val annotations: Annotations, val modifiers: Set) : Element() +abstract class Member(val annotations: Annotations, val modifiers: Modifiers) : Element() class ClassBody ( val primaryConstructor: PrimaryConstructor?, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 4cb3dc0c8bf..5c29743fb18 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -16,29 +16,30 @@ package org.jetbrains.jet.j2k.ast -import java.util.HashSet import java.util.ArrayList import org.jetbrains.jet.j2k.* abstract class Constructor( converter: Converter, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, parameterList: ParameterList, block: Block ) : Function(converter, Identifier.Empty, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) class PrimaryConstructor(converter: Converter, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, parameterList: ParameterList, block: Block) : Constructor(converter, annotations, modifiers, parameterList, block) { public fun appendSignature(builder: CodeBuilder): CodeBuilder { - val accessModifier = modifiers.accessModifier() - val modifiersString = if (accessModifier != null && accessModifier != Modifier.PUBLIC) " " + accessModifier.toKotlin() else "" - return builder.append(modifiersString).append("(").append(parameterList).append(")") + val accessModifier = modifiers.filter { it in ACCESS_MODIFIERS && it != Modifier.PUBLIC } + if (!accessModifier.isEmpty) { + builder append " " append accessModifier + } + return builder append "(" append parameterList append ")" } public fun appendBody(builder: CodeBuilder): CodeBuilder = builder.append(block!!) @@ -46,13 +47,12 @@ class PrimaryConstructor(converter: Converter, class SecondaryConstructor(converter: Converter, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, parameterList: ParameterList, block: Block) : Constructor(converter, annotations, modifiers, parameterList, block) { public fun toFactoryFunction(containingClass: Class?): Function { - val modifiers = HashSet(modifiers) val statements = ArrayList(block?.statements ?: listOf()) statements.add(ReturnStatement(tempValIdentifier)) val block = Block(statements, block?.lBrace ?: LBrace(), block?.rBrace ?: RBrace()) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 3fb80b56a23..2a1b4f526b4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -19,8 +19,8 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* import com.intellij.psi.PsiElement -fun TElement.assignPrototype(prototype: PsiElement?): TElement { - assignPrototypeInfos(if (prototype != null) listOf(PrototypeInfo(prototype, true)) else listOf()) +fun TElement.assignPrototype(prototype: PsiElement?, inheritBlankLinesBefore: Boolean = true): TElement { + assignPrototypeInfos(if (prototype != null) listOf(PrototypeInfo(prototype, inheritBlankLinesBefore)) else listOf()) return this } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index 6c5f33edd27..04903876a46 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -21,7 +21,7 @@ import org.jetbrains.jet.j2k.* class Enum( name: Identifier, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, typeParameterList: TypeParameterList, extendsTypes: List, baseClassParams: List, @@ -35,8 +35,7 @@ class Enum( } override fun generateCode(builder: CodeBuilder) { - builder append annotations - appendModifiers(builder) append "enum class " append name + builder append annotations appendWithSpaceAfter presentationModifiers() append "enum class " append name appendPrimaryConstructorSignature(builder) builder append typeParameterList appendBaseTypes(builder) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index 296b7c9282a..cd4417e9502 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -21,7 +21,7 @@ import org.jetbrains.jet.j2k.* class EnumConstant( identifier: Identifier, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, `type`: Type, params: Element ) : Field(identifier, annotations, modifiers, `type`.toNotNullType(), params, true, false) { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index 495153bf717..ea5338ff058 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -17,12 +17,11 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* -import java.util.ArrayList open class Field( val identifier: Identifier, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, val `type`: Type, val initializer: Element, val isVal: Boolean, @@ -31,7 +30,7 @@ open class Field( override fun generateCode(builder: CodeBuilder) { builder.append(annotations) - .appendModifiers() + .appendWithSpaceAfter(modifiers) .append(if (isVal) "val " else "var ") .append(identifier) .append(" : ") @@ -45,15 +44,4 @@ open class Field( builder append "=" append initializerToUse } } - - private fun CodeBuilder.appendModifiers(): CodeBuilder { - val modifierList = ArrayList() - if (modifiers.contains(Modifier.ABSTRACT)) { - modifierList.add(Modifier.ABSTRACT) - } - - modifiers.accessModifier()?.let { modifierList.add(it) } - - return append(modifierList) - } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt index e12535a2554..8e2bc8e0f68 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt @@ -16,14 +16,13 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList import org.jetbrains.jet.j2k.* open class Function( val converter: Converter, val name: Identifier, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, val `type`: Type, val typeParameterList: TypeParameterList, val parameterList: ParameterList, @@ -31,33 +30,23 @@ open class Function( val isInTrait: Boolean ) : Member(annotations, modifiers) { - private fun CodeBuilder.appendModifiers(): CodeBuilder { - val resultingModifiers = ArrayList() - val isOverride = modifiers.contains(Modifier.OVERRIDE) - if (isOverride) { - resultingModifiers.add(Modifier.OVERRIDE) + private fun presentationModifiers(): Modifiers { + var modifiers = this.modifiers + if (isInTrait) { + modifiers = modifiers.without(Modifier.ABSTRACT) } - val accessModifier = modifiers.accessModifier() - if (accessModifier != null && !isOverride) { - resultingModifiers.add(accessModifier) + if (modifiers.contains(Modifier.OVERRIDE)) { + modifiers = modifiers.filter { it != Modifier.OPEN && it !in ACCESS_MODIFIERS } } - if (modifiers.contains(Modifier.ABSTRACT) && !isInTrait) { - resultingModifiers.add(Modifier.ABSTRACT) - } - - if (modifiers.contains(Modifier.OPEN) && !isOverride) { - resultingModifiers.add(Modifier.OPEN) - } - - return append(resultingModifiers) + return modifiers } override fun generateCode(builder: CodeBuilder) { builder.append(annotations) - .appendModifiers() - .append(" fun ") + .appendWithSpaceAfter(presentationModifiers()) + .append("fun ") .appendWithSuffix(typeParameterList, " ") .append(name) .append("(") diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt index b2a6a317ad0..4be86f4d9bf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt @@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* -class Initializer(val block: Block, modifiers: Set) : Member(Annotations.Empty, modifiers) { +class Initializer(val block: Block, modifiers: Modifiers) : Member(Annotations.Empty, modifiers) { override fun generateCode(builder: CodeBuilder) { builder.append(block) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index b80f19f9691..9976c2ede32 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -23,7 +23,7 @@ import org.jetbrains.jet.j2k.append class LocalVariable( private val identifier: Identifier, private val annotations: Annotations, - private val modifiers: Set, + private val modifiers: Modifiers, private val typeCalculator: () -> Type /* we use lazy type calculation for better performance */, private val initializer: Expression, private val isVal: Boolean, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt index 985b646e510..405c4079e8d 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt @@ -16,7 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CodeBuilder +import org.jetbrains.jet.j2k.* +import java.util.HashSet enum class Modifier(val name: String) { PUBLIC: Modifier("public") @@ -33,16 +34,39 @@ enum class Modifier(val name: String) { val ACCESS_MODIFIERS = setOf(Modifier.PUBLIC, Modifier.PROTECTED, Modifier.PRIVATE) fun Collection.accessModifier(): Modifier? { - return firstOrNull { ACCESS_MODIFIERS.contains(it) } + return firstOrNull { it in ACCESS_MODIFIERS } } -fun CodeBuilder.append(modifiers: List): CodeBuilder { - if (!modifiers.isEmpty()) { - for (modifier in modifiers) { - append(modifier.toKotlin()).append(" ") - } +class Modifiers(val modifiers: Collection) : Element() { + override fun generateCode(builder: CodeBuilder) { + builder.append(modifiers.sortBy { it.ordinal() }.map { it.toKotlin() }.joinToString(" ")) + } + + override val isEmpty: Boolean + get() = modifiers.isEmpty() + + fun with(modifier: Modifier): Modifiers = Modifiers(modifiers + listOf(modifier)).assignPrototypesFrom(this) + + fun without(modifier: Modifier): Modifiers { + val set = HashSet(modifiers) + set.remove(modifier) + return Modifiers(set).assignPrototypesFrom(this) + } + + fun contains(modifier: Modifier): Boolean = modifiers.contains(modifier) + + class object { + val Empty = Modifiers(listOf()) + } +} + +fun Modifiers.filter(predicate: (Modifier) -> Boolean): Modifiers + = Modifiers(modifiers.filter(predicate)).assignPrototypesFrom(this) + +fun CodeBuilder.appendWithSpaceAfter(modifiers: Modifiers): CodeBuilder { + if (!modifiers.isEmpty) { + this append modifiers append " " } return this } - diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 103ba544ff8..ca5492bdbb1 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -22,7 +22,7 @@ class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parameter.VarValModifier, val annotations: Annotations, - val modifiers: List) : Element() { + val modifiers: Modifiers) : Element() { public enum class VarValModifier { None Val @@ -30,7 +30,7 @@ class Parameter(val identifier: Identifier, } override fun generateCode(builder: CodeBuilder) { - builder.append(annotations).append(modifiers) + builder.append(annotations).appendWithSpaceAfter(modifiers) if (`type` is VarArgType) { assert(varVal == VarValModifier.None) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index f174b7f7c8e..034d5bdc5ad 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -16,12 +16,11 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList import org.jetbrains.jet.j2k.CodeBuilder class Trait(name: Identifier, annotations: Annotations, - modifiers: Set, + modifiers: Modifiers, typeParameterList: TypeParameterList, extendsTypes: List, baseClassParams: List, @@ -34,10 +33,6 @@ class Trait(name: Identifier, override fun appendPrimaryConstructorSignature(builder: CodeBuilder) { } - override fun appendModifiers(builder: CodeBuilder): CodeBuilder { - val modifierList = ArrayList() - modifiers.accessModifier()?.let { modifierList.add(it) } - return builder.append(modifierList) - } - + override fun presentationModifiers(): Modifiers + = modifiers.filter { it in ACCESS_MODIFIERS } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 3f394093cb3..36dfff85d3a 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -742,6 +742,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/comments/comments.java"); } + @TestMetadata("comments2.java") + public void testComments2() throws Exception { + doTest("j2k/tests/testData/ast/comments/comments2.java"); + } + @TestMetadata("fieldWithEndOfLineComment.java") public void testFieldWithEndOfLineComment() throws Exception { doTest("j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.java"); diff --git a/j2k/tests/testData/ast/comments/comments2.java b/j2k/tests/testData/ast/comments/comments2.java new file mode 100644 index 00000000000..b9de99b91ed --- /dev/null +++ b/j2k/tests/testData/ast/comments/comments2.java @@ -0,0 +1,20 @@ +//file +package foo; + +class A { + void/* nothing to return */ foo(/* no parameters at all */) { + // let declare a variable + // with 2 comments before + int/*int*/ a /* it's a */ = 2 /* it's 2 */ + 1 /* it's 1 */; // variable a declared + } // end of foo + + int/* we return int*/ foo(int/*int*/ p/* parameter p */) { /* body is empty */ } + + private/*it's private*/ int field = 0; + + public /*it's public*/ char foo() { } + + protected/*it's protected*/ void foo() { } + + public/*it's public*/ static/*and static*/ final/*and final*/ int C = 1; +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/comments2.kt b/j2k/tests/testData/ast/comments/comments2.kt new file mode 100644 index 00000000000..ae870f41377 --- /dev/null +++ b/j2k/tests/testData/ast/comments/comments2.kt @@ -0,0 +1,26 @@ +package foo + +class A() { + fun /* nothing to return */ foo(/* no parameters at all */) { + // let declare a variable + // with 2 comments before + val /*int*/ a /* it's a */ = 2 /* it's 2 */ + 1 /* it's 1 */ // variable a declared + } // end of foo + + fun /* we return int*/ foo(/*int*/ p: Int/* parameter p */): Int { + /* body is empty */ + } + + private /*it's private*/ var field: Int = 0 + + public /*it's public*/ fun foo(): Char { + } + + protected /*it's protected*/ fun foo() { + } + + class object { + + public /*it's public*//*and static*//*and final*/ val C: Int = 1 + } +} \ No newline at end of file From 2188af2bf94200f3c08adb206edd2bbe645b4781 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 20 Jun 2014 17:52:10 +0400 Subject: [PATCH 081/143] Java to Kotlin converter: do not produce incorrect "code blocks" which are actually parsed as lambda's in Kotlin #KT-4670 Fixed --- .../jet/j2k/visitors/StatementVisitor.kt | 77 ++++++++++++++----- .../JavaToKotlinConverterTestGenerated.java | 21 ++++- j2k/tests/testData/ast/blocks/Blocks.java | 16 ++++ j2k/tests/testData/ast/blocks/Blocks.kt | 13 ++++ .../testData/ast/for/commonCaseForTest.kt | 6 +- .../testData/ast/for/forRangeWithBlock.java | 3 + .../testData/ast/for/forRangeWithBlock.kt | 4 + j2k/tests/testData/ast/for/forWithBlock.java | 6 +- j2k/tests/testData/ast/for/forWithBlock.kt | 11 ++- .../ast/for/forWithBlockAndDoubleUpdate.kt | 10 +-- .../testData/ast/for/forWithEmptyBlock.kt | 9 +-- .../testData/ast/for/forWithNullCondition.kt | 6 +- j2k/tests/testData/ast/for/forWithNullInit.kt | 12 +-- .../testData/ast/for/forWithNullUpdate.kt | 6 +- j2k/tests/testData/ast/for/forWithReturn.kt | 8 +- 15 files changed, 145 insertions(+), 63 deletions(-) create mode 100644 j2k/tests/testData/ast/blocks/Blocks.java create mode 100644 j2k/tests/testData/ast/blocks/Blocks.kt create mode 100644 j2k/tests/testData/ast/for/forRangeWithBlock.java create mode 100644 j2k/tests/testData/ast/for/forRangeWithBlock.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index 783f711b72b..b71246f1c03 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -51,7 +51,8 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito } override fun visitBlockStatement(statement: PsiBlockStatement) { - result = converter.convertBlock(statement.getCodeBlock()) + val block = converter.convertBlock(statement.getCodeBlock()) + result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block)) } override fun visitBreakStatement(statement: PsiBreakStatement) { @@ -82,7 +83,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito converter.convertExpression(condition, condition.getType()) else converter.convertExpression(condition) - result = DoWhileStatement(expression, converter.convertStatement(statement.getBody()), statement.isInSingleLine()) + result = DoWhileStatement(expression, convertStatementOrBlock(statement.getBody()), statement.isInSingleLine()) } override fun visitExpressionStatement(statement: PsiExpressionStatement) { @@ -111,7 +112,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito && condition != null && update != null && update.getChildren().size == 1 - && isPlusPlusExpression(update.getChildren().single()) + && update.getChildren().single().isPlusPlusExpression() && (operationTokenType == JavaTokenType.LT || operationTokenType == JavaTokenType.LE) && loopVar != null && loopVar.getNameIdentifier() != null @@ -121,19 +122,48 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito result = ForeachWithRangeStatement(loopVar.declarationIdentifier(), converter.convertExpression(loopVar.getInitializer()), endExpression, - converter.convertStatement(body), + convertStatementOrBlock(body), statement.isInSingleLine()) } else { - var forStatements = ArrayList() - forStatements.add(converter.convertStatement(initialization)) - val bodyAndUpdate = listOf(converter.convertStatement(body), - Block(listOf(converter.convertStatement(update)), LBrace(), RBrace())) - forStatements.add(WhileStatement( - if (condition == null) LiteralExpression("true") else converter.convertExpression(condition), - Block(bodyAndUpdate, LBrace(), RBrace()), - statement.isInSingleLine())) - result = Block(forStatements, LBrace(), RBrace()) + val initializationConverted = converter.convertStatement(initialization) + val updateConverted = converter.convertStatement(update) + + val whileBody = if (updateConverted.isEmpty) { + converter.convertStatement(body) + } + else if (body is PsiBlockStatement) { + val nameConflict = initialization is PsiDeclarationStatement && initialization.getDeclaredElements().any { loopVar -> + loopVar is PsiNamedElement && body.getCodeBlock().getStatements().any { statement -> + statement is PsiDeclarationStatement && statement.getDeclaredElements().any { + it is PsiNamedElement && it.getName() == loopVar.getName() + } + } + } + + if (nameConflict) { + Block(listOf(converter.convertStatement(body), updateConverted), LBrace(), RBrace(), true) + } + else { + val block = converter.convertBlock(body.getCodeBlock(), true) + Block(block.statements + listOf(updateConverted), block.lBrace, block.rBrace, true).assignPrototypesFrom(block) + } + } + else { + Block(listOf(converter.convertStatement(body), updateConverted), LBrace(), RBrace(), true) + } + val whileStatement = WhileStatement( + if (condition != null) converter.convertExpression(condition) else LiteralExpression("true"), + whileBody, + statement.isInSingleLine()) + + if (initializationConverted.isEmpty) { + result = whileStatement + } + else { + val block = Block(listOf(initializationConverted, whileStatement), LBrace(), RBrace()) + result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block)) + } } } @@ -147,7 +177,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito } result = ForeachStatement(converter.convertParameter(statement.getIterationParameter()), iterator, - converter.convertStatement(statement.getBody()), + convertStatementOrBlock(statement.getBody()), statement.isInSingleLine()) } @@ -155,8 +185,8 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito val condition = statement.getCondition() val expression = converter.convertExpression(condition, PsiType.BOOLEAN) result = IfStatement(expression, - converter.convertStatement(statement.getThenBranch()), - converter.convertStatement(statement.getElseBranch()), + convertStatementOrBlock(statement.getThenBranch()), + convertStatementOrBlock(statement.getElseBranch()), statement.isInSingleLine()) } @@ -307,7 +337,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito converter.convertExpression(condition, condition!!.getType()) else converter.convertExpression(condition) - result = WhileStatement(expression, converter.convertStatement(statement.getBody()), statement.isInSingleLine()) + result = WhileStatement(expression, convertStatementOrBlock(statement.getBody()), statement.isInSingleLine()) } override fun visitReturnStatement(statement: PsiReturnStatement) { @@ -324,9 +354,9 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito result = Statement.Empty } - private fun isPlusPlusExpression(psiElement: PsiElement): Boolean { - return (psiElement is PsiPostfixExpression && psiElement.getOperationTokenType() == JavaTokenType.PLUSPLUS) || - (psiElement is PsiPrefixExpression && psiElement.getOperationTokenType() == JavaTokenType.PLUSPLUS) + private fun PsiElement.isPlusPlusExpression(): Boolean { + return (this is PsiPostfixExpression && this.getOperationTokenType() == JavaTokenType.PLUSPLUS) || + (this is PsiPrefixExpression && this.getOperationTokenType() == JavaTokenType.PLUSPLUS) } private fun containsBreak(slice: List) = slice.any { it is PsiBreakStatement } @@ -371,4 +401,11 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito return cases } + + private fun convertStatementOrBlock(statement: PsiStatement?): Statement { + return if (statement is PsiBlockStatement) + converter.convertBlock(statement.getCodeBlock()) + else + converter.convertStatement(statement) + } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 36dfff85d3a..831cd2a68a7 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("j2k/tests/testData/ast") -@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.Comments.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) +@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.Blocks.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.Comments.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInAst() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true); @@ -441,6 +441,19 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } + @TestMetadata("j2k/tests/testData/ast/blocks") + public static class Blocks extends AbstractJavaToKotlinConverterTest { + public void testAllFilesPresentInBlocks() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/blocks"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("Blocks.java") + public void testBlocks() throws Exception { + doTest("j2k/tests/testData/ast/blocks/Blocks.java"); + } + + } + @TestMetadata("j2k/tests/testData/ast/boxedType") public static class BoxedType extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInBoxedType() throws Exception { @@ -1109,6 +1122,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/for/commonCaseForTest.java"); } + @TestMetadata("forRangeWithBlock.java") + public void testForRangeWithBlock() throws Exception { + doTest("j2k/tests/testData/ast/for/forRangeWithBlock.java"); + } + @TestMetadata("forRangeWithLE.java") public void testForRangeWithLE() throws Exception { doTest("j2k/tests/testData/ast/for/forRangeWithLE.java"); @@ -2809,6 +2827,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(AssertStatement.class); suite.addTestSuite(AssignmentExpression.class); suite.addTestSuite(BinaryExpression.class); + suite.addTestSuite(Blocks.class); suite.addTestSuite(BoxedType.class); suite.addTestSuite(BreakStatement.class); suite.addTestSuite(CallChainExpression.class); diff --git a/j2k/tests/testData/ast/blocks/Blocks.java b/j2k/tests/testData/ast/blocks/Blocks.java new file mode 100644 index 00000000000..b6d6c86aebe --- /dev/null +++ b/j2k/tests/testData/ast/blocks/Blocks.java @@ -0,0 +1,16 @@ +//method +void foo() { + { + int a = 1; + bar(a); + } + + { + int a = 2; + bar(a); + } + + { + bar(3); + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/blocks/Blocks.kt b/j2k/tests/testData/ast/blocks/Blocks.kt new file mode 100644 index 00000000000..f1644d4da0e --- /dev/null +++ b/j2k/tests/testData/ast/blocks/Blocks.kt @@ -0,0 +1,13 @@ +fun foo() { + run { + val a = 1 + bar(a) + } + + run { + val a = 2 + bar(a) + } + + run { bar(3) } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/commonCaseForTest.kt b/j2k/tests/testData/ast/for/commonCaseForTest.kt index 93765cdb4f9..8efe40b3183 100644 --- a/j2k/tests/testData/ast/for/commonCaseForTest.kt +++ b/j2k/tests/testData/ast/for/commonCaseForTest.kt @@ -1,9 +1,7 @@ -{ +run { init() while (condition()) { body() - { - update() - } + update() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forRangeWithBlock.java b/j2k/tests/testData/ast/for/forRangeWithBlock.java new file mode 100644 index 00000000000..255ff0538ac --- /dev/null +++ b/j2k/tests/testData/ast/for/forRangeWithBlock.java @@ -0,0 +1,3 @@ +//statement +int[] array = new int[10]; +for (int i = 0; i < 10; i++) {array[i] = i;} \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forRangeWithBlock.kt b/j2k/tests/testData/ast/for/forRangeWithBlock.kt new file mode 100644 index 00000000000..69ad99b50a8 --- /dev/null +++ b/j2k/tests/testData/ast/for/forRangeWithBlock.kt @@ -0,0 +1,4 @@ +val array = IntArray(10) +for (i in 0..10 - 1) { + array[i] = i +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forWithBlock.java b/j2k/tests/testData/ast/for/forWithBlock.java index 255ff0538ac..c648fa84a2a 100644 --- a/j2k/tests/testData/ast/for/forWithBlock.java +++ b/j2k/tests/testData/ast/for/forWithBlock.java @@ -1,3 +1,5 @@ //statement -int[] array = new int[10]; -for (int i = 0; i < 10; i++) {array[i] = i;} \ No newline at end of file +for (int i = 0; i < 10; j++, i++) { + System.out.println(i); + System.out.println(j); +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forWithBlock.kt b/j2k/tests/testData/ast/for/forWithBlock.kt index 69ad99b50a8..584bc4c0864 100644 --- a/j2k/tests/testData/ast/for/forWithBlock.kt +++ b/j2k/tests/testData/ast/for/forWithBlock.kt @@ -1,4 +1,9 @@ -val array = IntArray(10) -for (i in 0..10 - 1) { - array[i] = i +run { + val i = 0 + while (i < 10) { + System.out.println(i) + System.out.println(j) + j++ + i++ + } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forWithBlockAndDoubleUpdate.kt b/j2k/tests/testData/ast/for/forWithBlockAndDoubleUpdate.kt index 45e8901650b..88022ed0bb3 100644 --- a/j2k/tests/testData/ast/for/forWithBlockAndDoubleUpdate.kt +++ b/j2k/tests/testData/ast/for/forWithBlockAndDoubleUpdate.kt @@ -1,13 +1,11 @@ -{ +run { val i = 0 while (i < 0) { - { + run { val i = 1 i++ } - { - j++ - i++ - } + j++ + i++ } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forWithEmptyBlock.kt b/j2k/tests/testData/ast/for/forWithEmptyBlock.kt index fab9b579c8d..c321897d011 100644 --- a/j2k/tests/testData/ast/for/forWithEmptyBlock.kt +++ b/j2k/tests/testData/ast/for/forWithEmptyBlock.kt @@ -1,10 +1,7 @@ -{ +run { val i = 0 while (i < 0) { - {} - { - j++ - i++ - } + j++ + i++ } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forWithNullCondition.kt b/j2k/tests/testData/ast/for/forWithNullCondition.kt index 068c816cfcf..5eb7f9d06c6 100644 --- a/j2k/tests/testData/ast/for/forWithNullCondition.kt +++ b/j2k/tests/testData/ast/for/forWithNullCondition.kt @@ -1,9 +1,7 @@ -{ +run { init() while (true) { body() - { - update() - } + update() } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forWithNullInit.kt b/j2k/tests/testData/ast/for/forWithNullInit.kt index 9848b9962ac..f5bb9556fc6 100644 --- a/j2k/tests/testData/ast/for/forWithNullInit.kt +++ b/j2k/tests/testData/ast/for/forWithNullInit.kt @@ -1,8 +1,4 @@ -{ - while (condition()) { - body() - { - update() - } - } -} \ No newline at end of file +while (condition()) { + body() + update() +} diff --git a/j2k/tests/testData/ast/for/forWithNullUpdate.kt b/j2k/tests/testData/ast/for/forWithNullUpdate.kt index 7ca346555e1..d912eb3ed07 100644 --- a/j2k/tests/testData/ast/for/forWithNullUpdate.kt +++ b/j2k/tests/testData/ast/for/forWithNullUpdate.kt @@ -1,6 +1,4 @@ -{ +run { init() - while (condition()) { - body() - } + while (condition()) body() } \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/forWithReturn.kt b/j2k/tests/testData/ast/for/forWithReturn.kt index cd07bc24e34..b618d0f6647 100644 --- a/j2k/tests/testData/ast/for/forWithReturn.kt +++ b/j2k/tests/testData/ast/for/forWithReturn.kt @@ -1,10 +1,8 @@ -{ +run { val i = 0 while (i < 0) { return i - { - j++ - i++ - } + j++ + i++ } } \ No newline at end of file From 5ac762034a2fa71faa1b6deeb307776d9d754226 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 20 Jun 2014 19:26:39 +0400 Subject: [PATCH 082/143] Java to Kotlin converter: correct nullability in signatures of overrides #KT-5269 Fixed --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 17 ---------- .../org/jetbrains/jet/j2k/TypeConverter.kt | 31 ++++++++++++++++++- .../JavaToKotlinConverterTestGenerated.java | 20 ++++++++++++ j2k/tests/testData/JavaApi.java | 13 ++++++++ .../function/extendsBaseWhichExtendsObject.kt | 4 +-- .../testData/ast/function/overrideObject.kt | 2 +- .../testData/ast/function/overrideObject2.kt | 2 +- ...Object3.java.todo => overrideObject3.java} | 0 .../testData/ast/function/overrideObject3.kt | 2 +- j2k/tests/testData/ast/issues/kt-696.kt | 4 +-- .../ast/nullability/IndirectOverride.java | 4 +++ .../ast/nullability/IndirectOverride.kt | 5 +++ .../OverrideWithInheritanceLoop.java | 8 +++++ .../OverrideWithInheritanceLoop.kt | 9 ++++++ .../testData/ast/nullability/Overrides.java | 26 ++++++++++++++++ .../testData/ast/nullability/Overrides.kt | 31 +++++++++++++++++++ 16 files changed, 153 insertions(+), 25 deletions(-) rename j2k/tests/testData/ast/function/{overrideObject3.java.todo => overrideObject3.java} (100%) create mode 100644 j2k/tests/testData/ast/nullability/IndirectOverride.java create mode 100644 j2k/tests/testData/ast/nullability/IndirectOverride.kt create mode 100644 j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.java create mode 100644 j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.kt create mode 100644 j2k/tests/testData/ast/nullability/Overrides.java create mode 100644 j2k/tests/testData/ast/nullability/Overrides.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 3ba4c87e7f9..977415ce42c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -330,23 +330,6 @@ public class Converter private(val project: Project, val settings: ConverterSett } var params = convertParameterList(method.getParameterList()) - - // if we override equals from Object, change parameter type to nullable - if (isOverride && method.getName() == "equals") { - val superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures() - val overridesMethodFromObject = superSignatures.any { - it.getMethod().getContainingClass()?.getQualifiedName() == JAVA_LANG_OBJECT - } - if (overridesMethodFromObject) { - val correctedParameter = Parameter(Identifier("other"), - ClassType(Identifier("Any"), listOf(), Nullability.Nullable, settings), - Parameter.VarValModifier.None, - params.parameters.single().annotations, - Modifiers.Empty) - params = ParameterList(listOf(correctedParameter)) - } - } - val typeParameterList = convertTypeParameterList(method.getTypeParameterList()) val block = convertBlock(method.getBody()) return Function(this, method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index e7ed3cba81a..c92d79ba8c3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -25,6 +25,7 @@ import java.util.HashSet import org.jetbrains.jet.j2k.ast.Import import org.jetbrains.jet.j2k.ast.ImportList import org.jetbrains.jet.j2k.ast.assignPrototype +import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT class TypeConverter(val settings: ConverterSettings, val conversionScope: ConversionScope) { private val nullabilityCache = HashMap() @@ -72,6 +73,19 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver var nullability = variable.nullabilityFromAnnotations() + if (nullability == Nullability.Default && variable is PsiParameter) { + val scope = variable.getDeclarationScope() + if (scope is PsiMethod) { + val paramIndex = scope.getParameterList().getParameters().indexOf(variable) + assert(paramIndex >= 0) + val superSignatures = scope.getHierarchicalMethodSignature().getSuperSignatures() + nullability = superSignatures.map { signature -> + val params = signature.getMethod().getParameterList().getParameters() + if (paramIndex < params.size) variableNullability(params[paramIndex]) else Nullability.Default + }.firstOrNull { it != Nullability.Default } ?: Nullability.Default + } + } + if (nullability == Nullability.Default) { val initializer = variable.getInitializer() if (initializer != null) { @@ -85,7 +99,17 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver } } - if (!conversionScope.contains(variable)) return nullability // do not analyze usages of fields out of our conversion scope + if (!conversionScope.contains(variable)) { // do not analyze usages out of our conversion scope + if (variable is PsiParameter) { + // Object.equals corresponds to Any.equals which has nullable parameter: + val scope = variable.getDeclarationScope() + if (scope is PsiMethod && scope.getName() == "equals" && scope.getContainingClass()?.getQualifiedName() == JAVA_LANG_OBJECT) { + return Nullability.Nullable + } + } + + return nullability + } if (nullability == Nullability.Default) { val scope = searchScope(variable) @@ -133,6 +157,11 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver private fun methodNullabilityNoCache(method: PsiMethod): Nullability { var nullability = method.nullabilityFromAnnotations() + if (nullability == Nullability.Default) { + val superSignatures = method.getHierarchicalMethodSignature().getSuperSignatures() + nullability = superSignatures.map { methodNullability(it.getMethod()) }.firstOrNull { it != Nullability.Default } ?: Nullability.Default + } + if (!conversionScope.contains(method)) return nullability // do not analyze body and usages of methods out of our conversion scope if (nullability == Nullability.Default) { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 831cd2a68a7..2c51401dedd 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -1326,6 +1326,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/function/overrideObject2.java"); } + @TestMetadata("overrideObject3.java") + public void testOverrideObject3() throws Exception { + doTest("j2k/tests/testData/ast/function/overrideObject3.java"); + } + @TestMetadata("ownGenericParam.java") public void testOwnGenericParam() throws Exception { doTest("j2k/tests/testData/ast/function/ownGenericParam.java"); @@ -2004,6 +2009,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/nullability/FieldInitializedWithNull.java"); } + @TestMetadata("IndirectOverride.java") + public void testIndirectOverride() throws Exception { + doTest("j2k/tests/testData/ast/nullability/IndirectOverride.java"); + } + @TestMetadata("MethodInvokedWithNullArg.java") public void testMethodInvokedWithNullArg() throws Exception { doTest("j2k/tests/testData/ast/nullability/MethodInvokedWithNullArg.java"); @@ -2069,6 +2079,16 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/nullability/NullableVariableDotAccess.java"); } + @TestMetadata("OverrideWithInheritanceLoop.java") + public void testOverrideWithInheritanceLoop() throws Exception { + doTest("j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.java"); + } + + @TestMetadata("Overrides.java") + public void testOverrides() throws Exception { + doTest("j2k/tests/testData/ast/nullability/Overrides.java"); + } + @TestMetadata("ParameterComparedWithNull.java") public void testParameterComparedWithNull() throws Exception { doTest("j2k/tests/testData/ast/nullability/ParameterComparedWithNull.java"); diff --git a/j2k/tests/testData/JavaApi.java b/j2k/tests/testData/JavaApi.java index f0d51257d23..1da536be2ec 100644 --- a/j2k/tests/testData/JavaApi.java +++ b/j2k/tests/testData/JavaApi.java @@ -1,5 +1,10 @@ package javaApi; +import org.jetbrains.annotations.Nullable; + +import java.lang.Override; +import java.lang.String; + public @interface Anon1 { String[] value(); String[] stringArray(); @@ -43,3 +48,11 @@ public @interface Anon8 { public enum E { A, B, C } + +class Base { + public @Nullable String foo(@Nullable String s) { return s; } +} + +class Derived extends Base { + public String foo(String s) { return s; } +} diff --git a/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt b/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt index e7f0ebe62dc..57d95afb66e 100644 --- a/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt +++ b/j2k/tests/testData/ast/function/extendsBaseWhichExtendsObject.kt @@ -5,7 +5,7 @@ class Test() : Base() { return super.hashCode() } - override fun equals(o: Any): Boolean { + override fun equals(o: Any?): Boolean { return super.equals(o) } @@ -29,7 +29,7 @@ class Base() { return super.hashCode() } - override fun equals(other: Any?): Boolean { + override fun equals(o: Any?): Boolean { return super.equals(o) } diff --git a/j2k/tests/testData/ast/function/overrideObject.kt b/j2k/tests/testData/ast/function/overrideObject.kt index 2bebbe28944..fe55ec8bf2c 100644 --- a/j2k/tests/testData/ast/function/overrideObject.kt +++ b/j2k/tests/testData/ast/function/overrideObject.kt @@ -3,7 +3,7 @@ class X() { return super.hashCode() } - override fun equals(other: Any?): Boolean { + override fun equals(o: Any?): Boolean { return super.equals(o) } diff --git a/j2k/tests/testData/ast/function/overrideObject2.kt b/j2k/tests/testData/ast/function/overrideObject2.kt index 40f8b234ba3..9646e9e2740 100644 --- a/j2k/tests/testData/ast/function/overrideObject2.kt +++ b/j2k/tests/testData/ast/function/overrideObject2.kt @@ -5,7 +5,7 @@ class X() : Base() { return super.hashCode() } - override fun equals(other: Any?): Boolean { + override fun equals(o: Any?): Boolean { return super.equals(o) } diff --git a/j2k/tests/testData/ast/function/overrideObject3.java.todo b/j2k/tests/testData/ast/function/overrideObject3.java similarity index 100% rename from j2k/tests/testData/ast/function/overrideObject3.java.todo rename to j2k/tests/testData/ast/function/overrideObject3.java diff --git a/j2k/tests/testData/ast/function/overrideObject3.kt b/j2k/tests/testData/ast/function/overrideObject3.kt index 94e655b81d6..de83777788d 100644 --- a/j2k/tests/testData/ast/function/overrideObject3.kt +++ b/j2k/tests/testData/ast/function/overrideObject3.kt @@ -1,5 +1,5 @@ class Base() { - override fun equals(other: Any?): Boolean { + override fun equals(o: Any?): Boolean { return super.equals(o) } } diff --git a/j2k/tests/testData/ast/issues/kt-696.kt b/j2k/tests/testData/ast/issues/kt-696.kt index 405b1c9e5d3..d9aefd9c3ac 100644 --- a/j2k/tests/testData/ast/issues/kt-696.kt +++ b/j2k/tests/testData/ast/issues/kt-696.kt @@ -5,7 +5,7 @@ class Base() { return super.hashCode() } - override fun equals(other: Any?): Boolean { + override fun equals(o: Any?): Boolean { return super.equals(o) } @@ -19,7 +19,7 @@ class Child() : Base() { return super.hashCode() } - override fun equals(o: Any): Boolean { + override fun equals(o: Any?): Boolean { return super.equals(o) } diff --git a/j2k/tests/testData/ast/nullability/IndirectOverride.java b/j2k/tests/testData/ast/nullability/IndirectOverride.java new file mode 100644 index 00000000000..6548af24619 --- /dev/null +++ b/j2k/tests/testData/ast/nullability/IndirectOverride.java @@ -0,0 +1,4 @@ +//file +class C extends javaApi.Derived { + public String foo(String s) { return s; } +} diff --git a/j2k/tests/testData/ast/nullability/IndirectOverride.kt b/j2k/tests/testData/ast/nullability/IndirectOverride.kt new file mode 100644 index 00000000000..d65becf9df5 --- /dev/null +++ b/j2k/tests/testData/ast/nullability/IndirectOverride.kt @@ -0,0 +1,5 @@ +class C() : javaApi.Derived() { + override fun foo(s: String?): String? { + return s + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.java b/j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.java new file mode 100644 index 00000000000..0d9ca83749c --- /dev/null +++ b/j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.java @@ -0,0 +1,8 @@ +//file +class A extends B { + public void foo(String s) {} +} + +class B extends A { + public void foo(String s) {} +} diff --git a/j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.kt b/j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.kt new file mode 100644 index 00000000000..b4577d0e5d0 --- /dev/null +++ b/j2k/tests/testData/ast/nullability/OverrideWithInheritanceLoop.kt @@ -0,0 +1,9 @@ +class A() : B() { + public fun foo(s: String) { + } +} + +class B() : A() { + public fun foo(s: String) { + } +} diff --git a/j2k/tests/testData/ast/nullability/Overrides.java b/j2k/tests/testData/ast/nullability/Overrides.java new file mode 100644 index 00000000000..93a02f5450b --- /dev/null +++ b/j2k/tests/testData/ast/nullability/Overrides.java @@ -0,0 +1,26 @@ +//file +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class Base { + @Nullable + public String foo(@Nullable String s) { return ""; } + + public String bar(String s) { + return s != null ? s + 1 : null; + } + + public String zoo(Object o){ return ""; } +} + +interface I { + @Nullable String zoo(@Nullable Object o); +} + +class C extends Base implements I { + public String foo(String s) { return ""; } + + public String bar(String s) { return ""; } + + public String zoo(Object o) { return ""; } +} diff --git a/j2k/tests/testData/ast/nullability/Overrides.kt b/j2k/tests/testData/ast/nullability/Overrides.kt new file mode 100644 index 00000000000..0158b9f0f68 --- /dev/null +++ b/j2k/tests/testData/ast/nullability/Overrides.kt @@ -0,0 +1,31 @@ +class Base() { + public fun foo(s: String?): String? { + return "" + } + + public fun bar(s: String?): String? { + return if (s != null) s + 1 else null + } + + public fun zoo(o: Any): String { + return "" + } +} + +trait I { + public fun zoo(o: Any?): String? +} + +class C() : Base(), I { + override fun foo(s: String?): String? { + return "" + } + + override fun bar(s: String?): String? { + return "" + } + + override fun zoo(o: Any?): String? { + return "" + } +} From 6135ea56038eeaa77c55de2eac9c0be719cffc0e Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 20 Jun 2014 22:30:00 +0400 Subject: [PATCH 083/143] Java to Kotlin converter: minor code refactoring --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 977415ce42c..853877dea11 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -66,7 +66,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return builder.result } - private fun convertTopElement(element: PsiElement?): Element? = when(element) { + private fun convertTopElement(element: PsiElement?): Element? = when (element) { is PsiJavaFile -> convertFile(element) is PsiClass -> convertClass(element) is PsiMethod -> convertMethod(element, HashSet()) @@ -125,21 +125,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val primaryConstructor = convertedMembers.values().filterIsInstance(javaClass()).firstOrNull() val secondaryConstructors = convertedMembers.values().filterIsInstance(javaClass()) - // do not convert private static methods into class object if possible - val useClassObject = if (psiClass.isEnum()) { - false - } - else { - val members = convertedMembers.keySet().filter { it !is PsiMethod || !it.isConstructor() } - val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) } - val nestedClasses = members.filterIsInstance(javaClass()).filter { it.hasModifierProperty(PsiModifier.STATIC) } - if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) { - nestedClasses.any { nestedClass -> classObjectMembers.any { findMethodCalls(it as PsiMethod, nestedClass).isNotEmpty() } } - } - else { - true - } - } + val useClassObject = shouldGenerateClassObject(psiClass, convertedMembers) val normalMembers = ArrayList() val classObjectMembers = ArrayList() @@ -158,7 +144,21 @@ public class Converter private(val project: Project, val settings: ConverterSett return ClassBody(primaryConstructor, secondaryConstructors, normalMembers, classObjectMembers, lBrace, rBrace) } - private fun convertMember(member: PsiMember, membersToRemove: MutableSet): Member = when(member) { + // do not convert private static methods into class object if possible + private fun shouldGenerateClassObject(psiClass: PsiClass, convertedMembers: Map): Boolean { + if (psiClass.isEnum()) return false + val members = convertedMembers.keySet().filter { it !is PsiMethod || !it.isConstructor() } + val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) } + val nestedClasses = members.filterIsInstance(javaClass()).filter { it.hasModifierProperty(PsiModifier.STATIC) } + if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) { + return nestedClasses.any { nestedClass -> classObjectMembers.any { findMethodCalls(it as PsiMethod, nestedClass).isNotEmpty() } } + } + else { + return true + } + } + + private fun convertMember(member: PsiMember, membersToRemove: MutableSet): Member = when (member) { is PsiMethod -> convertMethod(member, membersToRemove) is PsiField -> convertField(member) is PsiClass -> convertClass(member) @@ -351,7 +351,7 @@ public class Converter private(val project: Project, val settings: ConverterSett it.getMethod().getContainingClass()?.getQualifiedName() == JAVA_LANG_OBJECT } if (overridesMethodFromObject) { - when(method.getName()) { + when (method.getName()) { "equals", "hashCode", "toString" -> return true // these methods from java.lang.Object exist in kotlin.Any else -> { @@ -435,7 +435,7 @@ public class Converter private(val project: Project, val settings: ConverterSett if (refs.any { PsiUtil.isAccessedForWriting(it) }) return null - for(ref in refs) { + for (ref in refs) { val assignment = ref.getParent() as? PsiAssignmentExpression ?: continue if (assignment.getOperationSign().getTokenType() != JavaTokenType.EQ) continue val assignee = assignment.getLExpression() as? PsiReferenceExpression ?: continue @@ -459,7 +459,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return null } - fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = {true}): Block { + fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = { true }): Block { if (block == null) return Block.Empty val lBrace = LBrace().assignPrototype(block.getLBrace()) @@ -570,7 +570,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } else { var child: PsiElement? = modifierList - while(true) { + while (true) { child = child!!.getNextSibling() if (child == null || child!!.getTextLength() != 0) break } @@ -608,7 +608,7 @@ public class Converter private(val project: Project, val settings: ConverterSett } private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List { - return when(value) { + return when (value) { is PsiExpression -> listOf(convertExpression(value as? PsiExpression, expectedType)) is PsiArrayInitializerMemberValue -> { From a28e7b087290cbe22601d2a59b33ecb34859e6ac Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 14:20:54 +0400 Subject: [PATCH 084/143] Java to Kotlin converter: minor code refactorings after code review --- .../org/jetbrains/jet/j2k/ConstructorUtils.kt | 4 +- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 2 +- .../org/jetbrains/jet/j2k/TypeConverter.kt | 5 +- .../jet/j2k/visitors/StatementVisitor.kt | 69 ++++++++++--------- .../jetbrains/jet/j2k/visitors/TypeVisitor.kt | 4 +- 5 files changed, 43 insertions(+), 41 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt b/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt index cc9330dfc5d..1a5608ce4e5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt @@ -80,8 +80,7 @@ fun PsiElement.getContainingConstructor(): PsiMethod? { fun PsiMethodCallExpression.isSuperConstructorCall(): Boolean { val ref = getMethodExpression() if (ref.getCanonicalText() == "super") { - val target = ref.resolve() - return target is PsiMethod && target.isConstructor() + return ref.resolve()?.isConstructor() ?: false } return false } @@ -89,3 +88,4 @@ fun PsiMethodCallExpression.isSuperConstructorCall(): Boolean { fun PsiReferenceExpression.isThisConstructorCall(): Boolean = getReferences().filter { it.getCanonicalText() == "this" }.map { it.resolve() }.any { it is PsiMethod && it.isConstructor() } +fun PsiElement.isConstructor(): Boolean = this is PsiMethod && this.isConstructor() diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 853877dea11..05375a6ddbf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -147,7 +147,7 @@ public class Converter private(val project: Project, val settings: ConverterSett // do not convert private static methods into class object if possible private fun shouldGenerateClassObject(psiClass: PsiClass, convertedMembers: Map): Boolean { if (psiClass.isEnum()) return false - val members = convertedMembers.keySet().filter { it !is PsiMethod || !it.isConstructor() } + val members = convertedMembers.keySet().filter { !it.isConstructor() } val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) } val nestedClasses = members.filterIsInstance(javaClass()).filter { it.hasModifierProperty(PsiModifier.STATIC) } if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) { diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index c92d79ba8c3..0611a67d5bb 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -37,8 +37,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver importNames = importList?.imports?.mapTo(HashSet()) { it.name } ?: setOf() } - public var importNames: Set = setOf() - private set + private var importNames: Set = setOf() public val importsToAdd: Collection get() = classesToImport.map { Import(it) } @@ -46,7 +45,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver public fun convertType(`type`: PsiType?, nullability: Nullability = Nullability.Default): Type { if (`type` == null) return Type.Empty - val result = `type`.accept(TypeVisitor(this, classesToImport))!! + val result = `type`.accept(TypeVisitor(this, importNames, classesToImport))!! return when (nullability) { Nullability.NotNull -> result.toNotNullType() Nullability.Nullable -> result.toNullableType() diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index b71246f1c03..ab314010adf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -277,39 +277,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito if (resourceList != null) { val variables = resourceList.getResourceVariables() if (variables.isNotEmpty()) { - var wrapResultStatement: (Expression) -> Statement = { it } - var converterForBody = converter - - val returns = collectReturns(tryBlock) - //TODO: support other returns when non-local returns supported by Kotlin - if (returns.size == 1 && returns.single() == tryBlock!!.getStatements().last()) { - wrapResultStatement = { ReturnStatement(it) } - converterForBody = converter.withStatementVisitor { object : StatementVisitor(it) { - override fun visitReturnStatement(statement: PsiReturnStatement) { - if (statement == returns.single()) { - result = converter.convertExpression(statement.getReturnValue(), tryStatement.getContainingMethod()?.getReturnType()) - } - else { - super.visitReturnStatement(statement) - } - } - }} - } - - var block = converterForBody.convertBlock(tryBlock) - var expression: Expression = Expression.Empty - for (variable in variables.reverse()) { - val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), block) - expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda) - block = Block(listOf(expression), LBrace(), RBrace()) - } - - if (catchesConverted.isEmpty() && finallyConverted.isEmpty) { - result = wrapResultStatement(expression) - return - } - - result = TryStatement(Block(listOf(wrapResultStatement(expression)), LBrace(), RBrace(), true), catchesConverted, finallyConverted) + result = convertTryWithResources(tryBlock, variables, catchesConverted, finallyConverted) return } } @@ -317,6 +285,41 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito result = TryStatement(converter.convertBlock(tryBlock), catchesConverted, finallyConverted) } + private fun convertTryWithResources(tryBlock: PsiCodeBlock?, resourceVariables: List, catchesConverted: List, finallyConverted: Block): Statement { + var wrapResultStatement: (Expression) -> Statement = { it } + var converterForBody = converter + + val returns = collectReturns(tryBlock) + //TODO: support other returns when non-local returns supported by Kotlin + if (returns.size == 1 && returns.single() == tryBlock!!.getStatements().last()) { + wrapResultStatement = { ReturnStatement(it) } + converterForBody = converter.withStatementVisitor { object : StatementVisitor(it) { + override fun visitReturnStatement(statement: PsiReturnStatement) { + if (statement == returns.single()) { + result = converter.convertExpression(statement.getReturnValue(), tryBlock!!.getContainingMethod()?.getReturnType()) + } + else { + super.visitReturnStatement(statement) + } + } + }} + } + + var block = converterForBody.convertBlock(tryBlock) + var expression: Expression = Expression.Empty + for (variable in resourceVariables.reverse()) { + val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), block) + expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda) + block = Block(listOf(expression), LBrace(), RBrace()) + } + + if (catchesConverted.isEmpty() && finallyConverted.isEmpty) { + return wrapResultStatement(expression) + } + + return TryStatement(Block(listOf(wrapResultStatement(expression)), LBrace(), RBrace(), true), catchesConverted, finallyConverted) + } + private fun collectReturns(block: PsiCodeBlock?): Collection { val returns = ArrayList() block?.accept(object: JavaRecursiveElementVisitor() { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index 39f6ef5a425..5d9ceb111d9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -27,7 +27,7 @@ import org.jetbrains.jet.j2k.TypeConverter private val PRIMITIVE_TYPES_NAMES = JvmPrimitiveType.values().map { it.getName() } -class TypeVisitor(private val converter: TypeConverter, private val classesToImport: MutableSet) : PsiTypeVisitor() { +class TypeVisitor(private val converter: TypeConverter, private val importNames: Set, private val classesToImport: MutableSet) : PsiTypeVisitor() { override fun visitPrimitiveType(primitiveType: PsiPrimitiveType): Type { val name = primitiveType.getCanonicalText() return if (name == "void") { @@ -75,7 +75,7 @@ class TypeVisitor(private val converter: TypeConverter, private val classesToImp val kotlinClassName = toKotlinTypesMap[javaClassName] if (kotlinClassName != null) { val kotlinShortName = getShortName(kotlinClassName) - if (kotlinShortName == getShortName(javaClassName!!) && converter.importNames.contains(getPackageName(javaClassName) + ".*")) { + if (kotlinShortName == getShortName(javaClassName!!) && importNames.contains(getPackageName(javaClassName) + ".*")) { classesToImport.add(kotlinClassName) } return Identifier(kotlinShortName) From 0e9edb74877352f90c10c54256fff9ee7cd525ea Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 14:30:26 +0400 Subject: [PATCH 085/143] Java to Kotlin converter: fixed a bug with incorrect assignment generation --- j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt | 4 ++-- j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt | 2 +- .../jet/j2k/test/AbstractJavaToKotlinConverterTest.kt | 2 +- .../jet/j2k/test/JavaToKotlinConverterTestGenerated.java | 5 +++++ j2k/tests/testData/ast/issues/spaceBeforeAssignment.java | 6 ++++++ j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt | 6 ++++++ 8 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 j2k/tests/testData/ast/issues/spaceBeforeAssignment.java create mode 100644 j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index efd2a66692d..eee1b070edf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -29,7 +29,7 @@ class ArrayAccessExpression(val expression: Expression, val index: Expression, v class AssignmentExpression(val left: Expression, val right: Expression, val op: String) : Expression() { override fun generateCode(builder: CodeBuilder) { - builder.appendOperand(this, left).append(op).appendOperand(this, right) + builder.appendOperand(this, left).append(" ").append(op).append(" ").appendOperand(this, right) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index ea5338ff058..9170924b60a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -41,7 +41,7 @@ open class Field( initializerToUse = getDefaultInitializer(this) } if (!initializerToUse.isEmpty) { - builder append "=" append initializerToUse + builder append " = " append initializerToUse } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index 9976c2ede32..68cb7538eea 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -38,9 +38,9 @@ class LocalVariable( else { val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault if (shouldSpecifyType) - builder append identifier append ":" append typeCalculator() append "=" append initializer + builder append identifier append ":" append typeCalculator() append " = " append initializer else - builder append identifier append "=" append initializer + builder append identifier append " = " append initializer } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index f3e0d56830f..52ad3fe0a75 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -77,7 +77,7 @@ class ExpressionVisitor(private val converter: Converter, val lhs = converter.convertExpression(expression.getLExpression()) val rhs = converter.convertExpression(expression.getRExpression()!!, expression.getLExpression().getType()) if (!secondOp.isEmpty()) { - result = AssignmentExpression(lhs, BinaryExpression(lhs, rhs, secondOp), "=") + result = AssignmentExpression(lhs, BinaryExpression(lhs, rhs, secondOp), " = ") } else { result = AssignmentExpression(lhs, rhs, expression.getOperationSign().getText()!!) diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index 859f5c5ea88..2c183fbc49b 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -145,7 +145,7 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { private fun expressionToKotlin(code: String, settings: ConverterSettings, project: Project): String { val result = statementToKotlin("final Object o =" + code + "}", settings, project) - return result.replaceFirst("val o:Any\\?=", "").replaceFirst("val o:Any=", "").replaceFirst("val o=", "").trim() + return result.replaceFirst("val o:Any\\? = ", "").replaceFirst("val o:Any = ", "").replaceFirst("val o = ", "").trim() } override fun getProjectJDK(): Sdk? { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 2c51401dedd..16a6f7db03a 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -1682,6 +1682,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/issues/qualifyStatic.java"); } + @TestMetadata("spaceBeforeAssignment.java") + public void testSpaceBeforeAssignment() throws Exception { + doTest("j2k/tests/testData/ast/issues/spaceBeforeAssignment.java"); + } + } @TestMetadata("j2k/tests/testData/ast/kotlinApiAccess") diff --git a/j2k/tests/testData/ast/issues/spaceBeforeAssignment.java b/j2k/tests/testData/ast/issues/spaceBeforeAssignment.java new file mode 100644 index 00000000000..fc6916bfbb3 --- /dev/null +++ b/j2k/tests/testData/ast/issues/spaceBeforeAssignment.java @@ -0,0 +1,6 @@ +//file +import java.util.* + +class A { + List list = new ArrayList(); +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt b/j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt new file mode 100644 index 00000000000..7f360fb4f0d --- /dev/null +++ b/j2k/tests/testData/ast/issues/spaceBeforeAssignment.kt @@ -0,0 +1,6 @@ +import java.util.* +import kotlin.List + +class A() { + var list: List = ArrayList() +} \ No newline at end of file From c458993fedb19631609614b3ea6092a4f7f93685 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 14:37:05 +0400 Subject: [PATCH 086/143] Java to Kotlin converter: fixed bug with unnecessary "run { }" construct generated in loop body --- j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt | 2 +- .../jet/j2k/test/JavaToKotlinConverterTestGenerated.java | 5 +++++ j2k/tests/testData/ast/for/infiniteFor.java | 6 ++++++ j2k/tests/testData/ast/for/infiniteFor.kt | 5 +++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 j2k/tests/testData/ast/for/infiniteFor.java create mode 100644 j2k/tests/testData/ast/for/infiniteFor.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index ab314010adf..2bcdc76238e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -130,7 +130,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito val updateConverted = converter.convertStatement(update) val whileBody = if (updateConverted.isEmpty) { - converter.convertStatement(body) + convertStatementOrBlock(body) } else if (body is PsiBlockStatement) { val nameConflict = initialization is PsiDeclarationStatement && initialization.getDeclaredElements().any { loopVar -> diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 16a6f7db03a..542b632ad73 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -1177,6 +1177,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/for/forWithReturn.java"); } + @TestMetadata("infiniteFor.java") + public void testInfiniteFor() throws Exception { + doTest("j2k/tests/testData/ast/for/infiniteFor.java"); + } + } @TestMetadata("j2k/tests/testData/ast/foreachStatement") diff --git a/j2k/tests/testData/ast/for/infiniteFor.java b/j2k/tests/testData/ast/for/infiniteFor.java new file mode 100644 index 00000000000..4d1092db123 --- /dev/null +++ b/j2k/tests/testData/ast/for/infiniteFor.java @@ -0,0 +1,6 @@ +//method +void foo() { + for(;;) { + if (!stop()) break; + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/for/infiniteFor.kt b/j2k/tests/testData/ast/for/infiniteFor.kt new file mode 100644 index 00000000000..2bf8960aea3 --- /dev/null +++ b/j2k/tests/testData/ast/for/infiniteFor.kt @@ -0,0 +1,5 @@ +fun foo() { + while (true) { + if (!stop()) break + } +} \ No newline at end of file From 4e7c7fc625c2595df6802cb9ae7585b6a943123a Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 14:56:58 +0400 Subject: [PATCH 087/143] Fixed KT-5299 J2K: When generating named this@type, do not insert FQN #KT-5299 Fixed --- .../org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt | 8 ++++---- .../testData/ast/superExpression/classAdotSuperFoo.java | 2 ++ .../testData/ast/superExpression/classAdotSuperFoo.kt | 2 ++ .../testData/ast/thisExpression/classAdotThisFoo.java | 2 ++ j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt | 2 ++ 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 52ad3fe0a75..2a17fa10bbd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -358,13 +358,13 @@ class ExpressionVisitor(private val converter: Converter, } override fun visitSuperExpression(expression: PsiSuperExpression) { - val qualifier = expression.getQualifier() - result = SuperExpression(if (qualifier != null) Identifier(qualifier.getQualifiedName()!!) else Identifier.Empty) + val qualifier = expression.getQualifier()?.getReferenceName() + result = SuperExpression(if (qualifier != null) Identifier(qualifier) else Identifier.Empty) } override fun visitThisExpression(expression: PsiThisExpression) { - val qualifier = expression.getQualifier() - result = ThisExpression(if (qualifier != null) Identifier(qualifier.getQualifiedName()!!) else Identifier.Empty) + val qualifier = expression.getQualifier()?.getReferenceName() + result = ThisExpression(if (qualifier != null) Identifier(qualifier) else Identifier.Empty) } override fun visitTypeCastExpression(expression: PsiTypeCastExpression) { diff --git a/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.java b/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.java index 2f5f53113af..33cea2861b2 100644 --- a/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.java +++ b/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.java @@ -1,4 +1,6 @@ //file +package a.b; + class Base { void foo(); } diff --git a/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt b/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt index dbbc9f934db..1585ecae8d1 100644 --- a/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt +++ b/j2k/tests/testData/ast/superExpression/classAdotSuperFoo.kt @@ -1,3 +1,5 @@ +package a.b + class Base() { fun foo() } diff --git a/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.java b/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.java index 0d2259d6e9b..fa564c172e7 100644 --- a/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.java +++ b/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.java @@ -1,4 +1,6 @@ //file +package a.b + class Base { void foo() {} } diff --git a/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt b/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt index f8802aeaba4..f32bed7d370 100644 --- a/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt +++ b/j2k/tests/testData/ast/thisExpression/classAdotThisFoo.kt @@ -1,3 +1,5 @@ +package a.b + class Base() { fun foo() { } From 93657419184248d64c9052ddb3234cdeef1ac91f Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 15:07:29 +0400 Subject: [PATCH 088/143] Renamed test data file --- j2k/tests/testData/ast/comments/{Comments.kt => сomments.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename j2k/tests/testData/ast/comments/{Comments.kt => сomments.kt} (100%) diff --git a/j2k/tests/testData/ast/comments/Comments.kt b/j2k/tests/testData/ast/comments/сomments.kt similarity index 100% rename from j2k/tests/testData/ast/comments/Comments.kt rename to j2k/tests/testData/ast/comments/сomments.kt From 04e2d3da584e91de7f80f61b1be9940e741a2281 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 19:03:49 +0400 Subject: [PATCH 089/143] Java to Kotlin converter: no explicit type for private and internal fields when possible --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 18 ++++++--- .../jetbrains/jet/j2k/ConverterSettings.kt | 7 ++-- .../org/jetbrains/jet/j2k/TypeConverter.kt | 37 +++++++++++++++---- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 12 +++--- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 9 +++-- j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt | 5 +++ j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 16 +++++++- .../jetbrains/jet/j2k/visitors/TypeVisitor.kt | 3 ++ .../test/AbstractJavaToKotlinConverterTest.kt | 1 + .../JavaToKotlinConverterTestGenerated.java | 10 +++++ .../ast/annotations/annotationUsages.kt | 8 ++-- .../ast/annotations/jetbrainsNotNull.kt | 2 +- .../testData/ast/class/classWithFields.kt | 4 +- .../ast/class/classWithMultiplyFields.kt | 2 +- .../ast/class/oneStaticFieldOneNonStatic.kt | 2 +- j2k/tests/testData/ast/comments/comments2.kt | 2 +- .../ast/comments/fieldWithEndOfLineComment.kt | 2 +- .../ast/constructors/genericIdentifier.kt | 2 +- .../testData/ast/constructors/identifier.kt | 2 +- j2k/tests/testData/ast/field/specifyType.java | 28 ++++++++++++++ j2k/tests/testData/ast/field/specifyType.kt | 29 +++++++++++++++ j2k/tests/testData/ast/field/valWithInit.kt | 2 +- j2k/tests/testData/ast/field/varWithInit.kt | 2 +- .../ast/formatting/nonStaticMembers.kt | 2 +- .../nonStaticMembersWithComments.kt | 2 +- .../staticAndNonStaticMembersWithComments.kt | 2 +- .../formatting/staticMembersWithComments.kt | 2 +- j2k/tests/testData/ast/issues/kt-638.kt | 2 +- .../testData/ast/issues/kt-809-string.kt | 4 +- j2k/tests/testData/ast/issues/kt-809.kt | 4 +- j2k/tests/testData/ast/issues/kt-820-field.kt | 4 +- j2k/tests/testData/ast/issues/kt-820.kt | 4 +- j2k/tests/testData/ast/issues/kt-824.kt | 4 +- j2k/tests/testData/ast/issues/kt-837.kt | 2 +- j2k/tests/testData/ast/issues/kt-963.kt | 2 +- .../MethodResultInitializesNullableField.kt | 2 +- .../settings/specifyFieldTypeByDefault.java | 17 +++++++++ .../ast/settings/specifyFieldTypeByDefault.kt | 16 ++++++++ .../ast/staticMembers/PrivateStaticMembers.kt | 2 +- 39 files changed, 214 insertions(+), 62 deletions(-) create mode 100644 j2k/tests/testData/ast/field/specifyType.java create mode 100644 j2k/tests/testData/ast/field/specifyType.kt create mode 100644 j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java create mode 100644 j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 05375a6ddbf..2005a5fd671 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -271,7 +271,7 @@ public class Converter private(val project: Project, val settings: ConverterSett return Initializer(convertBlock(initializer.getBody()), convertModifiers(initializer)).assignPrototype(initializer) } - private fun convertField(field: PsiField): Field { + private fun convertField(field: PsiField): Member { val annotations = convertAnnotations(field) val modifiers = convertModifiers(field) val name = field.declarationIdentifier() @@ -283,12 +283,20 @@ public class Converter private(val project: Project, val settings: ConverterSett convertElement(field.getArgumentList())) } else { + val initializer = field.getInitializer() + val convertedType = typeConverter.convertVariableType(field) + val isVal = field.hasModifierProperty(PsiModifier.FINAL) + val omitType = !settings.specifyFieldTypeByDefault && + initializer != null && + (modifiers.isPrivate && (isVal || convertedType == typeConverter.convertExpressionType(initializer)) || + modifiers.isInternal && convertedType == typeConverter.convertExpressionType(initializer)) Field(name, annotations, modifiers, - typeConverter.convertVariableType(field), - convertExpression(field.getInitializer(), field.getType()), - field.hasModifierProperty(PsiModifier.FINAL), + convertedType, + convertExpression(initializer, field.getType()), + isVal, + !omitType, field.hasWriteAccesses(field.getContainingClass())) } return converted.assignPrototype(field) @@ -324,7 +332,7 @@ public class Converter private(val project: Project, val settings: ConverterSett if (settings.openByDefault) { val isEffectivelyFinal = method.hasModifierProperty(PsiModifier.FINAL) || containingClass != null && (containingClass.hasModifierProperty(PsiModifier.FINAL) || containingClass.isEnum()) - if (!isEffectivelyFinal && !modifiers.contains(Modifier.ABSTRACT) && !modifiers.contains(Modifier.PRIVATE)) { + if (!isEffectivelyFinal && !modifiers.contains(Modifier.ABSTRACT) && !modifiers.isPrivate) { modifiers = modifiers.with(Modifier.OPEN) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ConverterSettings.kt b/j2k/src/org/jetbrains/jet/j2k/ConverterSettings.kt index 736163d24bd..0b54d5e48f3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ConverterSettings.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ConverterSettings.kt @@ -16,20 +16,19 @@ package org.jetbrains.jet.j2k -public class ConverterSettings( +public data class ConverterSettings( var forceNotNullTypes: Boolean, var forceLocalVariableImmutability: Boolean, var specifyLocalVariableTypeByDefault: Boolean, + var specifyFieldTypeByDefault: Boolean, var openByDefault: Boolean) { - public fun copy(): ConverterSettings - = ConverterSettings(forceNotNullTypes, forceLocalVariableImmutability, specifyLocalVariableTypeByDefault, openByDefault) - class object { public val defaultSettings: ConverterSettings = ConverterSettings( forceNotNullTypes = true, forceLocalVariableImmutability = true, specifyLocalVariableTypeByDefault = false, + specifyFieldTypeByDefault = false, openByDefault = false ) } diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 0611a67d5bb..395e6f5eacf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -88,7 +88,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver if (nullability == Nullability.Default) { val initializer = variable.getInitializer() if (initializer != null) { - val initializerNullability = initializer.nullability() + val initializerNullability = initializer.nullability(false) if (variable.isEffectivelyFinal()) { nullability = initializerNullability } @@ -129,7 +129,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver for (call in findMethodCalls(method, scope)) { val args = call.getArgumentList().getExpressions() if (args.size == parameters.size) { - if (args[parameterIndex].nullability() == Nullability.Nullable) { + if (args[parameterIndex].nullability(false) == Nullability.Nullable) { nullability = Nullability.Nullable break } @@ -166,7 +166,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver if (nullability == Nullability.Default) { method.getBody()?.accept(object: JavaRecursiveElementVisitor() { override fun visitReturnStatement(statement: PsiReturnStatement) { - if (statement.getReturnValue()?.nullability() == Nullability.Nullable) { + if (statement.getReturnValue()?.nullability(false) == Nullability.Nullable) { nullability = Nullability.Nullable } } @@ -189,6 +189,10 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver return nullability } + public fun convertExpressionType(expression: PsiExpression): Type { + return convertType(expression.getType(), expression.nullability(true)) + } + private fun searchScope(element: PsiElement): PsiElement? { return when(element) { is PsiParameter -> element.getDeclarationScope() @@ -199,22 +203,39 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver } } - private fun PsiExpression.nullability(): Nullability { + private fun PsiExpression.nullability(useDeclarationsNullability: Boolean): Nullability { return when (this) { is PsiLiteralExpression -> if (getType() != PsiType.NULL) Nullability.NotNull else Nullability.Nullable is PsiNewExpression -> Nullability.NotNull is PsiConditionalExpression -> { - val nullability1 = getThenExpression()?.nullability() + val nullability1 = getThenExpression()?.nullability(useDeclarationsNullability) if (nullability1 == Nullability.Nullable) return Nullability.Nullable - val nullability2 = getElseExpression()?.nullability() + val nullability2 = getElseExpression()?.nullability(useDeclarationsNullability) if (nullability2 == Nullability.Nullable) return Nullability.Nullable if (nullability1 == Nullability.NotNull && nullability2 == Nullability.NotNull) return Nullability.NotNull Nullability.Default } - is PsiParenthesizedExpression -> getExpression()?.nullability() ?: Nullability.Default + is PsiParenthesizedExpression -> getExpression()?.nullability(useDeclarationsNullability) ?: Nullability.Default + + is PsiMethodCallExpression -> if (useDeclarationsNullability) { + val method = resolveMethod() + if (method != null) methodNullability(method) else Nullability.Default + } + else { + Nullability.Default + } + + is PsiReferenceExpression -> if (useDeclarationsNullability) { + val variable = resolve() as? PsiVariable + if (variable != null) variableNullability(variable) else Nullability.Default + } + else { + Nullability.Default + } + //TODO: some other cases @@ -225,7 +246,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver private fun isNullableFromUsage(usage: PsiExpression): Boolean { val parent = usage.getParent() ?: return false if (parent is PsiAssignmentExpression && parent.getOperationTokenType() == JavaTokenType.EQ && usage == parent.getLExpression()) { - return parent.getRExpression()?.nullability() == Nullability.Nullable + return parent.getRExpression()?.nullability(false) == Nullability.Nullable } else if (parent is PsiBinaryExpression) { val operationType = parent.getOperationTokenType() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index cd4417e9502..21c869e2e81 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -19,20 +19,20 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* class EnumConstant( - identifier: Identifier, + val identifier: Identifier, annotations: Annotations, modifiers: Modifiers, - `type`: Type, - params: Element -) : Field(identifier, annotations, modifiers, `type`.toNotNullType(), params, true, false) { + val `type`: Type, + val params: Element +) : Member(annotations, modifiers) { override fun generateCode(builder: CodeBuilder) { - if (initializer.isEmpty) { + if (params.isEmpty) { builder append annotations append identifier return } - builder append annotations append identifier append " : " append `type` append "(" append initializer append ")" + builder append annotations append identifier append " : " append `type` append "(" append params append ")" } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index 9170924b60a..d0aaa657411 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -18,13 +18,14 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.* -open class Field( +class Field( val identifier: Identifier, annotations: Annotations, modifiers: Modifiers, val `type`: Type, val initializer: Element, val isVal: Boolean, + val explicitType: Boolean, private val hasWriteAccesses: Boolean ) : Member(annotations, modifiers) { @@ -33,8 +34,10 @@ open class Field( .appendWithSpaceAfter(modifiers) .append(if (isVal) "val " else "var ") .append(identifier) - .append(" : ") - .append(`type`) + + if (explicitType) { + builder append ":" append `type` + } var initializerToUse = initializer if (initializerToUse.isEmpty && !(isVal && hasWriteAccesses)) { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt index 405c4079e8d..6335d18c1bc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt @@ -55,6 +55,11 @@ class Modifiers(val modifiers: Collection) : Element() { fun contains(modifier: Modifier): Boolean = modifiers.contains(modifier) + val isPublic: Boolean get() = contains(Modifier.PUBLIC) + val isPrivate: Boolean get() = contains(Modifier.PRIVATE) + val isProtected: Boolean get() = contains(Modifier.PROTECTED) + val isInternal: Boolean get() = !isPublic && !isPrivate && !isProtected + class object { val Empty = Modifiers(listOf()) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 6acfa64caf2..52a9a9698d7 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -48,12 +48,16 @@ abstract class Type() : Element() { abstract val isNullable: Boolean open fun toNotNullType(): Type { - if (isNullable) throw UnsupportedOperationException("toNotNullType must be defined") + if (isNullable) { + throw UnsupportedOperationException("toNotNullType must be defined") + } return this } open fun toNullableType(): Type { - if (!isNullable) throw UnsupportedOperationException("toNullableType must be defined") + if (!isNullable) { + throw UnsupportedOperationException("toNullableType must be defined") + } return this } @@ -69,6 +73,14 @@ abstract class Type() : Element() { } } + object Null: Type() { + override val isNullable: Boolean = true + + override fun generateCode(builder: CodeBuilder) { + builder.append("???") + } + } + override fun equals(other: Any?): Boolean = other is Type && other.canonicalCode() == this.canonicalCode() override fun hashCode(): Int = canonicalCode().hashCode() diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt index 5d9ceb111d9..718835039df 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/TypeVisitor.kt @@ -36,6 +36,9 @@ class TypeVisitor(private val converter: TypeConverter, private val importNames: else if (PRIMITIVE_TYPES_NAMES.contains(name)) { PrimitiveType(Identifier(StringUtil.capitalize(name))) } + else if (name == "null") { + Type.Null + } else { PrimitiveType(Identifier(name)) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index 2c183fbc49b..fee8ec96f9b 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -77,6 +77,7 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { "forceNotNullTypes" -> settings.forceNotNullTypes = parseBoolean(value) "forceLocalVariableImmutability" -> settings.forceLocalVariableImmutability = parseBoolean(value) "specifyLocalVariableTypeByDefault" -> settings.specifyLocalVariableTypeByDefault = parseBoolean(value) + "specifyFieldTypeByDefault" -> settings.specifyFieldTypeByDefault = parseBoolean(value) "openByDefault" -> settings.openByDefault = parseBoolean(value) else -> throw IllegalArgumentException("Unknown option: $name") } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 542b632ad73..0b7c2c6a32a 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -1094,6 +1094,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/field/publicField.java"); } + @TestMetadata("specifyType.java") + public void testSpecifyType() throws Exception { + doTest("j2k/tests/testData/ast/field/specifyType.java"); + } + @TestMetadata("valWithInit.java") public void testValWithInit() throws Exception { doTest("j2k/tests/testData/ast/field/valWithInit.java"); @@ -2354,6 +2359,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/settings/openByDefault.java"); } + @TestMetadata("specifyFieldTypeByDefault.java") + public void testSpecifyFieldTypeByDefault() throws Exception { + doTest("j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java"); + } + @TestMetadata("specifyLocalVariableTypeByDefault.java") public void testSpecifyLocalVariableTypeByDefault() throws Exception { doTest("j2k/tests/testData/ast/settings/specifyLocalVariableTypeByDefault.java"); diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.kt b/j2k/tests/testData/ast/annotations/annotationUsages.kt index ced7214ba69..08497bd912a 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.kt +++ b/j2k/tests/testData/ast/annotations/annotationUsages.kt @@ -9,15 +9,15 @@ Anon6(array("x", "y")) Anon7(javaClass(), javaClass()) Anon8(classes = *array(javaClass(), javaClass())) class C() { - Anon5(1) deprecated("") private var field1: Int = 0 + Anon5(1) deprecated("") private var field1 = 0 Anon5(1) - private var field2: Int = 0 + private var field2 = 0 - Anon5(1) var field3: Int = 0 + Anon5(1) var field3 = 0 Anon5(1) - var field4: Int = 0 + var field4 = 0 Anon6(array()) fun foo(deprecated("") p1: Int, deprecated("") Anon5(2) p2: Char) { diff --git a/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt b/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt index c17e1652311..826a768f9ba 100644 --- a/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt +++ b/j2k/tests/testData/ast/annotations/jetbrainsNotNull.kt @@ -3,7 +3,7 @@ package test public class Test(str: String) { - var myStr: String = "String2" + var myStr = "String2" public fun sout(str: String) { System.out!!.println(str) diff --git a/j2k/tests/testData/ast/class/classWithFields.kt b/j2k/tests/testData/ast/class/classWithFields.kt index 134d4d62abf..c562a60dcfa 100644 --- a/j2k/tests/testData/ast/class/classWithFields.kt +++ b/j2k/tests/testData/ast/class/classWithFields.kt @@ -1,4 +1,4 @@ class T() { - var a: String = "abc" - var b: Int = 10 + var a = "abc" + var b = 10 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/classWithMultiplyFields.kt b/j2k/tests/testData/ast/class/classWithMultiplyFields.kt index 19cbb56f9f5..48202044e1e 100644 --- a/j2k/tests/testData/ast/class/classWithMultiplyFields.kt +++ b/j2k/tests/testData/ast/class/classWithMultiplyFields.kt @@ -1,5 +1,5 @@ class T() { var a: String = 0 var b: String = 0 - var c: String = "abc" + var c = "abc" } \ No newline at end of file diff --git a/j2k/tests/testData/ast/class/oneStaticFieldOneNonStatic.kt b/j2k/tests/testData/ast/class/oneStaticFieldOneNonStatic.kt index fa2ebfe0b04..118a135c79c 100644 --- a/j2k/tests/testData/ast/class/oneStaticFieldOneNonStatic.kt +++ b/j2k/tests/testData/ast/class/oneStaticFieldOneNonStatic.kt @@ -4,6 +4,6 @@ class S() { } class object { - var myI: Int = 10 + var myI = 10 } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/comments2.kt b/j2k/tests/testData/ast/comments/comments2.kt index ae870f41377..fab172ae131 100644 --- a/j2k/tests/testData/ast/comments/comments2.kt +++ b/j2k/tests/testData/ast/comments/comments2.kt @@ -11,7 +11,7 @@ class A() { /* body is empty */ } - private /*it's private*/ var field: Int = 0 + private /*it's private*/ var field = 0 public /*it's public*/ fun foo(): Char { } diff --git a/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt index ec3f0bf94e6..ea603f5e24a 100644 --- a/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt +++ b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt @@ -1,3 +1,3 @@ class A() { - private var isOpen: Boolean = true // ideally should be atomic boolean + private var isOpen = true // ideally should be atomic boolean } \ No newline at end of file diff --git a/j2k/tests/testData/ast/constructors/genericIdentifier.kt b/j2k/tests/testData/ast/constructors/genericIdentifier.kt index bd04550571f..6669d4aaa2f 100644 --- a/j2k/tests/testData/ast/constructors/genericIdentifier.kt +++ b/j2k/tests/testData/ast/constructors/genericIdentifier.kt @@ -1,5 +1,5 @@ public class Identifier private(private val myName: T, private var myHasDollar: Boolean) { - private var myNullable: Boolean = true + private var myNullable = true public fun getName(): T { return myName diff --git a/j2k/tests/testData/ast/constructors/identifier.kt b/j2k/tests/testData/ast/constructors/identifier.kt index 065a38f2edd..ee98211f791 100644 --- a/j2k/tests/testData/ast/constructors/identifier.kt +++ b/j2k/tests/testData/ast/constructors/identifier.kt @@ -1,5 +1,5 @@ public class Identifier private(private val myName: String, private var myHasDollar: Boolean) { - private var myNullable: Boolean = true + private var myNullable = true public fun getName(): String { return myName diff --git a/j2k/tests/testData/ast/field/specifyType.java b/j2k/tests/testData/ast/field/specifyType.java new file mode 100644 index 00000000000..47d819aade2 --- /dev/null +++ b/j2k/tests/testData/ast/field/specifyType.java @@ -0,0 +1,28 @@ +//file +import org.jetbrains.annotations.Nullable; +import java.util.*; + +class A { + private final List field1 = new ArrayList(); + final List field2 = new ArrayList(); + public final int field3 = 0; + protected final int field4 = 0; + + private List field5 = new ArrayList(); + List field6 = new ArrayList(); + + private int field7 = 0; + int field8 = 0; + + @Nullable private String field9 = "a" + @Nullable private String field10 = foo(); + + String foo() { return "x"; } + + void bar() { + field7++; + field8++; + field9 = null; + field10 = null; + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/specifyType.kt b/j2k/tests/testData/ast/field/specifyType.kt new file mode 100644 index 00000000000..9d149164e07 --- /dev/null +++ b/j2k/tests/testData/ast/field/specifyType.kt @@ -0,0 +1,29 @@ +import java.util.* +import kotlin.List + +class A() { + private val field1 = ArrayList() + val field2: List = ArrayList() + public val field3: Int = 0 + protected val field4: Int = 0 + + private var field5: List = ArrayList() + var field6: List = ArrayList() + + private var field7 = 0 + var field8 = 0 + + private var field9: String? = "a" + private var field10: String? = foo() + + fun foo(): String { + return "x" + } + + fun bar() { + field7++ + field8++ + field9 = null + field10 = null + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/valWithInit.kt b/j2k/tests/testData/ast/field/valWithInit.kt index 2d120001aa4..beb1395d375 100644 --- a/j2k/tests/testData/ast/field/valWithInit.kt +++ b/j2k/tests/testData/ast/field/valWithInit.kt @@ -1,3 +1,3 @@ class C() { - val f: Foo = Foo(1, 2) + val f = Foo(1, 2) } \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/varWithInit.kt b/j2k/tests/testData/ast/field/varWithInit.kt index 9238f03f782..ffed0dcc3a5 100644 --- a/j2k/tests/testData/ast/field/varWithInit.kt +++ b/j2k/tests/testData/ast/field/varWithInit.kt @@ -1,3 +1,3 @@ class C() { - var f: Foo = Foo(1, 2) + var f = Foo(1, 2) } \ No newline at end of file diff --git a/j2k/tests/testData/ast/formatting/nonStaticMembers.kt b/j2k/tests/testData/ast/formatting/nonStaticMembers.kt index 72079e2c1e7..33f676dfcd5 100644 --- a/j2k/tests/testData/ast/formatting/nonStaticMembers.kt +++ b/j2k/tests/testData/ast/formatting/nonStaticMembers.kt @@ -5,7 +5,7 @@ class F() { fun f2() { } - var i: Int = 0 + var i = 0 fun f3() { } diff --git a/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt index 61be9023894..ef0256981a4 100644 --- a/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt @@ -16,7 +16,7 @@ class F() { fun f2() { } - var i: Int = 0 + var i = 0 fun f3() { } diff --git a/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt index 482f5783f08..71b50c0348e 100644 --- a/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt @@ -24,7 +24,7 @@ class F() { fun f1() { } - var i: Int = 0 + var i = 0 //c5 diff --git a/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt index 51c1ee14d3c..2dc176320f2 100644 --- a/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt @@ -17,7 +17,7 @@ class F() { fun f2() { } - var i: Int = 0 + var i = 0 fun f3() { } diff --git a/j2k/tests/testData/ast/issues/kt-638.kt b/j2k/tests/testData/ast/issues/kt-638.kt index 211646d6498..cd59e50c894 100644 --- a/j2k/tests/testData/ast/issues/kt-638.kt +++ b/j2k/tests/testData/ast/issues/kt-638.kt @@ -1,5 +1,5 @@ public class Identifier private(private val myName: T, private var myHasDollar: Boolean) { - private var myNullable: Boolean = true + private var myNullable = true public fun getName(): T { return myName diff --git a/j2k/tests/testData/ast/issues/kt-809-string.kt b/j2k/tests/testData/ast/issues/kt-809-string.kt index 5a4bed58e1f..b6e142a9f62 100644 --- a/j2k/tests/testData/ast/issues/kt-809-string.kt +++ b/j2k/tests/testData/ast/issues/kt-809-string.kt @@ -1,12 +1,12 @@ package demo class Container() { - var myString: String = "1" + var myString = "1" } class One() { class object { - var myContainer: Container = Container() + var myContainer = Container() } } diff --git a/j2k/tests/testData/ast/issues/kt-809.kt b/j2k/tests/testData/ast/issues/kt-809.kt index 07d1c14aad1..c5f8865c31c 100644 --- a/j2k/tests/testData/ast/issues/kt-809.kt +++ b/j2k/tests/testData/ast/issues/kt-809.kt @@ -1,12 +1,12 @@ package demo class Container() { - var myInt: Int = 1 + var myInt = 1 } class One() { class object { - var myContainer: Container = Container() + var myContainer = Container() } } diff --git a/j2k/tests/testData/ast/issues/kt-820-field.kt b/j2k/tests/testData/ast/issues/kt-820-field.kt index 83bc0ee2951..897f1a2ce91 100644 --- a/j2k/tests/testData/ast/issues/kt-820-field.kt +++ b/j2k/tests/testData/ast/issues/kt-820-field.kt @@ -1,12 +1,12 @@ package demo class Container() { - var myInt: Int = 1 + var myInt = 1 } class One() { class object { - var myContainer: Container = Container() + var myContainer = Container() } } diff --git a/j2k/tests/testData/ast/issues/kt-820.kt b/j2k/tests/testData/ast/issues/kt-820.kt index e654ea3b795..fc630979d15 100644 --- a/j2k/tests/testData/ast/issues/kt-820.kt +++ b/j2k/tests/testData/ast/issues/kt-820.kt @@ -1,12 +1,12 @@ package demo class Container() { - var myInt: Int = 1 + var myInt = 1 } class One() { class object { - var myContainer: Container = Container() + var myContainer = Container() } } diff --git a/j2k/tests/testData/ast/issues/kt-824.kt b/j2k/tests/testData/ast/issues/kt-824.kt index 564d50a4afd..d7d016b07b8 100644 --- a/j2k/tests/testData/ast/issues/kt-824.kt +++ b/j2k/tests/testData/ast/issues/kt-824.kt @@ -1,12 +1,12 @@ package demo class Container() { - var myBoolean: Boolean = true + var myBoolean = true } class One() { class object { - var myContainer: Container = Container() + var myContainer = Container() } } diff --git a/j2k/tests/testData/ast/issues/kt-837.kt b/j2k/tests/testData/ast/issues/kt-837.kt index 0a85e5bb9cc..b6b3bef0653 100644 --- a/j2k/tests/testData/ast/issues/kt-837.kt +++ b/j2k/tests/testData/ast/issues/kt-837.kt @@ -11,6 +11,6 @@ public class Language(protected var code: String) : Serializable { class object { public var ENGLISH: Language = Language("en") public var SWEDISH: Language = Language("sv") - private val serialVersionUID: Long = -2442762969929206780 + private val serialVersionUID = -2442762969929206780 } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-963.kt b/j2k/tests/testData/ast/issues/kt-963.kt index b3a33d854cd..e2ec0dd01ab 100644 --- a/j2k/tests/testData/ast/issues/kt-963.kt +++ b/j2k/tests/testData/ast/issues/kt-963.kt @@ -1,7 +1,7 @@ package demo class C(a: Int) { - var abc: Int = 0 + var abc = 0 { abc = a * 2 diff --git a/j2k/tests/testData/ast/nullability/MethodResultInitializesNullableField.kt b/j2k/tests/testData/ast/nullability/MethodResultInitializesNullableField.kt index 3bde9e28c4b..de5326c20b9 100644 --- a/j2k/tests/testData/ast/nullability/MethodResultInitializesNullableField.kt +++ b/j2k/tests/testData/ast/nullability/MethodResultInitializesNullableField.kt @@ -1,5 +1,5 @@ class C() { - private val string: String? = getString() + private val string = getString() class object { diff --git a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java new file mode 100644 index 00000000000..bb34adba462 --- /dev/null +++ b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java @@ -0,0 +1,17 @@ +//file +// !specifyFieldTypeByDefault: true +import org.jetbrains.annotations.Nullable; +import java.util.*; + +class A { + private final List field1 = new ArrayList(); + final List field2 = new ArrayList(); + public final int field3 = 0; + protected final int field4 = 0; + + private List field5 = new ArrayList(); + List field6 = new ArrayList(); + + private int field7 = 0; + int field8 = 0; +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt new file mode 100644 index 00000000000..fa48c065aa7 --- /dev/null +++ b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt @@ -0,0 +1,16 @@ +// !specifyFieldTypeByDefault: true +import java.util.* +import kotlin.List + +class A() { + private val field1: List = ArrayList() + val field2: List = ArrayList() + public val field3: Int = 0 + protected val field4: Int = 0 + + private var field5: List = ArrayList() + var field6: List = ArrayList() + + private var field7: Int = 0 + var field8: Int = 0 +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt b/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt index d02168a612e..b44c55a1b3e 100644 --- a/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt +++ b/j2k/tests/testData/ast/staticMembers/PrivateStaticMembers.kt @@ -6,7 +6,7 @@ class A() { } class object { - private val s: String = "abc" + private val s = "abc" private fun privateStatic1() { } From 07bbab3ea02624054f24e7a0b78a707408134cbb Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 19:14:42 +0400 Subject: [PATCH 090/143] Java to Kotlin converter: fixed bug --- j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt | 3 +++ j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 14 ++------------ .../test/JavaToKotlinConverterTestGenerated.java | 5 +++++ .../ast/nullability/NullableIntNoCrash.java | 8 ++++++++ .../testData/ast/nullability/NullableIntNoCrash.kt | 7 +++++++ 5 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 j2k/tests/testData/ast/nullability/NullableIntNoCrash.java create mode 100644 j2k/tests/testData/ast/nullability/NullableIntNoCrash.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 395e6f5eacf..4458f631e5c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -69,6 +69,7 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver private fun variableNullabilityNoCache(variable: PsiVariable): Nullability { if (variable is PsiEnumConstant) return Nullability.NotNull + if (variable.getType() is PsiPrimitiveType) return Nullability.NotNull var nullability = variable.nullabilityFromAnnotations() @@ -154,6 +155,8 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver } private fun methodNullabilityNoCache(method: PsiMethod): Nullability { + if (method.getReturnType() is PsiPrimitiveType) return Nullability.NotNull + var nullability = method.nullabilityFromAnnotations() if (nullability == Nullability.Default) { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 52a9a9698d7..344a4e02bdf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -47,19 +47,9 @@ abstract class NotNullType() : Type() { abstract class Type() : Element() { abstract val isNullable: Boolean - open fun toNotNullType(): Type { - if (isNullable) { - throw UnsupportedOperationException("toNotNullType must be defined") - } - return this - } + open fun toNotNullType(): Type = this - open fun toNullableType(): Type { - if (!isNullable) { - throw UnsupportedOperationException("toNullableType must be defined") - } - return this - } + open fun toNullableType(): Type = this object Empty : NotNullType() { override fun generateCode(builder: CodeBuilder) { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 0b7c2c6a32a..5c3604760dc 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -2084,6 +2084,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/nullability/MethodReturnsTernaryNull.java"); } + @TestMetadata("NullableIntNoCrash.java") + public void testNullableIntNoCrash() throws Exception { + doTest("j2k/tests/testData/ast/nullability/NullableIntNoCrash.java"); + } + @TestMetadata("NullableMethodDotAccess.java") public void testNullableMethodDotAccess() throws Exception { doTest("j2k/tests/testData/ast/nullability/NullableMethodDotAccess.java"); diff --git a/j2k/tests/testData/ast/nullability/NullableIntNoCrash.java b/j2k/tests/testData/ast/nullability/NullableIntNoCrash.java new file mode 100644 index 00000000000..ba4276df19f --- /dev/null +++ b/j2k/tests/testData/ast/nullability/NullableIntNoCrash.java @@ -0,0 +1,8 @@ +import org.jetbrains.annotations.Nullable; + +//file +class A { + int field = foo(); + + @Nullable int foo() { return 1; } +} diff --git a/j2k/tests/testData/ast/nullability/NullableIntNoCrash.kt b/j2k/tests/testData/ast/nullability/NullableIntNoCrash.kt new file mode 100644 index 00000000000..83dda3a4ae5 --- /dev/null +++ b/j2k/tests/testData/ast/nullability/NullableIntNoCrash.kt @@ -0,0 +1,7 @@ +class A() { + var field = foo() + + fun foo(): Int { + return 1 + } +} \ No newline at end of file From 5a8ab4194833c627de7d23ec4df87d5f269bdd08 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 19:28:37 +0400 Subject: [PATCH 091/143] Java to Kotlin converter: declare private field with no writes as val --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt | 9 --------- j2k/src/org/jetbrains/jet/j2k/Utils.kt | 11 ++++++++++- .../test/JavaToKotlinConverterTestGenerated.java | 5 +++++ .../testData/ast/annotations/annotationUsages.kt | 4 ++-- j2k/tests/testData/ast/comments/comments2.kt | 2 +- .../ast/comments/fieldWithEndOfLineComment.kt | 2 +- .../ast/constructors/withManyDefaultParams.java | 14 +++++++------- .../ast/constructors/withManyDefaultParams.kt | 2 +- j2k/tests/testData/ast/enum/enumWithNameField.kt | 2 +- .../testData/ast/field/classChildExtendsBase.kt | 4 ++-- j2k/tests/testData/ast/field/privateField.kt | 2 +- j2k/tests/testData/ast/field/specifyType.java | 1 + j2k/tests/testData/ast/field/specifyType.kt | 1 + j2k/tests/testData/ast/field/valOrVar.java | 12 ++++++++++++ j2k/tests/testData/ast/field/valOrVar.kt | 11 +++++++++++ j2k/tests/testData/ast/issues/comments.kt | 2 +- .../ast/nullability/FieldComparedWithNull.kt | 2 +- .../ast/settings/specifyFieldTypeByDefault.java | 6 ------ .../ast/settings/specifyFieldTypeByDefault.kt | 6 ------ 20 files changed, 59 insertions(+), 41 deletions(-) create mode 100644 j2k/tests/testData/ast/field/valOrVar.java create mode 100644 j2k/tests/testData/ast/field/valOrVar.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 2005a5fd671..297c7cfbcca 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -285,7 +285,7 @@ public class Converter private(val project: Project, val settings: ConverterSett else { val initializer = field.getInitializer() val convertedType = typeConverter.convertVariableType(field) - val isVal = field.hasModifierProperty(PsiModifier.FINAL) + val isVal = field.isEffectivelyFinal() val omitType = !settings.specifyFieldTypeByDefault && initializer != null && (modifiers.isPrivate && (isVal || convertedType == typeConverter.convertExpressionType(initializer)) || diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 4458f631e5c..5b8b4c8e6c5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -263,13 +263,4 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver } return false } - - private fun PsiVariable.isEffectivelyFinal(): Boolean { - if (hasModifierProperty(PsiModifier.FINAL)) return true - return when(this) { - is PsiLocalVariable -> !hasWriteAccesses(getContainingMethod()) - is PsiField -> if (hasModifierProperty(PsiModifier.PRIVATE)) !hasWriteAccesses(getContainingClass()) else false - else -> false - } - } } diff --git a/j2k/src/org/jetbrains/jet/j2k/Utils.kt b/j2k/src/org/jetbrains/jet/j2k/Utils.kt index 13b83b6e1ab..6ab6d8bd4b5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Utils.kt @@ -92,4 +92,13 @@ fun PsiElement.isInSingleLine(): Boolean { child = child!!.getNextSibling() } return true -} \ No newline at end of file +} + +fun PsiVariable.isEffectivelyFinal(): Boolean { + if (hasModifierProperty(PsiModifier.FINAL)) return true + return when(this) { + is PsiLocalVariable -> !hasWriteAccesses(getContainingMethod()) + is PsiField -> if (hasModifierProperty(PsiModifier.PRIVATE)) !hasWriteAccesses(getContainingClass()) else false + else -> false + } +} diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 5c3604760dc..db113760629 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -1099,6 +1099,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/field/specifyType.java"); } + @TestMetadata("valOrVar.java") + public void testValOrVar() throws Exception { + doTest("j2k/tests/testData/ast/field/valOrVar.java"); + } + @TestMetadata("valWithInit.java") public void testValWithInit() throws Exception { doTest("j2k/tests/testData/ast/field/valWithInit.java"); diff --git a/j2k/tests/testData/ast/annotations/annotationUsages.kt b/j2k/tests/testData/ast/annotations/annotationUsages.kt index 08497bd912a..93e135f82af 100644 --- a/j2k/tests/testData/ast/annotations/annotationUsages.kt +++ b/j2k/tests/testData/ast/annotations/annotationUsages.kt @@ -9,10 +9,10 @@ Anon6(array("x", "y")) Anon7(javaClass(), javaClass()) Anon8(classes = *array(javaClass(), javaClass())) class C() { - Anon5(1) deprecated("") private var field1 = 0 + Anon5(1) deprecated("") private val field1 = 0 Anon5(1) - private var field2 = 0 + private val field2 = 0 Anon5(1) var field3 = 0 diff --git a/j2k/tests/testData/ast/comments/comments2.kt b/j2k/tests/testData/ast/comments/comments2.kt index fab172ae131..0760fa55820 100644 --- a/j2k/tests/testData/ast/comments/comments2.kt +++ b/j2k/tests/testData/ast/comments/comments2.kt @@ -11,7 +11,7 @@ class A() { /* body is empty */ } - private /*it's private*/ var field = 0 + private /*it's private*/ val field = 0 public /*it's public*/ fun foo(): Char { } diff --git a/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt index ea603f5e24a..4390146f416 100644 --- a/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt +++ b/j2k/tests/testData/ast/comments/fieldWithEndOfLineComment.kt @@ -1,3 +1,3 @@ class A() { - private var isOpen = true // ideally should be atomic boolean + private val isOpen = true // ideally should be atomic boolean } \ No newline at end of file diff --git a/j2k/tests/testData/ast/constructors/withManyDefaultParams.java b/j2k/tests/testData/ast/constructors/withManyDefaultParams.java index 2940814308f..659c10b522c 100644 --- a/j2k/tests/testData/ast/constructors/withManyDefaultParams.java +++ b/j2k/tests/testData/ast/constructors/withManyDefaultParams.java @@ -1,13 +1,13 @@ //file public class Test { private final String myName; - private boolean a; - private double b; - private float c; - private long d; - private int e; - private short f; - private char g; + boolean a; + double b; + float c; + long d; + int e; + protected short f; + protected char g; public Test() {} diff --git a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt index 2e19d45aa08..5afaeb3f3d6 100644 --- a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt +++ b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt @@ -1,4 +1,4 @@ -public class Test private(private val myName: String, private var a: Boolean, private var b: Double, private var c: Float, private var d: Long, private var e: Int, private var f: Short, private var g: Char) { +public class Test private(private val myName: String, var a: Boolean, var b: Double, var c: Float, var d: Long, var e: Int, protected var f: Short, protected var g: Char) { class object { public fun create(): Test { diff --git a/j2k/tests/testData/ast/enum/enumWithNameField.kt b/j2k/tests/testData/ast/enum/enumWithNameField.kt index 4dbfe1f26ac..578630d8058 100644 --- a/j2k/tests/testData/ast/enum/enumWithNameField.kt +++ b/j2k/tests/testData/ast/enum/enumWithNameField.kt @@ -1,4 +1,4 @@ enum class E { I - private var name: String = 0 + private val name: String = 0 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/classChildExtendsBase.kt b/j2k/tests/testData/ast/field/classChildExtendsBase.kt index 13bc6b8db49..c3cc9fc054a 100644 --- a/j2k/tests/testData/ast/field/classChildExtendsBase.kt +++ b/j2k/tests/testData/ast/field/classChildExtendsBase.kt @@ -1,7 +1,7 @@ class Base() { - private var myFirst: String = 0 + private val myFirst: String = 0 } class Child() : Base() { - private var mySecond: String = 0 + private val mySecond: String = 0 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/privateField.kt b/j2k/tests/testData/ast/field/privateField.kt index f321996b3fe..f3e87b44ca0 100644 --- a/j2k/tests/testData/ast/field/privateField.kt +++ b/j2k/tests/testData/ast/field/privateField.kt @@ -1,3 +1,3 @@ class C() { - private var f: Foo = 0 + private val f: Foo = 0 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/specifyType.java b/j2k/tests/testData/ast/field/specifyType.java index 47d819aade2..14a0e0cf7db 100644 --- a/j2k/tests/testData/ast/field/specifyType.java +++ b/j2k/tests/testData/ast/field/specifyType.java @@ -20,6 +20,7 @@ class A { String foo() { return "x"; } void bar() { + field5 = new ArrayList(); field7++; field8++; field9 = null; diff --git a/j2k/tests/testData/ast/field/specifyType.kt b/j2k/tests/testData/ast/field/specifyType.kt index 9d149164e07..57d4029693f 100644 --- a/j2k/tests/testData/ast/field/specifyType.kt +++ b/j2k/tests/testData/ast/field/specifyType.kt @@ -21,6 +21,7 @@ class A() { } fun bar() { + field5 = ArrayList() field7++ field8++ field9 = null diff --git a/j2k/tests/testData/ast/field/valOrVar.java b/j2k/tests/testData/ast/field/valOrVar.java new file mode 100644 index 00000000000..1d292dbfc26 --- /dev/null +++ b/j2k/tests/testData/ast/field/valOrVar.java @@ -0,0 +1,12 @@ +//file +class A { + private final int field1 = 0; + private int field2 = 0; + private int field3 = 0; + final int field4 = 0; + int field5 = 0; + + void foo() { + field3 = field2; + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/field/valOrVar.kt b/j2k/tests/testData/ast/field/valOrVar.kt new file mode 100644 index 00000000000..68817a0b885 --- /dev/null +++ b/j2k/tests/testData/ast/field/valOrVar.kt @@ -0,0 +1,11 @@ +class A() { + private val field1 = 0 + private val field2 = 0 + private var field3 = 0 + val field4 = 0 + var field5 = 0 + + fun foo() { + field3 = field2 + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/comments.kt b/j2k/tests/testData/ast/issues/comments.kt index fc29fd34d76..9ccc6394f66 100644 --- a/j2k/tests/testData/ast/issues/comments.kt +++ b/j2k/tests/testData/ast/issues/comments.kt @@ -15,7 +15,7 @@ class C() { /** * This is a field doc comment. */ - private var i: Int = 0 + private val i: Int = 0 /** * This is a function doc comment. diff --git a/j2k/tests/testData/ast/nullability/FieldComparedWithNull.kt b/j2k/tests/testData/ast/nullability/FieldComparedWithNull.kt index 7b8d014387f..f959711ac1e 100644 --- a/j2k/tests/testData/ast/nullability/FieldComparedWithNull.kt +++ b/j2k/tests/testData/ast/nullability/FieldComparedWithNull.kt @@ -1,5 +1,5 @@ class C() { - private var s: String? = x() + private val s = x() fun foo() { if (s == null) { diff --git a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java index bb34adba462..e8bf96c57d5 100644 --- a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java +++ b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.java @@ -8,10 +8,4 @@ class A { final List field2 = new ArrayList(); public final int field3 = 0; protected final int field4 = 0; - - private List field5 = new ArrayList(); - List field6 = new ArrayList(); - - private int field7 = 0; - int field8 = 0; } \ No newline at end of file diff --git a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt index fa48c065aa7..72942153033 100644 --- a/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt +++ b/j2k/tests/testData/ast/settings/specifyFieldTypeByDefault.kt @@ -7,10 +7,4 @@ class A() { val field2: List = ArrayList() public val field3: Int = 0 protected val field4: Int = 0 - - private var field5: List = ArrayList() - var field6: List = ArrayList() - - private var field7: Int = 0 - var field8: Int = 0 } \ No newline at end of file From e38b1b4fd888bc68ed369bf9cdf1655df2e46f79 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 20:11:06 +0400 Subject: [PATCH 092/143] Java to Kotlin converter: more cases when field can be declared as val --- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 27 +++++++++++++++++-- .../org/jetbrains/jet/j2k/TypeConverter.kt | 9 +++++++ j2k/src/org/jetbrains/jet/j2k/Utils.kt | 9 ------- .../ast/constructors/genericIdentifier.kt | 2 +- .../testData/ast/constructors/identifier.kt | 2 +- .../fieldsWithPrimaryPrivateConstructor.kt | 2 +- .../ast/enum/primaryPrivateConstructor.kt | 2 +- j2k/tests/testData/ast/field/valOrVar.java | 17 ++++++++++++ j2k/tests/testData/ast/field/valOrVar.kt | 15 ++++++++++- .../inheritance/classOneExtendsBaseGeneric.kt | 2 +- ...dsBaseWithZeroParamsNonEmptyConstructor.kt | 2 +- j2k/tests/testData/ast/issues/kt-638.kt | 2 +- .../ast/nullability/FieldComparedWithNull2.kt | 2 +- .../ast/nullability/FieldComparedWithNull4.kt | 2 +- 14 files changed, 74 insertions(+), 21 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 297c7cfbcca..b33d95ba986 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -285,7 +285,7 @@ public class Converter private(val project: Project, val settings: ConverterSett else { val initializer = field.getInitializer() val convertedType = typeConverter.convertVariableType(field) - val isVal = field.isEffectivelyFinal() + val isVal = isVal(field) val omitType = !settings.specifyFieldTypeByDefault && initializer != null && (modifiers.isPrivate && (isVal || convertedType == typeConverter.convertExpressionType(initializer)) || @@ -302,6 +302,29 @@ public class Converter private(val project: Project, val settings: ConverterSett return converted.assignPrototype(field) } + private fun isVal(field: PsiField): Boolean { + if (field.hasModifierProperty(PsiModifier.FINAL)) return true + if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false + val containingClass = field.getContainingClass() ?: return false + val writes = findVariableUsages(field, containingClass).filter { PsiUtil.isAccessedForWriting(it) } + if (writes.size == 0) return true + if (writes.size > 1) return false + val write = writes.single() + val parent = write.getParent() + if (parent is PsiAssignmentExpression && + parent.getOperationSign().getTokenType() == JavaTokenType.EQ && + isQualifierEmptyOrThis(write)) { + val constructor = write.getContainingConstructor() + if (constructor != null && + constructor.getContainingClass() == containingClass && + parent.getParent() is PsiExpressionStatement && + parent.getParent()?.getParent() == constructor.getBody()) { + return true + } + } + return false + } + private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove).assignPrototype(method) } @@ -428,7 +451,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val (field, `type`) = parameterToField[parameter]!! Parameter(field.declarationIdentifier(), `type`, - if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var, + if (isVal(field)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var, convertAnnotations(parameter) + convertAnnotations(field), convertModifiers(field).filter { it in ACCESS_MODIFIERS }).assignPrototypes(listOf(parameter, field), inheritBlankLinesBefore = false) } diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 5b8b4c8e6c5..4458f631e5c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -263,4 +263,13 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver } return false } + + private fun PsiVariable.isEffectivelyFinal(): Boolean { + if (hasModifierProperty(PsiModifier.FINAL)) return true + return when(this) { + is PsiLocalVariable -> !hasWriteAccesses(getContainingMethod()) + is PsiField -> if (hasModifierProperty(PsiModifier.PRIVATE)) !hasWriteAccesses(getContainingClass()) else false + else -> false + } + } } diff --git a/j2k/src/org/jetbrains/jet/j2k/Utils.kt b/j2k/src/org/jetbrains/jet/j2k/Utils.kt index 6ab6d8bd4b5..eee0ce84cfe 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Utils.kt @@ -93,12 +93,3 @@ fun PsiElement.isInSingleLine(): Boolean { } return true } - -fun PsiVariable.isEffectivelyFinal(): Boolean { - if (hasModifierProperty(PsiModifier.FINAL)) return true - return when(this) { - is PsiLocalVariable -> !hasWriteAccesses(getContainingMethod()) - is PsiField -> if (hasModifierProperty(PsiModifier.PRIVATE)) !hasWriteAccesses(getContainingClass()) else false - else -> false - } -} diff --git a/j2k/tests/testData/ast/constructors/genericIdentifier.kt b/j2k/tests/testData/ast/constructors/genericIdentifier.kt index 6669d4aaa2f..e569d2ca8b5 100644 --- a/j2k/tests/testData/ast/constructors/genericIdentifier.kt +++ b/j2k/tests/testData/ast/constructors/genericIdentifier.kt @@ -1,4 +1,4 @@ -public class Identifier private(private val myName: T, private var myHasDollar: Boolean) { +public class Identifier private(private val myName: T, private val myHasDollar: Boolean) { private var myNullable = true public fun getName(): T { diff --git a/j2k/tests/testData/ast/constructors/identifier.kt b/j2k/tests/testData/ast/constructors/identifier.kt index ee98211f791..3a3e6e9be5f 100644 --- a/j2k/tests/testData/ast/constructors/identifier.kt +++ b/j2k/tests/testData/ast/constructors/identifier.kt @@ -1,4 +1,4 @@ -public class Identifier private(private val myName: String, private var myHasDollar: Boolean) { +public class Identifier private(private val myName: String, private val myHasDollar: Boolean) { private var myNullable = true public fun getName(): String { diff --git a/j2k/tests/testData/ast/enum/fieldsWithPrimaryPrivateConstructor.kt b/j2k/tests/testData/ast/enum/fieldsWithPrimaryPrivateConstructor.kt index 53ff728122c..83a774702ba 100644 --- a/j2k/tests/testData/ast/enum/fieldsWithPrimaryPrivateConstructor.kt +++ b/j2k/tests/testData/ast/enum/fieldsWithPrimaryPrivateConstructor.kt @@ -1,4 +1,4 @@ -enum class Color private(private var code: Int) { +enum class Color private(private val code: Int) { WHITE : Color(21) BLACK : Color(22) RED : Color(23) diff --git a/j2k/tests/testData/ast/enum/primaryPrivateConstructor.kt b/j2k/tests/testData/ast/enum/primaryPrivateConstructor.kt index 583a45b4a47..838467a0bff 100644 --- a/j2k/tests/testData/ast/enum/primaryPrivateConstructor.kt +++ b/j2k/tests/testData/ast/enum/primaryPrivateConstructor.kt @@ -1,6 +1,6 @@ package demo -enum class Color private(private var code: Int) { +enum class Color private(private val code: Int) { public fun getCode(): Int { return code diff --git a/j2k/tests/testData/ast/field/valOrVar.java b/j2k/tests/testData/ast/field/valOrVar.java index 1d292dbfc26..02ccbef2060 100644 --- a/j2k/tests/testData/ast/field/valOrVar.java +++ b/j2k/tests/testData/ast/field/valOrVar.java @@ -5,6 +5,23 @@ class A { private int field3 = 0; final int field4 = 0; int field5 = 0; + private int field6; + private int field7; + private int field8; + private int field9; + private int field10; + private int field11; + + A(int p1, int p2, A a) { + field6 = p1; + field7 = 10; + this.field8 = p2; + this.field9 = 10; + if (p1 > 0) { + this.field10 = 10; + } + a.field11 = 10; + } void foo() { field3 = field2; diff --git a/j2k/tests/testData/ast/field/valOrVar.kt b/j2k/tests/testData/ast/field/valOrVar.kt index 68817a0b885..182656bca28 100644 --- a/j2k/tests/testData/ast/field/valOrVar.kt +++ b/j2k/tests/testData/ast/field/valOrVar.kt @@ -1,11 +1,24 @@ -class A() { +class A(private val field6: Int, private val field8: Int, a: A) { private val field1 = 0 private val field2 = 0 private var field3 = 0 val field4 = 0 var field5 = 0 + private val field7: Int + private val field9: Int + private var field10: Int = 0 + private var field11: Int = 0 fun foo() { field3 = field2 } + + { + field7 = 10 + this.field9 = 10 + if (field6 > 0) { + this.field10 = 10 + } + a.field11 = 10 + } } \ No newline at end of file diff --git a/j2k/tests/testData/ast/inheritance/classOneExtendsBaseGeneric.kt b/j2k/tests/testData/ast/inheritance/classOneExtendsBaseGeneric.kt index 3013c8a3582..d4499d9b10c 100644 --- a/j2k/tests/testData/ast/inheritance/classOneExtendsBaseGeneric.kt +++ b/j2k/tests/testData/ast/inheritance/classOneExtendsBaseGeneric.kt @@ -1,3 +1,3 @@ class Base(name: T) -class One(name: T, private var mySecond: K) : Base(name) \ No newline at end of file +class One(name: T, private val mySecond: K) : Base(name) \ No newline at end of file diff --git a/j2k/tests/testData/ast/inheritance/classOneExtendsBaseWithZeroParamsNonEmptyConstructor.kt b/j2k/tests/testData/ast/inheritance/classOneExtendsBaseWithZeroParamsNonEmptyConstructor.kt index 800d1f056c8..89d621b7bbf 100644 --- a/j2k/tests/testData/ast/inheritance/classOneExtendsBaseWithZeroParamsNonEmptyConstructor.kt +++ b/j2k/tests/testData/ast/inheritance/classOneExtendsBaseWithZeroParamsNonEmptyConstructor.kt @@ -1,3 +1,3 @@ class Base(name: String) -class One(name: String, private var mySecond: String) : Base(name) \ No newline at end of file +class One(name: String, private val mySecond: String) : Base(name) \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-638.kt b/j2k/tests/testData/ast/issues/kt-638.kt index cd59e50c894..6e7be82d223 100644 --- a/j2k/tests/testData/ast/issues/kt-638.kt +++ b/j2k/tests/testData/ast/issues/kt-638.kt @@ -1,4 +1,4 @@ -public class Identifier private(private val myName: T, private var myHasDollar: Boolean) { +public class Identifier private(private val myName: T, private val myHasDollar: Boolean) { private var myNullable = true public fun getName(): T { diff --git a/j2k/tests/testData/ast/nullability/FieldComparedWithNull2.kt b/j2k/tests/testData/ast/nullability/FieldComparedWithNull2.kt index 9b5e3dc0528..0d5c31887dc 100644 --- a/j2k/tests/testData/ast/nullability/FieldComparedWithNull2.kt +++ b/j2k/tests/testData/ast/nullability/FieldComparedWithNull2.kt @@ -1,4 +1,4 @@ -class C(private var s: String?) { +class C(private val s: String?) { fun foo() { if (s != null) { diff --git a/j2k/tests/testData/ast/nullability/FieldComparedWithNull4.kt b/j2k/tests/testData/ast/nullability/FieldComparedWithNull4.kt index 95ca8178272..54fad2fe62c 100644 --- a/j2k/tests/testData/ast/nullability/FieldComparedWithNull4.kt +++ b/j2k/tests/testData/ast/nullability/FieldComparedWithNull4.kt @@ -1,4 +1,4 @@ -class C(private var s: String?) { +class C(private val s: String?) { { if (s == null) { System.out.print("null") From 9f100df85fc09e0f52065442d59c0972eb8a1b49 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 21:37:54 +0400 Subject: [PATCH 093/143] Java to Kotlin converter: deleted wrong test data file --- j2k/tests/testData/ast/comments/сomments.kt | 30 --------------------- 1 file changed, 30 deletions(-) delete mode 100644 j2k/tests/testData/ast/comments/сomments.kt diff --git a/j2k/tests/testData/ast/comments/сomments.kt b/j2k/tests/testData/ast/comments/сomments.kt deleted file mode 100644 index 8fbef48f875..00000000000 --- a/j2k/tests/testData/ast/comments/сomments.kt +++ /dev/null @@ -1,30 +0,0 @@ -package foo - -// we use package 'foo' - -// imports: -import java.util.ArrayList - -// we need ArrayList - -// let's declare a class: -class A /* just a sample name*/() : Runnable /* let's implement Runnable */ { - fun foo/* again a sample name */(p: Int /* parameter p */, c: Char /* parameter c */) { - // let's print something: - System.out.println("1") // print 1 - System.out.println("2") // print 2 - - System.out.println("3") // print 3 - - // end of printing - - if (p > 0) { - // do this only when p > 0 - // we print 4 and return - System.out.println("3") - return // do not continue - } - - // some code to be added - } -} // end of class A \ No newline at end of file From b6aff9e9eed4deda3c66ce22778869d7abdc0637 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 23 Jun 2014 21:38:28 +0400 Subject: [PATCH 094/143] Java to Kotlin converter: added test data file back --- j2k/tests/testData/ast/comments/comments.kt | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 j2k/tests/testData/ast/comments/comments.kt diff --git a/j2k/tests/testData/ast/comments/comments.kt b/j2k/tests/testData/ast/comments/comments.kt new file mode 100644 index 00000000000..8fbef48f875 --- /dev/null +++ b/j2k/tests/testData/ast/comments/comments.kt @@ -0,0 +1,30 @@ +package foo + +// we use package 'foo' + +// imports: +import java.util.ArrayList + +// we need ArrayList + +// let's declare a class: +class A /* just a sample name*/() : Runnable /* let's implement Runnable */ { + fun foo/* again a sample name */(p: Int /* parameter p */, c: Char /* parameter c */) { + // let's print something: + System.out.println("1") // print 1 + System.out.println("2") // print 2 + + System.out.println("3") // print 3 + + // end of printing + + if (p > 0) { + // do this only when p > 0 + // we print 4 and return + System.out.println("3") + return // do not continue + } + + // some code to be added + } +} // end of class A \ No newline at end of file From 38d4ca54694212fbe285eb5bb06b64b6da2bf800 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sat, 21 Jun 2014 15:08:43 +0400 Subject: [PATCH 095/143] Do not generate @NotNull annotations on void- or primitive-returning methods #KT-4834 Fixed #KT-5255 Fixed --- .../jet/codegen/AnnotationCodegen.java | 20 +++++++++---- .../jet/codegen/FunctionCodegen.java | 7 +++-- .../codegen/ImplementationBodyCodegen.java | 14 ++++----- .../jet/codegen/PropertyCodegen.java | 24 +++++++-------- .../lightClasses/delegation/Function.java | 1 - .../lightClasses/delegation/Property.java | 1 - .../nullabilityAnnotations/Class.java | 4 --- .../ClassObjectField.java | 1 - .../ClassWithConstructor.java | 1 - .../ClassWithConstructorAndProperties.java | 1 - .../IntOverridesAny.java | 11 +++++++ .../nullabilityAnnotations/IntOverridesAny.kt | 12 ++++++++ .../NullableUnitReturn.java | 4 +++ .../NullableUnitReturn.kt | 3 ++ .../OverrideAnyWithUnit.java | 5 ++++ .../OverrideAnyWithUnit.kt | 9 ++++++ .../nullabilityAnnotations/Synthetic.java | 3 -- .../nullabilityAnnotations/Trait.java | 2 -- .../UnitAsGenericArgument.java | 5 ++++ .../UnitAsGenericArgument.kt | 9 ++++++ .../nullabilityAnnotations/UnitParameter.java | 3 ++ .../nullabilityAnnotations/UnitParameter.kt | 3 ++ .../nullabilityAnnotations/VoidReturn.java | 3 ++ .../nullabilityAnnotations/VoidReturn.kt | 3 ++ .../_DefaultPackage.java | 3 -- .../asJava/KotlinLightClassTestGenerated.java | 30 +++++++++++++++++++ .../foo/JavaClass.java.after | 2 -- 27 files changed, 136 insertions(+), 48 deletions(-) create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.java create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.kt create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.java create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.kt create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.java create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.kt create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.kt create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java create mode 100644 compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java index cb573329da2..df2af34a135 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java @@ -85,7 +85,10 @@ public abstract class AnnotationCodegen { bindingContext = typeMapper.getBindingContext(); } - public void genAnnotations(Annotated annotated) { + /** + * @param returnType can be null if not applicable (e.g. {@code annotated} is a class) + */ + public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType) { if (annotated == null) { return; } @@ -111,7 +114,7 @@ public abstract class AnnotationCodegen { } if (modifierList == null) { - generateAdditionalAnnotations(annotated, Collections.emptySet()); + generateAdditionalAnnotations(annotated, returnType, Collections.emptySet()); return; } @@ -131,10 +134,14 @@ public abstract class AnnotationCodegen { } } - generateAdditionalAnnotations(annotated, annotationDescriptorsAlreadyPresent); + generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent); } - private void generateAdditionalAnnotations(@NotNull Annotated annotated, @NotNull Set annotationDescriptorsAlreadyPresent) { + private void generateAdditionalAnnotations( + @NotNull Annotated annotated, + @Nullable Type returnType, + @NotNull Set annotationDescriptorsAlreadyPresent + ) { if (annotated instanceof CallableDescriptor) { CallableDescriptor descriptor = (CallableDescriptor) annotated; @@ -142,7 +149,9 @@ public abstract class AnnotationCodegen { if (isInvisibleFromTheOutside(descriptor)) return; if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return; - generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent); + if (returnType != null && !AsmUtil.isPrimitive(returnType)) { + generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent); + } } } @@ -166,7 +175,6 @@ public abstract class AnnotationCodegen { } boolean isNullableType = JvmCodegenUtil.isNullableType(type); - if (!isNullableType && KotlinBuiltIns.getInstance().isPrimitiveType(type)) return; Class annotationClass = isNullableType ? Nullable.class : NotNull.class; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index c2dbc72820a..6d859f6d627 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -143,7 +143,7 @@ public class FunctionCodegen extends ParentCodegenAware { v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod); } - AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor); + AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, asmMethod.getReturnType()); generateParameterAnnotations(functionDescriptor, mv, jvmSignature); @@ -180,7 +180,8 @@ public class FunctionCodegen extends ParentCodegenAware { List kotlinParameterTypes = jvmSignature.getValueParameters(); for (int i = 0; i < kotlinParameterTypes.size(); i++) { - JvmMethodParameterKind kind = kotlinParameterTypes.get(i).getKind(); + JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i); + JvmMethodParameterKind kind = parameterSignature.getKind(); if (kind.isSkippedInGenericSignature()) { markEnumOrInnerConstructorParameterAsSynthetic(mv, i); continue; @@ -189,7 +190,7 @@ public class FunctionCodegen extends ParentCodegenAware { if (kind == JvmMethodParameterKind.VALUE) { ValueParameterDescriptor parameter = iterator.next(); v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i); - AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameter); + AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameter, parameterSignature.getAsmType()); } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index df1b6cc5342..8adcd8e19e0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -54,7 +54,6 @@ import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmClassSignature; import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind; import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature; -import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; @@ -67,10 +66,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.*; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.DelegationToTraitImpl; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; import static org.jetbrains.jet.codegen.JvmCodegenUtil.*; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; @@ -78,6 +74,9 @@ import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.DelegationToTraitImpl; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class ImplementationBodyCodegen extends ClassBodyCodegen { @@ -208,7 +207,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { writeInnerClasses(); - AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor); + AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null); } @Override @@ -1083,11 +1082,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { for (PropertyAndDefaultValue info : classObjectPropertiesToCopy) { PropertyDescriptor property = info.descriptor; + Type type = typeMapper.mapType(property); FieldVisitor fv = v.newField(OtherOrigin(property), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, context.getFieldName(property, false), - typeMapper.mapType(property).getDescriptor(), typeMapper.mapFieldSignature(property.getType()), + type.getDescriptor(), typeMapper.mapFieldSignature(property.getType()), info.defaultValue); - AnnotationCodegen.forField(fv, typeMapper).genAnnotations(property); + AnnotationCodegen.forField(fv, typeMapper).genAnnotations(property, type); //This field are always static and final so if it has constant initializer don't do anything in clinit, //field would be initialized via default value in v.newField(...) - see JVM SPEC Ch.4 diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 1dc03a34674..714fe0463ab 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -145,18 +145,15 @@ public class PropertyCodegen { return false; } - FieldVisitor fv; if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) { - fv = generateBackingFieldAccess(p, descriptor); + generateBackingFieldAccess(p, descriptor); } else if (p instanceof JetProperty && ((JetProperty) p).hasDelegate()) { - fv = generatePropertyDelegateAccess((JetProperty) p, descriptor); + generatePropertyDelegateAccess((JetProperty) p, descriptor); } else { return false; } - - AnnotationCodegen.forField(fv, typeMapper).genAnnotations(descriptor); return true; } @@ -172,7 +169,7 @@ public class PropertyCodegen { if (!isTrait(context.getContextDescriptor()) || kind == OwnerKind.TRAIT_IMPL) { int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC; MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, name, desc, null, null); - AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(descriptor); + AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(descriptor, Type.VOID_TYPE); mv.visitCode(); mv.visitInsn(Opcodes.RETURN); mv.visitEnd(); @@ -187,7 +184,7 @@ public class PropertyCodegen { } } - private FieldVisitor generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) { + private void generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) { int modifiers = getDeprecatedAccessFlag(propertyDescriptor); for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) { @@ -230,21 +227,22 @@ public class PropertyCodegen { v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name)); - return builder.newField(OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(), - typeMapper.mapFieldSignature(jetType), defaultValue); + FieldVisitor fv = builder.newField(OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(), + typeMapper.mapFieldSignature(jetType), defaultValue); + AnnotationCodegen.forField(fv, typeMapper).genAnnotations(propertyDescriptor, type); } - private FieldVisitor generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) { + private void generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) { JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, p.getDelegateExpression()); if (delegateType == null) { // If delegate expression is unresolved reference delegateType = ErrorUtils.createErrorType("Delegate type"); } - return generateBackingField(p, propertyDescriptor, true, delegateType, null); + generateBackingField(p, propertyDescriptor, true, delegateType, null); } - private FieldVisitor generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) { + private void generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) { Object value = null; if (shouldWriteFieldInitializer(propertyDescriptor)) { @@ -254,7 +252,7 @@ public class PropertyCodegen { } } - return generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value); + generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value); } private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) { diff --git a/compiler/testData/asJava/lightClasses/delegation/Function.java b/compiler/testData/asJava/lightClasses/delegation/Function.java index 3f57046f3c5..8b07898697d 100644 --- a/compiler/testData/asJava/lightClasses/delegation/Function.java +++ b/compiler/testData/asJava/lightClasses/delegation/Function.java @@ -1,5 +1,4 @@ public final class Derived implements kotlin.jvm.internal.KObject, Base { - @org.jetbrains.annotations.NotNull public Derived(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "x") Base x) { /* compiled code */ } @org.jetbrains.annotations.NotNull diff --git a/compiler/testData/asJava/lightClasses/delegation/Property.java b/compiler/testData/asJava/lightClasses/delegation/Property.java index 7a570ffd6b7..b5d491bd57f 100644 --- a/compiler/testData/asJava/lightClasses/delegation/Property.java +++ b/compiler/testData/asJava/lightClasses/delegation/Property.java @@ -1,5 +1,4 @@ public final class Derived implements kotlin.jvm.internal.KObject, Base { - @org.jetbrains.annotations.NotNull public Derived(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "x") Base x) { /* compiled code */ } @org.jetbrains.annotations.NotNull diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Class.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Class.java index 02944a909ca..fd52f2a3e75 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Class.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Class.java @@ -34,7 +34,6 @@ public final class Class implements kotlin.jvm.internal.KObject { @org.jetbrains.annotations.Nullable public final java.lang.String getNullableVar() { /* compiled code */ } - @org.jetbrains.annotations.NotNull public final void setNullableVar(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "", type = "?") java.lang.String p) { /* compiled code */ } @org.jetbrains.annotations.NotNull @@ -43,7 +42,6 @@ public final class Class implements kotlin.jvm.internal.KObject { @org.jetbrains.annotations.NotNull public final java.lang.String getNotNullVar() { /* compiled code */ } - @org.jetbrains.annotations.NotNull public final void setNotNullVar(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "") java.lang.String p) { /* compiled code */ } @org.jetbrains.annotations.Nullable @@ -55,7 +53,6 @@ public final class Class implements kotlin.jvm.internal.KObject { public final java.lang.String getNotNullVarWithGetSet() { /* compiled code */ } @org.jetbrains.annotations.Nullable - @org.jetbrains.annotations.NotNull public final void setNotNullVarWithGetSet(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "v") java.lang.String v) { /* compiled code */ } @org.jetbrains.annotations.NotNull @@ -69,6 +66,5 @@ public final class Class implements kotlin.jvm.internal.KObject { @org.jetbrains.annotations.NotNull public final void setNullableVarWithGetSet(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "v", type = "?") java.lang.String v) { /* compiled code */ } - @org.jetbrains.annotations.NotNull public Class() { /* compiled code */ } } diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassObjectField.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassObjectField.java index 60f5378a83c..4de2e6cccee 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassObjectField.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassObjectField.java @@ -4,7 +4,6 @@ public final class ClassObjectField implements kotlin.jvm.internal.KObject { private static final java.lang.String y = ""; public static final ClassObjectField.object object$; - @org.jetbrains.annotations.NotNull public ClassObjectField() { /* compiled code */ } public static final class object implements kotlin.jvm.internal.KObject { diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructor.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructor.java index f781f98d627..3daedf91e11 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructor.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructor.java @@ -1,4 +1,3 @@ public final class ClassWithConstructor implements kotlin.jvm.internal.KObject { - @org.jetbrains.annotations.NotNull public ClassWithConstructor(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "nullable", type = "?") java.lang.String nullable, @org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "notNull") java.lang.String notNull) { /* compiled code */ } } diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructorAndProperties.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructorAndProperties.java index b59925f9a57..61917952f6e 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructorAndProperties.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructorAndProperties.java @@ -10,6 +10,5 @@ public final class ClassWithConstructorAndProperties implements kotlin.jvm.inter @org.jetbrains.annotations.NotNull public final java.lang.String getNotNull() { /* compiled code */ } - @org.jetbrains.annotations.NotNull public ClassWithConstructorAndProperties(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "nullable", type = "?") java.lang.String nullable, @org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "notNull") java.lang.String notNull) { /* compiled code */ } } diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.java new file mode 100644 index 00000000000..4a518c5ca97 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.java @@ -0,0 +1,11 @@ +public final class C implements kotlin.jvm.internal.KObject, Tr { + private final int v = 1; + + @org.jetbrains.annotations.NotNull + public java.lang.Integer foo() { /* compiled code */ } + + @org.jetbrains.annotations.NotNull + public java.lang.Integer getV() { /* compiled code */ } + + public C() { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt new file mode 100644 index 00000000000..274a682a4f6 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt @@ -0,0 +1,12 @@ +// C + +trait Tr { + fun foo(): Any + val v: Any +} + +class C: Tr { + override fun foo() = 1 + override val v = 1 +} + diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java new file mode 100644 index 00000000000..c4eae18b754 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.java @@ -0,0 +1,4 @@ +public final class _DefaultPackage { + @org.jetbrains.annotations.Nullable + public static final kotlin.Unit foo() { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.kt b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.kt new file mode 100644 index 00000000000..ac605d0a0ae --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.kt @@ -0,0 +1,3 @@ +// _DefaultPackage + +fun foo(): Unit? = null \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.java new file mode 100644 index 00000000000..ea46f1f8b4d --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.java @@ -0,0 +1,5 @@ +public final class C implements kotlin.jvm.internal.KObject, Base { + public void foo() { /* compiled code */ } + + public C() { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.kt b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.kt new file mode 100644 index 00000000000..1efb58ec710 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.kt @@ -0,0 +1,9 @@ +// C + +trait Base { + fun foo(): Any +} + +class C : Base { + override fun foo(): Unit {} +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Synthetic.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Synthetic.java index 4bbf5fb52b9..c9e411d88d4 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Synthetic.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Synthetic.java @@ -1,14 +1,11 @@ public final class Synthetic implements kotlin.jvm.internal.KObject { private final void foo() { /* compiled code */ } - @org.jetbrains.annotations.NotNull public Synthetic() { /* compiled code */ } public final class Inner implements kotlin.jvm.internal.KObject { - @org.jetbrains.annotations.NotNull public final void test() { /* compiled code */ } - @org.jetbrains.annotations.NotNull public Inner() { /* compiled code */ } } } diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java index ebe1ccec524..466a27bd758 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java @@ -25,7 +25,6 @@ public interface Trait extends kotlin.jvm.internal.KObject { @org.jetbrains.annotations.Nullable java.lang.String getNullableVar(); - @org.jetbrains.annotations.NotNull void setNullableVar(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "", type = "?") java.lang.String p); @org.jetbrains.annotations.NotNull @@ -34,6 +33,5 @@ public interface Trait extends kotlin.jvm.internal.KObject { @org.jetbrains.annotations.NotNull java.lang.String getNotNullVar(); - @org.jetbrains.annotations.NotNull void setNotNullVar(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "") java.lang.String p); } diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.java new file mode 100644 index 00000000000..51f7748cedb --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.java @@ -0,0 +1,5 @@ +public final class C implements kotlin.jvm.internal.KObject, Base { + public void foo(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "t") kotlin.Unit t) { /* compiled code */ } + + public C() { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.kt b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.kt new file mode 100644 index 00000000000..be4e460f616 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.kt @@ -0,0 +1,9 @@ +// C + +trait Base { + fun foo(t: T): T +} + +class C : Base { + override fun foo(t: Unit) {} +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java new file mode 100644 index 00000000000..f1fe4fc2028 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.java @@ -0,0 +1,3 @@ +public final class _DefaultPackage { + public static final void foo(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "s") kotlin.Unit s) { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.kt b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.kt new file mode 100644 index 00000000000..b417517b964 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.kt @@ -0,0 +1,3 @@ +// _DefaultPackage + +fun foo(s: Unit) {} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java new file mode 100644 index 00000000000..b2e287c1e78 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.java @@ -0,0 +1,3 @@ +public final class _DefaultPackage { + public static final void foo(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "s") java.lang.String s) { /* compiled code */ } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.kt b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.kt new file mode 100644 index 00000000000..4d2cdda1da3 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.kt @@ -0,0 +1,3 @@ +// _DefaultPackage + +fun foo(s: String) {} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java index 49af58748db..7c58f38e1fa 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.java @@ -9,7 +9,6 @@ public final class _DefaultPackage { @org.jetbrains.annotations.NotNull public static final java.lang.String getNotNullVar() { /* compiled code */ } - @org.jetbrains.annotations.NotNull public static final void setNotNullVar(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "") java.lang.String p) { /* compiled code */ } @org.jetbrains.annotations.Nullable @@ -17,7 +16,6 @@ public final class _DefaultPackage { public static final java.lang.String getNotNullVarWithGetSet() { /* compiled code */ } @org.jetbrains.annotations.Nullable - @org.jetbrains.annotations.NotNull public static final void setNotNullVarWithGetSet(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "v") java.lang.String v) { /* compiled code */ } @org.jetbrains.annotations.Nullable @@ -30,7 +28,6 @@ public final class _DefaultPackage { @org.jetbrains.annotations.Nullable public static final java.lang.String getNullableVar() { /* compiled code */ } - @org.jetbrains.annotations.NotNull public static final void setNullableVar(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "", type = "?") java.lang.String p) { /* compiled code */ } @org.jetbrains.annotations.NotNull diff --git a/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java b/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java index 2ce4a5ad997..ffc688593f2 100644 --- a/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/asJava/KotlinLightClassTestGenerated.java @@ -86,6 +86,21 @@ public class KotlinLightClassTestGenerated extends AbstractKotlinLightClassTest doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/Generic.kt"); } + @TestMetadata("IntOverridesAny.kt") + public void testIntOverridesAny() throws Exception { + doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt"); + } + + @TestMetadata("NullableUnitReturn.kt") + public void testNullableUnitReturn() throws Exception { + doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.kt"); + } + + @TestMetadata("OverrideAnyWithUnit.kt") + public void testOverrideAnyWithUnit() throws Exception { + doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.kt"); + } + @TestMetadata("Primitives.kt") public void testPrimitives() throws Exception { doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/Primitives.kt"); @@ -116,6 +131,21 @@ public class KotlinLightClassTestGenerated extends AbstractKotlinLightClassTest doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/TraitClassObjectField.kt"); } + @TestMetadata("UnitAsGenericArgument.kt") + public void testUnitAsGenericArgument() throws Exception { + doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.kt"); + } + + @TestMetadata("UnitParameter.kt") + public void testUnitParameter() throws Exception { + doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.kt"); + } + + @TestMetadata("VoidReturn.kt") + public void testVoidReturn() throws Exception { + doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.kt"); + } + @TestMetadata("_DefaultPackage.kt") public void test_DefaultPackage() throws Exception { doTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/_DefaultPackage.kt"); diff --git a/idea/testData/codeInsight/overrideImplement/functionFromTraitInJava/foo/JavaClass.java.after b/idea/testData/codeInsight/overrideImplement/functionFromTraitInJava/foo/JavaClass.java.after index af636c63cdf..650939d3544 100644 --- a/idea/testData/codeInsight/overrideImplement/functionFromTraitInJava/foo/JavaClass.java.after +++ b/idea/testData/codeInsight/overrideImplement/functionFromTraitInJava/foo/JavaClass.java.after @@ -1,11 +1,9 @@ package foo; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; class JavaClass { - @NotNull @Override public void bar(@Nullable String price) { From eec6fbb205abb90b590a8936f8a9d328713f4348 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 23 Jun 2014 18:02:04 +0400 Subject: [PATCH 096/143] Stubs: simplify JetStubElementType#shouldCreateStub() --- .../stubs/elements/JetFileElementType.java | 2 +- .../stubs/elements/JetStubElementType.java | 58 ++++--------------- 2 files changed, 11 insertions(+), 49 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java index 602fc439e60..6addb68814f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java @@ -36,7 +36,7 @@ import org.jetbrains.jet.plugin.JetLanguage; import java.io.IOException; public class JetFileElementType extends IStubFileElementType { - public static final int STUB_VERSION = 28; + public static final int STUB_VERSION = 29; public JetFileElementType() { super("jet.FILE", JetLanguage.INSTANCE); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementType.java index cac012ab8a3..fea9bfacc72 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementType.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementType.java @@ -23,13 +23,14 @@ import com.intellij.psi.stubs.IndexSink; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IStubFileElementType; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayFactory; -import com.intellij.util.ArrayUtil; import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetElementImplStub; +import org.jetbrains.jet.lang.psi.JetFunction; +import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.plugin.JetLanguage; import java.lang.reflect.Array; @@ -37,9 +38,6 @@ import java.lang.reflect.Constructor; public abstract class JetStubElementType> extends IStubElementType { - @SuppressWarnings("unchecked") - private static final Class[] ALWAYS_CREATE_STUB_FOR = new Class[] { JetClass.class, JetObjectDeclaration.class }; - @NotNull private final Constructor byNodeConstructor; @NotNull @@ -93,11 +91,14 @@ public abstract class JetStubElementType[] stopAt = ArrayUtil.append(ALWAYS_CREATE_STUB_FOR, JetBlockExpression.class); - @SuppressWarnings("unchecked") JetWithExpressionInitializer withInitializer = - PsiTreeUtil.getParentOfType(declaration, JetWithExpressionInitializer.class, true, stopAt); - if (withInitializer != null) { - JetExpression initializer = withInitializer.getInitializer(); - if (PsiTreeUtil.isAncestor(initializer, declaration, true)) { - return false; - } - } - - // Don't create stubs if declaration is inside property delegate - @SuppressWarnings("unchecked") JetPropertyDelegate delegate = PsiTreeUtil.getParentOfType(declaration, JetPropertyDelegate.class, true, stopAt); - if (delegate != null) { - JetExpression delegateExpression = delegate.getExpression(); - if (PsiTreeUtil.isAncestor(delegateExpression, declaration, true)) { - return false; - } - } - - return true; - } - @Override public void indexStub(@NotNull StubT stub, @NotNull IndexSink sink) { // do not force inheritors to implement this method From 8680ff4e888c58ae5659ac2d940fd17f5b04f057 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 20 Jun 2014 19:47:58 +0400 Subject: [PATCH 097/143] Do not mark comment next to reachable child as unreachable --- .../jetbrains/jet/lang/cfg/UnreachableCode.kt | 5 ++++- .../deadCode/commentsInDeadCode.kt | 22 +++++++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commentsInDeadCode.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt index b748efdf36a..b1597d88feb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/UnreachableCode.kt @@ -26,6 +26,7 @@ import com.intellij.psi.PsiWhiteSpace import java.util.ArrayList import org.jetbrains.jet.lexer.JetTokens import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.PsiComment trait UnreachableCode { val elements: Set @@ -70,7 +71,9 @@ class UnreachableCodeImpl( } fun List.removeReachableElementsWithMeaninglessSiblings(): List { - fun PsiElement.isMeaningless() = this is PsiWhiteSpace || this.getNode()?.getElementType() == JetTokens.COMMA + fun PsiElement.isMeaningless() = this is PsiWhiteSpace + || this.getNode()?.getElementType() == JetTokens.COMMA + || this is PsiComment val childrenToRemove = HashSet() fun collectSiblingsIfMeaningless(elementIndex: Int, direction: Int) { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commentsInDeadCode.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commentsInDeadCode.kt new file mode 100644 index 00000000000..7640277569f --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commentsInDeadCode.kt @@ -0,0 +1,22 @@ +package a + +fun test1() { + bar( + 11, + todo(),//comment1 + ""//comment2 + ) +} + +fun test2() { + bar(11, todo()/*comment1*/, ""/*comment2*/) +} +fun test3() { + bar(11, @l(todo()/*comment*/), "") +} + +fun todo() = throw Exception() + +fun bar(i: Int, s: String, a: Any) {} + + diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 80b66aba665..b37702a0811 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1451,6 +1451,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commasAndWhitespaces.kt"); } + @TestMetadata("commentsInDeadCode.kt") + public void testCommentsInDeadCode() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/commentsInDeadCode.kt"); + } + @TestMetadata("deadCallInInvokeCall.kt") public void testDeadCallInInvokeCall() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCallInInvokeCall.kt"); From e4a06512245a27da4a53dd21583de03289844ca8 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 23 Jun 2014 10:00:20 +0400 Subject: [PATCH 098/143] Added 'markedAsDead' flag to InstructionImpl to be used in tests --- .../jet/lang/cfg/JetFlowInformationProvider.java | 2 +- .../jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java | 2 +- .../jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java | 8 -------- .../lang/cfg/pseudocode/instructions/InstructionImpl.kt | 7 ++----- .../org/jetbrains/jet/cfg/AbstractControlFlowTest.java | 3 ++- .../org/jetbrains/jet/cfg/AbstractPseudocodeTest.java | 2 +- 6 files changed, 7 insertions(+), 17 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 36f3c3ac1f8..8bafae1e6a1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -276,7 +276,7 @@ public class JetFlowInformationProvider { if (!isJumpElement) continue; } - if (PseudocodeUtil.isDeadInAllCopies(instruction)) { + if (instruction.getDead()) { unreachableElements.add(element); } else { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java index 9613b7a0f40..7452157936e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java @@ -370,7 +370,7 @@ public class PseudocodeImpl implements Pseudocode { Set instructionSet = Sets.newHashSet(instructions); for (Instruction instruction : mutableInstructionList) { if (!instructionSet.contains(instruction)) { - ((InstructionImpl)instruction).die(); + ((InstructionImpl)instruction).setMarkedAsDead(true); for (Instruction nextInstruction : instruction.getNextInstructions()) { nextInstruction.getPreviousInstructions().remove(instruction); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java index b6e5bdc5db8..8ad89af03b5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java @@ -85,12 +85,4 @@ public class PseudocodeUtil { } return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference); } - - public static boolean isDeadInAllCopies(@NotNull Instruction instruction) { - boolean allCopiesAreDead = instruction.getDead(); - for (Instruction copy : instruction.getCopies()) { - allCopiesAreDead = allCopiesAreDead && copy.getDead(); - } - return allCopiesAreDead; - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt index a57b75dd7c2..6cf1c37d22e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt @@ -27,7 +27,6 @@ public abstract class InstructionImpl(public override val lexicalScope: LexicalS private var _owner: Pseudocode? = null private val _copies = HashSet() private var original: Instruction? = null - protected var _dead: Boolean = false private fun setOriginalInstruction(value: Instruction?) { assert(original == null) { "Instruction can't have two originals: this.original = ${original}; new original = $this" } @@ -49,11 +48,9 @@ public abstract class InstructionImpl(public override val lexicalScope: LexicalS protected abstract fun createCopy(): InstructionImpl - public fun die() { - _dead = true - } + public var markedAsDead: Boolean = false - override val dead: Boolean get() = _dead + override val dead: Boolean get() = markedAsDead && getCopies().all { (it as InstructionImpl).markedAsDead } public fun copy(): Instruction { return updateCopyInfo(createCopy()) diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java b/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java index cea52dc1fa4..569662b8224 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractControlFlowTest.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl; import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction; +import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionImpl; import org.jetbrains.jet.lang.resolve.BindingContext; import java.util.*; @@ -108,7 +109,7 @@ public abstract class AbstractControlFlowTest extends AbstractPseudocodeTest { //check edges directions Collection instructions = pseudocode.getInstructionsIncludingDeadCode(); for (Instruction instruction : instructions) { - if (!instruction.getDead()) { + if (!((InstructionImpl)instruction).getMarkedAsDead()) { for (Instruction nextInstruction : instruction.getNextInstructions()) { assertTrue("instruction '" + instruction + "' has '" + nextInstruction + "' among next instructions list, but not vice versa", nextInstruction.getPreviousInstructions().contains(instruction)); diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java index 1dc9d51d6d1..734e4c4d512 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudocodeTest.java @@ -140,7 +140,7 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironment { @NotNull Set remainedAfterPostProcessInstructions ) { boolean isRemovedThroughPostProcess = !remainedAfterPostProcessInstructions.contains(instruction); - assert isRemovedThroughPostProcess == ((InstructionImpl)instruction).getDead(); + assert isRemovedThroughPostProcess == ((InstructionImpl)instruction).getMarkedAsDead(); return isRemovedThroughPostProcess ? "-" : " "; } From ad8368066633fb522cd9d78c73c331e1fae12391 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 23 Jun 2014 17:59:26 +0400 Subject: [PATCH 099/143] Refactoring: changed methods order --- .../instructions/InstructionImpl.kt | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt index 6cf1c37d22e..45b4cb11df0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt @@ -25,36 +25,6 @@ import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue public abstract class InstructionImpl(public override val lexicalScope: LexicalScope): Instruction { private var _owner: Pseudocode? = null - private val _copies = HashSet() - private var original: Instruction? = null - - private fun setOriginalInstruction(value: Instruction?) { - assert(original == null) { "Instruction can't have two originals: this.original = ${original}; new original = $this" } - original = value - } - - protected fun outgoingEdgeTo(target: Instruction?): Instruction? { - if (target != null) { - target.previousInstructions.add(this) - } - return target - } - - protected fun updateCopyInfo(instruction: InstructionImpl): Instruction { - _copies.add(instruction) - instruction.setOriginalInstruction(this) - return instruction - } - - protected abstract fun createCopy(): InstructionImpl - - public var markedAsDead: Boolean = false - - override val dead: Boolean get() = markedAsDead && getCopies().all { (it as InstructionImpl).markedAsDead } - - public fun copy(): Instruction { - return updateCopyInfo(createCopy()) - } override var owner: Pseudocode get() = _owner!! @@ -63,9 +33,7 @@ public abstract class InstructionImpl(public override val lexicalScope: LexicalS _owner = value } - override val previousInstructions: MutableCollection = LinkedHashSet() - - override val inputValues: List = Collections.emptyList() + private val _copies = HashSet() override fun getCopies(): Collection { return original?.let { original -> @@ -75,4 +43,38 @@ public abstract class InstructionImpl(public override val lexicalScope: LexicalS originalCopies } ?: _copies } + + private var original: Instruction? = null + + private fun setOriginalInstruction(value: Instruction?) { + assert(original == null) { "Instruction can't have two originals: this.original = ${original}; new original = $this" } + original = value + } + + public fun copy(): Instruction { + return updateCopyInfo(createCopy()) + } + + protected abstract fun createCopy(): InstructionImpl + + protected fun updateCopyInfo(instruction: InstructionImpl): Instruction { + _copies.add(instruction) + instruction.setOriginalInstruction(this) + return instruction + } + + public var markedAsDead: Boolean = false + + override val dead: Boolean get() = markedAsDead && getCopies().all { (it as InstructionImpl).markedAsDead } + + override val previousInstructions: MutableCollection = LinkedHashSet() + + protected fun outgoingEdgeTo(target: Instruction?): Instruction? { + if (target != null) { + target.previousInstructions.add(this) + } + return target + } + + override val inputValues: List = Collections.emptyList() } \ No newline at end of file From 6a4ccfd91dd89b8ae07006c4a351c84a6ab55dcb Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 23 Jun 2014 18:46:06 +0400 Subject: [PATCH 100/143] Store copies of instruction only once removed reference to 'original' instruction --- .../pseudocode/instructions/Instruction.kt | 4 +-- .../instructions/InstructionImpl.kt | 36 ++++++------------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt index e98ff49cdb0..ea2df5fbe4e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/Instruction.kt @@ -23,7 +23,7 @@ import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue public trait Instruction { public var owner: Pseudocode - public val previousInstructions: MutableCollection + public val previousInstructions: Collection public val nextInstructions: Collection public val dead: Boolean @@ -32,7 +32,7 @@ public trait Instruction { public val inputValues: List - public fun getCopies(): Collection + public val copies: Collection public fun accept(visitor: InstructionVisitor) public fun accept(visitor: InstructionVisitorWithResult): R diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt index 45b4cb11df0..3318a932b83 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/instructions/InstructionImpl.kt @@ -33,46 +33,32 @@ public abstract class InstructionImpl(public override val lexicalScope: LexicalS _owner = value } - private val _copies = HashSet() + private var allCopies: MutableSet? = null - override fun getCopies(): Collection { - return original?.let { original -> - val originalCopies = Sets.newHashSet(original.getCopies()) - originalCopies.remove(this) - originalCopies.add(original) - originalCopies - } ?: _copies - } + override val copies: Collection + get() = allCopies?.filter { it != this } ?: Collections.emptyList() - private var original: Instruction? = null - - private fun setOriginalInstruction(value: Instruction?) { - assert(original == null) { "Instruction can't have two originals: this.original = ${original}; new original = $this" } - original = value - } - - public fun copy(): Instruction { - return updateCopyInfo(createCopy()) - } + fun copy(): Instruction = updateCopyInfo(createCopy()) protected abstract fun createCopy(): InstructionImpl protected fun updateCopyInfo(instruction: InstructionImpl): Instruction { - _copies.add(instruction) - instruction.setOriginalInstruction(this) + if (allCopies == null) { + allCopies = hashSetOf(this) + } + instruction.allCopies = allCopies + allCopies!!.add(instruction) return instruction } public var markedAsDead: Boolean = false - override val dead: Boolean get() = markedAsDead && getCopies().all { (it as InstructionImpl).markedAsDead } + override val dead: Boolean get() = allCopies?.all { it.markedAsDead } ?: markedAsDead override val previousInstructions: MutableCollection = LinkedHashSet() protected fun outgoingEdgeTo(target: Instruction?): Instruction? { - if (target != null) { - target.previousInstructions.add(this) - } + (target as InstructionImpl?)?.previousInstructions?.add(this) return target } From 0673dc51d6e28f89eb2b68506ed142736316d5b3 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 23 Jun 2014 18:58:54 +0400 Subject: [PATCH 101/143] Test for KT-3162 More precise try-finally error marking #KT-3162 Obsolete --- .../deadCode/kt3162tryAsInitializer.kt | 12 ++++++++++++ .../jet/checkers/JetDiagnosticsTestGenerated.java | 5 +++++ 2 files changed, 17 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt3162tryAsInitializer.kt diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt3162tryAsInitializer.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt3162tryAsInitializer.kt new file mode 100644 index 00000000000..a459cf6cf91 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt3162tryAsInitializer.kt @@ -0,0 +1,12 @@ +//KT-3162 More precise try-finally error marking + +fun foo(x: String) : String { + val a = try { + x + } finally { + try { + } catch (e: Exception) { + } + return x + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index b37702a0811..c5b4ea4326f 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1551,6 +1551,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_3.kt"); } + @TestMetadata("kt3162tryAsInitializer.kt") + public void testKt3162tryAsInitializer() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt3162tryAsInitializer.kt"); + } + @TestMetadata("kt5200DeadCodeInLambdas.kt") public void testKt5200DeadCodeInLambdas() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt"); From 41dd12d46be4c901167ca5ddcadb29b237e56d53 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 23 Jun 2014 19:17:59 +0400 Subject: [PATCH 102/143] Fix invalid usage of descriptorToDeclaration in QuickFixFactoryForTypeMismatchError --- .../QuickFixFactoryForTypeMismatchError.java | 33 ++++++++++++++----- .../beforeMultiFakeOverride.kt | 19 +++++++++++ ...eMultiFakeOverrideForOperatorConvention.kt | 22 +++++++++++++ .../quickfix/QuickFixTestGenerated.java | 10 ++++++ 4 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverride.kt create mode 100644 idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverrideForOperatorConvention.kt diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java index cc9a9ff1f49..623e0c49c2e 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2; import org.jetbrains.jet.lang.diagnostics.Errors; @@ -71,9 +72,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF ResolvedCall resolvedCall = context.get(BindingContext.RESOLVED_CALL, ((JetOperationExpression) expression).getOperationReference()); if (resolvedCall != null) { - PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getResultingDescriptor()); - if (declaration instanceof JetFunction) { - actions.add(new ChangeFunctionReturnTypeFix((JetFunction) declaration, expectedType)); + JetFunction declaration = getFunctionDeclaration(context, resolvedCall); + if (declaration != null) { + actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); } } } @@ -82,9 +83,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF if (parentBinary.getRight() == expression) { ResolvedCall resolvedCall = context.get(BindingContext.RESOLVED_CALL, parentBinary.getOperationReference()); if (resolvedCall != null) { - PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getResultingDescriptor()); - if (declaration instanceof JetFunction) { - JetParameter binaryOperatorParameter = ((JetFunction) declaration).getValueParameterList().getParameters().get(0); + JetFunction declaration = getFunctionDeclaration(context, resolvedCall); + if (declaration != null) { + JetParameter binaryOperatorParameter = declaration.getValueParameterList().getParameters().get(0); actions.add(new ChangeParameterTypeFix(binaryOperatorParameter, expressionType)); } } @@ -96,9 +97,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF ResolvedCall resolvedCall = context.get(BindingContext.RESOLVED_CALL, ((JetCallExpression) expression).getCalleeExpression()); if (resolvedCall != null) { - PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getResultingDescriptor()); - if (declaration instanceof JetFunction) { - actions.add(new ChangeFunctionReturnTypeFix((JetFunction) declaration, expectedType)); + JetFunction declaration = getFunctionDeclaration(context, resolvedCall); + if (declaration != null) { + actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); } } } @@ -128,4 +129,18 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF } return actions; } + + @Nullable + private static JetFunction getFunctionDeclaration(@NotNull BindingContext context, @NotNull ResolvedCall resolvedCall) { + List declarations = BindingContextUtils.descriptorToDeclarations(context, resolvedCall.getResultingDescriptor()); + //do not create fix if descriptor has more than one overridden declarations + //TODO: use change signature to deal with this case correctly + if (declarations.size() == 1) { + PsiElement result = declarations.iterator().next(); + if (result instanceof JetFunction) { + return (JetFunction) result; + } + } + return null; + } } diff --git a/idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverride.kt b/idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverride.kt new file mode 100644 index 00000000000..dbcb8365484 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverride.kt @@ -0,0 +1,19 @@ +// "Change 'AA.f' function return type to 'Boolean'" "false" +// ACTION: Change 'AAA.g' function return type to 'Int' +// ACTION: Convert to expression body +// ACTION: Disable 'Convert to Expression Body' +// ACTION: Edit intention settings +// ERROR: Type mismatch.
Required:kotlin.Boolean
Found:kotlin.Int
+trait A { + fun f(): Int +} + +open class AA { + fun f() = 3 +} + +class AAA: AA(), A { + fun g(): Boolean { + return f() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverrideForOperatorConvention.kt b/idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverrideForOperatorConvention.kt new file mode 100644 index 00000000000..ae55376a13e --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverrideForOperatorConvention.kt @@ -0,0 +1,22 @@ +// "Change 'AA.contains' function return type to 'Int'" "false" +// ACTION: Change 'AAA.g' function return type to 'Boolean' +// ACTION: Convert to expression body +// ACTION: Disable 'Convert to Expression Body' +// ACTION: Disable 'Replace Overloaded Operator With Function Call' +// ACTION: Edit intention settings +// ACTION: Edit intention settings +// ACTION: Replace overloaded operator with function call +// ERROR: Type mismatch.
Required:kotlin.Int
Found:kotlin.Boolean
+trait A { + fun contains(i: Int): Boolean +} + +open class AA { + fun contains(i: Int) = true +} + +class AAA: AA(), A { + fun g(): Int { + return 3 in this + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 7f93f8f37ed..657e6dffeb0 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -2306,6 +2306,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeExpectedTypeMismatch.kt"); } + @TestMetadata("beforeMultiFakeOverride.kt") + public void testMultiFakeOverride() throws Exception { + doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverride.kt"); + } + + @TestMetadata("beforeMultiFakeOverrideForOperatorConvention.kt") + public void testMultiFakeOverrideForOperatorConvention() throws Exception { + doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeMultiFakeOverrideForOperatorConvention.kt"); + } + @TestMetadata("beforePropertyGetterInitializerTypeMismatch.kt") public void testPropertyGetterInitializerTypeMismatch() throws Exception { doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforePropertyGetterInitializerTypeMismatch.kt"); From e3c170183e629a47e11eb1a1f2e82bba5402af54 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 23 Jun 2014 19:34:04 +0400 Subject: [PATCH 103/143] Fix invalid usage of descriptorToDeclaration in QuickFixUtil --- .../QuickFixFactoryForTypeMismatchError.java | 13 ++++--------- .../jetbrains/jet/plugin/quickfix/QuickFixUtil.java | 12 +++++++++++- .../beforeMultiFakeOverride.kt | 13 +++++++++++++ .../jet/plugin/quickfix/QuickFixTestGenerated.java | 5 +++++ 4 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeMultiFakeOverride.kt diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java index 623e0c49c2e..617ee4ef412 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java @@ -26,7 +26,6 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; @@ -34,6 +33,7 @@ import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; import java.util.LinkedList; import java.util.List; +//TODO: should use change signature to deal with cases of multiple overridden descriptors public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsFactory { @NotNull @Override @@ -132,14 +132,9 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF @Nullable private static JetFunction getFunctionDeclaration(@NotNull BindingContext context, @NotNull ResolvedCall resolvedCall) { - List declarations = BindingContextUtils.descriptorToDeclarations(context, resolvedCall.getResultingDescriptor()); - //do not create fix if descriptor has more than one overridden declarations - //TODO: use change signature to deal with this case correctly - if (declarations.size() == 1) { - PsiElement result = declarations.iterator().next(); - if (result instanceof JetFunction) { - return (JetFunction) result; - } + PsiElement result = QuickFixUtil.safeGetDeclaration(context, resolvedCall); + if (result instanceof JetFunction) { + return (JetFunction) result; } return null; } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java index 5d8052847ad..b807f17be18 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java @@ -109,7 +109,7 @@ public class QuickFixUtil { BindingContext context = ResolvePackage.getBindingContext(callExpression.getContainingJetFile()); ResolvedCall resolvedCall = context.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression()); if (resolvedCall == null) return null; - PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getCandidateDescriptor()); + PsiElement declaration = safeGetDeclaration(context, resolvedCall); if (declaration instanceof JetFunction) { return ((JetFunction) declaration).getValueParameterList(); } @@ -119,6 +119,16 @@ public class QuickFixUtil { return null; } + @Nullable + public static PsiElement safeGetDeclaration(@NotNull BindingContext context, @NotNull ResolvedCall resolvedCall) { + List declarations = BindingContextUtils.descriptorToDeclarations(context, resolvedCall.getResultingDescriptor()); + //do not create fix if descriptor has more than one overridden declaration + if (declarations.size() == 1) { + return declarations.iterator().next(); + } + return null; + } + @Nullable public static JetParameter getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(@NotNull JetFunctionLiteralExpression functionLiteralExpression) { if (!(functionLiteralExpression.getParent() instanceof JetCallExpression)) { diff --git a/idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeMultiFakeOverride.kt b/idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeMultiFakeOverride.kt new file mode 100644 index 00000000000..9d033b6e447 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeMultiFakeOverride.kt @@ -0,0 +1,13 @@ +// "class org.jetbrains.jet.plugin.quickfix.ChangeParameterTypeFix" "false" +// ERROR: Type mismatch.
Required:kotlin.Int
Found:kotlin.String
+trait A { + fun f(i: Int): Boolean +} + +open class AA { + fun f(i: Int) = true +} + +class AAA: AA(), A + +val c = AAA().f("") \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 657e6dffeb0..63155eca981 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -2263,6 +2263,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeChangePrimaryConstructorParameterType.kt"); } + @TestMetadata("beforeMultiFakeOverride.kt") + public void testMultiFakeOverride() throws Exception { + doTest("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeMultiFakeOverride.kt"); + } + } @TestMetadata("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression") From 40a245a91fb9fac3d9b94557b803365d44aeb70c Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Tue, 24 Jun 2014 14:56:34 +0400 Subject: [PATCH 104/143] Hack to filter out irrelevant actions in quick fix tests output Needed because of different behaviour locally and on build server --- .../jet/plugin/DirectiveBasedActionUtils.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/idea/tests/org/jetbrains/jet/plugin/DirectiveBasedActionUtils.java b/idea/tests/org/jetbrains/jet/plugin/DirectiveBasedActionUtils.java index 4e2d3ec5891..f88c1db30ff 100644 --- a/idea/tests/org/jetbrains/jet/plugin/DirectiveBasedActionUtils.java +++ b/idea/tests/org/jetbrains/jet/plugin/DirectiveBasedActionUtils.java @@ -23,6 +23,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.testFramework.UsefulTestCase; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.InTextDirectivesUtils; import org.jetbrains.jet.lang.diagnostics.Diagnostic; @@ -31,6 +32,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; import org.jetbrains.jet.plugin.highlighter.IdeErrorMessages; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -82,6 +84,26 @@ public class DirectiveBasedActionUtils { }))); UsefulTestCase.assertOrderedEquals("Some unexpected actions available at current position: %s. Use // ACTION: directive", - actualActions, validActions); + filterOutIrrelevantActions(actualActions), filterOutIrrelevantActions(validActions)); } + + @NotNull + //TODO: hack, implemented because irrelevant actions behave in different ways on build server and locally + // this behaviour should be investigated and hack can be removed + private static Collection filterOutIrrelevantActions(@NotNull Collection actions) { + return Collections2.filter(actions, new Predicate() { + @Override + public boolean apply(String input) { + for (String prefix : IRRELEVANT_ACTION_PREFIXES) { + if (input.startsWith(prefix)) { + return false; + } + } + return true; + } + }); + } + + private static final Collection IRRELEVANT_ACTION_PREFIXES = + Arrays.asList("Disable ", "Edit intention settings", "Edit inspection profile setting"); } From f26cad71d8044151d0114fa2be1dea24fb256233 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 23 Jun 2014 15:31:22 +0400 Subject: [PATCH 105/143] Useless final removed --- .../org/jetbrains/jet/lang/types/checker/JetTypeChecker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java index 9008697b8df..9c190e67c77 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java @@ -34,7 +34,7 @@ public class JetTypeChecker { return TYPE_CHECKER.isSubtypeOf(subtype, supertype); } - public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull final TypeConstructorEquality equalityAxioms) { + public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeConstructorEquality equalityAxioms) { return createWithAxioms(equalityAxioms).isSubtypeOf(subtype, supertype); } @@ -42,7 +42,7 @@ public class JetTypeChecker { return TYPE_CHECKER.equalTypes(a, b); } - public boolean equalTypes(@NotNull JetType a, @NotNull JetType b, @NotNull final TypeConstructorEquality equalityAxioms) { + public boolean equalTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeConstructorEquality equalityAxioms) { return createWithAxioms(equalityAxioms).equalTypes(a, b); } From cd28b216c17f59a835323d093616be34f6f0b15d Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 23 Jun 2014 15:34:13 +0400 Subject: [PATCH 106/143] Rename. INSTANCE -> DEFAULT in JetTypeChecker --- .../org/jetbrains/jet/codegen/ExpressionCodegen.java | 2 +- .../jet/codegen/ImplementationBodyCodegen.java | 2 +- .../AlternativeMethodSignatureData.java | 2 +- .../java/kotlinSignature/PropagationHeuristics.java | 4 ++-- .../jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt | 6 +++--- .../jet/lang/diagnostics/rendering/Renderers.java | 6 +++--- .../jet/lang/resolve/DeclarationsChecker.java | 4 ++-- .../jet/lang/resolve/DelegatedPropertyResolver.java | 2 +- .../jetbrains/jet/lang/resolve/DescriptorResolver.java | 4 ++-- .../org/jetbrains/jet/lang/resolve/OverloadUtil.java | 2 +- .../jetbrains/jet/lang/resolve/OverrideResolver.java | 4 ++-- .../jet/lang/resolve/calls/ArgumentTypeResolver.java | 2 +- .../jet/lang/resolve/calls/CandidateResolver.java | 4 ++-- .../lang/resolve/calls/autocasts/AutoCastUtils.java | 2 +- .../lang/resolve/calls/inference/ConstraintsUtil.java | 2 +- .../calls/results/OverloadingConflictResolver.java | 2 +- .../jet/lang/resolve/calls/tasks/TaskPrioritizer.java | 3 +-- .../resolve/constants/CompileTimeConstantChecker.java | 8 ++++---- .../jetbrains/jet/lang/types/CastDiagnosticsUtil.java | 6 +++--- .../expressions/BasicExpressionTypingVisitor.java | 4 ++-- .../expressions/ClosureExpressionsTypingVisitor.java | 4 ++-- .../expressions/ControlStructureTypingVisitor.java | 2 +- .../jet/lang/types/expressions/DataFlowUtils.java | 4 ++-- .../lang/types/expressions/ExpressionTypingUtils.java | 4 ++-- .../expressions/PatternMatchingTypingVisitor.java | 4 ++-- .../org/jetbrains/jet/plugin/MainFunctionDetector.java | 2 +- .../org/jetbrains/jet/types/JetTypeCheckerTest.java | 4 ++-- .../java/lazy/descriptors/LazyJavaClassDescriptor.kt | 2 +- .../resolve/java/lazy/types/LazyJavaTypeResolver.kt | 4 ++-- .../impl/AbstractTypeParameterDescriptor.java | 2 +- .../jetbrains/jet/lang/resolve/DescriptorUtils.java | 2 +- .../org/jetbrains/jet/lang/resolve/OverridingUtil.java | 10 +++++----- .../lang/resolve/calls/inference/TypeBoundsImpl.java | 8 ++++---- .../jet/lang/resolve/scopes/WritableScopeImpl.java | 2 +- .../org/jetbrains/jet/lang/types/AbstractJetType.java | 2 +- .../org/jetbrains/jet/lang/types/CommonSupertypes.java | 2 +- .../src/org/jetbrains/jet/lang/types/TypeUtils.java | 6 +++--- .../jet/lang/types/checker/JetTypeChecker.java | 2 +- .../org/jetbrains/jet/plugin/completion/smart/Utils.kt | 2 +- .../ReplaceContainsIntention.kt | 2 +- .../parameterInfo/JetFunctionParameterInfoHandler.java | 2 +- .../jet/plugin/quickfix/AddFunctionParametersFix.java | 2 +- .../jet/plugin/quickfix/AddFunctionToSupertypeFix.java | 4 ++-- .../jet/plugin/quickfix/AddNameToArgumentFix.java | 2 +- .../jet/plugin/quickfix/CastExpressionFix.java | 2 +- .../quickfix/ChangeFunctionLiteralReturnTypeFix.java | 6 +++--- .../plugin/quickfix/ChangeFunctionReturnTypeFix.java | 2 +- .../plugin/quickfix/ChangeFunctionSignatureFix.java | 2 +- .../quickfix/ChangeMemberFunctionSignatureFix.java | 2 +- .../jet/plugin/quickfix/ChangeVariableTypeFix.java | 6 +++--- .../jet/plugin/quickfix/CreateFunctionFromUsageFix.kt | 6 +++--- .../jetbrains/jet/plugin/quickfix/QuickFixUtil.java | 4 ++-- .../jet/plugin/refactoring/JetNameSuggester.java | 2 +- .../jet/plugin/refactoring/JetRefactoringUtil.java | 2 +- .../KotlinIntroduceVariableHandler.java | 7 ++----- 55 files changed, 94 insertions(+), 98 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 3624ea3bb2a..60cbe9f7dcc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -722,7 +722,7 @@ public class ExpressionCodegen extends JetVisitor implem invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), hasNextCall); JetType type = hasNextCall.getResultingDescriptor().getReturnType(); - assert type != null && JetTypeChecker.INSTANCE.isSubtypeOf(type, KotlinBuiltIns.getInstance().getBooleanType()); + assert type != null && JetTypeChecker.DEFAULT.isSubtypeOf(type, KotlinBuiltIns.getInstance().getBooleanType()); Type asmType = asmType(type); StackValue.coerce(asmType, Type.BOOLEAN_TYPE, v); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 8adcd8e19e0..15ef11f2960 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -484,7 +484,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { JetType returnType = function.getReturnType(); assert returnType != null : function.toString(); JetType paramType = function.getValueParameters().get(0).getType(); - if (JetTypeChecker.INSTANCE.equalTypes(arrayType, returnType) && JetTypeChecker.INSTANCE.equalTypes(arrayType, paramType)) { + if (JetTypeChecker.DEFAULT.equalTypes(arrayType, returnType) && JetTypeChecker.DEFAULT.equalTypes(arrayType, paramType)) { return true; } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/AlternativeMethodSignatureData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/AlternativeMethodSignatureData.java index 924c8f87f20..81f2e67463f 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/AlternativeMethodSignatureData.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/AlternativeMethodSignatureData.java @@ -139,7 +139,7 @@ public class AlternativeMethodSignatureData extends ElementAlternativeSignatureD JetType substitutedReturnType = substitutor.substitute(returnType, Variance.INVARIANT); assert substitutedReturnType != null; - if (!JetTypeChecker.INSTANCE.isSubtypeOf(altReturnType, substitutedReturnType)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(altReturnType, substitutedReturnType)) { throw new AlternativeSignatureMismatchException( "Return type is changed to not subtype for method which overrides another: " + altReturnType + ", was: " + returnType); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java index f8ba53037cc..b8a0da70239 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java @@ -59,8 +59,8 @@ class PropagationHeuristics { JetType elementTypeInSuper = arrayTypeFromSuper.getArguments().get(0).getType(); JetType elementType = type.getArguments().get(0).getType(); - if (JetTypeChecker.INSTANCE.isSubtypeOf(elementType, elementTypeInSuper) - && !JetTypeChecker.INSTANCE.equalTypes(elementType, elementTypeInSuper)) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(elementType, elementTypeInSuper) + && !JetTypeChecker.DEFAULT.equalTypes(elementType, elementTypeInSuper)) { JetTypeImpl betterTypeInSuper = new JetTypeImpl( arrayTypeFromSuper.getAnnotations(), arrayTypeFromSuper.getConstructor(), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt index 60aea47a0e1..04b8eb99a64 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/TypePredicate.kt @@ -28,12 +28,12 @@ public trait TypePredicate: (JetType) -> Boolean { } public data class SingleType(val targetType: JetType): TypePredicate { - override fun invoke(typeToCheck: JetType): Boolean = JetTypeChecker.INSTANCE.equalTypes(typeToCheck, targetType) + override fun invoke(typeToCheck: JetType): Boolean = JetTypeChecker.DEFAULT.equalTypes(typeToCheck, targetType) override fun toString(): String = targetType.render() } public data class AllSubtypes(val upperBound: JetType): TypePredicate { - override fun invoke(typeToCheck: JetType): Boolean = JetTypeChecker.INSTANCE.isSubtypeOf(typeToCheck, upperBound) + override fun invoke(typeToCheck: JetType): Boolean = JetTypeChecker.DEFAULT.isSubtypeOf(typeToCheck, upperBound) override fun toString(): String = "{<: ${upperBound.render()}}" } @@ -72,7 +72,7 @@ fun or(predicates: Collection): TypePredicate? = } fun JetType.getSubtypesPredicate(): TypePredicate? = - if (TypeUtils.canHaveSubtypes(JetTypeChecker.INSTANCE, this)) AllSubtypes(this) else SingleType(this) + if (TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, this)) AllSubtypes(this) else SingleType(this) private fun JetType.render(): String = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(this) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java index 0bf808a306e..72d3d2b52da 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/Renderers.java @@ -229,13 +229,13 @@ public class Renderers { parameterTypes.add(valueParameterDescriptor.getType()); if (valueParameterDescriptor.getIndex() >= inferenceErrorData.valueArgumentsTypes.size()) continue; JetType actualType = inferenceErrorData.valueArgumentsTypes.get(valueParameterDescriptor.getIndex()); - if (!JetTypeChecker.INSTANCE.isSubtypeOf(actualType, valueParameterDescriptor.getType())) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(actualType, valueParameterDescriptor.getType())) { errorPositions.add(ConstraintPosition.getValueParameterPosition(valueParameterDescriptor.getIndex())); } } if (receiverType != null && inferenceErrorData.receiverArgumentType != null && - !JetTypeChecker.INSTANCE.isSubtypeOf(inferenceErrorData.receiverArgumentType, receiverType)) { + !JetTypeChecker.DEFAULT.isSubtypeOf(inferenceErrorData.receiverArgumentType, receiverType)) { errorPositions.add(ConstraintPosition.RECEIVER_POSITION); } @@ -333,7 +333,7 @@ public class Renderers { JetType upperBoundWithSubstitutedInferredTypes = systemWithoutWeakConstraints.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT); if (upperBoundWithSubstitutedInferredTypes != null && - !JetTypeChecker.INSTANCE.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) { + !JetTypeChecker.DEFAULT.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) { violatedUpperBound = upperBoundWithSubstitutedInferredTypes; break; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java index a07420658a7..8c4c3bd712c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -220,13 +220,13 @@ public class DeclarationsChecker { REMOVE_IF_SUBTYPE_IN_THE_SET { @Override public boolean removeNeeded(JetType subject, JetType other) { - return JetTypeChecker.INSTANCE.isSubtypeOf(other, subject); + return JetTypeChecker.DEFAULT.isSubtypeOf(other, subject); } }, REMOVE_IF_SUPERTYPE_IN_THE_SET { @Override public boolean removeNeeded(JetType subject, JetType other) { - return JetTypeChecker.INSTANCE.isSubtypeOf(subject, other); + return JetTypeChecker.DEFAULT.isSubtypeOf(subject, other); } }; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java index 3cc288d0deb..327a1c81b5d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java @@ -98,7 +98,7 @@ public class DelegatedPropertyResolver { JetType propertyType = propertyDescriptor.getType(); /* Do not check return type of get() method of delegate for properties with DeferredType because property type is taken from it */ - if (!(propertyType instanceof DeferredType) && returnType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(returnType, propertyType)) { + if (!(propertyType instanceof DeferredType) && returnType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(returnType, propertyType)) { Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, propertyDescriptor.getGetter()); assert call != null : "Call should exists for " + propertyDescriptor.getGetter(); trace.report(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index c5f96ec1e87..9afc4b1a47a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -760,7 +760,7 @@ public class DescriptorResolver { boolean isClassObjectConstraint, BindingTrace trace ) { - if (!TypeUtils.canHaveSubtypes(JetTypeChecker.INSTANCE, upperBoundType)) { + if (!TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, upperBoundType)) { if (isClassObjectConstraint) { trace.report(FINAL_CLASS_OBJECT_UPPER_BOUND.on(upperBound, upperBoundType)); } @@ -1360,7 +1360,7 @@ public class DescriptorResolver { ) { for (JetType bound : typeParameterDescriptor.getUpperBounds()) { JetType substitutedBound = substitutor.safeSubstitute(bound, Variance.INVARIANT); - if (!JetTypeChecker.INSTANCE.isSubtypeOf(typeArgument, substitutedBound)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(typeArgument, substitutedBound)) { trace.report(UPPER_BOUND_VIOLATED.on(jetTypeArgument, substitutedBound, typeArgument)); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java index 6eccea98512..8bf3e2fc931 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java @@ -71,7 +71,7 @@ public class OverloadUtil { JetType superValueParameterType = OverridingUtil.getUpperBound(superValueParameters.get(i)); JetType subValueParameterType = OverridingUtil.getUpperBound(subValueParameters.get(i)); // TODO: compare erasure - if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) { + if (!JetTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType)) { return OverridingUtil.OverrideCompatibilityInfo .valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index 2b091f3459f..e5b1be44da5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -733,7 +733,7 @@ public class OverrideResolver { JetType substitutedSuperReturnType = typeSubstitutor.substitute(superReturnType, Variance.OUT_VARIANCE); assert substitutedSuperReturnType != null; - return JetTypeChecker.INSTANCE.isSubtypeOf(subReturnType, substitutedSuperReturnType); + return JetTypeChecker.DEFAULT.isSubtypeOf(subReturnType, substitutedSuperReturnType); } @Nullable @@ -768,7 +768,7 @@ public class OverrideResolver { JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getType(), Variance.OUT_VARIANCE); assert substitutedSuperReturnType != null; - return JetTypeChecker.INSTANCE.equalTypes(subDescriptor.getType(), substitutedSuperReturnType); + return JetTypeChecker.DEFAULT.equalTypes(subDescriptor.getType(), substitutedSuperReturnType); } private void checkOverrideForComponentFunction(@NotNull final CallableMemberDescriptor componentFunction) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java index 91f2d1d64e8..3eba4a8a729 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java @@ -74,7 +74,7 @@ public class ArgumentTypeResolver { if (actualType == PLACEHOLDER_FUNCTION_TYPE) { return isFunctionOrErrorType(expectedType) || KotlinBuiltIns.getInstance().isAnyOrNullableAny(expectedType); //todo function type extends } - return JetTypeChecker.INSTANCE.isSubtypeOf(actualType, expectedType); + return JetTypeChecker.DEFAULT.isSubtypeOf(actualType, expectedType); } private static boolean isFunctionOrErrorType(@NotNull JetType supertype) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index 1fb1f127305..2259350c967 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -735,7 +735,7 @@ public class CandidateResolver { Set possibleTypes = dataFlowInfoForArgument.getPossibleTypes(dataFlowValue); if (possibleTypes.isEmpty()) return type; - return TypeUtils.intersect(JetTypeChecker.INSTANCE, possibleTypes); + return TypeUtils.intersect(JetTypeChecker.DEFAULT, possibleTypes); } private ValueArgumentsCheckingResult checkAllValueArguments( @@ -859,7 +859,7 @@ public class CandidateResolver { List variants = AutoCastUtils.getAutoCastVariantsExcludingReceiver(context.trace.getBindingContext(), context.dataFlowInfo, receiverToCast); for (JetType possibleType : variants) { - if (JetTypeChecker.INSTANCE.isSubtypeOf(possibleType, expectedType)) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(possibleType, expectedType)) { return possibleType; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastUtils.java index 2e6bdc26d93..4991d3c4785 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/AutoCastUtils.java @@ -116,7 +116,7 @@ public class AutoCastUtils { } if (subTypes.isEmpty()) return null; - JetType intersection = TypeUtils.intersect(JetTypeChecker.INSTANCE, subTypes); + JetType intersection = TypeUtils.intersect(JetTypeChecker.DEFAULT, subTypes); if (intersection == null || !intersection.getConstructor().isDenotable()) { return receiverParameterType; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java index aec3e3562d3..ccaaaf8b12b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintsUtil.java @@ -94,7 +94,7 @@ public class ConstraintsUtil { JetType substitutedUpperBound = constraintSystem.getResultingSubstitutor().substitute(upperBound, Variance.INVARIANT); assert substitutedUpperBound != null : "We wanted to substitute projections as a result for " + typeParameter; - if (!JetTypeChecker.INSTANCE.isSubtypeOf(type, substitutedUpperBound)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(type, substitutedUpperBound)) { return false; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java index 03901b7d70a..2bd6d32a3c8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadingConflictResolver.java @@ -239,7 +239,7 @@ public class OverloadingConflictResolver { } private boolean typeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) { - return JetTypeChecker.INSTANCE.isSubtypeOf(specific, general) || + return JetTypeChecker.DEFAULT.isSubtypeOf(specific, general) || numericTypeMoreSpecific(specific, general); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java index 39eb7ff3f84..5166f22bd2a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java @@ -25,7 +25,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.psi.JetSuperExpression; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastUtils; @@ -326,7 +325,7 @@ public class TaskPrioritizer { if (expectedThisObject == null) return true; List receivers = scope.getImplicitReceiversHierarchy(); for (ReceiverParameterDescriptor receiver : receivers) { - if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) { // TODO : Autocasts & nullability candidate.setThisObject(expectedThisObject.getValue()); return true; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantChecker.java index ade5431b98a..58b04689557 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantChecker.java @@ -90,7 +90,7 @@ public class CompileTimeConstantChecker { if (!noExpectedTypeOrError(expectedType)) { JetType valueType = value.getType(KotlinBuiltIns.getInstance()); - if (!JetTypeChecker.INSTANCE.isSubtypeOf(valueType, expectedType)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) { return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "integer", expectedType)); } } @@ -107,7 +107,7 @@ public class CompileTimeConstantChecker { } if (!noExpectedTypeOrError(expectedType)) { JetType valueType = value.getType(KotlinBuiltIns.getInstance()); - if (!JetTypeChecker.INSTANCE.isSubtypeOf(valueType, expectedType)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) { return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "floating-point", expectedType)); } } @@ -119,7 +119,7 @@ public class CompileTimeConstantChecker { @NotNull JetConstantExpression expression ) { if (!noExpectedTypeOrError(expectedType) - && !JetTypeChecker.INSTANCE.isSubtypeOf(builtIns.getBooleanType(), expectedType)) { + && !JetTypeChecker.DEFAULT.isSubtypeOf(builtIns.getBooleanType(), expectedType)) { return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "boolean", expectedType)); } return false; @@ -127,7 +127,7 @@ public class CompileTimeConstantChecker { private boolean checkCharValue(CompileTimeConstant constant, JetType expectedType, JetConstantExpression expression) { if (!noExpectedTypeOrError(expectedType) - && !JetTypeChecker.INSTANCE.isSubtypeOf(builtIns.getCharType(), expectedType)) { + && !JetTypeChecker.DEFAULT.isSubtypeOf(builtIns.getCharType(), expectedType)) { return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "character", expectedType)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java index 95e8f484b89..e9032ba4682 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/CastDiagnosticsUtil.java @@ -66,8 +66,8 @@ public class CastDiagnosticsUtil { for (JetType aType : aTypes) { for (JetType bType : bTypes) { - if (JetTypeChecker.INSTANCE.isSubtypeOf(aType, bType)) return true; - if (JetTypeChecker.INSTANCE.isSubtypeOf(bType, aType)) return true; + if (JetTypeChecker.DEFAULT.isSubtypeOf(aType, bType)) return true; + if (JetTypeChecker.DEFAULT.isSubtypeOf(bType, aType)) return true; } } @@ -100,7 +100,7 @@ public class CastDiagnosticsUtil { } private static boolean isFinal(@NotNull JetType type) { - return !TypeUtils.canHaveSubtypes(JetTypeChecker.INSTANCE, type); + return !TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type); } private static boolean isTrait(@NotNull JetType type) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 0fb97d20f3f..edf331d8c97 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -212,7 +212,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace.report(CAST_NEVER_SUCCEEDS.on(expression.getOperationReference())); } else { - JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + JetTypeChecker typeChecker = JetTypeChecker.DEFAULT; // Upcast? if (typeChecker.isSubtypeOf(actualType, targetType)) { if (!typeChecker.isSubtypeOf(targetType, actualType)) { @@ -668,7 +668,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } else { JetType receiverType = receiver.getType(); - if (!JetTypeChecker.INSTANCE.isSubtypeOf(returnType, receiverType)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(returnType, receiverType)) { context.trace.report(RESULT_TYPE_MISMATCH.on(operationSign, name.asString(), receiverType, returnType)); } else { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java index 4bc6fd8baff..73331a549fb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java @@ -221,7 +221,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { if (typeReference != null) { type = components.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true); if (expectedType != null) { - if (!JetTypeChecker.INSTANCE.isSubtypeOf(expectedType, type)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(expectedType, type)) { context.trace.report(EXPECTED_PARAMETER_TYPE_MISMATCH.on(declaredParameter, expectedType)); } } @@ -278,7 +278,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions functionDescriptor.setReturnType(declaredReturnType); if (expectedReturnType != null) { - if (!JetTypeChecker.INSTANCE.isSubtypeOf(declaredReturnType, expectedReturnType)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(declaredReturnType, expectedReturnType)) { context.trace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType)); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index c8b74780ff3..e0ce8f2fcc5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -355,7 +355,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { variableDescriptor = components.expressionTypingServices.getDescriptorResolver().resolveLocalVariableDescriptor(context.scope, loopParameter, context.trace); JetType actualParameterType = variableDescriptor.getType(); if (expectedParameterType != null && - !JetTypeChecker.INSTANCE.isSubtypeOf(expectedParameterType, actualParameterType)) { + !JetTypeChecker.DEFAULT.isSubtypeOf(expectedParameterType, actualParameterType)) { context.trace.report(TYPE_MISMATCH_IN_FOR_LOOP.on(typeReference, expectedParameterType, actualParameterType)); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java index 270f4d1cba7..d8bf889087c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java @@ -164,7 +164,7 @@ public class DataFlowUtils { recordExpectedType(trace, expression, expectedType); if (expressionType == null || noExpectedType(expectedType) || !expectedType.getConstructor().isDenotable() || - JetTypeChecker.INSTANCE.isSubtypeOf(expressionType, expectedType)) { + JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType)) { return expressionType; } @@ -179,7 +179,7 @@ public class DataFlowUtils { DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, trace.getBindingContext()); for (JetType possibleType : dataFlowInfo.getPossibleTypes(dataFlowValue)) { - if (JetTypeChecker.INSTANCE.isSubtypeOf(possibleType, expectedType)) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(possibleType, expectedType)) { AutoCastUtils.recordCastOrError(expression, possibleType, trace, dataFlowValue.isStableIdentifier(), false); return possibleType; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 852453f93cb..c56aee232cf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -96,7 +96,7 @@ public class ExpressionTypingUtils { } public static boolean isBoolean(@NotNull JetType type) { - return JetTypeChecker.INSTANCE.isSubtypeOf(type, KotlinBuiltIns.getInstance().getBooleanType()); + return JetTypeChecker.DEFAULT.isSubtypeOf(type, KotlinBuiltIns.getInstance().getBooleanType()); } public static boolean ensureBooleanResult(JetExpression operationSign, Name name, JetType resultType, ExpressionTypingContext context) { @@ -401,7 +401,7 @@ public class ExpressionTypingUtils { context.trace.record(COMPONENT_RESOLVED_CALL, entry, results.getResultingCall()); componentType = results.getResultingDescriptor().getReturnType(); if (componentType != null && !noExpectedType(expectedType) - && !JetTypeChecker.INSTANCE.isSubtypeOf(componentType, expectedType)) { + && !JetTypeChecker.DEFAULT.isSubtypeOf(componentType, expectedType)) { context.trace.report( COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.on(reportErrorsOn, componentName, componentType, expectedType)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index a3692734077..f9b036c492a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -254,7 +254,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()); if (conditionExpected) { JetType booleanType = KotlinBuiltIns.getInstance().getBooleanType(); - if (!JetTypeChecker.INSTANCE.equalTypes(booleanType, type)) { + if (!JetTypeChecker.DEFAULT.equalTypes(booleanType, type)) { context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(expression, type)); } else { @@ -294,7 +294,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { context.trace.report(Errors.USELESS_NULLABLE_CHECK.on(nullableType)); } checkTypeCompatibility(context, type, subjectType, typeReferenceAfterIs); - if (CastDiagnosticsUtil.isCastErased(subjectType, type, JetTypeChecker.INSTANCE)) { + if (CastDiagnosticsUtil.isCastErased(subjectType, type, JetTypeChecker.DEFAULT)) { context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(typeReferenceAfterIs, type)); } return new DataFlowInfos(context.dataFlowInfo.establishSubtyping(subjectDataFlowValue, type), context.dataFlowInfo); diff --git a/compiler/frontend/src/org/jetbrains/jet/plugin/MainFunctionDetector.java b/compiler/frontend/src/org/jetbrains/jet/plugin/MainFunctionDetector.java index 46b9dcfff8f..33fb189f141 100644 --- a/compiler/frontend/src/org/jetbrains/jet/plugin/MainFunctionDetector.java +++ b/compiler/frontend/src/org/jetbrains/jet/plugin/MainFunctionDetector.java @@ -80,7 +80,7 @@ public class MainFunctionDetector { List typeArguments = parameterType.getArguments(); if (typeArguments.size() == 1) { JetType typeArgument = typeArguments.get(0).getType(); - if (JetTypeChecker.INSTANCE.equalTypes(typeArgument, kotlinBuiltIns.getStringType())) { + if (JetTypeChecker.DEFAULT.equalTypes(typeArgument, kotlinBuiltIns.getStringType())) { return true; } } diff --git a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 5899e002084..ae686135ce9 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -503,7 +503,7 @@ public class JetTypeCheckerTest extends JetLiteFixture { for (String type : types) { typesToIntersect.add(makeType(type)); } - JetType result = TypeUtils.intersect(JetTypeChecker.INSTANCE, typesToIntersect); + JetType result = TypeUtils.intersect(JetTypeChecker.DEFAULT, typesToIntersect); // assertNotNull("Intersection is null for " + typesToIntersect, result); assertEquals(makeType(expected), result); } @@ -520,7 +520,7 @@ public class JetTypeCheckerTest extends JetLiteFixture { private void assertSubtypingRelation(String subtype, String supertype, boolean expected) { JetType typeNode1 = makeType(subtype); JetType typeNode2 = makeType(supertype); - boolean result = JetTypeChecker.INSTANCE.isSubtypeOf( + boolean result = JetTypeChecker.DEFAULT.isSubtypeOf( typeNode1, typeNode2); String modifier = expected ? "not " : ""; diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/descriptors/LazyJavaClassDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/descriptors/LazyJavaClassDescriptor.kt index 01be75b4317..80b1b5a09ec 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/descriptors/LazyJavaClassDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/descriptors/LazyJavaClassDescriptor.kt @@ -181,7 +181,7 @@ class LazyJavaClassDescriptor( val candidateReturnType = candidate.getReturnType() val currentMostSpecificReturnType = currentMostSpecificType.getReturnType() assert(candidateReturnType != null && currentMostSpecificReturnType != null, "$candidate, $currentMostSpecificReturnType") - if (JetTypeChecker.INSTANCE.isSubtypeOf(candidateReturnType!!, currentMostSpecificReturnType!!)) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(candidateReturnType!!, currentMostSpecificReturnType!!)) { currentMostSpecificType = candidate } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt index 25ca250653d..b9f46f376cb 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/types/LazyJavaTypeResolver.kt @@ -147,7 +147,7 @@ class LazyJavaTypeResolver( for (supertype in (classifier() as JavaTypeParameter).getUpperBounds()) { supertypesJet.add(transformJavaType(supertype, UPPER_BOUND.toAttributes())) } - return TypeUtils.intersect(JetTypeChecker.INSTANCE, supertypesJet) + return TypeUtils.intersect(JetTypeChecker.DEFAULT, supertypesJet) ?: ErrorUtils.createErrorType("Can't intersect upper bounds of " + javaType.getPresentableText()) } @@ -276,4 +276,4 @@ fun TypeUsage.toAttributes() = object : JavaTypeAttributes { override val howThisTypeIsUsedAccordingToAnnotations: TypeUsage get() = howThisTypeIsUsed override val isMarkedNotNull: Boolean = false -} \ No newline at end of file +} diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractTypeParameterDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractTypeParameterDescriptor.java index 9be787d0c5b..07994b4070a 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractTypeParameterDescriptor.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractTypeParameterDescriptor.java @@ -132,7 +132,7 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip private JetType computeUpperBoundsAsType() { Set upperBounds = getUpperBounds(); assert !upperBounds.isEmpty() : "Upper bound list is empty in " + getName(); - JetType upperBoundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds); + JetType upperBoundsAsType = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds); return upperBoundsAsType != null ? upperBoundsAsType : KotlinBuiltIns.getInstance().getNothingType(); } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 6a51a1e1a1b..fd07e32b8ca 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -459,7 +459,7 @@ public class DescriptorUtils { JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType()); return "valueOf".equals(functionDescriptor.getName().asString()) && methodTypeParameters.size() == 1 - && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString); + && JetTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString); } public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) { diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index f5e744d2da5..942ddd72841 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -113,7 +113,7 @@ public class OverridingUtil { JetType superValueParameterType = getUpperBound(superValueParameters.get(i)); JetType subValueParameterType = getUpperBound(subValueParameters.get(i)); // TODO: compare erasure - if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) { + if (!JetTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType)) { return OverrideCompatibilityInfo.typeParameterNumberMismatch(); } } @@ -165,7 +165,7 @@ public class OverridingUtil { if (superReturnType != null && subReturnType != null) { boolean bothErrors = subReturnType.isError() && superReturnType.isError(); - if (!bothErrors && !JetTypeChecker.INSTANCE.isSubtypeOf(subReturnType, superReturnType, localEqualityAxioms)) { + if (!bothErrors && !JetTypeChecker.DEFAULT.isSubtypeOf(subReturnType, superReturnType, localEqualityAxioms)) { return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType); } } @@ -203,7 +203,7 @@ public class OverridingUtil { @NotNull JetTypeChecker.TypeConstructorEquality axioms ) { boolean bothErrors = typeInSuper.isError() && typeInSub.isError(); - if (!bothErrors && !JetTypeChecker.INSTANCE.equalTypes(typeInSuper, typeInSub, axioms)) { + if (!bothErrors && !JetTypeChecker.DEFAULT.equalTypes(typeInSuper, typeInSub, axioms)) { return false; } return true; @@ -317,7 +317,7 @@ public class OverridingUtil { JetType bReturnType = b.getReturnType(); assert bReturnType != null; - return JetTypeChecker.INSTANCE.isSubtypeOf(aReturnType, bReturnType); + return JetTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType); } if (a instanceof PropertyDescriptor) { assert b instanceof PropertyDescriptor : "b is " + b.getClass(); @@ -327,7 +327,7 @@ public class OverridingUtil { } // both vals - return JetTypeChecker.INSTANCE.isSubtypeOf(((PropertyDescriptor) a).getType(), ((PropertyDescriptor) b).getType()); + return JetTypeChecker.DEFAULT.isSubtypeOf(((PropertyDescriptor) a).getType(), ((PropertyDescriptor) b).getType()); } throw new IllegalArgumentException("Unexpected callable: " + a.getClass()); } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeBoundsImpl.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeBoundsImpl.java index 20ef01fb9f0..cb08c23f4b7 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeBoundsImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeBoundsImpl.java @@ -197,7 +197,7 @@ public class TypeBoundsImpl implements TypeBounds { } Set upperBounds = filterBounds(bounds, BoundKind.UPPER_BOUND, values); - JetType intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds); + JetType intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds); if (!upperBounds.isEmpty() && intersectionOfUpperBounds != null) { if (tryPossibleAnswer(intersectionOfUpperBounds)) { return Collections.singleton(intersectionOfUpperBounds); @@ -216,19 +216,19 @@ public class TypeBoundsImpl implements TypeBounds { for (Bound bound : bounds) { switch (bound.kind) { case LOWER_BOUND: - if (!JetTypeChecker.INSTANCE.isSubtypeOf(bound.type, possibleAnswer)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(bound.type, possibleAnswer)) { return false; } break; case UPPER_BOUND: - if (!JetTypeChecker.INSTANCE.isSubtypeOf(possibleAnswer, bound.type)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(possibleAnswer, bound.type)) { return false; } break; case EXACT_BOUND: - if (!JetTypeChecker.INSTANCE.equalTypes(bound.type, possibleAnswer)) { + if (!JetTypeChecker.DEFAULT.equalTypes(bound.type, possibleAnswer)) { return false; } break; diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java index 4be5948ab9f..816fb52f8f3 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java @@ -352,7 +352,7 @@ public class WritableScopeImpl extends WritableScopeWithImports { for (VariableDescriptor oldProperty : properties) { ReceiverParameterDescriptor receiverParameterForOldVariable = oldProperty.getReceiverParameter(); if (((receiverParameter != null && receiverParameterForOldVariable != null) && - (JetTypeChecker.INSTANCE.equalTypes(receiverParameter.getType(), receiverParameterForOldVariable.getType())))) { + (JetTypeChecker.DEFAULT.equalTypes(receiverParameter.getType(), receiverParameterForOldVariable.getType())))) { redeclarationHandler.handleRedeclaration(oldProperty, variableDescriptor); } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/AbstractJetType.java b/core/descriptors/src/org/jetbrains/jet/lang/types/AbstractJetType.java index d5ddee2fd74..4cbed4bca24 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/AbstractJetType.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/AbstractJetType.java @@ -37,7 +37,7 @@ public abstract class AbstractJetType implements JetType { JetType type = (JetType) obj; - return isNullable() == type.isNullable() && JetTypeChecker.INSTANCE.equalTypes(this, type); + return isNullable() == type.isNullable() && JetTypeChecker.DEFAULT.equalTypes(this, type); } @Override diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/CommonSupertypes.java b/core/descriptors/src/org/jetbrains/jet/lang/types/CommonSupertypes.java index 4c2eb28cd2c..100f56f3b9d 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/CommonSupertypes.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/CommonSupertypes.java @@ -216,7 +216,7 @@ public class CommonSupertypes { } if (ins != null) { - JetType intersection = TypeUtils.intersect(JetTypeChecker.INSTANCE, ins); + JetType intersection = TypeUtils.intersect(JetTypeChecker.DEFAULT, ins); if (intersection == null) { if (outs != null) { return new TypeProjectionImpl(OUT_VARIANCE, commonSupertype(outs)); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java index 084f1b64deb..ecebe07b469 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -142,7 +142,7 @@ public class TypeUtils { } public static boolean isIntersectionEmpty(@NotNull JetType typeA, @NotNull JetType typeB) { - return intersect(JetTypeChecker.INSTANCE, Sets.newLinkedHashSet(Lists.newArrayList(typeA, typeB))) == null; + return intersect(JetTypeChecker.DEFAULT, Sets.newLinkedHashSet(Lists.newArrayList(typeA, typeB))) == null; } @Nullable @@ -473,7 +473,7 @@ public class TypeUtils { } public static boolean equalTypes(@NotNull JetType a, @NotNull JetType b) { - return JetTypeChecker.INSTANCE.isSubtypeOf(a, b) && JetTypeChecker.INSTANCE.isSubtypeOf(b, a); + return JetTypeChecker.DEFAULT.isSubtypeOf(a, b) && JetTypeChecker.DEFAULT.isSubtypeOf(b, a); } public static boolean dependsOnTypeParameters(@NotNull JetType type, @NotNull Collection typeParameters) { @@ -586,7 +586,7 @@ public class TypeUtils { return getDefaultPrimitiveNumberType(numberValueTypeConstructor); } for (JetType primitiveNumberType : numberValueTypeConstructor.getSupertypes()) { - if (JetTypeChecker.INSTANCE.isSubtypeOf(primitiveNumberType, expectedType)) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(primitiveNumberType, expectedType)) { return primitiveNumberType; } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java index 9c190e67c77..7f52422fc7b 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java @@ -22,7 +22,7 @@ import org.jetbrains.jet.lang.types.TypeConstructor; public class JetTypeChecker { - public static final JetTypeChecker INSTANCE = new JetTypeChecker(); + public static final JetTypeChecker DEFAULT = new JetTypeChecker(); public interface TypeConstructorEquality { boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b); } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt b/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt index 7300d4bf674..ebc4e640e5d 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt @@ -172,7 +172,7 @@ fun createLookupElement(descriptor: DeclarationDescriptor, resolveSession: Resol return if (descriptor is FunctionDescriptor && descriptor.getValueParameters().isNotEmpty()) element.keepOldArgumentListOnTab() else element } -fun JetType.isSubtypeOf(expectedType: JetType) = !isError() && JetTypeChecker.INSTANCE.isSubtypeOf(this, expectedType) +fun JetType.isSubtypeOf(expectedType: JetType) = !isError() && JetTypeChecker.DEFAULT.isSubtypeOf(this, expectedType) fun T?.toList(): List = if (this != null) listOf(this) else listOf() fun T?.toSet(): Set = if (this != null) setOf(this) else setOf() diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/attributeCallReplacements/ReplaceContainsIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/attributeCallReplacements/ReplaceContainsIntention.kt index 00fd6a0167e..e44059121fe 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/attributeCallReplacements/ReplaceContainsIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/attributeCallReplacements/ReplaceContainsIntention.kt @@ -35,7 +35,7 @@ public open class ReplaceContainsIntention : AttributeCallReplacementIntention(" val ret = call.resolved.getResultingDescriptor().getReturnType() ?: return intentionFailed(editor, "undefined.returntype") - if (!JetTypeChecker.INSTANCE.isSubtypeOf(ret, KotlinBuiltIns.getInstance().getBooleanType())) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(ret, KotlinBuiltIns.getInstance().getBooleanType())) { return intentionFailed(editor, "contains.returns.boolean") } diff --git a/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java b/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java index 08b53ebb4d2..c31950ace67 100644 --- a/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java @@ -327,7 +327,7 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith if (argument.getArgumentExpression() != null) { JetType paramType = getActualParameterType(param); JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression()); - return exprType == null || JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType); + return exprType == null || JetTypeChecker.DEFAULT.isSubtypeOf(exprType, paramType); } return false; diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java index dd64bfbeff5..6a57910e7ed 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionParametersFix.java @@ -127,7 +127,7 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix { JetType argumentType = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null; JetType parameterType = parameters.get(i).getType(); - if (argumentType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(argumentType, parameterType)) + if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) changeSignatureData.getParameters().get(i).setTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(argumentType)); } else { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionToSupertypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionToSupertypeFix.java index 816b583f2c0..aac9af29ccd 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionToSupertypeFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddFunctionToSupertypeFix.java @@ -76,10 +76,10 @@ public class AddFunctionToSupertypeFix extends JetHintAction { if (o1.equals(o2)) { return 0; } - if (JetTypeChecker.INSTANCE.isSubtypeOf(o1, o2)) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(o1, o2)) { return -1; } - if (JetTypeChecker.INSTANCE.isSubtypeOf(o2, o1)) { + if (JetTypeChecker.DEFAULT.isSubtypeOf(o2, o1)) { return 1; } return o1.toString().compareTo(o2.toString()); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddNameToArgumentFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddNameToArgumentFix.java index 4a60dc9aefb..b8785740004 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddNameToArgumentFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddNameToArgumentFix.java @@ -76,7 +76,7 @@ public class AddNameToArgumentFix extends JetIntentionAction { for (ValueParameterDescriptor parameter: callableDescriptor.getValueParameters()) { String name = parameter.getName().asString(); if (usedParameters.contains(name)) continue; - if (type == null || JetTypeChecker.INSTANCE.isSubtypeOf(type, parameter.getType())) { + if (type == null || JetTypeChecker.DEFAULT.isSubtypeOf(type, parameter.getType())) { names.add(name); } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/CastExpressionFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/CastExpressionFix.java index 4390f5eff4f..5315f2f9a8b 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/CastExpressionFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/CastExpressionFix.java @@ -61,7 +61,7 @@ public class CastExpressionFix extends JetIntentionAction { if (!super.isAvailable(project, editor, file)) return false; BindingContext context = ResolvePackage.getBindingContext((JetFile) file); JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, element); - return expressionType != null && JetTypeChecker.INSTANCE.isSubtypeOf(type, expressionType); + return expressionType != null && JetTypeChecker.DEFAULT.isSubtypeOf(type, expressionType); } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java index d72d5ef61fa..e850ebac514 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionLiteralReturnTypeFix.java @@ -68,7 +68,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction for (FunctionDescriptor overriddenFunction: descriptor.getOverriddenDescriptors()) { JetType overriddenFunctionType = overriddenFunction.getReturnType(); if (overriddenFunctionType == null) continue; - if (!JetTypeChecker.INSTANCE.isSubtypeOf(functionType, overriddenFunctionType)) { + if (!JetTypeChecker.DEFAULT.isSubtypeOf(functionType, overriddenFunctionType)) { overriddenMismatchingFunctions.add(overriddenFunction); } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java index f5094022b7d..2be9908055b 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionSignatureFix.java @@ -132,7 +132,7 @@ public abstract class ChangeFunctionSignatureFix extends JetIntentionAction ErrorUtils.containsErrorType(expectedType) }) { return array() } - val theType = TypeUtils.intersect(JetTypeChecker.INSTANCE, expectedTypes) + val theType = TypeUtils.intersect(JetTypeChecker.DEFAULT, expectedTypes) if (theType != null) { return array(theType) } @@ -494,8 +494,8 @@ private class JetTypeSubstitution(public val forType: JetType, public val byType private fun JetType.substitute(substitution: JetTypeSubstitution, variance: Variance): JetType { if (when (variance) { Variance.INVARIANT -> this == substitution.forType - Variance.IN_VARIANCE -> JetTypeChecker.INSTANCE.isSubtypeOf(this, substitution.forType) - Variance.OUT_VARIANCE -> JetTypeChecker.INSTANCE.isSubtypeOf(substitution.forType, this) + Variance.IN_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(this, substitution.forType) + Variance.OUT_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(substitution.forType, this) }) { return substitution.byType } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java index b807f17be18..65e26224f91 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixUtil.java @@ -90,10 +90,10 @@ public class QuickFixUtil { if (overriddenReturnType == null) { return null; } - if (matchingReturnType == null || JetTypeChecker.INSTANCE.isSubtypeOf(overriddenReturnType, matchingReturnType)) { + if (matchingReturnType == null || JetTypeChecker.DEFAULT.isSubtypeOf(overriddenReturnType, matchingReturnType)) { matchingReturnType = overriddenReturnType; } - else if (!JetTypeChecker.INSTANCE.isSubtypeOf(matchingReturnType, overriddenReturnType)) { + else if (!JetTypeChecker.DEFAULT.isSubtypeOf(matchingReturnType, overriddenReturnType)) { return null; } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java index 24674e39958..a7efdec3eaa 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameSuggester.java @@ -98,7 +98,7 @@ public class JetNameSuggester { private static void addNamesForType(ArrayList result, JetType jetType, JetNameValidator validator) { KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); - JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + JetTypeChecker typeChecker = JetTypeChecker.DEFAULT; jetType = TypeUtils.makeNotNullable(jetType); // wipe out '?' if (ErrorUtils.containsErrorType(jetType)) return; if (typeChecker.equalTypes(builtIns.getBooleanType(), jetType)) { diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java index 2509d0e1c92..43af6fed9b4 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java @@ -440,7 +440,7 @@ public class JetRefactoringUtil { BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(expression); JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); if (expressionType == null || !(expressionType instanceof PackageType) && - !JetTypeChecker.INSTANCE.equalTypes(KotlinBuiltIns. + !JetTypeChecker.DEFAULT.equalTypes(KotlinBuiltIns. getInstance().getUnitType(), expressionType)) { expressions.add(expression); } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java index 4050baea7c2..422ec0d83c3 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java @@ -31,11 +31,8 @@ import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.introduce.inplace.OccurrencesChooser; -import kotlin.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.analyzer.AnalyzerPackage; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -139,7 +136,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase { JetType typeNoExpectedType = AnalyzerPackage.computeTypeInfoInContext( expression, scope, bindingTrace, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, resolveSession.getModuleDescriptor() ).getType(); - if (expressionType != null && typeNoExpectedType != null && !JetTypeChecker.INSTANCE.equalTypes(expressionType, + if (expressionType != null && typeNoExpectedType != null && !JetTypeChecker.DEFAULT.equalTypes(expressionType, typeNoExpectedType)) { noTypeInference = true; } @@ -149,7 +146,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase { return; } if (expressionType != null && - JetTypeChecker.INSTANCE.equalTypes(KotlinBuiltIns.getInstance().getUnitType(), expressionType)) { + JetTypeChecker.DEFAULT.equalTypes(KotlinBuiltIns.getInstance().getUnitType(), expressionType)) { showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.expression.has.unit.type")); return; } From 97b7768890eb7fc7d731500ad140b7f63235dbaa Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 23 Jun 2014 15:39:46 +0400 Subject: [PATCH 107/143] JetTypeChecker refactored: duplicate methods replaced by instance management --- .../jet/lang/resolve/OverridingUtil.java | 4 +- .../lang/types/checker/JetTypeChecker.java | 40 ++++++++----------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 942ddd72841..09c3abc67a9 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -165,7 +165,7 @@ public class OverridingUtil { if (superReturnType != null && subReturnType != null) { boolean bothErrors = subReturnType.isError() && superReturnType.isError(); - if (!bothErrors && !JetTypeChecker.DEFAULT.isSubtypeOf(subReturnType, superReturnType, localEqualityAxioms)) { + if (!bothErrors && !JetTypeChecker.withAxioms(localEqualityAxioms).isSubtypeOf(subReturnType, superReturnType)) { return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType); } } @@ -203,7 +203,7 @@ public class OverridingUtil { @NotNull JetTypeChecker.TypeConstructorEquality axioms ) { boolean bothErrors = typeInSuper.isError() && typeInSub.isError(); - if (!bothErrors && !JetTypeChecker.DEFAULT.equalTypes(typeInSuper, typeInSub, axioms)) { + if (!bothErrors && !JetTypeChecker.withAxioms(axioms).equalTypes(typeInSuper, typeInSub)) { return false; } return true; diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java index 7f52422fc7b..aaa4cc0a3b9 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java @@ -22,39 +22,33 @@ import org.jetbrains.jet.lang.types.TypeConstructor; public class JetTypeChecker { - public static final JetTypeChecker DEFAULT = new JetTypeChecker(); public interface TypeConstructorEquality { boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b); } - private JetTypeChecker() { - } - - public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { - return TYPE_CHECKER.isSubtypeOf(subtype, supertype); - } - - public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeConstructorEquality equalityAxioms) { - return createWithAxioms(equalityAxioms).isSubtypeOf(subtype, supertype); - } - - public boolean equalTypes(@NotNull JetType a, @NotNull JetType b) { - return TYPE_CHECKER.equalTypes(a, b); - } - - public boolean equalTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeConstructorEquality equalityAxioms) { - return createWithAxioms(equalityAxioms).equalTypes(a, b); - } + public static final JetTypeChecker DEFAULT = new JetTypeChecker(new TypeCheckingProcedure(new TypeCheckerTypingConstraints())); @NotNull - private static TypeCheckingProcedure createWithAxioms(@NotNull final TypeConstructorEquality equalityAxioms) { - return new TypeCheckingProcedure(new TypeCheckerTypingConstraints() { + public static JetTypeChecker withAxioms(@NotNull final TypeConstructorEquality equalityAxioms) { + return new JetTypeChecker(new TypeCheckingProcedure(new TypeCheckerTypingConstraints() { @Override public boolean assertEqualTypeConstructors(@NotNull TypeConstructor constructor1, @NotNull TypeConstructor constructor2) { return constructor1.equals(constructor2) || equalityAxioms.equals(constructor1, constructor2); } - }); + })); } - private static final TypeCheckingProcedure TYPE_CHECKER = new TypeCheckingProcedure(new TypeCheckerTypingConstraints()); + private final TypeCheckingProcedure procedure; + + private JetTypeChecker(@NotNull TypeCheckingProcedure procedure) { + this.procedure = procedure; + } + + public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { + return procedure.isSubtypeOf(subtype, supertype); + } + + public boolean equalTypes(@NotNull JetType a, @NotNull JetType b) { + return procedure.equalTypes(a, b); + } } From 0355b1bd539d57ad03de6997d17659e43d163be2 Mon Sep 17 00:00:00 2001 From: zarechenskiy Date: Tue, 24 Jun 2014 15:24:22 +0400 Subject: [PATCH 108/143] Implement JavaTypeSubstitutor without PSI --- .../java/structure/impl/JavaClassImpl.java | 31 ++- .../impl/JavaClassifierTypeImpl.java | 28 +- .../java/structure/impl/JavaTypeImpl.java | 10 +- .../structure/impl/JavaTypeProviderImpl.java | 20 ++ .../impl/JavaTypeSubstitutorImpl.java | 169 +++++++++--- .../resolve/java/structure/JavaClass.java | 3 + .../java/structure/JavaTypeProvider.java | 9 + .../jet/generators/tests/GenerateTests.kt | 6 + idea/testData/typeSubstitution/arrayType.java | 8 + idea/testData/typeSubstitution/classType.java | 8 + .../typeSubstitution/classWithWildcard.java | 10 + .../typeSubstitution/genericArray.java | 8 + .../typeSubstitution/innerParameter.java | 10 + .../typeSubstitution/intersectionType.java | 10 + .../intersectionTypeAsTypeParameter.java | 10 + .../intersectionTypeInEnum.java | 10 + ...ntersectionTypeInInterfaceDeclaration.java | 8 + .../intersectionTypeInTypeVariableClass.java | 10 + idea/testData/typeSubstitution/mapEntry.java | 10 + .../typeSubstitution/primitiveType.java | 8 + .../typeSubstitution/rawArrayType.java | 8 + .../rawArrayTypeParameterWithBound.java | 8 + idea/testData/typeSubstitution/rawEnum.java | 8 + .../typeSubstitution/rawExtendsWildcard.java | 10 + .../typeSubstitution/rawIntersectionType.java | 8 + .../typeSubstitution/rawSuperWildcard.java | 10 + idea/testData/typeSubstitution/rawType.java | 8 + .../rawTypeInDeclaration.java | 10 + .../typeSubstitution/rawTypeWithBound.java | 8 + .../rawTypeWithSelfReferenceBound.java | 8 + .../rawWildcardInTypeVariableClass.java | 10 + .../rawWildcardWithBound.java | 10 + .../typeSubstitution/selfReference.java | 10 + .../typeSubstitution/twoParameters.java | 10 + .../twoParametersInSubClass.java | 10 + .../typeSubstitution/typeVariableClass.java | 10 + .../typeSubstitution/typeVariableRaw.java | 10 + .../typeSubstitution/unboundedWildcard.java | 10 + .../unboundedWildcardToTypeParameter.java | 8 + .../typeSubstitution/varargArray.java | 10 + .../varargArrayTypeParameter.java | 10 + .../typeSubstitution/varargClass.java | 10 + .../varargClassWithWildcard.java | 10 + .../typeSubstitution/varargRawType.java | 10 + .../varargRawTypeWithBound.java | 10 + .../typeSubstitution/varargToClass.java | 10 + .../varargToClassWithWildcard.java | 10 + .../typeSubstitution/wildcardExtends.java | 10 + .../wildcardExtendsObject.java | 10 + .../wildcardExtendsTypeParameter.java | 10 + .../typeSubstitution/wildcardSuper.java | 10 + .../typeSubstitution/wildcardToWildcard.java | 8 + .../java/AbstractJavaTypeSubstitutorTest.java | 115 ++++++++ .../JavaTypeSubstitutorTestGenerated.java | 259 ++++++++++++++++++ 54 files changed, 1000 insertions(+), 62 deletions(-) create mode 100644 idea/testData/typeSubstitution/arrayType.java create mode 100644 idea/testData/typeSubstitution/classType.java create mode 100644 idea/testData/typeSubstitution/classWithWildcard.java create mode 100644 idea/testData/typeSubstitution/genericArray.java create mode 100644 idea/testData/typeSubstitution/innerParameter.java create mode 100644 idea/testData/typeSubstitution/intersectionType.java create mode 100644 idea/testData/typeSubstitution/intersectionTypeAsTypeParameter.java create mode 100644 idea/testData/typeSubstitution/intersectionTypeInEnum.java create mode 100644 idea/testData/typeSubstitution/intersectionTypeInInterfaceDeclaration.java create mode 100644 idea/testData/typeSubstitution/intersectionTypeInTypeVariableClass.java create mode 100644 idea/testData/typeSubstitution/mapEntry.java create mode 100644 idea/testData/typeSubstitution/primitiveType.java create mode 100644 idea/testData/typeSubstitution/rawArrayType.java create mode 100644 idea/testData/typeSubstitution/rawArrayTypeParameterWithBound.java create mode 100644 idea/testData/typeSubstitution/rawEnum.java create mode 100644 idea/testData/typeSubstitution/rawExtendsWildcard.java create mode 100644 idea/testData/typeSubstitution/rawIntersectionType.java create mode 100644 idea/testData/typeSubstitution/rawSuperWildcard.java create mode 100644 idea/testData/typeSubstitution/rawType.java create mode 100644 idea/testData/typeSubstitution/rawTypeInDeclaration.java create mode 100644 idea/testData/typeSubstitution/rawTypeWithBound.java create mode 100644 idea/testData/typeSubstitution/rawTypeWithSelfReferenceBound.java create mode 100644 idea/testData/typeSubstitution/rawWildcardInTypeVariableClass.java create mode 100644 idea/testData/typeSubstitution/rawWildcardWithBound.java create mode 100644 idea/testData/typeSubstitution/selfReference.java create mode 100644 idea/testData/typeSubstitution/twoParameters.java create mode 100644 idea/testData/typeSubstitution/twoParametersInSubClass.java create mode 100644 idea/testData/typeSubstitution/typeVariableClass.java create mode 100644 idea/testData/typeSubstitution/typeVariableRaw.java create mode 100644 idea/testData/typeSubstitution/unboundedWildcard.java create mode 100644 idea/testData/typeSubstitution/unboundedWildcardToTypeParameter.java create mode 100644 idea/testData/typeSubstitution/varargArray.java create mode 100644 idea/testData/typeSubstitution/varargArrayTypeParameter.java create mode 100644 idea/testData/typeSubstitution/varargClass.java create mode 100644 idea/testData/typeSubstitution/varargClassWithWildcard.java create mode 100644 idea/testData/typeSubstitution/varargRawType.java create mode 100644 idea/testData/typeSubstitution/varargRawTypeWithBound.java create mode 100644 idea/testData/typeSubstitution/varargToClass.java create mode 100644 idea/testData/typeSubstitution/varargToClassWithWildcard.java create mode 100644 idea/testData/typeSubstitution/wildcardExtends.java create mode 100644 idea/testData/typeSubstitution/wildcardExtendsObject.java create mode 100644 idea/testData/typeSubstitution/wildcardExtendsTypeParameter.java create mode 100644 idea/testData/typeSubstitution/wildcardSuper.java create mode 100644 idea/testData/typeSubstitution/wildcardToWildcard.java create mode 100644 idea/tests/org/jetbrains/jet/lang/resolve/java/AbstractJavaTypeSubstitutorTest.java create mode 100644 idea/tests/org/jetbrains/jet/lang/resolve/java/JavaTypeSubstitutorTestGenerated.java diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassImpl.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassImpl.java index 39050e233d4..9bd7d799793 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassImpl.java @@ -16,10 +16,8 @@ package org.jetbrains.jet.lang.resolve.java.structure.impl; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiCompiledElement; -import com.intellij.psi.PsiTypeParameter; +import com.intellij.psi.*; +import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,7 +28,9 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.jetbrains.jet.lang.resolve.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.*; @@ -181,4 +181,27 @@ public class JavaClassImpl extends JavaClassifierImpl implements JavaC return OriginKind.SOURCE; } } + + @NotNull + @Override + public JavaType createImmediateType(@NotNull JavaTypeSubstitutor substitutor) { + return new JavaClassifierTypeImpl( + JavaPsiFacade.getElementFactory(getPsi().getProject()).createType(getPsi(), createPsiSubstitutor(substitutor))); + } + + @NotNull + private static PsiSubstitutor createPsiSubstitutor(@NotNull JavaTypeSubstitutor substitutor) { + Map substMap = new HashMap(); + for (Map.Entry entry : substitutor.getSubstitutionMap().entrySet()) { + PsiTypeParameter key = ((JavaTypeParameterImpl) entry.getKey()).getPsi(); + if (entry.getValue() == null) { + substMap.put(key, null); + } + else { + substMap.put(key, ((JavaTypeImpl) entry.getValue()).getPsi()); + } + } + + return PsiSubstitutorImpl.createSubstitutor(substMap); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassifierTypeImpl.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassifierTypeImpl.java index 13493d162c6..d91be1c9ca7 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassifierTypeImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaClassifierTypeImpl.java @@ -16,20 +16,12 @@ package org.jetbrains.jet.lang.resolve.java.structure.impl; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiClassType; -import com.intellij.psi.PsiType; +import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.resolve.java.structure.JavaClassifier; -import org.jetbrains.jet.lang.resolve.java.structure.JavaClassifierType; -import org.jetbrains.jet.lang.resolve.java.structure.JavaType; -import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeSubstitutor; +import org.jetbrains.jet.lang.resolve.java.structure.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import static org.jetbrains.jet.lang.resolve.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.types; @@ -68,13 +60,25 @@ public class JavaClassifierTypeImpl extends JavaTypeImpl implement if (resolutionResult == null) { PsiClassType.ClassResolveResult result = getPsi().resolveGenerics(); PsiClass psiClass = result.getElement(); + PsiSubstitutor substitutor = result.getSubstitutor(); resolutionResult = new ResolutionResult( psiClass == null ? null : JavaClassifierImpl.create(psiClass), - new JavaTypeSubstitutorImpl(result.getSubstitutor()) + new JavaTypeSubstitutorImpl(convertSubstitutionMap(substitutor.getSubstitutionMap())) ); } } + @NotNull + private Map convertSubstitutionMap(@NotNull Map psiMap) { + Map substitutionMap = new HashMap(); + for (Map.Entry entry : psiMap.entrySet()) { + PsiType value = entry.getValue(); + substitutionMap.put(new JavaTypeParameterImpl(entry.getKey()), value == null ? null : JavaTypeImpl.create(value)); + } + + return substitutionMap; + } + @Override @NotNull public Collection getSupertypes() { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeImpl.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeImpl.java index 680d5c53cdb..d859abdba9c 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeImpl.java @@ -39,31 +39,31 @@ public abstract class JavaTypeImpl implements JavaType { return psiType.accept(new PsiTypeVisitor>() { @Nullable @Override - public JavaTypeImpl visitType(PsiType type) { + public JavaTypeImpl visitType(@NotNull PsiType type) { throw new UnsupportedOperationException("Unsupported PsiType: " + type); } @Nullable @Override - public JavaTypeImpl visitPrimitiveType(PsiPrimitiveType primitiveType) { + public JavaTypeImpl visitPrimitiveType(@NotNull PsiPrimitiveType primitiveType) { return new JavaPrimitiveTypeImpl(primitiveType); } @Nullable @Override - public JavaTypeImpl visitArrayType(PsiArrayType arrayType) { + public JavaTypeImpl visitArrayType(@NotNull PsiArrayType arrayType) { return new JavaArrayTypeImpl(arrayType); } @Nullable @Override - public JavaTypeImpl visitClassType(PsiClassType classType) { + public JavaTypeImpl visitClassType(@NotNull PsiClassType classType) { return new JavaClassifierTypeImpl(classType); } @Nullable @Override - public JavaTypeImpl visitWildcardType(PsiWildcardType wildcardType) { + public JavaTypeImpl visitWildcardType(@NotNull PsiWildcardType wildcardType) { return new JavaWildcardTypeImpl(wildcardType); } }); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeProviderImpl.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeProviderImpl.java index 45ad66eaf8a..6c45f61f0ad 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeProviderImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeProviderImpl.java @@ -18,10 +18,12 @@ package org.jetbrains.jet.lang.resolve.java.structure.impl; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiType; +import com.intellij.psi.PsiWildcardType; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.java.structure.JavaType; import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeProvider; +import org.jetbrains.jet.lang.resolve.java.structure.JavaWildcardType; public class JavaTypeProviderImpl implements JavaTypeProvider { private final PsiManager manager; @@ -35,4 +37,22 @@ public class JavaTypeProviderImpl implements JavaTypeProvider { public JavaType createJavaLangObjectType() { return JavaTypeImpl.create(PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject()))); } + + @NotNull + @Override + public JavaWildcardType createUpperBoundWildcard(@NotNull JavaType bound) { + return new JavaWildcardTypeImpl(PsiWildcardType.createExtends(manager, ((JavaTypeImpl) bound).getPsi())); + } + + @NotNull + @Override + public JavaWildcardType createLowerBoundWildcard(@NotNull JavaType bound) { + return new JavaWildcardTypeImpl(PsiWildcardType.createSuper(manager, ((JavaTypeImpl) bound).getPsi())); + } + + @NotNull + @Override + public JavaWildcardType createUnboundedWildcard() { + return new JavaWildcardTypeImpl(PsiWildcardType.createUnbounded(manager)); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeSubstitutorImpl.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeSubstitutorImpl.java index 9983a52bcf3..146d79a5e86 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeSubstitutorImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/impl/JavaTypeSubstitutorImpl.java @@ -16,83 +16,170 @@ package org.jetbrains.jet.lang.resolve.java.structure.impl; -import com.intellij.psi.PsiSubstitutor; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiTypeParameter; -import com.intellij.psi.impl.PsiSubstitutorImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.resolve.java.structure.JavaType; -import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter; -import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeSubstitutor; +import org.jetbrains.jet.lang.resolve.java.structure.*; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; public class JavaTypeSubstitutorImpl implements JavaTypeSubstitutor { - private final PsiSubstitutor psiSubstitutor; - private Map substitutionMap; + private final Map substitutionMap; - public JavaTypeSubstitutorImpl(@NotNull PsiSubstitutor psiSubstitutor) { - this.psiSubstitutor = psiSubstitutor; - } - - public JavaTypeSubstitutorImpl(@NotNull PsiSubstitutor psiSubstitutor, @NotNull Map substitutionMap) { - this(psiSubstitutor); + public JavaTypeSubstitutorImpl(@NotNull Map substitutionMap) { this.substitutionMap = substitutionMap; } @NotNull - public static JavaTypeSubstitutor create(@NotNull Map substitutionMap) { - Map psiMap = new HashMap(); - for (Map.Entry entry : substitutionMap.entrySet()) { - JavaTypeImpl value = ((JavaTypeImpl) entry.getValue()); - psiMap.put(((JavaTypeParameterImpl) entry.getKey()).getPsi(), value == null ? null : value.getPsi()); - } - PsiSubstitutor psiSubstitutor = PsiSubstitutorImpl.createSubstitutor(psiMap); - return new JavaTypeSubstitutorImpl(psiSubstitutor, substitutionMap); + @Override + public JavaType substitute(@NotNull JavaType type) { + JavaType substitutedType = substituteInternal(type); + return substitutedType != null ? substitutedType : correctSubstitutionForRawType(type); } - @Override @NotNull - public JavaType substitute(@NotNull JavaType type) { - return JavaTypeImpl.create(psiSubstitutor.substitute(((JavaTypeImpl) type).getPsi())); + // In case of raw type we get substition map like T -> null, + // in this case we should substitute upper bound of T or, + // if it does not exist, return java.lang.Object + private JavaType correctSubstitutionForRawType(@NotNull JavaType original) { + if (original instanceof JavaClassifierType) { + JavaClassifier classifier = ((JavaClassifierType) original).getClassifier(); + if (classifier instanceof JavaTypeParameter) { + return rawTypeForTypeParameter((JavaTypeParameter) classifier); + } + } + + return original; + } + + @Nullable + private JavaType substituteInternal(@NotNull JavaType type) { + if (type instanceof JavaClassifierType) { + JavaClassifierType classifierType = (JavaClassifierType) type; + JavaClassifier classifier = classifierType.getClassifier(); + + if (classifier instanceof JavaTypeParameter) { + return substitute((JavaTypeParameter) classifier); + } + else if (classifier instanceof JavaClass) { + JavaClass javaClass = (JavaClass) classifier; + Map substMap = new HashMap(); + processClass(javaClass, classifierType.getSubstitutor(), substMap); + + return javaClass.createImmediateType(new JavaTypeSubstitutorImpl(substMap)); + } + + return type; + } + else if (type instanceof JavaPrimitiveType) { + return type; + } + else if (type instanceof JavaArrayType) { + JavaType componentType = ((JavaArrayType) type).getComponentType(); + JavaType substitutedComponentType = substitute(componentType); + if (substitutedComponentType == componentType) return type; + + return substitutedComponentType.createArrayType(); + } + else if (type instanceof JavaWildcardType) { + return substituteWildcardType((JavaWildcardType) type); + } + + return type; + } + + private void processClass(@NotNull JavaClass javaClass, @NotNull JavaTypeSubstitutor substitutor, @NotNull Map substMap) { + List typeParameters = javaClass.getTypeParameters(); + for (JavaTypeParameter typeParameter : typeParameters) { + JavaType substitutedParam = substitutor.substitute(typeParameter); + if (substitutedParam == null) { + substMap.put(typeParameter, null); + } + else { + substMap.put(typeParameter, substituteInternal(substitutedParam)); + } + } + + if (javaClass.isStatic()) { + return; + } + + JavaClass outerClass = javaClass.getOuterClass(); + if (outerClass != null) { + processClass(outerClass, substitutor, substMap); + } + } + + @Nullable + private JavaType substituteWildcardType(@NotNull JavaWildcardType wildcardType) { + JavaType bound = wildcardType.getBound(); + if (bound == null) { + return wildcardType; + } + + JavaType newBound = substituteInternal(bound); + if (newBound == null) { + // This can be in case of substitution wildcard to raw type + return null; + } + + return rebound(wildcardType, newBound); + } + + @NotNull + private static JavaWildcardType rebound(@NotNull JavaWildcardType type, @NotNull JavaType newBound) { + if (type.getTypeProvider().createJavaLangObjectType().equals(newBound)) { + return type.getTypeProvider().createUnboundedWildcard(); + } + + if (type.isExtends()) { + return type.getTypeProvider().createUpperBoundWildcard(newBound); + } + else { + return type.getTypeProvider().createLowerBoundWildcard(newBound); + } + } + + @NotNull + private JavaType rawTypeForTypeParameter(@NotNull JavaTypeParameter typeParameter) { + Collection bounds = typeParameter.getUpperBounds(); + if (!bounds.isEmpty()) { + return substitute(bounds.iterator().next()); + } + + return typeParameter.getTypeProvider().createJavaLangObjectType(); } @Override @Nullable public JavaType substitute(@NotNull JavaTypeParameter typeParameter) { - PsiType psiType = psiSubstitutor.substitute(((JavaTypeParameterImpl) typeParameter).getPsi()); - return psiType == null ? null : JavaTypeImpl.create(psiType); + if (substitutionMap.containsKey(typeParameter)) { + return substitutionMap.get(typeParameter); + } + + return typeParameter.getType(); } @Override @NotNull public Map getSubstitutionMap() { - if (substitutionMap == null) { - Map psiMap = psiSubstitutor.getSubstitutionMap(); - substitutionMap = new HashMap(); - for (Map.Entry entry : psiMap.entrySet()) { - PsiType value = entry.getValue(); - substitutionMap.put(new JavaTypeParameterImpl(entry.getKey()), value == null ? null : JavaTypeImpl.create(value)); - } - } - return substitutionMap; } @Override public int hashCode() { - return psiSubstitutor.hashCode(); + return substitutionMap.hashCode(); } @Override public boolean equals(Object obj) { - return obj instanceof JavaTypeSubstitutorImpl && psiSubstitutor.equals(((JavaTypeSubstitutorImpl) obj).psiSubstitutor); + return obj instanceof JavaTypeSubstitutorImpl && substitutionMap.equals(((JavaTypeSubstitutorImpl) obj).substitutionMap); } @Override public String toString() { - return getClass().getSimpleName() + ": " + psiSubstitutor; + return getClass().getSimpleName() + ": " + substitutionMap; } -} +} \ No newline at end of file diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java index 99cb3b5107d..e5f50dd853c 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaClass.java @@ -62,6 +62,9 @@ public interface JavaClass extends JavaClassifier, JavaTypeParameterListOwner, J @NotNull OriginKind getOriginKind(); + @NotNull + JavaType createImmediateType(@NotNull JavaTypeSubstitutor substitutor); + enum OriginKind { COMPILED, SOURCE, diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeProvider.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeProvider.java index e29fbd2ea5e..b1d63f7e68a 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeProvider.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeProvider.java @@ -21,4 +21,13 @@ import org.jetbrains.annotations.NotNull; public interface JavaTypeProvider { @NotNull JavaType createJavaLangObjectType(); + + @NotNull + JavaWildcardType createUpperBoundWildcard(@NotNull JavaType bound); + + @NotNull + JavaWildcardType createLowerBoundWildcard(@NotNull JavaType bound); + + @NotNull + JavaWildcardType createUnboundedWildcard(); } diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt index 20f8e5867ca..835a0d55f15 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt @@ -115,6 +115,7 @@ import org.jetbrains.jet.plugin.structureView.AbstractKotlinFileStructureTest import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest import org.jetbrains.jet.jps.build.AbstractIncrementalJpsTest import org.jetbrains.jet.asJava.AbstractKotlinLightClassTest +import org.jetbrains.jet.lang.resolve.java.AbstractJavaTypeSubstitutorTest fun main(args: Array) { System.setProperty("java.awt.headless", "true") @@ -271,6 +272,11 @@ fun main(args: Array) { } testGroup("idea/tests", "idea/testData") { + + testClass(javaClass()) { + model("typeSubstitution", extension = "java") + } + testClass(javaClass()) { model("resolve/additionalLazyResolve", testMethod = "doTest") } diff --git a/idea/testData/typeSubstitution/arrayType.java b/idea/testData/typeSubstitution/arrayType.java new file mode 100644 index 00000000000..63c786d0e79 --- /dev/null +++ b/idea/testData/typeSubstitution/arrayType.java @@ -0,0 +1,8 @@ +interface arrayType { + interface SuperArray { + T[] typeForSubstitute(); + } + + interface MidArray extends SuperArray { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/classType.java b/idea/testData/typeSubstitution/classType.java new file mode 100644 index 00000000000..57fd4b9587d --- /dev/null +++ b/idea/testData/typeSubstitution/classType.java @@ -0,0 +1,8 @@ +interface classType { + interface SuperClass { + List typeForSubstitute(); + } + + interface MidClass extends SuperClass { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/classWithWildcard.java b/idea/testData/typeSubstitution/classWithWildcard.java new file mode 100644 index 00000000000..68e6a144c43 --- /dev/null +++ b/idea/testData/typeSubstitution/classWithWildcard.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface classWithWildcard { + interface SuperList { + List typeForSubstitute(); + } + + interface MidList extends SuperList> { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/genericArray.java b/idea/testData/typeSubstitution/genericArray.java new file mode 100644 index 00000000000..6840d9b0f05 --- /dev/null +++ b/idea/testData/typeSubstitution/genericArray.java @@ -0,0 +1,8 @@ +interface genericArray { + interface SuperGenericArray { + T typeForSubstitute(); + } + + interface MidGenericArray extends SuperGenericArray { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/innerParameter.java b/idea/testData/typeSubstitution/innerParameter.java new file mode 100644 index 00000000000..bd9050093ed --- /dev/null +++ b/idea/testData/typeSubstitution/innerParameter.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface innerParameter { + interface SuperInnerParam { + T typeForSubstitute(); + } + + interface MidInnerParam extends SuperInnerParam { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/intersectionType.java b/idea/testData/typeSubstitution/intersectionType.java new file mode 100644 index 00000000000..4aeaa7c401c --- /dev/null +++ b/idea/testData/typeSubstitution/intersectionType.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface intersectionType { + interface SuperIntersection { + & List> R typeForSubstitute(); + } + + interface MidIntersection extends SuperIntersection { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/intersectionTypeAsTypeParameter.java b/idea/testData/typeSubstitution/intersectionTypeAsTypeParameter.java new file mode 100644 index 00000000000..0a6e5912019 --- /dev/null +++ b/idea/testData/typeSubstitution/intersectionTypeAsTypeParameter.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface intersectionTypeAsTypeParameter { + interface Super { + & List> Map typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/intersectionTypeInEnum.java b/idea/testData/typeSubstitution/intersectionTypeInEnum.java new file mode 100644 index 00000000000..c4f005ce501 --- /dev/null +++ b/idea/testData/typeSubstitution/intersectionTypeInEnum.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface intersectionTypeInEnum { + interface Super { + & List> Enum typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/intersectionTypeInInterfaceDeclaration.java b/idea/testData/typeSubstitution/intersectionTypeInInterfaceDeclaration.java new file mode 100644 index 00000000000..d3984b60dd1 --- /dev/null +++ b/idea/testData/typeSubstitution/intersectionTypeInInterfaceDeclaration.java @@ -0,0 +1,8 @@ +interface intersectionTypeInInterfaceDeclaration { + interface SuperIntersection { + T typeForSubstitute(); + } + + interface MidIntersection extends SuperIntersection { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/intersectionTypeInTypeVariableClass.java b/idea/testData/typeSubstitution/intersectionTypeInTypeVariableClass.java new file mode 100644 index 00000000000..eb6bffbb236 --- /dev/null +++ b/idea/testData/typeSubstitution/intersectionTypeInTypeVariableClass.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface intersectionTypeInTypeVariableClass { + interface Super { + & List> TypeVariable typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/mapEntry.java b/idea/testData/typeSubstitution/mapEntry.java new file mode 100644 index 00000000000..ee711c4596e --- /dev/null +++ b/idea/testData/typeSubstitution/mapEntry.java @@ -0,0 +1,10 @@ +import java.util.Map; + +interface mapEntry { + interface Super { + Map.Entry typeForSubstitute(); + } + + interface Mid extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/primitiveType.java b/idea/testData/typeSubstitution/primitiveType.java new file mode 100644 index 00000000000..e28c8a1808f --- /dev/null +++ b/idea/testData/typeSubstitution/primitiveType.java @@ -0,0 +1,8 @@ +interface primitiveType { + interface SuperPrimitive { + int typeForSubstitute(); + } + + interface MidPrimitive extends SuperPrimitive { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawArrayType.java b/idea/testData/typeSubstitution/rawArrayType.java new file mode 100644 index 00000000000..18bc5e67a5c --- /dev/null +++ b/idea/testData/typeSubstitution/rawArrayType.java @@ -0,0 +1,8 @@ +interface rawArrayType { + interface SuperArray { + T[] typeForSubstitute(); + } + + interface MidArray extends SuperArray { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawArrayTypeParameterWithBound.java b/idea/testData/typeSubstitution/rawArrayTypeParameterWithBound.java new file mode 100644 index 00000000000..3c97bffd13c --- /dev/null +++ b/idea/testData/typeSubstitution/rawArrayTypeParameterWithBound.java @@ -0,0 +1,8 @@ +interface rawArrayTypeParameterWithBound { + interface Super { + T[] typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawEnum.java b/idea/testData/typeSubstitution/rawEnum.java new file mode 100644 index 00000000000..2320cbd9070 --- /dev/null +++ b/idea/testData/typeSubstitution/rawEnum.java @@ -0,0 +1,8 @@ +interface rawEnum { + interface Super> { + Enum typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawExtendsWildcard.java b/idea/testData/typeSubstitution/rawExtendsWildcard.java new file mode 100644 index 00000000000..026c9229551 --- /dev/null +++ b/idea/testData/typeSubstitution/rawExtendsWildcard.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface rawExtendsWildcard { + interface SuperRawWild { + List typeForSubstitute(); + } + + interface MidRawWildcard extends SuperRawWild { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawIntersectionType.java b/idea/testData/typeSubstitution/rawIntersectionType.java new file mode 100644 index 00000000000..3a568159dcb --- /dev/null +++ b/idea/testData/typeSubstitution/rawIntersectionType.java @@ -0,0 +1,8 @@ +interface rawIntersectionType { + interface Super { + T typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawSuperWildcard.java b/idea/testData/typeSubstitution/rawSuperWildcard.java new file mode 100644 index 00000000000..85fb61c8943 --- /dev/null +++ b/idea/testData/typeSubstitution/rawSuperWildcard.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface rawSuperWildcard { + interface SuperRawWild { + List typeForSubstitute(); + } + + interface MidRawWildcard extends SuperRawWild { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawType.java b/idea/testData/typeSubstitution/rawType.java new file mode 100644 index 00000000000..f928f813758 --- /dev/null +++ b/idea/testData/typeSubstitution/rawType.java @@ -0,0 +1,8 @@ +interface rawType { + interface Super { + T typeForSubstitute(); + } + + interface MidRaw extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawTypeInDeclaration.java b/idea/testData/typeSubstitution/rawTypeInDeclaration.java new file mode 100644 index 00000000000..e912477d946 --- /dev/null +++ b/idea/testData/typeSubstitution/rawTypeInDeclaration.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface rawTypeInDeclaration { + interface Super { + List typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawTypeWithBound.java b/idea/testData/typeSubstitution/rawTypeWithBound.java new file mode 100644 index 00000000000..e96a9e36bf4 --- /dev/null +++ b/idea/testData/typeSubstitution/rawTypeWithBound.java @@ -0,0 +1,8 @@ +interface rawTypeWithBound { + interface Super { + T typeForSubstitute(); + } + + interface MidRaw extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawTypeWithSelfReferenceBound.java b/idea/testData/typeSubstitution/rawTypeWithSelfReferenceBound.java new file mode 100644 index 00000000000..e8375c373e8 --- /dev/null +++ b/idea/testData/typeSubstitution/rawTypeWithSelfReferenceBound.java @@ -0,0 +1,8 @@ +interface rawTypeWithSelfReferenceBound { + interface Super> { + T typeForSubstitute(); + } + + interface MidRaw extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawWildcardInTypeVariableClass.java b/idea/testData/typeSubstitution/rawWildcardInTypeVariableClass.java new file mode 100644 index 00000000000..6d4c7a75042 --- /dev/null +++ b/idea/testData/typeSubstitution/rawWildcardInTypeVariableClass.java @@ -0,0 +1,10 @@ +import java.lang.reflect.TypeVariable; + +interface rawWildcardInTypeVariableClass { + interface Super { + TypeVariable typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/rawWildcardWithBound.java b/idea/testData/typeSubstitution/rawWildcardWithBound.java new file mode 100644 index 00000000000..fba6ef0157a --- /dev/null +++ b/idea/testData/typeSubstitution/rawWildcardWithBound.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface rawWildcardWithBound { + interface Super { + List typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/selfReference.java b/idea/testData/typeSubstitution/selfReference.java new file mode 100644 index 00000000000..c6958f1e916 --- /dev/null +++ b/idea/testData/typeSubstitution/selfReference.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface selfReference { + interface SuperSelfRef> { + public List typeForSubstitute(); + } + + interface MidSelfRef extends SuperSelfRef { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/twoParameters.java b/idea/testData/typeSubstitution/twoParameters.java new file mode 100644 index 00000000000..d4508cd37d5 --- /dev/null +++ b/idea/testData/typeSubstitution/twoParameters.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface twoParameters { + interface SuperTwoParams { + Map> typeForSubstitute(); + } + + interface MidTwoParams extends SuperTwoParams { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/twoParametersInSubClass.java b/idea/testData/typeSubstitution/twoParametersInSubClass.java new file mode 100644 index 00000000000..579cbfc3b8a --- /dev/null +++ b/idea/testData/typeSubstitution/twoParametersInSubClass.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface twoParametersInSubClass { + interface SuperTwoParams { + List typeForSubstitute(); + } + + interface MidTwoParams extends SuperTwoParams { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/typeVariableClass.java b/idea/testData/typeSubstitution/typeVariableClass.java new file mode 100644 index 00000000000..b738ab5e1b3 --- /dev/null +++ b/idea/testData/typeSubstitution/typeVariableClass.java @@ -0,0 +1,10 @@ +import java.lang.reflect.TypeVariable; + +interface typeVariableClass { + interface Super { + TypeVariable typeForSubstitute(); + } + + interface Mid extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/typeVariableRaw.java b/idea/testData/typeSubstitution/typeVariableRaw.java new file mode 100644 index 00000000000..37464247d2c --- /dev/null +++ b/idea/testData/typeSubstitution/typeVariableRaw.java @@ -0,0 +1,10 @@ +import java.lang.reflect.TypeVariable; + +interface typeVariableRaw { + interface Super { + TypeVariable typeForSubstitute(); + } + + interface Mid extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/unboundedWildcard.java b/idea/testData/typeSubstitution/unboundedWildcard.java new file mode 100644 index 00000000000..232230bf9d4 --- /dev/null +++ b/idea/testData/typeSubstitution/unboundedWildcard.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface unboundedWildcard { + interface Super { + List typeForSubstitute(); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/unboundedWildcardToTypeParameter.java b/idea/testData/typeSubstitution/unboundedWildcardToTypeParameter.java new file mode 100644 index 00000000000..981d5adf796 --- /dev/null +++ b/idea/testData/typeSubstitution/unboundedWildcardToTypeParameter.java @@ -0,0 +1,8 @@ +import java.util.*; + +interface unboundedWildcardToTypeParameter { + interface SupList extends List { + @Override + boolean retainAll(Collection c); // error, check that we do not fall + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargArray.java b/idea/testData/typeSubstitution/varargArray.java new file mode 100644 index 00000000000..853db136a2c --- /dev/null +++ b/idea/testData/typeSubstitution/varargArray.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargArray { + interface Super { + void typeForSubstitute(T... a); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargArrayTypeParameter.java b/idea/testData/typeSubstitution/varargArrayTypeParameter.java new file mode 100644 index 00000000000..0343a15100c --- /dev/null +++ b/idea/testData/typeSubstitution/varargArrayTypeParameter.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargArrayTypeParameter { + interface Super { + void typeForSubstitute(T... a); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargClass.java b/idea/testData/typeSubstitution/varargClass.java new file mode 100644 index 00000000000..371b6d1226e --- /dev/null +++ b/idea/testData/typeSubstitution/varargClass.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargClass { + interface Super { + void typeForSubstitute(List... a); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargClassWithWildcard.java b/idea/testData/typeSubstitution/varargClassWithWildcard.java new file mode 100644 index 00000000000..3aa87dfda7d --- /dev/null +++ b/idea/testData/typeSubstitution/varargClassWithWildcard.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargClassWithWildcard { + interface Super { + void typeForSubstitute(List... a); + } + + interface Sub extends Super> { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargRawType.java b/idea/testData/typeSubstitution/varargRawType.java new file mode 100644 index 00000000000..78a6b2515b2 --- /dev/null +++ b/idea/testData/typeSubstitution/varargRawType.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargRawType { + interface Super { + void typeForSubstitute(T... a); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargRawTypeWithBound.java b/idea/testData/typeSubstitution/varargRawTypeWithBound.java new file mode 100644 index 00000000000..cc7f8e8fb8b --- /dev/null +++ b/idea/testData/typeSubstitution/varargRawTypeWithBound.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargRawTypeWithBound { + interface Super { + void typeForSubstitute(T... a); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargToClass.java b/idea/testData/typeSubstitution/varargToClass.java new file mode 100644 index 00000000000..7132de49e80 --- /dev/null +++ b/idea/testData/typeSubstitution/varargToClass.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargToClass { + interface Super { + void typeForSubstitute(T... a); + } + + interface Sub extends Super { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/varargToClassWithWildcard.java b/idea/testData/typeSubstitution/varargToClassWithWildcard.java new file mode 100644 index 00000000000..93dc3b520af --- /dev/null +++ b/idea/testData/typeSubstitution/varargToClassWithWildcard.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface varargToClassWithWildcard { + interface Super { + void typeForSubstitute(T... a); + } + + interface Sub extends Super> { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/wildcardExtends.java b/idea/testData/typeSubstitution/wildcardExtends.java new file mode 100644 index 00000000000..721942f6376 --- /dev/null +++ b/idea/testData/typeSubstitution/wildcardExtends.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface wildcardExtends { + interface SuperWildcardExtends { + List typeForSubstitute(); + } + + interface MidWildcardExtends extends SuperWildcardExtends { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/wildcardExtendsObject.java b/idea/testData/typeSubstitution/wildcardExtendsObject.java new file mode 100644 index 00000000000..40e18ca5a83 --- /dev/null +++ b/idea/testData/typeSubstitution/wildcardExtendsObject.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface wildcardExtendsObject { + interface SuperWildcardExtendsObject { + List typeForSubstitute(); + } + + interface MidWildcardExtendsObject extends SuperWildcardExtendsObject { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/wildcardExtendsTypeParameter.java b/idea/testData/typeSubstitution/wildcardExtendsTypeParameter.java new file mode 100644 index 00000000000..d62939b11f3 --- /dev/null +++ b/idea/testData/typeSubstitution/wildcardExtendsTypeParameter.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface wildcardExtendsTypeParameter { + interface SuperWildcard { + Map typeForSubstitute(); + } + + interface MidWildcard extends SuperWildcard { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/wildcardSuper.java b/idea/testData/typeSubstitution/wildcardSuper.java new file mode 100644 index 00000000000..b1342fb7f1f --- /dev/null +++ b/idea/testData/typeSubstitution/wildcardSuper.java @@ -0,0 +1,10 @@ +import java.util.*; + +interface wildcardSuper { + interface SuperWildcardSuper { + List typeForSubstitute(); + } + + interface MidWildcardSuper extends SuperWildcardSuper { + } +} \ No newline at end of file diff --git a/idea/testData/typeSubstitution/wildcardToWildcard.java b/idea/testData/typeSubstitution/wildcardToWildcard.java new file mode 100644 index 00000000000..d52b18dd53c --- /dev/null +++ b/idea/testData/typeSubstitution/wildcardToWildcard.java @@ -0,0 +1,8 @@ +import java.util.*; + +interface wildcardToWildcard { + interface SupList extends List { + @Override + boolean addAll(Collection c); + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/lang/resolve/java/AbstractJavaTypeSubstitutorTest.java b/idea/tests/org/jetbrains/jet/lang/resolve/java/AbstractJavaTypeSubstitutorTest.java new file mode 100644 index 00000000000..fb0dffc21ef --- /dev/null +++ b/idea/tests/org/jetbrains/jet/lang/resolve/java/AbstractJavaTypeSubstitutorTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2010-2014 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 com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.testFramework.LightProjectDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.java.structure.JavaClassifierType; +import org.jetbrains.jet.lang.resolve.java.structure.JavaType; +import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter; +import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaTypeImpl; +import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaTypeParameterImpl; +import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase; +import org.jetbrains.jet.plugin.JetLightProjectDescriptor; + +public abstract class AbstractJavaTypeSubstitutorTest extends JetLightCodeInsightFixtureTestCase { + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JetLightProjectDescriptor.INSTANCE; + } + + public void doTest(@NotNull String testFile) { + PsiFile psiFile = myFixture.configureByFile(testFile); + + Project project = myFixture.getProject(); + String javaClassName = psiFile.getName().substring(0, psiFile.getName().length() - ".java".length()); + PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(javaClassName, GlobalSearchScope.allScope(project)); + assert psiClass != null : "Wrong path to test file: " + testFile; + + assert psiClass.getInnerClasses().length > 0; + + for (PsiClass innerInterface : psiClass.getInnerClasses()) { + PsiMethod method = getMethodWithTestData(innerInterface); + + PsiClassType[] superTypes = innerInterface.getSuperTypes(); + for (PsiClassType superType : superTypes) { + if (method.getReturnType() != null) { + doTest(superType, method.getReturnType()); + } + if (method.getTypeParameters().length > 0) { + doTest(superType, method.getTypeParameters()[0]); + } + PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length > 0) { + doTest(superType, parameters[0].getType()); + } + } + } + } + + private static void doTest(@NotNull PsiClassType type, @NotNull PsiTypeParameter typeParameter) { + PsiType expectedType = type.resolveGenerics().getSubstitutor().substitute(typeParameter); + + JavaClassifierType javaClassifierType = (JavaClassifierType) JavaTypeImpl.create(type); + JavaTypeParameter javaTypeToSubstitute = new JavaTypeParameterImpl(typeParameter); + JavaType actualType = javaClassifierType.getSubstitutor().substitute(javaTypeToSubstitute); + + if (actualType == null) { + assertEquals(expectedType, null); + } + else { + assertEquals(expectedType, ((JavaTypeImpl) actualType).getPsi()); + } + } + + private static void doTest(@NotNull PsiClassType type, @NotNull PsiType psiTypeToSubstitute) { + PsiType expectedType = type.resolveGenerics().getSubstitutor().substitute(psiTypeToSubstitute); + + JavaClassifierType javaClassifierType = (JavaClassifierType) JavaTypeImpl.create(type); + JavaType javaTypeToSubstitute = JavaTypeImpl.create(psiTypeToSubstitute); + JavaType actualType = javaClassifierType.getSubstitutor().substitute(javaTypeToSubstitute); + + if (expectedType instanceof PsiEllipsisType) { + PsiEllipsisType ellipsisType = (PsiEllipsisType) expectedType; + assertEquals(ellipsisType.toArrayType(), ((JavaTypeImpl) actualType).getPsi()); + } + else { + assertEquals(expectedType, ((JavaTypeImpl) actualType).getPsi()); + } + } + + @NotNull + private static PsiMethod getMethodWithTestData(@NotNull PsiClass psiClass) { + String substituteParameterName = "typeForSubstitute"; + PsiMethod[] methods = psiClass.findMethodsByName(substituteParameterName, false); + if (methods.length == 0) { + methods = psiClass.findMethodsByName(substituteParameterName, true); + } + + if (methods.length == 0) { + methods = psiClass.getMethods(); + } + + assert methods.length > 0 : "Wrong parameters for test: method typeForSubstitute not found"; + + return methods[0]; + } +} diff --git a/idea/tests/org/jetbrains/jet/lang/resolve/java/JavaTypeSubstitutorTestGenerated.java b/idea/tests/org/jetbrains/jet/lang/resolve/java/JavaTypeSubstitutorTestGenerated.java new file mode 100644 index 00000000000..0e101962a12 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/lang/resolve/java/JavaTypeSubstitutorTestGenerated.java @@ -0,0 +1,259 @@ +/* + * Copyright 2010-2014 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 junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.io.File; +import java.util.regex.Pattern; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.test.InnerTestClasses; +import org.jetbrains.jet.test.TestMetadata; + +import org.jetbrains.jet.lang.resolve.java.AbstractJavaTypeSubstitutorTest; + +/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/typeSubstitution") +public class JavaTypeSubstitutorTestGenerated extends AbstractJavaTypeSubstitutorTest { + public void testAllFilesPresentInTypeSubstitution() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/typeSubstitution"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("arrayType.java") + public void testArrayType() throws Exception { + doTest("idea/testData/typeSubstitution/arrayType.java"); + } + + @TestMetadata("classType.java") + public void testClassType() throws Exception { + doTest("idea/testData/typeSubstitution/classType.java"); + } + + @TestMetadata("classWithWildcard.java") + public void testClassWithWildcard() throws Exception { + doTest("idea/testData/typeSubstitution/classWithWildcard.java"); + } + + @TestMetadata("genericArray.java") + public void testGenericArray() throws Exception { + doTest("idea/testData/typeSubstitution/genericArray.java"); + } + + @TestMetadata("innerParameter.java") + public void testInnerParameter() throws Exception { + doTest("idea/testData/typeSubstitution/innerParameter.java"); + } + + @TestMetadata("intersectionType.java") + public void testIntersectionType() throws Exception { + doTest("idea/testData/typeSubstitution/intersectionType.java"); + } + + @TestMetadata("intersectionTypeAsTypeParameter.java") + public void testIntersectionTypeAsTypeParameter() throws Exception { + doTest("idea/testData/typeSubstitution/intersectionTypeAsTypeParameter.java"); + } + + @TestMetadata("intersectionTypeInEnum.java") + public void testIntersectionTypeInEnum() throws Exception { + doTest("idea/testData/typeSubstitution/intersectionTypeInEnum.java"); + } + + @TestMetadata("intersectionTypeInInterfaceDeclaration.java") + public void testIntersectionTypeInInterfaceDeclaration() throws Exception { + doTest("idea/testData/typeSubstitution/intersectionTypeInInterfaceDeclaration.java"); + } + + @TestMetadata("intersectionTypeInTypeVariableClass.java") + public void testIntersectionTypeInTypeVariableClass() throws Exception { + doTest("idea/testData/typeSubstitution/intersectionTypeInTypeVariableClass.java"); + } + + @TestMetadata("mapEntry.java") + public void testMapEntry() throws Exception { + doTest("idea/testData/typeSubstitution/mapEntry.java"); + } + + @TestMetadata("primitiveType.java") + public void testPrimitiveType() throws Exception { + doTest("idea/testData/typeSubstitution/primitiveType.java"); + } + + @TestMetadata("rawArrayType.java") + public void testRawArrayType() throws Exception { + doTest("idea/testData/typeSubstitution/rawArrayType.java"); + } + + @TestMetadata("rawArrayTypeParameterWithBound.java") + public void testRawArrayTypeParameterWithBound() throws Exception { + doTest("idea/testData/typeSubstitution/rawArrayTypeParameterWithBound.java"); + } + + @TestMetadata("rawEnum.java") + public void testRawEnum() throws Exception { + doTest("idea/testData/typeSubstitution/rawEnum.java"); + } + + @TestMetadata("rawExtendsWildcard.java") + public void testRawExtendsWildcard() throws Exception { + doTest("idea/testData/typeSubstitution/rawExtendsWildcard.java"); + } + + @TestMetadata("rawIntersectionType.java") + public void testRawIntersectionType() throws Exception { + doTest("idea/testData/typeSubstitution/rawIntersectionType.java"); + } + + @TestMetadata("rawSuperWildcard.java") + public void testRawSuperWildcard() throws Exception { + doTest("idea/testData/typeSubstitution/rawSuperWildcard.java"); + } + + @TestMetadata("rawType.java") + public void testRawType() throws Exception { + doTest("idea/testData/typeSubstitution/rawType.java"); + } + + @TestMetadata("rawTypeInDeclaration.java") + public void testRawTypeInDeclaration() throws Exception { + doTest("idea/testData/typeSubstitution/rawTypeInDeclaration.java"); + } + + @TestMetadata("rawTypeWithBound.java") + public void testRawTypeWithBound() throws Exception { + doTest("idea/testData/typeSubstitution/rawTypeWithBound.java"); + } + + @TestMetadata("rawTypeWithSelfReferenceBound.java") + public void testRawTypeWithSelfReferenceBound() throws Exception { + doTest("idea/testData/typeSubstitution/rawTypeWithSelfReferenceBound.java"); + } + + @TestMetadata("rawWildcardInTypeVariableClass.java") + public void testRawWildcardInTypeVariableClass() throws Exception { + doTest("idea/testData/typeSubstitution/rawWildcardInTypeVariableClass.java"); + } + + @TestMetadata("rawWildcardWithBound.java") + public void testRawWildcardWithBound() throws Exception { + doTest("idea/testData/typeSubstitution/rawWildcardWithBound.java"); + } + + @TestMetadata("selfReference.java") + public void testSelfReference() throws Exception { + doTest("idea/testData/typeSubstitution/selfReference.java"); + } + + @TestMetadata("twoParameters.java") + public void testTwoParameters() throws Exception { + doTest("idea/testData/typeSubstitution/twoParameters.java"); + } + + @TestMetadata("twoParametersInSubClass.java") + public void testTwoParametersInSubClass() throws Exception { + doTest("idea/testData/typeSubstitution/twoParametersInSubClass.java"); + } + + @TestMetadata("typeVariableClass.java") + public void testTypeVariableClass() throws Exception { + doTest("idea/testData/typeSubstitution/typeVariableClass.java"); + } + + @TestMetadata("typeVariableRaw.java") + public void testTypeVariableRaw() throws Exception { + doTest("idea/testData/typeSubstitution/typeVariableRaw.java"); + } + + @TestMetadata("unboundedWildcard.java") + public void testUnboundedWildcard() throws Exception { + doTest("idea/testData/typeSubstitution/unboundedWildcard.java"); + } + + @TestMetadata("unboundedWildcardToTypeParameter.java") + public void testUnboundedWildcardToTypeParameter() throws Exception { + doTest("idea/testData/typeSubstitution/unboundedWildcardToTypeParameter.java"); + } + + @TestMetadata("varargArray.java") + public void testVarargArray() throws Exception { + doTest("idea/testData/typeSubstitution/varargArray.java"); + } + + @TestMetadata("varargArrayTypeParameter.java") + public void testVarargArrayTypeParameter() throws Exception { + doTest("idea/testData/typeSubstitution/varargArrayTypeParameter.java"); + } + + @TestMetadata("varargClass.java") + public void testVarargClass() throws Exception { + doTest("idea/testData/typeSubstitution/varargClass.java"); + } + + @TestMetadata("varargClassWithWildcard.java") + public void testVarargClassWithWildcard() throws Exception { + doTest("idea/testData/typeSubstitution/varargClassWithWildcard.java"); + } + + @TestMetadata("varargRawType.java") + public void testVarargRawType() throws Exception { + doTest("idea/testData/typeSubstitution/varargRawType.java"); + } + + @TestMetadata("varargRawTypeWithBound.java") + public void testVarargRawTypeWithBound() throws Exception { + doTest("idea/testData/typeSubstitution/varargRawTypeWithBound.java"); + } + + @TestMetadata("varargToClass.java") + public void testVarargToClass() throws Exception { + doTest("idea/testData/typeSubstitution/varargToClass.java"); + } + + @TestMetadata("varargToClassWithWildcard.java") + public void testVarargToClassWithWildcard() throws Exception { + doTest("idea/testData/typeSubstitution/varargToClassWithWildcard.java"); + } + + @TestMetadata("wildcardExtends.java") + public void testWildcardExtends() throws Exception { + doTest("idea/testData/typeSubstitution/wildcardExtends.java"); + } + + @TestMetadata("wildcardExtendsObject.java") + public void testWildcardExtendsObject() throws Exception { + doTest("idea/testData/typeSubstitution/wildcardExtendsObject.java"); + } + + @TestMetadata("wildcardExtendsTypeParameter.java") + public void testWildcardExtendsTypeParameter() throws Exception { + doTest("idea/testData/typeSubstitution/wildcardExtendsTypeParameter.java"); + } + + @TestMetadata("wildcardSuper.java") + public void testWildcardSuper() throws Exception { + doTest("idea/testData/typeSubstitution/wildcardSuper.java"); + } + + @TestMetadata("wildcardToWildcard.java") + public void testWildcardToWildcard() throws Exception { + doTest("idea/testData/typeSubstitution/wildcardToWildcard.java"); + } + +} From 7742755de44f1c3c969588f90db29d7fd99cee45 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 14:30:46 +0400 Subject: [PATCH 109/143] Minor. Correct map with expected size creation. --- .../org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt index e06193a161d..fb71bfd94b5 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt @@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName import java.util.HashSet import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalCache import java.util.HashMap +import com.google.common.collect.Maps public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { class object { @@ -203,7 +204,7 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { override fun read(`in`: DataInput): Map? { val size = `in`.readInt() - val map = HashMap(size) + val map = Maps.newHashMapWithExpectedSize(size)!! for (i in size.indices) { val name = IOUtil.readString(`in`)!! From 111feb257451c204e52065788d5e7dd68ad47872 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 14:33:47 +0400 Subject: [PATCH 110/143] Added tests with removing files and changing packages. --- .../build/IncrementalJpsTestGenerated.java | 20 +++++++++++++++++++ .../incremental/filesExchangePackages/a.kt | 3 +++ .../incremental/filesExchangePackages/b.kt | 3 +++ .../filesExchangePackages/b.kt.new | 3 +++ .../filesExchangePackages/build.log | 17 ++++++++++++++++ .../incremental/filesExchangePackages/c.kt | 3 +++ .../filesExchangePackages/c.kt.new | 3 +++ .../multiplePackagesModified/a1.kt | 3 +++ .../multiplePackagesModified/a2.kt.new | 3 +++ .../multiplePackagesModified/b1.kt | 3 +++ .../multiplePackagesModified/b2.kt | 3 +++ .../multiplePackagesModified/b2.kt.delete | 0 .../multiplePackagesModified/build.log | 17 ++++++++++++++++ .../testData/incremental/packageRemoved/a.kt | 3 +++ .../incremental/packageRemoved/a.kt.delete | 0 .../testData/incremental/packageRemoved/b.kt | 3 +++ .../incremental/packageRemoved/b.kt.delete | 0 .../incremental/packageRemoved/build.log | 9 +++++++++ .../incremental/soleFileChangesPackage/a.kt | 3 +++ .../soleFileChangesPackage/a.kt.new | 4 ++++ .../soleFileChangesPackage/build.log | 7 +++++++ 21 files changed, 110 insertions(+) create mode 100644 jps-plugin/testData/incremental/filesExchangePackages/a.kt create mode 100644 jps-plugin/testData/incremental/filesExchangePackages/b.kt create mode 100644 jps-plugin/testData/incremental/filesExchangePackages/b.kt.new create mode 100644 jps-plugin/testData/incremental/filesExchangePackages/build.log create mode 100644 jps-plugin/testData/incremental/filesExchangePackages/c.kt create mode 100644 jps-plugin/testData/incremental/filesExchangePackages/c.kt.new create mode 100644 jps-plugin/testData/incremental/multiplePackagesModified/a1.kt create mode 100644 jps-plugin/testData/incremental/multiplePackagesModified/a2.kt.new create mode 100644 jps-plugin/testData/incremental/multiplePackagesModified/b1.kt create mode 100644 jps-plugin/testData/incremental/multiplePackagesModified/b2.kt create mode 100644 jps-plugin/testData/incremental/multiplePackagesModified/b2.kt.delete create mode 100644 jps-plugin/testData/incremental/multiplePackagesModified/build.log create mode 100644 jps-plugin/testData/incremental/packageRemoved/a.kt create mode 100644 jps-plugin/testData/incremental/packageRemoved/a.kt.delete create mode 100644 jps-plugin/testData/incremental/packageRemoved/b.kt create mode 100644 jps-plugin/testData/incremental/packageRemoved/b.kt.delete create mode 100644 jps-plugin/testData/incremental/packageRemoved/build.log create mode 100644 jps-plugin/testData/incremental/soleFileChangesPackage/a.kt create mode 100644 jps-plugin/testData/incremental/soleFileChangesPackage/a.kt.new create mode 100644 jps-plugin/testData/incremental/soleFileChangesPackage/build.log diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java index c8359bf9773..8ac2e37fa69 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java @@ -56,11 +56,21 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest("jps-plugin/testData/incremental/constantValue/"); } + @TestMetadata("filesExchangePackages") + public void testFilesExchangePackages() throws Exception { + doTest("jps-plugin/testData/incremental/filesExchangePackages/"); + } + @TestMetadata("independentClasses") public void testIndependentClasses() throws Exception { doTest("jps-plugin/testData/incremental/independentClasses/"); } + @TestMetadata("multiplePackagesModified") + public void testMultiplePackagesModified() throws Exception { + doTest("jps-plugin/testData/incremental/multiplePackagesModified/"); + } + @TestMetadata("packageFileAdded") public void testPackageFileAdded() throws Exception { doTest("jps-plugin/testData/incremental/packageFileAdded/"); @@ -86,6 +96,11 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest("jps-plugin/testData/incremental/packageFilesChangedInTurn/"); } + @TestMetadata("packageRemoved") + public void testPackageRemoved() throws Exception { + doTest("jps-plugin/testData/incremental/packageRemoved/"); + } + @TestMetadata("returnTypeChanged") public void testReturnTypeChanged() throws Exception { doTest("jps-plugin/testData/incremental/returnTypeChanged/"); @@ -96,6 +111,11 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest("jps-plugin/testData/incremental/simpleClassDependency/"); } + @TestMetadata("soleFileChangesPackage") + public void testSoleFileChangesPackage() throws Exception { + doTest("jps-plugin/testData/incremental/soleFileChangesPackage/"); + } + @TestMetadata("topLevelFunctionSameSignature") public void testTopLevelFunctionSameSignature() throws Exception { doTest("jps-plugin/testData/incremental/topLevelFunctionSameSignature/"); diff --git a/jps-plugin/testData/incremental/filesExchangePackages/a.kt b/jps-plugin/testData/incremental/filesExchangePackages/a.kt new file mode 100644 index 00000000000..058137655b8 --- /dev/null +++ b/jps-plugin/testData/incremental/filesExchangePackages/a.kt @@ -0,0 +1,3 @@ +package foo + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/filesExchangePackages/b.kt b/jps-plugin/testData/incremental/filesExchangePackages/b.kt new file mode 100644 index 00000000000..d838bdff1a4 --- /dev/null +++ b/jps-plugin/testData/incremental/filesExchangePackages/b.kt @@ -0,0 +1,3 @@ +package foo + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/filesExchangePackages/b.kt.new b/jps-plugin/testData/incremental/filesExchangePackages/b.kt.new new file mode 100644 index 00000000000..75675fcebb4 --- /dev/null +++ b/jps-plugin/testData/incremental/filesExchangePackages/b.kt.new @@ -0,0 +1,3 @@ +package bar + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/filesExchangePackages/build.log b/jps-plugin/testData/incremental/filesExchangePackages/build.log new file mode 100644 index 00000000000..492218cc4a6 --- /dev/null +++ b/jps-plugin/testData/incremental/filesExchangePackages/build.log @@ -0,0 +1,17 @@ +Cleaning output files: +out/production/module/bar/BarPackage-c-*.class +out/production/module/bar/BarPackage.class +out/production/module/foo/FooPackage-b-*.class +out/production/module/foo/FooPackage.class +End of files +Compiling files: +src/b.kt +src/c.kt +End of files +Cleaning output files: +out/production/module/foo/FooPackage-a-*.class +out/production/module/foo/FooPackage.class +End of files +Compiling files: +src/a.kt +End of files diff --git a/jps-plugin/testData/incremental/filesExchangePackages/c.kt b/jps-plugin/testData/incremental/filesExchangePackages/c.kt new file mode 100644 index 00000000000..ba081bb0bbd --- /dev/null +++ b/jps-plugin/testData/incremental/filesExchangePackages/c.kt @@ -0,0 +1,3 @@ +package bar + +fun c() = "c" diff --git a/jps-plugin/testData/incremental/filesExchangePackages/c.kt.new b/jps-plugin/testData/incremental/filesExchangePackages/c.kt.new new file mode 100644 index 00000000000..e51d910bb9d --- /dev/null +++ b/jps-plugin/testData/incremental/filesExchangePackages/c.kt.new @@ -0,0 +1,3 @@ +package foo + +fun c() = "c" diff --git a/jps-plugin/testData/incremental/multiplePackagesModified/a1.kt b/jps-plugin/testData/incremental/multiplePackagesModified/a1.kt new file mode 100644 index 00000000000..2bd705934bc --- /dev/null +++ b/jps-plugin/testData/incremental/multiplePackagesModified/a1.kt @@ -0,0 +1,3 @@ +package a + +fun a1() = ":)" \ No newline at end of file diff --git a/jps-plugin/testData/incremental/multiplePackagesModified/a2.kt.new b/jps-plugin/testData/incremental/multiplePackagesModified/a2.kt.new new file mode 100644 index 00000000000..4e46bd9087f --- /dev/null +++ b/jps-plugin/testData/incremental/multiplePackagesModified/a2.kt.new @@ -0,0 +1,3 @@ +package a + +fun a2() = ":))" \ No newline at end of file diff --git a/jps-plugin/testData/incremental/multiplePackagesModified/b1.kt b/jps-plugin/testData/incremental/multiplePackagesModified/b1.kt new file mode 100644 index 00000000000..21999b4bfe6 --- /dev/null +++ b/jps-plugin/testData/incremental/multiplePackagesModified/b1.kt @@ -0,0 +1,3 @@ +package b + +fun b1() = ":(" \ No newline at end of file diff --git a/jps-plugin/testData/incremental/multiplePackagesModified/b2.kt b/jps-plugin/testData/incremental/multiplePackagesModified/b2.kt new file mode 100644 index 00000000000..d2f49a90033 --- /dev/null +++ b/jps-plugin/testData/incremental/multiplePackagesModified/b2.kt @@ -0,0 +1,3 @@ +package b + +fun b2() = ":((" \ No newline at end of file diff --git a/jps-plugin/testData/incremental/multiplePackagesModified/b2.kt.delete b/jps-plugin/testData/incremental/multiplePackagesModified/b2.kt.delete new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/multiplePackagesModified/build.log b/jps-plugin/testData/incremental/multiplePackagesModified/build.log new file mode 100644 index 00000000000..914a8b69528 --- /dev/null +++ b/jps-plugin/testData/incremental/multiplePackagesModified/build.log @@ -0,0 +1,17 @@ +Cleaning output files: +out/production/module/b/BPackage-b2-*.class +out/production/module/b/BPackage.class +End of files +Compiling files: +src/a2.kt +End of files +Cleaning output files: +out/production/module/a/APackage-a1-*.class +out/production/module/a/APackage.class +out/production/module/b/BPackage-b1-*.class +out/production/module/b/BPackage.class +End of files +Compiling files: +src/a1.kt +src/b1.kt +End of files diff --git a/jps-plugin/testData/incremental/packageRemoved/a.kt b/jps-plugin/testData/incremental/packageRemoved/a.kt new file mode 100644 index 00000000000..30ca24b5576 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRemoved/a.kt @@ -0,0 +1,3 @@ +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/packageRemoved/a.kt.delete b/jps-plugin/testData/incremental/packageRemoved/a.kt.delete new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/packageRemoved/b.kt b/jps-plugin/testData/incremental/packageRemoved/b.kt new file mode 100644 index 00000000000..5c782f47a25 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRemoved/b.kt @@ -0,0 +1,3 @@ +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/packageRemoved/b.kt.delete b/jps-plugin/testData/incremental/packageRemoved/b.kt.delete new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jps-plugin/testData/incremental/packageRemoved/build.log b/jps-plugin/testData/incremental/packageRemoved/build.log new file mode 100644 index 00000000000..c307a197264 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRemoved/build.log @@ -0,0 +1,9 @@ +Cleaning output files: +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Cleaning output files: +out/production/module/test/TestPackage-b-*.class +End of files +Compiling files: +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/soleFileChangesPackage/a.kt b/jps-plugin/testData/incremental/soleFileChangesPackage/a.kt new file mode 100644 index 00000000000..058137655b8 --- /dev/null +++ b/jps-plugin/testData/incremental/soleFileChangesPackage/a.kt @@ -0,0 +1,3 @@ +package foo + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/soleFileChangesPackage/a.kt.new b/jps-plugin/testData/incremental/soleFileChangesPackage/a.kt.new new file mode 100644 index 00000000000..eb3b7b757d2 --- /dev/null +++ b/jps-plugin/testData/incremental/soleFileChangesPackage/a.kt.new @@ -0,0 +1,4 @@ +package bar + +fun a() = "a" +fun aa() = "aa" diff --git a/jps-plugin/testData/incremental/soleFileChangesPackage/build.log b/jps-plugin/testData/incremental/soleFileChangesPackage/build.log new file mode 100644 index 00000000000..3c8fdd9ea17 --- /dev/null +++ b/jps-plugin/testData/incremental/soleFileChangesPackage/build.log @@ -0,0 +1,7 @@ +Cleaning output files: +out/production/module/foo/FooPackage-a-*.class +out/production/module/foo/FooPackage.class +End of files +Compiling files: +src/a.kt +End of files \ No newline at end of file From bf442a970078ff931e87f638189cb49e31d29837 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 17:47:48 +0400 Subject: [PATCH 111/143] Fixed loading integral constants from compiled classes. --- .../InlinedConstants.A.kt | 18 +++++++++++ .../InlinedConstants.B.kt | 12 +++++++ .../loadJava/compiledKotlin/prop/Constants.kt | 17 ++++++++++ .../compiledKotlin/prop/Constants.txt | 28 +++++++++++++++++ ...mpileKotlinAgainstKotlinTestGenerated.java | 5 +++ .../jvm/compiler/LoadJavaTestGenerated.java | 5 +++ ...esolveRecursiveComparingTestGenerated.java | 5 +++ .../DescriptorDeserializersStorage.java | 31 ++++++++++++++++++- .../stubs/LazyResolveByStubTestGenerated.java | 5 +++ 9 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.A.kt create mode 100644 compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.B.kt create mode 100644 compiler/testData/loadJava/compiledKotlin/prop/Constants.kt create mode 100644 compiler/testData/loadJava/compiledKotlin/prop/Constants.txt diff --git a/compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.A.kt b/compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.A.kt new file mode 100644 index 00000000000..6e624ae137e --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.A.kt @@ -0,0 +1,18 @@ +package constants + +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy + +public val b: Byte = 100 +public val s: Short = 20000 +public val i: Int = 2000000 +public val l: Long = 2000000000000L +public val f: Float = 3.14f +public val d: Double = 3.14 +public val bb: Boolean = true +public val c: Char = '\u03c0' // pi symbol + +public val str: String = ":)" + +[Retention(RetentionPolicy.RUNTIME)] +public annotation class AnnotationClass(public val value: String) \ No newline at end of file diff --git a/compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.B.kt b/compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.B.kt new file mode 100644 index 00000000000..4c341b87225 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.B.kt @@ -0,0 +1,12 @@ +import constants.* + +AnnotationClass("$b $s $i $l $f $d $bb $c $str") +class DummyClass() + +fun main(args: Array) { + val klass = javaClass()!! + val annotationClass = javaClass() + val annotation = klass.getAnnotation(annotationClass)!! + val value = annotation.value + require(value == "100 20000 2000000 2000000000000 3.14 3.14 true \u03c0 :)", "Annotation value: $value") +} \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlin/prop/Constants.kt b/compiler/testData/loadJava/compiledKotlin/prop/Constants.kt new file mode 100644 index 00000000000..935c1a68f5b --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/prop/Constants.kt @@ -0,0 +1,17 @@ +//ALLOW_AST_ACCESS +package test + +val b: Byte = 100 +val b1: Byte = 1 +val s: Short = 20000 +val s1: Short = 1 +val i: Int = 2000000 +val i1: Short = 1 +val l: Long = 2000000000000L +val l1: Long = 1 +val f: Float = 3.14f +val d: Double = 3.14 +val bb: Boolean = true +val c: Char = '\u03c0' // pi symbol + +val str: String = ":)" \ No newline at end of file diff --git a/compiler/testData/loadJava/compiledKotlin/prop/Constants.txt b/compiler/testData/loadJava/compiledKotlin/prop/Constants.txt new file mode 100644 index 00000000000..d465db083c5 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/prop/Constants.txt @@ -0,0 +1,28 @@ +package test + +internal val b: kotlin.Byte = 100.toByte() + internal fun (): kotlin.Byte +internal val b1: kotlin.Byte = 1.toByte() + internal fun (): kotlin.Byte +internal val bb: kotlin.Boolean = true + internal fun (): kotlin.Boolean +internal val c: kotlin.Char = #960(π) + internal fun (): kotlin.Char +internal val d: kotlin.Double = 3.14.toDouble() + internal fun (): kotlin.Double +internal val f: kotlin.Float = 3.14.toFloat() + internal fun (): kotlin.Float +internal val i: kotlin.Int = 2000000 + internal fun (): kotlin.Int +internal val i1: kotlin.Short = 1.toShort() + internal fun (): kotlin.Short +internal val l: kotlin.Long = 2000000000000.toLong() + internal fun (): kotlin.Long +internal val l1: kotlin.Long = 1.toLong() + internal fun (): kotlin.Long +internal val s: kotlin.Short = 20000.toShort() + internal fun (): kotlin.Short +internal val s1: kotlin.Short = 1.toShort() + internal fun (): kotlin.Short +internal val str: kotlin.String = ":)" + internal fun (): kotlin.String \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java index 7a56fb31825..fcece966531 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java @@ -66,6 +66,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl doTest("compiler/testData/compileKotlinAgainstKotlin/ImportObject.A.kt"); } + @TestMetadata("InlinedConstants.A.kt") + public void testInlinedConstants() throws Exception { + doTest("compiler/testData/compileKotlinAgainstKotlin/InlinedConstants.A.kt"); + } + @TestMetadata("InnerClass.A.kt") public void testInnerClass() throws Exception { doTest("compiler/testData/compileKotlinAgainstKotlin/InnerClass.A.kt"); diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 4f20fb8b50a..a28d2b7d79f 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -2593,6 +2593,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTestCompiledKotlin("compiler/testData/loadJava/compiledKotlin/prop/CollectionSize.kt"); } + @TestMetadata("Constants.kt") + public void testConstants() throws Exception { + doTestCompiledKotlin("compiler/testData/loadJava/compiledKotlin/prop/Constants.kt"); + } + @TestMetadata("ExtValClass.kt") public void testExtValClass() throws Exception { doTestCompiledKotlin("compiler/testData/loadJava/compiledKotlin/prop/ExtValClass.kt"); diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveRecursiveComparingTestGenerated.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveRecursiveComparingTestGenerated.java index 9ef982632ec..5ab9d342207 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveRecursiveComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveRecursiveComparingTestGenerated.java @@ -1061,6 +1061,11 @@ public class LazyResolveRecursiveComparingTestGenerated extends AbstractLazyReso doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadJava/compiledKotlin/prop/CollectionSize.kt"); } + @TestMetadata("Constants.kt") + public void testConstants() throws Exception { + doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadJava/compiledKotlin/prop/Constants.kt"); + } + @TestMetadata("ExtValClass.kt") public void testExtValClass() throws Exception { doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadJava/compiledKotlin/prop/ExtValClass.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DescriptorDeserializersStorage.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DescriptorDeserializersStorage.java index 866c8899d95..48b03d61877 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DescriptorDeserializersStorage.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DescriptorDeserializersStorage.java @@ -87,9 +87,38 @@ public class DescriptorDeserializersStorage { @Override public KotlinJvmBinaryClass.AnnotationVisitor visitField(@NotNull Name name, @NotNull String desc, @Nullable Object initializer) { MemberSignature signature = MemberSignature.fromFieldNameAndDesc(name, desc); + if (initializer != null) { + Object normalizedValue; + if ("ZBCS".contains(desc)) { + int intValue = ((Integer) initializer).intValue(); + if ("Z".equals(desc)) { + normalizedValue = intValue != 0; + } + else if ("B".equals(desc)) { + normalizedValue = ((byte) intValue); + } + else if ("C".equals(desc)) { + normalizedValue = ((char) intValue); + } + else if ("S".equals(desc)) { + normalizedValue = ((short) intValue); + } + else { + throw new AssertionError(desc); + } + } + else { + normalizedValue = initializer; + } + propertyConstants.put(signature, ConstantsPackage.createCompileTimeConstant( - initializer, /* canBeUsedInAnnotation */ true, /* isPureIntConstant */ true, /* usesVariableAsConstant */ true, /* expectedType */ null)); + normalizedValue, + /* canBeUsedInAnnotation */ true, + /* isPureIntConstant */ true, + /* usesVariableAsConstant */ true, + /* expectedType */ null + )); } return new MemberAnnotationVisitor(signature); } diff --git a/idea/tests/org/jetbrains/jet/plugin/stubs/LazyResolveByStubTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/stubs/LazyResolveByStubTestGenerated.java index 83ae5f63739..8febd6a824d 100644 --- a/idea/tests/org/jetbrains/jet/plugin/stubs/LazyResolveByStubTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/stubs/LazyResolveByStubTestGenerated.java @@ -1061,6 +1061,11 @@ public class LazyResolveByStubTestGenerated extends AbstractLazyResolveByStubTes doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadJava/compiledKotlin/prop/CollectionSize.kt"); } + @TestMetadata("Constants.kt") + public void testConstants() throws Exception { + doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadJava/compiledKotlin/prop/Constants.kt"); + } + @TestMetadata("ExtValClass.kt") public void testExtValClass() throws Exception { doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadJava/compiledKotlin/prop/ExtValClass.kt"); From 3ee92da6f0fe46c7203de1676259ca4bbff0022f Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 17:50:26 +0400 Subject: [PATCH 112/143] Added test with all types of constants. --- .../build/IncrementalJpsTestGenerated.java | 5 +++++ .../incremental/allConstants/build.log | 22 +++++++++++++++++++ .../incremental/allConstants/const.kt | 12 ++++++++++ .../incremental/allConstants/const.kt.new.1 | 12 ++++++++++ .../incremental/allConstants/const.kt.new.2 | 12 ++++++++++ .../incremental/allConstants/usage.kt | 4 ++++ 6 files changed, 67 insertions(+) create mode 100644 jps-plugin/testData/incremental/allConstants/build.log create mode 100644 jps-plugin/testData/incremental/allConstants/const.kt create mode 100644 jps-plugin/testData/incremental/allConstants/const.kt.new.1 create mode 100644 jps-plugin/testData/incremental/allConstants/const.kt.new.2 create mode 100644 jps-plugin/testData/incremental/allConstants/usage.kt diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java index 8ac2e37fa69..d91f934ed53 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java @@ -32,6 +32,11 @@ import org.jetbrains.jet.jps.build.AbstractIncrementalJpsTest; @SuppressWarnings("all") @TestMetadata("jps-plugin/testData/incremental") public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { + @TestMetadata("allConstants") + public void testAllConstants() throws Exception { + doTest("jps-plugin/testData/incremental/allConstants/"); + } + public void testAllFilesPresentInIncremental() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("jps-plugin/testData/incremental"), Pattern.compile("^([^\\.]+)$"), false); } diff --git a/jps-plugin/testData/incremental/allConstants/build.log b/jps-plugin/testData/incremental/allConstants/build.log new file mode 100644 index 00000000000..22f4d62f635 --- /dev/null +++ b/jps-plugin/testData/incremental/allConstants/build.log @@ -0,0 +1,22 @@ +Cleaning output files: +out/production/module/test/TestPackage-const-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/const.kt +End of files + + +Cleaning output files: +out/production/module/test/TestPackage-const-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/const.kt +End of files +Cleaning output files: +out/production/module/test/Usage.class +End of files +Compiling files: +src/usage.kt +End of files diff --git a/jps-plugin/testData/incremental/allConstants/const.kt b/jps-plugin/testData/incremental/allConstants/const.kt new file mode 100644 index 00000000000..d0d300c1312 --- /dev/null +++ b/jps-plugin/testData/incremental/allConstants/const.kt @@ -0,0 +1,12 @@ +package test + +val b: Byte = 100 +val s: Short = 20000 +val i: Int = 2000000 +val l: Long = 2000000000000L +val f: Float = 3.14f +val d: Double = 3.14 +val bb: Boolean = true +val c: Char = '\u03c0' // pi symbol + +val str: String = ":)" diff --git a/jps-plugin/testData/incremental/allConstants/const.kt.new.1 b/jps-plugin/testData/incremental/allConstants/const.kt.new.1 new file mode 100644 index 00000000000..26796869ddc --- /dev/null +++ b/jps-plugin/testData/incremental/allConstants/const.kt.new.1 @@ -0,0 +1,12 @@ +package test + +val b: Byte = 50 + 50 +val s: Short = 10000 + 10000 +val i: Int = 1000000 + 1000000 +val l: Long = 1000000000000L + 1000000000000L +val f: Float = 0.0f + 3.14f +val d: Double = 0.0 + 3.14 +val bb: Boolean = !false +val c: Char = '\u03c0' // pi symbol + +val str: String = ":)" diff --git a/jps-plugin/testData/incremental/allConstants/const.kt.new.2 b/jps-plugin/testData/incremental/allConstants/const.kt.new.2 new file mode 100644 index 00000000000..668b4009dce --- /dev/null +++ b/jps-plugin/testData/incremental/allConstants/const.kt.new.2 @@ -0,0 +1,12 @@ +package test + +val b: Byte = 0 +val s: Short = 0 +val i: Int = 0 +val l: Long = 0 +val f: Float = 0.0f +val d: Double = 0.0 +val bb: Boolean = false +val c: Char = 'x' + +val str: String = ":(" diff --git a/jps-plugin/testData/incremental/allConstants/usage.kt b/jps-plugin/testData/incremental/allConstants/usage.kt new file mode 100644 index 00000000000..a52256d1a83 --- /dev/null +++ b/jps-plugin/testData/incremental/allConstants/usage.kt @@ -0,0 +1,4 @@ +package test + +deprecated("$b $s $i $l $f $d $bb $c $str") +class Usage From ab442754d6bf2eb27e0ffbba3646254a26ffe48f Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 17:48:47 +0400 Subject: [PATCH 113/143] Changing lastModified manually in case when it wasn't changed after file overwriting. --- .../jet/jps/build/AbstractIncrementalJpsTest.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt b/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt index 1879580f7d1..edd44cf39c1 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt @@ -187,7 +187,16 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { private class ModifyContent(name: String, val dataFile: File) : Modification(name) { override fun perform(workDir: File) { - dataFile.copyTo(File(workDir, "src/$name")) + val file = File(workDir, "src/$name") + + val oldLastModified = file.lastModified() + dataFile.copyTo(file) + + val newLastModified = file.lastModified() + if (newLastModified <= oldLastModified) { + //Mac OS and some versions of Linux truncate timestamp to nearest second + file.setLastModified(oldLastModified + 1000) + } } } From 9dd627a23db033c5c01ec7c33bd08c9e2aabd603 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 19:01:47 +0400 Subject: [PATCH 114/143] Removed ingoring files facility from incremental tests. It is not necessary since script.xml are not generated in out directory anymore. --- .../jps/build/AbstractIncrementalJpsTest.kt | 2 +- .../jet/jps/build/classFilesComparison.kt | 20 ++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt b/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt index edd44cf39c1..1878b410108 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt @@ -111,7 +111,7 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { rebuild() - assertEqualDirectories(outDir, outAfterMake, { it.name == "script.xml" }) + assertEqualDirectories(outDir, outAfterMake) FileUtil.delete(outAfterMake) } diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt b/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt index d5cf4a3667e..1811f5ed2d4 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/classFilesComparison.kt @@ -39,7 +39,7 @@ import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClass fun File.hash() = Files.hash(this, Hashing.crc32()) -fun getDirectoryString(dir: File, interestingPaths: List, ignore: (File) -> Boolean): String { +fun getDirectoryString(dir: File, interestingPaths: List): String { val buf = StringBuilder() val p = Printer(buf) @@ -52,10 +52,6 @@ fun getDirectoryString(dir: File, interestingPaths: List, ignore: (File) val children = listFiles!!.toList().sortBy { it.getName() }.sortBy { it.isDirectory() } for (child in children) { - if (ignore(child)) { - continue - } - if (child.isDirectory()) { p.println(child.name) addDirContent(child) @@ -82,10 +78,10 @@ fun getDirectoryString(dir: File, interestingPaths: List, ignore: (File) return buf.toString() } -fun getAllRelativePaths(dir: File, ignore: (File) -> Boolean): Set { +fun getAllRelativePaths(dir: File): Set { val result = HashSet() FileUtil.processFilesRecursively(dir) { - if (it!!.isFile() && !ignore(it)) { + if (it!!.isFile()) { result.add(FileUtil.getRelativePath(dir, it)!!) } @@ -95,16 +91,16 @@ fun getAllRelativePaths(dir: File, ignore: (File) -> Boolean): Set { return result } -fun assertEqualDirectories(expected: File, actual: File, ignore: (File) -> Boolean) { - val pathsInExpected = getAllRelativePaths(expected, ignore) - val pathsInActual = getAllRelativePaths(actual, ignore) +fun assertEqualDirectories(expected: File, actual: File) { + val pathsInExpected = getAllRelativePaths(expected) + val pathsInActual = getAllRelativePaths(actual) val changedPaths = Sets.intersection(pathsInExpected, pathsInActual) .filter { !Arrays.equals(File(expected, it).readBytes(), File(actual, it).readBytes()) } .sort() - val expectedString = getDirectoryString(expected, changedPaths, ignore) - val actualString = getDirectoryString(actual, changedPaths, ignore) + val expectedString = getDirectoryString(expected, changedPaths) + val actualString = getDirectoryString(actual, changedPaths) assertEquals(expectedString, actualString) } From fc7dceba5ad3acc42f87246ae03f872c74ce9c29 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 20:52:28 +0400 Subject: [PATCH 115/143] Clearing constants data when removing file. --- .../jps/incremental/IncrementalCacheImpl.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt index fb71bfd94b5..5a42f4e58bb 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt @@ -74,13 +74,14 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { if (header.syntheticClassKind == JvmAnnotationNames.KotlinSyntheticClass.Kind.PACKAGE_PART) { assert(sourceFiles.size == 1) { "Package part from several source files: $sourceFiles" } packagePartMap.putPackagePartSourceData(moduleId, sourceFiles.first(), className) - return constantsMap.process(className, fileBytes) + return constantsMap.process(moduleId, sourceFiles.first(), fileBytes) } return false } public fun clearCacheForRemovedFile(moduleId: String, sourceFile: File) { + constantsMap.remove(moduleId, sourceFile) packagePartMap.remove(moduleId, sourceFile) } @@ -135,6 +136,10 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { ConstantsMapExternalizer ) + private fun getKey(moduleId: String, sourceFile: File): String { + return moduleId + File.pathSeparator + sourceFile.getAbsolutePath() + } + private fun getConstantsMap(bytes: ByteArray): Map { val result = HashMap() @@ -150,12 +155,12 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return result } - public fun process(packagePartClass: JvmClassName, bytes: ByteArray): Boolean { - return put(packagePartClass, getConstantsMap(bytes)) + public fun process(moduleId: String, file: File, bytes: ByteArray): Boolean { + return put(moduleId, file, getConstantsMap(bytes)) } - private fun put(packagePartClass: JvmClassName, constantsMap: Map): Boolean { - val key = packagePartClass.getInternalName() + private fun put(moduleId: String, file: File, constantsMap: Map): Boolean { + val key = getKey(moduleId, file) val oldMap = map[key] if (oldMap == constantsMap) { @@ -165,6 +170,10 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return true } + public fun remove(moduleId: String, file: File) { + map.remove(getKey(moduleId, file)) + } + public fun close() { map.close() } From 5c49eb0a540482caef80629746740faa5fe50006 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 21:32:15 +0400 Subject: [PATCH 116/143] Writing class names in proto map (to avoid ambiguities) --- .../jps/incremental/IncrementalCacheImpl.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt index 5a42f4e58bb..6a4e2c54947 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt @@ -37,6 +37,7 @@ import java.util.HashSet import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalCache import java.util.HashMap import com.google.common.collect.Maps +import org.jetbrains.jet.lang.resolve.java.PackageClassUtils public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { class object { @@ -55,16 +56,15 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { if (classNameAndHeader == null) return false val (className, header) = classNameAndHeader - val classFqName = className.getFqNameForClassNameWithoutDollars() val annotationDataEncoded = header.annotationData if (annotationDataEncoded != null) { val data = BitEncoding.decodeBytes(annotationDataEncoded) when (header.kind) { KotlinClassHeader.Kind.PACKAGE_FACADE -> { - return protoMap.put(moduleId, classFqName.parent(), data) + return protoMap.put(moduleId, className, data) } KotlinClassHeader.Kind.CLASS -> { - return protoMap.put(moduleId, classFqName, data) + return protoMap.put(moduleId, className, data) } else -> { throw IllegalStateException("Unexpected kind with annotationData: ${header.kind}") @@ -90,7 +90,7 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { } public override fun getPackageData(moduleId: String, fqName: String): ByteArray? { - return protoMap[moduleId, fqName] + return protoMap[moduleId, JvmClassName.byFqNameWithoutInnerClasses(PackageClassUtils.getPackageClassFqName(FqName(fqName)))] } public fun close() { @@ -106,12 +106,12 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { ByteArrayExternalizer ) - private fun getKeyString(moduleId: String, fqName: FqName): String { - return moduleId + ":" + fqName + private fun getKeyString(moduleId: String, className: JvmClassName): String { + return moduleId + ":" + className.getInternalName() } - public fun put(moduleId: String, fqName: FqName, data: ByteArray): Boolean { - val key = getKeyString(moduleId, fqName) + public fun put(moduleId: String, className: JvmClassName, data: ByteArray): Boolean { + val key = getKeyString(moduleId, className) val oldData = map[key] if (Arrays.equals(data, oldData)) { return false @@ -120,8 +120,8 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return true } - public fun get(moduleId: String, fqName: String): ByteArray? { - return map[getKeyString(moduleId, FqName(fqName))] + public fun get(moduleId: String, className: JvmClassName): ByteArray? { + return map[getKeyString(moduleId, className)] } public fun close() { From 471e3e80f29653a37aa1a8b0532b845c84bec7e3 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 21:49:20 +0400 Subject: [PATCH 117/143] Minor. Fixed mixed up error messages in test. --- .../org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt b/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt index 1878b410108..3fb918b3e7e 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/AbstractIncrementalJpsTest.kt @@ -88,10 +88,10 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() { val haveFilesWithNumbers = testDataDir.listFiles { it.getName().matches(".+\\.(new|delete)\\.\\d+$") }?.isNotEmpty() ?: false if (haveFilesWithoutNumbers && haveFilesWithNumbers) { - fail("Bad test data format: no files ending with \".new\" or \".delete\" found") + fail("Bad test data format: files ending with both unnumbered and numbered \".new\"/\".delete\" were found") } if (!haveFilesWithoutNumbers && !haveFilesWithNumbers) { - fail("Bad test data format: files ending with both unnumbered and numbered \".new\"/\".delete\" were found") + fail("Bad test data format: no files ending with \".new\" or \".delete\" found") } if (haveFilesWithoutNumbers) { From 8479ca76b0e815cc104ca7143a2b355dc45a7a77 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Fri, 20 Jun 2014 21:51:27 +0400 Subject: [PATCH 118/143] Added clearing proto data in incremental cache. --- .../jet/jps/build/KotlinBuilder.java | 11 +++- .../jps/incremental/IncrementalCacheImpl.kt | 59 +++++++++++++++++-- .../build/IncrementalJpsTestGenerated.java | 15 +++++ .../incremental/classRecreated/A.kt.new.2 | 3 + .../testData/incremental/classRecreated/a.kt | 3 + .../incremental/classRecreated/a.kt.delete.1 | 1 + .../incremental/classRecreated/build.log | 17 ++++++ .../incremental/classRecreated/other.kt | 4 ++ .../incremental/packageRecreated/a.kt | 3 + .../packageRecreated/a.kt.delete.1 | 1 + .../incremental/packageRecreated/b.kt.new.2 | 3 + .../incremental/packageRecreated/build.log | 11 ++++ .../packageRecreatedAfterRenaming/a.kt | 3 + .../packageRecreatedAfterRenaming/a.kt.new.1 | 3 + .../packageRecreatedAfterRenaming/b.kt.new.2 | 3 + .../packageRecreatedAfterRenaming/build.log | 19 ++++++ 16 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 jps-plugin/testData/incremental/classRecreated/A.kt.new.2 create mode 100644 jps-plugin/testData/incremental/classRecreated/a.kt create mode 100644 jps-plugin/testData/incremental/classRecreated/a.kt.delete.1 create mode 100644 jps-plugin/testData/incremental/classRecreated/build.log create mode 100644 jps-plugin/testData/incremental/classRecreated/other.kt create mode 100644 jps-plugin/testData/incremental/packageRecreated/a.kt create mode 100644 jps-plugin/testData/incremental/packageRecreated/a.kt.delete.1 create mode 100644 jps-plugin/testData/incremental/packageRecreated/b.kt.new.2 create mode 100644 jps-plugin/testData/incremental/packageRecreated/build.log create mode 100644 jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt create mode 100644 jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt.new.1 create mode 100644 jps-plugin/testData/incremental/packageRecreatedAfterRenaming/b.kt.new.2 create mode 100644 jps-plugin/testData/incremental/packageRecreatedAfterRenaming/build.log diff --git a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java index 8faa3f15c23..853be538fc2 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java +++ b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.jps.build; +import com.google.common.collect.Lists; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.StreamUtil; @@ -23,6 +24,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; +import kotlin.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.cli.common.KotlinVersion; import org.jetbrains.jet.cli.common.arguments.CommonCompilerArguments; @@ -222,11 +224,18 @@ public class KotlinBuilder extends ModuleLevelBuilder { IncrementalCacheImpl cache = new IncrementalCacheImpl(KotlinBuilderModuleScriptGenerator.getIncrementalCacheDir(context)); try { + List> moduleIdsAndFiles = Lists.newArrayList(); + Map outDirectories = new HashMap(); + for (ModuleBuildTarget target : chunk.getTargets()) { + String targetId = target.getId(); + outDirectories.put(targetId, target.getOutputDir()); + for (String file : dirtyFilesHolder.getRemovedFiles(target)) { - cache.clearCacheForRemovedFile(target.getId(), new File(file)); + moduleIdsAndFiles.add(new Pair(targetId, new File(file))); } } + cache.clearCacheForRemovedFiles(moduleIdsAndFiles, outDirectories); boolean significantChanges = false; diff --git a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt index 6a4e2c54947..56a64060821 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt @@ -17,7 +17,6 @@ package org.jetbrains.jet.jps.incremental import java.io.File -import com.intellij.util.io.PersistentMap import com.intellij.util.io.PersistentHashMap import java.io.DataOutput import com.intellij.util.io.IOUtil @@ -38,6 +37,8 @@ import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalCache import java.util.HashMap import com.google.common.collect.Maps import org.jetbrains.jet.lang.resolve.java.PackageClassUtils +import com.intellij.util.containers.MultiMap +import com.intellij.openapi.util.io.FileUtil public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { class object { @@ -80,9 +81,13 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return false } - public fun clearCacheForRemovedFile(moduleId: String, sourceFile: File) { - constantsMap.remove(moduleId, sourceFile) - packagePartMap.remove(moduleId, sourceFile) + public fun clearCacheForRemovedFiles(moduleIdsAndFiles: Collection>, outDirectories: Map) { + for ((moduleId, sourceFile) in moduleIdsAndFiles) { + constantsMap.remove(moduleId, sourceFile) + packagePartMap.remove(moduleId, sourceFile) + } + + protoMap.clearOutdated(outDirectories) } public override fun getRemovedPackageParts(moduleId: String, compiledSourceFilesToFqName: Map): Collection { @@ -100,7 +105,7 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { } private inner class ProtoMap { - private val map: PersistentMap = PersistentHashMap( + private val map: PersistentHashMap = PersistentHashMap( File(baseDir, PROTO_MAP), EnumeratorStringDescriptor(), ByteArrayExternalizer @@ -110,6 +115,11 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return moduleId + ":" + className.getInternalName() } + private fun parseKeyString(key: String): Pair { + val colon = key.lastIndexOf(":") + return Pair(key.substring(0, colon), JvmClassName.byInternalName(key.substring(colon + 1))) + } + public fun put(moduleId: String, className: JvmClassName, data: ByteArray): Boolean { val key = getKeyString(moduleId, className) val oldData = map[key] @@ -124,6 +134,27 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return map[getKeyString(moduleId, className)] } + public fun clearOutdated(outDirectories: Map) { + val keysToRemove = HashSet() + + map.processKeys { key -> + val (moduleId, className) = parseKeyString(key!!) + val outDir = outDirectories[moduleId] + if (outDir != null) { + val classFile = File(outDir, FileUtil.toSystemDependentName(className.getInternalName()) + ".class") + if (!classFile.exists()) { + keysToRemove.add(key) + } + } + + true + } + + for (key in keysToRemove) { + map.remove(key) + } + } + public fun close() { map.close() } @@ -283,6 +314,24 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return result } + public fun getModulesToPackages(): MultiMap { + val result = MultiMap.createSet() + + map.processKeysWithExistingMapping { key -> + val indexOf = key!!.indexOf(File.pathSeparator) + val moduleId = key.substring(0, indexOf) + val packagePartClassName = map[key]!! + + val packageFqName = JvmClassName.byInternalName(packagePartClassName).getFqNameForClassNameWithoutDollars().parent() + + result.putValue(moduleId, packageFqName) + + true + } + + return result + } + public fun close() { map.close() } diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java index d91f934ed53..c475e1dda7a 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java @@ -41,6 +41,11 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("jps-plugin/testData/incremental"), Pattern.compile("^([^\\.]+)$"), false); } + @TestMetadata("classRecreated") + public void testClassRecreated() throws Exception { + doTest("jps-plugin/testData/incremental/classRecreated/"); + } + @TestMetadata("classSignatureChanged") public void testClassSignatureChanged() throws Exception { doTest("jps-plugin/testData/incremental/classSignatureChanged/"); @@ -101,6 +106,16 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest("jps-plugin/testData/incremental/packageFilesChangedInTurn/"); } + @TestMetadata("packageRecreated") + public void testPackageRecreated() throws Exception { + doTest("jps-plugin/testData/incremental/packageRecreated/"); + } + + @TestMetadata("packageRecreatedAfterRenaming") + public void testPackageRecreatedAfterRenaming() throws Exception { + doTest("jps-plugin/testData/incremental/packageRecreatedAfterRenaming/"); + } + @TestMetadata("packageRemoved") public void testPackageRemoved() throws Exception { doTest("jps-plugin/testData/incremental/packageRemoved/"); diff --git a/jps-plugin/testData/incremental/classRecreated/A.kt.new.2 b/jps-plugin/testData/incremental/classRecreated/A.kt.new.2 new file mode 100644 index 00000000000..1b0178fd9be --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/A.kt.new.2 @@ -0,0 +1,3 @@ +package test + +class A diff --git a/jps-plugin/testData/incremental/classRecreated/a.kt b/jps-plugin/testData/incremental/classRecreated/a.kt new file mode 100644 index 00000000000..1b0178fd9be --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/a.kt @@ -0,0 +1,3 @@ +package test + +class A diff --git a/jps-plugin/testData/incremental/classRecreated/a.kt.delete.1 b/jps-plugin/testData/incremental/classRecreated/a.kt.delete.1 new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/a.kt.delete.1 @@ -0,0 +1 @@ + diff --git a/jps-plugin/testData/incremental/classRecreated/build.log b/jps-plugin/testData/incremental/classRecreated/build.log new file mode 100644 index 00000000000..d59630c7ce7 --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/build.log @@ -0,0 +1,17 @@ +Cleaning output files: +out/production/module/test/A.class +End of files +Compiling files: +End of files + + +Compiling files: +src/A.kt +End of files +Cleaning output files: +out/production/module/test/TestPackage-other-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/other.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classRecreated/other.kt b/jps-plugin/testData/incremental/classRecreated/other.kt new file mode 100644 index 00000000000..dc156549ce5 --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/other.kt @@ -0,0 +1,4 @@ +package test + +fun other() { +} diff --git a/jps-plugin/testData/incremental/packageRecreated/a.kt b/jps-plugin/testData/incremental/packageRecreated/a.kt new file mode 100644 index 00000000000..30ca24b5576 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/a.kt @@ -0,0 +1,3 @@ +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/packageRecreated/a.kt.delete.1 b/jps-plugin/testData/incremental/packageRecreated/a.kt.delete.1 new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/a.kt.delete.1 @@ -0,0 +1 @@ + diff --git a/jps-plugin/testData/incremental/packageRecreated/b.kt.new.2 b/jps-plugin/testData/incremental/packageRecreated/b.kt.new.2 new file mode 100644 index 00000000000..5c782f47a25 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/b.kt.new.2 @@ -0,0 +1,3 @@ +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/packageRecreated/build.log b/jps-plugin/testData/incremental/packageRecreated/build.log new file mode 100644 index 00000000000..73408189236 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/build.log @@ -0,0 +1,11 @@ +Cleaning output files: +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +End of files + + +Compiling files: +src/b.kt +End of files diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt new file mode 100644 index 00000000000..30ca24b5576 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt @@ -0,0 +1,3 @@ +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt.new.1 b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt.new.1 new file mode 100644 index 00000000000..9d39f81713e --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt.new.1 @@ -0,0 +1,3 @@ +package test2 + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/b.kt.new.2 b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/b.kt.new.2 new file mode 100644 index 00000000000..5c782f47a25 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/b.kt.new.2 @@ -0,0 +1,3 @@ +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/build.log b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/build.log new file mode 100644 index 00000000000..7cb5ae7d3e1 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/build.log @@ -0,0 +1,19 @@ +Cleaning output files: +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/a.kt +End of files + + +Compiling files: +src/b.kt +End of files +Cleaning output files: +out/production/module/test2/Test2Package-a-*.class +out/production/module/test2/Test2Package.class +End of files +Compiling files: +src/a.kt +End of files From ca4ac43add86c8718e1c04a01c700d977662fa03 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 23 Jun 2014 14:23:26 +0400 Subject: [PATCH 119/143] Added tests with class referenced from proto. --- .../jps/build/IncrementalJpsTestGenerated.java | 10 ++++++++++ .../incremental/dependencyClassReferenced/a.kt | 6 ++++++ .../dependencyClassReferenced/a.kt.new | 6 ++++++ .../incremental/dependencyClassReferenced/b.kt | 6 ++++++ .../dependencyClassReferenced/build.log | 7 +++++++ .../incremental/ourClassReferenced/Klass.kt | 3 +++ .../ourClassReferenced/Klass.kt.new.2 | 3 +++ .../incremental/ourClassReferenced/a.kt | 8 ++++++++ .../incremental/ourClassReferenced/a.kt.new.1 | 8 ++++++++ .../incremental/ourClassReferenced/a.kt.new.2 | 8 ++++++++ .../incremental/ourClassReferenced/b.kt | 8 ++++++++ .../incremental/ourClassReferenced/build.log | 18 ++++++++++++++++++ 12 files changed, 91 insertions(+) create mode 100644 jps-plugin/testData/incremental/dependencyClassReferenced/a.kt create mode 100644 jps-plugin/testData/incremental/dependencyClassReferenced/a.kt.new create mode 100644 jps-plugin/testData/incremental/dependencyClassReferenced/b.kt create mode 100644 jps-plugin/testData/incremental/dependencyClassReferenced/build.log create mode 100644 jps-plugin/testData/incremental/ourClassReferenced/Klass.kt create mode 100644 jps-plugin/testData/incremental/ourClassReferenced/Klass.kt.new.2 create mode 100644 jps-plugin/testData/incremental/ourClassReferenced/a.kt create mode 100644 jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.1 create mode 100644 jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.2 create mode 100644 jps-plugin/testData/incremental/ourClassReferenced/b.kt create mode 100644 jps-plugin/testData/incremental/ourClassReferenced/build.log diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java index c475e1dda7a..487dbaee338 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java @@ -66,6 +66,11 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest("jps-plugin/testData/incremental/constantValue/"); } + @TestMetadata("dependencyClassReferenced") + public void testDependencyClassReferenced() throws Exception { + doTest("jps-plugin/testData/incremental/dependencyClassReferenced/"); + } + @TestMetadata("filesExchangePackages") public void testFilesExchangePackages() throws Exception { doTest("jps-plugin/testData/incremental/filesExchangePackages/"); @@ -81,6 +86,11 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest("jps-plugin/testData/incremental/multiplePackagesModified/"); } + @TestMetadata("ourClassReferenced") + public void testOurClassReferenced() throws Exception { + doTest("jps-plugin/testData/incremental/ourClassReferenced/"); + } + @TestMetadata("packageFileAdded") public void testPackageFileAdded() throws Exception { doTest("jps-plugin/testData/incremental/packageFileAdded/"); diff --git a/jps-plugin/testData/incremental/dependencyClassReferenced/a.kt b/jps-plugin/testData/incremental/dependencyClassReferenced/a.kt new file mode 100644 index 00000000000..89692d95832 --- /dev/null +++ b/jps-plugin/testData/incremental/dependencyClassReferenced/a.kt @@ -0,0 +1,6 @@ +package test + +fun a(ref: kotlin.test.Asserter) { + b(ref) + println(":)") +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/dependencyClassReferenced/a.kt.new b/jps-plugin/testData/incremental/dependencyClassReferenced/a.kt.new new file mode 100644 index 00000000000..89692d95832 --- /dev/null +++ b/jps-plugin/testData/incremental/dependencyClassReferenced/a.kt.new @@ -0,0 +1,6 @@ +package test + +fun a(ref: kotlin.test.Asserter) { + b(ref) + println(":)") +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/dependencyClassReferenced/b.kt b/jps-plugin/testData/incremental/dependencyClassReferenced/b.kt new file mode 100644 index 00000000000..9addb367f04 --- /dev/null +++ b/jps-plugin/testData/incremental/dependencyClassReferenced/b.kt @@ -0,0 +1,6 @@ +package test + +fun b(ref: kotlin.test.Asserter) { + a(ref) + println(":)") +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/dependencyClassReferenced/build.log b/jps-plugin/testData/incremental/dependencyClassReferenced/build.log new file mode 100644 index 00000000000..37112dda098 --- /dev/null +++ b/jps-plugin/testData/incremental/dependencyClassReferenced/build.log @@ -0,0 +1,7 @@ +Cleaning output files: +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/a.kt +End of files diff --git a/jps-plugin/testData/incremental/ourClassReferenced/Klass.kt b/jps-plugin/testData/incremental/ourClassReferenced/Klass.kt new file mode 100644 index 00000000000..a8ac38430eb --- /dev/null +++ b/jps-plugin/testData/incremental/ourClassReferenced/Klass.kt @@ -0,0 +1,3 @@ +package klass + +class Klass \ No newline at end of file diff --git a/jps-plugin/testData/incremental/ourClassReferenced/Klass.kt.new.2 b/jps-plugin/testData/incremental/ourClassReferenced/Klass.kt.new.2 new file mode 100644 index 00000000000..a8ac38430eb --- /dev/null +++ b/jps-plugin/testData/incremental/ourClassReferenced/Klass.kt.new.2 @@ -0,0 +1,3 @@ +package klass + +class Klass \ No newline at end of file diff --git a/jps-plugin/testData/incremental/ourClassReferenced/a.kt b/jps-plugin/testData/incremental/ourClassReferenced/a.kt new file mode 100644 index 00000000000..3682a9d2913 --- /dev/null +++ b/jps-plugin/testData/incremental/ourClassReferenced/a.kt @@ -0,0 +1,8 @@ +package test + +import klass.* + +fun a(klass: Klass) { + b(klass) + println(":)") +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.1 b/jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.1 new file mode 100644 index 00000000000..3682a9d2913 --- /dev/null +++ b/jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.1 @@ -0,0 +1,8 @@ +package test + +import klass.* + +fun a(klass: Klass) { + b(klass) + println(":)") +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.2 b/jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.2 new file mode 100644 index 00000000000..3682a9d2913 --- /dev/null +++ b/jps-plugin/testData/incremental/ourClassReferenced/a.kt.new.2 @@ -0,0 +1,8 @@ +package test + +import klass.* + +fun a(klass: Klass) { + b(klass) + println(":)") +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/ourClassReferenced/b.kt b/jps-plugin/testData/incremental/ourClassReferenced/b.kt new file mode 100644 index 00000000000..0d41f8e3417 --- /dev/null +++ b/jps-plugin/testData/incremental/ourClassReferenced/b.kt @@ -0,0 +1,8 @@ +package test + +import klass.* + +fun b(klass: Klass) { + a(klass) + println(":)") +} \ No newline at end of file diff --git a/jps-plugin/testData/incremental/ourClassReferenced/build.log b/jps-plugin/testData/incremental/ourClassReferenced/build.log new file mode 100644 index 00000000000..ccf56d9e65b --- /dev/null +++ b/jps-plugin/testData/incremental/ourClassReferenced/build.log @@ -0,0 +1,18 @@ +Cleaning output files: +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/a.kt +End of files + + +Cleaning output files: +out/production/module/klass/Klass.class +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/Klass.kt +src/a.kt +End of files From 1ce0e6cd3e7d2934f04fba1ddae41657a972484c Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Tue, 24 Jun 2014 16:29:00 +0400 Subject: [PATCH 120/143] Added exceptions for proguard: constants are used in JPS plugin. --- build.xml | 10 ++++++++++ .../src/org/jetbrains/jet/jps/build/KotlinBuilder.java | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/build.xml b/build.xml index e981cd215a2..0ed757c5698 100644 --- a/build.xml +++ b/build.xml @@ -474,6 +474,16 @@ void stop(); void dispose(); } + + -keepclassmembers class org.jetbrains.org.objectweb.asm.Opcodes { + *** ASM5; + } + + -keepclassmembers class org.jetbrains.org.objectweb.asm.ClassReader { + *** SKIP_CODE; + *** SKIP_DEBUG; + *** SKIP_FRAMES; + } ]]> diff --git a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java index 853be538fc2..7df7be35870 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java +++ b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java @@ -224,7 +224,7 @@ public class KotlinBuilder extends ModuleLevelBuilder { IncrementalCacheImpl cache = new IncrementalCacheImpl(KotlinBuilderModuleScriptGenerator.getIncrementalCacheDir(context)); try { - List> moduleIdsAndFiles = Lists.newArrayList(); + List> moduleIdsAndFiles = new ArrayList>(); Map outDirectories = new HashMap(); for (ModuleBuildTarget target : chunk.getTargets()) { From 0717511abec019a62ffeae9f438fb4b80e08f0e8 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Thu, 5 Jun 2014 21:07:38 +0400 Subject: [PATCH 121/143] Substring and replace before/after first/last occurrence of delimiter. --- libraries/stdlib/src/kotlin/text/Strings.kt | 152 ++++++++++++++++++++ libraries/stdlib/test/text/StringTest.kt | 58 +++++++- 2 files changed, 209 insertions(+), 1 deletion(-) diff --git a/libraries/stdlib/src/kotlin/text/Strings.kt b/libraries/stdlib/src/kotlin/text/Strings.kt index 57c44f98542..6256563df74 100644 --- a/libraries/stdlib/src/kotlin/text/Strings.kt +++ b/libraries/stdlib/src/kotlin/text/Strings.kt @@ -95,3 +95,155 @@ public fun Array.join(separator: String = ", ", prefix: String = "", pos public fun Stream.join(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String { return joinToString(separator, prefix, postfix, limit, truncated) } +/** + * Returns a substring before first occurrence of delimiter. In case of no delimiter, returns the whole string. + */ +public fun String.substringBefore(delimiter: Char): String { + val index = indexOf(delimiter) + return if (index == -1) this else substring(0, index) +} + +/** + * Returns a substring before first occurrence of delimiter. In case of no delimiter, returns the whole string. + */ +public fun String.substringBefore(delimiter: String): String { + val index = indexOf(delimiter) + return if (index == -1) this else substring(0, index) +} +/** + * Returns a substring after first occurrence of delimiter. In case of no delimiter, returns an empty string. + */ +public fun String.substringAfter(delimiter: Char): String { + val index = indexOf(delimiter) + return if (index == -1) "" else substring(index + 1, length) +} + +/** + * Returns a substring after first occurrence of delimiter. In case of no delimiter, returns an empty string. + */ +public fun String.substringAfter(delimiter: String): String { + val index = indexOf(delimiter) + return if (index == -1) "" else substring(index + delimiter.length, length) +} + +/** + * Returns a substring before last occurrence of delimiter. In case of no delimiter, returns the whole string. + */ +public fun String.substringBeforeLast(delimiter: Char): String { + val index = lastIndexOf(delimiter) + return if (index == -1) this else substring(0, index) +} + +/** + * Returns a substring before last occurrence of delimiter. In case of no delimiter, returns the whole string. + */ +public fun String.substringBeforeLast(delimiter: String): String { + val index = lastIndexOf(delimiter) + return if (index == -1) this else substring(0, index) +} + +/** + * Returns a substring after last occurrence of delimiter. In case of no delimiter, returns an empty string. + */ +public fun String.substringAfterLast(delimiter: Char): String { + val index = lastIndexOf(delimiter) + return if (index == -1) "" else substring(index + 1, length) +} + +/** + * Returns a substring after last occurrence of delimiter. In case of no delimiter, returns an empty string. + */ +public fun String.substringAfterLast(delimiter: String): String { + val index = lastIndexOf(delimiter) + return if (index == -1) "" else substring(index + delimiter.length, length) +} + +/** + * Replace part of string at given range with replacement string + */ +public fun String.replaceRange(firstIndex: Int, lastIndex: Int, replacement: String): String { + if (lastIndex < firstIndex) + throw IndexOutOfBoundsException("Last index ($lastIndex) is less than first index ($firstIndex)") + val sb = StringBuilder() + sb.append(this, 0, firstIndex) + sb.append(replacement) + sb.append(this, lastIndex, length) + return sb.toString() +} + +/** + * Replace part of string at given range with replacement string + */ +public fun String.replaceRange(range: IntRange, replacement: String): String { + if (range.end < range.start) + throw IndexOutOfBoundsException("Last index (${range.start}) is less than first index (${range.end})") + val sb = StringBuilder() + sb.append(this, 0, range.start) + sb.append(replacement) + sb.append(this, range.end, length) + return sb.toString() +} + +/** + * Replace part of string before first occurrence of given delimiter with replacement string + */ +public fun String.replaceBefore(delimiter: Char, replacement: String): String { + val index = indexOf(delimiter) + return if (index == -1) replacement else replaceRange(0, index, replacement) +} + +/** + * Replace part of string before first occurrence of given delimiter with replacement string + */ +public fun String.replaceBefore(delimiter: String, replacement: String): String { + val index = indexOf(delimiter) + return if (index == -1) replacement else replaceRange(0, index, replacement) +} + +/** + * Replace part of string after first occurrence of given delimiter with replacement string + */ +public fun String.replaceAfter(delimiter: Char, replacement: String): String { + val index = indexOf(delimiter) + return if (index == -1) this else replaceRange(index + 1, length, replacement) +} + +/** + * Replace part of string after first occurrence of given delimiter with replacement string + */ +public fun String.replaceAfter(delimiter: String, replacement: String): String { + val index = indexOf(delimiter) + return if (index == -1) this else replaceRange(index + delimiter.length, length, replacement) +} + +/** + * Replace part of string after last occurrence of given delimiter with replacement string + */ +public fun String.replaceAfterLast(delimiter: String, replacement: String): String { + val index = lastIndexOf(delimiter) + return if (index == -1) this else replaceRange(index + delimiter.length, length, replacement) +} + +/** + * Replace part of string after last occurrence of given delimiter with replacement string + */ +public fun String.replaceAfterLast(delimiter: Char, replacement: String): String { + val index = lastIndexOf(delimiter) + return if (index == -1) this else replaceRange(index + 1, length, replacement) +} + +/** + * Replace part of string before last occurrence of given delimiter with replacement string + */ +public fun String.replaceBeforeLast(delimiter: Char, replacement: String): String { + val index = lastIndexOf(delimiter) + return if (index == -1) replacement else replaceRange(0, index, replacement) +} + +/** + * Replace part of string before last occurrence of given delimiter with replacement string + */ +public fun String.replaceBeforeLast(delimiter: String, replacement: String): String { + val index = lastIndexOf(delimiter) + return if (index == -1) replacement else replaceRange(0, index, replacement) +} diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index a1d584ec0fc..d8d9a9942cb 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -66,6 +66,62 @@ class StringTest { test fun indices() { assertEquals(0..4, "abcde".indices) assertEquals(0..0, "a".indices) - assertEquals(IntRange.EMPTY, "".indices) + assertTrue("".indices.isEmpty()) } + + test fun replaceRange() { + val s = "sample text" + assertEquals("sa??e text", s.replaceRange(2, 5, "??")) + assertEquals("sa??e text", s.replaceRange(2..5, "??")) + fails { + s.replaceRange(5..2, "??") + } + fails { + s.replaceRange(5, 2, "??") + } + } + + test fun substringDelimited() { + val s = "-1,22,3+" + // chars + assertEquals("22,3+", s.substringAfter(',')) + assertEquals("3+", s.substringAfterLast(',')) + assertEquals("-1", s.substringBefore(',')) + assertEquals("-1,22", s.substringBeforeLast(',')) + + // strings + assertEquals("22,3+", s.substringAfter(",")) + assertEquals("3+", s.substringAfterLast(",")) + assertEquals("-1", s.substringBefore(",")) + assertEquals("-1,22", s.substringBeforeLast(",")) + + // non-existing delimiter + assertEquals("", s.substringAfter("+")) + assertEquals("", s.substringBefore("-")) + assertEquals(s, s.substringBefore("=")) + assertEquals("", s.substringAfter("=")) + + } + + test fun replaceDelimited() { + val s = "/user/folder/file.extension" + // chars + assertEquals("/user/folder/file.doc", s.replaceAfter('.', "doc")) + assertEquals("/user/folder/another.doc", s.replaceAfterLast('/', "another.doc")) + assertEquals("new name.extension", s.replaceBefore('.', "new name")) + assertEquals("/new/path/file.extension", s.replaceBeforeLast('/', "/new/path")) + + // strings + assertEquals("/user/folder/file.doc", s.replaceAfter(".", "doc")) + assertEquals("/user/folder/another.doc", s.replaceAfterLast("/", "another.doc")) + assertEquals("new name.extension", s.replaceBefore(".", "new name")) + assertEquals("/new/path/file.extension", s.replaceBeforeLast("/", "/new/path")) + + // non-existing delimiter + assertEquals("/user/folder/file.extension", s.replaceAfter("=", "doc")) + assertEquals("/user/folder/file.extension", s.replaceAfterLast("=", "another.doc")) + assertEquals("new name", s.replaceBefore("=", "new name")) + assertEquals("/new/path", s.replaceBeforeLast("=", "/new/path")) + } + } From 516bae17d7cfa78dacf5dea39b3e2f06193226fa Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Thu, 5 Jun 2014 23:20:39 +0400 Subject: [PATCH 122/143] StringBuilder builder and appendln --- js/js.libraries/src/core/javalang.kt | 5 +- .../semantics/StdLibStringBuilderTest.java | 10 ++++ .../k2js/test/semantics/StdLibStringTest.java | 10 ++++ .../src/org/jetbrains/k2js/config/Config.java | 1 + js/js.translator/testData/kotlin_lib.js | 11 +++- .../stdlib/src/kotlin/text/StringBuilder.kt | 37 ++++++++++++ .../src/kotlin/text/StringBuilderJVM.kt | 59 +++++++++++++++++++ libraries/stdlib/src/kotlin/text/Strings.kt | 6 +- .../stdlib/test/text/StringBuilderTest.kt | 28 +++++++++ libraries/stdlib/test/text/StringTest.kt | 1 - libraries/tools/kotlin-js-library/pom.xml | 1 + 11 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringBuilderTest.java create mode 100644 js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringTest.java create mode 100644 libraries/stdlib/src/kotlin/text/StringBuilder.kt create mode 100644 libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt create mode 100644 libraries/stdlib/test/text/StringBuilderTest.kt diff --git a/js/js.libraries/src/core/javalang.kt b/js/js.libraries/src/core/javalang.kt index fa927038af5..df87315b7f0 100644 --- a/js/js.libraries/src/core/javalang.kt +++ b/js/js.libraries/src/core/javalang.kt @@ -40,7 +40,7 @@ public trait Comparable { library public trait Appendable { public open fun append(csq: CharSequence?): Appendable - //public open fun append(csq: CharSequence?, start: Int, end: Int): Appendable + public open fun append(csq: CharSequence?, start: Int, end: Int): Appendable public open fun append(c: Char): Appendable } @@ -48,8 +48,7 @@ library public class StringBuilder() : Appendable { override fun append(c: Char): StringBuilder = js.noImpl override fun append(csq: CharSequence?): StringBuilder = js.noImpl - //TODO - //override fun append(csq: CharSequence?, start: Int, end: Int): StringBuilder = js.noImpl + override fun append(csq: CharSequence?, start: Int, end: Int): StringBuilder = js.noImpl public fun append(obj: Any?): StringBuilder = js.noImpl public fun reverse(): StringBuilder = js.noImpl override fun toString(): String = js.noImpl diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringBuilderTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringBuilderTest.java new file mode 100644 index 00000000000..3c4bf9c0755 --- /dev/null +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringBuilderTest.java @@ -0,0 +1,10 @@ +package org.jetbrains.k2js.test.semantics; + +import junit.framework.Test; + +@SuppressWarnings("JUnitTestCaseWithNoTests") +public final class StdLibStringBuilderTest extends JsUnitTestBase { + public static Test suite() throws Exception { + return createTestSuiteForFile("libraries/stdlib/test/text/StringBuilderTest.kt"); + } +} diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringTest.java new file mode 100644 index 00000000000..1a05014230a --- /dev/null +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/StdLibStringTest.java @@ -0,0 +1,10 @@ +package org.jetbrains.k2js.test.semantics; + +import junit.framework.Test; + +@SuppressWarnings("JUnitTestCaseWithNoTests") +public final class StdLibStringTest extends JsUnitTestBase { + public static Test suite() throws Exception { + return createTestSuiteForFile("libraries/stdlib/test/text/StringTest.kt"); + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/config/Config.java b/js/js.translator/src/org/jetbrains/k2js/config/Config.java index e570c104029..aea3607710f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/config/Config.java +++ b/js/js.translator/src/org/jetbrains/k2js/config/Config.java @@ -139,6 +139,7 @@ public abstract class Config { "/kotlin/Ranges.kt", "/kotlin/Numbers.kt", "/kotlin/text/Strings.kt", + "/kotlin/text/StringBuilder.kt", "/kotlin/dom/Dom.kt", "/kotlin/test/Test.kt" ); diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index 39e358bd7df..0e9d42c1081 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -649,8 +649,15 @@ function () { this.string = ""; }, { - append: function (obj) { - this.string = this.string + obj.toString(); + append: function (obj, from, to) { + if (from == undefined && to == undefined) { + this.string = this.string + obj.toString(); + } else if (to == undefined) { + this.string = this.string + obj.toString().substring(from); + } else { + this.string = this.string + obj.toString().substring(from, to); + } + return this; }, reverse: function () { diff --git a/libraries/stdlib/src/kotlin/text/StringBuilder.kt b/libraries/stdlib/src/kotlin/text/StringBuilder.kt new file mode 100644 index 00000000000..de8fffe04f6 --- /dev/null +++ b/libraries/stdlib/src/kotlin/text/StringBuilder.kt @@ -0,0 +1,37 @@ +package kotlin + +/** + * Builds newly created StringBuilder using provided body. + */ +public inline fun StringBuilder(body: StringBuilder.() -> Unit): StringBuilder { + val sb = StringBuilder() + sb.body() + return sb +} + +/** + * Appends all arguments to the given Appendable + */ +public fun T.append(vararg value: CharSequence?): T { + for (item in value) + append(item) + return this +} + +/** + * Appends all arguments to the given StringBuilder + */ +public fun StringBuilder.append(vararg value: String?): StringBuilder { + for (item in value) + append(item) + return this +} + +/** + * Appends all arguments to the given StringBuilder + */ +public fun StringBuilder.append(vararg value: Any?): StringBuilder { + for (item in value) + append(item) + return this +} diff --git a/libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt b/libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt new file mode 100644 index 00000000000..cf06ad96032 --- /dev/null +++ b/libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt @@ -0,0 +1,59 @@ +package kotlin + +/** Line separator for current system. */ +val LINE_SEPARATOR: String = System.getProperty("line.separator")!! + +/** Appends line separator to Appendable. */ +public fun Appendable.appendln(): Appendable = append(LINE_SEPARATOR) + +/** Appends value to the given Appendable and line separator after it. */ +public fun Appendable.appendln(value: CharSequence?): Appendable = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given Appendable and line separator after it. */ +public fun Appendable.appendln(value: Char): Appendable = append(value).append(LINE_SEPARATOR) + +/** Appends line separator to StringBuilder. */ + +public fun StringBuilder.appendln(): StringBuilder = append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: StringBuffer?): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: CharSequence?): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: String?): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Any?): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: StringBuilder?): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: CharArray): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Char): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Boolean): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Int): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Short): StringBuilder = append(value.toInt()).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Byte): StringBuilder = append(value.toInt()).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Long): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Float): StringBuilder = append(value).append(LINE_SEPARATOR) + +/** Appends value to the given StringBuilder and line separator after it. */ +public fun StringBuilder.appendln(value: Double): StringBuilder = append(value).append(LINE_SEPARATOR) diff --git a/libraries/stdlib/src/kotlin/text/Strings.kt b/libraries/stdlib/src/kotlin/text/Strings.kt index 6256563df74..4de2122fcd9 100644 --- a/libraries/stdlib/src/kotlin/text/Strings.kt +++ b/libraries/stdlib/src/kotlin/text/Strings.kt @@ -57,11 +57,11 @@ public val String.indices: IntRange * Returns a subsequence specified by given set of indices. */ public fun CharSequence.slice(indices: Iterable): CharSequence { - val result = StringBuilder() + val sb = StringBuilder() for (i in indices) { - result.append(get(i)) + sb.append(get(i)) } - return result.toString() + return sb.toString() } /** diff --git a/libraries/stdlib/test/text/StringBuilderTest.kt b/libraries/stdlib/test/text/StringBuilderTest.kt new file mode 100644 index 00000000000..90677c70e42 --- /dev/null +++ b/libraries/stdlib/test/text/StringBuilderTest.kt @@ -0,0 +1,28 @@ +package test.text + +import kotlin.test.* +import org.junit.Test as test + +class StringBuilderTest { + + test fun stringBuild() { + val s = StringBuilder { + append("a") + append(true) + }.toString() + assertEquals("atrue", s) + } + + test fun appendMany() { + assertEquals("a1", StringBuilder().append("a", "1").toString()) + assertEquals("a1", StringBuilder().append("a", 1).toString()) + assertEquals("a1", StringBuilder().append("a", StringBuilder().append("1")).toString()) + } + + test fun append() { + // this test is needed for JS implementation + assertEquals("em", StringBuilder { + append("element", 2, 4) + }.toString()) + } +} diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index d8d9a9942cb..10c6b50c78f 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -123,5 +123,4 @@ class StringTest { assertEquals("new name", s.replaceBefore("=", "new name")) assertEquals("/new/path", s.replaceBeforeLast("=", "/new/path")) } - } diff --git a/libraries/tools/kotlin-js-library/pom.xml b/libraries/tools/kotlin-js-library/pom.xml index 01c94c1834f..6d90531bcd6 100644 --- a/libraries/tools/kotlin-js-library/pom.xml +++ b/libraries/tools/kotlin-js-library/pom.xml @@ -71,6 +71,7 @@ --> + From 4e4d0b448cab807df7148f68a6acf11483595421 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Fri, 6 Jun 2014 01:31:04 +0400 Subject: [PATCH 123/143] Minor. Cleanup test. --- libraries/stdlib/test/collections/StreamTest.kt | 10 +++++----- libraries/stdlib/test/text/StringUtilTest.kt | 10 ++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/libraries/stdlib/test/collections/StreamTest.kt b/libraries/stdlib/test/collections/StreamTest.kt index 1e8f6562e56..c65dc8a820d 100644 --- a/libraries/stdlib/test/collections/StreamTest.kt +++ b/libraries/stdlib/test/collections/StreamTest.kt @@ -9,7 +9,7 @@ fun fibonacci(): Stream { var index = 0; var a = 0; var b = 1 - return stream { + return stream { when (index++) { 0 -> a; 1 -> b; else -> { val result = a + b; a = b; b = result; result } } @@ -81,8 +81,8 @@ public class StreamTest { test fun plus() { val stream = listOf("foo", "bar").stream() - val streamChease = stream + "cheese" - assertEquals(listOf("foo", "bar", "cheese"), streamChease.toList()) + val streamCheese = stream + "cheese" + assertEquals(listOf("foo", "bar", "cheese"), streamCheese.toList()) // lets use a mutable variable var mi = listOf("a", "b").stream() @@ -118,7 +118,7 @@ public class StreamTest { test fun streamFromFunction() { var count = 3 - val stream = stream { + val stream = stream { count-- if (count >= 0) count else null } @@ -128,7 +128,7 @@ public class StreamTest { } test fun streamFromFunctionWithInitialValue() { - val values = stream(3) { n -> if (n > 0) n - 1 else null } + val values = stream(3) { n -> if (n > 0) n - 1 else null } assertEquals(arrayListOf(3, 2, 1, 0), values.toList()) } diff --git a/libraries/stdlib/test/text/StringUtilTest.kt b/libraries/stdlib/test/text/StringUtilTest.kt index 3998aaeedd7..5414c3dc515 100644 --- a/libraries/stdlib/test/text/StringUtilTest.kt +++ b/libraries/stdlib/test/text/StringUtilTest.kt @@ -3,14 +3,12 @@ package test.text import kotlin.* import kotlin.test.* import kotlin.util.* +import org.junit.Test as test -import junit.framework.* - -class StringUtilTest() : TestCase() { - - fun testToRegex() { +class StringUtilTest() { + test fun toRegex() { val re = """foo""".toRegex() val list = re.split("hellofoobar").toList() - assertEquals(arrayList("hello", "bar"), list) + assertEquals(listOf("hello", "bar"), list) } } From f94b79fac3f8b2b737c0248e4ca20011268085b7 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Fri, 6 Jun 2014 01:45:29 +0400 Subject: [PATCH 124/143] Minor. Update reference to issue. --- libraries/stdlib/test/collections/IterableTests.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/stdlib/test/collections/IterableTests.kt b/libraries/stdlib/test/collections/IterableTests.kt index 10a5765bf5d..1ecee2492c6 100644 --- a/libraries/stdlib/test/collections/IterableTests.kt +++ b/libraries/stdlib/test/collections/IterableTests.kt @@ -105,7 +105,7 @@ abstract class IterableTests>(val data: T, val empty: T) { Test fun filter() { val foo = data.filter { it.startsWith("f") } - // TODO uncomment this when KT-4651 will be fixed + // TODO uncomment this when KT-2468 will be fixed //expect(true) { foo is List } expect(true) { foo.all { it.startsWith("f") } } expect(1) { foo.size } @@ -114,7 +114,7 @@ abstract class IterableTests>(val data: T, val empty: T) { Test fun filterNot() { val notFoo = data.filterNot { it.startsWith("f") } - // TODO uncomment this when KT-4651 will be fixed + // TODO uncomment this when KT-2468 will be fixed //expect(true) { notFoo is List } expect(true) { notFoo.none { it.startsWith("f") } } expect(1) { notFoo.size } From 65da4cb2fb05a91e02034f7cc8fca3811cf9c8bd Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 14:23:35 +0400 Subject: [PATCH 125/143] Generalize zip(..) to merge(..) { t1, t2 -> ... }, add merge for maps. --- libraries/stdlib/src/generated/_Generators.kt | 473 ++++++++++++------ .../stdlib/src/kotlin/collections/Stream.kt | 6 +- .../stdlib/test/collections/CollectionTest.kt | 14 + libraries/stdlib/test/collections/MapTest.kt | 2 +- .../stdlib/test/collections/StreamTest.kt | 7 + .../src/templates/Generators.kt | 87 +++- 6 files changed, 413 insertions(+), 176 deletions(-) diff --git a/libraries/stdlib/src/generated/_Generators.kt b/libraries/stdlib/src/generated/_Generators.kt index 5bdebb21b70..4949aa2280c 100644 --- a/libraries/stdlib/src/generated/_Generators.kt +++ b/libraries/stdlib/src/generated/_Generators.kt @@ -7,6 +7,299 @@ package kotlin import java.util.* +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Array.merge(array: Array, transform: (T, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun BooleanArray.merge(array: Array, transform: (Boolean, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ByteArray.merge(array: Array, transform: (Byte, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun CharArray.merge(array: Array, transform: (Char, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun DoubleArray.merge(array: Array, transform: (Double, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun FloatArray.merge(array: Array, transform: (Float, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun IntArray.merge(array: Array, transform: (Int, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun LongArray.merge(array: Array, transform: (Long, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ShortArray.merge(array: Array, transform: (Short, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Iterable.merge(array: Array, transform: (T, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun String.merge(array: Array, transform: (Char, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Array.merge(other: Iterable, transform: (T, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun BooleanArray.merge(other: Iterable, transform: (Boolean, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ByteArray.merge(other: Iterable, transform: (Byte, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun CharArray.merge(other: Iterable, transform: (Char, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun DoubleArray.merge(other: Iterable, transform: (Double, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun FloatArray.merge(other: Iterable, transform: (Float, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun IntArray.merge(other: Iterable, transform: (Int, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun LongArray.merge(other: Iterable, transform: (Long, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ShortArray.merge(other: Iterable, transform: (Short, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Iterable.merge(other: Iterable, transform: (T, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun String.merge(other: Iterable, transform: (Char, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a stream of values built from elements of both collections with same indexes using provided *transform*. Stream has length of shortest stream. + */ +public fun Stream.merge(stream: Stream, transform: (T, R) -> V): Stream { + return MergingStream(this, stream, transform) +} + /** * Splits original collection into pair of collections, * where *first* collection contains elements for which predicate yielded *true*, @@ -518,286 +811,154 @@ public fun Stream.plus(stream: Stream): Stream { * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Array.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun BooleanArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ByteArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun CharArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun DoubleArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun FloatArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun IntArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun LongArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ShortArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Iterable.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun String.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Array.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun BooleanArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ByteArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun CharArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun DoubleArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun FloatArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun IntArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun LongArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ShortArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Iterable.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun String.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** @@ -814,9 +975,9 @@ public fun String.zip(other: String): List> { } /** - * Returns a stream of pairs built from elements of both collections with same indexes. List has length of shortest collection. + * Returns a stream of pairs built from elements of both collections with same indexes. Stream has length of shortest stream. */ public fun Stream.zip(stream: Stream): Stream> { - return ZippingStream(this, stream) + return MergingStream(this, stream) { (t1, t2) -> t1 to t2 } } diff --git a/libraries/stdlib/src/kotlin/collections/Stream.kt b/libraries/stdlib/src/kotlin/collections/Stream.kt index f1701e46c9a..357e78ff1b6 100644 --- a/libraries/stdlib/src/kotlin/collections/Stream.kt +++ b/libraries/stdlib/src/kotlin/collections/Stream.kt @@ -38,13 +38,13 @@ public class TransformingStream(val stream: Stream, val transformer: (T } } -class ZippingStream(val stream1: Stream, val stream2: Stream) : Stream> { - override fun iterator(): Iterator> = object : AbstractIterator>() { +public class MergingStream(val stream1: Stream, val stream2: Stream, val transform: (T1, T2) -> V) : Stream { + override fun iterator(): Iterator = object : AbstractIterator() { val iterator1 = stream1.iterator() val iterator2 = stream2.iterator() override fun computeNext() { if (iterator1.hasNext() && iterator2.hasNext()) { - setNext(iterator1.next() to iterator2.next()) + setNext(transform(iterator1.next(), iterator2.next())) } else { done() } diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index cc2627ff3f9..72ea5224722 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -120,6 +120,20 @@ class CollectionTest { } } + test + fun merge() { + expect(listOf("ab", "bc", "cd")) { + listOf("a", "b", "c").merge(listOf("b", "c", "d")) { a, b -> a + b } + } + } + + test + fun zip() { + expect(listOf("a" to "b", "b" to "c", "c" to "d")) { + listOf("a", "b", "c").zip(listOf("b", "c", "d")) + } + } + test fun partition() { val data = arrayListOf("foo", "bar", "something", "xyz") val pair = data.partition { it.size == 3 } diff --git a/libraries/stdlib/test/collections/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index 43dc8cb5de1..4638138a035 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -53,7 +53,7 @@ class MapTest { assertEquals(map.size(), 1) assertEquals("James", map["name"]) } - + test fun iterate() { val map = TreeMap() map["beverage"] = "beer" diff --git a/libraries/stdlib/test/collections/StreamTest.kt b/libraries/stdlib/test/collections/StreamTest.kt index c65dc8a820d..4efc8b8c3c6 100644 --- a/libraries/stdlib/test/collections/StreamTest.kt +++ b/libraries/stdlib/test/collections/StreamTest.kt @@ -73,6 +73,13 @@ public class StreamTest { assertEquals("13, 21, 34, 55, 89, 144, 233, 377, 610, 987, ...", fibonacci().drop(3).drop(4).joinToString(limit = 10)) } + test + fun merge() { + expect(listOf("ab", "bc", "cd")) { + streamOf("a", "b", "c").merge(streamOf("b", "c", "d")) { a, b -> a + b }.toList() + } + } + test fun toStringJoinsNoMoreThanTheFirstTenElements() { assertEquals("0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...", fibonacci().joinToString(limit = 10)) assertEquals("13, 21, 34, 55, 89, 144, 233, 377, 610, 987, ...", fibonacci().filter { it > 10 }.joinToString(limit = 10)) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt index 3d1cb6599c6..1345cff7f72 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt @@ -118,6 +118,73 @@ fun generators(): List { } } + templates add f("merge(other: Iterable, transform: (T, R) -> V)") { + exclude(Streams) + doc { + """ + Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + """ + } + typeParam("R") + typeParam("V") + returns("List") + inline(true) + body { + """ + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list + """ + } + } + + templates add f("merge(array: Array, transform: (T, R) -> V)") { + exclude(Streams) + doc { + """ + Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + """ + } + typeParam("R") + typeParam("V") + returns("List") + inline(true) + body { + """ + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list + """ + } + } + + + templates add f("merge(stream: Stream, transform: (T, R) -> V)") { + only(Streams) + doc { + """ + Returns a stream of values built from elements of both collections with same indexes using provided *transform*. Stream has length of shortest stream. + """ + } + typeParam("R") + typeParam("V") + returns("Stream") + body { + """ + return MergingStream(this, stream, transform) + """ + } + } + + templates add f("zip(other: Iterable)") { exclude(Streams) doc { @@ -129,13 +196,7 @@ fun generators(): List { returns("List>") body { """ - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } """ } } @@ -172,13 +233,7 @@ fun generators(): List { returns("List>") body { """ - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } """ } } @@ -187,14 +242,14 @@ fun generators(): List { only(Streams) doc { """ - Returns a stream of pairs built from elements of both collections with same indexes. List has length of shortest collection. + Returns a stream of pairs built from elements of both collections with same indexes. Stream has length of shortest stream. """ } typeParam("R") returns("Stream>") body { """ - return ZippingStream(this, stream) + return MergingStream(this, stream) { (t1, t2) -> t1 to t2 } """ } } From 132f2a5fa8ba58a32b0c58ef2dd5e747d65e0d88 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 14:51:05 +0400 Subject: [PATCH 126/143] Improve performance for addAll with type check for Collection --- .../stdlib/src/kotlin/collections/MutableCollections.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt index 1a99bebe612..ba221cfd04c 100644 --- a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt +++ b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt @@ -4,7 +4,10 @@ package kotlin * Adds all elements of the given *iterable* to this [[MutableCollection]] */ public fun MutableCollection.addAll(iterable: Iterable): Unit { - for (e in iterable) add(e) + when (iterable) { + is Collection -> addAll(iterable) + else -> for (e in iterable) add(e) + } } public fun MutableCollection.addAll(stream: Stream): Unit { From ca7c3d79993271b418c95f874309eeb7ddba23f4 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 16:49:53 +0400 Subject: [PATCH 127/143] Set operations (distinct, union, intersect, subtract) --- libraries/stdlib/src/generated/_Sets.kt | 440 ++++++++++++++++++ .../kotlin/collections/MutableCollections.kt | 59 ++- .../test/collections/SetOperationsTest.kt | 30 ++ .../src/generators/GenerateCollections.kt | 1 + .../kotlin-stdlib-gen/src/templates/Sets.kt | 81 ++++ 5 files changed, 605 insertions(+), 6 deletions(-) create mode 100644 libraries/stdlib/src/generated/_Sets.kt create mode 100644 libraries/stdlib/test/collections/SetOperationsTest.kt create mode 100644 libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt diff --git a/libraries/stdlib/src/generated/_Sets.kt b/libraries/stdlib/src/generated/_Sets.kt new file mode 100644 index 00000000000..961e19e8a9a --- /dev/null +++ b/libraries/stdlib/src/generated/_Sets.kt @@ -0,0 +1,440 @@ +package kotlin + +// +// NOTE THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt +// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib +// + +import java.util.* + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun Array.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun BooleanArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun ByteArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun CharArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun DoubleArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun FloatArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun IntArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun LongArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun ShortArray.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from the given collection. + */ +public fun Iterable.distinct(): Set { + return this.toMutableSet() +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun Array.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun BooleanArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun ByteArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun CharArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun DoubleArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun FloatArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun IntArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun LongArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun ShortArray.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun Iterable.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun Array.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun BooleanArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun ByteArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun CharArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun DoubleArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun FloatArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun IntArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun LongArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun ShortArray.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun Iterable.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun Array.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun BooleanArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun ByteArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun CharArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun DoubleArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun FloatArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun IntArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun LongArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun ShortArray.toMutableSet(): MutableSet { + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + */ +public fun Iterable.toMutableSet(): MutableSet { + return when (this) { + is Collection -> LinkedHashSet(this) + else -> toCollection(LinkedHashSet()) + } +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun Array.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun BooleanArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun ByteArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun CharArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun DoubleArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun FloatArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun IntArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun LongArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun ShortArray.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns a set containing all distinct elements from both collections. + */ +public fun Iterable.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + diff --git a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt index ba221cfd04c..0aa9191f8d7 100644 --- a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt +++ b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt @@ -3,17 +3,64 @@ package kotlin /** * Adds all elements of the given *iterable* to this [[MutableCollection]] */ -public fun MutableCollection.addAll(iterable: Iterable): Unit { +public fun MutableCollection.addAll(iterable: Iterable) { when (iterable) { is Collection -> addAll(iterable) - else -> for (e in iterable) add(e) + else -> for (item in iterable) add(item) } } -public fun MutableCollection.addAll(stream: Stream): Unit { - for (e in stream) add(e) +/** + * Adds all elements of the given *stream* to this [[MutableCollection]] + */ +public fun MutableCollection.addAll(stream: Stream) { + for (item in stream) add(item) } -public fun MutableCollection.addAll(array: Array): Unit { - for (e in array) add(e) +/** + * Adds all elements of the given *array* to this [[MutableCollection]] + */ +public fun MutableCollection.addAll(array: Array) { + for (item in array) add(item) +} + +/** + * Removes all elements of the given *iterable* from this [[MutableCollection]] + */ +public fun MutableCollection.removeAll(iterable: Iterable) { + when (iterable) { + is Collection -> removeAll(iterable) + else -> for (item in iterable) remove(item) + } +} + +/** + * Removes all elements of the given *stream* from this [[MutableCollection]] + */ +public fun MutableCollection.removeAll(stream: Stream) { + for (item in stream) remove(item) +} + +/** + * Removes all elements of the given *array* from this [[MutableCollection]] + */ +public fun MutableCollection.removeAll(array: Array) { + for (item in array) remove(item) +} + +/** + * Retains only elements of the given *iterable* in this [[MutableCollection]] + */ +public fun MutableCollection.retainAll(iterable: Iterable) { + when (iterable) { + is Collection -> retainAll(iterable) + else -> retainAll(iterable.toSet()) + } +} + +/** + * Retains only elements of the given *array* in this [[MutableCollection]] + */ +public fun MutableCollection.retainAll(array: Array) { + retainAll(array.toSet()) } diff --git a/libraries/stdlib/test/collections/SetOperationsTest.kt b/libraries/stdlib/test/collections/SetOperationsTest.kt new file mode 100644 index 00000000000..6528a3bed34 --- /dev/null +++ b/libraries/stdlib/test/collections/SetOperationsTest.kt @@ -0,0 +1,30 @@ +package test.collections + +import kotlin.test.* +import org.junit.Test as test + +class SetOperationsTest { + test fun distinct() { + assertEquals(listOf(1, 3, 5), listOf(1, 3, 3, 1, 5, 1, 3).distinct().toList()) + assertEquals(listOf(), listOf().distinct().toList()) + } + + test fun union() { + assertEquals(listOf(1, 3, 5), listOf(1, 3).union(listOf(5)).toList()) + assertEquals(listOf(1), listOf().union(listOf(1)).toList()) + } + + test fun subtract() { + assertEquals(listOf(1, 3), listOf(1, 3).subtract(listOf(5)).toList()) + assertEquals(listOf(1, 3), listOf(1, 3, 5).subtract(listOf(5)).toList()) + assertEquals(listOf(), listOf(1, 3, 5).subtract(listOf(1, 3, 5)).toList()) + assertEquals(listOf(), listOf().subtract(listOf(1)).toList()) + } + + test fun intersect() { + assertEquals(listOf(), listOf(1, 3).intersect(listOf(5)).toList()) + assertEquals(listOf(5), listOf(1, 3, 5).intersect(listOf(5)).toList()) + assertEquals(listOf(1, 3, 5), listOf(1, 3, 5).intersect(listOf(1, 3, 5)).toList()) + assertEquals(listOf(), listOf().intersect(listOf(1)).toList()) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateCollections.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateCollections.kt index 2e43193bbd4..bc4deb906ad 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateCollections.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateCollections.kt @@ -12,6 +12,7 @@ fun generateCollectionsAPI(outDir: File) { arrays().writeTo(File(outDir, "_Arrays.kt")) { build() } snapshots().writeTo(File(outDir, "_Snapshots.kt")) { build() } mapping().writeTo(File(outDir, "_Mapping.kt")) { build() } + sets().writeTo(File(outDir, "_Sets.kt")) { build() } aggregates().writeTo(File(outDir, "_Aggregates.kt")) { build() } guards().writeTo(File(outDir, "_Guards.kt")) { build() } generators().writeTo(File(outDir, "_Generators.kt")) { build() } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt new file mode 100644 index 00000000000..6009f4535ec --- /dev/null +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Sets.kt @@ -0,0 +1,81 @@ +package templates + +import templates.Family.* + +fun sets(): List { + val templates = arrayListOf() + + templates add f("toMutableSet()") { + exclude(Strings, Streams) + doc { "Returns a mutable set containing all distinct elements from the given collection." } + returns("MutableSet") + body { + """ + return when (this) { + is Collection -> LinkedHashSet(this) + else -> toCollection(LinkedHashSet()) + } + """ + } + body(ArraysOfObjects, ArraysOfPrimitives) { + """ + val set = LinkedHashSet(size) + for (item in this) set.add(item) + return set + """ + } + } + + templates add f("distinct()") { + exclude(Strings, Streams) + doc { "Returns a set containing all distinct elements from the given collection." } + + returns("Set") + body { + """ + return this.toMutableSet() + """ + } + } + + templates add f("union(other: Iterable)") { + exclude(Strings, Streams) + doc { "Returns a set containing all distinct elements from both collections." } + returns("Set") + body { + """ + val set = this.toMutableSet() + set.addAll(other) + return set + """ + } + } + + templates add f("intersect(other: Iterable)") { + exclude(Strings, Streams) + doc { "Returns a set containing all distinct elements from both collections." } + returns("Set") + body { + """ + val set = this.toMutableSet() + set.retainAll(other) + return set + """ + } + } + + templates add f("subtract(other: Iterable)") { + exclude(Strings, Streams) + doc { "Returns a set containing all distinct elements from both collections." } + returns("Set") + body { + """ + val set = this.toMutableSet() + set.removeAll(other) + return set + """ + } + } + + return templates +} \ No newline at end of file From 1842d305678611edec7861d54691aef285b1dc37 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Fri, 20 Jun 2014 22:42:08 +0400 Subject: [PATCH 128/143] Implement equals for NumberRange in JavaScript. --- js/js.translator/testData/kotlin_lib.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index 0e9d42c1081..acfac5fbfb2 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -546,6 +546,11 @@ }, isEmpty: function () { return this.start > this.end; + }, + equals_za3rmp$: function(other) { + if (other == null) + return false; + return this.start === other.start && this.end === other.end && this.increment === other.increment; } }); From e06154c2048b9a3477d7eb182449ebafb7330424 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 24 Jun 2014 20:40:02 +0400 Subject: [PATCH 129/143] Don't compile runtime for each test run by default: only do it for All Tests --- .idea/runConfigurations/All_Tests.xml | 4 +++- .../jet/codegen/forTestCompile/ForTestCompileSomething.java | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.idea/runConfigurations/All_Tests.xml b/.idea/runConfigurations/All_Tests.xml index 2900c66d4dd..d1aa82a1633 100644 --- a/.idea/runConfigurations/All_Tests.xml +++ b/.idea/runConfigurations/All_Tests.xml @@ -21,7 +21,9 @@ - + + +