From 181835b0ee48b10208ceb29c817135ce27f53cb1 Mon Sep 17 00:00:00 2001 From: svtk Date: Mon, 17 Oct 2011 16:23:56 +0400 Subject: [PATCH 01/11] responsibility of computing data flow moved to JetFlowInformationProvider --- .../jet/lang/JetSemanticServices.java | 9 +- .../lang/cfg/JetFlowInformationProvider.java | 282 +++++++++++++----- .../jet/lang/resolve/AnalyzingUtils.java | 4 +- .../jet/lang/resolve/AnnotationResolver.java | 1 - .../jet/lang/resolve/BodyResolver.java | 1 - .../lang/resolve/ClassDescriptorResolver.java | 235 +-------------- .../jet/lang/resolve/ControlFlowAnalyzer.java | 20 +- .../jet/lang/resolve/TopDownAnalyzer.java | 11 +- .../lang/resolve/TypeHierarchyResolver.java | 5 +- 9 files changed, 237 insertions(+), 331 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java index 6b5517ace57..575a8b394b7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.lang; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.types.*; @@ -19,18 +18,12 @@ public class JetSemanticServices { return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), JetControlFlowDataTraceFactory.EMPTY); } - public static JetSemanticServices createSemanticServices(Project project, JetControlFlowDataTraceFactory flowDataTraceFactory) { - return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), flowDataTraceFactory); - } - private final JetStandardLibrary standardLibrary; private final JetTypeChecker typeChecker; - private final JetControlFlowDataTraceFactory flowDataTraceFactory; private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) { this.standardLibrary = standardLibrary; this.typeChecker = new JetTypeChecker(standardLibrary); - this.flowDataTraceFactory = flowDataTraceFactory; } @NotNull @@ -40,7 +33,7 @@ public class JetSemanticServices { @NotNull public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) { - return new ClassDescriptorResolver(this, trace, flowDataTraceFactory); + return new ClassDescriptorResolver(this, trace); } @NotNull 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 7430be1bed2..e38b2e8ca1c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -1,92 +1,236 @@ package org.jetbrains.jet.lang.cfg; +import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetLoopExpression; +import org.jetbrains.jet.lang.resolve.BindingTrace; -import java.util.Collection; +import java.util.*; /** - * @author abreslav - */ -public interface JetFlowInformationProvider { -// JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() { -// @Override +* @author svtk +*/ +public class JetFlowInformationProvider { + + private final Map pseudocodeMap; + + public JetFlowInformationProvider(@NotNull JetElement declaration, @NotNull final JetExpression bodyExpression, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace trace) { + final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); + pseudocodeMap = new HashMap(); + final Map representativeInstructions = new HashMap(); + final Map loopInfo = Maps.newHashMap(); + JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { + @Override + public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { + pseudocodeTrace.recordControlFlowData(element, pseudocode); + pseudocodeMap.put(element, pseudocode); + } + + @Override + public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { + Instruction oldValue = representativeInstructions.put(element, instruction); +// assert oldValue == null : element.getText(); + pseudocodeTrace.recordRepresentativeInstruction(element, instruction); + } + + @Override + public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) { + loopInfo.put(expression, blockInfo); + pseudocodeTrace.recordLoopInfo(expression, blockInfo); + } + + @Override + public void close() { + pseudocodeTrace.close(); + for (Pseudocode pseudocode : pseudocodeMap.values()) { + pseudocode.postProcess(); + } + } + }; + JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace); + new JetControlFlowProcessor(trace, instructionsGenerator).generate(declaration, bodyExpression); + wrappedTrace.close(); + } + // public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { -// throw new UnsupportedOperationException(); -// } +// Pseudocode pseudocode = pseudocodeMap.get(subroutine); +// assert pseudocode != null; // -// @Override -// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions) { -// throw new UnsupportedOperationException(); +// SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); +// processPreviousInstructions(exitInstruction, new HashSet(), returnedExpressions, elementsReturningUnit); // } -// -// @Override -// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { -// throw new UnsupportedOperationException(); -// } -// -// @Override + + public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection returnedExpressions) { + Pseudocode pseudocode = pseudocodeMap.get(subroutine); + assert pseudocode != null; + + SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); + for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) { + previousInstruction.accept(new InstructionVisitor() { + @Override + public void visitReturnValue(ReturnValueInstruction instruction) { + returnedExpressions.add((JetExpression) instruction.getElement()); + } + + @Override + public void visitReturnNoValue(ReturnNoValueInstruction instruction) { + returnedExpressions.add((JetExpression) instruction.getElement()); + } + + + @Override + public void visitJump(AbstractJumpInstruction instruction) { + // Nothing + } + + @Override + public void visitInstruction(Instruction instruction) { + if (instruction instanceof JetElementInstruction) { + JetElementInstruction elementInstruction = (JetElementInstruction) instruction; + returnedExpressions.add((JetExpression) elementInstruction.getElement()); + } + else { + throw new IllegalStateException(instruction + " precedes the exit point"); + } + } + }); + } + } + + public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { + Pseudocode pseudocode = pseudocodeMap.get(subroutine); + assert pseudocode != null; + + SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction(); + Set visited = new HashSet(); + collectReachable(enterInstruction, visited, null); + + for (Instruction instruction : pseudocode.getInstructions()) { + if (!visited.contains(instruction) && + instruction instanceof JetElementInstruction && + // TODO : do {return} while (1 > a) + !(instruction instanceof ReadUnitValueInstruction)) { + unreachableElements.add(((JetElementInstruction) instruction).getElement()); + } + } + } // public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { -// throw new UnsupportedOperationException(); +// Instruction dominatorInstruction = representativeInstructions.get(dominator); +// if (dominatorInstruction == null) { +// return; +// } +// SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction(); +// +// Set reachable = new HashSet(); +// collectReachable(enterInstruction, reachable, null); +// +// Set reachableWithDominatorProhibited = new HashSet(); +// reachableWithDominatorProhibited.add(dominatorInstruction); +// collectReachable(enterInstruction, reachableWithDominatorProhibited, null); +// +// for (Instruction instruction : reachable) { +// if (instruction instanceof JetElementInstruction +// && reachable.contains(instruction) +// && !reachableWithDominatorProhibited.contains(instruction)) { +// JetElementInstruction elementInstruction = (JetElementInstruction) instruction; +// dominated.add(elementInstruction.getElement()); +// } +// } // } // -// @Override // public boolean isBreakable(JetLoopExpression loop) { -// throw new UnsupportedOperationException(); +// LoopInfo info = loopInfo.get(loop); +// Pseudocode.PseudocodeLabel bodyEntryPoint = (Pseudocode.PseudocodeLabel) info.getBodyEntryPoint(); +// Pseudocode.PseudocodeLabel exitPoint = (Pseudocode.PseudocodeLabel) info.getExitPoint(); +// HashSet visited = Sets.newHashSet(); +// Pseudocode.PseudocodeLabel conditionEntryPoint = (Pseudocode.PseudocodeLabel) info.getConditionEntryPoint(); +// visited.add(conditionEntryPoint.resolveToInstruction()); +// return collectReachable(bodyEntryPoint.resolveToInstruction(), visited, exitPoint.resolveToInstruction()); // } // -// }; -// -// JetFlowInformationProvider NONE = new JetFlowInformationProvider() { -// @Override -// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { +// public boolean isReachable(JetExpression from, JetExpression to) { +// Instruction fromInstr = representativeInstructions.get(from); +// assert fromInstr != null : "No representative instruction for " + from.getText(); +// Instruction toInstr = representativeInstructions.get(to); +// assert toInstr != null : "No representative instruction for " + to.getText(); // +// return collectReachable(fromInstr, Sets.newHashSet(), toInstr); // } -// -// @Override -// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions) { -// -// } -// -// @Override -// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { -// -// } -// -// @Override -// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { -// -// } -// -// @Override -// public boolean isBreakable(JetLoopExpression loop) { -// return false; -// } -// -// }; +// } - /** - * Collects expressions returned from the given subroutine and 'return;' expressions - */ - void collectReturnedInformation( - @NotNull JetElement subroutine, - @NotNull Collection returnedExpressions, - @NotNull Collection elementsReturningUnit); + private boolean collectReachable(Instruction current, Set visited, @Nullable Instruction lookFor) { + if (!visited.add(current)) return false; + if (current == lookFor) return true; - /** - * Collects all 'return ...' expressions that return from the given subroutine and all the expressions that precede the exit point - */ - void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions); + for (Instruction nextInstruction : current.getNextInstructions()) { + if (collectReachable(nextInstruction, visited, lookFor)) { + return true; + } + } + return false; + } - void collectUnreachableExpressions( - @NotNull JetElement subroutine, - @NotNull Collection unreachableElements); - - void collectDominatedExpressions( - @NotNull JetExpression dominator, - @NotNull Collection dominated); - - boolean isBreakable(JetLoopExpression loop); +// private void processPreviousInstructions(Instruction previousFor, final Set visited, final Collection returnedExpressions, final Collection elementsReturningUnit) { +// if (!visited.add(previousFor)) return; +// +// Collection previousInstructions = previousFor.getPreviousInstructions(); +// InstructionVisitor visitor = new InstructionVisitor() { +// @Override +// public void visitReadValue(ReadValueInstruction instruction) { +// returnedExpressions.add((JetExpression) instruction.getElement()); +// } +// +// @Override +// public void visitReturnValue(ReturnValueInstruction instruction) { +// processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); +// } +// +// @Override +// public void visitReturnNoValue(ReturnNoValueInstruction instruction) { +// elementsReturningUnit.add(instruction.getElement()); +// } +// +// @Override +// public void visitSubroutineEnter(SubroutineEnterInstruction instruction) { +// elementsReturningUnit.add(instruction.getSubroutine()); +// } +// +// @Override +// public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) { +// context.getTrace().report(UNSUPPORTED.on(instruction.getElement(), "Control-flow builder")); +// } +// +// @Override +// public void visitWriteValue(WriteValueInstruction writeValueInstruction) { +// elementsReturningUnit.add(writeValueInstruction.getElement()); +// } +// +// @Override +// public void visitJump(AbstractJumpInstruction instruction) { +// processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); +// } +// +// @Override +// public void visitReadUnitValue(ReadUnitValueInstruction instruction) { +// returnedExpressions.add((JetExpression) instruction.getElement()); +// } +// +// @Override +// public void visitInstruction(Instruction instruction) { +// if (instruction instanceof JetElementInstructionImpl) { +// JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction; +// context.getTrace().report(UNSUPPORTED.on(elementInstruction.getElement(), "Control-flow builder")); +// } +// else { +// throw new UnsupportedOperationException(instruction.toString()); +// } +// } +// }; +// for (Instruction previousInstruction : previousInstructions) { +// previousInstruction.accept(visitor); +// } +// } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 7b39810143c..007c0c8340a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -74,7 +74,7 @@ public class AnalyzingUtils { public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull List declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { BindingTraceContext bindingTraceContext = new BindingTraceContext(); - JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, flowDataTraceFactory); + JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project); JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); ModuleDescriptor owner = new ModuleDescriptor(""); @@ -111,7 +111,7 @@ public class AnalyzingUtils { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { throw new IllegalStateException("Must be guaranteed not to happen by the parser"); } - }, declarations); + }, declarations, flowDataTraceFactory); return bindingTraceContext.getBindingContext(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index 512f9f192c3..f79fd41bf89 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -4,7 +4,6 @@ import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetAnnotationEntry; import org.jetbrains.jet.lang.psi.JetExpression; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index e4820f5044c..c7ab16a33a1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -6,7 +6,6 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.Queue; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index ecffbcc9abc..e0f720f2547 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -2,17 +2,12 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; 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.JetSemanticServices; -import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; -import org.jetbrains.jet.lang.cfg.LoopInfo; -import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.diagnostics.Errors; @@ -35,15 +30,13 @@ public class ClassDescriptorResolver { private final TypeResolver typeResolver; private final TypeResolver typeResolverNotCheckingBounds; private final BindingTrace trace; - private final JetControlFlowDataTraceFactory flowDataTraceFactory; private final AnnotationResolver annotationResolver; - public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace, JetControlFlowDataTraceFactory flowDataTraceFactory) { + public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace) { this.semanticServices = semanticServices; this.typeResolver = new TypeResolver(semanticServices, trace, true); this.typeResolverNotCheckingBounds = new TypeResolver(semanticServices, trace, false); this.trace = trace; - this.flowDataTraceFactory = flowDataTraceFactory; this.annotationResolver = new AnnotationResolver(semanticServices, trace); } @@ -813,230 +806,4 @@ public class ClassDescriptorResolver { } } } - - public JetFlowInformationProvider computeFlowData(@NotNull JetElement declaration, @NotNull final JetExpression bodyExpression) { - final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); - final Map pseudocodeMap = new HashMap(); - final Map representativeInstructions = new HashMap(); - final Map loopInfo = Maps.newHashMap(); - JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { - @Override - public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { - pseudocodeTrace.recordControlFlowData(element, pseudocode); - pseudocodeMap.put(element, pseudocode); - } - - @Override - public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { - Instruction oldValue = representativeInstructions.put(element, instruction); -// assert oldValue == null : element.getText(); - pseudocodeTrace.recordRepresentativeInstruction(element, instruction); - } - - @Override - public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) { - loopInfo.put(expression, blockInfo); - pseudocodeTrace.recordLoopInfo(expression, blockInfo); - } - - @Override - public void close() { - pseudocodeTrace.close(); - for (Pseudocode pseudocode : pseudocodeMap.values()) { - pseudocode.postProcess(); - } - } - }; - JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace); - new JetControlFlowProcessor(trace, instructionsGenerator).generate(declaration, bodyExpression); - wrappedTrace.close(); - return new JetFlowInformationProvider() { - @Override - public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - - SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); - processPreviousInstructions(exitInstruction, new HashSet(), returnedExpressions, elementsReturningUnit); - } - - @Override - public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection returnedExpressions) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - - SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); - for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) { - previousInstruction.accept(new InstructionVisitor() { - @Override - public void visitReturnValue(ReturnValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); - } - - @Override - public void visitReturnNoValue(ReturnNoValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); - } - - - - @Override - public void visitJump(AbstractJumpInstruction instruction) { - // Nothing - } - - @Override - public void visitInstruction(Instruction instruction) { - if (instruction instanceof JetElementInstruction) { - JetElementInstruction elementInstruction = (JetElementInstruction) instruction; - returnedExpressions.add((JetExpression) elementInstruction.getElement()); - } - else { - throw new IllegalStateException(instruction + " precedes the exit point"); - } - } - }); - } - } - - @Override - public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { - Pseudocode pseudocode = pseudocodeMap.get(subroutine); - assert pseudocode != null; - - SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction(); - Set visited = new HashSet(); - collectReachable(enterInstruction, visited, null); - - for (Instruction instruction : pseudocode.getInstructions()) { - if (!visited.contains(instruction) && - instruction instanceof JetElementInstruction && - // TODO : do {return} while (1 > a) - !(instruction instanceof ReadUnitValueInstruction)) { - unreachableElements.add(((JetElementInstruction) instruction).getElement()); - } - } - } - - @Override - public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { - Instruction dominatorInstruction = representativeInstructions.get(dominator); - if (dominatorInstruction == null) { - return; - } - SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction(); - - Set reachable = new HashSet(); - collectReachable(enterInstruction, reachable, null); - - Set reachableWithDominatorProhibited = new HashSet(); - reachableWithDominatorProhibited.add(dominatorInstruction); - collectReachable(enterInstruction, reachableWithDominatorProhibited, null); - - for (Instruction instruction : reachable) { - if (instruction instanceof JetElementInstruction - && reachable.contains(instruction) - && !reachableWithDominatorProhibited.contains(instruction)) { - JetElementInstruction elementInstruction = (JetElementInstruction) instruction; - dominated.add(elementInstruction.getElement()); - } - } - } - - @Override - public boolean isBreakable(JetLoopExpression loop) { - LoopInfo info = loopInfo.get(loop); - Pseudocode.PseudocodeLabel bodyEntryPoint = (Pseudocode.PseudocodeLabel) info.getBodyEntryPoint(); - Pseudocode.PseudocodeLabel exitPoint = (Pseudocode.PseudocodeLabel) info.getExitPoint(); - HashSet visited = Sets.newHashSet(); - Pseudocode.PseudocodeLabel conditionEntryPoint = (Pseudocode.PseudocodeLabel) info.getConditionEntryPoint(); - visited.add(conditionEntryPoint.resolveToInstruction()); - return collectReachable(bodyEntryPoint.resolveToInstruction(), visited, exitPoint.resolveToInstruction()); - } - - public boolean isReachable(JetExpression from, JetExpression to) { - Instruction fromInstr = representativeInstructions.get(from); - assert fromInstr != null : "No representative instruction for " + from.getText(); - Instruction toInstr = representativeInstructions.get(to); - assert toInstr != null : "No representative instruction for " + to.getText(); - - return collectReachable(fromInstr, Sets.newHashSet(), toInstr); - } - }; - } - - private boolean collectReachable(Instruction current, Set visited, @Nullable Instruction lookFor) { - if (!visited.add(current)) return false; - if (current == lookFor) return true; - - for (Instruction nextInstruction : current.getNextInstructions()) { - if (collectReachable(nextInstruction, visited, lookFor)) { - return true; - } - } - return false; - } - - private void processPreviousInstructions(Instruction previousFor, final Set visited, final Collection returnedExpressions, final Collection elementsReturningUnit) { - if (!visited.add(previousFor)) return; - - Collection previousInstructions = previousFor.getPreviousInstructions(); - InstructionVisitor visitor = new InstructionVisitor() { - @Override - public void visitReadValue(ReadValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); - } - - @Override - public void visitReturnValue(ReturnValueInstruction instruction) { - processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); - } - - @Override - public void visitReturnNoValue(ReturnNoValueInstruction instruction) { - elementsReturningUnit.add(instruction.getElement()); - } - - @Override - public void visitSubroutineEnter(SubroutineEnterInstruction instruction) { - elementsReturningUnit.add(instruction.getSubroutine()); - } - - @Override - public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) { -// trace.getErrorHandler().genericError(instruction.getElement().getNode(), "Unsupported by control-flow builder " + instruction.getElement()); - trace.report(UNSUPPORTED.on(instruction.getElement(), "Control-flow builder")); - } - - @Override - public void visitWriteValue(WriteValueInstruction writeValueInstruction) { - elementsReturningUnit.add(writeValueInstruction.getElement()); - } - - @Override - public void visitJump(AbstractJumpInstruction instruction) { - processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit); - } - - @Override - public void visitReadUnitValue(ReadUnitValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); - } - - @Override - public void visitInstruction(Instruction instruction) { - if (instruction instanceof JetElementInstructionImpl) { - JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction; -// trace.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement()); - trace.report(UNSUPPORTED.on(elementInstruction.getElement(), "Control-flow builder")); - } - else { - throw new UnsupportedOperationException(instruction.toString()); - } - } - }; - for (Instruction previousInstruction : previousInstructions) { - previousInstruction.accept(visitor); - } - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index d4f0dec17dd..80525b8e113 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptorImpl; @@ -12,7 +13,6 @@ import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetTypeInferrer; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -25,11 +25,13 @@ import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; */ public class ControlFlowAnalyzer { private TopDownAnalysisContext context; - private JetTypeInferrer.Services typeInferrer; + private JetTypeInferrer.Services typeInferrerServices; + private final JetControlFlowDataTraceFactory flowDataTraceFactory; - public ControlFlowAnalyzer(TopDownAnalysisContext context) { + public ControlFlowAnalyzer(TopDownAnalysisContext context, JetControlFlowDataTraceFactory flowDataTraceFactory) { this.context = context; - typeInferrer = context.getSemanticServices().getTypeInferrerServices(context.getTrace()); + this.flowDataTraceFactory = flowDataTraceFactory; + this.typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace()); } public void process() { @@ -37,7 +39,9 @@ public class ControlFlowAnalyzer { JetNamedFunction function = entry.getKey(); FunctionDescriptorImpl functionDescriptor = entry.getValue(); - final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() ? NO_EXPECTED_TYPE : functionDescriptor.getReturnType(); + final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() + ? NO_EXPECTED_TYPE + : functionDescriptor.getReturnType(); checkFunction(function, functionDescriptor, expectedReturnType); } @@ -58,7 +62,7 @@ public class ControlFlowAnalyzer { private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) { JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression == null) return; - JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData((JetElement) function, bodyExpression); + JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetElement) function, bodyExpression, flowDataTraceFactory, context.getTrace()); final boolean blockBody = function.hasBlockBody(); List unreachableElements = Lists.newArrayList(); @@ -96,7 +100,7 @@ public class ControlFlowAnalyzer { @Override public void visitExpression(JetExpression expression) { if (blockBody && expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) { - JetType type = typeInferrer.getType(scope, expression, expectedReturnType); + JetType type = typeInferrerServices.getType(scope, expression, expectedReturnType); if (type == null || !JetStandardClasses.isNothing(type)) { context.getTrace().report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression)); } @@ -109,6 +113,6 @@ public class ControlFlowAnalyzer { private void checkProperty(JetProperty property) { JetExpression initializer = property.getInitializer(); if (initializer == null) return; - context.getClassDescriptorResolver().computeFlowData(property, initializer); + new JetFlowInformationProvider(property, initializer, flowDataTraceFactory, context.getTrace()); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 085f89bb0f1..ca3b4d4148d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -1,8 +1,8 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -55,13 +55,16 @@ public class TopDownAnalyzer { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { return ClassObjectStatus.NOT_ALLOWED; } - }, Collections.singletonList(object)); + }, Collections.singletonList(object), JetControlFlowDataTraceFactory.EMPTY); } public static void process( @NotNull JetSemanticServices semanticServices, @NotNull BindingTrace trace, - @NotNull JetScope outerScope, NamespaceLike owner, @NotNull List declarations) { + @NotNull JetScope outerScope, + NamespaceLike owner, + @NotNull List declarations, + @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace); new TypeHierarchyResolver(context).process(outerScope, owner, declarations); new DeclarationResolver(context).process(); @@ -69,7 +72,7 @@ public class TopDownAnalyzer { new OverrideResolver(context).process(); new BodyResolver(context).resolveBehaviorDeclarationBodies(); new DeclarationsChecker(context).process(); - new ControlFlowAnalyzer(context).process(); + new ControlFlowAnalyzer(context, flowDataTraceFactory).process(); } public static void processStandardLibraryNamespace( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index e2789599d2a..dd10cd26edb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -8,7 +8,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNameIdentifierOwner; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; @@ -21,9 +20,7 @@ import org.jetbrains.jet.lexer.JetTokens; import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.resolve.BindingContext.CONSTRUCTOR; -import static org.jetbrains.jet.lang.resolve.BindingContext.DESCRIPTOR_TO_DECLARATION; -import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE; +import static org.jetbrains.jet.lang.resolve.BindingContext.*; /** * @author abreslav From 5a9c23e8de0eab6ca3fb229d0e52d6749cdaf3e2 Mon Sep 17 00:00:00 2001 From: svtk Date: Tue, 18 Oct 2011 16:52:16 +0400 Subject: [PATCH 02/11] Added edges check to control flow graph test --- .../jet/lang/cfg/JetControlFlowProcessor.java | 84 ---- .../jet/lang/cfg/pseudocode/Instruction.java | 1 + .../lang/cfg/pseudocode/InstructionImpl.java | 1 + .../NondeterministicJumpInstruction.java | 2 +- .../jet/lang/cfg/pseudocode/Pseudocode.java | 182 +------ idea/testData/cfg/ArrayAccess.instructions | 46 +- idea/testData/cfg/Assignments.instructions | 68 +-- idea/testData/cfg/Basic.instructions | 116 ++--- idea/testData/cfg/EmptyFunction.instructions | 8 +- idea/testData/cfg/FailFunction.instructions | 20 +- idea/testData/cfg/Finally.instructions | 456 +++++++++--------- idea/testData/cfg/LazyBooleans.instructions | 74 +-- idea/testData/cfg/Nonlocals.instructions | 86 ++-- .../cfg/OnlyWhileInFunctionBody.instructions | 42 +- .../cfg/ReturnFromExpression.instructions | 16 +- idea/testData/cfg/ShortFunction.instructions | 8 +- .../full/infos/Autocasts.jet | 8 +- .../full/regression/OverrideResolution.jet | 4 +- .../jetbrains/jet/cfg/JetControlFlowTest.java | 238 ++++++++- 19 files changed, 729 insertions(+), 731 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 07337a81a63..3d7f2a9d25a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -22,8 +22,6 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*; */ public class JetControlFlowProcessor { -// private final Map> labeledElements = new HashMap>(); - private final JetControlFlowBuilder builder; private final BindingTrace trace; @@ -37,10 +35,6 @@ public class JetControlFlowProcessor { } public void generateSubroutineControlFlow(@NotNull JetElement subroutineElement, @NotNull List body) { -// if (subroutineElement instanceof JetNamedDeclaration) { -// JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement; -// enterLabeledElement(JetPsiUtil.safeName(namedDeclaration.getName()), namedDeclaration); -// } boolean functionLiteral = subroutineElement instanceof JetFunctionLiteralExpression; builder.enterSubroutine(subroutineElement, functionLiteral); for (JetElement statement : body) { @@ -49,51 +43,6 @@ public class JetControlFlowProcessor { builder.exitSubroutine(subroutineElement, functionLiteral); } -// private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) { -// Stack stack = labeledElements.get(labelName); -// if (stack == null) { -// stack = new Stack(); -// labeledElements.put(labelName, stack); -// } -// stack.push(labeledElement); -// } -// -// private void exitElement(JetElement element) { -// // TODO : really suboptimal -// for (Iterator>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { -// Map.Entry> entry = mapIter.next(); -// Stack stack = entry.getValue(); -// for (Iterator stackIter = stack.iterator(); stackIter.hasNext(); ) { -// JetElement recorded = stackIter.next(); -// if (recorded == element) { -// stackIter.remove(); -// } -// } -// if (stack.isEmpty()) { -// mapIter.remove(); -// } -// } -// } - -// @Nullable -// private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved) { -// Stack stack = labeledElements.get(labelName); -// if (stack == null || stack.isEmpty()) { -// if (reportUnresolved) { -//// trace.report(UNRESOLVED_REFERENCE.on(labelExpression)); -// } -// return null; -// } -// else if (stack.size() > 1) { -//// trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope"); -//// trace.report(LABEL_NAME_CLASH.on(labelExpression)); -// } -// -// JetElement result = stack.peek(); -//// trace.record(BindingContext.LABEL_TARGET, labelExpression, result); -// return result; -// } - private class CFPVisitor extends JetVisitorVoid { private final boolean inCondition; @@ -111,7 +60,6 @@ public class JetControlFlowProcessor { visitor = new CFPVisitor(inCondition); } element.accept(visitor); -// exitElement(element); } @Override @@ -124,12 +72,6 @@ public class JetControlFlowProcessor { @Override public void visitThisExpression(JetThisExpression expression) { -// JetSimpleNameExpression targetLabel = expression.getTargetLabel(); -// if (targetLabel != null) { -// String labelName = expression.getLabelName(); -// assert labelName != null; -// resolveLabel(labelName, targetLabel, false); -// } builder.read(expression); } @@ -161,7 +103,6 @@ public class JetControlFlowProcessor { private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) { JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression); if (deparenthesized != null) { -// enterLabeledElement(labelName, deparenthesized); value(labeledExpression, inCondition); } } @@ -453,29 +394,16 @@ public class JetControlFlowProcessor { trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); loop = null; } -// loop = resolveLabel(labelName, targetLabel, true); -// if (!isLoop(loop)) { -//// trace.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop"); -// trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText())); -// loop = null; -// } } else { loop = builder.getCurrentLoop(); if (loop == null) { -// trace.getErrorHandler().genericError(expression.getNode(), "'break' and 'continue' are only allowed inside a loop"); trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression)); } } return loop; } -// private boolean isLoop(JetElement loop) { -// return loop instanceof JetWhileExpression || -// loop instanceof JetDoWhileExpression || -// loop instanceof JetForExpression; -// } - @Override public void visitReturnExpression(JetReturnExpression expression) { JetExpression returnedExpression = expression.getReturnedExpression(); @@ -495,7 +423,6 @@ public class JetControlFlowProcessor { else { subroutine = null; } - //subroutine = resolveLabel(labelName, labelElement, true); } else { subroutine = builder.getCurrentSubroutine(); @@ -672,7 +599,6 @@ public class JetControlFlowProcessor { if (whenEntry.isElse()) { if (iterator.hasNext()) { -// trace.getErrorHandler().genericError(whenEntry.getNode(), "'else' entry must be the last one in a when-expression"); trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry)); } } @@ -769,16 +695,6 @@ public class JetControlFlowProcessor { @Override public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) { -// List delegationSpecifiers = expression.getObjectDeclaration().getDelegationSpecifiers(); -// for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { -// if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) { -// JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier; -// JetExpression delegateExpression = specifier.getDelegateExpression(); -// if (delegateExpression != null) { -// value(delegateExpression, false, false); -// } -// } -// } value(expression.getObjectDeclaration(), inCondition); builder.read(expression); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java index 156f35debc2..4a2cf3832e6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java @@ -13,6 +13,7 @@ public interface Instruction { void setOwner(@NotNull Pseudocode owner); + @NotNull Collection getPreviousInstructions(); @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java index bcdbd850dcf..65fadb3b5a3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java @@ -28,6 +28,7 @@ public abstract class InstructionImpl implements Instruction { this.owner = owner; } + @NotNull @Override public Collection getPreviousInstructions() { return previousInstructions; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/NondeterministicJumpInstruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/NondeterministicJumpInstruction.java index 20a34886dde..d5e63335ef0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/NondeterministicJumpInstruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/NondeterministicJumpInstruction.java @@ -27,7 +27,7 @@ public class NondeterministicJumpInstruction extends AbstractJumpInstruction { } public void setNext(Instruction next) { - this.next = next; + this.next = outgoingEdgeTo(next); } @NotNull 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 93aa1264354..211abbc4575 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 @@ -75,9 +75,13 @@ public class Pseudocode { } @NotNull - public Collection getInstructions() { + public List getInstructions() { return instructions; } + + public List getLabels() { + return labels; + } public void addExitInstruction(SubroutineExitInstruction exitInstruction) { addInstruction(exitInstruction); @@ -163,170 +167,30 @@ public class Pseudocode { @NotNull private Instruction getJumpTarget(@NotNull Label targetLabel) { - return getTargetInstruction(((PseudocodeLabel) targetLabel).resolve()); + return ((PseudocodeLabel)targetLabel).resolveToInstruction(); + //return getTargetInstruction(((PseudocodeLabel) targetLabel).resolve()); } - @NotNull - private Instruction getTargetInstruction(@NotNull List instructions) { - while (true) { - assert instructions != null; - Instruction targetInstruction = instructions.get(0); - - if (false == targetInstruction instanceof UnconditionalJumpInstruction) { - return targetInstruction; - } - - Label label = ((UnconditionalJumpInstruction) targetInstruction).getTargetLabel(); - instructions = ((PseudocodeLabel)label).resolve(); - } - } +// @NotNull +// private Instruction getTargetInstruction(@NotNull List instructions) { +// while (true) { +// assert instructions != null; +// Instruction targetInstruction = instructions.get(0); +// +// //if (false == targetInstruction instanceof UnconditionalJumpInstruction) { +// return targetInstruction; +// //} +// +//// Label label = ((UnconditionalJumpInstruction) targetInstruction).getTargetLabel(); +//// instructions = ((PseudocodeLabel)label).resolve(); +// } +// } @NotNull private Instruction getNextPosition(int currentPosition) { int targetPosition = currentPosition + 1; assert targetPosition < instructions.size() : currentPosition; - return getTargetInstruction(instructions.subList(targetPosition, instructions.size())); + return instructions.get(targetPosition); + //return getTargetInstruction(instructions.subList(targetPosition, instructions.size())); } - - public void dfsDump(StringBuilder nodes, StringBuilder edges, Map nodeNames) { - dfsDump(nodes, edges, instructions.get(0), nodeNames); - } - - private void dfsDump(StringBuilder nodes, StringBuilder edges, Instruction instruction, Map nodeNames) { - if (nodeNames.containsKey(instruction)) return; - String name = "n" + nodeNames.size(); - nodeNames.put(instruction, name); - nodes.append(name).append(" := ").append(renderName(instruction)); - - } - - private String renderName(Instruction instruction) { - throw new UnsupportedOperationException(); // TODO - } - - public void dumpInstructions(@NotNull StringBuilder out) { - List locals = new ArrayList(); - for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) { - Instruction instruction = instructions.get(i); - if (instruction instanceof FunctionLiteralValueInstruction) { - FunctionLiteralValueInstruction functionLiteralValueInstruction = (FunctionLiteralValueInstruction) instruction; - locals.add(functionLiteralValueInstruction.getBody()); - } - for (PseudocodeLabel label: labels) { - if (label.getTargetInstructionIndex() == i) { - out.append(label.getName()).append(":\n"); - } - } - out.append(" ").append(instruction).append("\n"); - } - for (Pseudocode local : locals) { - local.dumpInstructions(out); - } - } - - public void dumpEdges(final PrintStream out, final int[] count, final Map nodeToName) { - for (final Instruction fromInst : instructions) { - fromInst.accept(new InstructionVisitor() { - @Override - public void visitFunctionLiteralValue(FunctionLiteralValueInstruction 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(instruction.getBody().instructions.get(0)), null); - visitInstructionWithNext(instruction); - } - - @Override - public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) { - // Nothing - } - - @Override - public void visitJump(AbstractJumpInstruction instruction) { - printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); - } - - @Override - public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { - visitJump(instruction); - printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); - } - - @Override - public void visitReturnValue(ReturnValueInstruction instruction) { - super.visitReturnValue(instruction); - } - - @Override - public void visitReturnNoValue(ReturnNoValueInstruction instruction) { - super.visitReturnNoValue(instruction); - } - - @Override - public void visitConditionalJump(ConditionalJumpInstruction instruction) { - String from = nodeToName.get(instruction); - printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no"); - printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes"); - } - - @Override - public void visitInstructionWithNext(InstructionWithNext instruction) { - printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); - } - - @Override - public void visitSubroutineExit(SubroutineExitInstruction instruction) { - // Nothing - } - - @Override - public void visitInstruction(Instruction instruction) { - throw new UnsupportedOperationException(instruction.toString()); - } - }); - } - } - - public void dumpNodes(PrintStream out, int[] count, Map nodeToName) { - for (Instruction node : instructions) { - if (node instanceof UnconditionalJumpInstruction) { - continue; - } - String name = "n" + count[0]++; - nodeToName.put(node, name); - String text = node.toString(); - int newline = text.indexOf("\n"); - if (newline >= 0) { - text = text.substring(0, newline); - } - String shape = "box"; - if (node instanceof ConditionalJumpInstruction) { - shape = "diamond"; - } - else if (node instanceof NondeterministicJumpInstruction) { - shape = "Mdiamond"; - } - else if (node instanceof UnsupportedElementInstruction) { - shape = "box, fillcolor=red, style=filled"; - } - else if (node instanceof FunctionLiteralValueInstruction) { - shape = "Mcircle"; - } - else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) { - shape = "roundrect, style=rounded"; - } - out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); - } - } - - private void printEdge(PrintStream out, String from, String to, String label) { - if (label != null) { - label = "[label=\"" + label + "\"]"; - } - else { - label = ""; - } - out.println(from + " -> " + to + label + ";"); - } - - } diff --git a/idea/testData/cfg/ArrayAccess.instructions b/idea/testData/cfg/ArrayAccess.instructions index b2d18a45e79..877a122fb43 100644 --- a/idea/testData/cfg/ArrayAccess.instructions +++ b/idea/testData/cfg/ArrayAccess.instructions @@ -10,29 +10,29 @@ fun foo() { } --------------------- l0: - - r(Array) - r(Array) - w(a) - r(3) - r(4) - r(10) - r(a) - r(=) - w(a[10]) - r(2) - r(10) - r(a) - r(a[10]) - r(100) - r(10) - r(a) - r(a[10]) - r(1) - r(+=) - w(a[10]) + NEXT:[r(Array)] PREV:[] + r(Array) NEXT:[r(Array)] PREV:[] + r(Array) NEXT:[w(a)] PREV:[r(Array)] + w(a) NEXT:[r(3)] PREV:[r(Array)] + r(3) NEXT:[r(4)] PREV:[w(a)] + r(4) NEXT:[r(10)] PREV:[r(3)] + r(10) NEXT:[r(a)] PREV:[r(4)] + r(a) NEXT:[r(=)] PREV:[r(10)] + r(=) NEXT:[w(a[10])] PREV:[r(a)] + w(a[10]) NEXT:[r(2)] PREV:[r(=)] + r(2) NEXT:[r(10)] PREV:[w(a[10])] + r(10) NEXT:[r(a)] PREV:[r(2)] + r(a) NEXT:[r(a[10])] PREV:[r(10)] + r(a[10]) NEXT:[r(100)] PREV:[r(a)] + r(100) NEXT:[r(10)] PREV:[r(a[10])] + r(10) NEXT:[r(a)] PREV:[r(100)] + r(a) NEXT:[r(a[10])] PREV:[r(10)] + r(a[10]) NEXT:[r(1)] PREV:[r(a)] + r(1) NEXT:[r(+=)] PREV:[r(a[10])] + r(+=) NEXT:[w(a[10])] PREV:[r(1)] + w(a[10]) NEXT:[] PREV:[r(+=)] l1: - + NEXT:[] PREV:[w(a[10])] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/Assignments.instructions b/idea/testData/cfg/Assignments.instructions index 07ceb36d2c8..671c6729d14 100644 --- a/idea/testData/cfg/Assignments.instructions +++ b/idea/testData/cfg/Assignments.instructions @@ -14,44 +14,44 @@ fun assignments() : Unit { } --------------------- l0: - - r(1) - w(x) - r(2) - w(x) - r(x) - r(2) - r(+=) - w(x) - r(true) - jf(l2) - r(1) - jmp(l3) + NEXT:[r(1)] PREV:[] + r(1) NEXT:[w(x)] PREV:[] + w(x) NEXT:[r(2)] PREV:[r(1)] + r(2) NEXT:[w(x)] PREV:[w(x)] + w(x) NEXT:[r(x)] PREV:[r(2)] + r(x) NEXT:[r(2)] PREV:[w(x)] + r(2) NEXT:[r(+=)] PREV:[r(x)] + r(+=) NEXT:[w(x)] PREV:[r(2)] + w(x) NEXT:[r(true)] PREV:[r(+=)] + r(true) NEXT:[jf(l2)] PREV:[w(x)] + jf(l2) NEXT:[r(2), r(1)] PREV:[r(true)] + r(1) NEXT:[jmp(l3)] PREV:[jf(l2)] + jmp(l3) NEXT:[w(x)] PREV:[r(1)] l2: - r(2) + r(2) NEXT:[w(x)] PREV:[jf(l2)] l3: - w(x) - r(true) - jf(l4) - r(false) + w(x) NEXT:[r(true)] PREV:[jmp(l3), r(2)] + r(true) NEXT:[jf(l4)] PREV:[w(x)] + jf(l4) NEXT:[r(true && false), r(false)] PREV:[r(true)] + r(false) NEXT:[r(true && false)] PREV:[jf(l4)] l4: - r(true && false) - w(y) - r(false) - jf(l5) - r(true) + r(true && false) NEXT:[w(y)] PREV:[jf(l4), r(false)] + w(y) NEXT:[r(false)] PREV:[r(true && false)] + r(false) NEXT:[jf(l5)] PREV:[w(y)] + jf(l5) NEXT:[r(false && true), r(true)] PREV:[r(false)] + r(true) NEXT:[r(false && true)] PREV:[jf(l5)] l5: - r(false && true) - w(z) - r(Test) - r(Test()) - w(t) - r(1) - r(t) - r(=) - w(t.x) + r(false && true) NEXT:[w(z)] PREV:[jf(l5), r(true)] + w(z) NEXT:[r(Test)] PREV:[r(false && true)] + r(Test) NEXT:[r(Test())] PREV:[w(z)] + r(Test()) NEXT:[w(t)] PREV:[r(Test)] + w(t) NEXT:[r(1)] PREV:[r(Test())] + r(1) NEXT:[r(t)] PREV:[w(t)] + r(t) NEXT:[r(=)] PREV:[r(1)] + r(=) NEXT:[w(t.x)] PREV:[r(t)] + w(t.x) NEXT:[] PREV:[r(=)] l1: - + NEXT:[] PREV:[w(t.x)] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/Basic.instructions b/idea/testData/cfg/Basic.instructions index 43e9c080245..f8f34d1dc84 100644 --- a/idea/testData/cfg/Basic.instructions +++ b/idea/testData/cfg/Basic.instructions @@ -2,12 +2,12 @@ {1} --------------------- l2: - - r(1) + NEXT:[r(1)] PREV:[] + r(1) NEXT:[] PREV:[] l3: - + NEXT:[] PREV:[r(1)] error: - + NEXT:[] PREV:[] ===================== == f == fun f(a : Boolean) : Unit { @@ -29,86 +29,86 @@ fun f(a : Boolean) : Unit { } --------------------- l0: - - r(1) - r(a) - r(2) - r(lng) - r(2.lng) - r(a) - r(3) - r(foo) - r(foo(a, 3)) - r(genfun) - r(genfun()) - rf({1}) - r(flfun) - r(flfun {1}) - r(3) - r(4) - r(equals) - r(equals(4)) - r(3.equals(4)) - r(3) - r(4) - r(equals) - r(3 equals 4) - r(1) - r(2) - r(+) - r(1 + 2) - r(a) - jf(l4) - r(true) + NEXT:[r(1)] PREV:[] + r(1) NEXT:[r(a)] PREV:[] + r(a) NEXT:[r(2)] PREV:[r(1)] + r(2) NEXT:[r(lng)] PREV:[r(a)] + r(lng) NEXT:[r(2.lng)] PREV:[r(2)] + r(2.lng) NEXT:[r(a)] PREV:[r(lng)] + r(a) NEXT:[r(3)] PREV:[r(2.lng)] + r(3) NEXT:[r(foo)] PREV:[r(a)] + r(foo) NEXT:[r(foo(a, 3))] PREV:[r(3)] + r(foo(a, 3)) NEXT:[r(genfun)] PREV:[r(foo)] + r(genfun) NEXT:[r(genfun())] PREV:[r(foo(a, 3))] + r(genfun()) NEXT:[rf({1})] PREV:[r(genfun)] + rf({1}) NEXT:[r(flfun)] PREV:[r(genfun())] + r(flfun) NEXT:[r(flfun {1})] PREV:[rf({1})] + r(flfun {1}) NEXT:[r(3)] PREV:[r(flfun)] + r(3) NEXT:[r(4)] PREV:[r(flfun {1})] + r(4) NEXT:[r(equals)] PREV:[r(3)] + r(equals) NEXT:[r(equals(4))] PREV:[r(4)] + r(equals(4)) NEXT:[r(3.equals(4))] PREV:[r(equals)] + r(3.equals(4)) NEXT:[r(3)] PREV:[r(equals(4))] + r(3) NEXT:[r(4)] PREV:[r(3.equals(4))] + r(4) NEXT:[r(equals)] PREV:[r(3)] + r(equals) NEXT:[r(3 equals 4)] PREV:[r(4)] + r(3 equals 4) NEXT:[r(1)] PREV:[r(equals)] + r(1) NEXT:[r(2)] PREV:[r(3 equals 4)] + r(2) NEXT:[r(+)] PREV:[r(1)] + r(+) NEXT:[r(1 + 2)] PREV:[r(2)] + r(1 + 2) NEXT:[r(a)] PREV:[r(+)] + r(a) NEXT:[jf(l4)] PREV:[r(1 + 2)] + jf(l4) NEXT:[r(a && true), r(true)] PREV:[r(a)] + r(true) NEXT:[r(a && true)] PREV:[jf(l4)] l4: - r(a && true) - r(a) - jt(l5) - r(false) + r(a && true) NEXT:[r(a)] PREV:[jf(l4), r(true)] + r(a) NEXT:[jt(l5)] PREV:[r(a && true)] + jt(l5) NEXT:[r(false), r(a || false)] PREV:[r(a)] + r(false) NEXT:[r(a || false)] PREV:[jt(l5)] l5: - r(a || false) + r(a || false) NEXT:[] PREV:[jt(l5), r(false)] l1: - + NEXT:[] PREV:[r(a || false)] error: - + NEXT:[] PREV:[] l2: - - r(1) + NEXT:[r(1)] PREV:[] + r(1) NEXT:[] PREV:[] l3: - + NEXT:[] PREV:[r(1)] error: - + NEXT:[] PREV:[] ===================== == foo == fun foo(a : Boolean, b : Int) : Unit {} --------------------- l0: - - read (Unit) + NEXT:[read (Unit)] PREV:[] + read (Unit) NEXT:[] PREV:[] l1: - + NEXT:[] PREV:[read (Unit)] error: - + NEXT:[] PREV:[] ===================== == genfun == fun genfun() : Unit {} --------------------- l0: - - read (Unit) + NEXT:[read (Unit)] PREV:[] + read (Unit) NEXT:[] PREV:[] l1: - + NEXT:[] PREV:[read (Unit)] error: - + NEXT:[] PREV:[] ===================== == flfun == fun flfun(f : fun () : Any) : Unit {} --------------------- l0: - - read (Unit) + NEXT:[read (Unit)] PREV:[] + read (Unit) NEXT:[] PREV:[] l1: - + NEXT:[] PREV:[read (Unit)] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/EmptyFunction.instructions b/idea/testData/cfg/EmptyFunction.instructions index 04fbe42e40a..36b5c7f0fc2 100644 --- a/idea/testData/cfg/EmptyFunction.instructions +++ b/idea/testData/cfg/EmptyFunction.instructions @@ -2,10 +2,10 @@ fun empty() {} --------------------- l0: - - read (Unit) + NEXT:[read (Unit)] PREV:[] + read (Unit) NEXT:[] PREV:[] l1: - + NEXT:[] PREV:[read (Unit)] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/FailFunction.instructions b/idea/testData/cfg/FailFunction.instructions index 716bd2a6536..be079a574d4 100644 --- a/idea/testData/cfg/FailFunction.instructions +++ b/idea/testData/cfg/FailFunction.instructions @@ -4,16 +4,16 @@ fun fail() : Nothing { } --------------------- l0: - - r(java) - r(lang) - r(java.lang) - r(RuntimeException) - r(RuntimeException()) - r(java.lang.RuntimeException()) - jmp(error) + NEXT:[r(java)] PREV:[] + r(java) NEXT:[r(lang)] PREV:[] + r(lang) NEXT:[r(java.lang)] PREV:[r(java)] + r(java.lang) NEXT:[r(RuntimeException)] PREV:[r(lang)] + r(RuntimeException) NEXT:[r(RuntimeException())] PREV:[r(java.lang)] + r(RuntimeException()) NEXT:[r(java.lang.RuntimeException())] PREV:[r(RuntimeException)] + r(java.lang.RuntimeException()) NEXT:[jmp(error)] PREV:[r(RuntimeException())] + jmp(error) NEXT:[] PREV:[r(java.lang.RuntimeException())] l1: - + NEXT:[] PREV:[] error: - + NEXT:[] PREV:[jmp(error)] ===================== diff --git a/idea/testData/cfg/Finally.instructions b/idea/testData/cfg/Finally.instructions index a5c381bc864..527b5f23b14 100644 --- a/idea/testData/cfg/Finally.instructions +++ b/idea/testData/cfg/Finally.instructions @@ -8,15 +8,15 @@ fun t3() { } --------------------- l0: - - jmp?(l2) - r(1) + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[r(2)] PREV:[jmp?(l2)] l2: - r(2) + r(2) NEXT:[] PREV:[jmp?(l2), r(1)] l1: - + NEXT:[] PREV:[r(2)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3() { @@ -31,26 +31,26 @@ fun t3() { } --------------------- l0: - - jmp?(l2) - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l3) - r(2) - ret l1 - jmp(l4) + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[r(2)] PREV:[jmp?(l2)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l3)] PREV:[r(>)] + jf(l3) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)] + r(2) NEXT:[ret l1] PREV:[jf(l3)] + ret l1 NEXT:[] PREV:[r(2)] + jmp(l4) NEXT:[r(2)] PREV:[] l3: - read (Unit) + read (Unit) NEXT:[r(2)] PREV:[jf(l3)] l2: l4: - r(2) + r(2) NEXT:[] PREV:[jmp?(l2), jmp(l4), read (Unit)] l1: - + NEXT:[] PREV:[ret l1, r(2)] error: - + NEXT:[] PREV:[] ===================== == anonymous_0 == { () => @@ -60,21 +60,21 @@ error: } --------------------- l3: - - r(2) - r(3) - r(>) - r(2 > 3) - jf(l5) - ret l4 - jmp(l6) + NEXT:[r(2)] PREV:[] + r(2) NEXT:[r(3)] PREV:[] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)] + jf(l5) NEXT:[read (Unit), ret l4] PREV:[r(2 > 3)] + ret l4 NEXT:[] PREV:[jf(l5)] + jmp(l6) NEXT:[] PREV:[] l5: - read (Unit) + read (Unit) NEXT:[] PREV:[jf(l5)] l4: l6: - + NEXT:[] PREV:[ret l4, jmp(l6), read (Unit)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3() { @@ -91,36 +91,36 @@ fun t3() { } --------------------- l0: - - jmp?(l2) - r(1) - rf({ () => - if (2 > 3) { - return@ - } - }) + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[rf({ () => if (2 > 3) { retu..)] PREV:[jmp?(l2)] + rf({ () => + if (2 > 3) { + return@ + } + }) NEXT:[r(2)] PREV:[r(1)] l2: - r(2) + r(2) NEXT:[] PREV:[jmp?(l2), rf({ () => if (2 > 3) { retu..)] l1: - + NEXT:[] PREV:[r(2)] error: - + NEXT:[] PREV:[] l3: - - r(2) - r(3) - r(>) - r(2 > 3) - jf(l5) - ret l4 - jmp(l6) + NEXT:[r(2)] PREV:[] + r(2) NEXT:[r(3)] PREV:[] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)] + jf(l5) NEXT:[read (Unit), ret l4] PREV:[r(2 > 3)] + ret l4 NEXT:[] PREV:[jf(l5)] + jmp(l6) NEXT:[] PREV:[] l5: - read (Unit) + read (Unit) NEXT:[] PREV:[jf(l5)] l4: l6: - + NEXT:[] PREV:[ret l4, jmp(l6), read (Unit)] error: - + NEXT:[] PREV:[] ===================== == anonymous_1 == { () => @@ -135,26 +135,26 @@ error: } --------------------- l2: - - jmp?(l4) - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l5) - r(2) - ret l3 - jmp(l6) + NEXT:[jmp?(l4)] PREV:[] + jmp?(l4) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[r(2)] PREV:[jmp?(l4)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)] + jf(l5) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)] + r(2) NEXT:[ret l3] PREV:[jf(l5)] + ret l3 NEXT:[] PREV:[r(2)] + jmp(l6) NEXT:[r(2)] PREV:[] l5: - read (Unit) + read (Unit) NEXT:[r(2)] PREV:[jf(l5)] l4: l6: - r(2) + r(2) NEXT:[] PREV:[jmp?(l4), jmp(l6), read (Unit)] l3: - + NEXT:[] PREV:[ret l3, r(2)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3() { @@ -171,42 +171,42 @@ fun t3() { } --------------------- l0: - - rf({ () => - try { - 1 - if (2 > 3) { - return@ - } - } finally { - 2 - } - }) + NEXT:[rf({ () => try { 1 if (2 > 3..)] PREV:[] + rf({ () => + try { + 1 + if (2 > 3) { + return@ + } + } finally { + 2 + } + }) NEXT:[] PREV:[] l1: - + NEXT:[] PREV:[rf({ () => try { 1 if (2 > 3..)] error: - + NEXT:[] PREV:[] l2: - - jmp?(l4) - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l5) - r(2) - ret l3 - jmp(l6) + NEXT:[jmp?(l4)] PREV:[] + jmp?(l4) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[r(2)] PREV:[jmp?(l4)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)] + jf(l5) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)] + r(2) NEXT:[ret l3] PREV:[jf(l5)] + ret l3 NEXT:[] PREV:[r(2)] + jmp(l6) NEXT:[r(2)] PREV:[] l5: - read (Unit) + read (Unit) NEXT:[r(2)] PREV:[jf(l5)] l4: l6: - r(2) + r(2) NEXT:[] PREV:[jmp?(l4), jmp(l6), read (Unit)] l3: - + NEXT:[] PREV:[ret l3, r(2)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3() { @@ -223,34 +223,34 @@ fun t3() { } --------------------- l0: - + NEXT:[r(true)] PREV:[] l2: l5: - r(true) - jf(l3) + r(true) NEXT:[jf(l3)] PREV:[, jmp(l2)] + jf(l3) NEXT:[read (Unit), jmp?(l6)] PREV:[r(true)] l4: - jmp?(l6) - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l7) - r(2) - jmp(l3) - jmp(l8) + jmp?(l6) NEXT:[r(2), r(1)] PREV:[jf(l3)] + r(1) NEXT:[r(2)] PREV:[jmp?(l6)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)] + jf(l7) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)] + r(2) NEXT:[jmp(l3)] PREV:[jf(l7)] + jmp(l3) NEXT:[read (Unit)] PREV:[r(2)] + jmp(l8) NEXT:[r(2)] PREV:[] l7: - read (Unit) + read (Unit) NEXT:[r(2)] PREV:[jf(l7)] l6: l8: - r(2) - jmp(l2) + r(2) NEXT:[jmp(l2)] PREV:[jmp?(l6), jmp(l8), read (Unit)] + jmp(l2) NEXT:[r(true)] PREV:[r(2)] l3: - read (Unit) + read (Unit) NEXT:[] PREV:[jf(l3), jmp(l3)] l1: - + NEXT:[] PREV:[read (Unit)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3() { @@ -268,34 +268,34 @@ fun t3() { } --------------------- l0: - - jmp?(l2) + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(true)] PREV:[] l3: l6: - r(true) - jf(l4) + r(true) NEXT:[jf(l4)] PREV:[jmp?(l2), jmp(l3)] + jf(l4) NEXT:[read (Unit), r(1)] PREV:[r(true)] l5: - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l7) - jmp(l4) - jmp(l8) + r(1) NEXT:[r(2)] PREV:[jf(l4)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)] + jf(l7) NEXT:[read (Unit), jmp(l4)] PREV:[r(2 > 3)] + jmp(l4) NEXT:[read (Unit)] PREV:[jf(l7)] + jmp(l8) NEXT:[jmp(l3)] PREV:[] l7: - read (Unit) + read (Unit) NEXT:[jmp(l3)] PREV:[jf(l7)] l8: - jmp(l3) + jmp(l3) NEXT:[r(true)] PREV:[jmp(l8), read (Unit)] l4: - read (Unit) - r(5) + read (Unit) NEXT:[r(5)] PREV:[jf(l4), jmp(l4)] + r(5) NEXT:[r(2)] PREV:[read (Unit)] l2: - r(2) + r(2) NEXT:[] PREV:[jmp?(l2), r(5)] l1: - + NEXT:[] PREV:[r(2)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3() { @@ -312,33 +312,33 @@ fun t3() { } --------------------- l0: - - jmp?(l2) + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(true)] PREV:[] l3: l6: - r(true) - jf(l4) + r(true) NEXT:[jf(l4)] PREV:[jmp?(l2), jmp(l3)] + jf(l4) NEXT:[read (Unit), r(1)] PREV:[r(true)] l5: - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l7) - jmp(l4) - jmp(l8) + r(1) NEXT:[r(2)] PREV:[jf(l4)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)] + jf(l7) NEXT:[read (Unit), jmp(l4)] PREV:[r(2 > 3)] + jmp(l4) NEXT:[read (Unit)] PREV:[jf(l7)] + jmp(l8) NEXT:[jmp(l3)] PREV:[] l7: - read (Unit) + read (Unit) NEXT:[jmp(l3)] PREV:[jf(l7)] l8: - jmp(l3) + jmp(l3) NEXT:[r(true)] PREV:[jmp(l8), read (Unit)] l4: - read (Unit) + read (Unit) NEXT:[r(2)] PREV:[jf(l4), jmp(l4)] l2: - r(2) + r(2) NEXT:[] PREV:[jmp?(l2), read (Unit)] l1: - + NEXT:[] PREV:[r(2)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3(a : Int) { @@ -355,37 +355,37 @@ fun t3(a : Int) { } --------------------- l0: - - r(1) - r(a) - r(..) - r(1..a) + NEXT:[r(1)] PREV:[] + r(1) NEXT:[r(a)] PREV:[] + r(a) NEXT:[r(..)] PREV:[r(1)] + r(..) NEXT:[r(1..a)] PREV:[r(a)] + r(1..a) NEXT:[jmp?(l2)] PREV:[r(..)] l3: - jmp?(l2) + jmp?(l2) NEXT:[read (Unit), jmp?(l6)] PREV:[r(1..a)] l4: l5: - jmp?(l6) - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l7) - r(2) - jmp(l4) - jmp(l8) + jmp?(l6) NEXT:[r(2), r(1)] PREV:[jmp?(l2), jmp(l4), jmp?(l4)] + r(1) NEXT:[r(2)] PREV:[jmp?(l6)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)] + jf(l7) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)] + r(2) NEXT:[jmp(l4)] PREV:[jf(l7)] + jmp(l4) NEXT:[jmp?(l6)] PREV:[r(2)] + jmp(l8) NEXT:[r(2)] PREV:[] l7: - read (Unit) + read (Unit) NEXT:[r(2)] PREV:[jf(l7)] l6: l8: - r(2) - jmp?(l4) + r(2) NEXT:[jmp?(l4)] PREV:[jmp?(l6), jmp(l8), read (Unit)] + jmp?(l4) NEXT:[jmp?(l6), read (Unit)] PREV:[r(2)] l2: - read (Unit) + read (Unit) NEXT:[] PREV:[jmp?(l2), jmp?(l4)] l1: - + NEXT:[] PREV:[read (Unit)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3(a : Int) { @@ -403,37 +403,37 @@ fun t3(a : Int) { } --------------------- l0: - - jmp?(l2) - r(1) - r(a) - r(..) - r(1..a) + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[r(a)] PREV:[jmp?(l2)] + r(a) NEXT:[r(..)] PREV:[r(1)] + r(..) NEXT:[r(1..a)] PREV:[r(a)] + r(1..a) NEXT:[jmp?(l3)] PREV:[r(..)] l4: - jmp?(l3) + jmp?(l3) NEXT:[read (Unit), r(1)] PREV:[r(1..a)] l5: l6: - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l7) - jmp(l5) - jmp(l8) + r(1) NEXT:[r(2)] PREV:[jmp?(l3), jmp(l5), jmp?(l5)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)] + jf(l7) NEXT:[read (Unit), jmp(l5)] PREV:[r(2 > 3)] + jmp(l5) NEXT:[r(1)] PREV:[jf(l7)] + jmp(l8) NEXT:[jmp?(l5)] PREV:[] l7: - read (Unit) + read (Unit) NEXT:[jmp?(l5)] PREV:[jf(l7)] l8: - jmp?(l5) + jmp?(l5) NEXT:[r(1), read (Unit)] PREV:[jmp(l8), read (Unit)] l3: - read (Unit) - r(5) + read (Unit) NEXT:[r(5)] PREV:[jmp?(l3), jmp?(l5)] + r(5) NEXT:[r(2)] PREV:[read (Unit)] l2: - r(2) + r(2) NEXT:[] PREV:[jmp?(l2), r(5)] l1: - + NEXT:[] PREV:[r(2)] error: - + NEXT:[] PREV:[] ===================== == t3 == fun t3(a : Int) { @@ -450,36 +450,36 @@ fun t3(a : Int) { } --------------------- l0: - - jmp?(l2) - r(1) - r(a) - r(..) - r(1..a) + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[r(a)] PREV:[jmp?(l2)] + r(a) NEXT:[r(..)] PREV:[r(1)] + r(..) NEXT:[r(1..a)] PREV:[r(a)] + r(1..a) NEXT:[jmp?(l3)] PREV:[r(..)] l4: - jmp?(l3) + jmp?(l3) NEXT:[read (Unit), r(1)] PREV:[r(1..a)] l5: l6: - r(1) - r(2) - r(3) - r(>) - r(2 > 3) - jf(l7) - jmp(l5) - jmp(l8) + r(1) NEXT:[r(2)] PREV:[jmp?(l3), jmp(l5), jmp?(l5)] + r(2) NEXT:[r(3)] PREV:[r(1)] + r(3) NEXT:[r(>)] PREV:[r(2)] + r(>) NEXT:[r(2 > 3)] PREV:[r(3)] + r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)] + jf(l7) NEXT:[read (Unit), jmp(l5)] PREV:[r(2 > 3)] + jmp(l5) NEXT:[r(1)] PREV:[jf(l7)] + jmp(l8) NEXT:[jmp?(l5)] PREV:[] l7: - read (Unit) + read (Unit) NEXT:[jmp?(l5)] PREV:[jf(l7)] l8: - jmp?(l5) + jmp?(l5) NEXT:[r(1), read (Unit)] PREV:[jmp(l8), read (Unit)] l3: - read (Unit) + read (Unit) NEXT:[r(2)] PREV:[jmp?(l3), jmp?(l5)] l2: - r(2) + r(2) NEXT:[] PREV:[jmp?(l2), read (Unit)] l1: - + NEXT:[] PREV:[r(2)] error: - + NEXT:[] PREV:[] ===================== == tf == fun tf() { @@ -492,17 +492,17 @@ fun tf() { } --------------------- l0: - - jmp?(l2) - r(1) - r(2) - ret(*) l1 - ret(*) l1 + NEXT:[jmp?(l2)] PREV:[] + jmp?(l2) NEXT:[r(2), r(1)] PREV:[] + r(1) NEXT:[r(2)] PREV:[jmp?(l2)] + r(2) NEXT:[ret(*) l1] PREV:[r(1)] + ret(*) l1 NEXT:[] PREV:[r(2)] + ret(*) l1 NEXT:[] PREV:[] l2: - r(2) - ret(*) l1 + r(2) NEXT:[ret(*) l1] PREV:[jmp?(l2)] + ret(*) l1 NEXT:[] PREV:[r(2)] l1: - + NEXT:[] PREV:[ret(*) l1, ret(*) l1, ret(*) l1] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/LazyBooleans.instructions b/idea/testData/cfg/LazyBooleans.instructions index d5aaf8eed74..8c477e17313 100644 --- a/idea/testData/cfg/LazyBooleans.instructions +++ b/idea/testData/cfg/LazyBooleans.instructions @@ -18,55 +18,55 @@ fun lazyBooleans(a : Boolean, b : Boolean) : Unit { } --------------------- l0: - - r(a) - jf(l2) - r(1) - jmp(l3) + NEXT:[r(a)] PREV:[] + r(a) NEXT:[jf(l2)] PREV:[] + jf(l2) NEXT:[r(2), r(1)] PREV:[r(a)] + r(1) NEXT:[jmp(l3)] PREV:[jf(l2)] + jmp(l3) NEXT:[r(3)] PREV:[r(1)] l2: - r(2) + r(2) NEXT:[r(3)] PREV:[jf(l2)] l3: - r(3) - r(a) - jf(l4) - r(b) + r(3) NEXT:[r(a)] PREV:[jmp(l3), r(2)] + r(a) NEXT:[jf(l4)] PREV:[r(3)] + jf(l4) NEXT:[jf(l5), r(b)] PREV:[r(a)] + r(b) NEXT:[jf(l5)] PREV:[jf(l4)] l4: - jf(l5) - r(5) - jmp(l6) + jf(l5) NEXT:[r(6), r(5)] PREV:[jf(l4), r(b)] + r(5) NEXT:[jmp(l6)] PREV:[jf(l5)] + jmp(l6) NEXT:[r(7)] PREV:[r(5)] l5: - r(6) + r(6) NEXT:[r(7)] PREV:[jf(l5)] l6: - r(7) - r(a) - jt(l7) - r(b) + r(7) NEXT:[r(a)] PREV:[jmp(l6), r(6)] + r(a) NEXT:[jt(l7)] PREV:[r(7)] + jt(l7) NEXT:[r(b), jf(l8)] PREV:[r(a)] + r(b) NEXT:[jf(l8)] PREV:[jt(l7)] l7: - jf(l8) - r(8) - jmp(l9) + jf(l8) NEXT:[r(9), r(8)] PREV:[jt(l7), r(b)] + r(8) NEXT:[jmp(l9)] PREV:[jf(l8)] + jmp(l9) NEXT:[r(10)] PREV:[r(8)] l8: - r(9) + r(9) NEXT:[r(10)] PREV:[jf(l8)] l9: - r(10) - r(a) - jf(l10) - r(11) - jmp(l11) + r(10) NEXT:[r(a)] PREV:[jmp(l9), r(9)] + r(a) NEXT:[jf(l10)] PREV:[r(10)] + jf(l10) NEXT:[read (Unit), r(11)] PREV:[r(a)] + r(11) NEXT:[jmp(l11)] PREV:[jf(l10)] + jmp(l11) NEXT:[r(12)] PREV:[r(11)] l10: - read (Unit) + read (Unit) NEXT:[r(12)] PREV:[jf(l10)] l11: - r(12) - r(a) - jf(l12) - read (Unit) - jmp(l13) + r(12) NEXT:[r(a)] PREV:[jmp(l11), read (Unit)] + r(a) NEXT:[jf(l12)] PREV:[r(12)] + jf(l12) NEXT:[r(13), read (Unit)] PREV:[r(a)] + read (Unit) NEXT:[jmp(l13)] PREV:[jf(l12)] + jmp(l13) NEXT:[r(14)] PREV:[read (Unit)] l12: - r(13) + r(13) NEXT:[r(14)] PREV:[jf(l12)] l13: - r(14) + r(14) NEXT:[] PREV:[jmp(l13), r(13)] l1: - + NEXT:[] PREV:[r(14)] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/Nonlocals.instructions b/idea/testData/cfg/Nonlocals.instructions index ba6a27c536e..080be40b5af 100644 --- a/idea/testData/cfg/Nonlocals.instructions +++ b/idea/testData/cfg/Nonlocals.instructions @@ -5,19 +5,19 @@ fun foo() { } --------------------- l6: - - r(b) - jf(l8) - r(1) - ret(*) l5 - jmp(l9) + NEXT:[r(b)] PREV:[] + r(b) NEXT:[jf(l8)] PREV:[] + jf(l8) NEXT:[read (Unit), r(1)] PREV:[r(b)] + r(1) NEXT:[ret(*) l5] PREV:[jf(l8)] + ret(*) l5 NEXT:[] PREV:[r(1)] + jmp(l9) NEXT:[] PREV:[] l8: - read (Unit) + read (Unit) NEXT:[] PREV:[jf(l8)] l7: l9: - + NEXT:[] PREV:[jmp(l9), read (Unit)] error: - + NEXT:[] PREV:[] ===================== == anonymous_0 == {a => @@ -31,14 +31,14 @@ error: } --------------------- l4: - - r(2) - r(5) - ret(*) l5 + NEXT:[r(2)] PREV:[] + r(2) NEXT:[r(5)] PREV:[] + r(5) NEXT:[ret(*) l5] PREV:[r(2)] + ret(*) l5 NEXT:[] PREV:[r(5)] l5: - + NEXT:[] PREV:[ret(*) l5, ret(*) l5] error: - + NEXT:[] PREV:[] ===================== == nonlocals1 == fun nonlocals1(a : Boolean, b : Boolean) : Any? { @@ -60,39 +60,39 @@ fun nonlocals1(a : Boolean, b : Boolean) : Any? { } --------------------- l0: - - r(a) - jf(l2) - r(1) - ret(*) l1 - jmp(l3) + NEXT:[r(a)] PREV:[] + r(a) NEXT:[jf(l2)] PREV:[] + jf(l2) NEXT:[read (Unit), r(1)] PREV:[r(a)] + r(1) NEXT:[ret(*) l1] PREV:[jf(l2)] + ret(*) l1 NEXT:[] PREV:[r(1)] + jmp(l3) NEXT:[r(1)] PREV:[] l2: - read (Unit) + read (Unit) NEXT:[r(1)] PREV:[jf(l2)] l3: - r(1) - rf({a => - 2 - fun foo() { - if (b) - return@a 1 - } - - return@a 5; - }) - r(1) - r(lng) - r(1.lng) + r(1) NEXT:[rf({a => 2 fun foo() { if (b..)] PREV:[jmp(l3), read (Unit)] + rf({a => + 2 + fun foo() { + if (b) + return@a 1 + } + + return@a 5; + }) NEXT:[r(1)] PREV:[r(1)] + r(1) NEXT:[r(lng)] PREV:[rf({a => 2 fun foo() { if (b..)] + r(lng) NEXT:[r(1.lng)] PREV:[r(1)] + r(1.lng) NEXT:[] PREV:[r(lng)] l1: - + NEXT:[] PREV:[ret(*) l1, r(1.lng)] error: - + NEXT:[] PREV:[] l4: - - r(2) - r(5) - ret(*) l5 + NEXT:[r(2)] PREV:[] + r(2) NEXT:[r(5)] PREV:[] + r(5) NEXT:[ret(*) l5] PREV:[r(2)] + ret(*) l5 NEXT:[] PREV:[r(5)] l5: - + NEXT:[] PREV:[ret(*) l5, ret(*) l5] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/OnlyWhileInFunctionBody.instructions b/idea/testData/cfg/OnlyWhileInFunctionBody.instructions index 4da6384a0b2..c0e4641ad03 100644 --- a/idea/testData/cfg/OnlyWhileInFunctionBody.instructions +++ b/idea/testData/cfg/OnlyWhileInFunctionBody.instructions @@ -6,23 +6,23 @@ fun main() { } --------------------- l0: - + NEXT:[r(1)] PREV:[] l2: l5: - r(1) - r(0) - r(>) - r(1 > 0) - jf(l3) + r(1) NEXT:[r(0)] PREV:[, jmp(l2)] + r(0) NEXT:[r(>)] PREV:[r(1)] + r(>) NEXT:[r(1 > 0)] PREV:[r(0)] + r(1 > 0) NEXT:[jf(l3)] PREV:[r(>)] + jf(l3) NEXT:[read (Unit), r(2)] PREV:[r(1 > 0)] l4: - r(2) - jmp(l2) + r(2) NEXT:[jmp(l2)] PREV:[jf(l3)] + jmp(l2) NEXT:[r(1)] PREV:[r(2)] l3: - read (Unit) + read (Unit) NEXT:[] PREV:[jf(l3)] l1: - + NEXT:[] PREV:[read (Unit)] error: - + NEXT:[] PREV:[] ===================== == dowhile == fun dowhile() { @@ -31,20 +31,20 @@ fun dowhile() { } --------------------- l0: - + NEXT:[ret l1] PREV:[] l2: l4: - ret l1 + ret l1 NEXT:[] PREV:[, jt(l2)] l5: - r(1) - r(0) - r(>) - r(1 > 0) - jt(l2) + r(1) NEXT:[r(0)] PREV:[] + r(0) NEXT:[r(>)] PREV:[r(1)] + r(>) NEXT:[r(1 > 0)] PREV:[r(0)] + r(1 > 0) NEXT:[jt(l2)] PREV:[r(>)] + jt(l2) NEXT:[read (Unit), ret l1] PREV:[r(1 > 0)] l3: - read (Unit) + read (Unit) NEXT:[] PREV:[jt(l2)] l1: - + NEXT:[] PREV:[ret l1, read (Unit)] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/ReturnFromExpression.instructions b/idea/testData/cfg/ReturnFromExpression.instructions index fb3a770b768..c097530ba85 100644 --- a/idea/testData/cfg/ReturnFromExpression.instructions +++ b/idea/testData/cfg/ReturnFromExpression.instructions @@ -4,15 +4,15 @@ fun blockAndAndMismatch() : Boolean { } --------------------- l0: - - r(false) - jt(l2) - r(false) - ret(*) l1 + NEXT:[r(false)] PREV:[] + r(false) NEXT:[jt(l2)] PREV:[] + jt(l2) NEXT:[r(false), r(false || (return false))] PREV:[r(false)] + r(false) NEXT:[ret(*) l1] PREV:[jt(l2)] + ret(*) l1 NEXT:[] PREV:[r(false)] l2: - r(false || (return false)) + r(false || (return false)) NEXT:[] PREV:[jt(l2)] l1: - + NEXT:[] PREV:[ret(*) l1, r(false || (return false))] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/cfg/ShortFunction.instructions b/idea/testData/cfg/ShortFunction.instructions index c3bdcaf3778..e0e2b89781b 100644 --- a/idea/testData/cfg/ShortFunction.instructions +++ b/idea/testData/cfg/ShortFunction.instructions @@ -2,10 +2,10 @@ fun short() = 1 --------------------- l0: - - r(1) + NEXT:[r(1)] PREV:[] + r(1) NEXT:[] PREV:[] l1: - + NEXT:[] PREV:[r(1)] error: - + NEXT:[] PREV:[] ===================== diff --git a/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet b/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet index a3cf2976f1f..0960ee88808 100644 --- a/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet +++ b/idea/testData/checkerWithErrorTypes/full/infos/Autocasts.jet @@ -6,8 +6,8 @@ class B() : A() { fun bar() {} } -fun f9() { - val a : A? +fun f9(init : A?) { + val a : A? = init a?.foo() a?.bar() if (a is B) { @@ -30,8 +30,8 @@ fun f9() { a.foo() } -fun f10() { - val a : A? +fun f10(init : A?) { + val a : A? = init if (!(a is B)) { return; } diff --git a/idea/testData/checkerWithErrorTypes/full/regression/OverrideResolution.jet b/idea/testData/checkerWithErrorTypes/full/regression/OverrideResolution.jet index b58ac616160..e4af018eda2 100644 --- a/idea/testData/checkerWithErrorTypes/full/regression/OverrideResolution.jet +++ b/idea/testData/checkerWithErrorTypes/full/regression/OverrideResolution.jet @@ -1,5 +1,5 @@ -fun box() { - val a : C +fun box(c : C) { + val a : C = c a.foo() } diff --git a/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java index 0399c97acf3..60c867aadeb 100644 --- a/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java +++ b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java @@ -10,10 +10,7 @@ import junit.framework.TestSuite; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestCaseBase; import org.jetbrains.jet.lang.cfg.LoopInfo; -import org.jetbrains.jet.lang.cfg.pseudocode.Instruction; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace; -import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode; +import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetFile; @@ -24,10 +21,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; public class JetControlFlowTest extends JetTestCaseBase { static { @@ -109,8 +103,19 @@ public class JetControlFlowTest extends JetTestCaseBase { instructionDump.append(correspondingElement.getText()); instructionDump.append("\n---------------------\n"); - pseudocode.dumpInstructions(instructionDump); + dumpInstructions(pseudocode, instructionDump); instructionDump.append("=====================\n"); + + //check edges directions + Collection instructions = pseudocode.getInstructions(); + for (Instruction instruction : instructions) { + for (Instruction nextInstruction : instruction.getNextInstructions()) { + assertTrue("instruction: " + instruction + " next: " + nextInstruction, nextInstruction.getPreviousInstructions().contains(instruction)); + } + for (Instruction prevInstruction : instruction.getPreviousInstructions()) { + assertTrue("instruction: " + instruction + " prev: " + prevInstruction, prevInstruction.getNextInstructions().contains(instruction)); + } + } } String expectedInstructionsFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".instructions"); @@ -129,6 +134,217 @@ public class JetControlFlowTest extends JetTestCaseBase { // } } + public void dfsDump(Pseudocode pseudocode, StringBuilder nodes, StringBuilder edges, Map nodeNames) { + dfsDump(nodes, edges, pseudocode.getInstructions().get(0), nodeNames); + } + + private void dfsDump(StringBuilder nodes, StringBuilder edges, Instruction instruction, Map nodeNames) { + if (nodeNames.containsKey(instruction)) return; + String name = "n" + nodeNames.size(); + nodeNames.put(instruction, name); + nodes.append(name).append(" := ").append(renderName(instruction)); + + } + + private String renderName(Instruction instruction) { + throw new UnsupportedOperationException(); // TODO + } + + private static String formatInstruction(Instruction instruction, int maxLength) { + String[] parts = instruction.toString().split("\n"); + if (parts.length == 1) { + return " " + String.format("%1$-" + maxLength + "s", instruction); + } + StringBuilder sb = new StringBuilder(); + for (int i = 0, partsLength = parts.length; i < partsLength; i++) { + String part = parts[i]; + sb.append(" ").append(String.format("%1$-" + maxLength + "s", part)); + if (i < partsLength - 1) sb.append("\n"); + } + return sb.toString(); + } + + private static String formatInstructionList(Collection instructions) { + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (Iterator iterator = instructions.iterator(); iterator.hasNext(); ) { + Instruction instruction = iterator.next(); + String instructionText = instruction.toString(); + String[] parts = instructionText.split("\n"); + if (parts.length > 1) { + StringBuilder instructionSb = new StringBuilder(); + for (String part : parts) { + instructionSb.append(part.trim()).append(' '); + } + if (instructionSb.toString().length() > 30) { + sb.append(instructionSb.substring(0, 28)).append("..)"); + } + else { + sb.append(instructionSb); + } + } + else { + sb.append(instruction); + } + if (iterator.hasNext()) { + sb.append(", "); + } + } + sb.append(']'); + return sb.toString(); + } + + public void dumpInstructions(Pseudocode pseudocode, @NotNull StringBuilder out) { + List instructions = pseudocode.getInstructions(); + List labels = pseudocode.getLabels(); + List locals = new ArrayList(); + int maxLength = 0; + int maxNextLength = 0; + for (Instruction instruction : instructions) { + String instuctionText = instruction.toString(); + if (instuctionText.length() > maxLength) { + String[] parts = instuctionText.split("\n"); + if (parts.length > 1) { + for (String part : parts) { + if (part.length() > maxLength) { + maxLength = part.length(); + } + } + } + else { + maxLength = instuctionText.length(); + } + } + String instructionListText = formatInstructionList(instruction.getNextInstructions()); + if (instructionListText.length() > maxNextLength) { + maxNextLength = instructionListText.length(); + } + } + for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) { + Instruction instruction = instructions.get(i); + if (instruction instanceof FunctionLiteralValueInstruction) { + FunctionLiteralValueInstruction functionLiteralValueInstruction = (FunctionLiteralValueInstruction) instruction; + locals.add(functionLiteralValueInstruction.getBody()); + } + for (Pseudocode.PseudocodeLabel label: labels) { + if (label.getTargetInstructionIndex() == i) { + out.append(label.getName()).append(":\n"); + } + } + + out.append(formatInstruction(instruction, maxLength)). + append(" NEXT:").append(String.format("%1$-" + maxNextLength + "s", formatInstructionList(instruction.getNextInstructions()))). + append(" PREV:").append(formatInstructionList(instruction.getPreviousInstructions())).append("\n"); + } + for (Pseudocode local : locals) { + dumpInstructions(local, out); + } + } + + public void dumpEdges(List instructions, final PrintStream out, final int[] count, final Map nodeToName) { + for (final Instruction fromInst : instructions) { + fromInst.accept(new InstructionVisitor() { + @Override + public void visitFunctionLiteralValue(FunctionLiteralValueInstruction 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(instruction.getBody().getInstructions().get(0)), null); + visitInstructionWithNext(instruction); + } + + @Override + public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) { + // Nothing + } + + @Override + public void visitJump(AbstractJumpInstruction instruction) { + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); + } + + @Override + public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { + visitJump(instruction); + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); + } + + @Override + public void visitReturnValue(ReturnValueInstruction instruction) { + super.visitReturnValue(instruction); + } + + @Override + public void visitReturnNoValue(ReturnNoValueInstruction instruction) { + super.visitReturnNoValue(instruction); + } + + @Override + public void visitConditionalJump(ConditionalJumpInstruction instruction) { + String from = nodeToName.get(instruction); + printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no"); + printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes"); + } + + @Override + public void visitInstructionWithNext(InstructionWithNext instruction) { + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); + } + + @Override + public void visitSubroutineExit(SubroutineExitInstruction instruction) { + // Nothing + } + + @Override + public void visitInstruction(Instruction instruction) { + throw new UnsupportedOperationException(instruction.toString()); + } + }); + } + } + + public void dumpNodes(List instructions, PrintStream out, int[] count, Map nodeToName) { + for (Instruction node : instructions) { + if (node instanceof UnconditionalJumpInstruction) { + continue; + } + String name = "n" + count[0]++; + nodeToName.put(node, name); + String text = node.toString(); + int newline = text.indexOf("\n"); + if (newline >= 0) { + text = text.substring(0, newline); + } + String shape = "box"; + if (node instanceof ConditionalJumpInstruction) { + shape = "diamond"; + } + else if (node instanceof NondeterministicJumpInstruction) { + shape = "Mdiamond"; + } + else if (node instanceof UnsupportedElementInstruction) { + shape = "box, fillcolor=red, style=filled"; + } + else if (node instanceof FunctionLiteralValueInstruction) { + shape = "Mcircle"; + } + else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) { + shape = "roundrect, style=rounded"; + } + out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); + } + } + + private void printEdge(PrintStream out, String from, String to, String label) { + if (label != null) { + label = "[label=\"" + label + "\"]"; + } + else { + label = ""; + } + out.println(from + " -> " + to + label + ";"); + } + private void dumpDot(String name, Collection pseudocodes) throws FileNotFoundException { String graphFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".dot"); File target = new File(graphFileName); @@ -139,7 +355,7 @@ public class JetControlFlowTest extends JetTestCaseBase { int[] count = new int[1]; Map nodeToName = new HashMap(); for (Pseudocode pseudocode : pseudocodes) { - pseudocode.dumpNodes(out, count, nodeToName); + dumpNodes(pseudocode.getInstructions(), out, count, nodeToName); } int i = 0; for (Pseudocode pseudocode : pseudocodes) { @@ -155,7 +371,7 @@ public class JetControlFlowTest extends JetTestCaseBase { out.println("subgraph cluster_" + i + " {\n" + "label=\"" + label + "\";\n" + "color=blue;\n"); - pseudocode.dumpEdges(out, count, nodeToName); + dumpEdges(pseudocode.getInstructions(), out, count, nodeToName); out.println("}"); i++; } From 101b836a718db3188dead4ceea64a9800c8200c7 Mon Sep 17 00:00:00 2001 From: svtk Date: Tue, 18 Oct 2011 16:53:04 +0400 Subject: [PATCH 03/11] Added 'Uninitialized variable' error --- .../lang/cfg/JetFlowInformationProvider.java | 117 +++++++++++++++++- .../jet/lang/diagnostics/Errors.java | 3 + .../jet/lang/resolve/ControlFlowAnalyzer.java | 2 + 3 files changed, 118 insertions(+), 4 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 e38b2e8ca1c..84d0b036d6b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -1,23 +1,29 @@ package org.jetbrains.jet.lang.cfg; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.*; -import org.jetbrains.jet.lang.psi.JetElement; -import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.LocalVariableDescriptor; +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.BindingTrace; import java.util.*; /** -* @author svtk -*/ + * @author svtk + */ public class JetFlowInformationProvider { private final Map pseudocodeMap; + private BindingTrace trace; public JetFlowInformationProvider(@NotNull JetElement declaration, @NotNull final JetExpression bodyExpression, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace trace) { + this.trace = trace; final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); pseudocodeMap = new HashMap(); final Map representativeInstructions = new HashMap(); @@ -86,6 +92,13 @@ public class JetFlowInformationProvider { // Nothing } + @Override + public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) { + for (Instruction previousInstruction : instruction.getPreviousInstructions()) { + previousInstruction.accept(this); + } + } + @Override public void visitInstruction(Instruction instruction) { if (instruction instanceof JetElementInstruction) { @@ -233,4 +246,100 @@ public class JetFlowInformationProvider { // previousInstruction.accept(visitor); // } // } + + private Map traverseInstructionGraphUntilFactsStabilization(Collection instructions, InstructionsMergeHandler instructionsMergeHandler, D initialDataValue, boolean straightDirection) { + + Map dataMap = Maps.newHashMap(); + for (Instruction instruction : instructions) { + dataMap.put(instruction, initialDataValue); + } + + boolean changed = true; + while (changed) { + changed = false; + for (Instruction instruction : instructions) { + D previousDataValue = dataMap.get(instruction); + + Collection previousInstructions = straightDirection + ? instruction.getPreviousInstructions() + : instruction.getNextInstructions(); + Collection incomingEdgesData = Sets.newHashSet(); + for (Instruction previousInstruction : previousInstructions) { + incomingEdgesData.add(dataMap.get(previousInstruction)); + } + D mergedData = instructionsMergeHandler.merge(instruction, previousDataValue, incomingEdgesData); + if (!mergedData.equals(previousDataValue)) { + changed = true; + dataMap.put(instruction, mergedData); + } + } + } + return dataMap; + } + + public void markUninitializedVariables(@NotNull JetElement subroutine) { + Pseudocode pseudocode = pseudocodeMap.get(subroutine); + assert pseudocode != null; + + Collection instructions = pseudocode.getInstructions(); + InstructionsMergeHandler> instructionsMergeHandler = new InstructionsMergeHandler>() { + @Override + public Set merge(Instruction instruction, Set previousDataValue, Collection> incomingEdgesData) { + Set initializedVariables = Sets.newHashSet(); + initializedVariables.addAll(previousDataValue); + for (Set edgeDataValue : incomingEdgesData) { + initializedVariables.addAll(edgeDataValue); + } + + if (instruction instanceof WriteValueInstruction) { + JetElement element = ((WriteValueInstruction) instruction).getElement(); + DeclarationDescriptor descriptor = null; + if (element instanceof JetBinaryExpression) { + JetExpression left = ((JetBinaryExpression) element).getLeft(); + if (left instanceof JetSimpleNameExpression) { + descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) left); + } + } + else if (element instanceof JetProperty) { + descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); + } + if (descriptor instanceof LocalVariableDescriptor) { + initializedVariables.add((LocalVariableDescriptor) descriptor); + } + } + return initializedVariables; + } + }; + Map> dataMap = traverseInstructionGraphUntilFactsStabilization(instructions, instructionsMergeHandler, Collections.emptySet(), true); + + for (Instruction instruction : instructions) { + Set initializedVariables = dataMap.get(instruction); + if (instruction instanceof ReadValueInstruction) { + JetElement element = ((ReadValueInstruction) instruction).getElement(); + if (element instanceof JetSimpleNameExpression) { + DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element); + if (descriptor instanceof LocalVariableDescriptor) { + if (!initializedVariables.contains(descriptor)) { + trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, descriptor)); + } + } + } + } + else if (instruction instanceof WriteValueInstruction) { + JetElement element = ((WriteValueInstruction) instruction).getElement(); + if (element instanceof JetSimpleNameExpression) { + DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element); + if (descriptor instanceof LocalVariableDescriptor) { + if (initializedVariables.contains(descriptor) && ((LocalVariableDescriptor) descriptor).isVar()) { + trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, descriptor)); + } + } + } + } + } + } + + interface InstructionsMergeHandler { + D merge(Instruction instruction, D previousDataValue, Collection incomingEdgesData); + } } 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 b91883012bc..861e2cd92a2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -142,6 +142,9 @@ public interface Errors { }; PsiElementOnlyDiagnosticFactory3 VIRTUAL_MEMBER_HIDDEN = PsiElementOnlyDiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", DescriptorRenderer.TEXT); + PsiElementOnlyDiagnosticFactory1 UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be initialized", NAME); + PsiElementOnlyDiagnosticFactory1 VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME); + SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code"); SimpleDiagnosticFactory MANY_CLASS_OBJECTS = SimpleDiagnosticFactory.create(ERROR, "Only one class object is allowed per class"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index 80525b8e113..3bb6bbc7b49 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -108,6 +108,8 @@ public class ControlFlowAnalyzer { } }); } + + //flowInformationProvider.markUninitializedVariables(function.asElement()); } private void checkProperty(JetProperty property) { From e5bd34c7b01e60f63f1f658c8f1b9bd4aa7305ca Mon Sep 17 00:00:00 2001 From: svtk Date: Fri, 21 Oct 2011 15:38:01 +0400 Subject: [PATCH 04/11] Added nondeternministic jump to several labels instruction to pseudocode --- .../jet/lang/cfg/JetControlFlowBuilder.java | 11 ++-- .../cfg/JetControlFlowBuilderAdapter.java | 50 +++++++++++---- .../NondeterministicJumpInstruction.java | 62 ++++++++++++++----- .../jet/lang/cfg/pseudocode/Pseudocode.java | 11 ++-- 4 files changed, 98 insertions(+), 36 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 4658d844a4f..72360b8b838 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -2,9 +2,9 @@ package org.jetbrains.jet.lang.cfg; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.JetElement; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetThrowExpression; +import org.jetbrains.jet.lang.psi.*; + +import java.util.List; /** * @author abreslav @@ -24,6 +24,7 @@ public interface JetControlFlowBuilder { void jumpOnFalse(@NotNull Label label); void jumpOnTrue(@NotNull Label label); void nondeterministicJump(Label label); // Maybe, jump to label + void nondeterministicJump(List