responsibility of computing data flow moved to JetFlowInformationProvider

This commit is contained in:
svtk
2011-10-17 16:23:56 +04:00
parent 7831fc3dc1
commit 181835b0ee
9 changed files with 237 additions and 331 deletions
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull; 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.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
@@ -19,18 +18,12 @@ public class JetSemanticServices {
return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), JetControlFlowDataTraceFactory.EMPTY); 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 JetStandardLibrary standardLibrary;
private final JetTypeChecker typeChecker; private final JetTypeChecker typeChecker;
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) { private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) {
this.standardLibrary = standardLibrary; this.standardLibrary = standardLibrary;
this.typeChecker = new JetTypeChecker(standardLibrary); this.typeChecker = new JetTypeChecker(standardLibrary);
this.flowDataTraceFactory = flowDataTraceFactory;
} }
@NotNull @NotNull
@@ -40,7 +33,7 @@ public class JetSemanticServices {
@NotNull @NotNull
public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) { public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) {
return new ClassDescriptorResolver(this, trace, flowDataTraceFactory); return new ClassDescriptorResolver(this, trace);
} }
@NotNull @NotNull
@@ -1,92 +1,236 @@
package org.jetbrains.jet.lang.cfg; package org.jetbrains.jet.lang.cfg;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull; 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.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression; 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 * @author svtk
*/ */
public interface JetFlowInformationProvider { public class JetFlowInformationProvider {
// JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
// @Override private final Map<JetElement, Pseudocode> 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<JetElement, Pseudocode>();
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
final Map<JetExpression, LoopInfo> 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<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) { // public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
// throw new UnsupportedOperationException(); // Pseudocode pseudocode = pseudocodeMap.get(subroutine);
// } // assert pseudocode != null;
// //
// @Override // SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) { // processPreviousInstructions(exitInstruction, new HashSet<Instruction>(), returnedExpressions, elementsReturningUnit);
// throw new UnsupportedOperationException();
// } // }
//
// @Override public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetExpression> returnedExpressions) {
// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) { Pseudocode pseudocode = pseudocodeMap.get(subroutine);
// throw new UnsupportedOperationException(); assert pseudocode != null;
// }
// SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
// @Override 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<JetElement> unreachableElements) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
Set<Instruction> visited = new HashSet<Instruction>();
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<JetElement> dominated) { // public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
// throw new UnsupportedOperationException(); // Instruction dominatorInstruction = representativeInstructions.get(dominator);
// if (dominatorInstruction == null) {
// return;
// }
// SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
//
// Set<Instruction> reachable = new HashSet<Instruction>();
// collectReachable(enterInstruction, reachable, null);
//
// Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
// 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) { // 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<Instruction> 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);
// JetFlowInformationProvider NONE = new JetFlowInformationProvider() { // assert fromInstr != null : "No representative instruction for " + from.getText();
// @Override // Instruction toInstr = representativeInstructions.get(to);
// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) { // assert toInstr != null : "No representative instruction for " + to.getText();
// //
// return collectReachable(fromInstr, Sets.<Instruction>newHashSet(), toInstr);
// } // }
// // }
// @Override
// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
//
// }
//
// @Override
// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
//
// }
//
// @Override
// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
//
// }
//
// @Override
// public boolean isBreakable(JetLoopExpression loop) {
// return false;
// }
//
// };
/** private boolean collectReachable(Instruction current, Set<Instruction> visited, @Nullable Instruction lookFor) {
* Collects expressions returned from the given subroutine and 'return;' expressions if (!visited.add(current)) return false;
*/ if (current == lookFor) return true;
void collectReturnedInformation(
@NotNull JetElement subroutine,
@NotNull Collection<JetExpression> returnedExpressions,
@NotNull Collection<JetElement> elementsReturningUnit);
/** for (Instruction nextInstruction : current.getNextInstructions()) {
* Collects all 'return ...' expressions that return from the given subroutine and all the expressions that precede the exit point if (collectReachable(nextInstruction, visited, lookFor)) {
*/ return true;
void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions); }
}
return false;
}
void collectUnreachableExpressions( // private void processPreviousInstructions(Instruction previousFor, final Set<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
@NotNull JetElement subroutine, // if (!visited.add(previousFor)) return;
@NotNull Collection<JetElement> unreachableElements); //
// Collection<Instruction> previousInstructions = previousFor.getPreviousInstructions();
void collectDominatedExpressions( // InstructionVisitor visitor = new InstructionVisitor() {
@NotNull JetExpression dominator, // @Override
@NotNull Collection<JetElement> dominated); // public void visitReadValue(ReadValueInstruction instruction) {
// returnedExpressions.add((JetExpression) instruction.getElement());
boolean isBreakable(JetLoopExpression loop); // }
//
// @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);
// }
// }
} }
@@ -74,7 +74,7 @@ public class AnalyzingUtils {
public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull List<? extends JetDeclaration> declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull List<? extends JetDeclaration> declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
BindingTraceContext bindingTraceContext = new BindingTraceContext(); BindingTraceContext bindingTraceContext = new BindingTraceContext();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, flowDataTraceFactory); JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project);
JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope();
ModuleDescriptor owner = new ModuleDescriptor("<module>"); ModuleDescriptor owner = new ModuleDescriptor("<module>");
@@ -111,7 +111,7 @@ public class AnalyzingUtils {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
throw new IllegalStateException("Must be guaranteed not to happen by the parser"); throw new IllegalStateException("Must be guaranteed not to happen by the parser");
} }
}, declarations); }, declarations, flowDataTraceFactory);
return bindingTraceContext.getBindingContext(); return bindingTraceContext.getBindingContext();
} }
@@ -4,7 +4,6 @@ import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices; 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.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetAnnotationEntry; import org.jetbrains.jet.lang.psi.JetAnnotationEntry;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
@@ -6,7 +6,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.Queue; import com.intellij.util.containers.Queue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -2,17 +2,12 @@ package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices; 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.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.Errors;
@@ -35,15 +30,13 @@ public class ClassDescriptorResolver {
private final TypeResolver typeResolver; private final TypeResolver typeResolver;
private final TypeResolver typeResolverNotCheckingBounds; private final TypeResolver typeResolverNotCheckingBounds;
private final BindingTrace trace; private final BindingTrace trace;
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
private final AnnotationResolver annotationResolver; private final AnnotationResolver annotationResolver;
public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace, JetControlFlowDataTraceFactory flowDataTraceFactory) { public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace) {
this.semanticServices = semanticServices; this.semanticServices = semanticServices;
this.typeResolver = new TypeResolver(semanticServices, trace, true); this.typeResolver = new TypeResolver(semanticServices, trace, true);
this.typeResolverNotCheckingBounds = new TypeResolver(semanticServices, trace, false); this.typeResolverNotCheckingBounds = new TypeResolver(semanticServices, trace, false);
this.trace = trace; this.trace = trace;
this.flowDataTraceFactory = flowDataTraceFactory;
this.annotationResolver = new AnnotationResolver(semanticServices, trace); 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<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
final Map<JetExpression, LoopInfo> 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<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
processPreviousInstructions(exitInstruction, new HashSet<Instruction>(), returnedExpressions, elementsReturningUnit);
}
@Override
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetExpression> 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<JetElement> unreachableElements) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
Set<Instruction> visited = new HashSet<Instruction>();
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<JetElement> dominated) {
Instruction dominatorInstruction = representativeInstructions.get(dominator);
if (dominatorInstruction == null) {
return;
}
SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
Set<Instruction> reachable = new HashSet<Instruction>();
collectReachable(enterInstruction, reachable, null);
Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
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<Instruction> 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.<Instruction>newHashSet(), toInstr);
}
};
}
private boolean collectReachable(Instruction current, Set<Instruction> 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<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
if (!visited.add(previousFor)) return;
Collection<Instruction> 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);
}
}
} }
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; 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.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptorImpl; 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.JetType;
import org.jetbrains.jet.lang.types.JetTypeInferrer; import org.jetbrains.jet.lang.types.JetTypeInferrer;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -25,11 +25,13 @@ import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
*/ */
public class ControlFlowAnalyzer { public class ControlFlowAnalyzer {
private TopDownAnalysisContext context; 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; this.context = context;
typeInferrer = context.getSemanticServices().getTypeInferrerServices(context.getTrace()); this.flowDataTraceFactory = flowDataTraceFactory;
this.typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
} }
public void process() { public void process() {
@@ -37,7 +39,9 @@ public class ControlFlowAnalyzer {
JetNamedFunction function = entry.getKey(); JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue(); 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); checkFunction(function, functionDescriptor, expectedReturnType);
} }
@@ -58,7 +62,7 @@ public class ControlFlowAnalyzer {
private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) { private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) {
JetExpression bodyExpression = function.getBodyExpression(); JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression == null) return; 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(); final boolean blockBody = function.hasBlockBody();
List<JetElement> unreachableElements = Lists.newArrayList(); List<JetElement> unreachableElements = Lists.newArrayList();
@@ -96,7 +100,7 @@ public class ControlFlowAnalyzer {
@Override @Override
public void visitExpression(JetExpression expression) { public void visitExpression(JetExpression expression) {
if (blockBody && expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(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)) { if (type == null || !JetStandardClasses.isNothing(type)) {
context.getTrace().report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression)); context.getTrace().report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression));
} }
@@ -109,6 +113,6 @@ public class ControlFlowAnalyzer {
private void checkProperty(JetProperty property) { private void checkProperty(JetProperty property) {
JetExpression initializer = property.getInitializer(); JetExpression initializer = property.getInitializer();
if (initializer == null) return; if (initializer == null) return;
context.getClassDescriptorResolver().computeFlowData(property, initializer); new JetFlowInformationProvider(property, initializer, flowDataTraceFactory, context.getTrace());
} }
} }
@@ -1,8 +1,8 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices; 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.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -55,13 +55,16 @@ public class TopDownAnalyzer {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
return ClassObjectStatus.NOT_ALLOWED; return ClassObjectStatus.NOT_ALLOWED;
} }
}, Collections.<JetDeclaration>singletonList(object)); }, Collections.<JetDeclaration>singletonList(object), JetControlFlowDataTraceFactory.EMPTY);
} }
public static void process( public static void process(
@NotNull JetSemanticServices semanticServices, @NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull JetScope outerScope, NamespaceLike owner, @NotNull List<? extends JetDeclaration> declarations) { @NotNull JetScope outerScope,
NamespaceLike owner,
@NotNull List<? extends JetDeclaration> declarations,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace); TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
new TypeHierarchyResolver(context).process(outerScope, owner, declarations); new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
new DeclarationResolver(context).process(); new DeclarationResolver(context).process();
@@ -69,7 +72,7 @@ public class TopDownAnalyzer {
new OverrideResolver(context).process(); new OverrideResolver(context).process();
new BodyResolver(context).resolveBehaviorDeclarationBodies(); new BodyResolver(context).resolveBehaviorDeclarationBodies();
new DeclarationsChecker(context).process(); new DeclarationsChecker(context).process();
new ControlFlowAnalyzer(context).process(); new ControlFlowAnalyzer(context, flowDataTraceFactory).process();
} }
public static void processStandardLibraryNamespace( public static void processStandardLibraryNamespace(
@@ -8,7 +8,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNameIdentifierOwner;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -21,9 +20,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; 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.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.DESCRIPTOR_TO_DECLARATION;
import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
/** /**
* @author abreslav * @author abreslav